From 419f69cef50023f8230ae9ddd63c777d89973715 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Wed, 11 Feb 2026 01:18:19 +0000 Subject: [PATCH] Style overhaul. --- frontend/auth/App.vue | 3 - frontend/auth/admin/AdminApp.vue | 1 - frontend/int/reset/ResetApp.vue | 19 +- frontend/src/admin/AdminDialogs.vue | 3 - frontend/src/admin/AdminOrgDetail.vue | 15 +- frontend/src/admin/AdminOverview.vue | 16 -- frontend/src/admin/AdminUserDetail.vue | 6 - frontend/src/assets/style.css | 193 ++++++++++++++++-- frontend/src/components/HostProfileView.vue | 11 +- frontend/src/components/LoadingView.vue | 9 +- frontend/src/components/NameEditForm.vue | 8 - frontend/src/components/ProfileView.vue | 28 +-- frontend/src/components/RemoteAuthPermit.vue | 23 ++- frontend/src/components/RemoteAuthRequest.vue | 10 +- frontend/src/components/RestrictedAuth.vue | 5 +- frontend/src/components/SessionList.vue | 3 +- frontend/src/components/StatusMessage.vue | 2 +- 17 files changed, 234 insertions(+), 121 deletions(-) diff --git a/frontend/auth/App.vue b/frontend/auth/App.vue index de01d77..c1d6533 100644 --- a/frontend/auth/App.vue +++ b/frontend/auth/App.vue @@ -148,6 +148,3 @@ onUnmounted(() => { removeAuthIframe() }) - - diff --git a/frontend/auth/admin/AdminApp.vue b/frontend/auth/admin/AdminApp.vue index 37d06a6..069ac18 100644 --- a/frontend/auth/admin/AdminApp.vue +++ b/frontend/auth/admin/AdminApp.vue @@ -841,7 +841,6 @@ async function submitDialog() { diff --git a/frontend/src/admin/AdminOrgDetail.vue b/frontend/src/admin/AdminOrgDetail.vue index 07accaf..ef0f48a 100644 --- a/frontend/src/admin/AdminOrgDetail.vue +++ b/frontend/src/admin/AdminOrgDetail.vue @@ -381,25 +381,15 @@ defineExpose({ focusFirstElement }) .card.surface { padding: var(--space-lg); } .org-title { display: flex; align-items: center; gap: var(--space-sm); margin-bottom: var(--space-lg); } .org-name { font-size: 1.5rem; font-weight: 600; color: var(--color-heading); } -.icon-btn { background: none; border: none; color: var(--color-text-muted); padding: 0.2rem; border-radius: var(--radius-sm); cursor: pointer; transition: background 0.2s ease, color 0.2s ease; } -.icon-btn:hover { color: var(--color-heading); background: var(--color-surface-muted); } -.matrix-wrapper { margin: var(--space-md) 0; padding: var(--space-lg); } -.matrix-scroll { overflow-x: auto; } -.matrix-hint { font-size: 0.8rem; color: var(--color-text-muted); } -.perm-matrix-grid { display: inline-grid; gap: 0.25rem; align-items: stretch; } -.perm-matrix-grid > * { padding: 0.35rem 0.45rem; font-size: 0.75rem; } -.perm-matrix-grid .grid-head { color: var(--color-text-muted); text-transform: uppercase; font-weight: 600; letter-spacing: 0.05em; } -.perm-matrix-grid .perm-head { display: flex; align-items: flex-end; justify-content: flex-start; padding: 0.35rem 0.45rem; font-size: 0.75rem; } .perm-matrix-grid .role-head { display: flex; align-items: flex-end; justify-content: center; } .perm-matrix-grid .role-head span { writing-mode: vertical-rl; transform: rotate(180deg); font-size: 0.65rem; } .perm-matrix-grid .add-role-head { cursor: pointer; } -.perm-name { font-weight: 600; color: var(--color-heading); padding: 0.35rem 0.45rem; font-size: 0.75rem; } .roles-grid { display: flex; gap: var(--space-lg); margin-top: var(--space-lg); } .role-column { flex: 1; min-width: 200px; border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-md); } .role-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-md); } .role-name { display: flex; align-items: center; gap: var(--space-xs); font-size: 1.1rem; color: var(--color-heading); } .role-actions { display: flex; gap: var(--space-xs); } -.plus-btn { background: var(--color-accent-soft); color: var(--color-accent); border: none; border-radius: var(--radius-sm); padding: 0.25rem 0.45rem; font-size: 1.1rem; cursor: pointer; } +.plus-btn { background: none; color: var(--color-accent); border: none; border-radius: var(--radius-sm); padding: 0.25rem 0.45rem; font-size: 1.1rem; cursor: pointer; } .plus-btn:hover { background: rgba(37, 99, 235, 0.18); } .user-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--space-xs); } .user-chip { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: 0.45rem 0.6rem; display: flex; justify-content: space-between; gap: var(--space-sm); cursor: grab; } @@ -407,9 +397,6 @@ defineExpose({ focusFirstElement }) .user-chip .meta { font-size: 0.7rem; color: var(--color-text-muted); } .empty-role { border: 1px dashed var(--color-border-strong); border-radius: var(--radius-md); padding: var(--space-sm); display: flex; flex-direction: column; gap: var(--space-xs); align-items: flex-start; } .empty-text { margin: 0; } -.delete-icon { color: var(--color-danger); } -.delete-icon:hover { background: var(--color-danger-bg); color: var(--color-danger-text); } -.muted { color: var(--color-text-muted); } @media (max-width: 720px) { .roles-grid { flex-direction: column; } diff --git a/frontend/src/admin/AdminOverview.vue b/frontend/src/admin/AdminOverview.vue index 143da8b..b3c4573 100644 --- a/frontend/src/admin/AdminOverview.vue +++ b/frontend/src/admin/AdminOverview.vue @@ -353,8 +353,6 @@ defineExpose({ focusFirstElement }) diff --git a/frontend/src/admin/AdminUserDetail.vue b/frontend/src/admin/AdminUserDetail.vue index b23ab9c..da9ad62 100644 --- a/frontend/src/admin/AdminUserDetail.vue +++ b/frontend/src/admin/AdminUserDetail.vue @@ -256,11 +256,5 @@ defineExpose({ focusFirstElement }) diff --git a/frontend/src/assets/style.css b/frontend/src/assets/style.css index 7701bc3..2e89233 100644 --- a/frontend/src/assets/style.css +++ b/frontend/src/assets/style.css @@ -9,8 +9,9 @@ --font-sans: "Inter", "Inter var", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", sans-serif; --font-mono: "DM Mono", "JetBrains Mono", "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", monospace; --color-canvas: white; - --color-surface: oklch(0.97 0.005 var(--hue)); - --color-surface-subtle: oklch(0.94 0.01 var(--hue)); + --color-surface: oklch(0.95 0.03 var(--hue)); + --color-surface-subtle: oklch(0.9 0.03 var(--hue)); + --color-surface-hover: white; --color-dialog: white; --color-border: oklch(0.8 0.02 var(--hue)); --color-border-strong: oklch(0.55 0.15 var(--hue)); @@ -31,30 +32,35 @@ --color-info-text: oklch(0.45 0.15 var(--hue)); --color-info-bg: oklch(0.95 0.02 var(--hue)); --color-danger: oklch(0.55 0.22 0.07turn); + --color-primary: oklch(0.55 0.2 var(--hue)); + --color-error: oklch(0.45 0.2 0.07turn); + --color-success: oklch(0.4 0.15 0.4turn); + --color-bg: oklch(0.97 0.005 var(--hue)); + --color-accent-soft: oklch(0.95 0.08 var(--hue)); --shadow-soft: 0 0 .2rem black; - --radius-none: 0; + --shadow-xl: 0 10px 40px rgba(0, 0, 0, 0.15); --radius-sm: 4px; --radius-md: 6px; --radius-lg: 10px; - --space-xxs: 0.25rem; --space-xs: 0.5rem; --space-sm: 0.75rem; --space-md: 1rem; --space-lg: 1.5rem; --space-xl: 2.25rem; - --space-xxl: 3.5rem; + --space-3xl: 5rem; --layout-padding: clamp(1.5rem, 3vw + 1rem, 3.25rem); --transition-base: 160ms ease; --focus-ring: 0 0 0 2px var(--color-accent); } :root.dark { - --color-canvas: oklch(0.15 0.03 var(--hue)); - --color-surface: oklch(0.18 0.03 var(--hue)); - --color-surface-subtle: oklch(0.22 0.03 var(--hue)); - --color-dialog: oklch(0.22 0.03 var(--hue)); - --color-border: oklch(0.3 0.03 var(--hue)); - --color-border-strong: oklch(0.4 0.04 var(--hue)); + --color-canvas: oklch(0.17 0.05 var(--hue)); + --color-surface: oklch(0.22 0.05 var(--hue)); + --color-surface-subtle: oklch(0.25 0.05 var(--hue)); + --color-surface-hover: oklch(0.28 0.05 var(--hue)); + --color-dialog: oklch(0.22 0.05 var(--hue)); + --color-border: oklch(0.3 0.05 var(--hue)); + --color-border-strong: oklch(0.4 0.05 var(--hue)); --color-heading: white; --color-text: oklch(0.9 0.01 var(--hue)); --color-text-muted: oklch(0.7 0.02 var(--hue)); @@ -72,7 +78,13 @@ --color-info-text: oklch(0.8 0.1 var(--hue)); --color-info-bg: oklch(0.3 0.05 var(--hue)); --color-danger: oklch(0.7 0.18 0.07turn); + --color-primary: oklch(0.7 0.15 var(--hue)); + --color-error: oklch(0.8 0.12 0.07turn); + --color-success: oklch(0.75 0.15 0.4turn); + --color-bg: oklch(0.18 0.03 var(--hue)); + --color-accent-soft: oklch(0.25 0.08 var(--hue)); --shadow-soft: 0 0 0 black; + --shadow-xl: 0 10px 40px rgba(0, 0, 0, 0.4); } *, @@ -160,6 +172,25 @@ a:focus-visible { max-width: 540px; } +.view-root--profile .view-header-wrapper { + width: 100%; + max-width: calc(1200px - 2 * var(--layout-padding)); + margin: 0 auto; + position: relative; +} + +.view-root--profile .theme-toggle { + position: absolute; + top: 0; + right: 0; +} + +.section-block--constrained { + width: 100%; + max-width: calc(1200px - 2 * var(--layout-padding)); + margin: 0 auto; +} + .view-header { display: flex; flex-direction: column; @@ -207,6 +238,7 @@ a:focus-visible { flex-wrap: nowrap; gap: 0.75rem; justify-content: flex-start; + width: 100%; } .button-row button { @@ -340,10 +372,118 @@ th { text-align: left; } +/* Permission matrix styles */ +.matrix-wrapper { + margin: var(--space-md) 0; + padding: var(--space-lg); +} + +.matrix-scroll { + overflow-x: auto; +} + +.matrix-hint { + font-size: 0.8rem; + color: var(--color-text-muted); +} + +.perm-matrix-grid { + display: inline-grid; + gap: 0.25rem; + align-items: stretch; +} + +.perm-matrix-grid > * { + padding: 0.35rem 0.45rem; + font-size: 0.75rem; +} + +.perm-matrix-grid .grid-head { + color: var(--color-text-muted); + text-transform: uppercase; + font-weight: 600; + letter-spacing: 0.05em; +} + +.perm-matrix-grid .perm-head { + display: flex; + align-items: flex-end; + justify-content: flex-start; + padding: 0.35rem 0.45rem; + font-size: 0.75rem; +} + +.perm-matrix-grid .rotated-head { + display: flex; + align-items: flex-end; + justify-content: center; +} + +.perm-matrix-grid .rotated-head span { + writing-mode: vertical-rl; + transform: rotate(180deg); + font-size: 0.65rem; +} + +.perm-name { + font-weight: 600; + color: var(--color-heading); + padding: 0.35rem 0.45rem; + font-size: 0.75rem; +} + .center { text-align: center; } +/* Utility classes */ +.muted { + color: var(--color-text-muted); +} + +.error { + color: var(--color-danger-text); +} + +.small { + font-size: 0.9rem; +} + +.icon-btn { + background: none; + border: none; + color: var(--color-text-muted); + padding: 0.2rem; + border-radius: var(--radius-sm); + cursor: pointer; + transition: background 0.2s ease, color 0.2s ease; +} + +.icon-btn:hover { + color: var(--color-heading); + background: var(--color-surface-subtle); +} + +.delete-icon { + color: var(--color-danger); +} + +.delete-icon:hover { + background: var(--color-error-bg); + color: var(--color-error-text); +} + +.actions { + display: flex; + flex-wrap: wrap; + gap: var(--space-sm); + align-items: center; +} + +.button-row--center { + justify-content: center; +} + .badge { display: inline-flex; align-items: center; @@ -369,6 +509,10 @@ th { display: none; } +.global-status.show { + display: block; +} + .global-status .status { display: flex; align-items: center; @@ -742,7 +886,7 @@ th { .slot-machine { padding: 0.875rem 1rem; - background: var(--color-surface-hover, rgba(0, 0, 0, 0.03)); + background: var(--color-surface-hover); border: 1px solid var(--color-border); border-radius: var(--radius-sm); font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace; @@ -763,3 +907,28 @@ th { height: 1.8em; position: relative; } + +/* Spinner utilities */ +.spinner { + border: 3px solid var(--color-border); + border-top-color: var(--color-primary); + border-radius: 50%; + animation: spin 1s linear infinite; +} + +.spinner--sm { + width: 16px; + height: 16px; + border-width: 2px; +} + +.spinner--md { + width: 40px; + height: 40px; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} diff --git a/frontend/src/components/HostProfileView.vue b/frontend/src/components/HostProfileView.vue index 3a6e7b6..e76d3a5 100644 --- a/frontend/src/components/HostProfileView.vue +++ b/frontend/src/components/HostProfileView.vue @@ -1,5 +1,5 @@