Add dark mode with CSS custom property theme system

Define 13 semantic color tokens (surface, text, border, hover) with
light/dark values in themes.css. Register with Tailwind via @theme inline.
Migrate all 335 Vue files from hardcoded gray/white classes to semantic
tokens. Add theme toggle (sun/moon/system) in user avatar dropdown.
Replace @tailwindcss/forms with custom form reset using theme vars.
Add status badge and alert tokens for dark mode. Theme-aware chart
grid/labels, skeleton placeholders, and editor. Inline script in
<head> prevents flash of wrong theme on load.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Darko Gjorgjijoski
2026-04-04 02:05:00 +02:00
parent 7fbe3d85a3
commit 88adfe0e50
221 changed files with 1265 additions and 982 deletions

View File

@@ -61,7 +61,7 @@
</BaseInputGroup>
</BaseInputGrid>
<div v-if="userData" class="mt-6 text-sm text-gray-500">
<div v-if="userData" class="mt-6 text-sm text-muted">
<p>
<strong>{{ $t('administration.users.role') }}:</strong>
{{ userData.role }}

View File

@@ -66,7 +66,7 @@
>
<BaseIcon
name="UsersIcon"
class="mt-5 mb-4 h-16 w-16 text-gray-300"
class="mt-5 mb-4 h-16 w-16 text-subtle"
/>
</BaseEmptyPlaceholder>
@@ -107,18 +107,18 @@
<span
v-for="company in row.data.companies.slice(0, 3)"
:key="company.id"
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-700"
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-surface-tertiary text-body"
>
{{ company.name }}
</span>
<span
v-if="row.data.companies.length > 3"
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-500"
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-surface-tertiary text-muted"
>
+{{ row.data.companies.length - 3 }}
</span>
</div>
<span v-else class="text-gray-400">-</span>
<span v-else class="text-subtle">-</span>
</template>
<template #cell-actions="{ row }">
@@ -158,7 +158,7 @@ const userTableColumns = computed(() => {
key: 'name',
label: t('users.name'),
thClass: 'extra',
tdClass: 'font-medium text-gray-900',
tdClass: 'font-medium text-heading',
},
{
key: 'email',
@@ -232,7 +232,7 @@ function getRoleBadgeClass(role) {
case 'admin':
return 'bg-blue-100 text-blue-800'
default:
return 'bg-gray-100 text-gray-800'
return 'bg-surface-tertiary text-heading'
}
}