From 229a388a1edc7a244db98ed4bb641677708057ab Mon Sep 17 00:00:00 2001 From: Jules Date: Tue, 7 Apr 2026 18:12:51 +0200 Subject: [PATCH] Wizard evenement tactile + menu admin simplifie + bouton update + logo SikaPics - Wizard: 6 etapes (nom, theme, modes, nb photos, partage, resume) - Gros boutons tactiles, une question par ecran - Parametres avances accessibles depuis le wizard - Bouton "Mettre a jour l'affichage" dans Fonctions > Systeme - Logo SikaPics dans le theme sikapics - Menu admin reorganise: Materiel / Compteur / Destinations / Personnalisation / Evenement / Fonctions Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/css/style.css | 187 ++++++++++++++++++++++++++++++++++++++++ frontend/css/themes.css | 12 +++ frontend/index.html | 180 ++++++++++++++++++++++++++------------ frontend/js/app.js | 120 +++++++++++++++++++++++++- 4 files changed, 440 insertions(+), 59 deletions(-) diff --git a/frontend/css/style.css b/frontend/css/style.css index dbe4326..694bde8 100644 --- a/frontend/css/style.css +++ b/frontend/css/style.css @@ -1203,6 +1203,193 @@ h3 { border-radius: 3px; } +/* === Wizard === */ +.wizard-header { + position: absolute; + top: 0; + left: 0; + right: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 1rem 1.5rem; + z-index: 10; +} + +.wizard-progress { + display: flex; + gap: 8px; +} + +.wizard-dot { + width: 12px; + height: 12px; + border-radius: 50%; + background: rgba(255,255,255,0.2); + transition: 0.3s; +} + +.wizard-dot.actif { + background: var(--primaire); + transform: scale(1.3); +} + +.wizard-dot.fait { + background: var(--succes); +} + +.wizard-step { + display: none; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 2rem; + padding: 2rem; + width: 100%; + height: 100%; + animation: fadeIn 0.3s ease; +} + +.wizard-step.actif { + display: flex; +} + +.wizard-step h2 { + font-size: 2rem; + font-weight: 600; +} + +.wizard-input { + width: 80%; + max-width: 500px; + padding: 1.2rem 1.5rem; + font-size: 1.5rem; + border: 2px solid rgba(255,255,255,0.2); + border-radius: var(--rayon); + background: var(--fond-carte); + color: var(--texte); + text-align: center; + outline: none; +} + +.wizard-input:focus { + border-color: var(--primaire); +} + +.wizard-choix { + display: flex; + gap: 1.5rem; + flex-wrap: wrap; + justify-content: center; +} + +.wizard-choix-wrap { + max-width: 600px; +} + +.wizard-card { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.8rem; + padding: 1.5rem 2rem; + border: 3px solid rgba(255,255,255,0.1); + border-radius: var(--rayon); + background: var(--fond-carte); + color: var(--texte); + cursor: pointer; + transition: 0.2s; + min-width: 140px; + font-size: 1.1rem; +} + +.wizard-card:active { + transform: scale(0.95); +} + +.wizard-card.actif { + border-color: var(--primaire); + background: rgba(233, 30, 99, 0.15); +} + +.wizard-card-icon { + font-size: 3rem; + width: 80px; + height: 80px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; +} + +.wizard-nombre { + display: flex; + align-items: center; + gap: 2rem; +} + +.wizard-nb-btn { + width: 80px; + height: 80px; + border-radius: 50%; + border: 3px solid var(--primaire); + background: transparent; + color: var(--primaire); + font-size: 2.5rem; + font-weight: bold; + cursor: pointer; +} + +.wizard-nb-btn:active { + background: var(--primaire); + color: #fff; +} + +.wizard-nb-val { + font-size: 5rem; + font-weight: bold; + min-width: 80px; + text-align: center; +} + +.wizard-btn-next { + padding: 1.2rem 3rem; + font-size: 1.3rem; + font-weight: 600; + border: none; + border-radius: var(--rayon); + background: var(--primaire); + color: #fff; + cursor: pointer; + min-width: 200px; + margin-top: 1rem; +} + +.wizard-btn-next:active { + transform: scale(0.95); +} + +.wizard-btn-go { + font-size: 1.5rem; + padding: 1.5rem 4rem; + background: var(--succes); +} + +.wizard-resume { + background: var(--fond-carte); + border-radius: var(--rayon); + padding: 1.5rem 2rem; + font-size: 1.1rem; + line-height: 2; + text-align: left; + min-width: 300px; +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(20px); } + to { opacity: 1; transform: translateY(0); } +} + /* Responsive tactile */ @media (max-width: 800px) { .accueil-contenu h1 { font-size: 2.5rem; } diff --git a/frontend/css/themes.css b/frontend/css/themes.css index 9308f38..bf8d06e 100644 --- a/frontend/css/themes.css +++ b/frontend/css/themes.css @@ -54,6 +54,18 @@ font-weight: 600; } +[data-theme="sikapics"] #nom-evenement::before { + content: ''; + display: block; + width: 180px; + height: 60px; + margin: 0 auto 1rem; + background-image: url('https://sikapics.com/wp-content/uploads/2024/03/sikapics-logo-sans-fond.png'); + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} + [data-theme="sikapics"] .accueil-instruction { color: var(--texte-secondaire); font-weight: 300; diff --git a/frontend/index.html b/frontend/index.html index 6d690f4..fe0b47a 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -134,10 +134,100 @@ - + +
+
+ +
+
+ + +
+

Nom de l'evenement

+ + +
+ + +
+

Theme visuel

+
+ + +
+ +
+ + +
+

Modes photo

+
+ + +
+ +
+ + +
+

Photos par pellicule

+
+ + 4 + +
+ +
+ + +
+

Partage

+
+ + + + +
+ +
+ + +
+

C'est pret !

+
+ + +
+
+ +
-

Parametres

+

Parametres avances

@@ -145,15 +235,9 @@ - - - + - - - - - +
@@ -254,50 +338,39 @@ - -
-

Cadres disponibles

+ +
+

Cadres / Overlays

Cochez les cadres a proposer aux utilisateurs.

Aucun cadre importe

-

Importer un cadre

- +
-
- -
-

Fonds pour chroma key

-

Importez des images de fond. Les utilisateurs choisiront leur fond apres la photo.

+

Fonds (chroma key)

+

Importez des images de fond pour le mode fond vert.

Aucun fond importe

-

Importer un fond

- +
-
- -
-

Animations CSS

-

Cochez les animations a utiliser. Si plusieurs sont cochees, une sera choisie au hasard a chaque photo.

+

Animations 3-2-1

+

Si plusieurs sont cochees, une sera choisie au hasard.

- -

Animations personnalisees (video/GIF)

-

Importez vos propres animations (GIF, MP4, WebM). Elles seront jouees en plein ecran avant la capture.

+

Animations personnalisees (video/GIF)

-

Apercu

@@ -343,56 +416,50 @@
- -
+ +
+

Modes photo

- + +
+ +

Partage

+
- +
-
- -
+

Email SMTP

- -
+ - -

Galerie Live

-

Les photos sont envoyees en temps reel sur un site web. Les invites scannent le QR code sur l'ecran d'accueil.

+

Photos envoyees en temps reel. QR code + code sur l'ecran d'accueil.

- +
-
+
- + -
- -
+

Galerie locale

- - +
@@ -400,10 +467,9 @@
-
- -
+

Systeme

+
diff --git a/frontend/js/app.js b/frontend/js/app.js index bae7863..afd18e4 100644 --- a/frontend/js/app.js +++ b/frontend/js/app.js @@ -152,11 +152,11 @@ function validerMdpAdmin() { const input = document.getElementById('input-mdp-admin'); if (input.value === MDP_ADMIN) { fermerPopupMdp(); - allerA('admin'); + allerA('wizard'); + wizardInit(); } else { document.getElementById('mdp-erreur').classList.remove('cache'); input.value = ''; - input.focus(); } } @@ -252,5 +252,121 @@ wsOnMessage('config_maj', (msg) => { appliquerConfig(); }); +// === WIZARD === + +let wizardStep = 1; +const WIZARD_TOTAL = 6; +let wizardData = { + nom: '', + theme: 'base', + modes: { simple: true, multi: true }, + nbPhotos: 4, + fonctions: {}, +}; + +function wizardInit() { + wizardStep = 1; + wizardData.nom = config.evenement?.nom || ''; + wizardData.theme = config.evenement?.theme || 'base'; + wizardData.nbPhotos = config.multi_shot?.nombre_photos || 4; + document.getElementById('wiz-nom').value = wizardData.nom; + document.getElementById('wiz-nb-photos').textContent = wizardData.nbPhotos; + wizardAfficherStep(); +} + +function wizardAfficherStep() { + document.querySelectorAll('.wizard-step').forEach(s => s.classList.remove('actif')); + const step = document.querySelector(`.wizard-step[data-step="${wizardStep}"]`); + if (step) step.classList.add('actif'); + + // Progress dots + const prog = document.getElementById('wizard-progress'); + prog.innerHTML = ''; + for (let i = 1; i <= WIZARD_TOTAL; i++) { + const dot = document.createElement('div'); + dot.className = 'wizard-dot' + (i === wizardStep ? ' actif' : '') + (i < wizardStep ? ' fait' : ''); + prog.appendChild(dot); + } +} + +function wizardSuivant() { + // Sauvegarder l'etape courante + if (wizardStep === 1) wizardData.nom = document.getElementById('wiz-nom').value; + if (wizardStep === 4) wizardData.nbPhotos = parseInt(document.getElementById('wiz-nb-photos').textContent); + + wizardStep++; + if (wizardStep > WIZARD_TOTAL) wizardStep = WIZARD_TOTAL; + + // Resume + if (wizardStep === WIZARD_TOTAL) { + const modes = Object.keys(wizardData.modes).filter(k => wizardData.modes[k]); + const foncs = Object.keys(wizardData.fonctions).filter(k => wizardData.fonctions[k]); + document.getElementById('wiz-resume').innerHTML = ` +
Evenement : ${wizardData.nom || 'Photobooth'}
+
Theme : ${wizardData.theme}
+
Modes : ${modes.join(', ') || 'photo'}
+
Photos/pellicule : ${wizardData.nbPhotos}
+
Partage : ${foncs.join(', ') || 'aucun'}
+ `; + } + + wizardAfficherStep(); +} + +function wizardChoisir(btn, key) { + btn.closest('.wizard-choix').querySelectorAll('.wizard-card').forEach(c => c.classList.remove('actif')); + btn.classList.add('actif'); + wizardData[key] = btn.dataset.val; +} + +function wizardToggle(btn) { + btn.classList.toggle('actif'); + const val = btn.dataset.val; + const isActive = btn.classList.contains('actif'); + + if (['simple', 'multi'].includes(val)) { + wizardData.modes[val] = isActive; + } else { + wizardData.fonctions[val] = isActive; + } +} + +function wizardNbPhotos(delta) { + const el = document.getElementById('wiz-nb-photos'); + let n = parseInt(el.textContent) + delta; + n = Math.max(2, Math.min(8, n)); + el.textContent = n; + wizardData.nbPhotos = n; +} + +async function wizardTerminer() { + // Sauvegarder toute la config + await apiPost('/api/config', { + evenement: { + nom: wizardData.nom || 'Photobooth', + theme: wizardData.theme, + }, + fonctionnalites: { + photo_simple: wizardData.modes.simple !== false, + multi_shot: wizardData.modes.multi !== false, + impression: !!wizardData.fonctions.impression, + email: !!wizardData.fonctions.email, + qr_code: !!wizardData.fonctions.qr, + }, + multi_shot: { + nombre_photos: wizardData.nbPhotos, + mode: 'strip', + }, + booth: { + actif: !!wizardData.fonctions.galerie_live, + }, + }); + + config = await apiGet('/api/config'); + appliquerConfig(); + chargerBoothInfo(); + allerA('accueil'); +} + // Demarrage document.addEventListener('DOMContentLoaded', init);