fix(ui): implement UI review findings — a11y, IA, and consistency fixes
Fixes the reviewed gaps: keyboard-inaccessible delete controls (SessionRail, Entities row), case-sensitive entity filter, two competing entity-detail navigation patterns (standardize on EntitySheet), non-clickable Overview KPI cards, a bare button bypassing the shared Button component, inconsistent blur-only vs live filtering, and an unenforced sanitization assumption on search snippet HTML (now using the already-present dompurify dependency). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
<script lang="ts">
|
||||
import DOMPurify from 'dompurify'
|
||||
import { searchKnowledge, fetchRecentKnowledge, type KnowledgeHit, type RecentKnowledge, type KnowledgeItem } from '$lib/api'
|
||||
import * as Card from '$lib/components/ui/card'
|
||||
import { Badge } from '$lib/components/ui/badge'
|
||||
import { Input } from '$lib/components/ui/input'
|
||||
import { Button } from '$lib/components/ui/button'
|
||||
import { ScrollArea } from '$lib/components/ui/scroll-area'
|
||||
import EntitySheet from '$lib/components/EntitySheet.svelte'
|
||||
import SearchIcon from '@lucide/svelte/icons/search'
|
||||
import SparklesIcon from '@lucide/svelte/icons/sparkles'
|
||||
import BotIcon from '@lucide/svelte/icons/bot'
|
||||
@@ -54,8 +56,12 @@
|
||||
return `${Math.floor(s / 86400)}d ago`
|
||||
}
|
||||
|
||||
let sheetOpen = $state(false)
|
||||
let selectedSlug = $state<string | null>(null)
|
||||
|
||||
function openEntity(slug: string) {
|
||||
location.hash = '#/entity/' + encodeURIComponent(slug)
|
||||
selectedSlug = slug
|
||||
sheetOpen = true
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -117,8 +123,10 @@
|
||||
<Badge variant={typeVariant(hit.type)}>{hit.type}</Badge>
|
||||
</div>
|
||||
{#if hit.snippet}
|
||||
<!-- eslint-disable-next-line svelte/no-at-html-tags — server-sanitized ts_headline -->
|
||||
<Card.Description class="text-xs">{@html hit.snippet}</Card.Description>
|
||||
<!-- eslint-disable-next-line svelte/no-at-html-tags — sanitized below, ts_headline only ever emits <b> -->
|
||||
<Card.Description class="text-xs"
|
||||
>{@html DOMPurify.sanitize(hit.snippet, { ALLOWED_TAGS: ['b'], ALLOWED_ATTR: [] })}</Card.Description
|
||||
>
|
||||
{/if}
|
||||
{#if hit.linked_entities?.length}
|
||||
<div class="mt-1 flex flex-wrap gap-1">
|
||||
@@ -174,3 +182,5 @@
|
||||
</ScrollArea>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<EntitySheet slug={selectedSlug} bind:open={sheetOpen} />
|
||||
|
||||
Reference in New Issue
Block a user