Added map

This commit is contained in:
2024-09-03 18:18:49 +02:00
parent 282ef00aa3
commit a4d77952de
24 changed files with 8075 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
+38
View File
@@ -0,0 +1,38 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
.env
+11
View File
@@ -0,0 +1,11 @@
{
"useTabs": true,
"tabWidth": 4,
"proseWrap": "never",
"jsxSingleQuote": true,
"singleQuote": true,
"singleAttributePerLine": true,
"arrowParens": "avoid",
"trailingComma": "es5",
"semi": true
}
+1
View File
@@ -1,2 +1,3 @@
# Lovemap # Lovemap
Interactive map to keep where you have made love ❤️ Interactive map to keep where you have made love ❤️
+48
View File
@@ -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;
+7
View File
@@ -0,0 +1,7 @@
export const useActions = ({ emailRef, passwordRef }) => {
const handleSubmit = () => {};
return {
handleSubmit,
};
};
+11
View File
@@ -0,0 +1,11 @@
import { useRef } from 'react';
export const useData = () => {
const emailRef = useRef(null);
const passwordRef = useRef(null);
return {
emailRef,
passwordRef,
};
};
+88
View File
@@ -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&apos;inscrire
</Link>
</div>
</div>
</div>
);
};
export default Login;
+12
View File
@@ -0,0 +1,12 @@
export const useActions = ({
usernameRef,
emailRef,
passwordRef,
confpasswordRef,
}) => {
const handleSubmit = () => {};
return {
handleSubmit,
};
};
+15
View File
@@ -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,
};
};
+110
View File
@@ -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&apos;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&apos;inscrire
</button>
<Link
href={'/auth/login'}
className='submitButton secondary'
>
Se connecter
</Link>
</div>
</div>
</div>
);
};
export default Register;
+131
View File
@@ -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;
}
}
}
}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+23
View File
@@ -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;
}
+43
View File
@@ -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,
};
};
+18
View File
@@ -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;
+64
View File
@@ -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&apos;accéder à votre position pour pouvoir
utiliser l&apos;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;
+21
View File
@@ -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;
}
}
+7
View File
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./*"]
}
}
}
+8
View File
@@ -0,0 +1,8 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
env: {
MAPBOX_TOKEN: process.env.MAPBOX_TOKEN,
},
};
export default nextConfig;
+7392
View File
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
{
"name": "lovemap",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"deck.gl": "^9.0.28",
"mapbox-gl": "^3.6.0",
"next": "14.2.7",
"react": "^18",
"react-dom": "^18",
"react-map-gl": "^7.1.7"
},
"devDependencies": {
"eslint": "^8",
"eslint-config-next": "14.2.7",
"sass": "^1.77.8"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 425 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB