Add multi-user auth, admin panel, and timezone support; rename to Yolkbook
- Rename app from Eggtracker to Yolkbook throughout - Add JWT-based authentication (python-jose, passlib/bcrypt) - Add users table; all data tables gain user_id FK for full data isolation - Super admin credentials sourced from ADMIN_USERNAME/ADMIN_PASSWORD env vars, synced on every startup; orphaned rows auto-assigned to admin post-migration - Login page with self-registration; JWT stored in localStorage (30-day expiry) - Admin panel (/admin): list users, reset passwords, disable/enable, delete, and impersonate (Login As) with Return to Admin banner - Settings modal (gear icon in nav): timezone selector and change password - Timezone stored per-user; stats date windows computed in user's timezone; date input setToday() respects user timezone via Intl API - migrate_v2.sql for existing single-user installs - Auto-migration adds timezone column to users on startup - Updated README with full setup, auth, admin, and migration docs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -173,6 +173,7 @@ label { font-size: 0.875rem; font-weight: 500; }
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
input[type="date"],
|
||||
input[type="password"],
|
||||
textarea,
|
||||
select {
|
||||
padding: 0.5rem 0.75rem;
|
||||
@@ -259,4 +260,120 @@ td input[type="date"] {
|
||||
.nav-links { overflow-x: auto; scrollbar-width: none; }
|
||||
.nav-links::-webkit-scrollbar { display: none; }
|
||||
.nav-links a { padding: 0.4rem 0.55rem; font-size: 0.82rem; white-space: nowrap; }
|
||||
.nav-username { display: none; }
|
||||
}
|
||||
|
||||
/* ── Nav user section ─────────────────────────────────────────────────────── */
|
||||
.nav-user {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.nav-username {
|
||||
color: rgba(255,255,255,0.85);
|
||||
font-size: 0.88rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-impersonating {
|
||||
color: #ffe08a;
|
||||
font-size: 0.85rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-admin-btn {
|
||||
color: rgba(255,255,255,0.85) !important;
|
||||
border-color: rgba(255,255,255,0.35) !important;
|
||||
}
|
||||
.nav-admin-btn:hover {
|
||||
background: rgba(255,255,255,0.15) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.btn-amber { background: var(--amber); color: #fff; }
|
||||
.btn-amber:hover { background: #b8720a; }
|
||||
|
||||
/* ── Login page ───────────────────────────────────────────────────────────── */
|
||||
.login-body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
.login-container {
|
||||
width: 100%;
|
||||
max-width: 380px;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.login-brand {
|
||||
text-align: center;
|
||||
font-size: 1.6rem;
|
||||
font-weight: 700;
|
||||
color: var(--green);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.login-card { padding: 2rem; }
|
||||
|
||||
.login-title {
|
||||
text-align: center;
|
||||
font-size: 1.3rem;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
/* ── Modals ───────────────────────────────────────────────────────────────── */
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.45);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 500;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.modal-box {
|
||||
background: var(--card-bg);
|
||||
border-radius: var(--radius);
|
||||
padding: 1.75rem;
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,0.18);
|
||||
}
|
||||
|
||||
.modal-box h2 { margin-bottom: 1rem; }
|
||||
|
||||
/* ── Badges ───────────────────────────────────────────────────────────────── */
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 0.2rem 0.55rem;
|
||||
border-radius: 99px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.badge-admin { background: #d4edff; color: #0055aa; }
|
||||
.badge-user { background: #e8f5e9; color: #2e6b3e; }
|
||||
.badge-active { background: #d4edda; color: #155724; }
|
||||
.badge-disabled { background: #f8d7da; color: #721c24; }
|
||||
|
||||
/* ── Settings modal extras ────────────────────────────────────────────────── */
|
||||
.settings-section-title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--green-dark);
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.settings-divider {
|
||||
border: none;
|
||||
border-top: 1px solid var(--border);
|
||||
margin: 1.25rem 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user