fixed accessibility

This commit is contained in:
2025-08-21 18:17:15 +02:00
parent da67406b5f
commit 8fbb692a2c
6 changed files with 113 additions and 122 deletions

View File

@@ -1,13 +1,16 @@
<script lang="ts">
import Button from "../ui/button/button.svelte";
let { portableText, children } = $props();
const { value } = portableText;
</script>
<a
<Button
href={value.href}
variant="link"
target={value.blank ? '_blank' : '_self'}
rel={value.blank ? 'noopener noreferrer' : undefined}
class="text-primary hover:underline"
class="text-primary hover:underline p-0"
>
{@render children()}
</a>
</Button>

View File

@@ -2,6 +2,7 @@
import { getFileAsset } from '@sanity/asset-utils';
import { Download } from '@lucide/svelte';
import { client } from '$lib/sanity';
import Button from '../ui/button/button.svelte';
let { portableText } = $props();
const { value } = portableText;
@@ -10,8 +11,8 @@
{#if value?.asset}
{@const file = getFileAsset(value, { projectId, dataset })}
<a href={file.url} download class="inline-flex items-center gap-2 text-primary hover:underline">
<Button href={file.url} download class="inline-flex items-center gap-2 text-primary hover:underline">
<Download size={16} />
{value.title || 'Download file'}
</a>
</Button>
{/if}

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { cn } from '$lib/utils';
import { ArrowRight, ExternalLink } from '@lucide/svelte';
import Button from './ui/button/button.svelte';
let {
text,
@@ -28,54 +29,18 @@
const baseClasses = cn(
'group',
'rounded-full',
'font-semibold',
'transition-all',
'duration-300',
'no-underline',
'flex',
'items-center',
'gap-2',
'inline-flex',
'justify-center',
'whitespace-nowrap',
'text-sm',
'font-medium',
'ring-offset-background',
'transition-colors',
'focus-visible:outline-none',
'focus-visible:ring-2',
'focus-visible:ring-ring',
'focus-visible:ring-offset-2',
'disabled:pointer-events-none',
'disabled:opacity-50',
showIcon ? 'pr-4' : 'px-6',
'active:transform',
'active:translate-y-[1px]',
{
// Variant styles
'bg-primary text-primary-foreground hover:bg-primary/90': variant === 'default',
'bg-destructive text-destructive-foreground hover:bg-destructive/90':
variant === 'destructive',
'border border-input bg-background hover:bg-accent hover:text-accent-foreground':
variant === 'outline',
'bg-secondary text-secondary-foreground hover:bg-secondary/80': variant === 'secondary',
'hover:bg-accent hover:text-accent-foreground': variant === 'ghost',
'text-primary underline-offset-4 hover:underline': variant === 'link'
},
{
// Size styles
'h-10 px-4 py-2': size === 'default',
'h-9 rounded-md px-3': size === 'sm',
'h-11 rounded-md px-8': size === 'lg',
'h-10 w-10': size === 'icon'
},
className
);
</script>
{#if linkData}
<a
<Button
href={linkData.href}
target={linkData?.target ?? '_self'}
rel={isExternal ? 'noopener noreferrer' : undefined}
@@ -102,5 +67,5 @@
{/if}
</span>
{/if}
</a>
</Button>
{/if}

View File

@@ -116,22 +116,28 @@
expandedSubmenu = expandedSubmenu === itemName ? null : itemName;
}
const shouldReload = $derived($page.url.pathname.startsWith('/blog/'));
</script>
<nav class="relative z-[50] bg-primary py-3">
<nav class="bg-primary relative z-[50] py-3">
<div class="container px-4 md:mx-auto md:px-0">
<div class="relative flex items-center">
<div class="flex items-center">
{#if settings}
<a href="/">
<Button variant="ghost">
<Logo {settings} class="text-white" />
</Button>
</a>
<Button variant="ghost" href="/">
<Logo {settings} class="text-white" />
</Button>
{:else}
<div class="text-lg font-semibold text-white">Logo</div>
{/if}
<a
href="#main-content"
class="sr-only ml-2 focus:not-sr-only focus:bg-white focus:text-black focus:px-3 focus:py-1 focus:rounded focus:text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all"
>
Skip navigation
</a>
</div>
<div class="absolute left-1/2 hidden -translate-x-1/2 transform md:flex">
@@ -146,10 +152,12 @@
<NavigationMenuItem data-navigation-menu-item>
{#if item.url && !item.subitems}
<NavigationMenuLink
class={cn('relative z-20 text-white transition-colors hover:text-white/80')}
class={cn(
'relative z-20 text-white transition-colors hover:text-white/80 focus:bg-white/10 focus:outline-none focus:ring-2 focus:ring-white/20'
)}
href={item.url}
data-sveltekit-reload={item.url?.startsWith('/blog/') && shouldReload
? 'true'
? true
: undefined}
>
{item.name}
@@ -157,12 +165,13 @@
{:else if item.subitems}
{#if item.url}
<NavigationMenuTrigger
class="relative z-20 cursor-pointer px-2 text-white transition-colors hover:text-white/80"
class="relative z-20 cursor-pointer px-2 text-white transition-colors hover:text-white/80 focus:bg-white/10 focus:outline-none focus:ring-2 focus:ring-white/20 data-[state=open]:bg-white/10"
>
<NavigationMenuLink
href={item.url}
class="focus:outline-none"
data-sveltekit-reload={item.url?.startsWith('/blog/') && shouldReload
? 'true'
? true
: undefined}
>
{item.name}
@@ -170,20 +179,20 @@
</NavigationMenuTrigger>
{:else}
<NavigationMenuTrigger
class="relative z-20 cursor-pointer text-white transition-colors hover:text-white/80"
class="relative z-20 cursor-pointer text-white transition-colors hover:text-white/80 focus:bg-white/10 focus:outline-none focus:ring-2 focus:ring-white/20 data-[state=open]:bg-white/10"
>
{item.name}
</NavigationMenuTrigger>
{/if}
<NavigationMenuContent
class="absolute left-1/2 z-[50] mt-2 min-w-max -translate-x-1/2 rounded-md border border-white/20 bg-primary shadow-lg"
class="bg-primary absolute left-1/2 z-[50] mt-2 min-w-max -translate-x-1/2 space-y-1 rounded-md border border-white/20 p-2 shadow-lg"
>
{#each item.subitems as subitem}
<NavigationMenuLink
href={subitem.url}
class="block rounded-md px-4 py-2 text-white transition-colors hover:text-white/80"
class="block rounded-md px-4 py-2 text-white transition-colors hover:bg-white/10 hover:text-white/80 focus:bg-white/10 focus:text-white focus:outline-none focus:ring-2 focus:ring-white/20"
data-sveltekit-reload={subitem.url?.startsWith('/blog/') && shouldReload
? 'true'
? true
: undefined}
>
{subitem.name}
@@ -204,15 +213,13 @@
<MoreHorizontal size={24} />
</Button>
</SheetTrigger>
<SheetContent side="top" class="h-full w-full border-primary bg-primary text-white">
<SheetContent side="top" class="border-primary bg-primary h-full w-full text-white">
<SheetHeader class="border-b border-white/20 pb-4">
<SheetTitle class="flex items-center justify-start">
{#if settings}
<a href="/">
<Button variant="ghost" class="px-1">
<Logo {settings} class="text-white" />
</Button>
</a>
<Button variant="ghost" class="px-1" href="/">
<Logo {settings} class="text-white" />
</Button>
{:else}
<div class="text-lg font-semibold">Navigation</div>
{/if}
@@ -222,7 +229,7 @@
{#each items || [] as item, index}
{#if item.url && !item.subitems}
<div class="relative">
<a
<Button
href={item.url}
class={cn(
'mx-2 block rounded-md px-4 py-2 text-sm transition-colors hover:text-white/80',
@@ -230,22 +237,26 @@
)}
onclick={closeMobileMenu}
data-sveltekit-reload={item.url?.startsWith('/blog/') && shouldReload
? 'true'
? true
: undefined}
>
{item.name}
</a>
</Button>
</div>
{:else if item.subitems}
<div class="relative space-y-1">
{#if index === activeIndex}
<div
class="absolute top-0 bottom-0 left-0 w-1 rounded-r-md bg-white/20"
class="absolute bottom-0 left-0 top-0 w-1 rounded-r-md bg-white/20"
></div>
{/if}
<Button
class="flex w-full items-center justify-between rounded-md px-4 py-2 text-left text-sm font-medium transition-all duration-200 hover:text-white/80"
class="flex w-full items-center justify-between rounded-md px-4 py-2 text-left text-sm font-medium text-white transition-all duration-200 hover:text-white/80 focus:outline-none focus:ring-2 focus:ring-white/20"
onclick={() => toggleSubmenu(item.name)}
aria-expanded={expandedSubmenu === item.name}
aria-controls={`submenu-${item.name}`}
id={`submenu-trigger-${item.name}`}
type="button"
>
<span>{item.name}</span>
<div
@@ -261,30 +272,33 @@
<div
class="ml-4 space-y-1"
transition:slide={{ duration: 300, easing: quintOut }}
id={`submenu-${item.name}`}
role="group"
aria-labelledby={`submenu-trigger-${item.name}`}
>
{#if item.url}
<a
<Button
href={item.url}
class="block rounded-md px-6 py-2 text-sm text-white/80 transition-colors hover:text-white"
class="block rounded-md px-6 py-2 text-sm text-white/80 transition-colors hover:text-white focus:outline-none focus:ring-2 focus:ring-white/20"
onclick={closeMobileMenu}
data-sveltekit-reload={item.url?.startsWith('/blog/') && shouldReload
? 'true'
? true
: undefined}
>
{item.name}
</a>
</Button>
{/if}
{#each item.subitems as subitem}
<a
<Button
href={subitem.url}
class="block rounded-md px-6 py-2 text-sm text-white/80 transition-colors hover:text-white"
class="block rounded-md px-6 py-2 text-sm text-white/80 transition-colors hover:text-white focus:outline-none focus:ring-2 focus:ring-white/20"
onclick={closeMobileMenu}
data-sveltekit-reload={subitem.url?.startsWith('/blog/') && shouldReload
? 'true'
? true
: undefined}
>
{subitem.name}
</a>
</Button>
{/each}
</div>
{/if}