diff --git a/CHANGELOG.md b/CHANGELOG.md index a003f7593..83206f526 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,21 @@ # Unreleased +### Features + +- Added `headings` option to control optional headings, #2729. +- Added a folder icon to page navigation elements which are not links, #2741. + ### Bug Fixes - `externalSymbolLinkMappings` now uses the TypeScript reported link target if available, #2725. - TypeDoc will no longer omit the modules page if a project contains only modules/documents, #2730. - Fixed missing breadcrumbs on project page, #2728. +- TypeDoc will no longer render an empty readme page if no readme was found. + +### Thanks! + +- @lriggle-strib +- @mrfigg ## v0.26.8 (2024-10-04) diff --git a/scripts/build_themes.js b/scripts/build_themes.js index d1b255b72..ca847f1d3 100644 --- a/scripts/build_themes.js +++ b/scripts/build_themes.js @@ -2,7 +2,7 @@ const esbuild = require("esbuild"); const fs = require("fs"); -const watch = process.argv.slice(2).includes("--watch"); +const watch = process.argv.slice(2).some((t) => t == "--watch" || t == "-w"); // It's convenient to be able to build the themes in watch mode without rebuilding the whole docs // to test some change to the frontend JS. diff --git a/src/lib/internationalization/locales/zh.cts b/src/lib/internationalization/locales/zh.cts index e22152b61..0dbd39a69 100644 --- a/src/lib/internationalization/locales/zh.cts +++ b/src/lib/internationalization/locales/zh.cts @@ -287,6 +287,7 @@ export = buildIncompleteTranslation({ help_sidebarLinks: "定义要包含在侧边栏中的链接", help_navigationLeaves: "导航树中不应扩展的分支", help_navigation: "确定导航侧边栏的组织方式", + help_headings: "确定标题是否需要被渲染", help_visibilityFilters: "根据修饰符标签指定内置过滤器和附加过滤器的默认可见性", help_searchCategoryBoosts: "配置搜索以提高所选类别的相关性", diff --git a/src/lib/internationalization/translatable.ts b/src/lib/internationalization/translatable.ts index 0d5c32aab..52c014bcf 100644 --- a/src/lib/internationalization/translatable.ts +++ b/src/lib/internationalization/translatable.ts @@ -300,6 +300,7 @@ export const translatable = { help_navigationLeaves: "Branches of the navigation tree which should not be expanded", help_navigation: "Determines how the navigation sidebar is organized", + help_headings: "Determines which optional headings are rendered", help_visibilityFilters: "Specify the default visibility for builtin filters and additional filters according to modifier tags", help_searchCategoryBoosts: diff --git a/src/lib/output/themes/default/DefaultTheme.tsx b/src/lib/output/themes/default/DefaultTheme.tsx index 622ccab44..1a58fd514 100644 --- a/src/lib/output/themes/default/DefaultTheme.tsx +++ b/src/lib/output/themes/default/DefaultTheme.tsx @@ -205,7 +205,7 @@ export class DefaultTheme extends Theme { const urls: UrlMapping[] = []; this.sluggers.set(project, new Slugger()); - if (!hasReadme(this.application.options.getValue("readme"))) { + if (!project.readme?.length) { project.url = "index.html"; urls.push(new UrlMapping("index.html", project, this.reflectionTemplate)); } else { @@ -507,10 +507,6 @@ export class DefaultTheme extends Theme { } } -function hasReadme(readme: string) { - return !readme.endsWith("none"); -} - function getReflectionClasses( reflection: DeclarationReflection | DocumentReflection, filters: Record, diff --git a/src/lib/output/themes/default/assets/typedoc/Navigation.ts b/src/lib/output/themes/default/assets/typedoc/Navigation.ts index 5c6a4f682..a5e15435b 100644 --- a/src/lib/output/themes/default/assets/typedoc/Navigation.ts +++ b/src/lib/output/themes/default/assets/typedoc/Navigation.ts @@ -103,7 +103,8 @@ function addNavText( } a.appendChild(document.createElement("span")).textContent = el.text; } else { - parent.appendChild(document.createElement("span")).textContent = - el.text; + const span = parent.appendChild(document.createElement("span")); + span.innerHTML = ``; + span.appendChild(document.createElement("span")).textContent = el.text; } } diff --git a/src/lib/output/themes/default/partials/header.tsx b/src/lib/output/themes/default/partials/header.tsx index 429dc76a3..dedfe375b 100644 --- a/src/lib/output/themes/default/partials/header.tsx +++ b/src/lib/output/themes/default/partials/header.tsx @@ -2,19 +2,39 @@ import { classNames, getDisplayName, hasTypeParameters, join } from "../../lib"; import { JSX } from "../../../../utils"; import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext"; import type { PageEvent } from "../../../events"; -import { type Reflection, ReflectionKind } from "../../../../models"; +import type { Reflection } from "../../../../models"; export const header = (context: DefaultThemeRenderContext, props: PageEvent) => { - const HeadingLevel = props.model.isProject() ? "h2" : "h1"; + const opts = context.options.getValue("headings"); + + // Don't render on the index page or the class hierarchy page + // We should probably someday render on the class hierarchy page, but currently breadcrumbs + // are entirely dependent on the reflection hierarchy, so it doesn't make sense today. + const renderBreadcrumbs = props.url !== "index.html" && props.url !== "hierarchy.html"; + + // Titles are always rendered on DeclarationReflection pages and the modules page for the project. + // They are also rendered on the readme + document pages if configured to do so by the user. + let renderTitle: boolean; + let titleKindString = ""; + if (props.model.isProject()) { + if (props.url === "index.html" && props.model.readme?.length) { + renderTitle = opts.readme; + } else { + renderTitle = true; + } + } else if (props.model.isDocument()) { + renderTitle = opts.document; + } else { + renderTitle = true; + titleKindString = " " + context.internationalization.kindSingularString(props.model.kind); + } + return (
- {props.url !== "index.html" && props.url !== "hierarchy.html" && ( -
    {context.breadcrumb(props.model)}
- )} - {!props.model.isDocument() && ( - - {props.model.kind !== ReflectionKind.Project && - `${context.internationalization.kindSingularString(props.model.kind)} `} + {renderBreadcrumbs &&
    {context.breadcrumb(props.model)}
} + {renderTitle && ( +

+ {titleKindString} {getDisplayName(props.model)} {hasTypeParameters(props.model) && ( <> @@ -24,7 +44,7 @@ export const header = (context: DefaultThemeRenderContext, props: PageEvent )} {context.reflectionFlags(props.model)} - +

)}
); diff --git a/src/lib/output/themes/default/partials/icon.tsx b/src/lib/output/themes/default/partials/icon.tsx index 2ed387c18..fcd0834e3 100644 --- a/src/lib/output/themes/default/partials/icon.tsx +++ b/src/lib/output/themes/default/partials/icon.tsx @@ -47,7 +47,7 @@ export function buildRefIcons JSX.Element>>( } export const icons: Record< - ReflectionKind | "chevronDown" | "checkbox" | "menu" | "search" | "chevronSmall" | "anchor", + ReflectionKind | "chevronDown" | "checkbox" | "menu" | "search" | "chevronSmall" | "anchor" | "folder", () => JSX.Element > = { [ReflectionKind.Accessor]: () => @@ -282,14 +282,21 @@ export const icons: Record< ), [ReflectionKind.Document]: () => kindIcon( - - - + + + , "var(--color-document)", ), + folder: () => + kindIcon( + + + , + "var(--color-document)", + ), chevronDown: () => ( ) { }, }); + options.addDeclaration({ + name: "headings", + help: (i18n) => i18n.help_headings(), + type: ParameterType.Flags, + defaults: { + readme: true, + document: false, + }, + }); + options.addDeclaration({ name: "visibilityFilters", help: (i18n) => i18n.help_visibilityFilters(),