"use client"; import Link from "next/link"; import { useState } from "react"; import { useQueryClient } from "@tanstack/react-query"; import { Sparkles, RefreshCw, Check, ArrowRight, FlaskConical, BookMarked, Beaker, Share2, Star, Clock, Pencil, FolderKanban, Inbox, ExternalLink } from "lucide-react"; import { api } from "@/lib/client/api"; import { useUI } from "@/lib/client/store"; import { cn, timeAgo, fmtDate, money } from "@/lib/utils"; import { Button } from "@/components/ui/button"; import { Input, Textarea } from "@/components/ui/input"; import { Badge, Spinner } from "@/components/ui/primitives"; import { toast } from "@/components/ui/toast"; import { Markdown } from "@/components/markdown"; import { Chat } from "@/components/chat/Chat"; import { PageGraphCard } from "@/components/graph/PageGraphCard"; import type { WidgetType } from "./types"; export interface PageLite { id: string; title: string; icon: string | null; section: string; type: string; updatedAt: string; lastOpenedAt?: string | null; wordCount?: number; pinned?: boolean; properties?: Record } export interface DashboardData { layout: { widgets: { id: string; type: WidgetType; size: "half" | "wide" | "third"; config?: Record }[]; custom: boolean }; user: { displayName: string; username: string; preferences: Record }; recent: PageLite[]; pinned: PageLite[]; modified: PageLite[]; projects: PageLite[]; tasks: { id: string; title: string; status: string; priority: string | null; dueAt: string | null; project: string | null; pageId: string | null; pageTitle: string | null }[]; research: { pages: PageLite[]; experiments: { id: string; name: string; status: string; pageId: string | null; updatedAt: string }[]; counts: { references: number; experiments: number; researchPages: number } }; graph: { top: { id: string; title: string; icon: string | null; section: string; degree: number }[]; suggested: number; edges: number }; usage: { today: { calls: number; costUsd: number; errors: number }; budgetUsd: number }; summary: { text: string; model: string; provider: string; costUsd: number | null; latencyMs: number; at: string; pages: number; tasks: number } | null; stats: { editedThisWeek: number }; } export interface WidgetProps { data: DashboardData; refresh: () => void; config?: Record } const pageIcon = (p: { icon: string | null; type: string }) => p.icon ?? (p.type === "database" ? "🗂" : p.type === "research" ? "🔬" : "📄"); export function PageRow({ p, meta }: { p: PageLite; meta?: React.ReactNode }) { return ( {pageIcon(p)} {p.title || "Untitled"} {meta ?? timeAgo(p.updatedAt)} ); } export function EmptyLine({ children }: { children: React.ReactNode }) { return
{children}
; } const More = ({ href, children }: { href: string; children: React.ReactNode }) => {children}; // ---------- quick capture export function QuickCapture({ data, refresh }: WidgetProps) { const [title, setTitle] = useState(""); const [text, setText] = useState(""); const [busy, setBusy] = useState(false); const qc = useQueryClient(); const openAI = useUI((s) => s.openAI); const section = (data.user.preferences?.defaultSection as string) || "notes"; async function save() { if (!title.trim() && !text.trim()) return; setBusy(true); try { const { markdownToDoc } = await import("@/lib/editor/markdown-client"); const p = await api("/api/pages", { method: "POST", json: { title: title.trim() || text.trim().split("\n")[0].slice(0, 80), section: ["notes", "documents", "projects", "research"].includes(section) ? section : "notes", content: { type: "doc", content: text.trim() ? markdownToDoc(text) : [{ type: "paragraph" }] } } }); qc.invalidateQueries({ queryKey: ["tree"] }); setTitle(""); setText(""); refresh(); toast("Note created", { description: p.title, tone: "success" }); } catch (e: any) { toast("Could not save", { description: e.message, tone: "danger" }); } finally { setBusy(false); } } const ask = () => openAI({ prefill: [title.trim(), text.trim()].filter(Boolean).join("\n\n") || null }); return (
setTitle(e.target.value)} placeholder="Title" onKeyDown={(e) => { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) save(); }} />