diff --git a/apps/web/app/(dashboard)/knowledge-base/page.tsx b/apps/web/app/(dashboard)/knowledge-base/page.tsx index f07243d1..e02b2ea7 100644 --- a/apps/web/app/(dashboard)/knowledge-base/page.tsx +++ b/apps/web/app/(dashboard)/knowledge-base/page.tsx @@ -1,10 +1,337 @@ -export default function KnowledgeBasePage() { - return ( -
- Your team's documents and references will appear here. +"use client"; + +import { useState } from "react"; +import { + FileText, + Plus, + Search, + Link as LinkIcon, +} from "lucide-react"; +import { MOCK_DOCUMENTS, type KBDocument } from "./_data/mock"; + +// --------------------------------------------------------------------------- +// 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`; +} + +// --------------------------------------------------------------------------- +// 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(
+ | + {h} + | + ))} +
|---|
| + {cell} + | + ))} +
+ {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 (
+