mirror of
https://github.com/arthur-pbty/clock.git
synced 2026-06-03 15:07:20 +02:00
feat: refactor Docker setup, enhance README, and add legal pages with environment variable support
This commit is contained in:
+22
-24
@@ -1,34 +1,32 @@
|
||||
# === Étape 1 : Build ===
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
FROM node:22-alpine AS base
|
||||
WORKDIR /app
|
||||
ARG SITE_URL=https://clock.arthurp.fr
|
||||
ARG CONTACT_URL=https://contact.arthurp.fr
|
||||
ARG CONTACT_EMAIL=contact@arthurp.fr
|
||||
ENV SITE_URL=${SITE_URL}
|
||||
ENV CONTACT_URL=${CONTACT_URL}
|
||||
ENV CONTACT_EMAIL=${CONTACT_EMAIL}
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# Copier les fichiers de dépendances pour profiter du cache Docker
|
||||
COPY package*.json ./
|
||||
|
||||
# Installer uniquement ce qu'il faut pour le build
|
||||
FROM base AS deps
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
|
||||
# Copier tout le code
|
||||
FROM deps AS dev
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
CMD ["npm", "run", "dev", "--", "--hostname", "0.0.0.0", "--port", "3000"]
|
||||
|
||||
# Build Next.js pour la production
|
||||
FROM deps AS builder
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# === Étape 2 : Runner léger ===
|
||||
FROM node:20-alpine AS runner
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copier uniquement ce qui est nécessaire pour la prod
|
||||
COPY --from=builder /app/package*.json ./
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/.next ./.next
|
||||
COPY --from=builder /app/public ./public
|
||||
|
||||
# Mode production
|
||||
FROM base AS runner
|
||||
ENV NODE_ENV=production
|
||||
ENV HOSTNAME=0.0.0.0
|
||||
ENV PORT=3000
|
||||
COPY --from=builder /app/.next/standalone ./
|
||||
COPY --from=builder /app/.next/static ./.next/static
|
||||
COPY --from=builder /app/public ./public
|
||||
EXPOSE 3000
|
||||
|
||||
# Lancer le serveur Next.js
|
||||
CMD ["npm", "start"]
|
||||
CMD ["node", "server.js"]
|
||||
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2026 Arthur
|
||||
|
||||
Licence pour tous les projets Arthur
|
||||
|
||||
1. Définition
|
||||
Cette licence définit les droits et obligations concernant l'utilisation, la modification et la redistribution du code fourni par l'auteur.
|
||||
|
||||
2. Autorisation d'utilisation
|
||||
Vous êtes libre d'utiliser ce code pour vos projets personnels ou commerciaux. L'utilisation doit inclure une mention de l'auteur d’une manière libre (ex: "inspiré de ArthurP").
|
||||
|
||||
3. Modification
|
||||
Vous pouvez modifier, adapter ou améliorer le code pour vos besoins. Les modifications doivent être identifiées comme telles et ne doivent pas être présentées comme l'original.
|
||||
|
||||
4. Redistribution
|
||||
- Le code original **ne peut pas être redistribué tel quel**.
|
||||
- Les versions modifiées peuvent être partagées, sous réserve de mentionner l'auteur original.
|
||||
|
||||
5. Usage commercial
|
||||
L’usage commercial des versions modifiées est autorisé. Vous pouvez générer des revenus avec votre version modifiée.
|
||||
|
||||
6. Attribution
|
||||
L'auteur original doit être cité d’une manière libre, mais visible, sur tout projet utilisant ce code ou ses dérivés.
|
||||
|
||||
7. Responsabilité
|
||||
Le code est fourni "tel quel", sans garantie d’aucune sorte. L’auteur décline toute responsabilité pour tout dommage direct ou indirect résultant de l’utilisation du code.
|
||||
@@ -1,73 +1,67 @@
|
||||
# Clock - Horloge En Ligne
|
||||
# Clock
|
||||
|
||||
Application d'horloge en ligne (Next.js + TypeScript) avec affichage plein ecran, modes digital/analogique/flip, fuseaux horaires et themes.
|
||||
Horloge en ligne construite avec Next.js, React et TypeScript.
|
||||
|
||||
## Projet en ligne
|
||||
## Site public
|
||||
|
||||
Lien public: https://clock.arthurp.fr
|
||||
https://clock.arthurp.fr
|
||||
|
||||
Ce lien est volontairement present dans ce README pour renforcer le backlink vers le projet en production.
|
||||
|
||||
## Fonctionnalites
|
||||
|
||||
- Horloge en temps reel (rafraichissement fin)
|
||||
- Modes: `digital`, `analog`, `flip`
|
||||
- Format horaire: `12h` / `24h`
|
||||
- Affichage optionnel des secondes
|
||||
- Selection de fuseau horaire (liste IANA)
|
||||
- Themes visuels
|
||||
- Parametres persistants dans le navigateur
|
||||
- URL partageable avec les parametres
|
||||
|
||||
## SEO
|
||||
|
||||
- `robots.ts` et `sitemap.ts` configures
|
||||
- Pages `loading`, `error`, `not-found`
|
||||
- Balises et structure optimisees pour l'indexation
|
||||
|
||||
## Parametres URL
|
||||
|
||||
| Parametre | Valeurs | Description |
|
||||
|---|---|---|
|
||||
| `tz` | ex: `Europe/Paris` | Fuseau horaire |
|
||||
| `type` | `digital`, `analog`, `flip` | Type d'horloge |
|
||||
| `format` | `12h`, `24h` | Format horaire |
|
||||
| `seconds` | `true`, `false` | Afficher les secondes |
|
||||
| `theme` | id du theme | Theme visuel |
|
||||
|
||||
Exemple:
|
||||
|
||||
`https://clock.arthurp.fr?tz=Europe/Paris&type=analog&format=24h&seconds=true&theme=midnight`
|
||||
|
||||
## Lancer le projet
|
||||
## Lancer en local
|
||||
|
||||
Prerequis:
|
||||
|
||||
- Node.js 18+
|
||||
- Node.js 22+
|
||||
- npm
|
||||
|
||||
Installation et dev:
|
||||
Commandes:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Build production:
|
||||
## Build production local
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm start
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
## Stack
|
||||
Mode developpement:
|
||||
|
||||
- Next.js
|
||||
- React
|
||||
- TypeScript
|
||||
- Tailwind CSS
|
||||
```bash
|
||||
docker compose --profile dev up --build
|
||||
```
|
||||
|
||||
Mode production:
|
||||
|
||||
```bash
|
||||
docker compose --profile prod up --build -d
|
||||
```
|
||||
|
||||
Services compose:
|
||||
|
||||
- `clock-dev`: serveur dev sur `http://localhost:3000`
|
||||
- `clock-prod`: serveur prod sur `http://localhost:3007`
|
||||
|
||||
Variables `.env` utilisees:
|
||||
|
||||
- `SITE_URL`
|
||||
- `CONTACT_URL`
|
||||
- `CONTACT_EMAIL`
|
||||
- `NODE_ENV`
|
||||
- `PORT`
|
||||
- `HOSTNAME`
|
||||
- `TZ`
|
||||
- `NEXT_TELEMETRY_DISABLED`
|
||||
|
||||
## Pages legales
|
||||
|
||||
- `/mentions-legales`
|
||||
- `/politique-confidentialite`
|
||||
|
||||
## Licence
|
||||
|
||||
MIT
|
||||
Tous droits reserves - © 2026 Arthur P.
|
||||
|
||||
+35
-5
@@ -1,11 +1,41 @@
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
clock-dev:
|
||||
profiles: ["dev"]
|
||||
build:
|
||||
context: .
|
||||
target: dev
|
||||
args:
|
||||
SITE_URL: ${SITE_URL}
|
||||
CONTACT_URL: ${CONTACT_URL}
|
||||
CONTACT_EMAIL: ${CONTACT_EMAIL}
|
||||
container_name: clock-dev
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./:/app
|
||||
- .:/app
|
||||
- /app/node_modules
|
||||
- /app/.next
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
command: npm run dev
|
||||
NEXT_TELEMETRY_DISABLED: "1"
|
||||
NODE_ENV: development
|
||||
|
||||
clock-prod:
|
||||
profiles: ["prod"]
|
||||
build:
|
||||
context: .
|
||||
target: runner
|
||||
args:
|
||||
SITE_URL: ${SITE_URL}
|
||||
CONTACT_URL: ${CONTACT_URL}
|
||||
CONTACT_EMAIL: ${CONTACT_EMAIL}
|
||||
container_name: clock-prod
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3007:3000"
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
NEXT_TELEMETRY_DISABLED: "1"
|
||||
NODE_ENV: production
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: 'standalone',
|
||||
|
||||
// Optimisations de production
|
||||
reactStrictMode: true,
|
||||
|
||||
|
||||
+133
-17
@@ -309,33 +309,149 @@ select {
|
||||
|
||||
/* ===== Footer SEO ===== */
|
||||
.seo-footer {
|
||||
max-width: 900px;
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem 1.5rem 3rem;
|
||||
text-align: center;
|
||||
color: rgba(148, 163, 184, 0.6);
|
||||
font-size: 0.85rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||
padding: 3rem 1.5rem 2.25rem;
|
||||
color: rgba(148, 163, 184, 0.75);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(15, 23, 42, 0) 0%,
|
||||
rgba(15, 23, 42, 0.35) 20%,
|
||||
rgba(15, 23, 42, 0.65) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.seo-footer nav {
|
||||
margin-top: 1rem;
|
||||
.footer-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.seo-footer nav ul {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 1.5rem;
|
||||
.seo-footer h2 {
|
||||
font-size: 1rem;
|
||||
font-weight: 650;
|
||||
letter-spacing: 0.02em;
|
||||
margin-bottom: 0.9rem;
|
||||
color: rgba(248, 250, 252, 0.95);
|
||||
}
|
||||
|
||||
.seo-footer ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
gap: 0.65rem;
|
||||
}
|
||||
|
||||
.seo-footer nav a {
|
||||
color: rgba(148, 163, 184, 0.7);
|
||||
.seo-footer a {
|
||||
color: rgba(148, 163, 184, 0.82);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.seo-footer nav a:hover {
|
||||
color: rgba(248, 250, 252, 0.9);
|
||||
.seo-footer a:hover {
|
||||
color: rgba(248, 250, 252, 0.98);
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||||
padding-top: 1rem;
|
||||
font-size: 0.9rem;
|
||||
display: grid;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.footer-bottom p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ===== Pages legales ===== */
|
||||
.legal-page {
|
||||
width: min(100% - 2rem, 760px);
|
||||
margin: 0 auto;
|
||||
padding: 3rem 0 4rem;
|
||||
color: rgba(226, 232, 240, 0.92);
|
||||
}
|
||||
|
||||
.legal-header {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
||||
padding-bottom: 1.1rem;
|
||||
}
|
||||
|
||||
.legal-header h1 {
|
||||
font-size: clamp(1.8rem, 3vw, 2.25rem);
|
||||
line-height: 1.15;
|
||||
letter-spacing: -0.01em;
|
||||
color: rgba(248, 250, 252, 0.98);
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.legal-header p {
|
||||
margin-top: 0.45rem;
|
||||
color: rgba(148, 163, 184, 0.85);
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.legal-sections {
|
||||
margin-top: 1.8rem;
|
||||
}
|
||||
|
||||
.legal-sections section {
|
||||
padding-top: 1.1rem;
|
||||
}
|
||||
|
||||
.legal-sections section + section {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||||
margin-top: 1.2rem;
|
||||
}
|
||||
|
||||
.legal-sections h2 {
|
||||
font-size: 1.15rem;
|
||||
font-weight: 600;
|
||||
color: rgba(248, 250, 252, 0.96);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.legal-sections p {
|
||||
line-height: 1.65;
|
||||
color: rgba(203, 213, 225, 0.95);
|
||||
}
|
||||
|
||||
.legal-sections a {
|
||||
color: rgba(224, 242, 254, 0.94);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.legal-page {
|
||||
width: min(100% - 1.25rem, 760px);
|
||||
padding: 2.25rem 0 3rem;
|
||||
}
|
||||
|
||||
.legal-sections section {
|
||||
padding-top: 0.95rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.footer-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.seo-footer {
|
||||
padding: 2.5rem 1rem 1.75rem;
|
||||
}
|
||||
|
||||
.footer-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { SITE_URL } from '@/lib/env';
|
||||
|
||||
const SITE_URL = 'https://clock.arthurp.fr';
|
||||
const SITE_NAME = 'Horloge en ligne';
|
||||
const SITE_DESCRIPTION = 'Horloge en ligne gratuite avec affichage plein écran. Choisissez entre horloge numérique ou analogique, personnalisez les couleurs et le fuseau horaire. Heure exacte en temps réel.';
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import type { Metadata } from 'next';
|
||||
import { CONTACT_EMAIL, CONTACT_MAILTO, CONTACT_URL, SITE_URL } from '@/lib/env';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Mentions legales',
|
||||
description: `Mentions legales du site ${SITE_URL}`,
|
||||
};
|
||||
|
||||
export default function MentionsLegalesPage() {
|
||||
return (
|
||||
<main className="legal-page">
|
||||
<header className="legal-header">
|
||||
<h1>Mentions legales</h1>
|
||||
<p>Derniere mise a jour: 01/04/2026</p>
|
||||
</header>
|
||||
|
||||
<div className="legal-sections">
|
||||
<section>
|
||||
<h2>Editeur du site</h2>
|
||||
<p>Site: {SITE_URL.replace(/^https?:\/\//, '')}</p>
|
||||
<p>Responsable de publication: Arthur P.</p>
|
||||
<p>
|
||||
Contact: <a className="underline underline-offset-4" href={CONTACT_URL}>{CONTACT_URL.replace(/^https?:\/\//, '')}</a> ou{' '}
|
||||
<a className="underline underline-offset-4" href={CONTACT_MAILTO}>{CONTACT_EMAIL}</a>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Hebergement</h2>
|
||||
<p>Service auto-heberge sur infrastructure Proxmox.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Propriete intellectuelle</h2>
|
||||
<p>
|
||||
Les contenus presentes sur ce site (textes, elements graphiques et code source specifique)
|
||||
restent proteges par les lois en vigueur. Toute reproduction non autorisee est interdite.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Liens externes</h2>
|
||||
<p>
|
||||
Le site peut contenir des liens vers des services externes. Le responsable du site ne peut
|
||||
pas etre tenu responsable du contenu de ces services tiers.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
+39
-7
@@ -1,4 +1,5 @@
|
||||
import { ClockApp } from '@/components/ClockApp';
|
||||
import { CONTACT_EMAIL, CONTACT_MAILTO, CONTACT_URL } from '@/lib/env';
|
||||
|
||||
// Contenu SEO visible en bas de page pour l'indexation Google
|
||||
function SEOContent() {
|
||||
@@ -137,6 +138,8 @@ function SEOContent() {
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
return (
|
||||
<>
|
||||
<a href="#main-clock" className="skip-to-content">
|
||||
@@ -145,17 +148,46 @@ export default function Home() {
|
||||
<ClockApp />
|
||||
<SEOContent />
|
||||
<footer className="seo-footer" role="contentinfo">
|
||||
<p>
|
||||
© {new Date().getFullYear()} Horloge en ligne — Heure exacte gratuite en temps réel.
|
||||
Horloge numérique, analogique et à bascule avec personnalisation complète.
|
||||
</p>
|
||||
<nav aria-label="Liens rapides">
|
||||
<div className="footer-grid">
|
||||
<section aria-labelledby="footer-navigation">
|
||||
<h2 id="footer-navigation">Navigation</h2>
|
||||
<nav aria-label="Navigation principale du site">
|
||||
<ul>
|
||||
<li><a href="#main-clock">Horloge</a></li>
|
||||
<li><a href="#features">Fonctionnalités</a></li>
|
||||
<li><a href="/">Accueil</a></li>
|
||||
<li><a href="https://arthurp.fr" target="_blank" rel="noopener noreferrer">Projets</a></li>
|
||||
<li><a href="#features">Fonctionnalites</a></li>
|
||||
<li><a href="#faq">FAQ</a></li>
|
||||
<li><a href={CONTACT_URL} target="_blank" rel="noopener noreferrer">Contact</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="footer-contact">
|
||||
<h2 id="footer-contact">Contact</h2>
|
||||
<ul>
|
||||
<li><a href={CONTACT_URL} target="_blank" rel="noopener noreferrer">{CONTACT_URL.replace(/^https?:\/\//, '')}</a></li>
|
||||
<li><a href={CONTACT_MAILTO}>{CONTACT_EMAIL}</a></li>
|
||||
<li><a href="https://arthurp.fr" target="_blank" rel="noopener noreferrer">arthurp.fr</a></li>
|
||||
<li><a href="https://github.com/arthur-pbty" target="_blank" rel="noopener noreferrer">GitHub</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="footer-legal">
|
||||
<h2 id="footer-legal">Informations</h2>
|
||||
<ul>
|
||||
<li><a href="/mentions-legales">Mentions legales</a></li>
|
||||
<li><a href="/politique-confidentialite">Politique de confidentialite</a></li>
|
||||
<li><a href="#main-clock">Horloge en direct</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div className="footer-bottom">
|
||||
<p>© {currentYear} Arthur P. Tous droits reserves.</p>
|
||||
<p>
|
||||
Fait avec <span aria-hidden="true">❤️</span> et auto-heberge sur Proxmox.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { Metadata } from 'next';
|
||||
import { CONTACT_EMAIL, CONTACT_MAILTO, CONTACT_URL, SITE_URL } from '@/lib/env';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Politique de confidentialite',
|
||||
description: `Politique de confidentialite du site ${SITE_URL}`,
|
||||
};
|
||||
|
||||
export default function PolitiqueConfidentialitePage() {
|
||||
return (
|
||||
<main className="legal-page">
|
||||
<header className="legal-header">
|
||||
<h1>Politique de confidentialite</h1>
|
||||
<p>Derniere mise a jour: 01/04/2026</p>
|
||||
</header>
|
||||
|
||||
<div className="legal-sections">
|
||||
<section>
|
||||
<h2>Donnees collectees</h2>
|
||||
<p>
|
||||
Cette application ne demande pas de creation de compte et ne collecte pas de donnees
|
||||
personnelles identifiantes pour son fonctionnement standard.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Stockage local</h2>
|
||||
<p>
|
||||
Certaines preferences utilisateur (theme, fuseau horaire, format d'affichage)
|
||||
peuvent etre enregistrees localement dans votre navigateur afin d'ameliorer
|
||||
votre experience.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Journaux techniques</h2>
|
||||
<p>
|
||||
Comme tout service web, des journaux techniques minimum peuvent exister cote serveur
|
||||
pour la securite, le diagnostic et la maintenance.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Contact</h2>
|
||||
<p>
|
||||
Pour toute question relative a la confidentialite: <a className="underline underline-offset-4" href={CONTACT_URL}>{CONTACT_URL.replace(/^https?:\/\//, '')}</a> ou{' '}
|
||||
<a className="underline underline-offset-4" href={CONTACT_MAILTO}>{CONTACT_EMAIL}</a>.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
import { MetadataRoute } from 'next';
|
||||
import { SITE_URL } from '@/lib/env';
|
||||
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
return {
|
||||
@@ -17,6 +18,6 @@ export default function robots(): MetadataRoute.Robots {
|
||||
allow: '/',
|
||||
},
|
||||
],
|
||||
sitemap: 'https://clock.arthurp.fr/sitemap.xml',
|
||||
sitemap: `${SITE_URL}/sitemap.xml`,
|
||||
};
|
||||
}
|
||||
|
||||
+14
-1
@@ -1,7 +1,8 @@
|
||||
import { MetadataRoute } from 'next';
|
||||
import { SITE_URL } from '@/lib/env';
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
const baseUrl = 'https://clock.arthurp.fr';
|
||||
const baseUrl = SITE_URL;
|
||||
const lastModified = new Date('2026-03-01');
|
||||
|
||||
// Page principale
|
||||
@@ -12,6 +13,18 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
||||
changeFrequency: 'weekly',
|
||||
priority: 1,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/mentions-legales`,
|
||||
lastModified,
|
||||
changeFrequency: 'yearly',
|
||||
priority: 0.4,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/politique-confidentialite`,
|
||||
lastModified,
|
||||
changeFrequency: 'yearly',
|
||||
priority: 0.4,
|
||||
},
|
||||
];
|
||||
|
||||
// Pages par type d'horloge
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
const FALLBACK_SITE_URL = 'https://clock.arthurp.fr';
|
||||
const FALLBACK_CONTACT_URL = 'https://contact.arthurp.fr';
|
||||
const FALLBACK_CONTACT_EMAIL = 'contact@arthurp.fr';
|
||||
|
||||
function normalizeUrl(value: string | undefined, fallback: string): string {
|
||||
if (!value) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = new URL(value);
|
||||
return parsed.origin;
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
export const SITE_URL = normalizeUrl(process.env.SITE_URL, FALLBACK_SITE_URL);
|
||||
export const CONTACT_URL = normalizeUrl(process.env.CONTACT_URL, FALLBACK_CONTACT_URL);
|
||||
export const CONTACT_EMAIL = process.env.CONTACT_EMAIL?.trim() || FALLBACK_CONTACT_EMAIL;
|
||||
export const CONTACT_MAILTO = `mailto:${CONTACT_EMAIL}`;
|
||||
Reference in New Issue
Block a user