Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 128 additions & 79 deletions bun.lock

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions packages/chronicle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@types/lodash-es": "^4.17.12",
"@types/mdast": "^4.0.4",
"@types/mdx": "^2.0.14",
"@types/bun": "^1.4.0",
"@types/node": "^25.9.5",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
Expand All @@ -39,21 +40,19 @@
},
"dependencies": {
"@analytics/google-analytics": "^1.1.0",
"@base-ui/react": ">=1.5.0 <1.6.0",
"@base-ui/react": "~1.6.0",
"@codemirror/lang-json": "^6.0.2",
"@codemirror/state": "^6.7.1",
"@codemirror/theme-one-dark": "^6.1.3",
"@codemirror/view": "^6.43.6",
"@heroicons/react": "^2.2.0",
"@opentelemetry/api": "^1.9.1",
"@opentelemetry/api-logs": "^0.218.0",
"@opentelemetry/exporter-prometheus": "^0.214.0",
"@opentelemetry/resources": "^2.10.0",
"@opentelemetry/sdk-logs": "^0.218.0",
"@opentelemetry/sdk-metrics": "^2.10.0",
"@opentelemetry/semantic-conventions": "^1.43.0",
"@radix-ui/react-icons": "^1.3.2",
"@raystack/apsara": "1.0.0-rc.7",
"@raystack/apsara": "1.6.0",
"@shikijs/rehype": "^4.3.1",
"@tanstack/react-query": "5.101.4",
"@vitejs/plugin-react": "^6.0.4",
Expand All @@ -62,15 +61,16 @@
"class-variance-authority": "^0.7.1",
"codemirror": "^6.0.2",
"commander": "^14.0.3",
"fumadocs-core": "16.12.1",
"fumadocs-mdx": "14.3.1",
"fumadocs-core": "16.15.4",
"fumadocs-mdx": "15.4.0",
"github-slugger": "^2.0.0",
"glob": "^11.1.0",
"gray-matter": "^4.0.3",
"h3": "^2.0.1-rc.25",
"html-tag-names": "^2.1.0",
"http-status-codes": "^2.3.0",
"lodash-es": "^4.18.1",
"lucide-react": "^0.577.0",
"mermaid": "^11.16.0",
"minisearch": "^7.2.0",
"nitro": "3.0.260610-beta",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'
import { useLocation } from 'react-router'
import type { ReactNode } from 'react'
import type { AnalyticsConfig } from '@/types'
import type { AnalyticsInstance } from 'analytics'
import type { AnalyticsInstance, AnalyticsPlugin } from 'analytics'

function PageViewTracker({ analytics }: { analytics: AnalyticsInstance }) {
const { pathname } = useLocation()
Expand Down Expand Up @@ -35,7 +35,7 @@ export function AnalyticsProvider({

const init = async () => {
try {
const plugins: unknown[] = []
const plugins: AnalyticsPlugin[] = []
if (config.googleAnalytics?.measurementId) {
const { default: googleAnalytics } = await import('@analytics/google-analytics')
plugins.push(
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/api/ApiSkeleton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function ApiFullSkeleton() {
<Flex className={layoutStyles.body}>
<Sidebar
defaultOpen
collapsible={false}
collapsible='none'
className={cx(layoutStyles.sidebar, apiLayoutStyles.sidebar)}
>
<Sidebar.Header className={layoutStyles.sidebarHeader}>
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/api/api-field-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useState, type ReactNode } from 'react'
import { Badge, Flex } from '@raystack/apsara'
import { ChevronRightIcon, ChevronDownIcon } from '@radix-ui/react-icons'
import { ChevronDownIcon, ChevronRightIcon } from '@/components/ui/icons';
import type { SchemaField } from '@/lib/schema'
import styles from './api-field-list.module.css'

Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/api/api-overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { useState } from 'react'
import type { OpenAPIV3 } from 'openapi-types'
import { Flex, Button, Menu, CopyButton, Separator } from '@raystack/apsara'
import { ChevronDownIcon } from '@radix-ui/react-icons'
import { ChevronDownIcon } from '@/components/ui/icons';
import { MethodBadge } from '@/components/api/method-badge'
import { ApiCodeSnippet } from './api-code-snippet'
import { ApiResponsePanel } from './api-response-panel'
Expand Down
9 changes: 4 additions & 5 deletions packages/chronicle/src/components/api/playground-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import { useState, useCallback, useMemo, useEffect } from 'react'
import type { OpenAPIV3 } from 'openapi-types'
import { Dialog, Button, Badge, IconButton, Input, CopyButton, Select, Menu } from '@raystack/apsara'
import { Cross2Icon, ChevronDownIcon, ChevronUpIcon, PlayIcon, PlusIcon } from '@radix-ui/react-icons'
import { CounterClockwiseClockIcon, CodeIcon } from '@radix-ui/react-icons'
import { ChevronDownIcon, ChevronUpIcon, CodeIcon, HistoryIcon, PlayIcon, PlusIcon, XIcon } from '@/components/ui/icons';
import { MethodBadge } from '@/components/api/method-badge'
import { flattenSchema, generateExampleJson, toKind, type SchemaField } from '@/lib/schema'
import { generateCurl } from '@/lib/snippet-generators'
Expand Down Expand Up @@ -289,10 +288,10 @@ export function PlaygroundDialog({
<span className={styles.actionNavTitle}>{operation.summary ?? `${method} ${path}`}</span>
<div style={{ display: 'flex', alignItems: 'center', gap: 'var(--rs-space-3)' }}>
<IconButton size={2} onClick={handleReset} aria-label="Reset">
<CounterClockwiseClockIcon />
<HistoryIcon />
</IconButton>
<IconButton size={2} onClick={() => onOpenChange(false)} aria-label="Close">
<Cross2Icon />
<XIcon />
</IconButton>
</div>
</div>
Expand Down Expand Up @@ -586,7 +585,7 @@ function BodyFieldRow({ field, value, onChange }: {
/>
</div>
<IconButton size={2} onClick={() => onChange(items.filter((_, j) => j !== i))} aria-label="Remove item">
<Cross2Icon />
<XIcon />
</IconButton>
</div>
))}
Expand Down
4 changes: 4 additions & 0 deletions packages/chronicle/src/components/common/callout.module.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
/* Apsara sizes a Callout at 400px by default. Prose callouts should fill the
content column instead. This used to be the component's `width` prop, which
apsara 1.6 dropped. */
.callout {
margin: var(--rs-space-5) 0;
width: 100%;
}

.callout p:last-child {
Expand Down
4 changes: 2 additions & 2 deletions packages/chronicle/src/components/common/callout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Callout } from '@raystack/apsara'
import styles from './callout.module.css'

function CalloutContainer(props: React.ComponentProps<typeof Callout>) {
return <Callout outline width="100%" className={styles.callout} {...props} />
return <Callout variant="outline" className={styles.callout} {...props} />
}

function CalloutTitle({ children }: { children: React.ReactNode }) {
Expand All @@ -18,7 +18,7 @@ function CalloutDescription({ children }: { children: React.ReactNode }) {

function MdxBlockquote(props: React.ComponentProps<'blockquote'>) {
return (
<Callout type="grey" outline width="100%" className={styles.callout}>
<Callout type="grey" variant="outline" className={styles.callout}>
{props.children}
</Callout>
)
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/ui/breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function Breadcrumbs({ slug, tree, className }: BreadcrumbsProps) {
<Breadcrumb.Item
key={`item-${index}`}
current={isCurrent}
render={isCurrent ? undefined : <RouterLink to={item.url} />}
render={isCurrent || !item.url ? undefined : <RouterLink to={item.url} />}
>
{item.name}
</Breadcrumb.Item>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import { MoonIcon, SunIcon } from '@heroicons/react/24/outline'
import { MoonIcon, SunIcon } from '@/components/ui/icons';
import { IconButton, useTheme } from '@raystack/apsara'
import { useEffect, useState } from 'react'

Expand Down
79 changes: 79 additions & 0 deletions packages/chronicle/src/components/ui/icons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* Chronicle's icon set.
*
* Every icon is a Lucide drawing, the same family Apsara draws with. Import
* icons from here rather than from `lucide-react` directly, so one idea keeps
* one drawing across the whole site.
*
* Icons Apsara already ships are re-exported under Apsara's own key, so a
* `<Theme icons>` override reaches Apsara's components and Chronicle's pages
* alike. The rest are built with `createIcon`, which gives them the same 16px
* frame, the same 1.5 stroke, and the same `data-icon` attribute.
*/
export {
ChevronDownIcon,
ChevronRightIcon,
/** Copies the page as markdown. */
CopyIcon,
/** A documentation page. */
FileTextIcon,
MoonIcon,
PlusIcon,
SearchIcon,
SunIcon,
/** An error state. Draws a warning triangle. */
WarningIcon,
/** Closes a dialog or panel. */
XIcon
} from '@raystack/apsara/icons';

import { createIcon } from '@raystack/apsara/icons';
import {
AlignLeft,
ArrowLeft,
ArrowRight,
BookOpen,
ChevronUp,
CircleQuestionMark,
Code,
Eye,
File,
Folder,
Hash,
History,
Layers,
Menu,
Play,
Sparkles,
SlidersHorizontal,
SquareCode
} from 'lucide-react';

/** An API reference section. */
export const ApiIcon = createIcon('ApiIcon', SquareCode);
export const ArrowLeftIcon = createIcon('ArrowLeftIcon', ArrowLeft);
export const ArrowRightIcon = createIcon('ArrowRightIcon', ArrowRight);
export const BookOpenIcon = createIcon('BookOpenIcon', BookOpen);
export const ChevronUpIcon = createIcon('ChevronUpIcon', ChevronUp);
/** A code block or an API endpoint. */
export const CodeIcon = createIcon('CodeIcon', Code);
export const EyeIcon = createIcon('EyeIcon', Eye);
/** A page with no text match — the fallback search result. */
export const FileIcon = createIcon('FileIcon', File);
export const FolderIcon = createIcon('FolderIcon', Folder);
/** A heading match in search results. */
export const HashIcon = createIcon('HashIcon', Hash);
export const HelpIcon = createIcon('HelpIcon', CircleQuestionMark);
/** Recent requests in the API playground. */
export const HistoryIcon = createIcon('HistoryIcon', History);
export const LayersIcon = createIcon('LayersIcon', Layers);
/** Opens the mobile navigation. */
export const MenuIcon = createIcon('MenuIcon', Menu);
/** Sends a request in the API playground. */
export const PlayIcon = createIcon('PlayIcon', Play);
/** Reader display settings. */
export const SettingsIcon = createIcon('SettingsIcon', SlidersHorizontal);
/** Marks an AI affordance. Shares a drawing with Apsara's `CoPilotIcon`. */
export const SparklesIcon = createIcon('SparklesIcon', Sparkles);
/** Opens the table of contents. */
export const TocIcon = createIcon('TocIcon', AlignLeft);
18 changes: 6 additions & 12 deletions packages/chronicle/src/components/ui/search.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import {
DocumentIcon,
HashtagIcon,
MagnifyingGlassIcon,
CodeBracketIcon,
ChevronRightIcon
} from '@heroicons/react/24/outline';
import { ChevronRightIcon, CodeIcon, FileIcon, HashIcon, SearchIcon } from '@/components/ui/icons';
import { Command, IconButton, Text } from '@raystack/apsara';
import { keepPreviousData, useQuery } from '@tanstack/react-query';
import GithubSlugger from 'github-slugger';
Expand Down Expand Up @@ -201,7 +195,7 @@ export function Search({ classNames }: SearchProps) {
onClick={() => setOpen(true)}
className={classNames?.trigger}
>
<MagnifyingGlassIcon width={16} height={16} />
<SearchIcon width={16} height={16} />
</IconButton>
);
}
Expand Down Expand Up @@ -277,7 +271,7 @@ export function SearchDialog() {
<Command items={displayResults}>
<Command.Input
placeholder='Search'
leadingIcon={<MagnifyingGlassIcon width={16} height={16} />}
leadingIcon={<SearchIcon width={16} height={16} />}
value={search}
onChange={onSearchChange}
className={styles.input}
Expand Down Expand Up @@ -405,12 +399,12 @@ function HighlightQuery({ text, query }: { text: string; query: string }) {

function getResultIcon(result: SearchResult): React.ReactNode {
if (result.url.startsWith('/apis/')) {
return <CodeBracketIcon className={styles.icon} />;
return <CodeIcon className={styles.icon} />;
}
if (result.match === SearchMatchType.Heading) {
return <HashtagIcon className={styles.icon} />;
return <HashIcon className={styles.icon} />;
}
return <DocumentIcon className={styles.icon} />;
return <FileIcon className={styles.icon} />;
}

function getPageTitle(url: string): string {
Expand Down
4 changes: 2 additions & 2 deletions packages/chronicle/src/components/ui/sidebar-links.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import { QuestionMarkCircledIcon } from '@radix-ui/react-icons'
import { HelpIcon } from '@/components/ui/icons';
import { IconButton, Menu, Sidebar } from '@raystack/apsara'
import { useNavigate } from 'react-router'
import { usePageContext } from '@/lib/page-context'
Expand Down Expand Up @@ -86,7 +86,7 @@ export function SidebarLinks({ variant = 'menu' }: SidebarLinksProps) {
<IconButton size={3} aria-label='Links' className={styles.trigger} />
}
>
<QuestionMarkCircledIcon width={16} height={16} />
<HelpIcon width={16} height={16} />
</Menu.Trigger>
<Menu.Content side='top' align='end'>
{links.map(link => (
Expand Down
6 changes: 5 additions & 1 deletion packages/chronicle/src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ export function loadConfig(): ChronicleConfig {
return {
...defaultConfig,
...parsed,
theme: { ...defaultConfig.theme, ...parsed.theme },
theme: {
...defaultConfig.theme,
...parsed.theme,
name: parsed.theme?.name ?? defaultConfig.theme?.name ?? 'default',
},
search: { ...defaultConfig.search, ...parsed.search },
}
}
Expand Down
10 changes: 0 additions & 10 deletions packages/chronicle/src/lib/get-llm-text.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/chronicle/src/lib/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ function convertV2SecurityDefs(defs: Record<string, OpenAPIV2.SecuritySchemeObje
const result: Record<string, OpenAPIV3.SecuritySchemeObject> = {}
for (const [name, def] of Object.entries(defs)) {
if (def.type === 'apiKey') {
result[name] = { type: 'apiKey', name: (def as JsonObject).name as string, in: def.in as string } as OpenAPIV3.ApiKeySecurityScheme
result[name] = { type: 'apiKey', name: def.name, in: def.in } as OpenAPIV3.ApiKeySecurityScheme
} else if (def.type === 'basic') {
result[name] = { type: 'http', scheme: 'basic' } as OpenAPIV3.HttpSecurityScheme
} else if (def.type === 'oauth2') {
Expand Down
21 changes: 13 additions & 8 deletions packages/chronicle/src/lib/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,22 @@ function buildSyntheticMeta(): {
return entries;
}

let cachedSource: ReturnType<typeof loader> | null = null;
// Built through a named factory so the cache keeps the loader's concrete
// type. `ReturnType<typeof loader>` would widen it to the default type
// arguments, which then fails to match what `loader()` actually returned.
function createSource() {
return loader({
source: { files: buildFiles() },
baseUrl: '/'
});
}

let cachedSource: ReturnType<typeof createSource> | null = null;
let cachedTree: Root | null = null;
let cachedNavMap: Map<string, PageNav> | null = null;

async function getSource() {
if (cachedSource) return cachedSource;
const files = buildFiles();
cachedSource = loader({
source: { files },
baseUrl: '/'
});
async function getSource(): Promise<ReturnType<typeof createSource>> {
cachedSource ??= createSource();
return cachedSource;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/lib/tree-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ describe('compactTree', () => {
const result = compactTree(tree)
expect(result.children[0]).toEqual({
type: 'page', name: 'Space Packet Protocol', short: 'SPP', url: '/protocols/spp',
})
} as Node)
})

test('keeps short on a folder index page', () => {
Expand Down
Loading
Loading