Compare commits

..

No commits in common. "a36aca1ad3eaf9f42973c66061f39f6769dba122" and "bbdbb1aec1e1a2d3cca65e32b5263a111cc16a36" have entirely different histories.

11 changed files with 165 additions and 495 deletions

View File

@ -1,195 +0,0 @@
import { onUpdateConsentCookie, onAcceptAllConsentCookie, type ConsentCookies } from "./Cookies.telefunc";
import React, { useState, useContext, createContext } from "react";
import { usePageContext } from "vike-react/usePageContext";
import { reload } from "vike/client/router";
import { Button } from "@syntax/Button";
import { toast } from "react-toastify";
import { Toggle } from "./Toggle";
import { Link } from "./Link";
export const CookiesContext = createContext<{
cookies: {
analytics: boolean;
customization: boolean;
};
setCookie: (cookieName: ConsentCookies, cookieValue: boolean) => void;
acceptAll: () => void;
isOpen: boolean;
setIsOpen: (isOpen: boolean) => void;
isSelectionOpen: boolean;
setIsSelectionOpen: (isSelectionOpen: boolean) => void;
}>({
cookies: {
analytics: false,
customization: false,
},
setCookie: (_cookieName: ConsentCookies, _cookieValue: boolean) => {},
acceptAll: () => {},
isOpen: false,
setIsOpen: () => {},
isSelectionOpen: false,
setIsSelectionOpen: () => {},
});
type CookiesContainerProps = {
children?: React.ReactNode;
};
export function CookiesContainer(props: CookiesContainerProps) {
const { cookies } = usePageContext();
const [consentCookies, setConsentCookies] = useState(cookies.consent);
const [isSelectionOpen, setIsSelectionOpen] = useState(false);
const [isOpen, setIsOpen] = useState(() => {
return !Object.keys(cookies.consent).every((value) => value);
});
const handleUpdateCookie = (cookieName: ConsentCookies, cookieValue: boolean) => {
setConsentCookies((prev) => ({
...prev,
[cookieName]: cookieValue,
}));
toast
.promise(onUpdateConsentCookie(cookieName, cookieValue), {
pending: "Mise à jour des cookies...",
success: "Cookies mis à jour !",
error: "Erreur lors de la mise à jour des cookies",
})
.then(() => {
setIsOpen(false);
reload();
});
};
const handleAcceptAll = () => {
setConsentCookies({ analytics: true, customization: true });
toast
.promise(onAcceptAllConsentCookie(), {
pending: "Acceptation des cookies...",
success: "Cookies acceptés !",
error: "Erreur lors de l'acceptation des cookies",
})
.then(() => {
setIsOpen(false);
setIsSelectionOpen(false);
reload();
});
};
return (
<CookiesContext.Provider
value={{
cookies: consentCookies,
setCookie: handleUpdateCookie,
acceptAll: handleAcceptAll,
isOpen,
setIsOpen,
isSelectionOpen,
setIsSelectionOpen,
}}
>
{props.children}
{isSelectionOpen && <CookieChoices />}
{isOpen && <CookieModal />}
</CookiesContext.Provider>
);
}
function CookieChoices() {
const cookiesContext = useContext(CookiesContext);
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-900/50 backdrop-blur-sm">
<div className="relative flex flex-col gap-2 bg-slate-50 dark:bg-slate-800 rounded-md shadow-xl w-full max-w-sm p-4">
<Button
variant="ghost"
size="sm"
className="absolute top-0 right-0"
onClick={() => cookiesContext.setIsSelectionOpen(false)}
>
Fermer
</Button>
<p className="font-display dark:text-slate-300 font-bold text-lg">Personnalisation des cookies 🍪</p>
<div className="flex flex-col gap-2 w-full items-start">
<Toggle
id="cookies-analytics"
label="Cookies d&lsquo;analyse (Umami et Google Analytics)"
checked={cookiesContext.cookies.analytics}
onChange={(checked) => cookiesContext.setCookie("analytics", checked)}
/>
<Toggle
id="cookies-customization"
label="Cookie de personnalisation (thème)"
checked={cookiesContext.cookies.customization}
onChange={(checked) => cookiesContext.setCookie("customization", checked)}
/>
</div>
</div>
</div>
);
}
function CookieModal() {
const cookiesContext = useContext(CookiesContext);
return (
<div className="flex flex-col fixed bottom-4 left-4 bg-slate-50 dark:bg-slate-800 z-50 rounded-md shadow-xl w-full max-w-sm overflow-hidden">
<Button
variant="ghost"
size="sm"
className="absolute top-0 right-0"
onClick={() => cookiesContext.setIsOpen(false)}
>
Fermer
</Button>
<div className="flex flex-col gap-2 p-4">
<p className="font-display dark:text-slate-300">
<span className="text-sm">Coucou c&apos;est nous...</span>
<br />
<span className="font-bold text-lg">les cookies ! 🍪</span>
</p>
<p className="text-slate-700 dark:text-slate-300">
On ne t&lsquo;embête pas longtemps, on te laisse même le choix <em>(si ça c&lsquo;est pas la classe 😎)</em>.
</p>
<p className="text-slate-700 dark:text-slate-300">
Si tu veux en savoir plus, tu peux consulter la page{" "}
<Link href="/politique-de-confidentialite" className="font-bold">
Politique de confidentialité
</Link>
.
</p>
</div>
<div className="grid items-center grid-cols-3 justify-between bg-slate-100 dark:bg-slate-700">
<button
className="cursor-pointer px-2 py-1 text-slate-600 dark:text-slate-300"
onClick={() => cookiesContext.setIsOpen(false)}
>
Non merci
</button>
<button
className="cursor-pointer px-2 py-1 text-slate-600 dark:text-slate-300"
onClick={() => cookiesContext.setIsSelectionOpen(true)}
>
Je choisis
</button>
<button
className="cursor-pointer px-2 py-1 font-bold text-white dark:text-black bg-violet-600 dark:bg-violet-300"
onClick={cookiesContext.acceptAll}
>
Oui, j&lsquo;ai faim !
</button>
</div>
</div>
);
}

