ClubLedger/static/style.css
Claude a5c9af1ca6
Add staff auth, admin area, currency decimal input
Auth system
- staff_accounts table: name, username, bcrypt password, role (staff|admin)
- Session tokens in memory (8-hour TTL), httpOnly cookie
- POST /auth/login, /auth/logout, GET /auth/me
- All API endpoints now require a valid session
- Default admin account seeded on first run (admin/admin), printed to console
- Staff name for transactions comes from the session, no more dropdown

Currency input fix
- Amount inputs are now decimal (step=0.01); users enter 1.00 not 100
- Frontend multiplies by cfg.currency_divisor before POSTing
- TopupRequest/ChargeRequest no longer include staff_name (from session)

Admin area (4th tab, admin role only)
- App Settings: club name, currency symbol, major/minor unit names,
  divisor, min/max topup, max charge, receipt footer, allow overdraft
- Settings persisted in app_settings DB table; merged with CONFIG defaults
  at startup and refreshed after each save
- Staff Accounts: list with edit modal (name, username, password, role,
  active flag) and delete; Add Account inline form
- /admin/settings GET/POST, /admin/staff-accounts CRUD
- /config endpoint exposes live settings to frontend on every page load

receipt_footer field rendered on both receipt and statement print views

https://claude.ai/code/session_01JuRTR5Xjx8emQsyerBgGU7
2026-05-30 09:19:07 +00:00

