Compare commits
3 Commits
master
...
integratio
Author | SHA1 | Date |
---|---|---|
|
2207318950 | |
|
a13c507ad0 | |
|
53883f9e04 |
2
.env
2
.env
|
@ -4,4 +4,4 @@
|
||||||
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
|
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
|
||||||
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||||
|
|
||||||
DATABASE_URL="mysql://monelia:monelia@localhost:3306/monelia?schema=public"
|
DATABASE_URL="mysql://sephigame:SephEsport33!@192.168.1.26:3306/Monelia_Nails?schema=public"
|
|
@ -9,10 +9,13 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^6.6.0",
|
"@prisma/client": "^6.6.0",
|
||||||
|
"bcryptjs": "^3.0.2",
|
||||||
|
"lucide-react": "^0.511.0",
|
||||||
"next": "15.3.0",
|
"next": "15.3.0",
|
||||||
"prisma": "^6.6.0",
|
"prisma": "^6.6.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.0.0",
|
||||||
|
"slugify": "^1.6.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3",
|
"@eslint/eslintrc": "^3",
|
||||||
|
@ -2461,6 +2464,15 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/bcryptjs": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"bin": {
|
||||||
|
"bcrypt": "bin/bcrypt"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
|
@ -4826,6 +4838,15 @@
|
||||||
"loose-envify": "cli.js"
|
"loose-envify": "cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lucide-react": {
|
||||||
|
"version": "0.511.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.511.0.tgz",
|
||||||
|
"integrity": "sha512-VK5a2ydJ7xm8GvBeKLS9mu1pVK6ucef9780JVUjw6bAjJL/QXnd4Y0p7SPeOUMC27YhzNCZvm5d/QX0Tp3rc0w==",
|
||||||
|
"license": "ISC",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/math-intrinsics": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
@ -5787,6 +5808,15 @@
|
||||||
"is-arrayish": "^0.3.1"
|
"is-arrayish": "^0.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/slugify": {
|
||||||
|
"version": "1.6.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz",
|
||||||
|
"integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
|
|
|
@ -6,14 +6,18 @@
|
||||||
"dev": "next dev --turbopack",
|
"dev": "next dev --turbopack",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint",
|
||||||
|
"start:migrate:prod": "npx prisma migrate deploy && npm run start"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^6.6.0",
|
"@prisma/client": "^6.6.0",
|
||||||
|
"bcryptjs": "^3.0.2",
|
||||||
|
"lucide-react": "^0.511.0",
|
||||||
"next": "15.3.0",
|
"next": "15.3.0",
|
||||||
"prisma": "^6.6.0",
|
"prisma": "^6.6.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.0.0",
|
||||||
|
"slugify": "^1.6.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3",
|
"@eslint/eslintrc": "^3",
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
Binary file not shown.
After Width: | Height: | Size: 74 KiB |
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,179 @@
|
||||||
|
"use server"
|
||||||
|
|
||||||
|
import prisma from "@/lib/db";
|
||||||
|
import bcrypt from "bcryptjs";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import slugify from "slugify";
|
||||||
|
|
||||||
|
export async function register(formData : FormData){
|
||||||
|
//Permet de récupérer les données demandées à l'utilisateur lors de l'inscription
|
||||||
|
const {email,password,passwordRepeat} = Object.fromEntries(formData)
|
||||||
|
|
||||||
|
if(password !== passwordRepeat){
|
||||||
|
throw new Error("Le passwords ne correspond pas")
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
|
||||||
|
//Vérification du mail
|
||||||
|
const verifUser = await prisma.utilisateur.findFirst({
|
||||||
|
where : {
|
||||||
|
ut_mail : email.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(verifUser){
|
||||||
|
throw new Error("Utilisateur déjà inscrit")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//slugify de l'email
|
||||||
|
const slug = slugify(email.toString().substring(0,email.toString().indexOf("@")),{lower:true,strict:true})
|
||||||
|
|
||||||
|
//hash du mdp
|
||||||
|
const salt = await bcrypt.genSalt(10)
|
||||||
|
const hashedPassword = await bcrypt.hash(password.toString(),salt)
|
||||||
|
|
||||||
|
//creation de l'utilisateur
|
||||||
|
const result = await prisma.utilisateur.create({
|
||||||
|
data :{
|
||||||
|
ut_mail : email.toString(),
|
||||||
|
ut_mdp : hashedPassword.toString(),
|
||||||
|
ut_slug : slug
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if(result){
|
||||||
|
return {success: true}
|
||||||
|
}
|
||||||
|
throw new Error("Anomalie lors de la création du user")
|
||||||
|
|
||||||
|
}catch(err){
|
||||||
|
const error = err as Error
|
||||||
|
throw new Error(error.message || "une erreur à été rencontrée lors de la création de l'utilisateur")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function login(formData : FormData){
|
||||||
|
const {email,password} = Object.fromEntries(formData)
|
||||||
|
|
||||||
|
try{
|
||||||
|
//vérification si l'utilisateur est trouvé
|
||||||
|
const user = await prisma.utilisateur.findFirst({
|
||||||
|
where : {
|
||||||
|
ut_mail : email.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(!user){
|
||||||
|
throw new Error("Invalide crédential")
|
||||||
|
}
|
||||||
|
//vérification du mdp
|
||||||
|
const isPasswordValid = await bcrypt.compare(password.toString(), user.ut_mdp)
|
||||||
|
if(!isPasswordValid){
|
||||||
|
throw new Error("Invalide crédential")
|
||||||
|
}
|
||||||
|
|
||||||
|
//vérification si une session de connexion existe
|
||||||
|
const existingSession = await prisma.session.findFirst({
|
||||||
|
where : {
|
||||||
|
se_ut_id : user.ut_id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//vérification si la session existe mais expiré
|
||||||
|
// delete de l'enreg pour le recréer
|
||||||
|
let verifDeleteSession = false
|
||||||
|
if(existingSession && new Date() > existingSession.expireAt ){
|
||||||
|
const deleteSession = await prisma.session.delete({
|
||||||
|
where : {
|
||||||
|
se_id : existingSession.se_id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(deleteSession){
|
||||||
|
verifDeleteSession = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//vérification si une session de connexion existe et tjr actif
|
||||||
|
// on regenere le cookie ensuite
|
||||||
|
let verifValiditeSession = false
|
||||||
|
if(existingSession && new Date() < existingSession.expireAt){
|
||||||
|
verifValiditeSession = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let sessionidCreate = ""
|
||||||
|
if(!existingSession || verifDeleteSession){
|
||||||
|
const createSession = await prisma.session.create({
|
||||||
|
data : {
|
||||||
|
se_ut_id : user.ut_id,
|
||||||
|
expireAt : new Date(Date.now() + 7*24*60*60*1000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(createSession){
|
||||||
|
sessionidCreate = createSession.se_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cookieStore = await cookies()
|
||||||
|
|
||||||
|
if(sessionidCreate !== ""){
|
||||||
|
cookieStore.set("sessionId",sessionidCreate,{
|
||||||
|
httpOnly : true,
|
||||||
|
secure: process.env.NODE_ENV ==="production",
|
||||||
|
path:"/",
|
||||||
|
maxAge: 24*60*60,
|
||||||
|
sameSite: "lax"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if(verifValiditeSession && existingSession?.se_id){
|
||||||
|
cookieStore.set("sessionId",existingSession?.se_id,{
|
||||||
|
httpOnly : true,
|
||||||
|
secure: process.env.NODE_ENV ==="production",
|
||||||
|
path:"/",
|
||||||
|
maxAge: 24*60*60,
|
||||||
|
sameSite: "lax"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {success : true}
|
||||||
|
}catch(err){
|
||||||
|
const error = err as Error
|
||||||
|
throw new Error(error.message || "une erreur à été rencontrée lors de la connexion de l'utilisateur")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function verifSession(){
|
||||||
|
try{
|
||||||
|
const cookie = await cookies()
|
||||||
|
const verif = cookie.get("sessionId")
|
||||||
|
if(verif){
|
||||||
|
const verifExpireSession = await prisma.session.findUnique({
|
||||||
|
where : {
|
||||||
|
se_id : verif.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(verifExpireSession && new Date() > verifExpireSession.expireAt){
|
||||||
|
await prisma.session.delete({
|
||||||
|
where : {
|
||||||
|
se_id : verifExpireSession.se_id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return {success : false}
|
||||||
|
}else{
|
||||||
|
cookie.set("sessionId",verif.value,{
|
||||||
|
httpOnly : true,
|
||||||
|
secure: process.env.NODE_ENV ==="production",
|
||||||
|
path:"/",
|
||||||
|
maxAge: 24*60*60,
|
||||||
|
sameSite: "lax"
|
||||||
|
})
|
||||||
|
return {success : true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {success : false}
|
||||||
|
|
||||||
|
}catch(err){
|
||||||
|
const error = err as Error
|
||||||
|
throw new Error(error.message || "une erreur à été rencontrée lors de la vérification de la session")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
import prisma from "@/lib/db";
|
||||||
|
|
||||||
|
export async function getInfoUser(slug : string){
|
||||||
|
try{
|
||||||
|
const user = await prisma.utilisateur.findFirst({
|
||||||
|
where : {
|
||||||
|
ut_slug : slug
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(user){
|
||||||
|
return {success : true, user}
|
||||||
|
}
|
||||||
|
return {success : false, message : "Impossible de trouver les infos de l'utilisateur"}
|
||||||
|
}catch(err){
|
||||||
|
const error = err as Error
|
||||||
|
throw new Error(error.message || "une erreur à été rencontrée lors de la recherche de l'utilisateur")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteUser(slug : string){
|
||||||
|
try{
|
||||||
|
|
||||||
|
const user = await prisma.utilisateur.findFirst({
|
||||||
|
where : {
|
||||||
|
ut_slug : slug
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(user){
|
||||||
|
await prisma.utilisateur.delete({
|
||||||
|
where : {
|
||||||
|
ut_id : user.ut_id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return {success : true}
|
||||||
|
}
|
||||||
|
return {success : false, message : "Impossible de supprimer l'utilisateur"}
|
||||||
|
}catch(err){
|
||||||
|
const error = err as Error
|
||||||
|
throw new Error(error.message || "une erreur à été rencontrée lors suppression de l'utilisateur")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
const Footer = () => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<footer>
|
||||||
|
Footer
|
||||||
|
</footer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Footer
|
|
@ -0,0 +1,32 @@
|
||||||
|
import Image from "next/image"
|
||||||
|
import Link from "next/link"
|
||||||
|
|
||||||
|
const DesktopHeader = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="gap-4 pl-8 my-auto w-1/3 bg-text">
|
||||||
|
<div className='flex justify-self-center'>
|
||||||
|
<Image src={'/Ryo.png'} alt={"Ryo"} width={40} height={40} />
|
||||||
|
<Image src={'/Kiki.png'} alt={"Ryo"} width={40} height={40} />
|
||||||
|
</div>
|
||||||
|
<div className='flex text-xs justify-self-center'>
|
||||||
|
<span className='cursor-pointer mr-2'>Se connecter</span> · <span className='cursor-pointer ml-2'>S'inscrire</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='my-auto text-4xl logo '>
|
||||||
|
Monelia Nails
|
||||||
|
</div>
|
||||||
|
<div className='grid h-full'>
|
||||||
|
<ul className='flex gap-8 self-center justify-self-end mr-8'>
|
||||||
|
<li><Link href='/'>Accueil</Link></li>
|
||||||
|
<li><Link href='/qui-suis-je'>Qui suis-je ?</Link></li>
|
||||||
|
<li><Link href='/prestations'>Mes prestations</Link></li>
|
||||||
|
<li><Link href='/formations'>Mes formations</Link></li>
|
||||||
|
<li><Link href='/contact'>Me contacter</Link></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DesktopHeader
|
|
@ -0,0 +1,25 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState } from "react"
|
||||||
|
import DesktopHeader from "./desktop"
|
||||||
|
import MobileHeader from "./mobile"
|
||||||
|
|
||||||
|
const Header = () => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<header className='fixed bottom-0 w-screen h-[7.5vh]
|
||||||
|
tablet:h-[6.5vh] bg-(--accent)
|
||||||
|
laptop:relative laptop:block laptop:h-auto'>
|
||||||
|
<div className='hidden laptop:grid laptop:grid-cols-3 w-full'>
|
||||||
|
<DesktopHeader />
|
||||||
|
</div>
|
||||||
|
<div className='laptop:hidden grid h-full'>
|
||||||
|
<MobileHeader />
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Header
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { Home, LayoutGrid, UserRound } from "lucide-react"
|
||||||
|
import { useState } from "react"
|
||||||
|
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
id: "menu",
|
||||||
|
icon: <LayoutGrid />,
|
||||||
|
label: 'Menu'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "home",
|
||||||
|
icon: <Home />,
|
||||||
|
label: "Accueil"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "user",
|
||||||
|
icon: <UserRound />,
|
||||||
|
label: "Profil"
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
const MobileHeader = () => {
|
||||||
|
const [menuSelected, setMenuSelected] = useState<string>('menu')
|
||||||
|
const [openMenu, setOpenMenu] = useState(false)
|
||||||
|
const activeIndex = items.findIndex((item) => item.id === menuSelected);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='max-w-screen w-full grid relative grid-cols-3 self-center transition-all duration-300'>
|
||||||
|
<div
|
||||||
|
className="absolute -top-[50%] tablet:-top-[60%] left-0 w-1/3 flex justify-center transition-all duration-300 ease-in-out"
|
||||||
|
style={{
|
||||||
|
transform: `translateX(${activeIndex * 100}%)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="w-2/3 tablet:w-1/2 h-14 bg-(--accent) rounded-[100%]"></div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{items.map((item) => (
|
||||||
|
<div
|
||||||
|
key={item.id}
|
||||||
|
onClick={() => setMenuSelected(item.id)}
|
||||||
|
className="flex flex-col items-center justify-center relative"
|
||||||
|
>
|
||||||
|
<div className="text-xl">{item.icon}</div>
|
||||||
|
<span
|
||||||
|
className={`text-xs tablet:text-lg duration-300 ${menuSelected === item.id ? "text-white font-semibold" : "text-(--background)"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MobileHeader
|
|
@ -1,15 +1,35 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Gruppo&family=Monsieur+La+Doulaise&display=swap');
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400;700&family=Ephesis&family=Gruppo&family=Monsieur+La+Doulaise&display=swap');
|
||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--background: #ffffff;
|
--background: rgb(245,235,221);
|
||||||
--foreground: #171717;
|
--color-bgMenu: rgb(204, 195, 181);
|
||||||
|
--color-text: rgb(92,74,66);
|
||||||
|
--color-title: rgb(216,163,157);
|
||||||
|
--color-accent: rgb(203,174,158);
|
||||||
|
--color-buttons: rgb(200,213,193);
|
||||||
|
--color-bold: rgb(238,200,195);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--breakpoint-tablet: 768px;
|
||||||
|
--breakpoint-laptop: 1024px;
|
||||||
|
--breakpoint-desktop: 1280px;
|
||||||
|
--breakpoint-big : 1536px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--color-background: var(--background);
|
--color-background: var(--background);
|
||||||
--color-foreground: var(--foreground);
|
|
||||||
--font-sans: var(--font-geist-sans);
|
--font-sans: var(--font-geist-sans);
|
||||||
--font-mono: var(--font-geist-mono);
|
--font-mono: var(--font-geist-mono);
|
||||||
|
--text: var(--color-text);
|
||||||
|
--title: var(--color-title);
|
||||||
|
--accent: var(--color-accent);
|
||||||
|
--buttons: var(--color-buttons);
|
||||||
|
--bold: var(--color-bold);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
|
@ -22,5 +42,41 @@
|
||||||
body {
|
body {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: "Grupo", Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
b {
|
||||||
|
color : var(--color-bold)
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: var(--color-buttons);
|
||||||
|
padding: 0.5rem 2rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: var(--color-accent);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background: var(--color-menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-family: "Monsieur La Doulaise", cursive;
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-ellipse {
|
||||||
|
clip-path: ellipse(50% 34% at 50% 100%)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* FILTRES DE COULEUR */
|
||||||
|
|
||||||
|
.filterToText {
|
||||||
|
filter: brightness(0) saturate(100%) invert(28%) sepia(8%) saturate(1314%) hue-rotate(333deg) brightness(91%) contrast(83%);
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { Geist, Geist_Mono } from "next/font/google";
|
import { Geist, Geist_Mono } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
import Header from "./components/header/header";
|
||||||
|
import Footer from "./components/footer";
|
||||||
|
|
||||||
const geistSans = Geist({
|
const geistSans = Geist({
|
||||||
variable: "--font-geist-sans",
|
variable: "--font-geist-sans",
|
||||||
|
@ -13,7 +15,7 @@ const geistMono = Geist_Mono({
|
||||||
});
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Create Next App",
|
title: "Monelia Nails",
|
||||||
description: "Generated by create next app",
|
description: "Generated by create next app",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,11 +25,13 @@ export default function RootLayout({
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="fr">
|
||||||
<body
|
<body
|
||||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
className={`antialiased grid grid-rows-[auto_1fr_auto] h-screen w-screen`}
|
||||||
>
|
>
|
||||||
{children}
|
<Header />
|
||||||
|
{children}
|
||||||
|
<Footer />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|
100
src/app/page.tsx
100
src/app/page.tsx
|
@ -1,103 +1,7 @@
|
||||||
import Image from "next/image";
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
<div className="">
|
||||||
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
|
Test
|
||||||
<Image
|
|
||||||
className="dark:invert"
|
|
||||||
src="/next.svg"
|
|
||||||
alt="Next.js logo"
|
|
||||||
width={180}
|
|
||||||
height={38}
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
|
||||||
<li className="mb-2 tracking-[-.01em]">
|
|
||||||
Get started by editing{" "}
|
|
||||||
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
|
|
||||||
src/app/page.tsx
|
|
||||||
</code>
|
|
||||||
.
|
|
||||||
</li>
|
|
||||||
<li className="tracking-[-.01em]">
|
|
||||||
Save and see your changes instantly.
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
|
||||||
<a
|
|
||||||
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
|
|
||||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
className="dark:invert"
|
|
||||||
src="/vercel.svg"
|
|
||||||
alt="Vercel logomark"
|
|
||||||
width={20}
|
|
||||||
height={20}
|
|
||||||
/>
|
|
||||||
Deploy now
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
|
|
||||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Read our docs
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
|
|
||||||
<a
|
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
||||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
aria-hidden
|
|
||||||
src="/file.svg"
|
|
||||||
alt="File icon"
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
Learn
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
||||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
aria-hidden
|
|
||||||
src="/window.svg"
|
|
||||||
alt="Window icon"
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
Examples
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
||||||
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
aria-hidden
|
|
||||||
src="/globe.svg"
|
|
||||||
alt="Globe icon"
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
Go to nextjs.org →
|
|
||||||
</a>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import type { Config } from 'tailwindcss'
|
||||||
|
|
||||||
|
const config: Config = {
|
||||||
|
content: [
|
||||||
|
"./src/**/*.{js,ts,jsx,tsx}",
|
||||||
|
"./app/**/*.{js,ts,jsx,tsx}", // pour les projets Next 13+
|
||||||
|
"./pages/**/*.{js,ts,jsx,tsx}", // si tu n’es pas en app directory
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
screens: {
|
||||||
|
mobile: '640px',
|
||||||
|
tablet: '768px',
|
||||||
|
laptop: '1024px',
|
||||||
|
desktop: '1280px',
|
||||||
|
big: '1536px',
|
||||||
|
fhd: '1920px',
|
||||||
|
qhd: '2560px',
|
||||||
|
uhd: '3840px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default config
|
Loading…
Reference in New Issue