theme and camera cookie

This commit is contained in:
Shiro-Nek0
2026-02-27 00:57:45 -03:00
parent 8cba7937c3
commit 7235c7ff09
2 changed files with 161 additions and 30 deletions

View File

@@ -872,18 +872,25 @@
try { try {
const devices = await Html5Qrcode.getCameras(); const devices = await Html5Qrcode.getCameras();
const select = document.getElementById('camera-select'); const select = document.getElementById('camera-select');
select.innerHTML = ''; // Clear "loading" message select.innerHTML = '';
if (devices && devices.length) { if (devices && devices.length) {
devices.forEach((device, index) => { devices.forEach((device, index) => {
const option = document.createElement('option'); const option = document.createElement('option');
option.value = device.id; option.value = device.id;
// Store the index in a data attribute for easier retrieval later
option.dataset.index = index;
option.text = device.label || `Cámara ${index + 1}`; option.text = device.label || `Cámara ${index + 1}`;
select.appendChild(option); select.appendChild(option);
}); });
// Default to the last camera (often the main back camera on mobile) // Retrieve saved index or default to the last camera
currentCameraId = devices[devices.length - 1].id; const savedIndex = getCookie('cameraIndex');
const targetIndex = (savedIndex !== null && savedIndex < devices.length)
? savedIndex
: devices.length - 1;
currentCameraId = devices[targetIndex].id;
select.value = currentCameraId; select.value = currentCameraId;
launchCamera(currentCameraId); launchCamera(currentCameraId);
@@ -924,6 +931,14 @@
function switchCamera(cameraId) { function switchCamera(cameraId) {
if (cameraId) { if (cameraId) {
const select = document.getElementById('camera-select');
const selectedOption = select.options[select.selectedIndex];
// Save the index of the selected camera to a cookie
if (selectedOption && selectedOption.dataset.index !== undefined) {
setCookie('cameraIndex', selectedOption.dataset.index, 365);
}
currentCameraId = cameraId; currentCameraId = cameraId;
launchCamera(cameraId); launchCamera(cameraId);
} }
@@ -936,6 +951,69 @@
}).catch(err => console.error("Error stopping scanner", err)); }).catch(err => console.error("Error stopping scanner", err));
} }
} }
/* ── Theme Management ── */
// Helper to set a cookie
function setCookie(name, value, days = 365) {
const d = new Date();
d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
let expires = "expires=" + d.toUTCString();
document.cookie = name + "=" + value + ";" + expires + ";path=/;SameSite=Lax";
}
// Helper to get a cookie
function getCookie(name) {
let nameEQ = name + "=";
let ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
function applyTheme(t) {
document.documentElement.setAttribute('data-theme', t);
const isDark = t === 'dark';
const themeIcon = document.getElementById('theme-icon');
const themeLabel = document.getElementById('theme-label');
if (themeIcon) themeIcon.className = isDark ? 'bi bi-sun me-2' : 'bi bi-moon-stars me-2';
if (themeLabel) themeLabel.innerText = isDark ? 'Modo Claro' : 'Modo Oscuro';
setCookie('theme', t);
}
function toggleTheme() {
const current = document.documentElement.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
applyTheme(next);
}
// Initialization Logic
function initTheme() {
const savedTheme = getCookie('theme');
if (savedTheme) {
// Use user preference if it exists
applyTheme(savedTheme);
} else {
// Otherwise, detect OS preference
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
applyTheme(prefersDark ? 'dark' : 'light');
}
}
// Listen for OS theme changes in real-time if no cookie is set
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
if (!getCookie('theme')) {
applyTheme(e.matches ? 'dark' : 'light');
}
});
initTheme();
</script> </script>
</body> </body>

View File

