fix: a11y — QuickCapture label/role/aria-live/spinner, LogEntryRow expand button
This commit is contained in:
parent
f361c86019
commit
04f26e4074
2 changed files with 24 additions and 13 deletions
|
|
@ -1,8 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="border-b border-surface-border px-4 py-3 hover:bg-surface-raised transition-colors"
|
class="border-b border-surface-border px-4 py-3 hover:bg-surface-raised transition-colors"
|
||||||
:class="{ 'border-l-2 border-l-sev-error': isHighSeverity, 'cursor-pointer': isLong }"
|
:class="{ 'border-l-2 border-l-sev-error': isHighSeverity }"
|
||||||
@click="isLong && (expanded = !expanded)"
|
|
||||||
>
|
>
|
||||||
<div class="flex items-start gap-3">
|
<div class="flex items-start gap-3">
|
||||||
<SeverityBadge :severity="entry.severity" class="mt-0.5 shrink-0 w-16 text-center" />
|
<SeverityBadge :severity="entry.severity" class="mt-0.5 shrink-0 w-16 text-center" />
|
||||||
|
|
@ -18,14 +17,20 @@
|
||||||
<span v-if="entry.repeat_count > 1" class="text-text-dim text-xs">×{{ entry.repeat_count }}</span>
|
<span v-if="entry.repeat_count > 1" class="text-text-dim text-xs">×{{ entry.repeat_count }}</span>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
|
:id="`entry-text-${entry.entry_id}`"
|
||||||
class="text-text-primary text-sm whitespace-pre-wrap break-words leading-relaxed"
|
class="text-text-primary text-sm whitespace-pre-wrap break-words leading-relaxed"
|
||||||
:class="{ 'line-clamp-3': isLong && !expanded }"
|
:class="{ 'line-clamp-3': isLong && !expanded }"
|
||||||
>{{ entry.text }}</p>
|
>{{ entry.text }}</p>
|
||||||
<button
|
<button
|
||||||
v-if="isLong"
|
v-if="isLong"
|
||||||
|
@click="expanded = !expanded"
|
||||||
|
:aria-expanded="expanded"
|
||||||
|
:aria-controls="`entry-text-${entry.entry_id}`"
|
||||||
class="mt-1 text-text-dim hover:text-accent text-xs transition-colors"
|
class="mt-1 text-text-dim hover:text-accent text-xs transition-colors"
|
||||||
@click.stop="expanded = !expanded"
|
>
|
||||||
>{{ expanded ? '▲ collapse' : '▼ expand' }}</button>
|
<span aria-hidden="true">{{ expanded ? '▲' : '▼' }}</span>
|
||||||
|
{{ expanded ? 'Collapse entry' : 'Expand entry' }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
<div>
|
<div>
|
||||||
<!-- Input row -->
|
<!-- Input row -->
|
||||||
<div class="flex gap-3 mb-6">
|
<div class="flex gap-3 mb-6">
|
||||||
|
<label for="qc-query" class="sr-only">Describe the symptom or issue</label>
|
||||||
<input
|
<input
|
||||||
|
id="qc-query"
|
||||||
v-model="query"
|
v-model="query"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder='e.g. "plex stopped playing audio around 2pm"'
|
placeholder='e.g. "plex stopped playing audio around 2pm"'
|
||||||
|
|
@ -14,19 +16,21 @@
|
||||||
@click="run()"
|
@click="run()"
|
||||||
class="px-6 py-2.5 rounded bg-accent text-white text-sm font-semibold hover:bg-blue-400 transition-colors disabled:opacity-50"
|
class="px-6 py-2.5 rounded bg-accent text-white text-sm font-semibold hover:bg-blue-400 transition-colors disabled:opacity-50"
|
||||||
>
|
>
|
||||||
<span v-if="loading">Go</span>
|
<span v-if="loading">Searching…</span>
|
||||||
<span v-else>Go</span>
|
<span v-else>Search logs</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pipeline status -->
|
<!-- Pipeline status -->
|
||||||
|
<div aria-live="polite" aria-atomic="true">
|
||||||
<div
|
<div
|
||||||
v-if="loading && statusMsg"
|
v-if="loading && statusMsg"
|
||||||
class="flex items-center gap-2 mb-3 text-xs text-text-dim"
|
class="flex items-center gap-2 mb-3 text-xs text-text-dim"
|
||||||
>
|
>
|
||||||
<span class="inline-block w-3 h-3 rounded-full border-2 border-accent border-t-transparent animate-spin" />
|
<span class="inline-block w-3 h-3 rounded-full border-2 border-accent border-t-transparent animate-spin motion-reduce:animate-none" aria-hidden="true" />
|
||||||
<span>{{ statusMsg }}</span>
|
<span>{{ statusMsg }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Source scope badge -->
|
<!-- Source scope badge -->
|
||||||
<div v-if="sourceScope" class="flex items-center gap-2 mb-4 text-xs">
|
<div v-if="sourceScope" class="flex items-center gap-2 mb-4 text-xs">
|
||||||
|
|
@ -36,11 +40,12 @@
|
||||||
@click="sourceScope = null"
|
@click="sourceScope = null"
|
||||||
class="text-text-dim hover:text-text-primary ml-1"
|
class="text-text-dim hover:text-text-primary ml-1"
|
||||||
title="Clear scope"
|
title="Clear scope"
|
||||||
|
aria-label="Clear source scope filter"
|
||||||
>✕</button>
|
>✕</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error -->
|
<!-- Error -->
|
||||||
<div v-if="error" class="mb-4 p-3 rounded bg-red-900/30 border border-red-700/40 text-sev-error text-sm">
|
<div v-if="error" role="alert" class="mb-4 p-3 rounded bg-red-900/30 border border-red-700/40 text-sev-error text-sm">
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -61,6 +66,7 @@
|
||||||
v-for="(count, sev) in nonZeroSeverity"
|
v-for="(count, sev) in nonZeroSeverity"
|
||||||
:key="String(sev)"
|
:key="String(sev)"
|
||||||
@click="severityFilter = severityFilter === String(sev) ? null : String(sev)"
|
@click="severityFilter = severityFilter === String(sev) ? null : String(sev)"
|
||||||
|
:aria-pressed="severityFilter === String(sev)"
|
||||||
:class="[
|
:class="[
|
||||||
'px-2 py-0.5 rounded text-xs font-medium border transition-colors',
|
'px-2 py-0.5 rounded text-xs font-medium border transition-colors',
|
||||||
severityFilter === String(sev)
|
severityFilter === String(sev)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue