Refactor Docker setup, enhance README, add legal pages, and implement site footer

This commit is contained in:
Puechberty Arthur
2026-04-01 22:58:00 +02:00
parent 9d6ac9b46d
commit 19652d5fb9
11 changed files with 537 additions and 53 deletions
+93
View File
@@ -0,0 +1,93 @@
import Link from "next/link";
const navigationLinks = [
{ href: "/", label: "Accueil" },
{ href: "/mentions-legales", label: "Mentions légales" },
{ href: "/confidentialite", label: "Confidentialité" },
];
const contactLinks = [
{ href: "https://contact.arthurp.fr", label: "contact.arthurp.fr", external: true },
{ href: "mailto:contact@arthurp.fr", label: "contact@arthurp.fr", external: true },
];
export default function SiteFooter() {
const year = new Date().getFullYear();
return (
<footer className="site-footer" aria-label="Pied de page">
<div className="site-footer-inner">
<div className="site-footer-brand">
<div className="site-footer-logo">
<img
className="site-footer-mark"
src="/icon.svg"
alt=""
aria-hidden="true"
width={34}
height={34}
/>
<span>BlocNote</span>
</div>
<p className="site-footer-description">
BlocNote est un bloc-notes Markdown rapide, auto-hébergé et pensé pour écrire sans friction, organiser ses idées et garder le contrôle sur ses données.
</p>
<div className="site-footer-badges">
<span className="site-footer-badge">Auto-hébergé sur Proxmox</span>
<span className="site-footer-badge">Fait avec </span>
</div>
</div>
<nav className="site-footer-column" aria-label="Navigation du site">
<h2 className="site-footer-heading">Navigation</h2>
<div className="site-footer-links">
{navigationLinks.map((link) => (
<Link key={link.href} href={link.href} className="site-footer-link">
{link.label}
</Link>
))}
</div>
</nav>
<div className="site-footer-column">
<h2 className="site-footer-heading">Contact</h2>
<div className="site-footer-links">
{contactLinks.map((link) =>
link.external ? (
<a
key={link.href}
href={link.href}
className="site-footer-link site-footer-link-muted"
target="_blank"
rel="noreferrer"
>
{link.label}
</a>
) : (
<Link key={link.href} href={link.href} className="site-footer-link site-footer-link-muted">
{link.label}
</Link>
)
)}
</div>
</div>
<div className="site-footer-column">
<h2 className="site-footer-heading">Service</h2>
<div className="site-footer-links">
<span className="site-footer-link site-footer-link-muted">Edition Markdown</span>
<span className="site-footer-link site-footer-link-muted">Sauvegarde locale</span>
<span className="site-footer-link site-footer-link-muted">Export et recherche</span>
</div>
</div>
</div>
<div className="site-footer-bottom">
<span>
© {year} <strong>BlocNote</strong>. Tous droits réservés.
</span>
<span>Un outil sobre pour écrire vite, garder ses notes et rester indépendant.</span>
</div>
</footer>
);
}
+56
View File
@@ -0,0 +1,56 @@
import type { Metadata } from "next";
import Link from "next/link";
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://blocnote.arthurp.fr";
export const metadata: Metadata = {
title: "Confidentialité",
description: "Politique de confidentialité de BlocNote.",
alternates: {
canonical: `${siteUrl}/confidentialite`,
},
};
export default function ConfidentialitePage() {
return (
<main className="legal-page">
<div className="legal-page-hero">
<span className="legal-page-kicker">Vie privée</span>
<h1 className="legal-page-title">Confidentialité</h1>
<p className="legal-page-intro">
BlocNote est conçu pour garder les notes localement dans le navigateur et éviter la collecte de données inutile.
</p>
</div>
<div className="legal-page-grid">
<section className="legal-card">
<h2>Stockage des notes</h2>
<p>
Les notes sont enregistrées dans le navigateur via <Link className="legal-page-link" href="/">localStorage</Link>. Elles ne sont pas envoyées à un serveur BlocNote pour la synchronisation.
</p>
</section>
<section className="legal-card">
<h2>Données collectées</h2>
<p>
L'application n'exige pas de compte utilisateur. Les contenus créés restent sous le contrôle direct de la personne qui utilise le site.
</p>
</section>
<section className="legal-card">
<h2>Partage et support</h2>
<p>
Si vous souhaitez signaler un souci ou poser une question liée à la confidentialité, contactez <a className="legal-page-link" href="https://contact.arthurp.fr" target="_blank" rel="noreferrer">contact.arthurp.fr</a> ou <a className="legal-page-link" href="mailto:contact@arthurp.fr">contact@arthurp.fr</a>.
</p>
</section>
<section className="legal-card">
<h2>Évolution</h2>
<p>
Cette page peut évoluer si le fonctionnement technique du service change. La version la plus récente reste celle publiée sur le site.
</p>
</section>
</div>
</main>
);
}
+232 -2
View File
@@ -64,17 +64,25 @@
}
html, body {
height: 100%;
overflow: hidden;
min-height: 100%;
}
body {
font-family: var(--font-sans);
background: var(--bg-primary);
color: var(--text-primary);
overflow-x: hidden;
overflow-y: auto;
transition: background var(--transition), color var(--transition);
}
.site-shell {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
}
/* ===== Layout ===== */
.app-container {
display: flex;
@@ -82,6 +90,200 @@ body {
overflow: hidden;
}
/* ===== Site Footer ===== */
.site-footer {
border-top: 1px solid var(--border-color);
background:
radial-gradient(circle at top left, rgba(59, 130, 246, 0.14), transparent 34%),
linear-gradient(180deg, var(--bg-secondary), var(--bg-primary));
padding: 40px 24px 28px;
}
.site-footer-inner {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
gap: 28px;
}
.site-footer-brand {
display: flex;
flex-direction: column;
gap: 16px;
}
.site-footer-logo {
display: inline-flex;
align-items: center;
gap: 10px;
font-size: 22px;
font-weight: 700;
letter-spacing: -0.4px;
}
.site-footer-mark {
display: block;
width: 34px;
height: 34px;
border-radius: 10px;
}
.site-footer-description {
max-width: 34rem;
font-size: 15px;
line-height: 1.7;
color: var(--text-secondary);
}
.site-footer-badges {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.site-footer-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 12px;
border: 1px solid var(--border-color);
border-radius: 999px;
background: var(--bg-primary);
color: var(--text-secondary);
font-size: 12px;
}
.site-footer-column {
display: flex;
flex-direction: column;
gap: 14px;
}
.site-footer-heading {
font-size: 13px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-tertiary);
}
.site-footer-links {
display: flex;
flex-direction: column;
gap: 10px;
}
.site-footer-link {
color: var(--text-primary);
text-decoration: none;
font-size: 15px;
line-height: 1.5;
transition: color var(--transition);
}
.site-footer-link:hover {
color: var(--accent);
}
.site-footer-link-muted {
color: var(--text-secondary);
}
.site-footer-bottom {
max-width: 1200px;
margin: 28px auto 0;
padding-top: 20px;
border-top: 1px solid var(--border-light);
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
color: var(--text-tertiary);
font-size: 13px;
}
.site-footer-bottom strong {
color: var(--text-primary);
}
.legal-page {
flex: 1;
width: 100%;
max-width: 1100px;
margin: 0 auto;
padding: 80px 24px 96px;
}
.legal-page-hero {
display: flex;
flex-direction: column;
gap: 14px;
max-width: 46rem;
margin-bottom: 32px;
}
.legal-page-kicker {
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--accent);
}
.legal-page-title {
font-size: clamp(2rem, 4vw, 3.2rem);
line-height: 1.05;
letter-spacing: -0.05em;
}
.legal-page-intro {
font-size: 18px;
line-height: 1.7;
color: var(--text-secondary);
}
.legal-page-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 18px;
}
.legal-card {
padding: 24px;
border: 1px solid var(--border-color);
border-radius: var(--radius-lg);
background: linear-gradient(180deg, var(--bg-secondary), var(--bg-primary));
box-shadow: var(--shadow-sm);
}
.legal-card h2 {
margin-bottom: 12px;
font-size: 20px;
letter-spacing: -0.02em;
}
.legal-card p,
.legal-card li {
font-size: 15px;
line-height: 1.7;
color: var(--text-secondary);
}
.legal-card ul {
padding-left: 18px;
}
.legal-page-link {
color: var(--accent);
text-decoration: none;
}
.legal-page-link:hover {
text-decoration: underline;
}
/* ===== Loading ===== */
.loading-screen {
display: flex;
@@ -898,6 +1100,26 @@ body {
.preview-pane {
padding: 14px 16px;
}
.site-footer {
padding: 32px 20px 24px;
}
.site-footer-inner {
grid-template-columns: 1fr 1fr;
}
.site-footer-brand {
grid-column: 1 / -1;
}
.legal-page {
padding: 64px 20px 88px;
}
.legal-page-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
@@ -913,6 +1135,14 @@ body {
width: 48px;
min-width: 48px;
}
.site-footer-inner {
grid-template-columns: 1fr;
}
.site-footer-bottom {
align-items: flex-start;
}
}
/* ===== Accessibility ===== */
+6 -1
View File
@@ -1,6 +1,7 @@
import type { Metadata, Viewport } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import SiteFooter from "./components/SiteFooter";
const geistSans = Geist({
variable: "--font-geist-sans",
@@ -95,6 +96,7 @@ export const metadata: Metadata = {
},
icons: {
icon: [
{ url: "/icon.svg", type: "image/svg+xml" },
{ url: "/favicon.ico", sizes: "any" },
{ url: "/icon-192.png", sizes: "192x192", type: "image/png" },
{ url: "/icon-512.png", sizes: "512x512", type: "image/png" },
@@ -151,7 +153,10 @@ export default function RootLayout({
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<a href="#main-content" className="skip-to-content">Aller au contenu principal</a>
{children}
<div className="site-shell">
{children}
<SiteFooter />
</div>
</body>
</html>
);
+56
View File
@@ -0,0 +1,56 @@
import type { Metadata } from "next";
import Link from "next/link";
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://blocnote.arthurp.fr";
export const metadata: Metadata = {
title: "Mentions légales",
description: "Mentions légales du site BlocNote.",
alternates: {
canonical: `${siteUrl}/mentions-legales`,
},
};
export default function MentionsLegalesPage() {
return (
<main className="legal-page">
<div className="legal-page-hero">
<span className="legal-page-kicker">Informations légales</span>
<h1 className="legal-page-title">Mentions légales</h1>
<p className="legal-page-intro">
Les informations ci-dessous résument l'éditeur du site, les contacts utiles et le cadre technique de BlocNote.
</p>
</div>
<div className="legal-page-grid">
<section className="legal-card">
<h2>Éditeur du site</h2>
<p>
BlocNote est édité par Arthur P. Le site est accessible à l'adresse <Link className="legal-page-link" href="/">blocnote.arthurp.fr</Link>.
</p>
</section>
<section className="legal-card">
<h2>Contact</h2>
<p>
Pour toute demande, utilisez <a className="legal-page-link" href="https://contact.arthurp.fr" target="_blank" rel="noreferrer">contact.arthurp.fr</a> ou écrivez à <a className="legal-page-link" href="mailto:contact@arthurp.fr">contact@arthurp.fr</a>.
</p>
</section>
<section className="legal-card">
<h2>Hébergement</h2>
<p>
Le site est auto-hébergé sur Proxmox, avec une mise en production Docker pour servir l'application Next.js.
</p>
</section>
<section className="legal-card">
<h2>Propriété intellectuelle</h2>
<p>
Le contenu, l'identité visuelle et le code source de BlocNote restent protégés par le droit d'auteur. Toute réutilisation doit respecter les droits du titulaire.
</p>
</section>
</div>
</main>
);
}
+12
View File
@@ -9,5 +9,17 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: "weekly",
priority: 1.0,
},
{
url: `${siteUrl}/mentions-legales`,
lastModified: new Date(),
changeFrequency: "yearly",
priority: 0.3,
},
{
url: `${siteUrl}/confidentialite`,
lastModified: new Date(),
changeFrequency: "yearly",
priority: 0.3,
},
];
}