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.
Sidebar
<Sidebar> — KB/src/components/Sidebar.tsx
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:
- 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. - Article selected → header (category pill, applicability, first 3 tags, title, summary box, last-updated date), then sections, then citations list, then sticky
<TableOfContents>aside onxl: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.