Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/opt-in-reading-time.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@doc-kit/generator-react': minor
---

Make reading time opt-in via `showReadingTime`
4 changes: 3 additions & 1 deletion packages/react/src/html/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,9 @@ export default ({ metadata }) => (
- `metadata` {Object} Serialized page metadata — all YAML frontmatter properties
plus `addedIn`, `basename`, `path`, and any custom user-defined fields.
- `headings` {Array} Pre-computed table of contents heading entries.
- `readingTime` {string} Estimated reading time (e.g. `'5 min read'`).
- `readingTime` {string|undefined} Estimated reading time (e.g. `'5 min read'`).
Only present when the `jsx-ast` generator's `showReadingTime` option is
enabled.
- `children` {ComponentChildren} Processed page content.

The `Layout` component receives the props above. Custom Layout components can use
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/html/ui/components/Layout/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import SideBar from '#theme/Sidebar';
* main content, meta bar, and footer. Override via `#theme/Layout` in your
* configuration's `imports` to customize the entire page structure.
*
* @param {{ metadata: import('../../types').SerializedMetadata, headings: Array, readingTime: string, children: import('preact').ComponentChildren }} props
* @param {{ metadata: import('../../types').SerializedMetadata, headings: Array, readingTime?: string, children: import('preact').ComponentChildren }} props
*/
export default ({ metadata, headings, readingTime, children }) => {
const crossLinkItems = navigation.showCrossLinks
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/html/ui/components/MetaBar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const HeadingValue = ({ value, stability }) => {

/**
* MetaBar component that displays table of contents and page metadata
* @param {{ metadata: import('../../types').SerializedMetadata, headings: Array, readingTime: string }} props
* @param {{ metadata: import('../../types').SerializedMetadata, headings: Array, readingTime?: string }} props
*/
export default ({ metadata, headings = [], readingTime }) => {
const editThisPage = editURL?.replace('{path}', metadata.path);
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/jsx-ast/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The `jsx-ast` generator converts MDAST (Markdown Abstract Syntax Tree) to JSX AS
for `all.html`. **Default:** `true`.
- `generateNotFoundPage` {boolean} When `true`, creates a synthetic JSX AST
entry for `404.html`. **Default:** `true`.
- `showReadingTime` {boolean} When `true`, computes an estimated reading time
for each page and displays it in the MetaBar. **Default:** `false`.

## Index page

Expand Down
1 change: 1 addition & 0 deletions packages/react/src/jsx-ast/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default {
ref: 'main',
generateAllPage: true,
generateNotFoundPage: true,
showReadingTime: false,
},

hasParallelProcessor: true,
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/jsx-ast/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export type Generator = GeneratorMetadata<
ref: string;
generateAllPage: boolean;
generateNotFoundPage: boolean;
showReadingTime: boolean;
},
Generate<Array<MetadataEntry>, AsyncGenerator<JSXContent>>,
ProcessChunk<
Expand Down
17 changes: 13 additions & 4 deletions packages/react/src/jsx-ast/utils/buildContent.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { UNIST } from '@doc-kit/core/utils/queries/index.mjs';
import { transformNodesToString } from '@doc-kit/core/utils/unist.mjs';
import { h as createElement } from 'hastscript';
import { slice } from 'mdast-util-slice-markdown';
import readingTime from 'reading-time';
import remarkParse from 'remark-parse';
import { unified } from 'unified';
import { u as createTree } from 'unist-builder';
Expand Down Expand Up @@ -50,6 +49,12 @@ const toPlainText = markdown =>
unified().use(remarkParse).parse(markdown).children
).trim();

/**
*
*/
const readingTime = text =>
import('reading-time').then(({ default: rt }) => rt(text).text);

/**
* Processes lifecycle and change history data into a sorted array of change entries.
* @param {import('@doc-kit/core/generators/metadata/types').MetadataEntry} entry - The metadata entry
Expand Down Expand Up @@ -315,16 +320,20 @@ export const processEntry = entry => {
* @param {Array<import('@doc-kit/core/generators/metadata/types').MetadataEntry>} entries - API documentation metadata entries
* @param {Object} metadata - Raw page metadata from the head entry
*/
export const createDocumentLayout = (entries, metadata) => {
export const createDocumentLayout = async (entries, metadata) => {
// Collapse overloaded function headings into one stable ToC entry, tagging the
// underlying headings with compact anchors / overload flags read just below.
annotateOverloads(entries);

const { showReadingTime } = getConfig('jsx-ast');

return createTree('root', [
createJSXElement(JSX_IMPORTS.Layout.name, {
metadata,
headings: extractHeadings(entries),
readingTime: readingTime(extractTextContent(entries)).text,
readingTime: showReadingTime
? await readingTime(extractTextContent(entries))
: undefined,
children: entries.map(processEntry),
}),
]);
Expand All @@ -348,7 +357,7 @@ const buildContent = async (metadataEntries, head) => {
]);

// Create root document AST with all layout components and processed content
const root = createDocumentLayout(metadataEntries, metadata);
const root = await createDocumentLayout(metadataEntries, metadata);

// Run remark processor to transform AST (parse markdown, plugins, etc.)
const ast = await remark().run(root);
Expand Down
Loading