style(research-lab): move help into MODULE_HELP, drop subtitle, keys-button to footer

- The PageShell's ? icon already renders in-view help from the central
  MODULE_HELP map, so the inline subtitle was duplicative. Added a
  rich help entry (description + 7 features + 4 tips) matching the
  calendar/contacts pattern.
- ListView header now just carries the mode-toggle (Suche/Extrakt/
  Agent). Clean single-row layout.
- Moved "🔑 Eigene API-Keys verwalten" to a footer section at the
  bottom of the page, separated by a border. Less busy header, and
  BYO-key management is a rare action — belongs at the end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-18 17:16:51 +02:00
parent 20ec81e3dd
commit e813401dc0
3 changed files with 48 additions and 23 deletions

View file

@ -746,4 +746,23 @@ export const MODULE_HELP: Record<string, ModuleHelp> = {
'Starte einfach: z.B. "Wenn ein neuer Kontakt erstellt wird, erstelle eine Aufgabe zum Kennenlernen"',
],
},
'research-lab': {
description:
'Web-Research-Anbieter Seite-an-Seite vergleichen: gleiche Query an bis zu fünf Provider parallel, Antworten + Latenz + Kosten nebeneinander. Alle Runs werden serverseitig persistiert für spätere Auswertung.',
features: [
'Drei Modi: Suche (6 Provider wie Brave, Tavily, Exa, Serper, SearXNG, DuckDuckGo)',
'Extrakt (Firecrawl, Jina Reader, Readability) — eine URL, drei Extraktoren',
'Agent (Perplexity Sonar, Claude web_search, OpenAI Responses, Gemini Grounding)',
'Auto-Router: ohne Provider-Auswahl klassifiziert ein Regex-/LLM-Mix die Query und wählt den besten Anbieter',
'15 Sterne pro Ergebnis bewerten — deine Ratings persistieren zur späteren Auswertung',
'BYO-Keys: eigene API-Keys hinterlegen, deine Calls gehen direkt ohne Credits-Verbrauch',
'Runs-Historie klickbar mit Detail-View für jeden vergangenen Vergleich',
],
tips: [
'Lass den Provider leer → Auto-Router wählt je nach Query-Typ (News → Tavily, Paper → Exa, allgemein → Brave)',
'"Suche" für Links + Snippets, "Extrakt" für Volltext einer URL, "Agent" für synthetisierte Antwort mit Zitaten',
'Cmd/Ctrl+Enter startet den Vergleich ohne Klick',
'Eigene API-Keys unter "🔑 API-Keys" — überschreiben den Server-Key und kosten dich keine Credits',
],
},
};

View file

@ -123,7 +123,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}

View file

@ -77,15 +77,6 @@
<div class="lab">
<header class="lab-header">
<p class="subtitle">
Gleiche Anfrage parallel an mehrere Anbieter schicken, Antworten nebeneinander vergleichen,
persistent speichern.
</p>
<div class="header-actions">
<button type="button" class="keys-link" onclick={() => void goto('/research-lab/keys')}>
🔑 API-Keys
</button>
</div>
<div class="mode-toggle" role="tablist">
{#each ['search', 'extract', 'agent'] as const as m}
<button
@ -205,6 +196,12 @@
</ul>
{/if}
</section>
<footer class="lab-footer">
<button type="button" class="keys-link" onclick={() => void goto('/research-lab/keys')}>
🔑 Eigene API-Keys verwalten
</button>
</footer>
</div>
<style>
@ -221,38 +218,36 @@
.lab-header {
display: flex;
justify-content: space-between;
justify-content: flex-start;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
}
.subtitle {
margin: 0;
font-size: 0.875rem;
color: hsl(var(--color-muted-foreground));
max-width: 40rem;
flex: 1 1 20rem;
}
.header-actions {
.lab-footer {
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid hsl(var(--color-border));
display: flex;
gap: 0.5rem;
justify-content: flex-end;
}
.keys-link {
padding: 0.375rem 0.75rem;
padding: 0.5rem 0.875rem;
border: 1px solid hsl(var(--color-border));
border-radius: 0.375rem;
background: hsl(var(--color-surface));
color: hsl(var(--color-foreground));
color: hsl(var(--color-muted-foreground));
font-size: 0.8125rem;
cursor: pointer;
transition:
background 0.15s,
border-color 0.15s;
border-color 0.15s,
color 0.15s;
}
.keys-link:hover {
background: hsl(var(--color-surface-hover));
border-color: hsl(var(--color-border-strong));
color: hsl(var(--color-foreground));
}
.mode-toggle {