lernschiff/resources/views/livewire/notifications/index.blade.php

87 lines
4.8 KiB
PHP

@php
$colorMap = [
'primary' => ['bg' => 'bg-primary-soft', 'ink' => 'text-primary-ink'],
'rose' => ['bg' => 'bg-rose-soft', 'ink' => 'text-rose-ink'],
'violet' => ['bg' => 'bg-violet-soft', 'ink' => 'text-violet-ink'],
'green' => ['bg' => 'bg-green-soft', 'ink' => 'text-green-ink'],
'amber' => ['bg' => 'bg-amber-soft', 'ink' => 'text-amber-ink'],
];
@endphp
<div class="flex flex-col gap-6">
<header class="flex justify-between items-end gap-6">
<div>
<div class="text-[11px] uppercase tracking-[0.14em] text-ink-3 font-semibold mb-1.5">Inbox</div>
<h1 class="text-[28px] leading-tight font-extrabold tracking-tight text-ink-1">Mitteilungen</h1>
<p class="text-sm text-ink-2 mt-2 max-w-xl leading-relaxed">Nachrichten von Lehrer:innen, Erinnerungen und Lernschiff-Updates.</p>
</div>
<x-btn wire:click="markAllRead">
<x-heroicon-o-check class="w-3.5 h-3.5" />
Alle als gelesen
</x-btn>
</header>
<div class="flex gap-2" wire:key="notif-filters">
@foreach(['all' => 'Alle', 'unread' => 'Ungelesen'] as $key => $label)
<button
type="button"
wire:click="setFilter('{{ $key }}')"
wire:loading.attr="disabled"
class="inline-flex items-center gap-2 px-3 py-1.5 rounded-full border text-xs font-semibold transition-all cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1 {{ $filter === $key ? 'bg-ink-1 text-bg-base border-ink-1' : 'bg-bg-soft text-ink-2 border-line hover:bg-bg-tint' }}"
data-testid="notif-filter-{{ $key }}"
@if($filter === $key) aria-current="page" @endif
>
{{ $label }} <span class="font-mono tabular-nums">({{ $this->counts[$key] }})</span>
</button>
@endforeach
</div>
{{-- Skeleton with bg-line bars on bg-bg-tint container --}}
<div wire:loading.flex wire:target="setFilter,markAllRead,markRead" class="hidden flex-col bg-bg-soft border border-line rounded-xl shadow-sm" data-testid="notif-skeleton">
@for($i = 0; $i < 4; $i++)
<div class="grid grid-cols-[44px_1fr_auto] gap-4 items-start p-4 border-t border-line first:border-t-0 animate-pulse">
<div class="w-10 h-10 rounded-lg bg-line"></div>
<div class="flex flex-col gap-2 flex-1">
<div class="h-3 bg-line rounded w-2/5"></div>
<div class="h-2 bg-line rounded w-3/4"></div>
</div>
<div class="h-2 bg-line rounded w-16"></div>
</div>
@endfor
</div>
<x-card class="shadow-sm p-0 overflow-hidden" wire:loading.remove wire:target="setFilter,markAllRead,markRead">
@if(empty($this->filteredNotifications))
<div class="py-8 text-center text-sm text-ink-3">Keine Mitteilungen.</div>
@else
<div class="flex flex-col divide-y divide-line">
@foreach($this->filteredNotifications as $n)
@php $c = $colorMap[$n['color']]; @endphp
<button
type="button"
wire:key="notif-{{ $n['key'] }}"
wire:click="markRead('{{ $n['key'] }}'); $dispatch('openModal', { component: 'notifications.modals.detail', arguments: { notification: {{ \Illuminate\Support\Js::from($n) }} } })"
class="text-left grid grid-cols-[44px_1fr_auto] gap-4 items-start p-4 transition-colors hover:bg-bg-tint cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1"
>
<div class="relative">
<div class="w-10 h-10 rounded-lg {{ $c['bg'] }} {{ $c['ink'] }} grid place-items-center">
<x-dynamic-component :component="'heroicon-o-' . $n['icon']" class="w-5 h-5" />
</div>
@if(! $n['read'])
<span class="absolute -top-0.5 -right-0.5 w-2.5 h-2.5 rounded-full bg-primary ring-2 ring-bg-soft"></span>
@endif
</div>
<div class="min-w-0">
<div class="font-semibold text-sm text-ink-1 truncate mb-0.5">{{ $n['title'] }}</div>
<p class="text-xs text-ink-2 leading-relaxed line-clamp-2">{{ $n['body'] }}</p>
</div>
<div class="text-[11px] text-ink-3 font-medium whitespace-nowrap">{{ $n['time'] }}</div>
</button>
@endforeach
</div>
@endif
</x-card>
</div>