Pablan, as it stands
Self-hosted knowledge management for SMEs: a split-screen Markdown editor whose sections an LLM refines while you write, and RAG question answering over the documents that result. FastAPI + Postgres/pgvector on the back, SvelteKit on the front, everything OpenAI-compatible and self-hostable. Squashed into a single commit; the development history stays local. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CA43ZJda8Rbp2hKXNy8f6b
This commit is contained in:
co-authored by
Claude Opus 5
parent
68d3a43191
commit
784b76baf7
@@ -0,0 +1,44 @@
|
||||
<script lang="ts">
|
||||
import { Tabs } from 'bits-ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
type Tab = { value: string; label: string };
|
||||
|
||||
type Props = {
|
||||
tabs: Tab[];
|
||||
value?: string;
|
||||
/** Rendered once per tab; receives that tab's value. */
|
||||
panel: Snippet<[string]>;
|
||||
class?: string;
|
||||
};
|
||||
|
||||
let {
|
||||
tabs,
|
||||
value = $bindable(tabs[0]?.value ?? ''),
|
||||
panel,
|
||||
class: className = ''
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<Tabs.Root bind:value class="flex min-h-0 flex-col {className}">
|
||||
<Tabs.List class="flex gap-1 rounded-md bg-surface-sunken p-1">
|
||||
{#each tabs as tab (tab.value)}
|
||||
<Tabs.Trigger
|
||||
value={tab.value}
|
||||
data-testid="tab-{tab.value}"
|
||||
class="flex-1 cursor-pointer rounded-md px-3 py-1.5 text-sm font-medium text-ink-muted transition-colors data-[state=active]:bg-surface-raised data-[state=active]:text-ink"
|
||||
>
|
||||
{tab.label}
|
||||
</Tabs.Trigger>
|
||||
{/each}
|
||||
</Tabs.List>
|
||||
{#each tabs as tab (tab.value)}
|
||||
<Tabs.Content value={tab.value} class="mt-2 min-h-0 flex-1">
|
||||
<!-- Only the open tab is rendered. Bits keeps inactive panels mounted
|
||||
(just hidden), which for a page of independent panels means every
|
||||
one of them fetches its data on arrival and hidden controls sit in
|
||||
the DOM where a click can never reach them. -->
|
||||
{#if tab.value === value}{@render panel(tab.value)}{/if}
|
||||
</Tabs.Content>
|
||||
{/each}
|
||||
</Tabs.Root>
|
||||
Reference in New Issue
Block a user