feat(docs): add custom documentation pages with AI beautify
User-created dynamic doc pages live at /docs/custom/:slug, persisted in the new backend. The editor offers "Beautify with AI", which regenerates the page as structured HTML with Mermaid diagrams and replaces the raw markdown source (the beautified version becomes the page's canonical content and survives edits). Adds a DocHtml renderer that lazily renders Mermaid blocks, a purple design token, sidebar/topbar entries for custom pages, and routing.
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
import { NavLink } from "react-router-dom";
|
||||
import { navSections } from "../data/nav";
|
||||
import { useCustomPages } from "../lib/customPagesStore";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
type SidebarProps = {
|
||||
collapsed: boolean;
|
||||
};
|
||||
|
||||
export function Sidebar({ collapsed }: SidebarProps) {
|
||||
const { pages } = useCustomPages();
|
||||
|
||||
return (
|
||||
<aside
|
||||
className={[
|
||||
@@ -62,6 +66,56 @@ export function Sidebar({ collapsed }: SidebarProps) {
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* User-created dynamic pages */}
|
||||
<div className="max-md:flex max-md:flex-none max-md:gap-2">
|
||||
<div
|
||||
className={[
|
||||
"flex items-center justify-between overflow-hidden whitespace-nowrap px-3 pb-2 pt-4 font-mono text-[0.65rem] uppercase tracking-[0.1em] text-muted max-md:hidden",
|
||||
collapsed ? "h-2 p-2 text-0" : "",
|
||||
].join(" ")}
|
||||
>
|
||||
<span>Custom Pages</span>
|
||||
<Link
|
||||
to="/docs/custom/new"
|
||||
className="text-accent no-underline hover:text-accent-hover"
|
||||
title="Add a custom page"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
+
|
||||
</Link>
|
||||
</div>
|
||||
<NavLink
|
||||
end
|
||||
className={({ isActive }) =>
|
||||
[
|
||||
"mb-0.5 flex select-none items-center gap-3 overflow-hidden whitespace-nowrap rounded-lg px-3 py-2 text-[0.85rem] text-fg-dim no-underline transition-all duration-150 hover:bg-surface-raised hover:text-fg-bright max-md:mb-0 max-md:justify-start",
|
||||
collapsed ? "justify-center p-3 max-md:px-3 max-md:py-2" : "",
|
||||
isActive ? "border border-accent/25 bg-accent/8 text-accent" : "",
|
||||
].join(" ")
|
||||
}
|
||||
to="/docs/custom"
|
||||
>
|
||||
<span className="min-w-5 text-center text-base">✦</span>
|
||||
<span className={collapsed ? "hidden max-md:inline" : ""}>Custom Pages</span>
|
||||
</NavLink>
|
||||
{!collapsed &&
|
||||
pages.map((page) => (
|
||||
<NavLink
|
||||
key={page.id}
|
||||
className={({ isActive }) =>
|
||||
[
|
||||
"mb-0.5 flex select-none items-center gap-3 overflow-hidden whitespace-nowrap rounded-lg px-3 py-2 pl-7 text-[0.82rem] text-fg-dim no-underline transition-all duration-150 hover:bg-surface-raised hover:text-fg-bright max-md:mb-0",
|
||||
isActive ? "border border-accent/25 bg-accent/8 text-accent" : "",
|
||||
].join(" ")
|
||||
}
|
||||
to={`/docs/custom/${page.slug}`}
|
||||
>
|
||||
<span className="min-w-5 text-center text-sm">{page.icon}</span>
|
||||
<span className="truncate">{page.title}</span>
|
||||
</NavLink>
|
||||
))}
|
||||
</div>
|
||||
</nav>
|
||||
</aside>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user