✨ Added map
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
//! Imports
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// --------------------------------------------------- Components ------------------------------------------------------
|
||||
import Image from 'next/image';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------- Assets & Styles ---------------------------------------------------
|
||||
import '../styles.scss';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
const Forgot = () => {
|
||||
return (
|
||||
<div className='authContainer'>
|
||||
<Image
|
||||
src={'/logo-transparent.png'}
|
||||
className='appLogo'
|
||||
alt='appLogo'
|
||||
width={1024}
|
||||
height={1024}
|
||||
/>
|
||||
<div className='formContainer'>
|
||||
<h1 className='formTitle'>Connexion</h1>
|
||||
|
||||
<div
|
||||
role='form'
|
||||
className='form'
|
||||
>
|
||||
<div className='inputContainer'>
|
||||
<input
|
||||
type='password'
|
||||
name='password'
|
||||
className='input'
|
||||
required
|
||||
/>
|
||||
<label className='inputLabel'>Mot de passe</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className='buttonsContainer'>
|
||||
<button className='submitButton'>Se connecter</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Forgot;
|
||||
@@ -0,0 +1,7 @@
|
||||
export const useActions = ({ emailRef, passwordRef }) => {
|
||||
const handleSubmit = () => {};
|
||||
|
||||
return {
|
||||
handleSubmit,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import { useRef } from 'react';
|
||||
|
||||
export const useData = () => {
|
||||
const emailRef = useRef(null);
|
||||
const passwordRef = useRef(null);
|
||||
|
||||
return {
|
||||
emailRef,
|
||||
passwordRef,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
'use client';
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
//! Imports
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// --------------------------------------------------- Components ------------------------------------------------------
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// -------------------------------------------------- Hooks & Utils ----------------------------------------------------
|
||||
import { useData } from './hooks/useData';
|
||||
import { useActions } from './hooks/useActions';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------- Assets & Styles ---------------------------------------------------
|
||||
import '../styles.scss';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
const Login = () => {
|
||||
const { emailRef, passwordRef } = useData();
|
||||
const { handleSubmit } = useActions({ emailRef, passwordRef });
|
||||
|
||||
return (
|
||||
<div className='authContainer'>
|
||||
<Image
|
||||
src={'/logo-transparent.png'}
|
||||
className='appLogo'
|
||||
alt='appLogo'
|
||||
width={1024}
|
||||
height={1024}
|
||||
/>
|
||||
<div className='formContainer'>
|
||||
<h1 className='formTitle'>Connexion</h1>
|
||||
|
||||
<div
|
||||
role='form'
|
||||
className='form'
|
||||
>
|
||||
<div className='inputContainer'>
|
||||
<input
|
||||
ref={emailRef}
|
||||
type='email'
|
||||
name='email'
|
||||
className='input'
|
||||
required
|
||||
/>
|
||||
<label className='inputLabel'>Adresse e-mail</label>
|
||||
</div>
|
||||
<div className='inputContainer'>
|
||||
<input
|
||||
ref={passwordRef}
|
||||
type='password'
|
||||
name='password'
|
||||
className='input'
|
||||
required
|
||||
/>
|
||||
<label className='inputLabel'>Mot de passe</label>
|
||||
</div>
|
||||
|
||||
<Link
|
||||
href={'/auth/forgot'}
|
||||
className='forgetLink'
|
||||
>
|
||||
Mot de passe oublié ?
|
||||
</Link>
|
||||
</div>
|
||||
<div className='buttonsContainer'>
|
||||
<button
|
||||
className='submitButton'
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
Se connecter
|
||||
</button>
|
||||
<Link
|
||||
href={'/auth/register'}
|
||||
className='submitButton secondary'
|
||||
>
|
||||
S'inscrire
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
||||
@@ -0,0 +1,12 @@
|
||||
export const useActions = ({
|
||||
usernameRef,
|
||||
emailRef,
|
||||
passwordRef,
|
||||
confpasswordRef,
|
||||
}) => {
|
||||
const handleSubmit = () => {};
|
||||
|
||||
return {
|
||||
handleSubmit,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import { useRef } from 'react';
|
||||
|
||||
export const useData = () => {
|
||||
const usernameRef = useRef(null);
|
||||
const emailRef = useRef(null);
|
||||
const passwordRef = useRef(null);
|
||||
const confpasswordRef = useRef(null);
|
||||
|
||||
return {
|
||||
usernameRef,
|
||||
emailRef,
|
||||
passwordRef,
|
||||
confpasswordRef,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,110 @@
|
||||
'use client';
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
//! Imports
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// --------------------------------------------------- Components ------------------------------------------------------
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// -------------------------------------------------- Hooks & Utils ----------------------------------------------------
|
||||
import { useData } from './hooks/useData';
|
||||
import { useActions } from './hooks/useActions';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------- Assets & Styles ---------------------------------------------------
|
||||
import '../styles.scss';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
const Register = () => {
|
||||
const { usernameRef, emailRef, passwordRef, confpasswordRef } = useData();
|
||||
const { handleSubmit } = useActions({
|
||||
usernameRef,
|
||||
emailRef,
|
||||
passwordRef,
|
||||
confpasswordRef,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className='authContainer'>
|
||||
<Image
|
||||
src={'/logo-transparent.png'}
|
||||
className='appLogo'
|
||||
alt='appLogo'
|
||||
width={1024}
|
||||
height={1024}
|
||||
/>
|
||||
<div className='formContainer'>
|
||||
<h1 className='formTitle'>Inscription</h1>
|
||||
|
||||
<div
|
||||
role='form'
|
||||
className='form'
|
||||
>
|
||||
<div className='inputContainer'>
|
||||
<input
|
||||
ref={usernameRef}
|
||||
type='text'
|
||||
name='name'
|
||||
className='input'
|
||||
required
|
||||
/>
|
||||
<label className='inputLabel'>
|
||||
Nom d'utilisateur
|
||||
</label>
|
||||
</div>
|
||||
<div className='inputContainer'>
|
||||
<input
|
||||
ref={emailRef}
|
||||
type='email'
|
||||
name='email'
|
||||
className='input'
|
||||
required
|
||||
/>
|
||||
<label className='inputLabel'>Adresse e-mail</label>
|
||||
</div>
|
||||
<div className='inputContainer'>
|
||||
<input
|
||||
ref={passwordRef}
|
||||
type='password'
|
||||
name='password'
|
||||
className='input'
|
||||
required
|
||||
/>
|
||||
<label className='inputLabel'>Mot de passe</label>
|
||||
</div>
|
||||
<div className='inputContainer'>
|
||||
<input
|
||||
ref={confpasswordRef}
|
||||
type='password'
|
||||
name='confpassword'
|
||||
className='input'
|
||||
required
|
||||
/>
|
||||
<label className='inputLabel'>
|
||||
Confirmer le mot de passe
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className='buttonsContainer'>
|
||||
<button
|
||||
className='submitButton'
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
S'inscrire
|
||||
</button>
|
||||
<Link
|
||||
href={'/auth/login'}
|
||||
className='submitButton secondary'
|
||||
>
|
||||
Se connecter
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Register;
|
||||
@@ -0,0 +1,131 @@
|
||||
.authContainer {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100svw;
|
||||
height: 100svh;
|
||||
|
||||
& > .appLogo {
|
||||
position: absolute;
|
||||
top: 5svh;
|
||||
width: 30svw;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
& > .formContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 10px;
|
||||
padding: 30px 60px;
|
||||
width: 95svw;
|
||||
max-width: 450px;
|
||||
border: 3px solid #fefefa;
|
||||
border-radius: 7px;
|
||||
background-color: #d94253;
|
||||
|
||||
& > .formTitle {
|
||||
margin-bottom: 20px;
|
||||
font-size: 2rem;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
color: #fefefa;
|
||||
}
|
||||
|
||||
& > .form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 15px;
|
||||
|
||||
& > .inputContainer {
|
||||
position: relative;
|
||||
display: grid;
|
||||
|
||||
& > .inputLabel {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 15px;
|
||||
transform: translateY(-50%);
|
||||
padding: 5px;
|
||||
background-color: #d94253;
|
||||
color: #fefefa;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
transition: top 0.3s ease, left 0.3s ease,
|
||||
font-size 0.3s ease, transform 0.3s ease;
|
||||
}
|
||||
|
||||
& > .input {
|
||||
padding: 10px;
|
||||
border: 2px solid #fefefa;
|
||||
border-radius: 5px;
|
||||
background-color: #d94253;
|
||||
outline: none;
|
||||
font-size: 1em;
|
||||
color: #fefefa;
|
||||
|
||||
&:focus + .inputLabel {
|
||||
top: 0;
|
||||
left: 10px;
|
||||
transform: translateY(-50%);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > .forgetLink {
|
||||
position: relative;
|
||||
width: max-content;
|
||||
font-size: 0.8rem;
|
||||
color: #dff8f2;
|
||||
cursor: pointer;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 1px;
|
||||
background-color: #dff8f2;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
&:hover::after {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > .buttonsContainer {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
align-items: center;
|
||||
gap: 30px;
|
||||
margin-top: 15px;
|
||||
|
||||
& > .submitButton {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 7px 21px;
|
||||
border: 2px solid #fefefa;
|
||||
border-radius: 5px;
|
||||
background-color: #fefefa;
|
||||
font-size: 0.9rem;
|
||||
color: #d94253;
|
||||
cursor: pointer;
|
||||
|
||||
&.secondary {
|
||||
background-color: #d94253;
|
||||
color: #fefefa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,23 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
body {
|
||||
position: relative;
|
||||
width: 100svw;
|
||||
height: 100svh;
|
||||
background-color: #d94253;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const useData = () => {
|
||||
const [canUseGeolocation, setCanUseGeolocation] = useState(false);
|
||||
const [geoError, setGeoError] = useState(null);
|
||||
|
||||
const [initialState, setInitialState] = useState({
|
||||
longitude: 2.209666999999996,
|
||||
latitude: 46.232192999999995,
|
||||
zoom: 5,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if ('geolocation' in navigator == false) {
|
||||
setCanUseGeolocation(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setCanUseGeolocation(true);
|
||||
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
position => {
|
||||
setInitialState(prev => ({
|
||||
...prev,
|
||||
latitude: position.coords.latitude,
|
||||
longitude: position.coords.longitude,
|
||||
}));
|
||||
},
|
||||
error => {
|
||||
if (error.PERMISSION_DENIED) {
|
||||
setGeoError('permission_denied');
|
||||
console.warn(error.message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
initialState,
|
||||
geoError,
|
||||
canUseGeolocation,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Inter } from 'next/font/google';
|
||||
import './globals.scss';
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] });
|
||||
|
||||
export const metadata = {
|
||||
title: 'Lovemap ❤️',
|
||||
};
|
||||
|
||||
const RootLayout = ({ children }) => {
|
||||
return (
|
||||
<html lang='fr'>
|
||||
<body className={inter.className}>{children}</body>
|
||||
</html>
|
||||
);
|
||||
};
|
||||
|
||||
export default RootLayout;
|
||||
@@ -0,0 +1,64 @@
|
||||
'use client';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// Imports
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// --------------------------------------------------- Components ------------------------------------------------------
|
||||
import { DeckGL } from 'deck.gl';
|
||||
import { Map } from 'react-map-gl';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// -------------------------------------------------- Hooks & Utils ----------------------------------------------------
|
||||
import { useData } from './hooks/useData';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------- Assets & Styles ---------------------------------------------------
|
||||
import './styles.scss';
|
||||
import 'mapbox-gl/dist/mapbox-gl.css';
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
const Home = () => {
|
||||
const { canUseGeolocation, geoError, initialState } = useData();
|
||||
|
||||
if (!canUseGeolocation && !geoError) {
|
||||
return <p className='appMessage'>Chargement...</p>;
|
||||
}
|
||||
|
||||
if (!canUseGeolocation && geoError) {
|
||||
return (
|
||||
<p className='appMessage'>
|
||||
Nous avons besoin d'accéder à votre position pour pouvoir
|
||||
utiliser l'application.
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='mapContainer'>
|
||||
<DeckGL
|
||||
initialViewState={initialState}
|
||||
layers={[]}
|
||||
controller
|
||||
useDevicePixels={false}
|
||||
getCursor={({ isDragging }) =>
|
||||
isDragging ? 'grabbing' : 'grab'
|
||||
}
|
||||
>
|
||||
<Map
|
||||
logoPosition='bottom-right'
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
mapboxAccessToken={process.env.MAPBOX_TOKEN}
|
||||
mapStyle={
|
||||
'mapbox://styles/unepicier/cm0l8fydz009v01qkh9bvau16'
|
||||
}
|
||||
preserveDrawingBuffer
|
||||
></Map>
|
||||
</DeckGL>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
@@ -0,0 +1,21 @@
|
||||
.mapContainer {
|
||||
position: relative;
|
||||
width: 100svw;
|
||||
height: 100svh;
|
||||
}
|
||||
|
||||
.appMessage {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: block;
|
||||
width: 90svw;
|
||||
font-size: 2rem;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
|
||||
@media (max-width: 992px) {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user