diff --git a/TODO.md b/TODO.md index f85e78b..2bf6d03 100644 --- a/TODO.md +++ b/TODO.md @@ -7,7 +7,8 @@ ## Medium Impact, Lower Effort – Quick Wins - [ ] CONTRIBUTING.md — how to run tests locally, code style expectations, PR process -- [ ] GitHub repo metadata — description, topics/tags (`mcp`, `claude`, `prd`, `product-requirements`, `ai-tools`, `developer-tools`, `mcp-server`), website URL +- [x] GitHub repo metadata — description, topics/tags (`mcp`, `claude`, `prd`, `product-requirements`, `ai-tools`, `developer-tools`, `mcp-server`, `nextjs`, `fastapi`, `docker`) +- [ ] GitHub repo website URL — set homepage once public site is ready - [ ] `prd_diff_sections` tool — unified diff between two revisions of a section, avoids loading both and diffing manually - [ ] UI Playwright tests @@ -29,7 +30,7 @@ - [ ] Support `### ` (h3) splitting in import for nested section hierarchies - [ ] Add `prd_merge_sections` tool (combine two sections into one) - [ ] Add `prd_reorder_sections` tool (bulk sort_order update) -- [ ] Export as PDF via headless browser +- [x] ~~Export as PDF via headless browser~~ Export as PDF via browser print dialog - [ ] MCP auth for remote Claude clients (SSH tunnel or authenticated ingress) - [ ] move to tasks github projects - [ ] add Playwright preview autoupdate (CI for PR + agents.md for agent instructions on which sections to observe) diff --git a/frontend/src/app/projects/[slug]/page.tsx b/frontend/src/app/projects/[slug]/page.tsx index 980397a..4811b9b 100644 --- a/frontend/src/app/projects/[slug]/page.tsx +++ b/frontend/src/app/projects/[slug]/page.tsx @@ -9,6 +9,9 @@ import { Clock, BarChart3, MessageSquare, + Eye, + Download, + FileDown, } from "lucide-react"; import { TopBar } from "@/components/top-bar"; import { SectionSidebar } from "@/components/section-sidebar"; @@ -20,7 +23,9 @@ import { EmptyState } from "@/components/empty-state"; import { LoadingOverlay } from "@/components/loading-overlay"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { MarkdownRenderer } from "@/components/markdown-renderer"; import { fetchProject, fetchSection, fetchTokenStats } from "@/lib/api"; import type { ProjectDetailResponse, @@ -67,6 +72,8 @@ export default function ProjectDetailPage() { const [loading, setLoading] = useState(true); const [sectionLoading, setSectionLoading] = useState(false); const [activeTab, setActiveTab] = useState("sections"); + const [previewOpen, setPreviewOpen] = useState(false); + const [previewContent, setPreviewContent] = useState(""); const loadComments = useCallback(async () => { try { @@ -498,14 +505,95 @@ export default function ProjectDetailPage() { - +
+ + + + +
)} + + + + +
+ {project?.project.name} — Full PRD +
+ + +
+
+
+
+ +
+
+
); } diff --git a/frontend/src/components/markdown-renderer.tsx b/frontend/src/components/markdown-renderer.tsx index 62509d3..53befcb 100644 --- a/frontend/src/components/markdown-renderer.tsx +++ b/frontend/src/components/markdown-renderer.tsx @@ -4,6 +4,7 @@ import ReactMarkdown from "react-markdown"; import rehypeHighlight from "rehype-highlight"; import remarkGfm from "remark-gfm"; import { cn } from "@/lib/utils"; +import "highlight.js/styles/github-dark.min.css"; interface MarkdownRendererProps { content: string; diff --git a/install.sh b/install.sh index aaec10d..f06c549 100755 --- a/install.sh +++ b/install.sh @@ -262,7 +262,7 @@ import sys, json lines = sys.stdin.read().strip().split('\n') services = [json.loads(l) for l in lines if l.strip()] healthy = all(s.get('Health','') == 'healthy' or s.get('State','') == 'running' for s in services) -sys.exit(0 if healthy and len(services) >= 4 else 1) +sys.exit(0 if healthy and len(services) >= 5 else 1) " 2>/dev/null; then break fi