-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ New table of contents directive (#1826)
- Loading branch information
Showing
13 changed files
with
786 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
'myst-directives': patch | ||
'myst-transforms': patch | ||
'myst-cli': patch | ||
--- | ||
|
||
New TOC directive |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import type { SiteManifest } from 'myst-config'; | ||
import { castSession } from '../../session/cache.js'; | ||
import type { ISession } from '../../session/types.js'; | ||
import { selectors } from '../../store/index.js'; | ||
import { fileTitle } from '../../utils/fileInfo.js'; | ||
import type { PageFrontmatter } from 'myst-frontmatter'; | ||
|
||
export type ManifestProject = Required<SiteManifest>['projects'][0]; | ||
|
||
export async function manifestPagesFromProject(session: ISession, projectPath: string) { | ||
const state = session.store.getState(); | ||
const proj = selectors.selectLocalProject(state, projectPath); | ||
if (!proj) return []; | ||
const cache = castSession(session); | ||
const pages = await Promise.all( | ||
proj.pages.map(async (page) => { | ||
if ('file' in page) { | ||
const fileInfo = selectors.selectFileInfo(state, page.file); | ||
const title = fileInfo.title || fileTitle(page.file); | ||
const short_title = fileInfo.short_title ?? undefined; | ||
const description = fileInfo.description ?? ''; | ||
const thumbnail = fileInfo.thumbnail ?? ''; | ||
const thumbnailOptimized = fileInfo.thumbnailOptimized ?? ''; | ||
const banner = fileInfo.banner ?? ''; | ||
const bannerOptimized = fileInfo.bannerOptimized ?? ''; | ||
const date = fileInfo.date ?? ''; | ||
const tags = fileInfo.tags ?? []; | ||
const { slug, level, file } = page; | ||
const { frontmatter } = cache.$getMdast(file)?.post ?? {}; | ||
const projectPage: ManifestProject['pages'][0] = { | ||
slug, | ||
title, | ||
short_title, | ||
description, | ||
date, | ||
thumbnail, | ||
thumbnailOptimized, | ||
banner, | ||
bannerOptimized, | ||
tags, | ||
level, | ||
enumerator: frontmatter?.enumerator, | ||
}; | ||
return projectPage; | ||
} | ||
return { ...page }; | ||
}), | ||
); | ||
return pages; | ||
} | ||
|
||
export function manifestTitleFromProject(session: ISession, projectPath: string) { | ||
const state = session.store.getState(); | ||
const projConfig = selectors.selectLocalProjectConfig(state, projectPath); | ||
if (projConfig?.title) return projConfig.title; | ||
const proj = selectors.selectLocalProject(state, projectPath); | ||
if (!proj) return 'Untitled'; | ||
const projectFileInfo = selectors.selectFileInfo(session.store.getState(), proj.file); | ||
return projectFileInfo.title || proj.index || 'Untitled'; | ||
} | ||
|
||
export function indexFrontmatterFromProject( | ||
session: ISession, | ||
projectPath: string, | ||
): PageFrontmatter { | ||
const state = session.store.getState(); | ||
const cache = castSession(session); | ||
const proj = selectors.selectLocalProject(state, projectPath); | ||
if (!proj) return {}; | ||
const { file } = proj; | ||
const { frontmatter } = cache.$getMdast(file)?.post ?? {}; | ||
return frontmatter ?? {}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import type { VFile } from 'vfile'; | ||
import { type DirectiveSpec, type DirectiveData, type GenericNode, fileError } from 'myst-common'; | ||
import { addCommonDirectiveOptions, commonDirectiveOptions } from './utils.js'; | ||
|
||
const CONTEXTS = ['project', 'page', 'section']; | ||
|
||
export const tocDirective: DirectiveSpec = { | ||
name: 'toc', | ||
doc: 'Inserts table of contents in the page. This may be for the project (each page has an entry), the current page (each heading has an entry), or the current section (only headings in the section have an entry).', | ||
alias: ['tableofcontents', 'table-of-contents', 'toctree', 'contents'], | ||
arg: { | ||
type: 'myst', | ||
doc: 'Heading to be included with table of contents', | ||
}, | ||
options: { | ||
context: { | ||
type: String, | ||
doc: 'Table of Contents context; one of project, page, or section', | ||
alias: ['kind'], | ||
}, | ||
depth: { | ||
type: Number, | ||
doc: 'Number of levels to include in Table of Contents; by default, all levels will be included', | ||
alias: ['maxdepth'], | ||
}, | ||
...commonDirectiveOptions('toc'), | ||
}, | ||
run(data: DirectiveData, vfile: VFile): GenericNode[] { | ||
let context = data.options?.context | ||
? (data.options.context as string) | ||
: data.name === 'contents' | ||
? 'section' | ||
: 'project'; | ||
if (!CONTEXTS.includes(context)) { | ||
fileError(vfile, `Unknown context for ${data.name} directive: ${context}`); | ||
context = 'project'; | ||
} | ||
let depth = data.options?.depth as number | undefined; | ||
if (depth != null && depth < 1) { | ||
fileError(vfile, `Table of Contents 'depth' must be a number greater than 0`); | ||
depth = undefined; | ||
} | ||
const children: GenericNode[] = []; | ||
if (data.arg) { | ||
const parsedArg = data.arg as GenericNode[]; | ||
if (parsedArg[0]?.type === 'heading') { | ||
children.push(...parsedArg); | ||
} else { | ||
children.push({ | ||
type: 'heading', | ||
depth: 2, | ||
enumerated: false, | ||
children: parsedArg, | ||
}); | ||
} | ||
} | ||
const toc = { type: 'toc', kind: context, depth, children }; | ||
addCommonDirectiveOptions(data, toc); | ||
return [toc]; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.