68b0a36031
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/
108 lines
3.8 KiB
HTML
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>
|