diff --git a/src/app/globals.css b/src/app/globals.css index f154bf3..8932bd0 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -88,9 +88,18 @@ button { transform: translateY(-14px) rotate(0.6deg); } } -@media (prefers-reduced-motion: reduce) { - * { - animation: none !important; +/* Dérive lente des étoiles. Utilise la propriété `translate` (indépendante de + `transform`) pour se cumuler avec le scintillement `plr-twinkle`. */ +@keyframes plr-drift { + 0%, + 100% { + translate: 0 0; + } + 33% { + translate: 12px -18px; + } + 66% { + translate: -10px 10px; } } @@ -98,6 +107,20 @@ button { clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%); } +/* ---- Champ d'étoiles flottantes ---- */ +.starfield { + position: absolute; + inset: 0; + overflow: hidden; + pointer-events: none; + z-index: 0; +} +.starfield .star { + position: absolute; + animation: plr-twinkle var(--tw, 3.2s) ease-in-out infinite, + plr-drift var(--dr, 9s) ease-in-out infinite; +} + /* ---- Scroll-reveal entrance animations ---- */ @keyframes plr-fade-up { from { @@ -134,16 +157,6 @@ button { .reveal-stagger.is-visible > *:nth-child(8) { animation-delay: 0.46s; } .reveal-stagger.is-visible > *:nth-child(n + 9) { animation-delay: 0.52s; } -@media (prefers-reduced-motion: reduce) { - .reveal, - .reveal-stagger > * { - opacity: 1 !important; - } - .reveal.is-visible, - .reveal-stagger.is-visible > * { - animation: none !important; - } -} .twinkle { animation: plr-twinkle 3.2s ease-in-out infinite; } diff --git a/src/app/page.tsx b/src/app/page.tsx index 0cb2beb..787d49d 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -5,6 +5,7 @@ import { SiteHeader } from "@/components/SiteHeader"; import { SiteFooter } from "@/components/SiteFooter"; import { MembershipModalButton } from "@/components/MembershipModalButton"; import { MembersCarousel } from "@/components/MembersCarousel"; +import { StarField } from "@/components/StarField"; import { getLivePromotions, getRotatingActiveMembers } from "@/lib/queries"; export const dynamic = "force-dynamic"; @@ -40,12 +41,9 @@ export default async function AccueilPage() { className="grid hero-grid" style={{ position: "relative", padding: "30px 0 50px", overflow: "hidden", alignItems: "center" }} > - - - - + -
+
{/* eslint-disable-next-line @next/next/no-img-element */}
- +
{ if (!canRotate) return; - // Respecte la préférence de réduction d'animation. - const reduce = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches; const tick = setInterval(() => { - if (reduce) { - setStart((s) => (s + VISIBLE) % total); - return; - } // Disparition une à une, puis changement, puis réapparition une à une. setVisible(false); const outMs = FADE_MS + STAGGER_MS * (VISIBLE - 1); diff --git a/src/components/StarField.tsx b/src/components/StarField.tsx new file mode 100644 index 0000000..d7e6054 --- /dev/null +++ b/src/components/StarField.tsx @@ -0,0 +1,56 @@ +import type { CSSProperties } from "react"; + +type Star = { + top: string; + left: string; + size: number; + color: string; + tw: number; // durée scintillement (s) + dr: number; // durée dérive (s) + delay: number; +}; + +// Positions fixes (déterministes) pour éviter tout décalage d'hydratation. +const STARS: Star[] = [ + { top: "8%", left: "6%", size: 16, color: "#E0A63C", tw: 3.1, dr: 9, delay: 0 }, + { top: "18%", left: "22%", size: 10, color: "#6FB0C6", tw: 2.6, dr: 11, delay: 0.6 }, + { top: "12%", left: "44%", size: 13, color: "#9a6638", tw: 3.6, dr: 8, delay: 1.1 }, + { top: "26%", left: "63%", size: 11, color: "#2C6FB3", tw: 2.9, dr: 12, delay: 0.3 }, + { top: "9%", left: "82%", size: 18, color: "#E0A63C", tw: 3.3, dr: 10, delay: 0.9 }, + { top: "40%", left: "12%", size: 12, color: "#2C6FB3", tw: 3.0, dr: 13, delay: 1.4 }, + { top: "52%", left: "33%", size: 9, color: "#E0A63C", tw: 2.7, dr: 9.5, delay: 0.2 }, + { top: "46%", left: "72%", size: 14, color: "#6FB0C6", tw: 3.4, dr: 11.5, delay: 1.7 }, + { top: "62%", left: "52%", size: 10, color: "#9a6638", tw: 2.8, dr: 10.5, delay: 0.5 }, + { top: "70%", left: "18%", size: 13, color: "#E0A63C", tw: 3.2, dr: 12.5, delay: 1.0 }, + { top: "76%", left: "88%", size: 11, color: "#2C6FB3", tw: 3.5, dr: 8.5, delay: 0.7 }, + { top: "84%", left: "40%", size: 15, color: "#6FB0C6", tw: 3.0, dr: 11, delay: 1.3 }, + { top: "33%", left: "90%", size: 9, color: "#9a6638", tw: 2.5, dr: 9, delay: 0.4 }, + { top: "88%", left: "67%", size: 12, color: "#E0A63C", tw: 3.3, dr: 10, delay: 1.6 }, +]; + +export function StarField({ density = 1, style }: { density?: number; style?: CSSProperties }) { + const stars = STARS.slice(0, Math.max(4, Math.round(STARS.length * density))); + return ( +
+ {stars.map((s, i) => ( + + ))} +
+ ); +}