View File

@ -1,4 +1,3 @@
import React from "react";
import clsx from "clsx"; import clsx from "clsx";
type ToggleProps = { type ToggleProps = {

View File

@ -161,7 +161,6 @@ export function Navigation({
onLinkClick?: React.MouseEventHandler<HTMLAnchorElement>; onLinkClick?: React.MouseEventHandler<HTMLAnchorElement>;
}) { }) {
const firstSections = navigation.filter((section) => section.position === "start"); const firstSections = navigation.filter((section) => section.position === "start");
const lastSections = navigation.filter((section) => section.position === "end");
const filteredSections = navigation const filteredSections = navigation
.filter((section) => section.position === "auto" || section.position === undefined) .filter((section) => section.position === "auto" || section.position === undefined)
@ -193,12 +192,6 @@ export function Navigation({
))} ))}
</li> </li>
))} ))}
<li>
<h2 className="font-display font-bold text-base text-slate-900 dark:text-white">{lastSections[0]?.type}</h2>
{lastSections.map((section) => (
<NavigationItem key={section.title} section={section} onLinkClick={onLinkClick} />
))}
</li>
</ul> </ul>
</nav> </nav>
); );

View File

@ -36,7 +36,6 @@ export default tseslint.config(
"@typescript-eslint/no-unused-vars": [1, { argsIgnorePattern: "^_" }], "@typescript-eslint/no-unused-vars": [1, { argsIgnorePattern: "^_" }],
"@typescript-eslint/no-namespace": 0, "@typescript-eslint/no-namespace": 0,
"react/react-in-jsx-scope": "warn", "react/react-in-jsx-scope": "warn",
"react/no-unescaped-entities": "off",
"react/jsx-filename-extension": [1, { extensions: [".tsx"] }], "react/jsx-filename-extension": [1, { extensions: [".tsx"] }],
}, },
}, },

View File

