La modale de bienvenue (position: fixed, inset: 0) recouvre tout l'écran y compris l'en-tête où vivait le seul lien vers la galerie : au premier chargement (cas le plus fréquent, un seul passage par invité et par événement), le lien était visuellement présent mais totalement inatteignable au clic. Ajout d'un lien dupliqué dans la carte de la modale elle-même. Au passage, "mur" remplacé par "fête" partout (jugé pas assez fun) pour rester cohérent avec le texte déjà utilisé sur l'écran de succès. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
239 lines
12 KiB
HTML
239 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
<title>Ajouter une photo</title>
|
|
<!--
|
|
Cette page est servie pour toute URL du type /e/<slug> (le slug est lu
|
|
côté client depuis window.location.pathname, voir upload.js).
|
|
Ça suppose une règle de réécriture côté serveur (ex. nginx try_files)
|
|
qui renvoie ce fichier pour toute requête sous /e/* — à mettre en place
|
|
lors du déploiement, hors scope de ce fichier front.
|
|
-->
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<!-- Thème unique sombre "Polaroid Néon" (voir src/e/style.css) : une seule
|
|
meta theme-color, comme src/galerie/index.html. -->
|
|
<meta name="theme-color" content="#12100E">
|
|
<link rel="preload" href="/vendor/fonts/generalsans-700.woff2" as="font" type="font/woff2" crossorigin>
|
|
<link rel="preload" href="/vendor/fonts/caveat-latin-variable.woff2" as="font" type="font/woff2" crossorigin>
|
|
<link rel="stylesheet" href="/e/style.css">
|
|
</head>
|
|
<body>
|
|
<main class="page">
|
|
<header class="page__header">
|
|
<p class="brand" aria-hidden="true">
|
|
<svg class="brand__mark" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" focusable="false">
|
|
<path d="M4 8h3l1.5-2h7L17 8h3a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1Z"/>
|
|
<circle cx="12" cy="13" r="3.5"/>
|
|
</svg>
|
|
<span class="brand__name">photobooth</span>
|
|
</p>
|
|
<h1 id="event-name">Ajouter une photo</h1>
|
|
<p class="page__kicker">Une photo, un petit mot, et hop dans l'album !</p>
|
|
<!-- href posé par upload.js une fois le slug connu (getSlugFromPath) ;
|
|
"#" par défaut pour ne jamais pointer nulle part avant ça. Lien
|
|
permanent vers la galerie, accessible même sans avoir uploadé —
|
|
ajouté suite à la demande de Kévin le 2026-09-18. "Mur" jugé pas
|
|
assez fun par Kévin -> renommé "la fête" partout (cohérent avec
|
|
le texte déjà existant de l'écran de succès). -->
|
|
<a href="#" id="wall-link" class="wall-link">Voir la fête →</a>
|
|
</header>
|
|
|
|
<!-- Mot de bienvenue + mention légale RGPD condensée, affiché une seule
|
|
fois par événement (localStorage, cf. upload.js) plutôt qu'en bloc
|
|
permanent dans le formulaire — décision Kévin 2026-09-16. Reste
|
|
consultable à tout moment via le lien "Infos sur tes données" sous
|
|
le formulaire, pour ne jamais perdre l'info, juste la rendre moins
|
|
envahissante au quotidien. -->
|
|
<div id="welcome-modal" class="welcome-modal" hidden>
|
|
<div class="welcome-modal__card">
|
|
<p class="brand brand--modal" aria-hidden="true">
|
|
<svg class="brand__mark" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" focusable="false">
|
|
<path d="M4 8h3l1.5-2h7L17 8h3a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1Z"/>
|
|
<circle cx="12" cy="13" r="3.5"/>
|
|
</svg>
|
|
<span class="brand__name">photobooth</span>
|
|
</p>
|
|
<p class="welcome-modal__title" id="welcome-modal-title">Bienvenue !</p>
|
|
<p class="welcome-modal__text">
|
|
Scanne, souris, dépose ta photo — elle rejoint la fête en quelques
|
|
secondes, visible par tous les invités.
|
|
</p>
|
|
<p class="legal-notice welcome-modal__legal">
|
|
<svg class="legal-notice__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
|
|
<rect x="4.5" y="10.5" width="15" height="9.5" rx="2"/>
|
|
<path d="M8 10.5V7.5a4 4 0 0 1 8 0v3"/>
|
|
</svg>
|
|
<!-- Texte légal complet, identique à docs/rgpd.md (mention
|
|
obligatoire) — seule la présentation change (modale au premier
|
|
passage + lien de rappel), pas le contenu. Mis à jour le
|
|
2026-09-18 : mentionne explicitement la visibilité par les
|
|
autres invités (galerie commune), cf. docs/decisions.md. -->
|
|
<span>
|
|
En déposant une photo, tu acceptes qu'elle soit stockée temporairement
|
|
dans le cadre de cet événement et visible par les autres invités de
|
|
l'événement ainsi que par l'organisateur. Tes photos sont
|
|
automatiquement supprimées 7 jours après la date de l'événement,
|
|
sans action de ta part. Aucune photo n'est utilisée à d'autres
|
|
fins, ni transmise à des tiers en dehors des invités de
|
|
l'événement. Tu peux demander la suppression anticipée d'une
|
|
photo en contactant l'organisateur de l'événement.
|
|
</span>
|
|
</p>
|
|
<button type="button" id="welcome-modal-dismiss">C'est parti !</button>
|
|
<!-- Lien dupliqué ici (même que #wall-link dans l'en-tête) : la
|
|
modale recouvre tout l'écran en position fixed, donc le lien de
|
|
l'en-tête est inatteignable tant qu'elle est ouverte — bug réel
|
|
remonté par Kévin le 2026-09-18 ("le bouton ne marche pas", en
|
|
fait il tapait dessus derrière la modale). -->
|
|
<a href="#" id="wall-link-modal" class="btn-secondary-link">Voir la fête sans envoyer de photo →</a>
|
|
</div>
|
|
</div>
|
|
|
|
<section id="status-loading" class="state-block state-block--loading" role="status">
|
|
<span class="spinner" aria-hidden="true"></span>
|
|
<p>Chargement de l'événement…</p>
|
|
</section>
|
|
|
|
<section id="status-error" class="state-block state-block--error" hidden role="alert">
|
|
<div class="state-icon state-icon--error" aria-hidden="true">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" focusable="false">
|
|
<circle cx="12" cy="12" r="9"/>
|
|
<path d="M12 8v5"/>
|
|
<path d="M12 16.2v.1"/>
|
|
</svg>
|
|
</div>
|
|
<div class="state-icon state-icon--limit" aria-hidden="true">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" focusable="false">
|
|
<path d="M12 20.2s-7.5-4.6-7.5-10.1a4.4 4.4 0 0 1 7.5-3.1 4.4 4.4 0 0 1 7.5 3.1c0 5.5-7.5 10.1-7.5 10.1Z"/>
|
|
</svg>
|
|
</div>
|
|
<p id="status-error-message"></p>
|
|
<button type="button" id="retry-btn" hidden>Réessayer</button>
|
|
</section>
|
|
|
|
<section id="success-block" class="state-block state-block--success" hidden role="status">
|
|
<div class="confetti" aria-hidden="true">
|
|
<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>
|
|
</div>
|
|
<div class="success-check" aria-hidden="true">
|
|
<svg viewBox="0 0 52 52" fill="none" focusable="false">
|
|
<circle class="success-check__circle" cx="26" cy="26" r="23" stroke-width="2.5"/>
|
|
<path class="success-check__mark" d="M15 27.5 22.5 35 38 18" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</svg>
|
|
</div>
|
|
<p class="success-title">C'est envoyé !</p>
|
|
<p class="success-text">Ta photo vient de rejoindre la fête. Merci d'avoir été là !</p>
|
|
<div class="success-actions">
|
|
<button type="button" id="add-another-btn">Ajouter une autre photo</button>
|
|
<a href="#" id="wall-link-success" class="btn-secondary-link">Voir la fête →</a>
|
|
</div>
|
|
</section>
|
|
|
|
<form id="upload-form" class="upload-form" hidden novalidate>
|
|
<div class="field">
|
|
<label id="photo-field-label">Ta photo</label>
|
|
<!-- Deux entrées séparées : "photo-input" (capture="environment")
|
|
ouvre directement l'appareil photo, "photo-input-gallery" ouvre
|
|
le sélecteur de fichiers classique. Décision actée avec Kévin le
|
|
2026-09-16 : les deux doivent être accessibles en un tap.
|
|
Hiérarchie visuelle ajoutée : "Prendre une photo" est l'action
|
|
attendue pour l'immense majorité des invités pendant l'événement
|
|
(capture sur le moment), donc traitée en primaire ; "Depuis la
|
|
galerie" reste secondaire mais tout aussi accessible. -->
|
|
<div class="photo-source-buttons">
|
|
<label for="photo-input" class="btn-source btn-source--primary">
|
|
<svg class="btn-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
|
|
<path d="M4 8h3l1.5-2h7L17 8h3a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1Z"/>
|
|
<circle cx="12" cy="13" r="3.5"/>
|
|
</svg>
|
|
<span>Prendre une photo</span>
|
|
</label>
|
|
<label for="photo-input-gallery" class="btn-source btn-source--secondary">
|
|
<svg class="btn-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
|
|
<rect x="3" y="4" width="18" height="16" rx="2.5"/>
|
|
<circle cx="8.5" cy="9.5" r="1.5"/>
|
|
<path d="M21 16.5 15.6 11a1 1 0 0 0-1.4 0L6 19"/>
|
|
</svg>
|
|
<span>Depuis la galerie</span>
|
|
</label>
|
|
</div>
|
|
<input
|
|
type="file"
|
|
id="photo-input"
|
|
name="photo"
|
|
accept="image/*,.heic,.heif"
|
|
capture="environment"
|
|
required
|
|
class="visually-hidden"
|
|
>
|
|
<input
|
|
type="file"
|
|
id="photo-input-gallery"
|
|
accept="image/*,.heic,.heif"
|
|
class="visually-hidden"
|
|
tabindex="-1"
|
|
aria-hidden="true"
|
|
>
|
|
<p id="file-chosen-label" class="file-chosen-label">Aucun fichier choisi</p>
|
|
</div>
|
|
|
|
<img id="preview" class="preview" alt="Aperçu de la photo choisie" hidden>
|
|
|
|
<div class="field-group">
|
|
<div class="field">
|
|
<label for="nom-input">Ton prénom <span class="optional">(facultatif)</span></label>
|
|
<input
|
|
type="text"
|
|
id="nom-input"
|
|
name="nom"
|
|
maxlength="60"
|
|
autocomplete="given-name"
|
|
placeholder="Ex : Camille"
|
|
>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label for="message-input">Un petit mot <span class="optional">(facultatif)</span></label>
|
|
<textarea
|
|
id="message-input"
|
|
name="message"
|
|
maxlength="300"
|
|
rows="3"
|
|
placeholder="Ton petit mot pour l'occasion…"
|
|
></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="button" id="legal-link" class="legal-link">
|
|
<svg class="legal-notice__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
|
|
<rect x="4.5" y="10.5" width="15" height="9.5" rx="2"/>
|
|
<path d="M8 10.5V7.5a4 4 0 0 1 8 0v3"/>
|
|
</svg>
|
|
<span>Infos sur tes données (RGPD)</span>
|
|
</button>
|
|
|
|
<p id="progress-text" class="progress-text" aria-live="polite"></p>
|
|
|
|
<button type="submit" id="submit-btn">
|
|
<svg class="btn-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
|
|
<path d="M21 4 3 11.5l7 2.5"/>
|
|
<path d="M10 14l2.5 7L21 4"/>
|
|
</svg>
|
|
<span id="submit-btn-label">Envoyer ma photo</span>
|
|
</button>
|
|
</form>
|
|
</main>
|
|
|
|
<!--
|
|
config.js n'est PAS commité (voir .gitignore) : copier config.example.js
|
|
en config.js et renseigner les vraies valeurs Supabase avant déploiement.
|
|
Chargé en script classique (donc synchrone, avant le module) pour garantir
|
|
que window.__PHOTOBOOTH_CONFIG__ existe avant l'exécution de upload.js.
|
|
-->
|
|
<script src="/e/config.js"></script>
|
|
<script type="module" src="/e/upload.js"></script>
|
|
</body>
|
|
</html>
|