More minimalistic light theme. UI hint for org admin user/role management.

This commit is contained in:
Leo Vasanko
2026-02-17 19:42:31 +00:00
parent 69c456b0b3
commit eafbdce4f8
3 changed files with 97 additions and 87 deletions
+2 -1
View File
@@ -375,6 +375,7 @@ defineExpose({ focusFirstElement })
</div> </div>
</div> </div>
</div> </div>
<p v-if="sortedRoles.length >= 2" class="roles-hint muted">Members can be drag&dropped to different roles.</p>
</template> </template>
<style scoped> <style scoped>
@@ -385,7 +386,7 @@ defineExpose({ focusFirstElement })
.perm-matrix-grid .role-head span { writing-mode: vertical-rl; transform: rotate(180deg); font-size: 0.65rem; } .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-matrix-grid .add-role-head { cursor: pointer; }
.roles-grid { display: flex; gap: var(--space-lg); margin-top: var(--space-lg); } .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-column { flex: 1; min-width: 200px; 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-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-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); } .role-actions { display: flex; gap: var(--space-xs); }
+72 -64
View File
@@ -9,34 +9,34 @@
--font-sans: "Inter", "Inter var", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", sans-serif; --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; --font-mono: "DM Mono", "JetBrains Mono", "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", monospace;
--color-canvas: white; --color-canvas: white;
--color-surface: oklch(0.95 0.03 var(--hue)); --color-surface: white;
--color-surface-subtle: oklch(0.9 0.03 var(--hue)); --color-surface-subtle: white;
--color-surface-hover: white; --color-surface-hover: oklab(0.97 -0.01 -0.02);
--color-dialog: white; --color-dialog: oklab(0.96 -0.01 -0.03);
--color-border: oklch(0.8 0.02 var(--hue)); --color-border: oklab(0.82 -0.02 -0.06);
--color-border-strong: oklch(0.55 0.15 var(--hue)); --color-border-strong: oklab(0.55 -0.05 -0.14);
--color-heading: oklch(0.3 0.05 var(--hue)); --color-heading: oklab(0.22 -0.03 -0.09);
--color-text: oklch(0.25 0.02 var(--hue)); --color-text: oklab(0.2 -0.02 -0.05);
--color-text-muted: oklch(0.5 0.02 var(--hue)); --color-text-muted: oklab(0.42 -0.02 -0.06);
--color-link: oklch(0.5 0.18 var(--hue)); --color-link: oklab(0.5 -0.06 -0.17);
--color-link-hover: oklch(0.45 0.2 var(--hue)); --color-link-hover: oklab(0.45 -0.06 -0.19);
--color-accent: oklch(0.55 0.2 var(--hue)); --color-accent: oklab(0.55 -0.06 -0.19);
--color-accent-strong: oklch(0.45 0.2 var(--hue)); --color-accent-strong: oklab(0.45 -0.06 -0.19);
--color-accent-contrast: white; --color-accent-contrast: white;
--color-secondary: oklch(0.55 0.05 var(--hue)); --color-secondary: oklab(0.55 -0.02 -0.05);
--color-secondary-strong: oklch(0.45 0.05 var(--hue)); --color-secondary-strong: oklab(0.45 -0.02 -0.05);
--color-success-text: oklch(0.4 0.15 0.4turn); --color-success-text: oklab(0.4 -0.12 0.09);
--color-success-bg: oklch(0.95 0.03 0.4turn); --color-success-bg: oklab(0.95 -0.02 0.02);
--color-error-text: oklch(0.45 0.2 0.07turn); --color-error-text: oklab(0.45 0.18 0.09);
--color-error-bg: oklch(0.95 0.03 0.07turn); --color-error-bg: oklab(0.95 0.03 0.01);
--color-info-text: oklch(0.45 0.15 var(--hue)); --color-info-text: oklab(0.45 -0.05 -0.14);
--color-info-bg: oklch(0.95 0.02 var(--hue)); --color-info-bg: oklab(0.95 -0.01 -0.02);
--color-danger: oklch(0.55 0.22 0.07turn); --color-danger: oklab(0.55 0.20 0.09);
--color-primary: oklch(0.55 0.2 var(--hue)); --color-primary: oklab(0.55 -0.06 -0.19);
--color-error: oklch(0.45 0.2 0.07turn); --color-error: oklab(0.45 0.18 0.09);
--color-success: oklch(0.4 0.15 0.4turn); --color-success: oklab(0.4 -0.12 0.09);
--color-bg: oklch(0.97 0.005 var(--hue)); --color-bg: oklab(0.94 -0.01 -0.03);
--color-accent-soft: oklch(0.95 0.08 var(--hue)); --color-accent-soft: oklab(0.92 -0.03 -0.08);
--shadow-soft: 0 0 .2rem black; --shadow-soft: 0 0 .2rem black;
--shadow-xl: 0 10px 40px rgba(0, 0, 0, 0.15); --shadow-xl: 0 10px 40px rgba(0, 0, 0, 0.15);
--radius-sm: 4px; --radius-sm: 4px;
@@ -54,35 +54,35 @@
} }
:root.dark { :root.dark {
--color-canvas: oklch(0.17 0.05 var(--hue)); --color-canvas: oklab(0.17 -0.02 -0.05);
--color-surface: oklch(0.22 0.05 var(--hue)); --color-surface: oklab(0.22 -0.02 -0.05);
--color-surface-subtle: oklch(0.25 0.05 var(--hue)); --color-surface-subtle: oklab(0.25 -0.02 -0.05);
--color-surface-hover: oklch(0.28 0.05 var(--hue)); --color-surface-hover: oklab(0.28 -0.02 -0.05);
--color-dialog: oklch(0.22 0.05 var(--hue)); --color-dialog: oklab(0.22 -0.02 -0.05);
--color-border: oklch(0.3 0.05 var(--hue)); --color-border: oklab(0.3 -0.02 -0.05);
--color-border-strong: oklch(0.4 0.05 var(--hue)); --color-border-strong: oklab(0.4 -0.02 -0.05);
--color-heading: white; --color-heading: white;
--color-text: oklch(0.9 0.01 var(--hue)); --color-text: oklab(0.9 0.00 -0.01);
--color-text-muted: oklch(0.7 0.02 var(--hue)); --color-text-muted: oklab(0.7 -0.01 -0.02);
--color-link: oklch(0.7 0.15 var(--hue)); --color-link: oklab(0.7 -0.05 -0.14);
--color-link-hover: oklch(0.8 0.12 var(--hue)); --color-link-hover: oklab(0.8 -0.04 -0.11);
--color-accent: oklch(0.7 0.15 var(--hue)); --color-accent: oklab(0.7 -0.05 -0.14);
--color-accent-strong: oklch(0.6 0.18 var(--hue)); --color-accent-strong: oklab(0.6 -0.06 -0.17);
--color-accent-contrast: oklch(0.12 0.03 var(--hue)); --color-accent-contrast: oklab(0.12 -0.01 -0.03);
--color-secondary: oklch(0.6 0.05 var(--hue)); --color-secondary: oklab(0.6 -0.02 -0.05);
--color-secondary-strong: oklch(0.5 0.05 var(--hue)); --color-secondary-strong: oklab(0.5 -0.02 -0.05);
--color-success-text: oklch(0.75 0.15 0.4turn); --color-success-text: oklab(0.75 -0.12 0.09);
--color-success-bg: oklch(0.3 0.08 0.4turn); --color-success-bg: oklab(0.3 -0.07 0.05);
--color-error-text: oklch(0.8 0.12 0.07turn); --color-error-text: oklab(0.8 0.11 0.05);
--color-error-bg: oklch(0.3 0.08 0.07turn); --color-error-bg: oklab(0.3 0.07 0.03);
--color-info-text: oklch(0.8 0.1 var(--hue)); --color-info-text: oklab(0.8 -0.03 -0.10);
--color-info-bg: oklch(0.3 0.05 var(--hue)); --color-info-bg: oklab(0.3 -0.02 -0.05);
--color-danger: oklch(0.7 0.18 0.07turn); --color-danger: oklab(0.7 0.16 0.08);
--color-primary: oklch(0.7 0.15 var(--hue)); --color-primary: oklab(0.7 -0.05 -0.14);
--color-error: oklch(0.8 0.12 0.07turn); --color-error: oklab(0.8 0.11 0.05);
--color-success: oklch(0.75 0.15 0.4turn); --color-success: oklab(0.75 -0.12 0.09);
--color-bg: oklch(0.18 0.03 var(--hue)); --color-bg: oklab(0.18 -0.01 -0.03);
--color-accent-soft: oklch(0.25 0.08 var(--hue)); --color-accent-soft: oklab(0.25 -0.03 -0.08);
--shadow-soft: 0 0 0 black; --shadow-soft: 0 0 0 black;
--shadow-xl: 0 10px 40px rgba(0, 0, 0, 0.4); --shadow-xl: 0 10px 40px rgba(0, 0, 0, 0.4);
} }
@@ -284,39 +284,39 @@ output[title="Click to copy"] {
} }
.btn-primary { .btn-primary {
background: linear-gradient(to bottom, oklch(1 0 0 / 0.15), transparent 60%) var(--color-accent); background: linear-gradient(to bottom, oklab(1 0 0 / 0.15), transparent 60%) var(--color-accent);
color: var(--color-accent-contrast); color: var(--color-accent-contrast);
border-color: var(--color-accent); border-color: var(--color-accent);
} }
.btn-primary:hover:not(:disabled), .btn-primary:hover:not(:disabled),
.btn-primary:focus-visible { .btn-primary:focus-visible {
background: linear-gradient(to bottom, oklch(1 0 0 / 0.15), transparent 60%) var(--color-accent-strong); background: linear-gradient(to bottom, oklab(1 0 0 / 0.15), transparent 60%) var(--color-accent-strong);
border-color: var(--color-accent-strong); border-color: var(--color-accent-strong);
box-shadow: var(--shadow-soft); box-shadow: var(--shadow-soft);
} }
.btn-secondary { .btn-secondary {
background: linear-gradient(to bottom, oklch(1 0 0 / 0.15), transparent 60%) var(--color-secondary); background: linear-gradient(to bottom, oklab(1 0 0 / 0.15), transparent 60%) var(--color-secondary);
color: var(--color-accent-contrast); color: var(--color-accent-contrast);
border-color: transparent; border-color: transparent;
} }
.btn-secondary:hover:not(:disabled), .btn-secondary:hover:not(:disabled),
.btn-secondary:focus-visible { .btn-secondary:focus-visible {
background: linear-gradient(to bottom, oklch(1 0 0 / 0.15), transparent 60%) var(--color-secondary-strong); background: linear-gradient(to bottom, oklab(1 0 0 / 0.15), transparent 60%) var(--color-secondary-strong);
box-shadow: var(--shadow-soft); box-shadow: var(--shadow-soft);
} }
.btn-danger { .btn-danger {
background: linear-gradient(to bottom, oklch(1 0 0 / 0.15), transparent 60%) var(--color-danger); background: linear-gradient(to bottom, oklab(1 0 0 / 0.15), transparent 60%) var(--color-danger);
color: var(--color-accent-contrast); color: var(--color-accent-contrast);
border-color: transparent; border-color: transparent;
} }
.btn-danger:hover:not(:disabled), .btn-danger:hover:not(:disabled),
.btn-danger:focus-visible { .btn-danger:focus-visible {
background: linear-gradient(to bottom, oklch(1 0 0 / 0.15), transparent 60%) var(--color-danger); background: linear-gradient(to bottom, oklab(1 0 0 / 0.15), transparent 60%) var(--color-danger);
filter: brightness(0.92); filter: brightness(0.92);
box-shadow: var(--shadow-soft); box-shadow: var(--shadow-soft);
} }
@@ -601,7 +601,6 @@ th {
.qr-code { .qr-code {
padding: 1rem; padding: 1rem;
background: white; background: white;
box-shadow: var(--shadow-soft);
} }
.link-container, .link-container,
@@ -658,9 +657,18 @@ th {
.record-item.is-current, .record-item.is-current,
.credential-item.current-session, .credential-item.current-session,
.session-item.is-current {
border-color: var(--color-accent);
background-color: var(--color-surface-subtle);
}
.credential-item.is-hovered, .credential-item.is-hovered,
.session-item.is-current, .session-item.is-hovered {
.session-item.is-hovered { border-color: var(--color-accent); background-color: var(--color-surface-subtle); } border-color: var(--color-accent);
background-color: var(--color-surface-subtle);
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.12);
transform: translateY(-1px);
}
.credential-item.is-linked-session, .credential-item.is-linked-session,
.session-item.is-linked-credential { border-color: var(--color-accent); background-color: var(--color-surface-subtle); } .session-item.is-linked-credential { border-color: var(--color-accent); background-color: var(--color-surface-subtle); }
+23 -22
View File
@@ -83,6 +83,29 @@
section-description="You are currently signed in to the following sessions. If you don't recognize something, consider deleting not only the session but the associated passkey you suspect is compromised, as only this terminates all linked sessions and prevents logging in again." section-description="You are currently signed in to the following sessions. If you don't recognize something, consider deleting not only the session but the associated passkey you suspect is compromised, as only this terminates all linked sessions and prevents logging in again."
/> />
<section :class="['section-block', { 'section-block--constrained': !useWideLayout }]">
<div class="button-row" ref="logoutButtons">
<button
type="button"
class="btn-secondary"
@click="goBack"
@keydown="handleLogoutButtonKeydown"
>
Back
</button>
<button v-if="!hasMultipleSessions" @click="logoutEverywhere" class="btn-danger" :disabled="authStore.isLoading" @keydown="handleLogoutButtonKeydown">Logout</button>
<template v-else>
<button @click="logout" class="btn-danger" :disabled="authStore.isLoading" @keydown="handleLogoutButtonKeydown">Logout</button>
<button @click="logoutEverywhere" class="btn-danger" :disabled="authStore.isLoading" @keydown="handleLogoutButtonKeydown">All</button>
</template>
</div>
<div class="logout-footer">
<p class="logout-note" v-if="!hasMultipleSessions"><strong>Logout</strong> from {{ currentSessionHost }}.</p>
<p class="logout-note" v-else><strong>Logout</strong> this session on {{ currentSessionHost }}, or <strong>All</strong> sessions across all sites and devices for {{ rpName }}.</p>
<a class="paskia-version" href="https://git.zi.fi/leovasanko/paskia" target="_blank" rel="noopener noreferrer">Paskia {{ paskiaVersion }}</a>
</div>
</section>
<Modal v-if="showEditDialog" @close="showEditDialog = false"> <Modal v-if="showEditDialog" @close="showEditDialog = false">
<h3>Edit Profile</h3> <h3>Edit Profile</h3>
<form @submit.prevent="saveProfile" class="modal-form"> <form @submit.prevent="saveProfile" class="modal-form">
@@ -108,28 +131,6 @@
</form> </form>
</Modal> </Modal>
<section :class="['section-block', { 'section-block--constrained': !useWideLayout }]">
<div class="button-row" ref="logoutButtons">
<button
type="button"
class="btn-secondary"
@click="goBack"
@keydown="handleLogoutButtonKeydown"
>
Back
</button>
<button v-if="!hasMultipleSessions" @click="logoutEverywhere" class="btn-danger" :disabled="authStore.isLoading" @keydown="handleLogoutButtonKeydown">Logout</button>
<template v-else>
<button @click="logout" class="btn-danger" :disabled="authStore.isLoading" @keydown="handleLogoutButtonKeydown">Logout</button>
<button @click="logoutEverywhere" class="btn-danger" :disabled="authStore.isLoading" @keydown="handleLogoutButtonKeydown">All</button>
</template>
</div>
<div class="logout-footer">
<p class="logout-note" v-if="!hasMultipleSessions"><strong>Logout</strong> from {{ currentSessionHost }}.</p>
<p class="logout-note" v-else><strong>Logout</strong> this session on {{ currentSessionHost }}, or <strong>All</strong> sessions across all sites and devices for {{ rpName }}. You'll need to log in again with your passkey afterwards.</p>
<a class="paskia-version" href="https://git.zi.fi/leovasanko/paskia" target="_blank" rel="noopener noreferrer">Paskia {{ paskiaVersion }}</a>
</div>
</section>
<RegistrationLinkModal <RegistrationLinkModal
v-if="showRegLink" v-if="showRegLink"
endpoint="/auth/api/user/create-link" endpoint="/auth/api/user/create-link"