@ -3,7 +3,7 @@ import type { PageContext } from "vike/types";
import { getTelefuncContext } from "@/lib/getTelefuncContext"; import { getTelefuncContext } from "@/lib/getTelefuncContext";
import { CookieParser } from "@/services/CookieParser"; import { CookieParser } from "@/services/CookieParser";
export type ConsentCookies = keyof PageContext["cookies"]["consent"]; type ConsentCookies = keyof PageContext["cookies"]["consent"];
export async function onUpdateConsentCookie(cookieName: ConsentCookies, cookieValue: boolean) { export async function onUpdateConsentCookie(cookieName: ConsentCookies, cookieValue: boolean) {
const context = getTelefuncContext(); const context = getTelefuncContext();

View File

@ -1,13 +1,17 @@
import { CookiesContainer } from "@/components/common/Cookies"; import { onUpdateConsentCookie, onAcceptAllConsentCookie } from "./LayoutDefault.telefunc";
import { MobileNavigation } from "@syntax/MobileNavigation"; import { MobileNavigation } from "@syntax/MobileNavigation";
import { usePageContext } from "vike-react/usePageContext"; import { usePageContext } from "vike-react/usePageContext";
import { ThemeProvider } from "@/providers/ThemeProvider"; import { ThemeProvider } from "@/providers/ThemeProvider";
import { ToastContainer, toast } from "react-toastify";
import { ThemeSelector } from "@syntax/ThemeSelector"; import { ThemeSelector } from "@syntax/ThemeSelector";
import { Button } from "@/components/syntax/Button";
import { Toggle } from "@/components/common/Toggle";
import { clientOnly } from "vike-react/clientOnly"; import { clientOnly } from "vike-react/clientOnly";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { ToastContainer } from "react-toastify";
import { Navigation } from "@syntax/Navigation"; import { Navigation } from "@syntax/Navigation";
import { Link } from "@/components/common/Link"; import { Link } from "@/components/common/Link";
import { navigation } from "@/lib/navigation";
import { reload } from "vike/client/router";
import { Hero } from "@syntax/Hero"; import { Hero } from "@syntax/Hero";
import { Logo } from "@syntax/Logo"; import { Logo } from "@syntax/Logo";
import clsx from "clsx"; import clsx from "clsx";
@ -77,6 +81,141 @@ function Header() {
); );
} }
function CookieModal() {
const { cookies } = usePageContext();
const [consentCookies, setConsentCookies] = useState(cookies.consent);
const [isSelectionOpen, setIsSelectionOpen] = useState(false);
const [isOpen, setIsOpen] = useState(() => {
return Object.keys(cookies.consent).every((value) => value);
});
if (isSelectionOpen) {
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-900/50 backdrop-blur-sm">
<div className="relative flex flex-col gap-2 bg-slate-50 dark:bg-slate-800 rounded-md shadow-xl w-full max-w-sm p-4">
<Button
variant="ghost"
size="sm"
className="absolute top-0 right-0"
onClick={() => setIsSelectionOpen(false)}
>
Fermer
</Button>
<p className="font-display dark:text-slate-300 font-bold text-lg">Personnalisation des cookies 🍪</p>
<div className="flex flex-col gap-2 w-full items-start">
<Toggle
id="cookies-analytics"
label="Cookies d'analyse (Umami et Google Analytics)"
checked={consentCookies.analytics}
onChange={(checked) => {
setConsentCookies({ ...consentCookies, analytics: checked });
toast
.promise(onUpdateConsentCookie("analytics", checked), {
pending: "Mise à jour des cookies...",
success: "Cookies mis à jour !",
error: "Erreur lors de la mise à jour des cookies.",
})
.finally(reload);
}}
/>
<Toggle
id="cookies-customization"
label="Cookie de personnalisation (thème)"
checked={consentCookies.customization}
onChange={(checked) => {
setConsentCookies({ ...consentCookies, analytics: checked });
toast
.promise(onUpdateConsentCookie("customization", checked), {
pending: "Mise à jour des cookies...",
success: "Cookies mis à jour !",
error: "Erreur lors de la mise à jour des cookies.",
})
.then((data) => {
setConsentCookies({ ...consentCookies, [data.cookieName]: data.cookieValue });
reload();
});
}}
/>
</div>
</div>
</div>
);
}
if (!isOpen) return null;
return (
<div className="flex flex-col fixed bottom-4 left-4 bg-slate-50 dark:bg-slate-800 z-50 rounded-md shadow-xl w-full max-w-sm overflow-hidden">
<Button variant="ghost" size="sm" className="absolute top-0 right-0" onClick={() => setIsOpen(false)}>
Fermer
</Button>
<div className="flex flex-col gap-2 p-4">
<p className="font-display dark:text-slate-300">
<span className="text-sm">Coucou c'est nous...</span>
<br />
<span className="font-bold text-lg">les cookies ! 🍪</span>
</p>
<p className="text-slate-700 dark:text-slate-300">
On ne t'embête pas longtemps, on te laisse même le choix <em>(si ça c'est pas la classe 😎)</em>.
</p>
<p className="text-slate-700 dark:text-slate-300">
Si tu veux en savoir plus, tu peux consulter la page{" "}
<Link href="/politique-de-confidentialite" className="font-bold">
Politique de confidentialité
</Link>
.
</p>
</div>
<div className="grid items-center grid-cols-3 justify-between bg-slate-100 dark:bg-slate-700">
<button
className="cursor-pointer px-2 py-1 text-slate-600 dark:text-slate-300"
onClick={() => setIsOpen(false)}
>
Non merci
</button>
<button
className="cursor-pointer px-2 py-1 text-slate-600 dark:text-slate-300"
onClick={() => setIsSelectionOpen(true)}
>
Je choisis
</button>
<button
className="cursor-pointer px-2 py-1 font-bold text-white dark:text-black bg-violet-600 dark:bg-violet-300"
onClick={() => {
setConsentCookies({ analytics: true, customization: true });
toast
.promise(onAcceptAllConsentCookie(), {
pending: "Mise à jour des cookies...",
success: "Cookies mis à jour !",
error: "Erreur lors de la mise à jour des cookies.",
})
.then(() => {
setIsOpen(false);
setIsOpen(false);
reload();
});
}}
>
Oui, j'ai faim !
</button>
</div>
</div>
);
}
function Footer() { function Footer() {
return ( return (
<footer className="bg-slate-50 dark:bg-slate-950 text-slate-700 dark:text-slate-200"> <footer className="bg-slate-50 dark:bg-slate-950 text-slate-700 dark:text-slate-200">
@ -89,7 +228,7 @@ function Footer() {
<p> <p>
Plateforme de ressources et documentations synthétiques et concises, conçue pour les développeurs ou Plateforme de ressources et documentations synthétiques et concises, conçue pour les développeurs ou
passionnés de l&lsquo;informatique en quête de savoir. passionnés de l'informatique en quête de savoir.
</p> </p>
</section> </section>
@ -118,29 +257,29 @@ export default function DefaultLayout({ children }: { children: React.ReactNode
const isHomePage = urlPathname === "/"; const isHomePage = urlPathname === "/";
return ( return (
<CookiesContainer> <ThemeProvider defaultTheme={cookies.settings.theme}>
<ThemeProvider defaultTheme={cookies.settings.theme}> <CookieModal />
<div className="flex w-full flex-col font-sans">
<Header />
{isHomePage && <Hero />} <div className="flex w-full flex-col font-sans">
<Header />
<div className="relative mx-auto w-full flex max-w-8xl flex-auto justify-center sm:px-2 lg:px-8 xl:px-12"> {isHomePage && <Hero />}
<div className="hidden lg:relative lg:block lg:flex-none">
<div className="absolute inset-y-0 right-0 w-[50vw] bg-slate-50 dark:hidden" /> <div className="relative mx-auto w-full flex max-w-8xl flex-auto justify-center sm:px-2 lg:px-8 xl:px-12">
<div className="absolute top-16 right-0 bottom-0 hidden h-12 w-px bg-linear-to-t from-slate-800 dark:block" /> <div className="hidden lg:relative lg:block lg:flex-none">
<div className="absolute top-28 right-0 bottom-0 hidden w-px bg-slate-800 dark:block" /> <div className="absolute inset-y-0 right-0 w-[50vw] bg-slate-50 dark:hidden" />
<div className="sticky top-[4.75rem] -ml-0.5 h-[calc(100vh-4.75rem)] w-64 overflow-x-hidden overflow-y-auto py-16 pr-8 pl-0.5 xl:w-72 xl:pr-16"> <div className="absolute top-16 right-0 bottom-0 hidden h-12 w-px bg-linear-to-t from-slate-800 dark:block" />
<Navigation /> <div className="absolute top-28 right-0 bottom-0 hidden w-px bg-slate-800 dark:block" />
</div> <div className="sticky top-[4.75rem] -ml-0.5 h-[calc(100vh-4.75rem)] w-64 overflow-x-hidden overflow-y-auto py-16 pr-8 pl-0.5 xl:w-72 xl:pr-16">
<Navigation />
</div> </div>
{children}
</div> </div>
{children}
<Footer />
</div> </div>
<ToastContainer />
</ThemeProvider> <Footer />
</CookiesContainer> </div>
<ToastContainer />
</ThemeProvider>
); );
} }

View File

@ -2,13 +2,12 @@ const navigationsTypes = {
GLOBAL: "👋 Général", GLOBAL: "👋 Général",
CERTIFICATIONS: "🎓 Certifications", CERTIFICATIONS: "🎓 Certifications",
DOCUMENTATIONS: "📚 Documentations", DOCUMENTATIONS: "📚 Documentations",
OTHER: "🔗 Autres",
}; };
export type NavigationSection = { export type NavigationSection = {
title: string; title: string;
type: (typeof navigationsTypes)[keyof typeof navigationsTypes]; type: (typeof navigationsTypes)[keyof typeof navigationsTypes];
position: "start" | "end" | "auto"; position: "start" | "auto";
links: NavigationLink[]; links: NavigationLink[];
}; };
@ -48,15 +47,6 @@ export const navigation: NavigationSection[] = [
{ title: "Partages et réutilisations", href: "/docs/communaute/partages", subitems: [] }, { title: "Partages et réutilisations", href: "/docs/communaute/partages", subitems: [] },
], ],
}, },
{
title: "Légal",
type: navigationsTypes.OTHER,
position: "end",
links: [
{ title: "Mentions légales", href: "/mentions-legales", subitems: [] },
{ title: "Politique de confidentialité", href: "/politique-de-confidentialite", subitems: [] },
],
},
{ {
title: "Développeur Web et Web Mobile", title: "Développeur Web et Web Mobile",
type: navigationsTypes.CERTIFICATIONS, type: navigationsTypes.CERTIFICATIONS,

View File

@ -1,52 +0,0 @@
import React from "react";
export function Page() {
return (
<div className="flex flex-col gap-4 p-4 text-slate-700 dark:text-slate-300">
<h1 className="font-display text-3xl tracking-tight text-slate-900 dark:text-white">Mentions légales</h1>
<section>
<h2 className="font-display text-xl text-slate-900 dark:text-slate-100">Éditeur du site</h2>
<p>
<span className="font-bold">Nom :</span> <strong className="font-normal">Gauthier Daniels</strong>
</p>
<p>
<span className="font-bold">Adresse physique :</span>{" "}
<strong className="font-normal">689 Chemin Latéral, 45240 La Ferté Saint-Aubin</strong>
</p>
<p>
<span className="font-bold">Adresse email :</span>{" "}
<strong className="font-normal">gauthier@gauthierdaniels.fr</strong>
</p>
<p>
<span className="font-bold">Téléphone :</span> <strong className="font-normal">+33 6 52 84 92 41</strong>
</p>
</section>
<section>
<h2 className="font-display text-xl text-slate-900 dark:text-slate-100">Directeur de la publication</h2>
<p>
<span className="font-bold">Nom :</span> <strong className="font-normal">Gauthier Daniels</strong>
</p>
<p>
<span className="font-bold">Adresse email :</span>{" "}
<strong className="font-normal">gauthier@gauthierdaniels.fr</strong>
</p>
</section>
<section>
<h2 className="font-display text-xl text-slate-900 dark:text-slate-100">Hébergement du site</h2>
<p>
<span className="font-bold">Nom :</span> <strong className="font-normal">Infomaniak Network SA</strong>
</p>
<p>
<span className="font-bold">Site internet :</span> <strong className="font-normal">www.infomaniak.com</strong>
</p>
<p>
<span className="font-bold">Adresse physique :</span>{" "}
<strong className="font-normal">Rue Eugène Marziano 25, 1227 Les Acacias (GE), Suisse</strong>
</p>
</section>
</div>
);
}

View File

@ -1,189 +1,3 @@
import { CookiesContext } from "@/components/common/Cookies";
import { Button } from "@/components/syntax/Button";
import { Link } from "@/components/common/Link";
import React, { useContext } from "react";
export function Page() { export function Page() {
const { setIsOpen } = useContext(CookiesContext); return <div>Rédaction en cours</div>;
return (
<div className="flex flex-col gap-4 p-4 text-slate-700 dark:text-slate-300">
<h1 className="font-display text-3xl tracking-tight text-slate-900 dark:text-white">
Politique de confidentialité
</h1>
<section className="flex flex-col gap-2">
<h2 className="font-display text-xl text-slate-900 dark:text-slate-100">1. Introduction</h2>
<p>
Sur <strong>Memento Dev</strong>, qui est un site à but de documentation, je prends très au sérieux la
protection de votre vie privée et de vos données personnelles.
</p>
<p>
Cette politique de confidentialité explique comment je collecte, utilise et protège les informations des
utilisateurs de ce site.
</p>
</section>
<section className="flex flex-col gap-2">
<h2 className="font-display text-xl text-slate-900 dark:text-slate-100">2. Outils externes</h2>
<p>
Mon site ne collecte aucune donnée personnelle de manière directe. Cependant, j'utilise des outils externes
pour améliorer votre expérience utilisateur et analyser l'utilisation du site.
</p>
<section className="ml-4">
<h3 className="font-display text-lg text-slate-900 dark:text-slate-100">a. Google Analytics</h3>
<p>
J'utilise <strong>Google Analytics</strong> pour analyser le trafic et l'utilisation de mon site. Les
données collectées par Google Analytics sont anonymisées et ne sont pas partagées avec des tiers.
</p>
</section>
<section className="ml-4">
<h3 className="font-display text-lg text-slate-900 dark:text-slate-100">b. Umami</h3>
<p>
<strong>Umami</strong> est un autre outil d'analyse que j'utilise pour comprendre comment les visiteurs
interagissent avec mon site. Comme <strong>Google Analytics</strong>, les données collectées sont
anonymisées et ne sont pas tranmises à des tiers.
</p>
</section>
<section className="ml-4">
<h3 className="font-display text-lg text-slate-900 dark:text-slate-100">c. Cookie "theme"</h3>
<p>
J'utilise et dépose un cookie nommé "theme" pour mémoriser votre préférence de thème (clair ou sombre). Ce
cookie est utilisé uniquement pour personnaliser votre expérience utilisateur et n'est pas utilisé à des
fins de suivi ou de marketing.
</p>
</section>
</section>
<section className="flex flex-col gap-2">
<h2 className="font-display text-xl text-slate-900 dark:text-slate-100">3. Cookies</h2>
<p>
Ce site utilise des cookies pour améliorer votre expérience utilisateur et analyser l'utilisation du site. Les
cookies sont de petits fichiers texte stockés sur votre appareil lorsque vous visitez un site web. Ils
permettent de mémoriser vos préférences et d'analyser le trafic du site.
</p>
<p>
Vous pouvez gérer vos préférences de cookies directement via les paramètres de votre navigateur. La plupart
des navigateurs vous permettent de refuser ou de supprimer les cookies. Cependant, cela peut affecter votre
expérience sur le site et certaines fonctionnalités peuvent ne pas fonctionner correctement (comme la
personnalisation du thème par exemple).
</p>
<p>
Pour reconfigurer les cookies, vous pouvez appuyer sur le bouton "Paramétrer les cookies" à la suite de ce
paragraphe.
</p>
<Button variant="secondary" className="w-max max-w-full" onClick={() => setIsOpen(true)}>
Paramétrer les cookies
</Button>
<p>
Pour plus d'informations sur la gestion des cookies, vous pouvez consulter la documentation de votre
navigateur. Voici quelques liens utiles :
</p>
<ul className="list-disc pl-4">
<li>
<Link
href="https://support.google.com/chrome/answer/95647?hl=fr"
className="text-violet-500 dark:text-violet-400"
>
Google Chrome
</Link>
</li>
<li>
<Link
href="https://support.mozilla.org/fr/kb/activer-desactiver-cookies"
className="text-violet-500 dark:text-violet-400"
>
Mozilla Firefox
</Link>
</li>
<li>
<Link
href="https://support.microsoft.com/fr-fr/help/278835/how-to-delete-cookie-files-in-internet-explorer"
className="text-violet-500 dark:text-violet-400"
>
Internet Explorer
</Link>
</li>
<li>
<Link href="https://support.apple.com/fr-fr/HT201265" className="text-violet-500 dark:text-violet-400">
Safari
</Link>
</li>
<li>
<Link
href="https://support.microsoft.com/fr-fr/help/278835/how-to-delete-cookie-files-in-internet-explorer"
className="text-violet-500 dark:text-violet-400"
>
Microsoft Edge
</Link>
</li>
</ul>
</section>
<section className="flex flex-col gap-2">
<h2 className="font-display text-xl text-slate-900 dark:text-slate-100">4. Utilisation des données</h2>
<p>
Les données collectées par les outils d'analyse sont utilisées uniquement pour améliorer le site Memento Dev
et comprendre comment les visiteurs l'utilisent. Je n'utilise pas ces données à des fins commerciales ou pour
cibler des publicités.
</p>
</section>
<section className="flex flex-col gap-2">
<h2 className="font-display text-xl text-slate-900 dark:text-slate-100">5. Protection des données</h2>
<p>
Les données collectées par <strong>Google Analytics</strong> et <strong>Umami</strong> sont anonymisées et
stockées de manière sécurisée par ces services. Je ne stocke aucune donnée personnelle sur mes propres
serveurs. Pour plus d'informations sur la manière dont ces services protègent vos données, veuillez consulter
leurs politiques de confidentialité respectives.
</p>
</section>
<section className="flex flex-col gap-2">
<h2 className="font-display text-xl text-slate-900 dark:text-slate-100">6. Vos droits</h2>
<p>
Étant donné que je ne stocke aucune donnée personnelle, je ne suis pas en mesure de répondre aux demandes
d'accès, de rectification ou de suppression de données personnelles. Cependant, vous pouvez gérer vos
préférences de cookies directement via les paramètres de votre navigateur. Pour toute question concernant vos
droits, veuillez me contacter à <strong>gauthier@gauthierdaniels.fr</strong>.
</p>
</section>
<section className="flex flex-col gap-2">
<h2 className="font-display text-xl text-slate-900 dark:text-slate-100">
7. Modifications de la Politique de Confidentialité
</h2>
<p>
Je me réserve le droit de modifier cette politique de confidentialité à tout moment. Les modifications seront
publiées sur cette page et entreront en vigueur immédiatement. Je vous encourage à consulter régulièrement
cette page pour rester informé de mes pratiques en matière de confidentialité.
</p>
</section>
<section className="flex flex-col gap-2">
<h2 className="font-display text-xl text-slate-900 dark:text-slate-100">8. Contact</h2>
<p>
Si vous avez des questions ou des préoccupations concernant ma politique de confidentialité, veuillez me
contacter à l'adresse suivante : <strong>gauthier@gauthierdaniels.fr</strong>.
</p>
</section>
</div>
);
} }

View File

@ -1,13 +0,0 @@
import type { Theme } from "@/contexts/ThemeContext";
import { getTelefuncContext } from "@/lib/getTelefuncContext";
import { CookieParser } from "@/services/CookieParser";
export async function onUpdateThemeCookie(value: Theme) {
const context = getTelefuncContext();
const { reply } = context;
CookieParser.set(reply, "theme", value, 365);
return { ok: true, message: "Updated theme cookie", value };
}

View File

@ -1,8 +1,6 @@
import { onUpdateThemeCookie } from "@/providers/ThemeProvider.telefunc";
import { ThemeContext, type Theme } from "@/contexts/ThemeContext"; import { ThemeContext, type Theme } from "@/contexts/ThemeContext";
import { usePageContext } from "vike-react/usePageContext"; import { usePageContext } from "vike-react/usePageContext";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { toast } from "react-toastify";
type ThemeProviderProps = { type ThemeProviderProps = {
children: React.ReactNode; children: React.ReactNode;
@ -20,9 +18,7 @@ export function ThemeProvider(props: ThemeProviderProps) {
rootElement.classList.toggle("light", theme === "light"); rootElement.classList.toggle("light", theme === "light");
if (cookies.consent.customization) { if (cookies.consent.customization) {
onUpdateThemeCookie(theme).catch(() => { // TODO: update the theme in the cookies
toast.error("Erreur lors de la mise à jour du cookie de thème");
});
} }
}, [theme]); }, [theme]);