From 10bf4b94ade089ae694247d202e228b0f0e18d33 Mon Sep 17 00:00:00 2001 From: Jonas <77726472+kobolol@users.noreply.github.com> Date: Thu, 23 Apr 2026 22:07:07 +0200 Subject: [PATCH] UI refresh: animation, cards, responsive tweaks Large frontend modernization: add route fade transition and hoard-soft-enter keyframes with prefers-reduced-motion support; introduce smoother motion tokens and stronger shadow tokens. Update global CSS to use subtle surface gradients, unified transitions, hover lift effects, focus rings and improved button/card/table/overlay styles. Wrap in a transition and adjust brand/logo sizing and interactions. Revamp several pages/components (Home, Login, Impressum, 404, Forbidden) with adjusted typography, animated entry for sections and improved card hover states. Admin/Dashboard pages enhanced: AdminUsers gains stats, mobile card list & computed counts; AdminUserDetail and Dashboard show compact summary cards and updated styles. Documentation updated (style.md, codexInfo.md) to reflect the new modernisation rules. No API or backend changes. --- GUI/src/Layout.vue | 52 ++- GUI/src/global.css | 127 ++++++- GUI/src/routes/404NotFound.vue | 15 +- GUI/src/routes/Forbidden.vue | 6 + GUI/src/routes/Home.vue | 100 +++++- GUI/src/routes/Impressum.vue | 38 ++- GUI/src/routes/admin/AdminUserDetail.vue | 58 +++- GUI/src/routes/admin/AdminUsers.vue | 311 +++++++++++++++--- .../routes/authentication/ChangePassword.vue | 10 +- GUI/src/routes/authentication/Login.vue | 34 +- GUI/src/routes/dashboard/Dashboard.vue | 143 +++++++- GUI/style.md | 13 +- codexInfo.md | 4 + 13 files changed, 827 insertions(+), 84 deletions(-) diff --git a/GUI/src/Layout.vue b/GUI/src/Layout.vue index 60fac58..2f9cc6d 100644 --- a/GUI/src/Layout.vue +++ b/GUI/src/Layout.vue @@ -428,7 +428,11 @@ watch(
- + + + + +
{ h1 { margin-bottom: var(--space-3); - font-size: clamp(1.8rem, 2vw + 1rem, 2.4rem); + font-size: 2.35rem; font-weight: 700; } @@ -160,6 +160,17 @@ h1 { align-items: center; } +@media (prefers-reduced-motion: no-preference) { + .not-found-visual, + .not-found-content { + animation: hoard-soft-enter 260ms both; + } + + .not-found-content { + animation-delay: 80ms; + } +} + @media (width <= 960px) { .not-found-shell { grid-template-columns: 1fr; @@ -191,7 +202,7 @@ h1 { } h1 { - font-size: clamp(1.5rem, 7vw, 1.9rem); + font-size: 1.85rem; } .not-found-text { diff --git a/GUI/src/routes/Forbidden.vue b/GUI/src/routes/Forbidden.vue index 408df39..1ed0e7f 100644 --- a/GUI/src/routes/Forbidden.vue +++ b/GUI/src/routes/Forbidden.vue @@ -80,4 +80,10 @@ onMounted(() => { .forbidden-head p { color: var(--color-text-secondary); } + +@media (prefers-reduced-motion: no-preference) { + .forbidden-shell { + animation: hoard-soft-enter 260ms both; + } +} diff --git a/GUI/src/routes/Home.vue b/GUI/src/routes/Home.vue index 80e677d..14f02c2 100644 --- a/GUI/src/routes/Home.vue +++ b/GUI/src/routes/Home.vue @@ -88,7 +88,7 @@ const techStack = ['Vue 3', 'ASP.NET Core', 'PostgreSQL', 'MinIO', 'md-editor-v3 -
+

Beispielansicht

Workspace @@ -199,7 +199,7 @@ const techStack = ['Vue 3', 'ASP.NET Core', 'PostgreSQL', 'MinIO', 'md-editor-v3 h1 { margin-bottom: var(--space-4); max-width: 20ch; - font-size: clamp(2rem, 2.5vw + 1rem, 3rem); + font-size: 3rem; line-height: 1.08; } @@ -235,7 +235,15 @@ h1 { align-self: center; padding: var(--space-5); width: 100%; - background-color: color-mix(in srgb, var(--color-surface-alt) 86%, var(--color-surface) 14%); + border: 1px solid color-mix(in srgb, var(--color-border) 76%, var(--color-surface) 24%); + border-radius: var(--radius-lg); + background: + linear-gradient( + 180deg, + color-mix(in srgb, var(--color-surface-alt) 82%, var(--color-surface) 18%), + var(--color-surface) + ); + box-shadow: var(--shadow-sm); } .preview-head { @@ -277,6 +285,16 @@ h1 { border: 1px solid color-mix(in srgb, var(--color-border) 75%, var(--color-surface) 25%); border-radius: var(--radius-md); background-color: var(--color-surface); + transition: + border-color var(--transition-fast), + box-shadow var(--transition-fast), + transform var(--transition-fast); +} + +.preview-row:hover { + border-color: color-mix(in srgb, var(--color-primary-300) 52%, var(--color-border) 48%); + box-shadow: var(--shadow-sm); + transform: translateX(3px); } .row-title { @@ -300,10 +318,38 @@ h1 { padding: var(--space-5); } +.value-card, +.workflow-card, +.feature-card { + transition: + border-color var(--transition-fast), + box-shadow var(--transition-fast), + transform var(--transition-fast); +} + +.value-card:hover, +.workflow-card:hover, +.feature-card:hover { + border-color: color-mix(in srgb, var(--color-primary-300) 48%, var(--color-border) 52%); + box-shadow: var(--shadow-md); + transform: translateY(-2px); +} + +:deep(.value-card > .v-icon), +:deep(.feature-card > .v-icon) { + display: inline-flex; + width: 36px; + height: 36px; + padding: var(--space-2); + border-radius: var(--radius-md); + color: var(--color-primary-700); + background-color: color-mix(in srgb, var(--color-primary-100) 82%, var(--color-surface) 18%); +} + .value-card h2, .section-head h2 { margin: var(--space-3) 0 var(--space-2); - font-size: clamp(1.25rem, 1.2vw + 0.8rem, 1.8rem); + font-size: 1.65rem; } .value-card p, @@ -381,6 +427,44 @@ h1 { background-color: color-mix(in srgb, var(--color-surface-alt) 75%, var(--color-surface) 25%); } +@media (prefers-reduced-motion: no-preference) { + .hero-copy, + .hero-preview, + .value-card, + .feature-section, + .workflow-section, + .stack-section { + animation: hoard-soft-enter 260ms both; + } + + .hero-preview { + animation-delay: 70ms; + } + + .value-card:nth-child(2), + .feature-section, + .workflow-section { + animation-delay: 90ms; + } + + .value-card:nth-child(3), + .stack-section { + animation-delay: 130ms; + } + + .preview-row { + animation: hoard-soft-enter 240ms both; + } + + .preview-row:nth-child(2) { + animation-delay: 70ms; + } + + .preview-row:nth-child(3) { + animation-delay: 120ms; + } +} + @media (width <= 1100px) { .hero, .stack-section { @@ -419,6 +503,12 @@ h1 { h1 { max-width: none; + font-size: 2.25rem; + } + + .value-card h2, + .section-head h2 { + font-size: 1.45rem; } } @@ -430,7 +520,7 @@ h1 { } h1 { - font-size: clamp(1.6rem, 8vw, 2rem); + font-size: 1.9rem; } .hero-lead { diff --git a/GUI/src/routes/Impressum.vue b/GUI/src/routes/Impressum.vue index f9ffdc3..0458f48 100644 --- a/GUI/src/routes/Impressum.vue +++ b/GUI/src/routes/Impressum.vue @@ -135,7 +135,7 @@ const legalNotes = [ h1 { margin-bottom: var(--space-3); - font-size: clamp(1.9rem, 2.2vw + 1rem, 2.5rem); + font-size: 2.45rem; } .hero-lead { @@ -187,7 +187,7 @@ h1 { h2 { margin: 0; - font-size: clamp(1.2rem, 1.2vw + 0.85rem, 1.6rem); + font-size: 1.45rem; } .detail-list { @@ -250,6 +250,38 @@ h3 { color: var(--color-text-secondary); } +.detail-card, +.note-card { + transition: + border-color var(--transition-fast), + box-shadow var(--transition-fast), + transform var(--transition-fast); +} + +.detail-card:hover, +.note-card:hover { + border-color: color-mix(in srgb, var(--color-primary-300) 46%, var(--color-border) 54%); + box-shadow: var(--shadow-md); + transform: translateY(-2px); +} + +@media (prefers-reduced-motion: no-preference) { + .impressum-hero, + .detail-card, + .notes-section { + animation: hoard-soft-enter 260ms both; + } + + .detail-card:nth-child(2) { + animation-delay: 80ms; + } + + .detail-card:nth-child(3), + .notes-section { + animation-delay: 120ms; + } +} + @media (width <= 1080px) { .details-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); @@ -289,7 +321,7 @@ h3 { } h1 { - font-size: clamp(1.55rem, 7vw, 1.95rem); + font-size: 1.9rem; } .hero-meta { diff --git a/GUI/src/routes/admin/AdminUserDetail.vue b/GUI/src/routes/admin/AdminUserDetail.vue index ead6434..47d3b0c 100644 --- a/GUI/src/routes/admin/AdminUserDetail.vue +++ b/GUI/src/routes/admin/AdminUserDetail.vue @@ -93,7 +93,17 @@ onMounted(() => {

Benutzerdetails werden geladen...

-
+
+
+ + + +
+

Ausgewähltes Konto

+

{{ user.userName || '(ohne Benutzername)' }}

+
+
+
ID
@@ -186,7 +196,47 @@ onMounted(() => { } .admin-user-detail-card { + display: grid; + gap: var(--space-4); padding: var(--space-4); + border: 1px solid color-mix(in srgb, var(--color-border) 82%, var(--color-surface) 18%); + border-radius: var(--radius-md); + background-color: color-mix(in srgb, var(--color-surface-alt) 54%, var(--color-surface) 46%); +} + +.admin-user-detail-profile { + display: grid; + grid-template-columns: auto 1fr; + gap: var(--space-3); + align-items: center; + min-width: 0; +} + +.admin-user-detail-avatar { + display: inline-flex; + align-items: center; + justify-content: center; + width: 48px; + height: 48px; + border-radius: var(--radius-lg); + color: var(--color-primary-700); + background-color: color-mix(in srgb, var(--color-primary-100) 82%, var(--color-surface) 18%); +} + +.admin-user-detail-profile-label { + margin: 0; + color: var(--color-text-muted); + font-size: var(--font-size-xs); + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +.admin-user-detail-profile h2 { + margin: var(--space-1) 0 0; + color: var(--color-text); + font-size: 1.35rem; + overflow-wrap: anywhere; } .admin-user-detail-grid { @@ -217,6 +267,12 @@ onMounted(() => { justify-content: flex-end; } +@media (prefers-reduced-motion: no-preference) { + .admin-user-detail-shell { + animation: hoard-soft-enter 260ms both; + } +} + @media (width <= 600px) { .admin-user-detail-shell { padding: var(--space-4); diff --git a/GUI/src/routes/admin/AdminUsers.vue b/GUI/src/routes/admin/AdminUsers.vue index d67953e..1b42cab 100644 --- a/GUI/src/routes/admin/AdminUsers.vue +++ b/GUI/src/routes/admin/AdminUsers.vue @@ -13,6 +13,10 @@ const errorMessage = ref('') const users = ref([]) const hasUsers = computed(() => users.value.length > 0) +const activeUserCount = computed(() => users.value.filter((user) => user.isActive).length) +const passwordChangeCount = computed( + () => users.value.filter((user) => user.mustChangePassword).length, +) function formatRoles(roles: string[]): string { return roles.length > 0 ? roles.join(', ') : 'Keine Rolle' @@ -68,6 +72,21 @@ onMounted(() => {

Alle App-Konten mit Rollen, Status und Passwortwechselpflicht.

+
+
+

Konten

+

{{ users.length }}

+
+
+

Aktiv

+

{{ activeUserCount }}

+
+
+

Passwortwechsel

+

{{ passwordChangeCount }}

+
+
+ {

Aktuell sind keine Konten vorhanden.

-
- - - - Benutzername - Rollen - Aktiv - Passwortwechsel - Aktion - - - - - {{ user.userName || '(ohne Benutzername)' }} - {{ formatRoles(user.roles) }} - - - {{ user.isActive ? 'Aktiv' : 'Inaktiv' }} - - - - - {{ user.mustChangePassword ? 'Erforderlich' : 'Nein' }} - - - - - Details - - - - - +
+
+ + + + Benutzername + Rollen + Aktiv + Passwortwechsel + Aktion + + + + + {{ user.userName || '(ohne Benutzername)' }} + {{ formatRoles(user.roles) }} + + + {{ user.isActive ? 'Aktiv' : 'Inaktiv' }} + + + + + {{ user.mustChangePassword ? 'Erforderlich' : 'Nein' }} + + + + + Details + + + + + +
+ +
+
+
+ + + +
+

Benutzer

+

{{ user.userName || '(ohne Benutzername)' }}

+
+
+ +
+
+
Rollen
+
{{ formatRoles(user.roles) }}
+
+
+
Aktiv
+
+ + {{ user.isActive ? 'Aktiv' : 'Inaktiv' }} + +
+
+
+
Passwortwechsel
+
+ + {{ user.mustChangePassword ? 'Erforderlich' : 'Nein' }} + +
+
+
+ + + Details + +
+
@@ -179,8 +256,46 @@ onMounted(() => { color: var(--color-text-secondary); } +.admin-users-stats { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: var(--space-3); +} + +.admin-users-stat { + padding: var(--space-4); + border: 1px solid color-mix(in srgb, var(--color-border) 82%, var(--color-surface) 18%); + border-radius: var(--radius-md); + background-color: color-mix(in srgb, var(--color-surface-alt) 58%, var(--color-surface) 42%); +} + +.admin-users-stat-label, +.admin-users-stat-value { + margin: 0; +} + +.admin-users-stat-label { + color: var(--color-text-muted); + font-size: var(--font-size-xs); + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +.admin-users-stat-value { + color: var(--color-text); + font-size: 1.75rem; + font-weight: 700; + line-height: 1.15; +} + .admin-users-table-wrap { overflow-x: auto; + border-radius: var(--radius-md); +} + +.admin-users-mobile-list { + display: none; } .admin-users-table { @@ -201,9 +316,109 @@ onMounted(() => { justify-content: flex-end; } +@media (prefers-reduced-motion: no-preference) { + .admin-users-shell { + animation: hoard-soft-enter 260ms both; + } +} + @media (width <= 600px) { .admin-users-shell { padding: var(--space-4); + overflow: hidden; + } + + .admin-users-stats { + grid-template-columns: 1fr; + } + + .admin-users-table-wrap { + display: none; + } + + .admin-users-mobile-list { + display: grid; + gap: var(--space-3); + } + + .admin-users-mobile-card { + display: grid; + gap: var(--space-4); + min-width: 0; + padding: var(--space-4); + border: 1px solid color-mix(in srgb, var(--color-border) 80%, var(--color-surface) 20%); + border-radius: var(--radius-md); + background-color: color-mix(in srgb, var(--color-surface-alt) 58%, var(--color-surface) 42%); + } + + .admin-users-mobile-head { + display: grid; + grid-template-columns: auto 1fr; + gap: var(--space-3); + align-items: center; + min-width: 0; + } + + .admin-users-mobile-avatar { + display: inline-flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border-radius: var(--radius-md); + color: var(--color-primary-700); + background-color: color-mix(in srgb, var(--color-primary-100) 82%, var(--color-surface) 18%); + } + + .admin-users-mobile-label, + .admin-users-mobile-head h2, + .admin-users-mobile-details { + margin: 0; + } + + .admin-users-mobile-label { + color: var(--color-text-muted); + font-size: var(--font-size-xs); + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + } + + .admin-users-mobile-head h2 { + color: var(--color-text); + font-size: 1.1rem; + overflow-wrap: anywhere; + } + + .admin-users-mobile-details { + display: grid; + gap: var(--space-3); + } + + .admin-users-mobile-details div { + display: grid; + gap: var(--space-1); + padding-bottom: var(--space-3); + border-bottom: 1px solid color-mix(in srgb, var(--color-border) 78%, var(--color-surface) 22%); + } + + .admin-users-mobile-details div:last-child { + padding-bottom: 0; + border-bottom: none; + } + + .admin-users-mobile-details dt { + color: var(--color-text-muted); + font-size: var(--font-size-xs); + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + } + + .admin-users-mobile-details dd { + margin: 0; + color: var(--color-text); + overflow-wrap: anywhere; } .admin-users-actions { diff --git a/GUI/src/routes/authentication/ChangePassword.vue b/GUI/src/routes/authentication/ChangePassword.vue index d813d86..b074d95 100644 --- a/GUI/src/routes/authentication/ChangePassword.vue +++ b/GUI/src/routes/authentication/ChangePassword.vue @@ -76,7 +76,7 @@ async function handleSubmit() {

Sicherheitsvorgabe

Passwort ändern

-

Hier kannst du ganz bequem dein Password aktualisieren.

+

Hier kannst du ganz bequem dein Passwort aktualisieren.

{ -