mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-15 21:39:39 +02:00
feat(workbench): interactive scope badge — click to clear, tooltip lists tags
The Funnel badge on a scoped scene pill is now a real button:
- Click clears the scene's scopeTagIds in one interaction instead of
sending the user through the TagSelector in SceneHeader.
- Tooltip shows the active scope tag names ("Bereich: Deep Work,
Urlaub — klicken zum Aufheben") so users see which filter is on
without opening the scene header.
- Keyboard-accessible via Enter/Space; stopPropagation prevents the
surrounding scene-pill button from also firing scene-select.
Tag names are resolved via the existing useAllTags liveQuery — no
extra Dexie round-trip per render.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
85537cb92a
commit
0f4535c48c
1 changed files with 51 additions and 1 deletions
|
|
@ -8,6 +8,8 @@
|
|||
import type { CarouselPage } from '$lib/components/page-carousel/types';
|
||||
import type { WorkbenchScene } from '$lib/types/workbench-scenes';
|
||||
import { useAgents } from '$lib/data/ai/agents/queries';
|
||||
import { useAllTags } from '@mana/shared-stores';
|
||||
import { workbenchScenesStore } from '$lib/stores/workbench-scenes.svelte';
|
||||
|
||||
// Resolve each scene's bound agent → avatar + name. Cheap lookup
|
||||
// since all active agents are already in memory from the live-
|
||||
|
|
@ -15,6 +17,30 @@
|
|||
const agents = $derived(useAgents({ state: 'active' }));
|
||||
const agentById = $derived(new Map(agents.value.map((a) => [a.id, a])));
|
||||
|
||||
// Tag name lookup for the scope-badge tooltip. Same liveQuery that
|
||||
// SceneHeader already uses — no extra Dexie round-trip.
|
||||
const allTags = $derived(useAllTags());
|
||||
const tagNameById = $derived(new Map((allTags.value ?? []).map((t) => [t.id, t.name] as const)));
|
||||
|
||||
function scopeTitle(scopeTagIds: readonly string[] | undefined): string {
|
||||
const names = (scopeTagIds ?? [])
|
||||
.map((id) => tagNameById.get(id))
|
||||
.filter((n): n is string => !!n);
|
||||
return names.length > 0
|
||||
? `Bereich: ${names.join(', ')} — klicken zum Aufheben`
|
||||
: 'Bereichsfilter aktiv — klicken zum Aufheben';
|
||||
}
|
||||
|
||||
async function handleClearScope(e: MouseEvent | KeyboardEvent, sceneId: string) {
|
||||
e.stopPropagation();
|
||||
if ('key' in e) e.preventDefault();
|
||||
try {
|
||||
await workbenchScenesStore.setSceneScopeTags(sceneId, undefined);
|
||||
} catch (err) {
|
||||
console.error('[workbench] setSceneScopeTags failed:', err);
|
||||
}
|
||||
}
|
||||
|
||||
interface Props {
|
||||
scenes: WorkbenchScene[];
|
||||
activeSceneId: string | null;
|
||||
|
|
@ -141,7 +167,18 @@
|
|||
{/if}
|
||||
<span class="scene-name">{scene.name}</span>
|
||||
{#if hasScope}
|
||||
<span class="scope-badge" title="Bereichsfilter aktiv">
|
||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||
<span
|
||||
class="scope-badge"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
aria-label="Bereich aufheben"
|
||||
title={scopeTitle(scene.scopeTagIds)}
|
||||
onclick={(e) => handleClearScope(e, scene.id)}
|
||||
onkeydown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') handleClearScope(e, scene.id);
|
||||
}}
|
||||
>
|
||||
<Funnel size={10} weight="fill" />
|
||||
</span>
|
||||
{/if}
|
||||
|
|
@ -264,6 +301,19 @@
|
|||
color: hsl(var(--color-primary));
|
||||
opacity: 0.8;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
padding: 0.125rem;
|
||||
margin: -0.125rem;
|
||||
border-radius: 9999px;
|
||||
transition:
|
||||
opacity 0.15s,
|
||||
background 0.15s;
|
||||
}
|
||||
.scope-badge:hover,
|
||||
.scope-badge:focus-visible {
|
||||
opacity: 1;
|
||||
background: color-mix(in oklab, hsl(var(--color-primary)) 18%, transparent);
|
||||
outline: none;
|
||||
}
|
||||
.group-sep {
|
||||
width: 1px;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue