From 4e2caa1e2e4797b50d26a4c67a44d51253e21c0c Mon Sep 17 00:00:00 2001 From: Rishabh Date: Thu, 19 Feb 2026 09:47:35 +0530 Subject: [PATCH 1/9] fix: resolve TypeScript build errors Update tsconfig lib to ES2022 for error.cause support and fix invalid IconButton props (size/variant) to match Apsara component types. Co-Authored-By: Claude Opus 4.6 --- packages/chronicle/next-env.d.ts | 2 +- packages/chronicle/src/components/api/field-row.tsx | 4 ++-- packages/chronicle/src/components/api/key-value-editor.tsx | 2 +- packages/chronicle/tsconfig.json | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/chronicle/next-env.d.ts b/packages/chronicle/next-env.d.ts index c4b7818f..9edff1c7 100644 --- a/packages/chronicle/next-env.d.ts +++ b/packages/chronicle/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/dev/types/routes.d.ts"; +import "./.next/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/packages/chronicle/src/components/api/field-row.tsx b/packages/chronicle/src/components/api/field-row.tsx index c7458dfe..1ede3ddc 100644 --- a/packages/chronicle/src/components/api/field-row.tsx +++ b/packages/chronicle/src/components/api/field-row.tsx @@ -63,7 +63,7 @@ export function FieldRow({ field, location, editable, value, onChange }: FieldRo {label} - { + { const newItem = itemChildren ? {} : '' onChange?.(field.name, [...items, newItem]) }}> @@ -105,7 +105,7 @@ export function FieldRow({ field, location, editable, value, onChange }: FieldRo }} /> )} - { + { const updated = items.filter((_, j) => j !== i) onChange?.(field.name, updated) }}> diff --git a/packages/chronicle/src/components/api/key-value-editor.tsx b/packages/chronicle/src/components/api/key-value-editor.tsx index b2960897..ed8ce391 100644 --- a/packages/chronicle/src/components/api/key-value-editor.tsx +++ b/packages/chronicle/src/components/api/key-value-editor.tsx @@ -49,7 +49,7 @@ export function KeyValueEditor({ entries, onChange }: KeyValueEditorProps) { onChange={(e) => updateEntry(i, 'value', e.target.value)} /> - removeEntry(i)}> + removeEntry(i)}> diff --git a/packages/chronicle/tsconfig.json b/packages/chronicle/tsconfig.json index ecfaea9f..471ded2f 100644 --- a/packages/chronicle/tsconfig.json +++ b/packages/chronicle/tsconfig.json @@ -4,6 +4,7 @@ "outDir": "dist", "rootDir": ".", "baseUrl": ".", + "lib": ["ES2022", "DOM", "DOM.Iterable"], "moduleResolution": "bundler", "paths": { "@/*": ["./src/*"], From 6981860a6989ed0d7a59e6551e54967aa8883fdc Mon Sep 17 00:00:00 2001 From: Rishabh Date: Thu, 19 Feb 2026 12:19:41 +0530 Subject: [PATCH 2/9] feat: add paper theme with dynamic theme registry Add theme registry for config-driven theme selection and implement paper theme with chapter nav, serif content, reading progress ruler, and prev/next navigation. Co-Authored-By: Claude Opus 4.6 --- .../chronicle/src/app/[[...slug]]/page.tsx | 4 +- .../src/app/apis/[[...slug]]/layout.tsx | 3 +- .../src/themes/paper/ChapterNav.module.css | 58 ++++++++++++++++ .../chronicle/src/themes/paper/ChapterNav.tsx | 69 +++++++++++++++++++ .../src/themes/paper/Layout.module.css | 33 +++++++++ .../chronicle/src/themes/paper/Layout.tsx | 36 ++++++++++ .../src/themes/paper/Page.module.css | 15 ++++ packages/chronicle/src/themes/paper/Page.tsx | 21 ++++++ .../src/themes/paper/PrevNextNav.module.css | 25 +++++++ .../src/themes/paper/PrevNextNav.tsx | 43 ++++++++++++ .../themes/paper/ReadingProgress.module.css | 47 +++++++++++++ .../src/themes/paper/ReadingProgress.tsx | 60 ++++++++++++++++ packages/chronicle/src/themes/paper/index.ts | 8 +++ packages/chronicle/src/themes/registry.ts | 14 ++++ 14 files changed, 433 insertions(+), 3 deletions(-) create mode 100644 packages/chronicle/src/themes/paper/ChapterNav.module.css create mode 100644 packages/chronicle/src/themes/paper/ChapterNav.tsx create mode 100644 packages/chronicle/src/themes/paper/Layout.module.css create mode 100644 packages/chronicle/src/themes/paper/Layout.tsx create mode 100644 packages/chronicle/src/themes/paper/Page.module.css create mode 100644 packages/chronicle/src/themes/paper/Page.tsx create mode 100644 packages/chronicle/src/themes/paper/PrevNextNav.module.css create mode 100644 packages/chronicle/src/themes/paper/PrevNextNav.tsx create mode 100644 packages/chronicle/src/themes/paper/ReadingProgress.module.css create mode 100644 packages/chronicle/src/themes/paper/ReadingProgress.tsx create mode 100644 packages/chronicle/src/themes/paper/index.ts create mode 100644 packages/chronicle/src/themes/registry.ts diff --git a/packages/chronicle/src/app/[[...slug]]/page.tsx b/packages/chronicle/src/app/[[...slug]]/page.tsx index 8231f34b..077fe87c 100644 --- a/packages/chronicle/src/app/[[...slug]]/page.tsx +++ b/packages/chronicle/src/app/[[...slug]]/page.tsx @@ -2,7 +2,7 @@ import { notFound } from 'next/navigation' import type { MDXContent } from 'mdx/types' import { loadConfig } from '../../lib/config' import { source, buildPageTree } from '../../lib/source' -import { defaultTheme } from '../../themes/default' +import { getTheme } from '../../themes/registry' import { mdxComponents } from '../../components/mdx' interface PageProps { @@ -26,7 +26,7 @@ export default async function DocsPage({ params }: PageProps) { notFound() } - const { Layout, Page } = defaultTheme + const { Layout, Page } = getTheme(config.theme?.name) const data = page.data as PageData const MDXBody = data.body diff --git a/packages/chronicle/src/app/apis/[[...slug]]/layout.tsx b/packages/chronicle/src/app/apis/[[...slug]]/layout.tsx index b27b9c05..e9f03c76 100644 --- a/packages/chronicle/src/app/apis/[[...slug]]/layout.tsx +++ b/packages/chronicle/src/app/apis/[[...slug]]/layout.tsx @@ -1,11 +1,12 @@ import { loadConfig } from '../../../lib/config' import { loadApiSpecs } from '../../../lib/openapi' import { buildApiPageTree } from '../../../lib/api-routes' -import { Layout } from '../../../themes/default' +import { getTheme } from '../../../themes/registry' import styles from './layout.module.css' export default function ApiLayout({ children }: { children: React.ReactNode }) { const config = loadConfig() + const { Layout } = getTheme(config.theme?.name) const specs = loadApiSpecs(config.api ?? []) const tree = buildApiPageTree(specs) diff --git a/packages/chronicle/src/themes/paper/ChapterNav.module.css b/packages/chronicle/src/themes/paper/ChapterNav.module.css new file mode 100644 index 00000000..97acf63a --- /dev/null +++ b/packages/chronicle/src/themes/paper/ChapterNav.module.css @@ -0,0 +1,58 @@ +.nav { + display: flex; + flex-direction: column; + gap: var(--rs-space-5); +} + +.chapter { + display: flex; + flex-direction: column; + gap: var(--rs-space-2); +} + +.chapterLabel { + font-size: var(--rs-font-size-small); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--rs-color-foreground-base-primary); +} + +.chapterItems { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: var(--rs-space-1); + padding-left: var(--rs-space-4); +} + +.item { + list-style: none; +} + +.link { + display: flex; + align-items: center; + gap: var(--rs-space-2); + font-size: var(--rs-font-size-small); + color: var(--rs-color-foreground-base-tertiary); + text-decoration: none; + padding: var(--rs-space-1) 0; +} + +.link:hover { + color: var(--rs-color-foreground-base-primary); +} + +.active { + color: var(--rs-color-foreground-accent-primary); + font-weight: 500; +} + +.icon { + display: flex; + align-items: center; + flex-shrink: 0; +} diff --git a/packages/chronicle/src/themes/paper/ChapterNav.tsx b/packages/chronicle/src/themes/paper/ChapterNav.tsx new file mode 100644 index 00000000..7c1e5735 --- /dev/null +++ b/packages/chronicle/src/themes/paper/ChapterNav.tsx @@ -0,0 +1,69 @@ +'use client' + +import { usePathname } from 'next/navigation' +import NextLink from 'next/link' +import { MethodBadge } from '../../components/api/method-badge' +import type { PageTree, PageTreeItem } from '../../types' +import styles from './ChapterNav.module.css' + +const iconMap: Record = { + 'method-get': , + 'method-post': , + 'method-put': , + 'method-delete': , + 'method-patch': , +} + +interface ChapterNavProps { + tree: PageTree +} + +export function ChapterNav({ tree }: ChapterNavProps) { + const pathname = usePathname() + let chapterIndex = 0 + + return ( + + ) +} + +function ChapterItem({ item, pathname }: { item: PageTreeItem; pathname: string }) { + if (item.type === 'separator') return null + + const isActive = pathname === item.url + const icon = item.icon ? iconMap[item.icon] : null + + return ( +
  • + + {icon && {icon}} + {item.name} + +
  • + ) +} diff --git a/packages/chronicle/src/themes/paper/Layout.module.css b/packages/chronicle/src/themes/paper/Layout.module.css new file mode 100644 index 00000000..e6124676 --- /dev/null +++ b/packages/chronicle/src/themes/paper/Layout.module.css @@ -0,0 +1,33 @@ +.layout { + min-height: 100vh; +} + +.header { + border-bottom: 1px solid var(--rs-color-border-base-primary); +} + +.body { + flex: 1; +} + +.sidebar { + width: 260px; + padding: var(--rs-space-7) var(--rs-space-5); + border-right: 1px solid var(--rs-color-border-base-primary); + overflow-y: auto; + font-family: 'SF Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', monospace; +} + +.title { + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--rs-color-foreground-accent-primary); + font-family: inherit; + margin-bottom: var(--rs-space-7); +} + +.content { + flex: 1; + padding: var(--rs-space-9); + overflow-y: auto; +} diff --git a/packages/chronicle/src/themes/paper/Layout.tsx b/packages/chronicle/src/themes/paper/Layout.tsx new file mode 100644 index 00000000..9b52bf1c --- /dev/null +++ b/packages/chronicle/src/themes/paper/Layout.tsx @@ -0,0 +1,36 @@ +'use client' + +import { Flex, Navbar, Headline } from '@raystack/apsara' +import { ClientThemeSwitcher } from '../../components/ui/client-theme-switcher' +import { Search } from '../../components/ui/search' +import { Footer } from '../../components/ui/footer' +import { ChapterNav } from './ChapterNav' +import { PrevNextNav } from './PrevNextNav' +import type { ThemeLayoutProps } from '../../types' +import styles from './Layout.module.css' + +export function Layout({ children, config, tree }: ThemeLayoutProps) { + return ( + + + + {config.search?.enabled && } + + + + + + + + +
    {children}
    +
    +