From 2d22158dd95f76399f5716d556be60c77da04a46 Mon Sep 17 00:00:00 2001 From: Tom van der Lee Date: Thu, 30 Jul 2026 16:03:32 +0200 Subject: Admin ui --- templates/_styles.html | 539 +++++++++++++++++++++++++++++++++++++++++++++++++ templates/global.html | 19 ++ templates/macros.html | 49 +++++ 3 files changed, 607 insertions(+) create mode 100644 templates/_styles.html create mode 100644 templates/macros.html (limited to 'templates') diff --git a/templates/_styles.html b/templates/_styles.html new file mode 100644 index 0000000..f68b9c0 --- /dev/null +++ b/templates/_styles.html @@ -0,0 +1,539 @@ +:root, +:root[data-theme="dark"] { + --bg: #12161c; + --surface: #1a2029; + --surface-raised: #212836; + --border: #2a323d; + --text: #e7ebf1; + --text-muted: #8891a0; + --accent: #f5a623; + --accent-strong: #ffbb47; + --accent-ink: #1a1305; + --status-good: #3ddc84; + --status-bad: #e5484d; + color-scheme: dark; +} + +:root[data-theme="light"] { + --bg: #eef1f6; + --surface: #ffffff; + --surface-raised: #f7f9fc; + --border: #d7dce3; + --text: #12161c; + --text-muted: #5b6472; + --accent: #b9750f; + --accent-strong: #8f5c0c; + --accent-ink: #fff8ec; + --status-good: #1e9a5a; + --status-bad: #c53328; + color-scheme: light; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + -webkit-text-size-adjust: 100%; +} + +body { + background: var(--bg); + color: var(--text); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + font-size: 15px; + line-height: 1.6; + min-height: 100vh; +} + +body, +.pulse-line, +.theme-toggle, +.field__input, +.btn, +.module-card { + transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease; +} + +.mono { + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; +} + +.eyebrow { + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 11px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--text-muted); +} + +.muted { + color: var(--text-muted); +} + +.small { + font-size: 13px; +} + +a { + color: var(--accent); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +h1 { + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 26px; + font-weight: 600; + letter-spacing: -0.01em; +} + +h2 { + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 18px; + font-weight: 600; +} + +/* signature element: one-time handshake pulse on load */ +.pulse-line { + position: fixed; + top: 0; + left: 0; + right: 0; + height: 2px; + z-index: 40; + background: linear-gradient(90deg, transparent, var(--accent), transparent); + background-size: 200% 100%; + animation: pulse-sweep 1.4s ease-out 1; +} + +@keyframes pulse-sweep { + from { background-position: 160% 0; } + to { background-position: -60% 0; } +} + +/* theme toggle */ +.theme-toggle { + position: fixed; + top: 16px; + right: 16px; + z-index: 50; + display: flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + border-radius: 8px; + border: 1px solid var(--border); + background: var(--surface); + color: var(--text-muted); + cursor: pointer; +} + +.theme-toggle:hover { + color: var(--accent); + border-color: var(--accent); +} + +.theme-toggle:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.theme-toggle .icon-sun { display: none; } +.theme-toggle .icon-moon { display: block; } +:root[data-theme="light"] .theme-toggle .icon-sun { display: block; } +:root[data-theme="light"] .theme-toggle .icon-moon { display: none; } + +/* focus ring, used everywhere */ +a:focus-visible, +button:focus-visible, +input:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* buttons */ +.btn { + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 14px; + font-weight: 600; + padding: 10px 18px; + border-radius: 8px; + border: 1px solid transparent; + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 8px; +} + +.btn--primary { + background: var(--accent); + color: var(--accent-ink); +} + +.btn--primary:hover { + background: var(--accent-strong); +} + +.btn--full { + width: 100%; + justify-content: center; +} + +/* form fields */ +.field { + margin-bottom: 18px; +} + +.field__label { + display: block; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 11px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--text-muted); + margin-bottom: 6px; +} + +.field__input { + width: 100%; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 14px; + padding: 10px 12px; + background: var(--bg); + color: var(--text); + border: 1px solid var(--border); + border-radius: 8px; +} + +.field__input:focus { + outline: 2px solid var(--accent); + outline-offset: 1px; + border-color: var(--accent); +} + +.field__input--error { + border-color: var(--status-bad); +} + +.field__error { + margin-top: 6px; + font-size: 13px; + color: var(--status-bad); +} + +/* auth split-panel shell */ +.auth-page { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 32px 16px; +} + +.auth-shell { + display: grid; + grid-template-columns: 1fr 1fr; + max-width: 880px; + width: 100%; + border: 1px solid var(--border); + border-radius: 16px; + overflow: hidden; +} + +.auth-hero { + background: var(--surface-raised); + padding: 40px 32px; + display: flex; + flex-direction: column; + justify-content: space-between; + gap: 32px; + border-right: 1px solid var(--border); +} + +.auth-hero__brand { + display: flex; + align-items: center; + gap: 10px; + color: var(--accent); + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 18px; + font-weight: 600; +} + +.auth-hero__diagram { + display: flex; + align-items: center; + gap: 10px; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 13px; + color: var(--text); +} + +.auth-hero__diagram .connector { + color: var(--accent); + flex: 1; +} + +.auth-hero__diagram span.mono { + background: var(--surface); + border: 1px solid var(--border); + padding: 4px 8px; + border-radius: 6px; + white-space: nowrap; +} + +.auth-hero__tagline { + font-size: 14px; + color: var(--text-muted); + line-height: 1.5; +} + +.auth-form { + background: var(--surface); + padding: 40px 32px; + display: flex; + flex-direction: column; + justify-content: center; +} + +.auth-form h1 { + margin-bottom: 4px; +} + +.auth-form__intro { + color: var(--text-muted); + font-size: 14px; + margin-bottom: 24px; +} + +.auth-switch { + margin-top: 16px; + font-size: 13px; + color: var(--text-muted); +} + +/* management top bar */ +.nav { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 14px 24px; + background: var(--surface-raised); + border-bottom: 1px solid var(--border); + flex-wrap: wrap; +} + +.nav__brand { + display: flex; + align-items: center; + gap: 8px; + color: var(--accent); + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-weight: 600; + font-size: 16px; +} + +.nav__links { + display: flex; + align-items: center; + gap: 20px; +} + +.nav__link { + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 12px; + letter-spacing: 0.05em; + text-transform: uppercase; + color: var(--text-muted); + padding-bottom: 2px; + border-bottom: 2px solid transparent; +} + +.nav__link:hover { + color: var(--text); + text-decoration: none; +} + +.nav__link--active { + color: var(--accent); + border-bottom-color: var(--accent); +} + +.nav__actions { + display: flex; + align-items: center; + gap: 20px; + margin-left: auto; +} + +.nav__status { + display: flex; + align-items: center; + gap: 8px; +} + +.status-dot { + width: 8px; + height: 8px; + border-radius: 50%; + display: inline-block; +} + +.status-dot--good { + background: var(--status-good); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--status-good) 25%, transparent); +} + +.status-dot--bad { + background: var(--status-bad); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--status-bad) 25%, transparent); +} + +/* content area */ +.content { + max-width: 960px; + margin: 0 auto; + padding: 40px 24px; +} + +.content__header { + margin-bottom: 28px; +} + +.content__header h1 { + margin-top: 4px; +} + +/* dashboard module grid */ +.module-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 16px; +} + +.module-card { + display: block; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 12px; + padding: 20px; +} + +.module-card:hover { + border-color: var(--accent); + background: var(--surface-raised); + text-decoration: none; +} + +.module-card__title { + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 15px; + font-weight: 600; + color: var(--text); + margin-bottom: 6px; +} + +.module-card__desc { + font-size: 13px; + color: var(--text-muted); + line-height: 1.5; +} + +.module-card__meta { + margin-top: 12px; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 12px; + color: var(--accent); +} + +/* data table */ +.table-wrap { + overflow-x: auto; + border: 1px solid var(--border); + border-radius: 12px; +} + +table { + width: 100%; + border-collapse: collapse; +} + +thead th { + text-align: left; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 11px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--text-muted); + padding: 12px 16px; + border-bottom: 1px solid var(--border); + background: var(--surface-raised); +} + +tbody td { + padding: 12px 16px; + border-bottom: 1px solid var(--border); + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; + font-size: 13px; +} + +tbody tr:last-child td { + border-bottom: none; +} + +tbody tr:hover { + background: var(--surface-raised); +} + +@media (max-width: 720px) { + .auth-shell { + grid-template-columns: 1fr; + } + + .auth-hero { + border-right: none; + border-bottom: 1px solid var(--border); + padding: 24px; + } + + .auth-hero__diagram { + display: none; + } + + .auth-form { + padding: 24px; + } + + .nav { + gap: 12px; + } + + .nav__actions { + margin-left: 0; + } +} + +@media (prefers-reduced-motion: reduce) { + .pulse-line { + animation: none; + background: var(--accent); + opacity: 0.6; + } + + body, + .pulse-line, + .theme-toggle, + .field__input, + .btn, + .module-card { + transition: none; + } +} diff --git a/templates/global.html b/templates/global.html index d9bd29d..97212df 100644 --- a/templates/global.html +++ b/templates/global.html @@ -1,8 +1,17 @@ +{% import 'macros.html' as ui %} + TTUN + + + {% block template %}{% endblock %} diff --git a/templates/macros.html b/templates/macros.html new file mode 100644 index 0000000..7c35f5e --- /dev/null +++ b/templates/macros.html @@ -0,0 +1,49 @@ +{% macro connector_icon(size=16) %} + +{% endmacro %} + +{% macro sun_icon(size=16) %} + +{% endmacro %} + +{% macro moon_icon(size=16) %} + +{% endmacro %} + +{% macro field(name, type='text', label='', value='', error='', placeholder='') %} +
+ + + {% if error %} +

{{ error }}

+ {% endif %} +
+{% endmacro %} + +{% macro button(text, variant='primary', type='submit') %} + +{% endmacro %} + +{% macro status_badge(label, variant='good') %} + + + {{ label }} + +{% endmacro %} -- cgit v1.2.3