Files
photobooth-qr/src/e/index.html
T
KevinLecouandClaude Sonnet 5 e06f8afd3e Corrige le lien vers la galerie inatteignable derrière la modale + renomme "mur" en "fête"
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>
2026-09-18 09:54:09 +02:00

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&nbsp;!</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&nbsp;</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&nbsp;!</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&nbsp;!</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&nbsp;</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é&nbsp;!</p>
<p class="success-text">Ta photo vient de rejoindre la fête. Merci d'avoir été là&nbsp;!</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&nbsp;</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>