Files
admin 68b0a36031
🚀 Deploy — JH Photomaton / 🔍 Vérification (push) Has been cancelled
🚀 Deploy — JH Photomaton / 🍓 Deploy sur le Pi (push) Has been cancelled
Changes to be committed:
modified:   Opencode/scripts/script_print.sh
	modified:   backend/services/printer_service.py
	modified:   frontend/templates/admin/actions.html
	modified:   frontend/templates/admin/events.html
	modified:   frontend/templates/admin/gallery.html
	modified:   frontend/templates/admin/settings.html
	modified:   frontend/templates/base.html
	modified:   frontend/templates/public/gallery.html
 Untracked files:
	photobooth-app/script/
	photobooth-app/userdata/
2026-07-17 17:02:57 +02:00

108 lines
3.8 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}JH Photomaton{% endblock %}</title>
<link rel="stylesheet" href="/static/css/main.css">
{% block head %}{% endblock %}
</head>
<body>
{% block navbar %}
<nav class="navbar">
<div class="navbar-brand">📷 <span>JH</span> Photomaton</div>
<div class="navbar-links">
{% set p = request.url.path %}
{% if p.startswith('/admin') %}
<a href="/admin" class="{{ 'active' if p == '/admin' or p == '/admin/' else '' }}">Dashboard</a>
<a href="/admin/gallery" class="{{ 'active' if p.startswith('/admin/gallery') else '' }}">Galerie</a>
<a href="/admin/actions" class="{{ 'active' if p.startswith('/admin/actions') else '' }}">Actions</a>
<a href="/admin/print" class="{{ 'active' if p.startswith('/admin/print') else '' }}">Impression</a>
<a href="/admin/settings" class="{{ 'active' if p.startswith('/admin/settings') else '' }}">Réglages</a>
<a href="/admin/events" class="{{ 'active' if p.startswith('/admin/events') else '' }}">Événements</a>
<a href="/admin/logout">Déconnexion</a>
{% elif p.startswith('/gallery') or p == '/' %}
<a href="/gallery" class="{{ 'active' if p.startswith('/gallery') else '' }}">📷 Galerie photos</a>
{% else %}
{% block nav_links %}{% endblock %}
{% endif %}
</div>
<div class="navbar-status" id="ws-status">
<span class="dot dot-gray" id="ws-dot"></span>
<span id="ws-label">Connexion…</span>
</div>
</nav>
{% endblock %}
<main>
{% block content %}{% endblock %}
</main>
<!-- Toast container -->
<div class="toast-container" id="toasts"></div>
<script>
// ── WebSocket global ─────────────────────────────────────────────────────────
let ws = null;
let wsReconnectTimer = null;
function connectWS() {
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
ws = new WebSocket(`${proto}//${location.host}/ws`);
ws.onopen = () => {
document.getElementById('ws-dot').className = 'dot dot-green';
document.getElementById('ws-label').textContent = 'Connecté';
clearTimeout(wsReconnectTimer);
};
ws.onclose = () => {
document.getElementById('ws-dot').className = 'dot dot-red';
document.getElementById('ws-label').textContent = 'Déconnecté';
wsReconnectTimer = setTimeout(connectWS, 3000);
};
ws.onerror = () => ws.close();
ws.onmessage = (e) => {
try {
const msg = JSON.parse(e.data);
handleWsMessage(msg);
} catch(err) {}
};
}
function handleWsMessage(msg) {
// Override dans chaque page si besoin
if (typeof onWsMessage === 'function') onWsMessage(msg);
}
// ── Toast notifications ──────────────────────────────────────────────────────
function showToast(text, type = 'info', duration = 4000) {
const el = document.createElement('div');
el.className = `toast ${type}`;
el.textContent = text;
document.getElementById('toasts').appendChild(el);
setTimeout(() => el.remove(), duration);
}
// ── API helper ───────────────────────────────────────────────────────────────
async function api(method, url, body = null) {
const opts = { method, headers: {} };
if (body) {
opts.headers['Content-Type'] = 'application/json';
opts.body = JSON.stringify(body);
}
const r = await fetch(url, opts);
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return r.json();
}
connectWS();
</script>
{% block scripts %}{% endblock %}
</body>
</html>