"use client"; import { useState } from "react"; import { FileText, Plus, Search, Link as LinkIcon, } from "lucide-react"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function timeAgo(dateStr: string): string { const diff = Date.now() - new Date(dateStr).getTime(); const hours = Math.floor(diff / 3600000); if (hours < 24) return `${hours}h ago`; const days = Math.floor(hours / 24); return `${days}d ago`; } interface KBDocument { id: string; title: string; content: string; createdBy: string; updatedAt: string; referencedBy: string[]; } // --------------------------------------------------------------------------- // Simple Markdown-ish renderer (handles headers, code blocks, tables, lists) // --------------------------------------------------------------------------- function renderMarkdown(text: string): React.ReactNode[] { const lines = text.split("\n"); const elements: React.ReactNode[] = []; let i = 0; while (i < lines.length) { const line = lines[i]!; // Code block if (line.startsWith("```")) { const lang = line.slice(3).trim(); const codeLines: string[] = []; i++; while (i < lines.length && !lines[i]!.startsWith("```")) { codeLines.push(lines[i]!); i++; } i++; // skip closing ``` elements.push(
          {codeLines.join("\n")}
        
); continue; } // Table (simplified: detect | pipes) if (line.includes("|") && line.trim().startsWith("|")) { const tableRows: string[] = []; while (i < lines.length && lines[i]!.includes("|") && lines[i]!.trim().startsWith("|")) { tableRows.push(lines[i]!); i++; } // Filter out separator rows (|---|---|) const dataRows = tableRows.filter((r) => !r.match(/^\|[\s-|]+\|$/)); if (dataRows.length > 0) { const parseRow = (row: string) => row.split("|").filter((c) => c.trim() !== "").map((c) => c.trim()); const header = parseRow(dataRows[0]!); const body = dataRows.slice(1).map(parseRow); elements.push(
{header.map((h, hi) => ( ))} {body.map((row, ri) => ( {row.map((cell, ci) => ( ))} ))}
{h}
{cell}
); } continue; } // Heading if (line.startsWith("## ")) { elements.push(

{line.slice(3)}

, ); i++; continue; } if (line.startsWith("### ")) { elements.push(

{line.slice(4)}

, ); i++; continue; } // List item if (/^- \[[ x]\] /.test(line)) { const checked = line.includes("[x]"); const text = line.replace(/^- \[[ x]\] /, ""); elements.push(
{text}
); i++; continue; } if (line.startsWith("- ")) { elements.push(
{renderInline(line.slice(2))}
); i++; continue; } // Numbered list if (/^\d+\. /.test(line)) { const num = line.match(/^(\d+)\. /)![1]!; const text = line.replace(/^\d+\. /, ""); elements.push(
{num}. {text}
); i++; continue; } // Empty line — guard is redundant since line is already asserted, but keeps TS happy if (line.trim() === "") { elements.push(
); i++; continue; } // Paragraph elements.push(

{renderInline(line)}

); i++; } return elements; } function renderInline(text: string): React.ReactNode { // Handle inline code `...` const parts = text.split(/(`[^`]+`)/); return parts.map((part, i) => { if (part.startsWith("`") && part.endsWith("`")) { return ( {part.slice(1, -1)} ); } return part; }); } // --------------------------------------------------------------------------- // Components // --------------------------------------------------------------------------- function DocListItem({ doc, isSelected, onClick, }: { doc: KBDocument; isSelected: boolean; onClick: () => void; }) { return ( ); } function DocDetail({ doc }: { doc: KBDocument }) { return (
{/* Title */}

{doc.title}

{/* Meta */}
By {doc.createdBy} · Updated {timeAgo(doc.updatedAt)}
{/* Content */}
{renderMarkdown(doc.content)}
{/* Referenced by */} {doc.referencedBy.length > 0 && (
Referenced by
{doc.referencedBy.map((ref) => ( {ref} ))}
)}
); } // --------------------------------------------------------------------------- // Page // --------------------------------------------------------------------------- export default function KnowledgeBasePage() { const [documents] = useState([]); const [selectedId, setSelectedId] = useState(""); const [search, setSearch] = useState(""); const filtered = search ? documents.filter((d) => d.title.toLowerCase().includes(search.toLowerCase()) ) : documents; const selected = documents.find((d) => d.id === selectedId) ?? null; return (
{/* Left: Document list */}

Knowledge Base

{/* Search */}
setSearch(e.target.value)} className="border-0 bg-transparent shadow-none focus-visible:ring-0 flex-1 text-sm" />
{/* Document list */}
{filtered.map((doc) => ( setSelectedId(doc.id)} /> ))} {filtered.length === 0 && (
No documents found
)}
{/* Right: Document content */} {selected ? ( ) : (
Select a document
)}
); }