Skip to content

Commit 243cdbf

Browse files
committed
feat: add article toc title length limit
1 parent a67bd60 commit 243cdbf

6 files changed

Lines changed: 47 additions & 1 deletion

File tree

_config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ articles:
318318
number: false # Whether to add number to TOC automatically
319319
expand: true # Whether to expand TOC
320320
init_open: true # Open toc by default
321+
title_max_length: 40 # Hide the article title in the TOC when it exceeds this length
321322
# Whether to enable copyright notice
322323
copyright:
323324
enable: true # Whether to enable

docs/content/docs/en/posts/articles.mdx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,17 @@ Whether to default open the table of contents.
277277
| :-----: | :-------------: | :-----------: |
278278
| Boolean | `true \| false` | `true` |
279279

280+
### Article Title Maximum Length
281+
282+
**Configuration Item: `articles.toc.title_max_length`**
283+
284+
The article title is omitted from the table of contents when it exceeds this
285+
number of characters. Set it to `0` to always omit the title.
286+
287+
| Type | Possible Values | Default Value |
288+
| :---: | :---: | :---: |
289+
| Number | `0` or greater | `40` |
290+
280291
## Article Copyright
281292

282293
### Toggle

docs/content/docs/zh/posts/articles.mdx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,16 @@ npm install hexo-wordcount
270270
| :---: | :---: | :---: |
271271
| 布尔值 | `true \| false` | `true` |
272272

273+
### 文章标题最大长度
274+
275+
**配置项名称:`articles.toc.title_max_length`**
276+
277+
当文章标题超过此字符数时,不在目录中显示文章标题。设置为 `0` 可始终隐藏标题。
278+
279+
| 类型 | 可选值 | 默认值 |
280+
| :---: | :---: | :---: |
281+
| 数字 | `0` 或更大 | `40` |
282+
273283
## 文章版权
274284

275285
### 开关

layout/pages/post/toc.ejs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
<%
2+
const configuredTitleMaxLength = theme.articles.toc.title_max_length;
3+
const titleMaxLength = Number.isInteger(configuredTitleMaxLength) && configuredTitleMaxLength >= 0
4+
? configuredTitleMaxLength
5+
: 40;
6+
const showTitle = page.title && [...String(page.title)].length <= titleMaxLength;
7+
%>
18
<div class="box-border w-full">
29
<div class="mb-1 text-xs font-medium text-rd-gray-1000"><%- __('toc') %></div>
3-
<div class="mb-2.5 text-lg leading-normal font-bold whitespace-normal text-rd-gray-1000"><%= page.title %></div>
10+
<% if (showTitle) { %>
11+
<div class="mb-2.5 text-lg leading-normal font-bold whitespace-normal text-rd-gray-1000"><%= page.title %></div>
12+
<% } %>
413
<%- toc(page.content, {
514
class: 'nav',
615
list_number: theme.articles.toc.number,

tests/fixtures/optional-theme-config.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ theme_config:
1414
style:
1515
delete_mask: true
1616
image_caption: true
17+
toc:
18+
title_max_length: 0
1719
code_block:
1820
highlight_theme:
1921
light: atom-one-light

tests/theme-generation.test.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ const includes = (output, values) => {
1717
const borderedPageTitle =
1818
'<h1 class="text-4xl mt-4 mb-8 font-medium font-display tracking-tight border-b border-rd-gray-alpha-400 pb-2">';
1919

20+
const getArticleToc = (output) =>
21+
output.match(/<aside id="article-toc"[\s\S]*?<\/aside>/)?.[0] || "";
22+
2023
const readTemplates = (directory) => fs.readdirSync(directory, { withFileTypes: true })
2124
.flatMap((entry) => {
2225
const entryPath = path.join(directory, entry.name);
@@ -88,6 +91,15 @@ test("theme build and generation configurations", async (t) => {
8891
assert.ok(outputExists("css/build/theme.css"));
8992
});
9093

94+
await t.test("article TOC omits titles above the configured length", () => {
95+
const shortTitleToc = getArticleToc(readOutput("2022/10/02/theme-demo/index.html"));
96+
const longTitleToc = getArticleToc(readOutput("2024/01/17/super-long-title-test/index.html"));
97+
98+
assert.ok(shortTitleToc.includes("主题样式 Demo"));
99+
assert.ok(!longTitleToc.includes("This is an extremely long title"));
100+
assert.ok(longTitleToc.includes("Super Long Title Test"));
101+
});
102+
91103
await t.test("archive renders an unframed semantic timeline", () => {
92104
const archive = readOutput("archives/index.html");
93105
includes(archive, [
@@ -199,6 +211,7 @@ test("theme build and generation configurations", async (t) => {
199211
const nested = readOutput("2026/08/06/tab-folding-nesting-test/index.html");
200212
includes(home, ['id="local-search"', 'id="reading-progress"', 'id="preloader"', 'id="aplayer"']);
201213
includes(writing, ["data-writing-button", 'data-lazy-state="pending"']);
214+
assert.ok(!getArticleToc(writing).includes("主题样式 Demo"));
202215
includes(nested, ["data-tabs", 'role="tabpanel"', 'class="folding']);
203216
});
204217

0 commit comments

Comments
 (0)