@@ -1,14 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="es" data-theme="light"> <html lang="es" data-theme="light">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SekiPOS Login</title> <title>SekiPOS Login</title>
<link rel="shortcut icon" href="./static/favicon.png" type="image/x-icon"> <link rel="shortcut icon" href="./static/favicon.png" type="image/x-icon">
<link <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet"
>
<style> <style>
:root { :root {
--bg: #5865f2; --bg: #5865f2;
@@ -19,6 +17,7 @@
--accent-hover: #4752c4; --accent-hover: #4752c4;
--error: #ed4245; --error: #ed4245;
} }
[data-theme="dark"] { [data-theme="dark"] {
--bg: #36393f; --bg: #36393f;
--card-bg: #2f3136; --card-bg: #2f3136;
@@ -45,7 +44,7 @@
padding: 2rem; padding: 2rem;
width: 100%; width: 100%;
max-width: 400px; max-width: 400px;
box-shadow: 0 8px 24px rgba(0,0,0,0.25); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
transition: background 0.2s, color 0.2s; transition: background 0.2s, color 0.2s;
} }
@@ -54,10 +53,14 @@
color: var(--text) !important; color: var(--text) !important;
border: none; border: none;
} }
.form-control:focus { .form-control:focus {
box-shadow: 0 0 0 2px var(--accent); box-shadow: 0 0 0 2px var(--accent);
} }
.form-control::placeholder { color: #8a8e94; }
.form-control::placeholder {
color: #8a8e94;
}
.btn-login { .btn-login {
background: var(--accent); background: var(--accent);
@@ -65,6 +68,7 @@
border: none; border: none;
font-weight: 600; font-weight: 600;
} }
.btn-login:hover { .btn-login:hover {
background: var(--accent-hover); background: var(--accent-hover);
color: #fff; color: #fff;
@@ -78,6 +82,7 @@
} }
</style> </style>
</head> </head>
<body> <body>
<div class="login-box text-center"> <div class="login-box text-center">
<h2 class="fw-bold mb-1">SekiPOS</h2> <h2 class="fw-bold mb-1">SekiPOS</h2>
@@ -90,21 +95,8 @@
{% endwith %} {% endwith %}
<form method="POST"> <form method="POST">
<input <input class="form-control mb-3" type="text" name="username" placeholder="Usuario" required autofocus>
class="form-control mb-3" <input class="form-control mb-3" type="password" name="password" placeholder="Contraseña" required>
type="text"
name="username"
placeholder="Usuario"
required
autofocus
>
<input
class="form-control mb-3"
type="password"
name="password"
placeholder="Contraseña"
required
>
<button type="submit" class="btn btn-login w-100"> <button type="submit" class="btn btn-login w-100">
Iniciar Sesión Iniciar Sesión
</button> </button>
@@ -112,8 +104,69 @@
</div> </div>
<script> <script>
const t = localStorage.getItem('theme') || 'light'; /* ── Theme Management ── */
if (t === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
// Helper to set a cookie
function setCookie(name, value, days = 365) {
const d = new Date();
d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
let expires = "expires=" + d.toUTCString();
document.cookie = name + "=" + value + ";" + expires + ";path=/;SameSite=Lax";
}
// Helper to get a cookie
function getCookie(name) {
let nameEQ = name + "=";
let ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
function applyTheme(t) {
document.documentElement.setAttribute('data-theme', t);
const isDark = t === 'dark';
const themeIcon = document.getElementById('theme-icon');
const themeLabel = document.getElementById('theme-label');
if (themeIcon) themeIcon.className = isDark ? 'bi bi-sun me-2' : 'bi bi-moon-stars me-2';
if (themeLabel) themeLabel.innerText = isDark ? 'Modo Claro' : 'Modo Oscuro';
setCookie('theme', t);
}
function toggleTheme() {
const current = document.documentElement.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
applyTheme(next);
}
// Initialization Logic
function initTheme() {
const savedTheme = getCookie('theme');
if (savedTheme) {
// Use user preference if it exists
applyTheme(savedTheme);
} else {
// Otherwise, detect OS preference
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
applyTheme(prefersDark ? 'dark' : 'light');
}
}
// Listen for OS theme changes in real-time if no cookie is set
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
if (!getCookie('theme')) {
applyTheme(e.matches ? 'dark' : 'light');
}
});
initTheme();
</script> </script>
</body> </body>
</html> </html>