livemark 0.23.0 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/change-review/SKILL.md +47 -0
- package/{skills/configuration → .agents/skills/livemark-configuration}/SKILL.md +2 -4
- package/build/actions/changelog/build.d.ts +21 -9
- package/build/actions/changelog/build.js +31 -23
- package/build/actions/changelog/build.unit.js +156 -2
- package/build/actions/config/load.js +1 -1
- package/build/actions/config/load.unit.js +1 -1
- package/build/actions/target/build.js +2 -5
- package/build/commands/build.js +1 -1
- package/build/commands/escape.js +1 -1
- package/build/commands/preview.js +1 -1
- package/build/commands/start.js +1 -1
- package/build/components/Abbr.js +2 -2
- package/build/components/Article.js +2 -2
- package/build/components/BlogIndex.js +2 -4
- package/build/components/Callout.js +2 -2
- package/build/components/ChangelogIndex.js +1 -1
- package/build/components/CodeBlock.js +3 -5
- package/build/components/CodeTabs.js +1 -1
- package/build/components/Columns.js +2 -4
- package/build/components/Content.js +2 -2
- package/build/components/ContentTab.js +1 -1
- package/build/components/ContentTabs.js +1 -1
- package/build/components/DefinitionList.js +1 -1
- package/build/components/FileTree.js +1 -1
- package/build/components/FootnoteRef.js +2 -2
- package/build/components/InlineToc.js +1 -1
- package/build/components/Layout.js +1 -1
- package/build/components/LinkButton.js +2 -2
- package/build/components/Mermaid.js +1 -1
- package/build/components/PackageTabs.js +2 -2
- package/build/components/PageToolbar.js +2 -2
- package/build/components/PrevNext.js +3 -7
- package/build/components/SearchDialog.js +1 -1
- package/build/components/Section.js +2 -2
- package/build/components/SectionHeader.js +2 -2
- package/build/components/Sidebar.js +2 -2
- package/build/components/SidebarArticles.js +2 -2
- package/build/components/SidebarLinks.js +2 -2
- package/build/components/TagIndex.js +2 -4
- package/build/components/Toc.js +1 -1
- package/build/content/article.js +1 -1
- package/build/content-collections.js +6 -7
- package/build/elements/accordion.js +2 -2
- package/build/elements/alert-dialog.js +5 -5
- package/build/elements/alert.js +2 -2
- package/build/elements/aspect-ratio.js +2 -2
- package/build/elements/avatar.d.ts +1 -1
- package/build/elements/avatar.js +3 -3
- package/build/elements/badge.js +2 -2
- package/build/elements/breadcrumb.js +2 -2
- package/build/elements/button-group.d.ts +1 -1
- package/build/elements/button-group.js +3 -3
- package/build/elements/button.js +2 -2
- package/build/elements/calendar.js +5 -5
- package/build/elements/card.js +2 -2
- package/build/elements/carousel.js +2 -2
- package/build/elements/chart.js +5 -15
- package/build/elements/checkbox.js +2 -2
- package/build/elements/collapsible.js +3 -3
- package/build/elements/command.js +2 -2
- package/build/elements/context-menu.js +5 -5
- package/build/elements/dialog.js +2 -2
- package/build/elements/direction.d.ts +1 -1
- package/build/elements/direction.js +2 -2
- package/build/elements/drawer.js +2 -2
- package/build/elements/dropdown-menu.js +3 -3
- package/build/elements/empty.d.ts +1 -1
- package/build/elements/empty.js +3 -3
- package/build/elements/field.js +2 -2
- package/build/elements/hover-card.js +3 -3
- package/build/elements/input-group.js +2 -2
- package/build/elements/input-otp.js +2 -2
- package/build/elements/input.js +2 -2
- package/build/elements/item.js +2 -2
- package/build/elements/kbd.js +2 -2
- package/build/elements/label.js +2 -2
- package/build/elements/menubar.js +2 -2
- package/build/elements/native-select.js +2 -2
- package/build/elements/navigation-menu.js +2 -2
- package/build/elements/pagination.js +3 -3
- package/build/elements/popover.js +2 -2
- package/build/elements/progress.d.ts +1 -1
- package/build/elements/progress.js +3 -3
- package/build/elements/radio-group.js +2 -2
- package/build/elements/resizable.js +3 -3
- package/build/elements/scroll-area.js +2 -2
- package/build/elements/select.js +2 -2
- package/build/elements/separator.js +2 -2
- package/build/elements/sheet.js +2 -2
- package/build/elements/sidebar.js +3 -4
- package/build/elements/skeleton.js +2 -2
- package/build/elements/slider.js +2 -2
- package/build/elements/spinner.js +2 -2
- package/build/elements/switch.js +2 -2
- package/build/elements/table.js +2 -2
- package/build/elements/tabs.js +2 -2
- package/build/elements/textarea.js +2 -2
- package/build/elements/toggle-group.js +2 -2
- package/build/elements/toggle.js +2 -2
- package/build/elements/tooltip.js +2 -2
- package/build/helpers/changelog-source.js +1 -1
- package/build/helpers/dynamic-icon-resolver.js +1 -1
- package/build/helpers/resolve-asset-path.unit.js +1 -1
- package/build/helpers/resolve-base.unit.js +2 -2
- package/build/helpers/resolve-includes.js +2 -2
- package/build/helpers/resolve-includes.unit.js +1 -1
- package/build/helpers/rss.js +2 -4
- package/build/helpers/rss.unit.js +1 -1
- package/build/helpers/section.js +2 -3
- package/build/helpers/section.unit.js +4 -13
- package/build/helpers/toc.unit.js +2 -4
- package/build/plugins/rehype-inline-code.js +2 -2
- package/build/plugins/rehype-task-list-a11y.js +1 -1
- package/build/plugins/remark-abbr.js +2 -4
- package/build/plugins/remark-ansi.js +2 -4
- package/build/plugins/remark-ansi.unit.js +1 -1
- package/build/plugins/remark-badge.js +2 -4
- package/build/plugins/remark-button.unit.js +1 -1
- package/build/plugins/remark-callout.js +1 -1
- package/build/plugins/remark-card.js +1 -1
- package/build/plugins/remark-code-tabs.js +4 -8
- package/build/plugins/remark-columns.js +1 -1
- package/build/plugins/remark-custom-heading-id.unit.js +1 -1
- package/build/plugins/remark-deflist.js +1 -1
- package/build/plugins/remark-details.js +2 -4
- package/build/plugins/remark-filetree.js +1 -1
- package/build/plugins/remark-filetree.unit.js +1 -1
- package/build/plugins/remark-media.js +3 -7
- package/build/plugins/remark-media.unit.js +1 -1
- package/build/plugins/remark-steps.unit.js +1 -1
- package/build/plugins/remark-tab.js +4 -2
- package/build/plugins/remark-tab.unit.js +3 -7
- package/build/plugins/remark-toc.unit.js +1 -1
- package/build/plugins/shiki-icon.js +1 -1
- package/build/plugins/shiki-line-highlight.js +1 -1
- package/build/plugins/vite-livemark.js +1 -1
- package/build/plugins/vite-robots.js +1 -1
- package/build/plugins/vite-robots.unit.js +1 -1
- package/build/routes/$.js +1 -1
- package/build/vite.config.js +3 -8
- package/package.json +17 -19
- package/source/actions/changelog/build.ts +32 -35
- package/source/actions/changelog/build.unit.ts +191 -1
- package/source/actions/config/load.ts +1 -3
- package/source/actions/config/load.unit.ts +2 -7
- package/source/actions/target/build.ts +1 -4
- package/source/commands/build.ts +1 -7
- package/source/commands/escape.ts +3 -8
- package/source/commands/preview.ts +1 -7
- package/source/commands/start.ts +1 -7
- package/source/components/Abbr.tsx +1 -5
- package/source/components/Article.tsx +1 -5
- package/source/components/BlogIndex.tsx +3 -9
- package/source/components/Callout.tsx +2 -7
- package/source/components/ChangelogIndex.tsx +1 -3
- package/source/components/CodeBlock.tsx +4 -14
- package/source/components/CodeTabs.tsx +1 -3
- package/source/components/Columns.tsx +1 -3
- package/source/components/Content.tsx +1 -5
- package/source/components/ContentTab.tsx +1 -4
- package/source/components/ContentTabs.tsx +3 -10
- package/source/components/DefinitionList.tsx +1 -4
- package/source/components/FileTree.tsx +1 -5
- package/source/components/FootnoteRef.tsx +1 -5
- package/source/components/InlineToc.tsx +1 -4
- package/source/components/Layout.tsx +3 -10
- package/source/components/LinkButton.tsx +2 -8
- package/source/components/Mermaid.tsx +1 -3
- package/source/components/PackageTabs.tsx +1 -5
- package/source/components/PageToolbar.tsx +1 -5
- package/source/components/PrevNext.tsx +2 -6
- package/source/components/SearchDialog.tsx +2 -6
- package/source/components/Section.tsx +1 -1
- package/source/components/SectionHeader.tsx +2 -8
- package/source/components/Sidebar.tsx +2 -7
- package/source/components/SidebarArticles.tsx +4 -20
- package/source/components/SidebarLinks.tsx +2 -6
- package/source/components/TagIndex.tsx +3 -9
- package/source/components/Toc.tsx +2 -7
- package/source/content/article.ts +1 -2
- package/source/content-collections.ts +6 -8
- package/source/elements/accordion.tsx +1 -1
- package/source/elements/alert-dialog.tsx +8 -30
- package/source/elements/alert.tsx +2 -5
- package/source/elements/aspect-ratio.tsx +1 -1
- package/source/elements/avatar.tsx +5 -21
- package/source/elements/badge.tsx +3 -5
- package/source/elements/breadcrumb.tsx +4 -14
- package/source/elements/button-group.tsx +2 -7
- package/source/elements/button.tsx +1 -1
- package/source/elements/calendar.tsx +7 -24
- package/source/elements/card.tsx +1 -1
- package/source/elements/carousel.tsx +4 -11
- package/source/elements/chart.tsx +9 -34
- package/source/elements/checkbox.tsx +1 -1
- package/source/elements/collapsible.tsx +2 -6
- package/source/elements/command.tsx +4 -13
- package/source/elements/context-menu.tsx +8 -25
- package/source/elements/dialog.tsx +4 -14
- package/source/elements/direction.tsx +1 -4
- package/source/elements/drawer.tsx +4 -10
- package/source/elements/dropdown-menu.tsx +5 -19
- package/source/elements/empty.tsx +3 -13
- package/source/elements/field.tsx +3 -7
- package/source/elements/hover-card.tsx +2 -4
- package/source/elements/input-group.tsx +15 -28
- package/source/elements/input-otp.tsx +1 -1
- package/source/elements/input.tsx +1 -1
- package/source/elements/item.tsx +4 -13
- package/source/elements/kbd.tsx +1 -1
- package/source/elements/label.tsx +1 -1
- package/source/elements/menubar.tsx +5 -14
- package/source/elements/native-select.tsx +4 -15
- package/source/elements/navigation-menu.tsx +2 -5
- package/source/elements/pagination.tsx +4 -14
- package/source/elements/popover.tsx +2 -5
- package/source/elements/progress.tsx +4 -16
- package/source/elements/radio-group.tsx +1 -1
- package/source/elements/resizable.tsx +4 -12
- package/source/elements/scroll-area.tsx +2 -6
- package/source/elements/select.tsx +4 -14
- package/source/elements/separator.tsx +1 -1
- package/source/elements/sheet.tsx +3 -10
- package/source/elements/sidebar.tsx +7 -25
- package/source/elements/skeleton.tsx +1 -1
- package/source/elements/slider.tsx +1 -1
- package/source/elements/spinner.tsx +1 -1
- package/source/elements/switch.tsx +1 -1
- package/source/elements/table.tsx +4 -13
- package/source/elements/tabs.tsx +1 -1
- package/source/elements/textarea.tsx +1 -1
- package/source/elements/toggle-group.tsx +2 -4
- package/source/elements/toggle.tsx +1 -1
- package/source/elements/tooltip.tsx +3 -10
- package/source/helpers/changelog-source.ts +1 -3
- package/source/helpers/dynamic-icon-resolver.tsx +1 -4
- package/source/helpers/resolve-asset-path.unit.ts +6 -12
- package/source/helpers/resolve-base.unit.ts +1 -2
- package/source/helpers/resolve-includes.ts +2 -8
- package/source/helpers/resolve-includes.unit.ts +9 -36
- package/source/helpers/rss.ts +3 -9
- package/source/helpers/rss.unit.ts +1 -3
- package/source/helpers/section.ts +1 -4
- package/source/helpers/section.unit.ts +5 -18
- package/source/helpers/toc.unit.ts +1 -3
- package/source/plugins/rehype-inline-code.ts +5 -21
- package/source/plugins/rehype-task-list-a11y.ts +1 -2
- package/source/plugins/remark-abbr.ts +1 -3
- package/source/plugins/remark-ansi.ts +2 -5
- package/source/plugins/remark-ansi.unit.ts +6 -18
- package/source/plugins/remark-badge.ts +1 -3
- package/source/plugins/remark-button.unit.ts +3 -9
- package/source/plugins/remark-callout.ts +35 -40
- package/source/plugins/remark-card.ts +25 -29
- package/source/plugins/remark-code-tabs.ts +3 -7
- package/source/plugins/remark-columns.ts +13 -17
- package/source/plugins/remark-custom-heading-id.unit.ts +2 -6
- package/source/plugins/remark-deflist.ts +1 -2
- package/source/plugins/remark-details.ts +28 -34
- package/source/plugins/remark-filetree.ts +28 -34
- package/source/plugins/remark-filetree.unit.ts +1 -4
- package/source/plugins/remark-media.ts +2 -6
- package/source/plugins/remark-media.unit.ts +2 -6
- package/source/plugins/remark-steps.unit.ts +2 -7
- package/source/plugins/remark-tab.ts +26 -30
- package/source/plugins/remark-tab.unit.ts +2 -6
- package/source/plugins/remark-toc.unit.ts +1 -3
- package/source/plugins/shiki-icon.ts +1 -4
- package/source/plugins/shiki-line-highlight.ts +4 -11
- package/source/plugins/vite-livemark.ts +3 -10
- package/source/plugins/vite-robots.ts +1 -6
- package/source/plugins/vite-robots.unit.ts +1 -3
- package/source/routes/$.tsx +1 -3
- package/source/styles/general.css +1 -5
- package/source/vite.config.ts +2 -7
- package/build/utils/style.d.ts +0 -2
- package/build/utils/style.js +0 -6
- package/source/utils/style.ts +0 -6
- /package/{skills/authoring → .agents/skills/livemark-authoring}/SKILL.md +0 -0
- /package/{skills/customization → .agents/skills/livemark-customization}/SKILL.md +0 -0
package/package.json
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livemark",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.1",
|
|
4
4
|
"description": "Livemark description",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Evgeny Karev",
|
|
7
|
-
"repository":
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/datisthq/livemark"
|
|
10
|
+
},
|
|
8
11
|
"bin": {
|
|
9
12
|
"livemark": "./build/entrypoints/main.js"
|
|
10
13
|
},
|
|
11
14
|
"files": [
|
|
12
15
|
"build",
|
|
13
16
|
"source",
|
|
14
|
-
"skills"
|
|
17
|
+
".agents/skills"
|
|
15
18
|
],
|
|
16
19
|
"type": "module",
|
|
17
20
|
"sideEffects": false,
|
|
@@ -20,8 +23,7 @@
|
|
|
20
23
|
"./components/*": "./source/components/*.tsx",
|
|
21
24
|
"./elements/*": "./source/elements/*.tsx",
|
|
22
25
|
"./hooks/*": "./source/hooks/*.ts",
|
|
23
|
-
"./styles/*": "./source/styles/*.css"
|
|
24
|
-
"./utils/*": "./source/utils/*.ts"
|
|
26
|
+
"./styles/*": "./source/styles/*.css"
|
|
25
27
|
},
|
|
26
28
|
"dependencies": {
|
|
27
29
|
"@base-ui/react": "1.3.0",
|
|
@@ -50,14 +52,14 @@
|
|
|
50
52
|
"@vitejs/plugin-react": "6.0.1",
|
|
51
53
|
"chokidar": "^5.0.0",
|
|
52
54
|
"class-variance-authority": "0.7.1",
|
|
53
|
-
"clsx": "2.1.1",
|
|
54
55
|
"cmdk": "1.1.1",
|
|
56
|
+
"cn": "0.2.4",
|
|
55
57
|
"commander": "14.0.3",
|
|
56
58
|
"embla-carousel-react": "8.6.0",
|
|
57
59
|
"es-toolkit": "1.44.0",
|
|
58
60
|
"github-slugger": "^2.0.0",
|
|
59
61
|
"input-otp": "1.4.2",
|
|
60
|
-
"katex": "
|
|
62
|
+
"katex": "0.18.9",
|
|
61
63
|
"lucide-react": "0.577.0",
|
|
62
64
|
"mdast-util-directive": "^3.1.0",
|
|
63
65
|
"mdast-util-to-string": "^4.0.0",
|
|
@@ -81,31 +83,28 @@
|
|
|
81
83
|
"shadcn": "3.7.0",
|
|
82
84
|
"shiki": "4.0.2",
|
|
83
85
|
"sonner": "2.0.7",
|
|
84
|
-
"tailwind-merge": "3.5.0",
|
|
85
86
|
"tailwindcss": "4.2.2",
|
|
86
87
|
"tw-animate-css": "1.4.0",
|
|
87
88
|
"unified": "^11.0.5",
|
|
88
89
|
"unist-util-visit": "^5.1.0",
|
|
89
90
|
"vaul": "1.1.2",
|
|
90
|
-
"vite": "8.
|
|
91
|
+
"vite": "8.3.1",
|
|
91
92
|
"vite-plugin-svgr": "5.2.0",
|
|
92
93
|
"zod": "4.3.6"
|
|
93
94
|
},
|
|
94
95
|
"devDependencies": {
|
|
95
96
|
"@plausible-analytics/tracker": "^0.4.4",
|
|
96
|
-
"@semantic-release/exec": "7.1.0",
|
|
97
97
|
"@types/node": "24.2.0",
|
|
98
98
|
"@typescript/native-preview": "7.0.0-dev.20260316.1",
|
|
99
|
-
"@vitest/coverage-v8": "
|
|
100
|
-
"conventional-changelog-conventionalcommits": "9.1.0",
|
|
99
|
+
"@vitest/coverage-v8": "5.0.1",
|
|
101
100
|
"lefthook": "2.1.1",
|
|
102
101
|
"livemark": "link:.",
|
|
103
|
-
"npm-check-updates": "
|
|
102
|
+
"npm-check-updates": "23.1.0",
|
|
104
103
|
"react": "19.2.4",
|
|
105
104
|
"react-dom": "19.2.4",
|
|
106
|
-
"semantic-release": "24.2.9",
|
|
107
105
|
"tempy": "3.2.0",
|
|
108
|
-
"vite-plus": "0.
|
|
106
|
+
"vite-plus": "1.0.0",
|
|
107
|
+
"vitest": "5.0.1",
|
|
109
108
|
"wrangler": "4.85.0"
|
|
110
109
|
},
|
|
111
110
|
"peerDependencies": {
|
|
@@ -113,15 +112,15 @@
|
|
|
113
112
|
"react-dom": "^19.0.0"
|
|
114
113
|
},
|
|
115
114
|
"engines": {
|
|
116
|
-
"node": "^24.
|
|
115
|
+
"node": "^24.11.0",
|
|
117
116
|
"pnpm": "^11.0.0"
|
|
118
117
|
},
|
|
119
118
|
"scripts": {
|
|
120
119
|
"build": "tsgo --project tsconfig.build.json",
|
|
121
|
-
"deps": "ncu -u",
|
|
120
|
+
"deps": "ncu -u --cooldown 7d",
|
|
122
121
|
"docs:build": "node source/entrypoints/main.ts build",
|
|
123
122
|
"docs:start": "node source/entrypoints/main.ts start",
|
|
124
|
-
"format": "vp fmt",
|
|
123
|
+
"format": "vp fmt --no-error-on-unmatched-pattern",
|
|
125
124
|
"leaks": "gitleaks git --config=.gitleaks.toml --verbose --redact",
|
|
126
125
|
"lint": "vp fmt --check && vp lint",
|
|
127
126
|
"release": "pnpm publish --access public --ignore-scripts --no-git-checks",
|
|
@@ -130,7 +129,6 @@
|
|
|
130
129
|
"test": "pnpm lint && pnpm type && pnpm unit",
|
|
131
130
|
"type": "tsgo --noEmit",
|
|
132
131
|
"unit": "vp test",
|
|
133
|
-
"vers": "pnpm version --no-git-tag-version",
|
|
134
132
|
"vulns": "semgrep --config=p/typescript --config=p/nodejs --config=p/owasp-top-ten --config=p/secrets --exclude=\"**/fixtures/**\" --metrics=off"
|
|
135
133
|
}
|
|
136
134
|
}
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
mkdir,
|
|
4
|
-
readFile,
|
|
5
|
-
readdir,
|
|
6
|
-
rm,
|
|
7
|
-
writeFile,
|
|
8
|
-
} from "node:fs/promises"
|
|
1
|
+
import { createHash } from "node:crypto"
|
|
2
|
+
import { access, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises"
|
|
9
3
|
import { dirname, join, resolve } from "node:path"
|
|
10
4
|
import slugify from "@sindresorhus/slugify"
|
|
11
5
|
import type { Root, RootContent } from "mdast"
|
|
@@ -49,24 +43,31 @@ const stringifier = unified().use(remarkStringify, {
|
|
|
49
43
|
emphasis: "_",
|
|
50
44
|
})
|
|
51
45
|
|
|
52
|
-
/** Glob (absolute path) covering
|
|
53
|
-
*
|
|
54
|
-
* article scan. */
|
|
55
|
-
export function cacheIncludeGlob(config: Config) {
|
|
56
|
-
return join(
|
|
46
|
+
/** Glob (absolute path) covering the cached changelog markdown files of
|
|
47
|
+
* one changelog section. Used by content-collections to include them in
|
|
48
|
+
* the article scan. */
|
|
49
|
+
export function cacheIncludeGlob(section: ChangelogSection, config: Config) {
|
|
50
|
+
return join(changelogCacheDir(section, config), "*.md")
|
|
57
51
|
}
|
|
58
52
|
|
|
59
|
-
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
)
|
|
68
|
-
const
|
|
69
|
-
|
|
53
|
+
/** Directory holding one changelog section's cache state: the rendered
|
|
54
|
+
* `.md` entries plus a `meta.json` holding the etag for conditional
|
|
55
|
+
* GETs. Each section gets its own subdirectory of `cache/changelog/`,
|
|
56
|
+
* keyed by its prefix's slug plus a hash of the raw prefix
|
|
57
|
+
* (`/python/changelog/` → `python-changelog-<hash>`), so several
|
|
58
|
+
* changelogs never overwrite each other's entries even when their
|
|
59
|
+
* prefixes slugify alike. */
|
|
60
|
+
export function changelogCacheDir(section: ChangelogSection, config: Config) {
|
|
61
|
+
const slug = slugify(section.prefix) || "index"
|
|
62
|
+
const hash = createHash("sha256").update(section.prefix).digest("hex").slice(0, 8)
|
|
63
|
+
return join(targetDirFor(config.configPath), CACHE_SUBDIR, `${slug}-${hash}`)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Build the per-version changelog cache files of one changelog section
|
|
67
|
+
* into its own cache directory. On refresh we wipe only that
|
|
68
|
+
* directory's `.md` files, leaving meta intact. */
|
|
69
|
+
export async function buildChangelog(section: ChangelogSection, config: Config) {
|
|
70
|
+
const cacheDir = changelogCacheDir(section, config)
|
|
70
71
|
const metaPath = join(cacheDir, "meta.json")
|
|
71
72
|
|
|
72
73
|
const entries = isGitHubUrl(section.source)
|
|
@@ -147,10 +148,12 @@ function processBody(body: string) {
|
|
|
147
148
|
return escapeMdxAngles(stringifier.stringify(tree).trimEnd())
|
|
148
149
|
}
|
|
149
150
|
|
|
150
|
-
/** Escape `<` to
|
|
151
|
+
/** Escape `<` to `<` outside fenced code blocks and inline backtick spans
|
|
151
152
|
* so commit messages with placeholders like `<subdir>` don't get parsed as
|
|
152
|
-
* JSX by MDX.
|
|
153
|
-
|
|
153
|
+
* JSX by MDX. The entity is used rather than a `\<` backslash escape because
|
|
154
|
+
* MDX's JSX-aware parser does not honour the backslash and still reads
|
|
155
|
+
* `\<name>` as an unclosed tag. */
|
|
156
|
+
export function escapeMdxAngles(markdown: string) {
|
|
154
157
|
let inFence = false
|
|
155
158
|
return markdown
|
|
156
159
|
.split("\n")
|
|
@@ -160,9 +163,7 @@ function escapeMdxAngles(markdown: string) {
|
|
|
160
163
|
return line
|
|
161
164
|
}
|
|
162
165
|
if (inFence) return line
|
|
163
|
-
return line.replace(/`[^`]*`|</g, match =>
|
|
164
|
-
match === "<" ? "\\<" : match,
|
|
165
|
-
)
|
|
166
|
+
return line.replace(/`[^`]*`|</g, match => (match === "<" ? "<" : match))
|
|
166
167
|
})
|
|
167
168
|
.join("\n")
|
|
168
169
|
}
|
|
@@ -230,11 +231,7 @@ async function buildFromGitHub(
|
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
function wrapFrontmatter(entry: ChangelogEntry, section: ChangelogSection) {
|
|
233
|
-
const lines = [
|
|
234
|
-
"---",
|
|
235
|
-
`title: ${entry.title}`,
|
|
236
|
-
`path: ${section.prefix}${entry.slug}/`,
|
|
237
|
-
]
|
|
234
|
+
const lines = ["---", `title: ${entry.title}`, `path: ${section.prefix}${entry.slug}/`]
|
|
238
235
|
if (entry.date) lines.push(`date: ${entry.date}`)
|
|
239
236
|
if (entry.sourceUrl) {
|
|
240
237
|
lines.push(`sourceUrl: ${entry.sourceUrl}`, "sourceAction: view")
|
|
@@ -1,5 +1,159 @@
|
|
|
1
|
+
import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises"
|
|
2
|
+
import { basename, dirname, join } from "node:path"
|
|
3
|
+
import { temporaryDirectoryTask } from "tempy"
|
|
1
4
|
import { describe, expect, it } from "vite-plus/test"
|
|
2
|
-
import {
|
|
5
|
+
import { partitionBySection } from "../../helpers/section.ts"
|
|
6
|
+
import { Config } from "../../models/config.ts"
|
|
7
|
+
import type { ChangelogSection } from "../../models/section.ts"
|
|
8
|
+
import { targetDirFor } from "../target/build.ts"
|
|
9
|
+
import {
|
|
10
|
+
buildChangelog,
|
|
11
|
+
cacheIncludeGlob,
|
|
12
|
+
changelogCacheDir,
|
|
13
|
+
escapeMdxAngles,
|
|
14
|
+
splitLocalChangelog,
|
|
15
|
+
} from "./build.ts"
|
|
16
|
+
|
|
17
|
+
describe("buildChangelog", () => {
|
|
18
|
+
it("keeps several changelog sections apart when they share a version", () =>
|
|
19
|
+
temporaryDirectoryTask(async root => {
|
|
20
|
+
const configPath = join(root, "livemark.config.ts")
|
|
21
|
+
const standard: ChangelogSection = {
|
|
22
|
+
type: "changelog",
|
|
23
|
+
title: "Changelog",
|
|
24
|
+
prefix: "/changelog/",
|
|
25
|
+
source: "standard/CHANGELOG.md",
|
|
26
|
+
version: true,
|
|
27
|
+
position: "sidebar",
|
|
28
|
+
}
|
|
29
|
+
const python: ChangelogSection = {
|
|
30
|
+
type: "changelog",
|
|
31
|
+
title: "Changelog",
|
|
32
|
+
prefix: "/python/changelog/",
|
|
33
|
+
source: "python/CHANGELOG.md",
|
|
34
|
+
version: true,
|
|
35
|
+
position: "sidebar",
|
|
36
|
+
}
|
|
37
|
+
const config = makeConfig(root, [standard, python])
|
|
38
|
+
|
|
39
|
+
await writeChangelog(
|
|
40
|
+
root,
|
|
41
|
+
"standard",
|
|
42
|
+
"## 0.2.0\n\nStandard two.\n\n## 0.1.0\n\nStandard one.\n",
|
|
43
|
+
)
|
|
44
|
+
await writeChangelog(root, "python", "## 0.2.0\n\nPython two.\n")
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
await buildChangelog(standard, config)
|
|
48
|
+
await buildChangelog(python, config)
|
|
49
|
+
|
|
50
|
+
const standardDir = changelogCacheDir(standard, config)
|
|
51
|
+
const pythonDir = changelogCacheDir(python, config)
|
|
52
|
+
const cacheRoot = join(targetDirFor(configPath), "cache/changelog")
|
|
53
|
+
expect(dirname(standardDir)).toBe(cacheRoot)
|
|
54
|
+
expect(dirname(pythonDir)).toBe(cacheRoot)
|
|
55
|
+
expect(basename(standardDir)).toMatch(/^changelog-[0-9a-f]{8}$/)
|
|
56
|
+
expect(basename(pythonDir)).toMatch(/^python-changelog-[0-9a-f]{8}$/)
|
|
57
|
+
expect(cacheIncludeGlob(python, config)).toBe(join(pythonDir, "*.md"))
|
|
58
|
+
|
|
59
|
+
expect((await readdir(standardDir)).sort()).toEqual(["0-1-0.md", "0-2-0.md"])
|
|
60
|
+
expect(await readdir(pythonDir)).toEqual(["0-2-0.md"])
|
|
61
|
+
|
|
62
|
+
const standardEntry = await readFile(join(standardDir, "0-2-0.md"), "utf-8")
|
|
63
|
+
const pythonEntry = await readFile(join(pythonDir, "0-2-0.md"), "utf-8")
|
|
64
|
+
expect(standardEntry).toContain("path: /changelog/0-2-0/")
|
|
65
|
+
expect(standardEntry).toContain("Standard two.")
|
|
66
|
+
expect(pythonEntry).toContain("path: /python/changelog/0-2-0/")
|
|
67
|
+
expect(pythonEntry).toContain("Python two.")
|
|
68
|
+
|
|
69
|
+
const olderEntry = await readFile(join(standardDir, "0-1-0.md"), "utf-8")
|
|
70
|
+
const articles = [standardEntry, olderEntry, pythonEntry].map(markdown => ({
|
|
71
|
+
path: markdown.match(/^path: (.+)$/m)?.[1] ?? "",
|
|
72
|
+
}))
|
|
73
|
+
const buckets = partitionBySection(articles, [standard, python])
|
|
74
|
+
expect(buckets.get("/changelog/")?.map(a => a.path)).toEqual([
|
|
75
|
+
"/changelog/0-2-0/",
|
|
76
|
+
"/changelog/0-1-0/",
|
|
77
|
+
])
|
|
78
|
+
expect(buckets.get("/python/changelog/")?.map(a => a.path)).toEqual([
|
|
79
|
+
"/python/changelog/0-2-0/",
|
|
80
|
+
])
|
|
81
|
+
} finally {
|
|
82
|
+
await rm(targetDirFor(configPath), { recursive: true, force: true })
|
|
83
|
+
}
|
|
84
|
+
}))
|
|
85
|
+
|
|
86
|
+
it("cleans only its own cache directory on rebuild", () =>
|
|
87
|
+
temporaryDirectoryTask(async root => {
|
|
88
|
+
const configPath = join(root, "livemark.config.ts")
|
|
89
|
+
const standard: ChangelogSection = {
|
|
90
|
+
type: "changelog",
|
|
91
|
+
title: "Changelog",
|
|
92
|
+
prefix: "/changelog/",
|
|
93
|
+
source: "standard/CHANGELOG.md",
|
|
94
|
+
position: "sidebar",
|
|
95
|
+
}
|
|
96
|
+
const python: ChangelogSection = {
|
|
97
|
+
type: "changelog",
|
|
98
|
+
title: "Changelog",
|
|
99
|
+
prefix: "/python/changelog/",
|
|
100
|
+
source: "python/CHANGELOG.md",
|
|
101
|
+
position: "sidebar",
|
|
102
|
+
}
|
|
103
|
+
const config = makeConfig(root, [standard, python])
|
|
104
|
+
|
|
105
|
+
await writeChangelog(root, "standard", "## 0.2.0\n\nStandard two.\n")
|
|
106
|
+
await writeChangelog(root, "python", "## 0.3.0\n\nPython three.\n")
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
await buildChangelog(standard, config)
|
|
110
|
+
await buildChangelog(python, config)
|
|
111
|
+
await writeChangelog(root, "standard", "## 0.4.0\n\nStandard four.\n")
|
|
112
|
+
await buildChangelog(standard, config)
|
|
113
|
+
|
|
114
|
+
expect(await readdir(changelogCacheDir(standard, config))).toEqual(["0-4-0.md"])
|
|
115
|
+
expect(await readdir(changelogCacheDir(python, config))).toEqual(["0-3-0.md"])
|
|
116
|
+
} finally {
|
|
117
|
+
await rm(targetDirFor(configPath), { recursive: true, force: true })
|
|
118
|
+
}
|
|
119
|
+
}))
|
|
120
|
+
|
|
121
|
+
it("keeps sections apart when their prefixes slugify to the same key", () =>
|
|
122
|
+
temporaryDirectoryTask(async root => {
|
|
123
|
+
const configPath = join(root, "livemark.config.ts")
|
|
124
|
+
const nested: ChangelogSection = {
|
|
125
|
+
type: "changelog",
|
|
126
|
+
title: "Changelog",
|
|
127
|
+
prefix: "/python/changelog/",
|
|
128
|
+
source: "nested/CHANGELOG.md",
|
|
129
|
+
position: "sidebar",
|
|
130
|
+
}
|
|
131
|
+
const flat: ChangelogSection = {
|
|
132
|
+
type: "changelog",
|
|
133
|
+
title: "Changelog",
|
|
134
|
+
prefix: "/python-changelog/",
|
|
135
|
+
source: "flat/CHANGELOG.md",
|
|
136
|
+
position: "sidebar",
|
|
137
|
+
}
|
|
138
|
+
const config = makeConfig(root, [nested, flat])
|
|
139
|
+
|
|
140
|
+
await writeChangelog(root, "nested", "## 0.1.0\n\nNested one.\n")
|
|
141
|
+
await writeChangelog(root, "flat", "## 0.2.0\n\nFlat two.\n")
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
await buildChangelog(nested, config)
|
|
145
|
+
await buildChangelog(flat, config)
|
|
146
|
+
|
|
147
|
+
const nestedDir = changelogCacheDir(nested, config)
|
|
148
|
+
const flatDir = changelogCacheDir(flat, config)
|
|
149
|
+
expect(nestedDir).not.toBe(flatDir)
|
|
150
|
+
expect(await readdir(nestedDir)).toEqual(["0-1-0.md"])
|
|
151
|
+
expect(await readdir(flatDir)).toEqual(["0-2-0.md"])
|
|
152
|
+
} finally {
|
|
153
|
+
await rm(targetDirFor(configPath), { recursive: true, force: true })
|
|
154
|
+
}
|
|
155
|
+
}))
|
|
156
|
+
})
|
|
3
157
|
|
|
4
158
|
describe("splitLocalChangelog", () => {
|
|
5
159
|
it("splits by h2 headings", () => {
|
|
@@ -67,3 +221,39 @@ Release notes.
|
|
|
67
221
|
expect(entries[0]?.date).toBeUndefined()
|
|
68
222
|
})
|
|
69
223
|
})
|
|
224
|
+
|
|
225
|
+
describe("escapeMdxAngles", () => {
|
|
226
|
+
it("escapes a bare angle placeholder as an HTML entity", () => {
|
|
227
|
+
// `\<` is honoured by remark but NOT by MDX's JSX-aware parser, which still
|
|
228
|
+
// reads `\<name>` as an unclosed tag. Only the entity survives both.
|
|
229
|
+
expect(escapeMdxAngles("a <name> b")).toBe("a <name> b")
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it("escapes a placeholder that follows a bare URL", () => {
|
|
233
|
+
const input = "See https://fairspec.org/profiles/latest/<name>.json, ok."
|
|
234
|
+
expect(escapeMdxAngles(input)).toBe(
|
|
235
|
+
"See https://fairspec.org/profiles/latest/<name>.json, ok.",
|
|
236
|
+
)
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
it("leaves inline code spans alone", () => {
|
|
240
|
+
expect(escapeMdxAngles("use `--resource <name>` here")).toBe(
|
|
241
|
+
"use `--resource <name>` here",
|
|
242
|
+
)
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
it("leaves fenced code blocks alone", () => {
|
|
246
|
+
const input = "```sh\nfoo <bar>\n```"
|
|
247
|
+
expect(escapeMdxAngles(input)).toBe(input)
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
function makeConfig(root: string, sections: ChangelogSection[]) {
|
|
252
|
+
const configPath = join(root, "livemark.config.ts")
|
|
253
|
+
return { ...Config.parse({ root, configPath, sections }), base: undefined }
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async function writeChangelog(root: string, dir: string, body: string) {
|
|
257
|
+
await mkdir(join(root, dir), { recursive: true })
|
|
258
|
+
await writeFile(join(root, dir, "CHANGELOG.md"), body, "utf-8")
|
|
259
|
+
}
|
|
@@ -33,9 +33,7 @@ function detectCommand() {
|
|
|
33
33
|
* hash, watcher) still has a stable per-project key.
|
|
34
34
|
*/
|
|
35
35
|
export async function loadConfig(path?: string): Promise<Config> {
|
|
36
|
-
const configIndex = process.argv.findIndex(
|
|
37
|
-
a => a === "-c" || a === "--config",
|
|
38
|
-
)
|
|
36
|
+
const configIndex = process.argv.findIndex(a => a === "-c" || a === "--config")
|
|
39
37
|
const cliPath = configIndex !== -1 ? process.argv[configIndex + 1] : undefined
|
|
40
38
|
const explicit = path ?? cliPath
|
|
41
39
|
const resolved = resolve(explicit ?? "livemark.config.ts")
|
|
@@ -6,9 +6,7 @@ import { loadConfig } from "./load.ts"
|
|
|
6
6
|
|
|
7
7
|
describe("loadConfig", () => {
|
|
8
8
|
it("should throw when an explicit path points at a missing file", async () => {
|
|
9
|
-
await expect(loadConfig("/nonexistent/config.ts")).rejects.toThrow(
|
|
10
|
-
/not found/,
|
|
11
|
-
)
|
|
9
|
+
await expect(loadConfig("/nonexistent/config.ts")).rejects.toThrow(/not found/)
|
|
12
10
|
})
|
|
13
11
|
|
|
14
12
|
it("should return defaults when no path is given and cwd has no config", () =>
|
|
@@ -29,10 +27,7 @@ describe("loadConfig", () => {
|
|
|
29
27
|
it("should load config from explicit path", () =>
|
|
30
28
|
temporaryDirectoryTask(async tmpDir => {
|
|
31
29
|
const configPath = join(tmpDir, "livemark.config.ts")
|
|
32
|
-
fs.writeFileSync(
|
|
33
|
-
configPath,
|
|
34
|
-
'export default { include: "articles/**/*.mdx" }\n',
|
|
35
|
-
)
|
|
30
|
+
fs.writeFileSync(configPath, 'export default { include: "articles/**/*.mdx" }\n')
|
|
36
31
|
const config = await loadConfig(configPath)
|
|
37
32
|
expect(config.include).toBe("articles/**/*.mdx")
|
|
38
33
|
expect(config.root).toBe(tmpDir)
|
|
@@ -81,9 +81,6 @@ export function buildTarget(configPath: string) {
|
|
|
81
81
|
* rebuilding it. Used by code that needs to write into the target
|
|
82
82
|
* (e.g. cache writers) outside of `buildTarget`'s setup phase. */
|
|
83
83
|
export function targetDirFor(configPath: string) {
|
|
84
|
-
const hash = createHash("sha256")
|
|
85
|
-
.update(configPath)
|
|
86
|
-
.digest("hex")
|
|
87
|
-
.slice(0, 16)
|
|
84
|
+
const hash = createHash("sha256").update(configPath).digest("hex").slice(0, 16)
|
|
88
85
|
return join(TARGETS_ROOT, hash)
|
|
89
86
|
}
|
package/source/commands/build.ts
CHANGED
|
@@ -2,13 +2,7 @@ import { join } from "node:path"
|
|
|
2
2
|
import { Command } from "commander"
|
|
3
3
|
import { createBuilder } from "vite"
|
|
4
4
|
|
|
5
|
-
const configFile = join(
|
|
6
|
-
import.meta.dirname,
|
|
7
|
-
"..",
|
|
8
|
-
"..",
|
|
9
|
-
"source",
|
|
10
|
-
"vite.config.ts",
|
|
11
|
-
)
|
|
5
|
+
const configFile = join(import.meta.dirname, "..", "..", "source", "vite.config.ts")
|
|
12
6
|
|
|
13
7
|
/**
|
|
14
8
|
* Build the site for production.
|
|
@@ -29,14 +29,11 @@ export const escape = new Command("escape")
|
|
|
29
29
|
.action((relPath?: string) => {
|
|
30
30
|
if (!relPath) {
|
|
31
31
|
for (const file of listEscapable()) console.log(file)
|
|
32
|
-
console.log(
|
|
33
|
-
pc.dim("\nRun 'livemark escape <path>' to copy a file into .livemark/"),
|
|
34
|
-
)
|
|
32
|
+
console.log(pc.dim("\nRun 'livemark escape <path>' to copy a file into .livemark/"))
|
|
35
33
|
return
|
|
36
34
|
}
|
|
37
35
|
|
|
38
|
-
const isTopLevelFile =
|
|
39
|
-
!relPath.includes("/") && ESCAPABLE_FILES.includes(relPath)
|
|
36
|
+
const isTopLevelFile = !relPath.includes("/") && ESCAPABLE_FILES.includes(relPath)
|
|
40
37
|
const [first] = relPath.split("/")
|
|
41
38
|
const isFolderPath =
|
|
42
39
|
!!first && ESCAPABLE_FOLDERS.includes(first) && !relPath.includes("..")
|
|
@@ -63,9 +60,7 @@ export const escape = new Command("escape")
|
|
|
63
60
|
|
|
64
61
|
mkdirSync(dirname(dest), { recursive: true })
|
|
65
62
|
writeFileSync(dest, readFileSync(src))
|
|
66
|
-
console.log(
|
|
67
|
-
`Copied ${pc.dim(relPath)} → ${pc.green(`.livemark/${relPath}`)}`,
|
|
68
|
-
)
|
|
63
|
+
console.log(`Copied ${pc.dim(relPath)} → ${pc.green(`.livemark/${relPath}`)}`)
|
|
69
64
|
})
|
|
70
65
|
|
|
71
66
|
function listEscapable() {
|
|
@@ -2,13 +2,7 @@ import { join } from "node:path"
|
|
|
2
2
|
import { Command } from "commander"
|
|
3
3
|
import { preview as vitePreview } from "vite"
|
|
4
4
|
|
|
5
|
-
const configFile = join(
|
|
6
|
-
import.meta.dirname,
|
|
7
|
-
"..",
|
|
8
|
-
"..",
|
|
9
|
-
"source",
|
|
10
|
-
"vite.config.ts",
|
|
11
|
-
)
|
|
5
|
+
const configFile = join(import.meta.dirname, "..", "..", "source", "vite.config.ts")
|
|
12
6
|
|
|
13
7
|
/**
|
|
14
8
|
* Preview the production build locally.
|
package/source/commands/start.ts
CHANGED
|
@@ -2,13 +2,7 @@ import { join } from "node:path"
|
|
|
2
2
|
import { Command } from "commander"
|
|
3
3
|
import { createServer } from "vite"
|
|
4
4
|
|
|
5
|
-
const configFile = join(
|
|
6
|
-
import.meta.dirname,
|
|
7
|
-
"..",
|
|
8
|
-
"..",
|
|
9
|
-
"source",
|
|
10
|
-
"vite.config.ts",
|
|
11
|
-
)
|
|
5
|
+
const configFile = join(import.meta.dirname, "..", "..", "source", "vite.config.ts")
|
|
12
6
|
|
|
13
7
|
/**
|
|
14
8
|
* Start a development server.
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Tooltip,
|
|
3
|
-
TooltipContent,
|
|
4
|
-
TooltipTrigger,
|
|
5
|
-
} from "../elements/tooltip.tsx"
|
|
1
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../elements/tooltip.tsx"
|
|
6
2
|
|
|
7
3
|
/** Renders an abbreviation with a shadcn tooltip showing its full form */
|
|
8
4
|
export function Abbr(props: { text: string; title: string }) {
|
|
@@ -13,11 +13,7 @@ import { Column } from "./Column.tsx"
|
|
|
13
13
|
import { Columns } from "./Columns.tsx"
|
|
14
14
|
import { ContentTab } from "./ContentTab.tsx"
|
|
15
15
|
import { ContentTabs } from "./ContentTabs.tsx"
|
|
16
|
-
import {
|
|
17
|
-
DefinitionDetail,
|
|
18
|
-
DefinitionList,
|
|
19
|
-
DefinitionTerm,
|
|
20
|
-
} from "./DefinitionList.tsx"
|
|
16
|
+
import { DefinitionDetail, DefinitionList, DefinitionTerm } from "./DefinitionList.tsx"
|
|
21
17
|
import { Details } from "./Details.tsx"
|
|
22
18
|
import { FileTree } from "./FileTree.tsx"
|
|
23
19
|
import { Footer } from "./Footer.tsx"
|
|
@@ -31,9 +31,7 @@ export function BlogIndex(props: { sectionPrefix: string }) {
|
|
|
31
31
|
const parts = [`## ${post.title}`]
|
|
32
32
|
if (post.date) parts.push(formatDate(post.date))
|
|
33
33
|
if (post.author) {
|
|
34
|
-
parts.push(
|
|
35
|
-
Array.isArray(post.author) ? post.author.join(", ") : post.author,
|
|
36
|
-
)
|
|
34
|
+
parts.push(Array.isArray(post.author) ? post.author.join(", ") : post.author)
|
|
37
35
|
}
|
|
38
36
|
if (post.description) parts.push("", post.description)
|
|
39
37
|
return parts.join("\n")
|
|
@@ -77,16 +75,12 @@ export function BlogIndex(props: { sectionPrefix: string }) {
|
|
|
77
75
|
{post.date && <span>{formatDate(post.date)}</span>}
|
|
78
76
|
{post.author && (
|
|
79
77
|
<span>
|
|
80
|
-
{Array.isArray(post.author)
|
|
81
|
-
? post.author.join(", ")
|
|
82
|
-
: post.author}
|
|
78
|
+
{Array.isArray(post.author) ? post.author.join(", ") : post.author}
|
|
83
79
|
</span>
|
|
84
80
|
)}
|
|
85
81
|
</p>
|
|
86
82
|
{post.description && (
|
|
87
|
-
<p className="text-muted-foreground mt-2">
|
|
88
|
-
{post.description}
|
|
89
|
-
</p>
|
|
83
|
+
<p className="text-muted-foreground mt-2">{post.description}</p>
|
|
90
84
|
)}
|
|
91
85
|
</article>
|
|
92
86
|
))}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AlertTriangle, Flame, Info, Lightbulb } from "lucide-react"
|
|
2
|
-
import { cn } from "
|
|
2
|
+
import { cn } from "cn"
|
|
3
3
|
|
|
4
4
|
type CalloutType = "note" | "tip" | "info" | "warning" | "danger"
|
|
5
5
|
|
|
@@ -54,12 +54,7 @@ export function Callout(props: {
|
|
|
54
54
|
const title = props.title ?? config.label
|
|
55
55
|
|
|
56
56
|
return (
|
|
57
|
-
<aside
|
|
58
|
-
className={cn(
|
|
59
|
-
"not-prose my-4 rounded-xl border px-4 py-3",
|
|
60
|
-
config.classes,
|
|
61
|
-
)}
|
|
62
|
-
>
|
|
57
|
+
<aside className={cn("not-prose my-4 rounded-xl border px-4 py-3", config.classes)}>
|
|
63
58
|
<div className="flex items-center gap-2 font-semibold text-sm mb-2">
|
|
64
59
|
<Icon className="size-4 shrink-0" />
|
|
65
60
|
<span>{title}</span>
|
|
@@ -74,9 +74,7 @@ export function ChangelogIndex(props: { sectionPrefix: string }) {
|
|
|
74
74
|
</p>
|
|
75
75
|
)}
|
|
76
76
|
{entry.description && (
|
|
77
|
-
<p className="text-muted-foreground mt-2">
|
|
78
|
-
{entry.description}
|
|
79
|
-
</p>
|
|
77
|
+
<p className="text-muted-foreground mt-2">{entry.description}</p>
|
|
80
78
|
)}
|
|
81
79
|
</article>
|
|
82
80
|
))}
|