import Link from "next/link";
import type { ReactNode } from "react";
import { CloneUrlTabs, type CloneUrls } from "@/components/clone-button";
import { BookIcon, FileIcon, PlusIcon } from "@/components/icons";
import { Markdown } from "@/components/markdown";
import { Box } from "@/components/ui";
import type { WikiPage } from "@/lib/wiki";
import { pageHref } from "@/lib/wiki-links";
/** How many pages the sidebar lists before linking to all of them. */
const SIDEBAR_PAGES = 20;
/** An engraved heading over a sidebar group, with an optional readout at its right. */
function SectionLabel({ children, count }: { children: ReactNode; count?: number }) {
return (
<h2 className="mb-2 flex items-center justify-between type-label engraved">
{children}
{count !== undefined && <span className="type-readout text-ink3 [text-shadow:none]">{count}</span>}
</h2>
);
}
const quietLinkClass = "inline-flex items-center gap-1.5 type-meta text-ink2 transition-colors hover:text-ink [&_svg]:size-3";
/** "+ Add a custom sidebar": where a writer starts one of the special pages. */
export function AddSpecialLink({ wiki, slug, children }: { wiki: string; slug: string; children: ReactNode }) {
return (
<Link href={`${wiki}/_new?title=${encodeURIComponent(slug)}`} className={quietLinkClass}>
<PlusIcon /> {children}
</Link>
);
}
/**
* The wiki's sidebar, like GitHub's: its pages, the custom _Sidebar page if there is one, and the
* clone URL.
*/
export function WikiSidebar({
wiki,
pages,
current,
sidebar,
canWrite,
cloneUrls,
}: {
wiki: string;
pages: WikiPage[];
current?: string;
/** The _Sidebar page's Markdown. */
sidebar: string | null;
canWrite: boolean;
cloneUrls: CloneUrls;
}) {
return (
<aside className="flex flex-col gap-7">
<section>
<SectionLabel count={pages.length}>Pages</SectionLabel>
{pages.length === 0 ? (
<p className="type-body text-ink3">No pages yet.</p>
) : (
<ul>
{pages.slice(0, SIDEBAR_PAGES).map((p) => (
<li key={p.path}>
<Link
href={pageHref(wiki, p.slug)}
aria-current={p.slug === current ? "page" : undefined}
className={`group -mx-2 flex min-h-8 items-center gap-2.5 rounded-row px-2 py-1 type-ui outline-none hover:recipe-row-list-hover focus-visible:focus-ring ${
p.slug === current ? "font-medium text-ink recipe-row-list-hover" : "text-ink2 hover:text-ink"
}`}
>
<FileIcon width={14} height={14} className="shrink-0 text-ink3 transition-colors group-hover:text-ink2" />
<span className="min-w-0 truncate">{p.title}</span>
</Link>
</li>
))}
</ul>
)}
{pages.length > SIDEBAR_PAGES && (
<Link href={`${wiki}/_pages`} className={`${quietLinkClass} mt-2`}>
Show all {pages.length} pages
</Link>
)}
</section>
{sidebar !== null ? (
<Box className="px-5 py-4 text-[13px]">
<Markdown wiki={wiki}>{sidebar}</Markdown>
{canWrite && (
<Link href={`${wiki}/_Sidebar/_edit`} className={`${quietLinkClass} mt-3`}>
Edit sidebar
</Link>
)}
</Box>
) : (
canWrite && (
<div>
<AddSpecialLink wiki={wiki} slug="_Sidebar">
Add a custom sidebar
</AddSpecialLink>
</div>
)
)}
<section>
<SectionLabel>
<span className="inline-flex items-center gap-1.5">
<BookIcon width={12} height={12} /> Clone this wiki locally
</span>
</SectionLabel>
<CloneUrlTabs urls={cloneUrls} />
</section>
</aside>
);
}
/** The wiki's two columns: the page, then the sidebar. */
export function WikiColumns({ children, sidebar }: { children: ReactNode; sidebar: ReactNode }) {
return (
<div className="grid gap-8 lg:grid-cols-[minmax(0,1fr)_280px] xl:gap-10">
<div className="min-w-0">{children}</div>
{sidebar}
</div>
);
}