Skip to content

Commit 9597746

Browse files
committed
♻️ use page to implement changelog sidebar instead
1 parent e5a640a commit 9597746

File tree

7 files changed

+95
-17
lines changed

7 files changed

+95
-17
lines changed

packages/plugin-changelog/src/index.ts

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
getChunkContent,
99
getChunkFilename,
1010
getChunkTitle,
11+
getPaginator,
1112
} from "./utils";
1213

1314
import type {
@@ -16,12 +17,14 @@ import type {
1617
Plugin,
1718
} from "@docusaurus/types";
1819
import type { Options, PluginOptions } from "./options";
20+
import type { ChangelogChunk } from "./types";
1921

2022
export const HEADER = `---
21-
sidebar_position: {{position}}
2223
{{extraHeader}}
2324
---
2425
26+
import DocPaginator from "@theme/DocPaginator"
27+
2528
# {{chunkTitle}}
2629
`;
2730

@@ -48,6 +51,35 @@ ${content}
4851
};
4952
}
5053

54+
export async function getChangelogItems(
55+
changelogPath: string,
56+
changelogPerPage: number,
57+
): Promise<ChangelogChunk> {
58+
const fileContent = await fs.readFile(changelogPath, "utf-8");
59+
const sections = fileContent
60+
.split(/(?=\n## )/)
61+
.map(processSection)
62+
.filter(Boolean);
63+
const chunks = chunkArray(sections, changelogPerPage);
64+
65+
return chunks;
66+
}
67+
68+
export function getChangelogItemsSync(
69+
changelogPath: string,
70+
changelogPerPage: number,
71+
): ChangelogChunk {
72+
// eslint-disable-next-line no-restricted-properties
73+
const fileContent = fs.readFileSync(changelogPath, "utf-8");
74+
const sections = fileContent
75+
.split(/(?=\n## )/)
76+
.map(processSection)
77+
.filter(Boolean);
78+
const chunks = chunkArray(sections, changelogPerPage);
79+
80+
return chunks;
81+
}
82+
5183
export default async function pluginChangelog(
5284
context: LoadContext,
5385
options: PluginOptions,
@@ -56,12 +88,10 @@ export default async function pluginChangelog(
5688
const generateDir = path.join(siteDir, options.changelogDestPath);
5789
const changelogPath = path.join(siteDir, options.changelogPath);
5890

59-
const fileContent = await fs.readFile(changelogPath, "utf-8");
60-
const sections = fileContent
61-
.split(/(?=\n## )/)
62-
.map(processSection)
63-
.filter(Boolean);
64-
const chunks = chunkArray(sections, 10);
91+
const chunks = await getChangelogItems(
92+
changelogPath,
93+
options.changelogPerPage,
94+
);
6595
await Promise.all(
6696
chunks.map((chunk, index) =>
6797
fs.outputFile(
@@ -71,7 +101,7 @@ export default async function pluginChangelog(
71101
HEADER.replaceAll("{{extraHeader}}", options.changelogHeader)
72102
.replaceAll("{{position}}", index.toString())
73103
.replaceAll("{{chunkTitle}}", getChunkTitle(chunk)),
74-
),
104+
) + getPaginator(chunks, index - 1, index + 1),
75105
),
76106
),
77107
);
@@ -83,8 +113,9 @@ export default async function pluginChangelog(
83113

84114
const pluginOptionsSchema = Joi.object<PluginOptions>({
85115
changelogPath: Joi.string().default("src/changelog/changelog.md"),
86-
changelogDestPath: Joi.string().default("docs/changelog"),
116+
changelogDestPath: Joi.string().default("src/pages/changelog"),
87117
changelogHeader: Joi.string().default(""),
118+
changelogPerPage: Joi.number().default(10),
88119
});
89120

90121
export function validateOptions({
@@ -94,4 +125,4 @@ export function validateOptions({
94125
return validate(pluginOptionsSchema, options);
95126
}
96127

97-
export type { Options, PluginOptions };
128+
export type { ChangelogChunk, Options, PluginOptions };

packages/plugin-changelog/src/options.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export type PluginOptions = {
22
changelogPath: string;
33
changelogDestPath: string;
44
changelogHeader: string;
5+
changelogPerPage: number;
56
};
67

78
export type Options = Partial<PluginOptions>;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export type Section = { title: string; content: string } | null;
2+
export type ChangelogChunk = Section[][];

packages/plugin-changelog/src/utils.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
type Section = { title: string; content: string } | null;
1+
import type { Section } from "./types";
22

33
export function chunkArray<T>(array: Array<T>, size: number): Array<Array<T>> {
44
const result = [];
@@ -9,6 +9,34 @@ export function chunkArray<T>(array: Array<T>, size: number): Array<Array<T>> {
99
return result;
1010
}
1111

12+
export function getPaginator(
13+
chunks: Section[][],
14+
prevIdx: number,
15+
nextIdx: number,
16+
): string {
17+
let content = '\n<DocPaginator className="not-prose"';
18+
if (prevIdx >= 0 && prevIdx < chunks.length) {
19+
const chunk = chunks?.[prevIdx]?.[0];
20+
if (chunk) {
21+
const title = prevIdx === 0 ? "" : encodeURIComponent(chunk.title);
22+
content += ` previous={{ title: "${chunk.title}", permalink: "/changelog/${title}" }}`;
23+
}
24+
}
25+
26+
if (nextIdx >= 0 && nextIdx < chunks.length) {
27+
const chunk = chunks?.[nextIdx]?.[0];
28+
if (chunk) {
29+
content += ` next={{ title: "${
30+
chunk.title
31+
}", permalink: "/changelog/${encodeURIComponent(chunk.title)}" }}`;
32+
}
33+
}
34+
35+
content += "/>";
36+
37+
return content;
38+
}
39+
1240
export function getChunkContent(chunk: Section[], header: string): string {
1341
let finalContent = "";
1442
for (const section of chunk) {

website/docs/changelog/.gitignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

website/docusaurus.config.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@ export default async function createConfigAsync() {
7575
[
7676
"@nullbot/docusaurus-plugin-changelog",
7777
{
78-
changelogHeader: `sidebar_custom_props:
79-
sidebar_id: examples`,
78+
changelogHeader: `description: Changelog
79+
toc_max_heading_level: 2
80+
sidebar_custom_props:
81+
sidebar_id: changelog`,
8082
} satisfies ChangelogOptions,
8183
],
8284
],
@@ -143,7 +145,7 @@ export default async function createConfigAsync() {
143145
},
144146
{
145147
label: "Changelog",
146-
to: "/docs/next/changelog",
148+
to: "/changelog",
147149
},
148150
],
149151
},

website/sidebars.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1+
import path from "path";
2+
3+
import { getChangelogItemsSync } from "@nullbot/docusaurus-plugin-changelog";
4+
15
import type { SidebarsConfig } from "@docusaurus/plugin-content-docs";
26

7+
const changelogPath = path.join(__dirname, "src/changelog/changelog.md");
8+
const changelogItems = getChangelogItemsSync(changelogPath, 10);
9+
310
const sidebars: SidebarsConfig = {
411
// By default, Docusaurus generates a sidebar from the docs folder structure
512
main: [
@@ -42,7 +49,16 @@ const sidebars: SidebarsConfig = {
4249
{
4350
type: "category",
4451
label: "Changelog",
45-
items: [{ type: "autogenerated", dirName: "changelog" }],
52+
collapsible: false,
53+
items: changelogItems.map<{ type: "link"; label: string; href: string }>(
54+
(chunk, index) => ({
55+
type: "link",
56+
label: chunk[0]!.title,
57+
href: `/changelog/${
58+
index > 0 ? encodeURIComponent(chunk[0]!.title) : ""
59+
}`,
60+
}),
61+
),
4662
},
4763
],
4864
};

0 commit comments

Comments
 (0)