Fix: auth en NGINX, Tailwind local, soporte teclado y layout desktop

- Auth movida a NGINX (Basic Auth en htpasswd) para que fetch() del browser
  incluya credenciales automáticamente — resuelve categorías sin cargar y POST fallido
- Tailwind CDN descargado al build del Docker y servido localmente — elimina
  dependencia externa en cada carga de página
- Soporte de teclado físico en add.html (números, punto/coma, Backspace, Enter)
- Layout centrado en desktop con max-w-md mx-auto en las tres páginas
- Eliminada imagen decorativa externa y links de fonts duplicados

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ricardo Monla
2026-06-03 16:19:37 -03:00
co-authored by Claude Sonnet 4.6
parent 1db200343d
commit 1244235820
10 changed files with 73 additions and 36 deletions
+3
View File
@@ -1,2 +1,5 @@
# Credenciales locales — nunca commitear
pagos/api/config.php
# Assets generados (se descargan al hacer docker compose build)
pagos/js/tailwind.cdn.js
+10 -2
View File
@@ -1,6 +1,14 @@
FROM php:8.2-fpm-alpine
RUN apk add --no-cache sqlite sqlite-dev \
&& docker-php-ext-install pdo pdo_sqlite
RUN apk add --no-cache sqlite sqlite-dev curl \
&& docker-php-ext-install pdo pdo_sqlite \
&& curl -sL "https://cdn.tailwindcss.com?plugins=forms,container-queries" \
-o /tmp/tailwind.cdn.js
WORKDIR /var/www/html
COPY docker/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["php-fpm"]
+1
View File
@@ -13,6 +13,7 @@ services:
volumes:
- ./pagos:/var/www/html
- ./docker/nginx.conf:/etc/nginx/conf.d/default.conf
- ./docker/htpasswd:/etc/nginx/.htpasswd:ro
depends_on:
- app
networks:
+6
View File
@@ -0,0 +1,6 @@
#!/bin/sh
# Copiar tailwind.cdn.js al directorio servido si no existe
if [ ! -f /var/www/html/js/tailwind.cdn.js ]; then
cp /tmp/tailwind.cdn.js /var/www/html/js/tailwind.cdn.js
fi
exec "$@"
+1
View File
@@ -0,0 +1 @@
root:$apr1$69HFcTHn$9hHiieirPfFe3M.lo87O21
+5
View File
@@ -5,6 +5,9 @@ server {
resolver 127.0.0.11 valid=10s;
auth_basic "Quiet Wealth";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
try_files $uri $uri/ =404;
}
@@ -15,6 +18,8 @@ server {
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PHP_AUTH_USER $remote_user;
fastcgi_param PHP_AUTH_PW $http_authorization;
}
location ~ /db/ {
+5 -7
View File
@@ -4,10 +4,9 @@
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>Nuevo Movimiento - Sanctuary</title>
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@300;400;500;600;700;800&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<script src="js/tailwind.cdn.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
<script id="tailwind-config">
tailwind.config = {
darkMode: "class",
@@ -98,6 +97,7 @@
</style>
</head>
<body class="bg-background text-on-background min-h-screen flex flex-col">
<div class="max-w-md mx-auto w-full flex flex-col flex-1 relative">
<!-- Top AppBar - Transactional Context (Shell Suppressed per mandate) -->
<header class="bg-[#f8faf9] dark:bg-[#191c1c] w-full top-0 px-6 py-4 flex justify-between items-center bg-transparent">
<div class="flex items-center gap-4">
@@ -174,9 +174,7 @@
<span class="material-symbols-outlined" data-icon="check_circle">check_circle</span>
</button>
</div>
<!-- Background Decorative Image (Sanctuary Aesthetic) -->
<div class="fixed top-0 right-0 -z-10 opacity-10">
<img alt="Calm plant leaves" class="w-64 h-64 object-cover rounded-full blur-xl translate-x-20 -translate-y-20" data-alt="Close-up of minimalist green tropical leaves with soft natural light and subtle shadows on a neutral background" src="https://lh3.googleusercontent.com/aida-public/AB6AXuD2h_FlCe-zmCdWpoDHshmlKT5cXI45RMNZ5-AgxCqZYUPAm3glpQE_wwgbqJ2nxoYSqTenbalJ4bQQBYGIiBfP5wtSkQt6hOJ-Gtl_cifGTAktK43DvjfdfiHDniAMFOJUG0cJmjTrd3nISnFPn-xNsg3CSTGPMIIW_n5H7HSUQcYBeDxWje7Wu8zDxapTTpMfci3Y4IeXwn-Wq94lmbuXPYPbpNtL19_R_6JNyujOMerXEhtUQm5nUIjIEG27anBV5TGHfaZabw"/>
</div>
<script src="js/ui.js"></script>
<script src="js/add.js"></script>
</body></html>
+4 -2
View File
@@ -4,7 +4,7 @@
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>Historial - Quiet Wealth</title>
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<script src="js/tailwind.cdn.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
<script id="tailwind-config">
@@ -82,6 +82,7 @@
</style>
</head>
<body class="bg-background text-on-background min-h-screen pb-24">
<div class="max-w-md mx-auto relative">
<!-- Header -->
<header class="bg-[#f8faf9] sticky top-0 z-40 px-6 py-4 flex items-center gap-4">
@@ -108,13 +109,14 @@
</main>
<!-- FAB agregar -->
<div class="fixed bottom-6 right-6 z-50">
<div class="fixed bottom-6 right-6 z-50 md:right-[calc(50%-176px)]">
<button onclick="window.location.href='add.html'"
class="w-14 h-14 bg-primary text-white rounded-2xl shadow-lg shadow-primary/30 flex items-center justify-center active:scale-90 transition-transform">
<span class="material-symbols-outlined">add</span>
</button>
</div>
</div>
<script src="js/ui.js"></script>
<script src="js/historial.js"></script>
</body>
+10 -11
View File
@@ -3,10 +3,9 @@
<html lang="en"><head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<script src="js/tailwind.cdn.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
<script id="tailwind-config">
tailwind.config = {
darkMode: "class",
@@ -89,6 +88,7 @@
</style>
</head>
<body class="bg-background text-on-background min-h-screen pb-32">
<div class="max-w-md mx-auto relative">
<!-- TopAppBar -->
<header class="bg-[#f8faf9] dark:bg-slate-950 docked full-width top-0 sticky z-40">
<div class="flex justify-between items-center w-full px-6 py-4">
@@ -218,19 +218,18 @@
</section>
</main>
<!-- BottomNavBar -->
<nav class="fixed bottom-0 left-0 w-full z-50 flex justify-around items-center px-8 pb-8 pt-4 bg-[#ffffff]/70 dark:bg-slate-900/70 backdrop-blur-xl shadow-[0px_-12px_32px_rgba(0,80,80,0.06)] rounded-t-[2rem]">
<nav class="fixed bottom-0 left-0 right-0 max-w-md mx-auto z-50 flex justify-around items-center px-8 pb-8 pt-4 bg-[#ffffff]/70 backdrop-blur-xl shadow-[0px_-12px_32px_rgba(0,80,80,0.06)] rounded-t-[2rem]">
<button class="flex items-center justify-center bg-[#006a6a] text-white rounded-2xl p-3 shadow-lg shadow-[#006a6a]/20 active:scale-90 transition-transform duration-300">
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 1;">home</span>
</button>
<button class="flex items-center justify-center text-[#3e4948] dark:text-slate-400 p-3 hover:text-[#006a6a] dark:hover:text-teal-300 active:scale-90 transition-transform duration-300" onclick="window.location.href='historial.html'">
<button class="flex items-center justify-center text-[#3e4948] p-3 hover:text-[#006a6a] active:scale-90 transition-transform duration-300" onclick="window.location.href='historial.html'">
<span class="material-symbols-outlined">history</span>
</button>
<button class="flex items-center justify-center text-[#3e4948] dark:text-slate-400 p-3 hover:text-[#006a6a] dark:hover:text-teal-300 active:scale-90 transition-transform duration-300">
<span class="material-symbols-outlined">credit_card</span>
</button>
<button class="flex items-center justify-center text-[#3e4948] dark:text-slate-400 p-3 hover:text-[#006a6a] dark:hover:text-teal-300 active:scale-90 transition-transform duration-300">
<span class="material-symbols-outlined">person</span>
<button class="flex items-center justify-center text-[#3e4948] p-3 hover:text-[#006a6a] active:scale-90 transition-transform duration-300" onclick="window.location.href='add.html'">
<span class="material-symbols-outlined">add_circle</span>
</button>
</nav>
</div>
<script src="js/ui.js"></script>
<script src="js/dashboard.js"></script>
</body></html>
+28 -14
View File
@@ -43,25 +43,39 @@ document.addEventListener('DOMContentLoaded', () => {
btnGasto.addEventListener('click', () => { selectedTipo = 'gasto'; updateTipoUI(); });
btnIngreso.addEventListener('click', () => { selectedTipo = 'ingreso'; updateTipoUI(); });
// Numpad logic
function applyInput(val) {
if (val === 'backspace') {
currentMonto = currentMonto.slice(0, -1);
if (currentMonto === '') currentMonto = "0";
} else if (/^[0-9]$/.test(val)) {
if (currentMonto === "0") {
currentMonto = val;
} else {
currentMonto += val;
}
} else if (val === '.') {
if (!currentMonto.includes('.')) currentMonto += '.';
}
montoEl.textContent = currentMonto;
}
// Numpad táctil
numpad.addEventListener('click', (e) => {
const btn = e.target.closest('button');
if (!btn) return;
const val = btn.textContent.trim() || btn.innerText.trim();
if (val === 'backspace' || btn.querySelector('[data-icon="backspace"]')) {
currentMonto = currentMonto.slice(0, -1);
if (currentMonto === '') currentMonto = "0";
if (btn.querySelector('[data-icon="backspace"]')) {
applyInput('backspace');
} else {
if (currentMonto === "0" && val !== ".") {
currentMonto = val;
} else {
if (val === "." && currentMonto.includes(".")) return;
currentMonto += val;
}
applyInput(btn.textContent.trim());
}
montoEl.textContent = currentMonto;
});
// Teclado físico (desktop)
document.addEventListener('keydown', (e) => {
if (e.key >= '0' && e.key <= '9') applyInput(e.key);
else if (e.key === '.' || e.key === ',') applyInput('.');
else if (e.key === 'Backspace') applyInput('backspace');
else if (e.key === 'Enter') btnSave.click();
});
// Guardar Movimiento