Enhance FormMessage and styleguide for improved accessibility and user feedback
- Add orange AlertCircle icon to FormMessage component for better visibility of validation errors. - Update styleguide to demonstrate new alert components with icons for error, success, and warning messages. - Refactor CSS for status messages and form error messages to improve layout and accessibility compliance.
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
import type { HTMLAttributes } from 'vue'
|
import type { HTMLAttributes } from 'vue'
|
||||||
import { inject } from 'vue'
|
import { inject } from 'vue'
|
||||||
import { useFieldError } from 'vee-validate'
|
import { useFieldError } from 'vee-validate'
|
||||||
|
import { AlertCircle } from 'lucide-vue-next'
|
||||||
import { cn } from '~/lib/utils'
|
import { cn } from '~/lib/utils'
|
||||||
import type { FormItemContext } from '.'
|
import type { FormItemContext } from '.'
|
||||||
import { FORM_ITEM_INJECT_KEY } from '.'
|
import { FORM_ITEM_INJECT_KEY } from '.'
|
||||||
@@ -9,6 +10,7 @@ import { FORM_ITEM_INJECT_KEY } from '.'
|
|||||||
/**
|
/**
|
||||||
* FormMessage component - Displays validation error messages
|
* FormMessage component - Displays validation error messages
|
||||||
* Only renders when there is an error for the associated field
|
* Only renders when there is an error for the associated field
|
||||||
|
* Includes orange AlertCircle icon for better accessibility
|
||||||
*/
|
*/
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -38,7 +40,8 @@ const error = useFieldError()
|
|||||||
:id="`${formItemContext?.id}-message`"
|
:id="`${formItemContext?.id}-message`"
|
||||||
:class="cn('form-error', props.class)"
|
:class="cn('form-error', props.class)"
|
||||||
>
|
>
|
||||||
{{ error }}
|
<AlertCircle class="h-6 w-6 text-warning flex-shrink-0" />
|
||||||
|
<span>{{ error }}</span>
|
||||||
</p>
|
</p>
|
||||||
</Transition>
|
</Transition>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
* Protected by Basic Auth via server/middleware/internal-auth.ts
|
* Protected by Basic Auth via server/middleware/internal-auth.ts
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { AlertCircle, CheckCircle } from 'lucide-vue-next'
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'styleguide',
|
layout: 'styleguide',
|
||||||
})
|
})
|
||||||
@@ -442,9 +444,21 @@ const copyCode = async (code: string) => {
|
|||||||
<!-- Error Message Styles -->
|
<!-- Error Message Styles -->
|
||||||
<div class="space-y-3 mt-6">
|
<div class="space-y-3 mt-6">
|
||||||
<h4 class="text-lg font-semibold text-white">Fehlermeldungen (.form-error)</h4>
|
<h4 class="text-lg font-semibold text-white">Fehlermeldungen (.form-error)</h4>
|
||||||
<p class="form-error">Dies ist eine Fehlermeldung mit gutem Kontrast</p>
|
<p class="text-sm text-white/70 mb-4">
|
||||||
<p class="form-error">Required</p>
|
Orange Border (WCAG AA konform) mit Icon für bessere Barrierefreiheit. Icon optional.
|
||||||
<p class="form-error">Das Passwort muss mindestens 8 Zeichen lang sein</p>
|
</p>
|
||||||
|
<p class="form-error">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-warning flex-shrink-0"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
||||||
|
Dies ist eine Fehlermeldung mit gutem Kontrast
|
||||||
|
</p>
|
||||||
|
<p class="form-error">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-warning flex-shrink-0"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
||||||
|
Dieses Feld ist erforderlich
|
||||||
|
</p>
|
||||||
|
<p class="form-error">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-warning flex-shrink-0"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
||||||
|
Das Passwort muss mindestens 8 Zeichen lang sein
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -495,26 +509,29 @@ const copyCode = async (code: string) => {
|
|||||||
|
|
||||||
<div class="card-glass">
|
<div class="card-glass">
|
||||||
<h3 class="text-2xl font-semibold mb-6 text-white">Status Indicators</h3>
|
<h3 class="text-2xl font-semibold mb-6 text-white">Status Indicators</h3>
|
||||||
|
<p class="text-sm text-white/70 mb-6">
|
||||||
|
Einheitlicher Stil mit orange/grünem Border für bessere Barrierefreiheit. Alle verwenden den gleichen Hintergrund mit farbigem Icon.
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="status-message status-success">
|
<div class="status-message status-success">
|
||||||
<span class="status-icon">✓</span>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="status-icon"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>
|
||||||
<span>Success message</span>
|
<span>Erfolgsmeldung - Aktion wurde ausgeführt</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="status-message status-warning">
|
<div class="status-message status-warning">
|
||||||
<span class="status-icon">⚠</span>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="status-icon"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>
|
||||||
<span>Warning message</span>
|
<span>Warnung - Bitte beachten</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="status-message status-error">
|
<div class="status-message status-error">
|
||||||
<span class="status-icon">✕</span>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="status-icon"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
||||||
<span>Error message</span>
|
<span>Fehlermeldung - Etwas ist schiefgelaufen</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="status-message status-info">
|
<div class="status-message status-info">
|
||||||
<span class="status-icon">ⓘ</span>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="status-icon"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>
|
||||||
<span>Info message</span>
|
<span>Information - Nützlicher Hinweis</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -528,6 +545,66 @@ const copyCode = async (code: string) => {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Alert Components Section -->
|
||||||
|
<section id="alerts" class="mb-16">
|
||||||
|
<h2 class="text-4xl font-bold mb-6 text-experimenta-accent">Alert Components</h2>
|
||||||
|
|
||||||
|
<div class="card-glass">
|
||||||
|
<h3 class="text-2xl font-semibold mb-6 text-white">shadcn-nuxt Alert Variants</h3>
|
||||||
|
<p class="text-sm text-white/70 mb-6">
|
||||||
|
Alert-Komponenten für Benachrichtigungen und Fehlermeldungen. Die "error" Variante verwendet Orange für bessere Barrierefreiheit (WCAG AA konform).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<!-- Error Alert -->
|
||||||
|
<Alert variant="error">
|
||||||
|
<AlertCircle class="h-6 w-6" />
|
||||||
|
<AlertDescription>
|
||||||
|
Ungültige E-Mail-Adresse oder Passwort
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
|
||||||
|
<!-- Success Alert -->
|
||||||
|
<Alert class="bg-white/15 border-l-4 border-success text-white">
|
||||||
|
<CheckCircle class="h-6 w-6 text-success" />
|
||||||
|
<AlertTitle class="text-success font-medium">Registrierung erfolgreich!</AlertTitle>
|
||||||
|
<AlertDescription>
|
||||||
|
Bitte bestätige deine E-Mail-Adresse über den Link, den wir dir gesendet haben.
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
|
||||||
|
<!-- Destructive Alert (original red) -->
|
||||||
|
<Alert variant="destructive">
|
||||||
|
<AlertCircle class="h-5 w-5" />
|
||||||
|
<AlertTitle>Warnung</AlertTitle>
|
||||||
|
<AlertDescription>
|
||||||
|
Dies ist die ursprüngliche "destructive" Variante mit rotem Border.
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<details class="bg-white/5 p-4 rounded-lg mt-6">
|
||||||
|
<summary class="cursor-pointer text-white/90 font-semibold">Show Code</summary>
|
||||||
|
<pre class="mt-4 text-sm text-white/80 overflow-x-auto"><code><!-- Error Alert (empfohlen für Fehler) -->
|
||||||
|
<Alert variant="error">
|
||||||
|
<AlertCircle class="h-6 w-6" />
|
||||||
|
<AlertDescription>
|
||||||
|
Ungültige E-Mail-Adresse oder Passwort
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
|
||||||
|
<!-- Success Alert -->
|
||||||
|
<Alert class="bg-white/15 border-l-4 border-success text-white">
|
||||||
|
<CheckCircle class="h-6 w-6 text-success" />
|
||||||
|
<AlertTitle class="text-success font-medium">Erfolg!</AlertTitle>
|
||||||
|
<AlertDescription>
|
||||||
|
Deine Nachricht...
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert></code></pre>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Progress Bars Section -->
|
<!-- Progress Bars Section -->
|
||||||
<section id="progress" class="mb-16">
|
<section id="progress" class="mb-16">
|
||||||
<h2 class="text-4xl font-bold mb-6 text-experimenta-accent">Progress Bars</h2>
|
<h2 class="text-4xl font-bold mb-6 text-experimenta-accent">Progress Bars</h2>
|
||||||
|
|||||||
@@ -496,28 +496,52 @@
|
|||||||
|
|
||||||
/* Status Messages */
|
/* Status Messages */
|
||||||
.status-message {
|
.status-message {
|
||||||
@apply flex items-center gap-4;
|
@apply flex items-center gap-3;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background-color: rgba(255, 255, 255, 0.15); /* White with 15% opacity */
|
||||||
|
color: #ffffff; /* White text */
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-icon {
|
.status-icon {
|
||||||
@apply flex items-center justify-center;
|
@apply flex items-center justify-center;
|
||||||
@apply w-25 h-25 rounded-full;
|
@apply flex-shrink-0;
|
||||||
@apply text-6xl text-white;
|
width: 1.5rem;
|
||||||
@apply animate-pulse;
|
height: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
.status-success {
|
||||||
.status-icon {
|
@apply border-l-4 border-success;
|
||||||
@apply text-5xl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-success .status-icon {
|
.status-success .status-icon {
|
||||||
@apply bg-success;
|
@apply text-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-error {
|
||||||
|
@apply border-l-4 border-warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-error .status-icon {
|
.status-error .status-icon {
|
||||||
@apply bg-error;
|
@apply text-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-warning {
|
||||||
|
@apply border-l-4 border-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-warning .status-icon {
|
||||||
|
@apply text-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-info {
|
||||||
|
@apply border-l-4 border-accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-info .status-icon {
|
||||||
|
@apply text-accent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Progress Bar */
|
/* Progress Bar */
|
||||||
@@ -606,17 +630,20 @@
|
|||||||
@apply outline-none ring-2 ring-accent;
|
@apply outline-none ring-2 ring-accent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Form Error Message - High contrast for readability */
|
/* Form Error Message - High contrast with orange accent */
|
||||||
.form-error {
|
.form-error {
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.75rem 1rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
border: 1px solid rgba(248, 113, 113, 0.4); /* red-400 with 40% opacity */
|
border-left: 4px solid var(--color-warning); /* Orange left border for accessibility */
|
||||||
background-color: rgba(239, 68, 68, 0.2); /* red-500 with 20% opacity */
|
background-color: rgba(255, 255, 255, 0.15); /* White with 15% opacity */
|
||||||
color: #fecaca; /* red-200 for better contrast */
|
color: #ffffff; /* White text */
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-checkbox {
|
.form-checkbox {
|
||||||
|
|||||||
Reference in New Issue
Block a user