patx/projectpay
add dark mode
Commit d910bc4 · patx · 2026-07-06T01:06:48-04:00
Comments
No comments yet.
Diff
diff --git a/templates/base.html b/templates/base.html
index de12dfe..ccee373 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -7,10 +7,62 @@
<style>
* { box-sizing: border-box; }
[hidden] { display: none !important; }
+ :root {
+ color-scheme: light;
+ --page-bg: #f7f7f7;
+ --surface-bg: #fff;
+ --surface-subtle: #fafafa;
+ --field-bg: #fff;
+ --text-color: #1f2933;
+ --muted-color: #697586;
+ --border-color: #cfd6dd;
+ --border-subtle: #eceff3;
+ --primary-color: #176b5b;
+ --primary-hover-color: #13584c;
+ --primary-contrast: #fff;
+ --danger-color: #b42318;
+ --danger-bg: #fff0ee;
+ --danger-border: #efb5ad;
+ --warning-color: #8a5a00;
+ --warning-bg: #fff8e8;
+ --success-color: #166534;
+ --success-bg: #eaf7ef;
+ --info-color: #164c7d;
+ --info-bg: #edf5ff;
+ --sticky-bg: rgba(247, 247, 247, .96);
+ --shadow-color: rgba(31, 41, 51, .22);
+ }
+ @media (prefers-color-scheme: dark) {
+ :root {
+ color-scheme: dark;
+ --page-bg: #0f1720;
+ --surface-bg: #17212b;
+ --surface-subtle: #1f2a36;
+ --field-bg: #101923;
+ --text-color: #e6edf3;
+ --muted-color: #a8b3c2;
+ --border-color: #344454;
+ --border-subtle: #2a3745;
+ --primary-color: #1f7a6d;
+ --primary-hover-color: #279382;
+ --primary-contrast: #fff;
+ --danger-color: #ffb4aa;
+ --danger-bg: #3b1715;
+ --danger-border: #71332d;
+ --warning-color: #ffd47a;
+ --warning-bg: #36270c;
+ --success-color: #8ee3a6;
+ --success-bg: #12301f;
+ --info-color: #9bd2ff;
+ --info-bg: #132c45;
+ --sticky-bg: rgba(15, 23, 32, .96);
+ --shadow-color: rgba(0, 0, 0, .35);
+ }
+ }
body {
margin: 0;
- background: #f7f7f7;
- color: #1f2933;
+ background: var(--page-bg);
+ color: var(--text-color);
font: 15px/1.45 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
a { color: inherit; }
@@ -19,11 +71,13 @@
h2 { font-size: 18px; margin: 0 0 12px; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 20px 0; text-align: left; vertical-align: top; }
- th { color: #697586; font-size: 13px; }
+ th { color: var(--muted-color); font-size: 13px; }
input, textarea {
width: 100%;
- border: 1px solid #cfd6dd;
+ border: 1px solid var(--border-color);
border-radius: 6px;
+ background: var(--field-bg);
+ color: var(--text-color);
padding: 10px;
font: inherit;
}
@@ -33,19 +87,19 @@
align-items: center;
justify-content: center;
min-height: 38px;
- border: 1px solid #176b5b;
+ border: 1px solid var(--primary-color);
border-radius: 6px;
- background: #176b5b;
- color: #fff;
+ background: var(--primary-color);
+ color: var(--primary-contrast);
padding: 8px 12px;
font: inherit;
font-weight: 650;
text-decoration: none;
cursor: pointer;
}
- .secondary { background: #fff; border-color: #cfd6dd; color: #1f2933; }
- .danger { background: #fff; border-color: #efb5ad; color: #b42318; }
- .topbar { background: #fff; }
+ .secondary { background: var(--surface-bg); border-color: var(--border-color); color: var(--text-color); }
+ .danger { background: var(--surface-bg); border-color: var(--danger-border); color: var(--danger-color); }
+ .topbar { background: var(--surface-bg); }
.topbar-inner, .page { max-width: 1080px; margin: 0 auto; padding: 16px 20px; }
.topbar-inner, .header-row, .nav, .searchbar {
display: flex;
@@ -69,7 +123,7 @@
gap: 10px;
}
.back-link {
- color: #697586;
+ color: var(--muted-color);
font-size: 24px;
line-height: 1;
text-decoration: none;
@@ -77,12 +131,12 @@
.page { padding-top: 28px; padding-bottom: 48px; }
.narrow { max-width: 680px; }
.section {
- background: #fff;
+ background: var(--surface-bg);
border-radius: 8px;
padding: 18px;
margin-bottom: 16px;
}
- .muted, .footer-note { color: #697586; }
+ .muted, .footer-note { color: var(--muted-color); }
.field { margin-bottom: 14px; }
.prewrap { white-space: pre-wrap; }
.star-emphasis { font-size: calc(1em + 1px); font-weight: 700; }
@@ -95,34 +149,34 @@
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.stats { grid-template-columns: repeat(3, minmax(0, 1fr)); margin: 16px 0; }
.stat { border-radius: 8px; padding: 12px; }
- .stat span { display: block; color: #697586; font-size: 13px; }
+ .stat span { display: block; color: var(--muted-color); font-size: 13px; }
.stat strong { font-size: 19px; }
- .alert { border-radius: 8px; padding: 10px 12px; margin-bottom: 14px; }
- .alert.error { border-color: #efb5ad; color: #b42318; background: #fff0ee; }
- .alert.info { background: #fff8e8; }
- .alert.ok { background: #eaf7ef; }
+ .alert { border: 1px solid transparent; border-radius: 8px; padding: 10px 12px; margin-bottom: 14px; }
+ .alert.error { border-color: var(--danger-border); color: var(--danger-color); background: var(--danger-bg); }
+ .alert.info { color: var(--warning-color); background: var(--warning-bg); }
+ .alert.ok { color: var(--success-color); background: var(--success-bg); }
.status {
border-radius: 999px;
- background: #edf5ff;
- color: #164c7d;
+ background: var(--info-bg);
+ color: var(--info-color);
padding: 3px 9px;
font-size: 13px;
font-weight: 700;
text-transform: capitalize;
}
.status.paid,
- .status.succeeded { background: #eaf7ef; color: #166534; }
+ .status.succeeded { background: var(--success-bg); color: var(--success-color); }
.status.processing,
- .status.pending { background: #fff8e8; color: #8a5a00; }
+ .status.pending { background: var(--warning-bg); color: var(--warning-color); }
.status.failed,
- .status.canceled { background: #fff0ee; color: #b42318; }
+ .status.canceled { background: var(--danger-bg); color: var(--danger-color); }
.project-list {
display: grid;
gap: 12px;
}
.project-card,
.payment-card {
- background: #fff;
+ background: var(--surface-bg);
border-radius: 8px;
color: inherit;
text-decoration: none;
@@ -130,7 +184,7 @@
}
.invoice-line-card,
.invoice-summary {
- background: #fff;
+ background: var(--surface-bg);
color: inherit;
text-decoration: none;
padding: 14px;
@@ -146,11 +200,11 @@
font-size: 18px;
margin: 0 0 4px;
}
- .project-card-id { color: #697586; font-size: 13px; }
+ .project-card-id { color: var(--muted-color); font-size: 13px; }
.project-card-amount { text-align: right; }
.project-card-amount span {
display: block;
- color: #697586;
+ color: var(--muted-color);
font-size: 13px;
}
.project-card-footer {
@@ -160,7 +214,7 @@
}
.payment-card-reference { overflow-wrap: anywhere; }
.line-items-section {
- background: #fff;
+ background: var(--surface-bg);
border-radius: 8px;
margin-bottom: 16px;
overflow: hidden;
@@ -186,7 +240,7 @@
.invoice-line-amount span,
.invoice-summary-row span {
display: block;
- color: #697586;
+ color: var(--muted-color);
font-size: 13px;
}
.invoice-line-amount strong,
@@ -204,7 +258,7 @@
align-items: baseline;
}
.invoice-summary-row + .invoice-summary-row {
- border-top: 1px solid #eceff3;
+ border-top: 1px solid var(--border-subtle);
padding-top: 8px;
}
.invoice-summary-total strong { font-size: 18px; }
@@ -216,7 +270,7 @@
border-radius: 8px;
padding: 14px;
margin-bottom: 12px;
- background: #fafafa;
+ background: var(--surface-subtle);
}
.line-item-text { grid-column: 1 / -1; }
.line-item-price { max-width: 180px; }
@@ -239,11 +293,11 @@
width: 28px;
border: 0;
background: transparent;
- color: #697586;
+ color: var(--muted-color);
padding: 0;
transform: translateY(-50%);
}
- .search-clear:hover { background: transparent; color: #1f2933; }
+ .search-clear:hover { background: transparent; color: var(--text-color); }
.copy-field { position: relative; }
.copy-field input {
cursor: pointer;
@@ -255,7 +309,7 @@
right: 12px;
width: 22px;
height: 22px;
- color: #697586;
+ color: var(--muted-color);
pointer-events: none;
transform: translateY(-50%);
}
@@ -267,14 +321,14 @@
height: 13px;
border: 1.5px solid currentColor;
border-radius: 2px;
- background: #fff;
+ background: var(--surface-bg);
}
.copy-indicator::before { left: 2px; top: 6px; }
.copy-indicator::after { left: 7px; top: 1px; }
.copy-indicator.copied {
width: auto;
height: auto;
- color: #176b5b;
+ color: var(--primary-color);
font-size: 13px;
font-weight: 700;
}
@@ -294,7 +348,7 @@
right: 0;
bottom: 0;
z-index: 10;
- background: rgba(247, 247, 247, .96);
+ background: var(--sticky-bg);
padding: 12px 20px;
}
.sticky-pay-inner {
@@ -313,7 +367,7 @@
right: 0;
bottom: 0;
z-index: 10;
- background: rgba(247, 247, 247, .96);
+ background: var(--sticky-bg);
padding: 12px 20px;
}
.sticky-actions-inner {
@@ -341,7 +395,7 @@
left: 0;
right: 0;
z-index: 10;
- background: rgba(247, 247, 247, .96);
+ background: var(--sticky-bg);
padding: 12px 20px;
}
.sticky-index-search {
@@ -364,11 +418,11 @@
z-index: 11;
width: 56px;
height: 56px;
- border: 1px solid #176b5b;
+ border: 1px solid var(--primary-color);
border-radius: 50%;
- background: #176b5b;
- color: #fff;
- box-shadow: 0 10px 24px rgba(31, 41, 51, .22);
+ background: var(--primary-color);
+ color: var(--primary-contrast);
+ box-shadow: 0 10px 24px var(--shadow-color);
font-size: 34px;
font-weight: 500;
line-height: 1;
@@ -376,10 +430,10 @@
text-decoration: none;
}
.floating-new-project:hover {
- background: #13584c;
- border-color: #13584c;
+ background: var(--primary-hover-color);
+ border-color: var(--primary-hover-color);
}
- .empty { color: #697586; padding: 18px 0; }
+ .empty { color: var(--muted-color); padding: 18px 0; }
.amount { text-align: right; }
@media (max-width: 760px) {
.topbar-inner, .header-row, .nav, .searchbar { align-items: stretch; flex-direction: column; }