275 lines
8.1 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ClubLedger main styles */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--primary: #1a56db;
--primary-dark: #1140a6;
--danger: #d63b3b;
--danger-dark: #a82e2e;
--success: #1a7f3c;
--bg: #f4f6fb;
--panel-bg: #ffffff;
--border: #d1d5db;
--text: #111827;
--muted: #6b7280;
--nav-bg: #1a1a2e;
--nav-text: #e0e0e0;
}
body { font-family: 'Segoe UI', system-ui, sans-serif; background: var(--bg); color: var(--text); min-height: 100vh; }
/* ---- Nav ---- */
nav {
background: var(--nav-bg);
color: var(--nav-text);
display: flex;
align-items: center;
padding: 0 20px;
height: 52px;
gap: 8px;
position: sticky;
top: 0;
z-index: 100;
}
.brand { font-size: 1.2rem; font-weight: 700; letter-spacing: .5px; margin-right: 16px; color: #fff; }
.nav-btn {
background: transparent;
border: 2px solid transparent;
color: var(--nav-text);
padding: 6px 16px;
border-radius: 6px;
cursor: pointer;
font-size: .95rem;
transition: background .15s, border-color .15s;
}
.nav-btn:hover { background: rgba(255,255,255,.1); }
.nav-btn.active { border-color: #4a9eff; color: #fff; }
.nav-link {
color: var(--nav-text);
text-decoration: none;
padding: 6px 16px;
border-radius: 6px;
border: 2px solid transparent;
font-size: .95rem;
transition: background .15s, border-color .15s;
}
.nav-link:hover { background: rgba(255,255,255,.1); }
.nav-link.active { border-color: #4a9eff; color: #fff; }
/* ---- Views ---- */
.view { max-width: 900px; margin: 28px auto; padding: 0 16px; display: flex; flex-direction: column; gap: 24px; }
.hidden { display: none !important; }
/* ---- Panel ---- */
.panel { background: var(--panel-bg); border: 1px solid var(--border); border-radius: 10px; padding: 24px; }
.panel h2 { font-size: 1.15rem; margin-bottom: 18px; color: var(--text); }
/* ---- Forms ---- */
.form-row { display: flex; flex-direction: column; gap: 4px; margin-bottom: 14px; }
.form-row label { font-size: .85rem; font-weight: 600; color: var(--muted); }
.form-row input {
padding: 9px 12px;
border: 1px solid var(--border);
border-radius: 6px;
font-size: 1rem;
outline: none;
transition: border-color .15s;
}
.form-row input:focus { border-color: var(--primary); }
.search-row { display: flex; gap: 8px; margin-bottom: 14px; }
.search-row input { flex: 1; padding: 9px 12px; border: 1px solid var(--border); border-radius: 6px; font-size: 1rem; outline: none; }
.search-row input:focus { border-color: var(--primary); }
/* ---- Buttons ---- */
.btn {
padding: 9px 20px;
border: 1px solid var(--border);
border-radius: 6px;
background: #fff;
cursor: pointer;
font-size: .95rem;
transition: background .15s;
margin-right: 6px;
}
.btn:hover { background: #f0f0f0; }
.btn-primary { background: var(--primary); color: #fff; border-color: var(--primary); }
.btn-primary:hover { background: var(--primary-dark); }
.btn-danger { background: var(--danger); color: #fff; border-color: var(--danger); }
.btn-danger:hover { background: var(--danger-dark); }
/* ---- Data table ---- */
.data-table { width: 100%; border-collapse: collapse; font-size: .93rem; margin-top: 8px; }
.data-table th { background: #f0f2f7; padding: 8px 10px; text-align: left; font-weight: 600; border-bottom: 2px solid var(--border); }
.data-table td { padding: 8px 10px; border-bottom: 1px solid #eee; }
.data-table tr:last-child td { border-bottom: none; }
.data-table tr:hover td { background: #f9f9ff; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.balance-pos { color: var(--success); font-weight: 600; }
.balance-neg { color: var(--danger); font-weight: 600; }
/* ---- Member pick list ---- */
.member-pick-list { margin-bottom: 14px; }
.member-pick-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 14px;
border: 1px solid var(--border);
border-radius: 6px;
margin-bottom: 6px;
cursor: pointer;
transition: background .12s, border-color .12s;
}
.member-pick-item:hover { background: #eef2ff; border-color: var(--primary); }
.member-pick-name { font-weight: 600; }
.member-pick-sub { font-size: .83rem; color: var(--muted); }
/* ---- Selected member box ---- */
.selected-member-box {
background: #eef2ff;
border: 1px solid #c7d2f7;
border-radius: 8px;
padding: 12px 16px;
margin-bottom: 16px;
font-size: .95rem;
}
.selected-member-box strong { font-size: 1.05rem; }
/* ---- Product results ---- */
.product-results { margin-bottom: 14px; }
.product-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
border: 1px solid var(--border);
border-radius: 6px;
margin-bottom: 5px;
cursor: pointer;
transition: background .12s;
}
.product-item:hover { background: #f0fff4; border-color: #34d399; }
.product-price { font-weight: 700; color: var(--primary); }
/* ---- Staff chips ---- */
.staff-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.staff-chip {
display: inline-flex;
align-items: center;
gap: 6px;
background: #eef2ff;
border: 1px solid #c7d2f7;
border-radius: 20px;
padding: 4px 10px 4px 12px;
font-size: .88rem;
}
.chip-del {
background: none;
border: none;
cursor: pointer;
color: #888;
font-size: 1rem;
line-height: 1;
padding: 0;
}
.chip-del:hover { color: var(--danger); }
/* ---- Select / dropdown ---- */
.form-row select {
padding: 9px 12px;
border: 1px solid var(--border);
border-radius: 6px;
font-size: 1rem;
outline: none;
background: #fff;
cursor: pointer;
transition: border-color .15s;
}
.form-row select:focus { border-color: var(--primary); }
/* ---- Row action buttons ---- */
.row-actions { white-space: nowrap; }
.row-btn { padding: 4px 10px !important; font-size: .82rem !important; margin-right: 4px !important; }
/* ---- Edit modal ---- */
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,.45);
display: flex;
align-items: center;
justify-content: center;
z-index: 200;
}
.modal {
background: #fff;
border-radius: 10px;
padding: 28px 32px;
width: 420px;
max-width: calc(100vw - 32px);
box-shadow: 0 20px 60px rgba(0,0,0,.3);
}
.modal h3 { font-size: 1.1rem; margin-bottom: 18px; }
.modal-actions { display: flex; gap: 8px; margin-top: 18px; }
/* ---- Messages ---- */
.msg { margin-top: 12px; padding: 10px 14px; border-radius: 6px; font-size: .93rem; }
.msg:empty { display: none; }
.msg.ok { background: #d1fae5; color: #065f46; border: 1px solid #6ee7b7; }
.msg.err { background: #fee2e2; color: #991b1b; border: 1px solid #fca5a5; }
/* ---- Login overlay ---- */
.login-overlay {
position: fixed;
inset: 0;
background: #1a1a2e;
display: flex;
align-items: center;
justify-content: center;
z-index: 500;
}
.login-card {
background: #fff;
border-radius: 12px;
padding: 40px;
width: 380px;
max-width: calc(100vw - 32px);
box-shadow: 0 20px 60px rgba(0,0,0,.4);
}
.login-card h1 { font-size: 1.6rem; margin-bottom: 4px; text-align: center; }
.login-sub { text-align: center; color: var(--muted); font-size: .9rem; margin-bottom: 24px; }
/* ---- Nav right (user + logout) ---- */
.nav-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.nav-user { color: #aaa; font-size: .88rem; }
.nav-logout {
background: transparent;
border: 1px solid #555;
color: #ccc;
padding: 4px 12px;
border-radius: 4px;
cursor: pointer;
font-size: .85rem;
transition: background .15s;
}
.nav-logout:hover { background: rgba(255,255,255,.1); }
/* ---- Admin form extras ---- */
.label-hint { font-weight: 400; color: #aaa; font-size: .8rem; }
.form-row textarea {
padding: 9px 12px;
border: 1px solid var(--border);
border-radius: 6px;
font-size: 1rem;
outline: none;
resize: vertical;
font-family: inherit;
transition: border-color .15s;
}
.form-row textarea:focus { border-color: var(--primary); }
.form-row-check { flex-direction: row !important; align-items: center; gap: 8px; }
.form-row-check label { font-weight: 400; color: var(--text); font-size: 1rem; }
.panel-divider { border: none; border-top: 1px solid var(--border); margin: 20px 0; }
.sub-heading { font-size: 1rem; margin-bottom: 14px; color: var(--text); }