Rename hoard- to ui- and add UI components

Mass rename of CSS classes, tokens and animations from the hoard- namespace to ui- (classes, variables like --ui-*, and keyframes). Introduces new UI components: EmptyState, StatusPill, and UserAvatar and updates admin views to import and use them. Updates many route/layout components and global.css to use the new ui- patterns and responsive variables. Also updates Impressum contact emails and adds .claude/settings.local.json to allow running npm scripts in the Claude local settings.
This commit is contained in:
Jonas
2026-04-28 21:52:22 +02:00
parent a512aaa0a7
commit 7e2ca4c9e2
19 changed files with 381 additions and 382 deletions
+37 -54
View File
@@ -4,6 +4,9 @@ import { useRouter } from 'vue-router'
import { fetchAdminUsers, type AdminUser } from '@/services/adminUsers'
import { AuthRequestError } from '@/services/authSession'
import { useAppBannersStore } from '@/stores/appBanners'
import StatusPill from '@/components/ui/StatusPill.vue'
import UserAvatar from '@/components/ui/UserAvatar.vue'
import EmptyState from '@/components/ui/EmptyState.vue'
const router = useRouter()
const appBannersStore = useAppBannersStore()
@@ -111,15 +114,15 @@ onMounted(() => {
</script>
<template>
<v-container fluid class="admin-users-page hoard-page">
<header class="admin-users-header hoard-panel hoard-panel-gradient">
<v-container fluid class="admin-users-page ui-page">
<header class="admin-users-header ui-panel ui-panel-gradient">
<div class="admin-users-header__copy">
<p class="hoard-kicker hoard-kicker--wide">Adminbereich</p>
<p class="ui-kicker ui-kicker--wide">Adminbereich</p>
<h1>Benutzerverwaltung</h1>
<p>Alle Hoard-Konten mit Rollen, Status und Passwortwechselpflicht read-only.</p>
</div>
<div class="admin-users-header__actions hoard-action-row">
<div class="admin-users-header__actions ui-action-row">
<v-text-field
v-model="searchQuery"
variant="outlined"
@@ -144,7 +147,7 @@ onMounted(() => {
<section v-if="!isLoading && !errorMessage" class="admin-users-stats" aria-label="Benutzerübersicht">
<article class="admin-users-stat">
<span class="hoard-icon-tile">
<span class="ui-icon-tile">
<v-icon icon="mdi-account-group-outline" size="20" />
</span>
<div>
@@ -153,7 +156,7 @@ onMounted(() => {
</div>
</article>
<article class="admin-users-stat">
<span class="hoard-icon-tile">
<span class="ui-icon-tile">
<v-icon icon="mdi-account-check-outline" size="20" />
</span>
<div>
@@ -162,7 +165,7 @@ onMounted(() => {
</div>
</article>
<article class="admin-users-stat">
<span class="hoard-icon-tile">
<span class="ui-icon-tile">
<v-icon icon="mdi-shield-account-outline" size="20" />
</span>
<div>
@@ -171,7 +174,7 @@ onMounted(() => {
</div>
</article>
<article class="admin-users-stat">
<span class="hoard-icon-tile">
<span class="ui-icon-tile">
<v-icon icon="mdi-lock-reset" size="20" />
</span>
<div>
@@ -187,16 +190,16 @@ onMounted(() => {
<p v-else-if="isLoading" class="admin-users-loading">Benutzer werden geladen </p>
<section v-else-if="!hasUsers" class="hoard-panel hoard-empty-state">
<span class="hoard-icon-tile hoard-icon-tile--lg">
<v-icon icon="mdi-account-question-outline" size="22" />
</span>
<h2>Keine Benutzer gefunden</h2>
<p>Aktuell sind keine Konten vorhanden. Ein neuer Account muss vom Admin manuell angelegt werden.</p>
</section>
<EmptyState
v-else-if="!hasUsers"
icon="mdi-account-question-outline"
title="Keine Benutzer gefunden"
>
Aktuell sind keine Konten vorhanden. Ein neuer Account muss vom Admin manuell angelegt werden.
</EmptyState>
<section v-else class="admin-users-listing hoard-panel">
<header class="admin-users-listing__head hoard-toolbar">
<section v-else class="admin-users-listing ui-panel">
<header class="admin-users-listing__head ui-toolbar">
<div>
<p class="admin-users-listing__title">Benutzer</p>
<p class="admin-users-listing__meta">{{ filteredUsers.length }} von {{ users.length }} angezeigt</p>
@@ -222,7 +225,7 @@ onMounted(() => {
<tr v-for="user in filteredUsers" :key="user.id">
<td>
<div class="admin-users-cell-user">
<span class="admin-users-cell-user__avatar">{{ userInitials(user) }}</span>
<UserAvatar class="admin-users-cell-user__avatar" :initials="userInitials(user)" />
<div>
<p class="admin-users-cell-user__name">{{ user.userName || '(ohne Benutzername)' }}</p>
<p class="admin-users-cell-user__id">{{ user.id }}</p>
@@ -231,24 +234,14 @@ onMounted(() => {
</td>
<td>{{ formatRoles(user.roles) }}</td>
<td>
<span
:class="[
'hoard-status',
user.isActive ? 'hoard-status--success' : 'hoard-status--danger',
]"
>
<StatusPill :variant="user.isActive ? 'success' : 'danger'">
{{ user.isActive ? 'Aktiv' : 'Inaktiv' }}
</span>
</StatusPill>
</td>
<td>
<span
:class="[
'hoard-status',
user.mustChangePassword ? 'hoard-status--warning' : 'hoard-status--info',
]"
>
<StatusPill :variant="user.mustChangePassword ? 'warning' : 'info'">
{{ user.mustChangePassword ? 'Erforderlich' : 'Aktuell' }}
</span>
</StatusPill>
</td>
<td class="admin-users-col-actions">
<v-btn
@@ -268,7 +261,7 @@ onMounted(() => {
<div v-if="filteredUsers.length > 0" class="admin-users-mobile-list" aria-label="Benutzerliste">
<article v-for="user in filteredUsers" :key="user.id" class="admin-users-mobile-card">
<header class="admin-users-mobile-head">
<span class="admin-users-mobile-avatar">{{ userInitials(user) }}</span>
<UserAvatar class="admin-users-mobile-avatar" :initials="userInitials(user)" />
<div>
<p class="admin-users-mobile-label">Benutzer</p>
<h2>{{ user.userName || '(ohne Benutzername)' }}</h2>
@@ -284,27 +277,17 @@ onMounted(() => {
<div>
<dt>Aktiv</dt>
<dd>
<span
:class="[
'hoard-status',
user.isActive ? 'hoard-status--success' : 'hoard-status--danger',
]"
>
<StatusPill :variant="user.isActive ? 'success' : 'danger'">
{{ user.isActive ? 'Aktiv' : 'Inaktiv' }}
</span>
</StatusPill>
</dd>
</div>
<div>
<dt>Passwortwechsel</dt>
<dd>
<span
:class="[
'hoard-status',
user.mustChangePassword ? 'hoard-status--warning' : 'hoard-status--info',
]"
>
<StatusPill :variant="user.mustChangePassword ? 'warning' : 'info'">
{{ user.mustChangePassword ? 'Erforderlich' : 'Nein' }}
</span>
</StatusPill>
</dd>
</div>
</dl>
@@ -325,15 +308,15 @@ onMounted(() => {
<style scoped>
.admin-users-page {
--hoard-page-width: 1200px;
--ui-page-width: 1200px;
}
/* ---------- Header ---------- */
.admin-users-header {
--hoard-gradient-angle: 120deg;
--hoard-gradient-start: color-mix(in srgb, var(--color-primary-100) 55%, var(--color-surface) 45%);
--hoard-gradient-end: var(--color-surface);
--hoard-gradient-end-stop: 65%;
--ui-gradient-angle: 120deg;
--ui-gradient-start: color-mix(in srgb, var(--color-primary-100) 55%, var(--color-surface) 45%);
--ui-gradient-end: var(--color-surface);
--ui-gradient-end-stop: 65%;
display: grid;
grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
@@ -505,7 +488,7 @@ onMounted(() => {
white-space: nowrap;
}
.hoard-empty-state {
.ui-empty-state {
display: flex;
flex-direction: column;
align-items: center;
@@ -516,7 +499,7 @@ onMounted(() => {
.admin-users-header,
.admin-users-stat,
.admin-users-listing {
animation: hoard-soft-enter 280ms both;
animation: ui-soft-enter 280ms both;
}
.admin-users-stat:nth-child(2) { animation-delay: 60ms; }