/* global React, ReactDOM, gsap, ScrollTrigger, MotionPathPlugin */
/* eslint-disable */
const { useState, useEffect, useMemo, useRef, useCallback } = React;
/* ============================================================
GSAP plugin registration
============================================================ */
if (typeof gsap !== "undefined") {
gsap.registerPlugin(ScrollTrigger);
if (typeof MotionPathPlugin !== "undefined") gsap.registerPlugin(MotionPathPlugin);
}
/* ============================================================
Storage helpers
============================================================ */
const STORAGE_KEY = "mariany_rsvps_v1";
function loadRsvps() {
try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]"); }
catch { return []; }
}
function saveRsvp(r) {
const all = loadRsvps();
all.unshift({ ...r, id: Date.now(), createdAt: new Date().toISOString() });
localStorage.setItem(STORAGE_KEY, JSON.stringify(all));
}
/* ============================================================
Tweaks defaults
============================================================ */
const TWEAK_DEFAULTS = {
palette: "blush",
showFlyingButterflies: true,
showParticles: true,
particleDensity: 28,
videoLabel: "Mariany",
};
const PALETTES = {
blush: {
name: "Blush Garden",
"--blush-50": "oklch(0.985 0.008 10)",
"--blush-100": "oklch(0.965 0.018 12)",
"--blush-200": "oklch(0.93 0.04 10)",
"--blush-300": "oklch(0.88 0.07 10)",
"--blush-400": "oklch(0.82 0.11 10)",
"--candy-500": "oklch(0.74 0.16 12)",
"--rose-600": "oklch(0.62 0.18 14)",
"--rose-700": "oklch(0.48 0.16 16)",
"--rose-900": "oklch(0.28 0.10 18)",
"--lilac-200": "oklch(0.92 0.035 320)",
},
candy: {
name: "Candy Bloom",
"--blush-50": "oklch(0.98 0.012 350)",
"--blush-100": "oklch(0.96 0.026 350)",
"--blush-200": "oklch(0.92 0.05 350)",
"--blush-300": "oklch(0.86 0.09 350)",
"--blush-400": "oklch(0.78 0.14 350)",
"--candy-500": "oklch(0.7 0.2 350)",
"--rose-600": "oklch(0.58 0.22 0)",
"--rose-700": "oklch(0.44 0.18 5)",
"--rose-900": "oklch(0.26 0.12 8)",
"--lilac-200": "oklch(0.9 0.05 310)",
},
pearl: {
name: "Pearl Petal",
"--blush-50": "oklch(0.99 0.004 20)",
"--blush-100": "oklch(0.975 0.012 20)",
"--blush-200": "oklch(0.95 0.025 20)",
"--blush-300": "oklch(0.91 0.05 20)",
"--blush-400": "oklch(0.86 0.08 18)",
"--candy-500": "oklch(0.78 0.12 15)",
"--rose-600": "oklch(0.66 0.14 18)",
"--rose-700": "oklch(0.52 0.12 20)",
"--rose-900": "oklch(0.32 0.08 22)",
"--lilac-200": "oklch(0.94 0.025 320)",
},
};
function applyPalette(key) {
const p = PALETTES[key] || PALETTES.blush;
const root = document.documentElement;
Object.entries(p).forEach(([k, v]) => {
if (k.startsWith("--")) root.style.setProperty(k, v);
});
}
/* ============================================================
GSAP reveal hook — replaces IntersectionObserver
============================================================ */
function useGsapReveal(active) {
useEffect(() => {
if (!active || typeof gsap === "undefined") return;
// Immediately reveal elements in view
const revealEls = document.querySelectorAll(".reveal:not(.in)");
revealEls.forEach((el) => {
ScrollTrigger.create({
trigger: el,
start: "top 88%",
onEnter: () => {
gsap.to(el, {
opacity: 1,
y: 0,
duration: 1.1,
ease: "power3.out",
overwrite: "auto",
});
el.classList.add("in");
},
once: true,
});
// Reveal immediately if already in viewport
const rect = el.getBoundingClientRect();
if (rect.top < window.innerHeight * 0.95) {
gsap.to(el, { opacity: 1, y: 0, duration: 1.1, ease: "power3.out", overwrite: "auto" });
el.classList.add("in");
}
});
}, [active]);
}
/* ============================================================
GSAP scene entrance hook
============================================================ */
function useGsapScenes(active) {
const [activeScene, setActiveScene] = useState("hero");
useEffect(() => {
if (!active || typeof gsap === "undefined") return;
const scenes = document.querySelectorAll("section[data-scene]");
if (!scenes.length) return;
const triggers = [];
scenes.forEach((scene) => {
const inner = scene.querySelector(".scene-inner");
if (!inner) return;
// Entrance
const enterTrigger = ScrollTrigger.create({
trigger: scene,
start: "top 65%",
onEnter: () => {
gsap.to(inner, {
opacity: 1,
y: 0,
scale: 1,
filter: "blur(0px)",
duration: 1.4,
ease: "power3.out",
});
scene.classList.add("in");
scene.classList.remove("past");
setActiveScene(scene.dataset.scene);
// Stagger child reveals
const children = scene.querySelectorAll(".reveal:not(.in)");
gsap.to(children, {
opacity: 1,
y: 0,
duration: 1.1,
ease: "power3.out",
stagger: 0.12,
delay: 0.2,
onStart() { children.forEach((c) => c.classList.add("in")); },
});
},
once: false,
});
// Exit upward
const exitTrigger = ScrollTrigger.create({
trigger: scene,
start: "bottom 20%",
onLeave: () => {
gsap.to(inner, {
opacity: 0.15,
y: -30,
scale: 0.97,
filter: "blur(6px)",
duration: 0.8,
ease: "power2.in",
});
scene.classList.add("past");
},
onEnterBack: () => {
gsap.to(inner, {
opacity: 1,
y: 0,
scale: 1,
filter: "blur(0px)",
duration: 1.0,
ease: "power3.out",
});
scene.classList.remove("past");
setActiveScene(scene.dataset.scene);
},
});
triggers.push(enterTrigger, exitTrigger);
});
// Always show first scene
const first = scenes[0];
if (first) {
const fi = first.querySelector(".scene-inner");
if (fi) {
gsap.set(fi, { opacity: 1, y: 0, scale: 1, filter: "blur(0px)" });
first.classList.add("in");
first.querySelectorAll(".reveal").forEach((el) => {
gsap.to(el, { opacity: 1, y: 0, duration: 1.1, ease: "power3.out", stagger: 0.1 });
el.classList.add("in");
});
}
}
return () => {
triggers.forEach((t) => t.kill());
};
}, [active]);
return activeScene;
}
/* ============================================================
Topbar
============================================================ */
function Topbar({ route, go }) {
const ref = useRef(null);
useEffect(() => {
if (!ref.current || typeof gsap === "undefined") return;
gsap.fromTo(ref.current,
{ y: -60, opacity: 0 },
{ y: 0, opacity: 1, duration: 1.2, ease: "power3.out", delay: 0.3 }
);
}, []);
return (
);
}
/* ============================================================
Audio toggle
============================================================ */
function AudioToggle() {
const [on, setOn] = useState(false);
const audioRef = useRef(null);
useEffect(() => {
const audio = new Audio("/musica.mp3");
audio.loop = true;
audio.volume = 0.45;
audioRef.current = audio;
return () => { audio.pause(); audio.src = ""; };
}, []);
const toggle = () => {
const audio = audioRef.current;
if (!audio) return;
if (!on) {
audio.play().then(() => setOn(true)).catch(() => {});
} else {
audio.pause();
setOn(false);
}
};
return (
);
}
/* ============================================================
Hero — 10-second lock + GSAP cinematic entrance
============================================================ */
const HERO_LOCK_SECONDS = 10;
function Hero({ tweaks, locked, secondsLeft }) {
const stageRef = useRef(null);
const progress = 1 - secondsLeft / HERO_LOCK_SECONDS;
const R = 32;
const C = 2 * Math.PI * R;
const dashOffset = C * (1 - progress);
// Cinematic entrance timeline
useEffect(() => {
if (!stageRef.current || typeof gsap === "undefined") return;
const stage = stageRef.current;
const tl = gsap.timeline({ delay: 0.5 });
// Video wrap scales in from center
tl.fromTo(stage.querySelector(".video-wrap"),
{ scale: 0.7, opacity: 0, y: 40 },
{ scale: 1, opacity: 1, y: 0, duration: 1.6, ease: "back.out(1.3)" }
);
// Left titles stagger in
tl.fromTo(stage.querySelectorAll(".hero-side.left .hero-title, .hero-side.left .hero-lede, .hero-side.left .hero-meta"),
{ x: -40, opacity: 0 },
{ x: 0, opacity: 1, duration: 1.2, ease: "power3.out", stagger: 0.15 },
"-=1.2"
);
// Right titles stagger in
tl.fromTo(stage.querySelectorAll(".hero-side.right .hero-title, .hero-side.right .hero-lede, .hero-side.right .hero-meta"),
{ x: 40, opacity: 0 },
{ x: 0, opacity: 1, duration: 1.2, ease: "power3.out", stagger: 0.15 },
"-=1.2"
);
}, []);
// Subtle continuous parallax on video-wrap
useEffect(() => {
if (!stageRef.current || typeof gsap === "undefined") return;
const vw = stageRef.current.querySelector(".video-wrap");
if (!vw) return;
const onMove = (e) => {
const mx = (e.clientX / window.innerWidth - 0.5) * 14;
const my = (e.clientY / window.innerHeight - 0.5) * 10;
gsap.to(vw, { x: mx, y: my, duration: 1.4, ease: "power1.out", overwrite: "auto" });
};
window.addEventListener("mousemove", onMove);
return () => window.removeEventListener("mousemove", onMove);
}, []);
return (
Da forma mais linda que poderíamos imaginar.
Hoje, entre flores e borboletas, celebramos o primeiro
capítulo do nosso conto encantado.
Está completando seu primeiro aninho e
queremos viver esse momento mágico ao seu lado.
Borboletas dançam ao vento e cada pétala carrega um pedacinho de fantasia.
Preparamos uma celebração cheia de amor, magia e memórias inesquecíveis —
como um jardim que floresce só uma vez por ano.
Cada sorriso da nossa princesa transformou nossos dias
em um verdadeiro conto encantado.
✦ com amor, papai & mamãe ✦
Agora queremos celebrar esse capítulo tão especial ao lado das pessoas
que amamos. ♡
Seu carinho faz parte da nossa história…
Esperamos por você ✿
Para viver esse dia mágico ao nosso lado.
Há 1 ano…
o nosso mundo
floresceu ✿
Mariany
nossa princesa
Entre flores encantadas e brilho no ar
Você está convidado para um dia mágico
Sua presença é o nosso maior presente.
Te esperamos no jardim encantado em 13 · 06 · 2026.
Mas, para quem desejar presentear nossa princesa, deixamos algumas sugestões com muito carinho — escolha o que tocar o seu coração.
Vestidos, conjuntos e peças tamanho 2 a 3 anos para acompanhar nossa borboleta.
Para pisar leve no jardim — também tamanho 2 a 3 anos.
Que estimulem o desenvolvimento infantil — descoberta, cores e sons.
Para quem preferir, também disponibilizamos esta opção delicada.
QR Code indisponível — copie a chave acima
`; } }, [pixPayload]); return ( ); } /* ============================================================ Admin confirmações ============================================================ */ function ConfirmacoesPage() { const [auth, setAuth] = useState(() => sessionStorage.getItem("admin_ok") === "1"); const [pw, setPw] = useState(""); const [err, setErr] = useState(""); const [filter, setFilter] = useState("all"); const [rows, setRows] = useState(() => loadRsvps()); useEffect(() => { const id = setInterval(() => setRows(loadRsvps()), 1500); return () => clearInterval(id); }, []); if (!auth) { const tryLogin = (e) => { e.preventDefault(); if (pw === "mariany1106") { sessionStorage.setItem("admin_ok", "1"); setAuth(true); setErr(""); } else { setErr("Senha incorreta — tente novamente."); } }; return (Apenas a família tem acesso a esta área ✿
Painel privado · convidados da Mariany ✿
Nenhuma confirmação ainda
As respostas aparecerão aqui assim que chegarem ✿
| Nome | Qtd. | Acompanhantes | PIX | Data | |
|---|---|---|---|---|---|
| {r.name} | {r.phone} | {r.count || 0} | {(r.companions || []).length === 0 ? — : (r.companions || []).map((c, i) => {c}) } | {r.pix ? `R$${r.pix}` : "—"} | {new Date(r.createdAt).toLocaleString("pt-BR", { dateStyle: "short", timeStyle: "short" })} |
Dados armazenados localmente neste navegador