ui: overhaul files, kanban, calendar, settings, chat modules

- FileBrowser: modernize breadcrumbs, toolbar, list/grid items, empty states
- KanbanColumn: remove fixed height, border-based styling, compact header
- KanbanCard: cleaner border styling, smaller tags, compact footer
- Calendar: compact nav bar, border grid, today circle indicator, day view empty state
- DocumentViewer: remove bg-night rounded-[32px], border-b header pattern
- Settings tags: inline border/rounded-xl cards, icon action buttons
- Chat: create +layout.svelte with PageHeader, overhaul sidebar and main area
- Chat i18n: add nav_chat, chat_title, chat_subtitle keys (en + et)

svelte-check: 0 errors, vitest: 112/112 passed
This commit is contained in:
AlacrisDevs
2026-02-07 11:03:58 +02:00
parent 2913912cb8
commit 819d5b876a
10 changed files with 376 additions and 410 deletions

View File

@@ -0,0 +1,36 @@
<script lang="ts">
import type { Snippet } from "svelte";
import { navigating } from "$app/stores";
import { PageHeader, ContentSkeleton } from "$lib/components/ui";
import * as m from "$lib/paraglide/messages";
interface Props {
data: {
org: { id: string; name: string; slug: string };
};
children: Snippet;
}
let { data, children }: Props = $props();
const isNavigatingHere = $derived(
$navigating?.to?.url.pathname?.includes(`/${data.org.slug}/chat`),
);
</script>
<div class="flex flex-col h-full overflow-hidden">
<PageHeader
title={m.chat_title()}
subtitle={m.chat_subtitle()}
icon="chat"
iconColor="text-primary"
/>
{#if isNavigatingHere && !$navigating?.from?.url.pathname?.includes(`/${data.org.slug}/chat`)}
<ContentSkeleton variant="default" />
{:else}
<div class="flex-1 overflow-hidden">
{@render children()}
</div>
{/if}
</div>

View File

@@ -392,9 +392,9 @@
<!-- Matrix Login Modal -->
{#if showMatrixLogin}
<div class="h-full flex items-center justify-center">
<div class="bg-night rounded-[32px] p-8 w-full max-w-md">
<h2 class="font-heading text-h3 text-white mb-2">Connect to Chat</h2>
<p class="text-light/50 text-body mb-6">
<div class="bg-dark/30 border border-light/5 rounded-xl p-8 w-full max-w-md">
<h2 class="font-heading text-body text-white mb-1">Connect to Chat</h2>
<p class="text-body-sm text-light/50 mb-6">
Enter your Matrix credentials to enable messaging.
</p>
@@ -410,12 +410,12 @@
placeholder="@user:matrix.org"
/>
<div>
<label class="block text-body-sm font-body text-light mb-1">Password</label>
<label class="block text-body-sm font-body text-light/60 mb-1">Password</label>
<input
type="password"
bind:value={matrixPassword}
placeholder="Password"
class="w-full bg-dark border border-light/10 rounded-2xl px-4 py-3 text-white font-body text-body placeholder:text-light/30 focus:outline-none focus:border-primary"
class="w-full bg-dark border border-light/10 rounded-xl px-3 py-2 text-white font-body text-body-sm placeholder:text-light/30 focus:outline-none focus:border-primary"
onkeydown={(e) => {
if (e.key === "Enter") handleMatrixLogin();
}}
@@ -438,9 +438,9 @@
<div class="h-full flex items-center justify-center">
<div class="text-center">
<div
class="animate-spin w-12 h-12 border-4 border-primary border-t-transparent rounded-full mx-auto mb-4"
class="animate-spin w-10 h-10 border-3 border-primary border-t-transparent rounded-full mx-auto mb-4"
></div>
<p class="text-light/50">
<p class="text-body-sm text-light/40">
{#if isInitializing}
Connecting to Matrix...
{:else if $syncState === "CATCHUP"}
@@ -460,56 +460,50 @@
{:else if matrixClient}
<MatrixProvider client={matrixClient}>
{#snippet children()}
<div class="h-full flex gap-2 min-h-0">
<div class="h-full flex min-h-0">
<!-- Chat Sidebar -->
<aside class="w-56 bg-night rounded-[32px] flex flex-col overflow-hidden shrink-0">
<header class="px-3 py-5">
<div class="flex items-center gap-2">
<span class="material-symbols-rounded text-light" style="font-size: 20px;">chat</span>
<span class="flex-1 font-heading text-light text-base">Messages</span>
<button
class="text-light hover:text-primary transition-colors"
onclick={() => (showStartDMModal = true)}
title="New message"
>
<span class="material-symbols-rounded" style="font-size: 20px;">add</span>
</button>
</div>
</header>
<aside class="w-56 border-r border-light/5 flex flex-col overflow-hidden shrink-0">
<div class="flex items-center gap-2 px-3 py-2.5 border-b border-light/5">
<span class="flex-1 font-heading text-body-sm text-white">Messages</span>
<button
class="p-1 text-light/40 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
onclick={() => (showStartDMModal = true)}
title="New message"
>
<span class="material-symbols-rounded" style="font-size: 18px;">add</span>
</button>
</div>
<!-- Room search -->
<div class="px-3 pb-2">
<div class="px-2 py-2">
<div class="relative">
<span
class="material-symbols-rounded absolute left-3 top-1/2 -translate-y-1/2 text-light/40"
class="material-symbols-rounded absolute left-2.5 top-1/2 -translate-y-1/2 text-light/30"
style="font-size: 16px;"
>search</span>
<input
type="text"
bind:value={roomSearchQuery}
placeholder="Search rooms..."
class="w-full pl-9 pr-3 py-2 bg-dark text-light text-sm rounded-lg border border-light/10 placeholder:text-light/30 focus:outline-none focus:border-primary"
placeholder="Search..."
class="w-full pl-8 pr-3 py-1.5 bg-dark/50 text-white text-[12px] rounded-lg border border-light/5 placeholder:text-light/30 focus:outline-none focus:border-primary"
/>
</div>
</div>
<!-- Room list (sectioned) -->
<nav class="flex-1 overflow-y-auto px-2 pb-2">
<nav class="flex-1 overflow-y-auto px-1.5 pb-2">
{#if allRooms.length === 0}
<p class="text-light/40 text-sm text-center py-8">
<p class="text-light/30 text-[12px] text-center py-8">
{roomSearchQuery ? "No matching rooms" : "No rooms yet"}
</p>
{:else}
<!-- Org / Space Rooms -->
{#if filteredOrgRooms.length > 0}
<div class="mb-2">
<div class="mb-1.5">
<div class="flex items-center justify-between px-2 py-1">
<span class="text-xs font-semibold text-light/40 uppercase tracking-wider">
<span class="material-symbols-rounded align-middle" style="font-size: 14px;">workspaces</span>
Organization
</span>
<span class="text-[10px] font-body text-light/30 uppercase tracking-wider">Organization</span>
<button
class="w-5 h-5 flex items-center justify-center text-light/40 hover:text-light hover:bg-light/10 rounded transition-colors"
class="p-0.5 text-light/30 hover:text-white hover:bg-dark/50 rounded transition-colors"
onclick={() => (showCreateRoomModal = true)}
title="Create room"
>
@@ -520,16 +514,16 @@
{#each filteredOrgRooms as room (room.roomId)}
<li>
<button
class="w-full flex items-center gap-2 pl-1 pr-2 py-1 rounded-[50px] transition-colors text-left
{$selectedRoomId === room.roomId ? 'bg-primary/20' : 'hover:bg-light/5'}"
class="w-full flex items-center gap-2 px-2 py-1.5 rounded-lg transition-colors text-left
{$selectedRoomId === room.roomId ? 'bg-primary/10 text-white' : 'text-light/60 hover:bg-dark/50 hover:text-white'}"
onclick={() => handleRoomSelect(room.roomId)}
>
<Avatar src={room.avatarUrl} name={room.name} size="xs" />
<div class="flex-1 min-w-0">
<span class="font-bold text-sm text-light truncate block">{room.name}</span>
<span class="text-[12px] font-body truncate block">{room.name}</span>
</div>
{#if room.unreadCount > 0}
<span class="bg-primary text-white text-xs px-1.5 py-0.5 rounded-full min-w-[18px] text-center">
<span class="bg-primary text-background text-[10px] px-1.5 py-0.5 rounded-full min-w-[16px] text-center font-bold">
{room.unreadCount > 99 ? "99+" : room.unreadCount}
</span>
{/if}
@@ -542,14 +536,11 @@
<!-- Direct Messages -->
{#if filteredDmRooms.length > 0}
<div class="mb-2">
<div class="mb-1.5">
<div class="flex items-center justify-between px-2 py-1">
<span class="text-xs font-semibold text-light/40 uppercase tracking-wider">
<span class="material-symbols-rounded align-middle" style="font-size: 14px;">chat_bubble</span>
Direct Messages
</span>
<span class="text-[10px] font-body text-light/30 uppercase tracking-wider">Direct Messages</span>
<button
class="w-5 h-5 flex items-center justify-center text-light/40 hover:text-light hover:bg-light/10 rounded transition-colors"
class="p-0.5 text-light/30 hover:text-white hover:bg-dark/50 rounded transition-colors"
onclick={() => (showStartDMModal = true)}
title="New DM"
>
@@ -560,16 +551,16 @@
{#each filteredDmRooms as room (room.roomId)}
<li>
<button
class="w-full flex items-center gap-2 pl-1 pr-2 py-1 rounded-[50px] transition-colors text-left
{$selectedRoomId === room.roomId ? 'bg-primary/20' : 'hover:bg-light/5'}"
class="w-full flex items-center gap-2 px-2 py-1.5 rounded-lg transition-colors text-left
{$selectedRoomId === room.roomId ? 'bg-primary/10 text-white' : 'text-light/60 hover:bg-dark/50 hover:text-white'}"
onclick={() => handleRoomSelect(room.roomId)}
>
<Avatar src={room.avatarUrl} name={room.name} size="xs" />
<div class="flex-1 min-w-0">
<span class="font-bold text-sm text-light truncate block">{room.name}</span>
<span class="text-[12px] font-body truncate block">{room.name}</span>
</div>
{#if room.unreadCount > 0}
<span class="bg-primary text-white text-xs px-1.5 py-0.5 rounded-full min-w-[18px] text-center">
<span class="bg-primary text-background text-[10px] px-1.5 py-0.5 rounded-full min-w-[16px] text-center font-bold">
{room.unreadCount > 99 ? "99+" : room.unreadCount}
</span>
{/if}
@@ -582,14 +573,11 @@
<!-- Other Rooms (not in a space, not DMs) -->
{#if filteredOtherRooms.length > 0}
<div class="mb-2">
<div class="mb-1.5">
<div class="flex items-center justify-between px-2 py-1">
<span class="text-xs font-semibold text-light/40 uppercase tracking-wider">
<span class="material-symbols-rounded align-middle" style="font-size: 14px;">tag</span>
Rooms
</span>
<span class="text-[10px] font-body text-light/30 uppercase tracking-wider">Rooms</span>
<button
class="w-5 h-5 flex items-center justify-center text-light/40 hover:text-light hover:bg-light/10 rounded transition-colors"
class="p-0.5 text-light/30 hover:text-white hover:bg-dark/50 rounded transition-colors"
onclick={() => (showCreateRoomModal = true)}
title="Create room"
>
@@ -600,16 +588,16 @@
{#each filteredOtherRooms as room (room.roomId)}
<li>
<button
class="w-full flex items-center gap-2 pl-1 pr-2 py-1 rounded-[50px] transition-colors text-left
{$selectedRoomId === room.roomId ? 'bg-primary/20' : 'hover:bg-light/5'}"
class="w-full flex items-center gap-2 px-2 py-1.5 rounded-lg transition-colors text-left
{$selectedRoomId === room.roomId ? 'bg-primary/10 text-white' : 'text-light/60 hover:bg-dark/50 hover:text-white'}"
onclick={() => handleRoomSelect(room.roomId)}
>
<Avatar src={room.avatarUrl} name={room.name} size="xs" />
<div class="flex-1 min-w-0">
<span class="font-bold text-sm text-light truncate block">{room.name}</span>
<span class="text-[12px] font-body truncate block">{room.name}</span>
</div>
{#if room.unreadCount > 0}
<span class="bg-primary text-white text-xs px-1.5 py-0.5 rounded-full min-w-[18px] text-center">
<span class="bg-primary text-background text-[10px] px-1.5 py-0.5 rounded-full min-w-[16px] text-center font-bold">
{room.unreadCount > 99 ? "99+" : room.unreadCount}
</span>
{/if}
@@ -623,76 +611,76 @@
</nav>
<!-- User footer -->
<footer class="p-3 border-t border-light/10">
<div class="px-2 py-2 border-t border-light/5">
<div class="flex items-center gap-2">
<Avatar name={$auth.userId || "User"} size="xs" status="online" />
<div class="flex-1 min-w-0">
<p class="text-xs font-medium text-light truncate">{$auth.userId}</p>
<p class="text-[11px] text-light/50 truncate">{$auth.userId}</p>
</div>
<button
class="text-light/50 hover:text-light p-1 rounded-lg hover:bg-light/10 transition-colors"
class="p-1 text-light/30 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
onclick={handleLogout}
title="Disconnect chat"
>
<span class="material-symbols-rounded" style="font-size: 18px;">logout</span>
<span class="material-symbols-rounded" style="font-size: 16px;">logout</span>
</button>
</div>
</footer>
</div>
</aside>
<!-- Main Chat Area -->
<main class="flex-1 flex flex-col min-h-0 overflow-hidden bg-night rounded-[32px]">
<main class="flex-1 flex flex-col min-h-0 overflow-hidden">
{#if $selectedRoomId}
<div class="flex-1 flex flex-col min-h-0 overflow-hidden">
<!-- Room Header -->
<header class="h-14 px-5 flex items-center border-b border-light/10">
<div class="px-4 py-2.5 flex items-center border-b border-light/5 shrink-0">
{#each $roomSummaries.filter((r) => r.roomId === $selectedRoomId) as room}
<div class="flex items-center gap-3 w-full">
<div class="flex items-center gap-2.5 w-full">
<Avatar src={room.avatarUrl} name={room.name} size="sm" />
<div class="flex-1 min-w-0">
<h2 class="font-heading text-h5 text-light truncate">{room.name}</h2>
<p class="text-xs text-light/50">
<h2 class="font-heading text-body-sm text-white truncate">{room.name}</h2>
<p class="text-[11px] text-light/40">
{room.memberCount} members{room.isEncrypted ? " · Encrypted" : ""}
</p>
</div>
<button
class="p-2 text-light/50 hover:text-light hover:bg-light/10 rounded-lg transition-colors"
class="p-1.5 text-light/40 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
onclick={() => (showMessageSearch = !showMessageSearch)}
title="Search messages"
>
<span class="material-symbols-rounded" style="font-size: 20px;">search</span>
<span class="material-symbols-rounded" style="font-size: 18px;">search</span>
</button>
<button
class="p-2 text-light/50 hover:text-light hover:bg-light/10 rounded-lg transition-colors"
class="p-1.5 text-light/40 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
onclick={() => (showRoomInfo = !showRoomInfo)}
title="Room info"
>
<span class="material-symbols-rounded" style="font-size: 20px;">info</span>
<span class="material-symbols-rounded" style="font-size: 18px;">info</span>
</button>
<button
class="p-2 text-light/50 hover:text-light hover:bg-light/10 rounded-lg transition-colors"
class="p-1.5 text-light/40 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
onclick={() => (showMemberList = !showMemberList)}
title="Members"
>
<span class="material-symbols-rounded" style="font-size: 20px;">group</span>
<span class="material-symbols-rounded" style="font-size: 18px;">group</span>
</button>
</div>
{/each}
</header>
</div>
<!-- Message search panel -->
{#if showMessageSearch}
<div class="border-b border-light/10 p-3 bg-dark/50">
<div class="border-b border-light/5 px-4 py-2.5">
<div class="relative">
<span class="material-symbols-rounded absolute left-3 top-1/2 -translate-y-1/2 text-light/40" style="font-size: 16px;">search</span>
<span class="material-symbols-rounded absolute left-2.5 top-1/2 -translate-y-1/2 text-light/30" style="font-size: 16px;">search</span>
<input
type="text"
bind:value={messageSearchQuery}
placeholder="Search messages in this room..."
class="w-full pl-9 pr-8 py-2 bg-night text-light text-sm rounded-lg border border-light/10 placeholder:text-light/30 focus:outline-none focus:border-primary"
placeholder="Search messages..."
class="w-full pl-8 pr-8 py-1.5 bg-dark/50 text-white text-[12px] rounded-lg border border-light/5 placeholder:text-light/30 focus:outline-none focus:border-primary"
/>
<button
class="absolute right-2 top-1/2 -translate-y-1/2 text-light/40 hover:text-light"
class="absolute right-2 top-1/2 -translate-y-1/2 text-light/30 hover:text-white"
onclick={() => { showMessageSearch = false; messageSearchQuery = ""; }}
>
<span class="material-symbols-rounded" style="font-size: 16px;">close</span>
@@ -700,22 +688,22 @@
</div>
{#if messageSearchQuery && messageSearchResults.length > 0}
<div class="mt-2 max-h-48 overflow-y-auto">
<p class="text-xs text-light/40 mb-2">
<p class="text-[11px] text-light/30 mb-1.5">
{messageSearchResults.length} result{messageSearchResults.length !== 1 ? "s" : ""}
</p>
{#each messageSearchResults.slice(0, 20) as result}
<button
class="w-full text-left px-3 py-2 hover:bg-light/5 rounded transition-colors"
class="w-full text-left px-3 py-1.5 hover:bg-dark/50 rounded-lg transition-colors"
onclick={() => { showMessageSearch = false; messageSearchQuery = ""; }}
>
<p class="text-xs text-primary">{result.senderName}</p>
<p class="text-sm text-light truncate">{result.content}</p>
<p class="text-xs text-light/30">{new Date(result.timestamp).toLocaleString()}</p>
<p class="text-[11px] text-primary">{result.senderName}</p>
<p class="text-body-sm text-white truncate">{result.content}</p>
<p class="text-[10px] text-light/30">{new Date(result.timestamp).toLocaleString()}</p>
</button>
{/each}
</div>
{:else if messageSearchQuery}
<p class="text-sm text-light/40 mt-2">No results found</p>
<p class="text-body-sm text-light/30 mt-2">No results found</p>
{/if}
</div>
{/if}
@@ -729,11 +717,11 @@
role="region"
>
{#if isDraggingFile}
<div class="absolute inset-0 z-50 bg-primary/20 border-2 border-dashed border-primary rounded-lg flex items-center justify-center backdrop-blur-sm">
<div class="absolute inset-0 z-50 bg-primary/10 border-2 border-dashed border-primary rounded-xl flex items-center justify-center backdrop-blur-sm">
<div class="text-center">
<span class="material-symbols-rounded text-primary mb-4 block" style="font-size: 64px;">upload_file</span>
<p class="text-xl font-semibold text-primary">Drop to upload</p>
<p class="text-sm text-light/60 mt-1">Release to send file</p>
<span class="material-symbols-rounded text-primary mb-3 block" style="font-size: 48px; font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 48;">upload_file</span>
<p class="text-body-sm font-heading text-primary">Drop to upload</p>
<p class="text-[12px] text-light/40 mt-0.5">Release to send file</p>
</div>
</div>
{/if}
@@ -764,7 +752,7 @@
<!-- Side panels -->
{#if showRoomInfo}
{#each $roomSummaries.filter((r) => r.roomId === $selectedRoomId) as currentRoom}
<aside class="w-72 border-l border-light/10 bg-dark/30">
<aside class="w-72 border-l border-light/5">
<RoomInfoPanel
room={currentRoom}
members={currentMembers}
@@ -773,7 +761,7 @@
</aside>
{/each}
{:else if showMemberList}
<aside class="w-64 border-l border-light/10 bg-dark/30">
<aside class="w-64 border-l border-light/5">
<MemberList members={currentMembers} />
</aside>
{/if}
@@ -782,10 +770,10 @@
{:else}
<!-- No room selected -->
<div class="flex-1 flex items-center justify-center">
<div class="text-center text-light/40">
<span class="material-symbols-rounded mb-4 block" style="font-size: 64px; font-variation-settings: 'FILL' 0, 'wght' 300;">chat</span>
<h2 class="font-heading text-h4 text-light/50 mb-2">Select a room</h2>
<p class="text-body text-light/30">Choose a conversation to start chatting</p>
<div class="text-center text-light/30">
<span class="material-symbols-rounded mb-3 block" style="font-size: 48px; font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 48;">chat</span>
<p class="text-body-sm text-light/40 mb-1">Select a room</p>
<p class="text-[12px] text-light/20">Choose a conversation to start chatting</p>
</div>
</div>
{/if}

View File

@@ -322,74 +322,73 @@
<!-- Tags Tab -->
{#if activeTab === "tags"}
<div class="space-y-6 max-w-2xl">
<div class="space-y-4 max-w-2xl">
<div class="flex items-center justify-between">
<div>
<h2 class="text-lg font-semibold text-light">
<h2 class="text-body font-heading text-white">
{m.settings_tags_title()}
</h2>
<p class="text-sm text-light/50">
<p class="text-body-sm text-light/50 mt-0.5">
{m.settings_tags_desc()}
</p>
</div>
<Button onclick={() => openTagModal()} icon="add">
<Button size="sm" onclick={() => openTagModal()} icon="add">
{m.settings_tags_create()}
</Button>
</div>
{#if orgTags.length === 0 && tagsLoaded}
<Card>
<div class="p-8 text-center">
<span
class="material-symbols-rounded text-light/20 mb-4 block"
style="font-size: 48px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 48;"
>label</span
>
<p class="text-light/50">{m.settings_tags_empty()}</p>
</div>
</Card>
<div class="bg-dark/30 border border-light/5 rounded-xl p-8 text-center">
<span
class="material-symbols-rounded text-light/20 mb-3 block"
style="font-size: 48px; font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 48;"
>label</span
>
<p class="text-body-sm text-light/40">{m.settings_tags_empty()}</p>
</div>
{:else}
<div class="grid gap-3">
<div class="flex flex-col gap-2">
{#each orgTags as tag}
<Card>
<div class="flex items-center justify-between p-4">
<div class="flex items-center gap-3">
<div
class="w-8 h-8 rounded-lg flex items-center justify-center"
style="background-color: {tag.color ||
'#00A3E0'}"
<div class="flex items-center justify-between px-4 py-3 bg-dark/30 border border-light/5 rounded-xl hover:border-light/10 transition-colors">
<div class="flex items-center gap-3">
<div
class="w-7 h-7 rounded-lg flex items-center justify-center shrink-0"
style="background-color: {tag.color || '#00A3E0'}"
>
<span
class="material-symbols-rounded text-night"
style="font-size: 16px; font-variation-settings: 'FILL' 0, 'wght' 600, 'GRAD' 0, 'opsz' 16;"
>label</span
>
<span
class="material-symbols-rounded text-night"
style="font-size: 18px; font-variation-settings: 'FILL' 0, 'wght' 600, 'GRAD' 0, 'opsz' 18;"
>label</span
>
</div>
<div>
<p class="text-light font-medium">
{tag.name}
</p>
<p class="text-xs text-light/40">
{tag.color || "#00A3E0"}
</p>
</div>
</div>
<div class="flex items-center gap-2">
<Button
variant="tertiary"
size="sm"
onclick={() => openTagModal(tag)}
>Edit</Button
>
<Button
variant="danger"
size="sm"
onclick={() => deleteOrgTag(tag)}
>Delete</Button
>
<div>
<p class="text-body-sm text-white font-medium">
{tag.name}
</p>
<p class="text-[11px] text-light/30">
{tag.color || "#00A3E0"}
</p>
</div>
</div>
</Card>
<div class="flex items-center gap-1.5">
<button
type="button"
class="p-1.5 text-light/40 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
onclick={() => openTagModal(tag)}
title="Edit"
>
<span class="material-symbols-rounded" style="font-size: 18px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 18;">edit</span>
</button>
<button
type="button"
class="p-1.5 text-light/40 hover:text-error hover:bg-error/10 rounded-lg transition-colors"
onclick={() => deleteOrgTag(tag)}
title="Delete"
>
<span class="material-symbols-rounded" style="font-size: 18px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 18;">delete</span>
</button>
</div>
</div>
{/each}
</div>
{/if}