Component map

All in KB/src/components/. Roughly 1700 lines of TSX total. Tailwind 3 utility classes throughout; no CSS modules. Custom utility classes (.btn-ghost, .btn-primary, .input-field, .sidebar-item, .legal-prose, .category-pill, .chat-bubble-*, .streaming-cursor, .legal-ref-tag, .scrollbar-thin, .chat-panel-enter, .card) are defined in KB/src/index.css.

Top-level

<App>KB/src/frontend.tsx:16

Single screen. Holds three state values (selected article, chat open, settings open) and the useSettings hook. Composes the layout: sidebar (256px) + main column. Floating “Ask Claude” button shows an amber dot when no Anthropic key is set.

Logo + settings button at top, search input below, scrollable category-grouped article tree, theme toggle in footer.

Categories rendered in fixed order: gdpr, swedish-law, b2b-enrichment, enforcement, templates (Sidebar.tsx:14–20). Each is collapsible (useState<Set<KBCategory>>). Empty categories show “No articles yet” stub.

<SearchResults>KB/src/components/SearchResults.tsx

Popover dropdown shown under the search input when there is a 2+ char query. Renders title, applicability emoji, category pill, first two tag pills, and a 2-line clamped summary per result.

<ThemeToggle>KB/src/components/ThemeToggle.tsx

Sun/moon icon button. Reads from useTheme. See KB Settings.

Main content

<LegalDisclaimer>KB/src/components/LegalDisclaimer.tsx

Amber banner: “Informational content only — not legal advice.” Dismissible, persisted to localStorage["kb_disclaimer_dismissed"]. See KB Legal Disclaimer.

<ArticleViewer>KB/src/components/ArticleViewer.tsx

Two states:

  1. No article selected<WelcomeScreen> with hero, three feature cards (“29 Legal Articles” — see KB Content Index for the 10-vs-29 mismatch), and a category grid.
  2. Article selected → header (category pill, applicability, first 3 tags, title, summary box, last-updated date), then sections, then citations list, then sticky <TableOfContents> aside on xl: breakpoint.

Section rendering (SectionBlock, ArticleViewer.tsx:99) splits content on \n\n+ into paragraphs; each paragraph runs through renderTextWithLegalRefs() (ArticleViewer.tsx:73) which converts [GDPR Art. 6(1)(f)] patterns into a styled .legal-ref-tag span. Heading IDs are slug-derived from the heading text for TOC anchoring.

<TableOfContents>KB/src/components/TableOfContents.tsx

Sticky right-rail. Uses IntersectionObserver with rootMargin: "-80px 0px -60% 0px" to highlight the active section as the user scrolls. Renders only level: 2 entries by default; falls back to all sections if there are no h2s.

<SourceBadge>KB/src/components/SourceBadge.tsx

Colored pill per credibility tier. Used in citations and chat source dropdowns. See KB Credibility Scoring.

Chat

<ChatPanel>KB/src/components/ChatPanel.tsx

Right slide-in panel (md:w-96). Header with “Clear” + “Close” buttons; article-context indicator strip when an article is selected; auto-resizing textarea (max 120px); send on Enter, newline on Shift+Enter; three suggestion buttons when the conversation is empty.

When anthropicKey is empty, shows a key icon + “API Key Required” CTA pointing to settings.

<ChatMessage>KB/src/components/ChatMessage.tsx

Per-message bubble. formatContent() (ChatMessage.tsx:9) parses **bold** markup and renders \n as <br/>. Streaming messages get a CSS .streaming-cursor blink. Sources from web search render as a collapsible list of cards (title, snippet, domain, source badge).

Settings

<SettingsModal>KB/src/components/SettingsModal.tsx

Modal dialog. Three fields: Anthropic key (password input), Serper key (password input), Claude model (<select> with three options — see KB Chat Flow for the full list). Backdrop dismiss; Esc dismiss; “Saved” confirmation flash for 2 seconds.

See also

KB Architecture, KB Chat Flow, KB Search, KB Settings, KB Credibility Scoring, KB Legal Disclaimer.

See also