valaxy 0.0.2 → 0.0.7

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.
Files changed (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -1
  3. package/bin/valaxy.js +11 -0
  4. package/dist/build-OOT6HK6S.js +1 -0
  5. package/dist/build-SG32QSQ3.mjs +1 -0
  6. package/dist/chunk-7JDYOPID.js +1 -0
  7. package/dist/chunk-JJEBEWGI.mjs +1 -0
  8. package/dist/chunk-L3EDI35I.js +1 -0
  9. package/dist/chunk-L5SNNWFJ.js +78 -0
  10. package/dist/chunk-MVJUGWXR.mjs +1 -0
  11. package/dist/chunk-QI435Q25.mjs +78 -0
  12. package/dist/config-d6527c8c.d.ts +174 -0
  13. package/dist/node/cli.d.ts +3 -0
  14. package/dist/node/cli.js +6 -0
  15. package/dist/node/cli.mjs +6 -0
  16. package/dist/node/index.d.ts +45 -0
  17. package/dist/node/index.js +1 -0
  18. package/dist/node/index.mjs +1 -0
  19. package/dist/types/index.d.ts +110 -0
  20. package/dist/types/index.js +1 -0
  21. package/dist/types/index.mjs +1 -0
  22. package/package.json +75 -3
  23. package/src/client/App.vue +16 -0
  24. package/src/client/components/AppLink.vue +20 -0
  25. package/src/client/components/PostCard.vue +69 -0
  26. package/src/client/components/PostList.vue +50 -0
  27. package/src/client/components/README.md +7 -0
  28. package/src/client/components/ValaxyCopyright.vue +80 -0
  29. package/src/client/components/ValaxyFooter.vue +53 -0
  30. package/src/client/components/ValaxyHamburger.vue +21 -0
  31. package/src/client/components/ValaxyMd.vue +71 -0
  32. package/src/client/components/ValaxyOverlay.vue +44 -0
  33. package/src/client/components/ValaxyPagination.vue +122 -0
  34. package/src/client/components/ValaxyRightSidebar.vue +32 -0
  35. package/src/client/components/ValaxySidebar.vue +35 -0
  36. package/src/client/components/ValaxyToc.vue +70 -0
  37. package/src/client/composables/category.ts +101 -0
  38. package/src/client/composables/comments/index.ts +1 -0
  39. package/src/client/composables/comments/waline.ts +60 -0
  40. package/src/client/composables/common.ts +27 -0
  41. package/src/client/composables/dark.ts +4 -0
  42. package/src/client/composables/features/index.ts +1 -0
  43. package/src/client/composables/features/katex.ts +15 -0
  44. package/src/client/composables/helper.ts +26 -0
  45. package/src/client/composables/index.ts +17 -0
  46. package/src/client/composables/layout.ts +7 -0
  47. package/src/client/composables/post.ts +96 -0
  48. package/src/client/composables/search/algolia.ts +114 -0
  49. package/src/client/composables/search/index.ts +0 -0
  50. package/src/client/composables/sidebar.ts +128 -0
  51. package/src/client/composables/tag.ts +70 -0
  52. package/src/client/composables/widgets/aplayer.ts +23 -0
  53. package/src/client/composables/widgets/backToTop.ts +28 -0
  54. package/src/client/composables/widgets/codepen.ts +12 -0
  55. package/src/client/composables/widgets/index.ts +3 -0
  56. package/src/client/index.html +24 -0
  57. package/src/client/layouts/404.vue +25 -0
  58. package/src/client/layouts/README.md +14 -0
  59. package/src/client/locales/README.md +7 -0
  60. package/src/client/locales/en.yml +107 -0
  61. package/src/client/locales/zh-CN.yml +106 -0
  62. package/src/client/main.ts +30 -0
  63. package/src/client/modules/README.md +11 -0
  64. package/src/client/modules/nprogress.ts +14 -0
  65. package/src/client/modules/pinia.ts +17 -0
  66. package/src/client/modules/pwa.ts +12 -0
  67. package/src/client/modules/valaxy.ts +42 -0
  68. package/src/client/pages/README.md +20 -0
  69. package/src/client/pages/[...all].vue +15 -0
  70. package/src/client/pages/about/index.md +5 -0
  71. package/src/client/pages/hi/[name].vue +52 -0
  72. package/src/client/pages/index.vue +3 -0
  73. package/src/client/pages/page/[page].vue +12 -0
  74. package/src/client/pages/posts/index.md +5 -0
  75. package/src/client/public/_headers +3 -0
  76. package/src/client/public/favicon.svg +21 -0
  77. package/src/client/public/pwa-192x192.png +0 -0
  78. package/src/client/public/pwa-512x512.png +0 -0
  79. package/src/client/public/safari-pinned-tab.svg +41 -0
  80. package/src/client/shims.d.ts +36 -0
  81. package/src/client/stores/app.ts +14 -0
  82. package/src/client/stores/user.ts +35 -0
  83. package/src/client/styles/common/button.scss +29 -0
  84. package/src/client/styles/common/code.scss +35 -0
  85. package/src/client/styles/common/hamburger.scss +56 -0
  86. package/src/client/styles/common/markdown.scss +43 -0
  87. package/src/client/styles/common/scrollbar.scss +34 -0
  88. package/src/client/styles/common/sidebar.scss +30 -0
  89. package/src/client/styles/common/transition.scss +23 -0
  90. package/src/client/styles/css-vars/dark.scss +17 -0
  91. package/src/client/styles/css-vars/index.scss +18 -0
  92. package/src/client/styles/css-vars/light.scss +9 -0
  93. package/src/client/styles/global/helper.scss +3 -0
  94. package/src/client/styles/global/index.scss +38 -0
  95. package/src/client/styles/global/nprogress.scss +14 -0
  96. package/src/client/styles/global/reset.scss +20 -0
  97. package/src/client/styles/index.scss +18 -0
  98. package/src/client/styles/mixins/config.scss +1 -0
  99. package/src/client/styles/mixins/index.scss +2 -0
  100. package/src/client/styles/mixins/size.scss +49 -0
  101. package/src/client/styles/mixins/variable.scss +30 -0
  102. package/src/client/styles/palette.scss +61 -0
  103. package/src/client/styles/vars.scss +39 -0
  104. package/src/client/styles/widgets/banner.scss +116 -0
  105. package/src/client/types.ts +3 -0
  106. package/src/client/utils/helper.ts +30 -0
  107. package/src/client/utils/index.ts +2 -0
  108. package/src/client/utils/time.ts +23 -0
  109. package/src/core/config.ts +51 -0
  110. package/src/core/index.ts +5 -0
  111. package/src/core/utils.ts +1 -0
  112. package/src/index.ts +2 -0
  113. package/src/node/build.ts +12 -0
  114. package/src/node/cli.ts +177 -0
  115. package/src/node/config.ts +43 -0
  116. package/src/node/index.ts +1 -0
  117. package/src/node/markdown/headings.ts +24 -0
  118. package/src/node/markdown/index.ts +74 -0
  119. package/src/node/markdown/markdown-it-container.ts +53 -0
  120. package/src/node/markdown/markdown-it-katex.ts +200 -0
  121. package/src/node/markdown/parseHeader.ts +70 -0
  122. package/src/node/markdown/slugify.ts +24 -0
  123. package/src/node/options.ts +90 -0
  124. package/src/node/plugins/extendConfig.ts +28 -0
  125. package/src/node/plugins/index.ts +91 -0
  126. package/src/node/plugins/markdown.ts +62 -0
  127. package/src/node/plugins/preset.ts +174 -0
  128. package/src/node/plugins/unocss.ts +106 -0
  129. package/src/node/plugins/valaxy.ts +1 -0
  130. package/src/node/server.ts +21 -0
  131. package/src/node/shims.d.ts +23 -0
  132. package/src/node/utils/cli.ts +105 -0
  133. package/src/node/utils/index.ts +26 -0
  134. package/src/node/vite.ts +83 -0
  135. package/src/types/config.ts +250 -0
  136. package/src/types/index.ts +2 -0
  137. package/src/types/posts.ts +107 -0
  138. package/tsup.config.ts +17 -0
@@ -0,0 +1,116 @@
1
+ @use "../mixins" as *;
2
+
3
+ $banner-animation-duration: 1s;
4
+ $line-animation-duration: 0.4s;
5
+ $char-animation-duration: 0.4s;
6
+
7
+ #banner {
8
+ position: relative;
9
+ display: flex;
10
+ flex-direction: column;
11
+ align-items: center;
12
+ height: 100vh;
13
+ }
14
+
15
+ .banner-char-container {
16
+ display: flex;
17
+ flex-direction: column;
18
+ align-items: center;
19
+ }
20
+
21
+ .vertical-line {
22
+ &-top, &-bottom {
23
+ display: flex;
24
+ background-color: var(--banner-line-color);
25
+ width: 1px;
26
+ height: 0;
27
+ animation-name: extend-line;
28
+ animation-duration: $line-animation-duration;
29
+ animation-fill-mode: forwards;
30
+ animation-timing-function: ease-in;
31
+ }
32
+
33
+ &-bottom {
34
+ position: absolute;
35
+ bottom: 0;
36
+ }
37
+ }
38
+
39
+ @keyframes extend-line {
40
+ from {
41
+ height: 0;
42
+ }
43
+
44
+ to {
45
+ height: var(--banner-line-height);
46
+ }
47
+ }
48
+
49
+ .char {
50
+ font-family: get-css-var('font', 'serif');
51
+ font-size: var(--banner-char-size, 1rem);
52
+ font-weight: get-css-var('font', 'serif-weight');
53
+ background-color: var(--banner-char-bg-color);
54
+ line-height: 1;
55
+
56
+ transition: all 0.3s ease-in-out;
57
+ transition-delay: 0s;
58
+
59
+ &:hover {
60
+ color: var(--banner-char-hover-color);
61
+ background-color: var(--banner-char-color);
62
+ }
63
+
64
+ &-left,
65
+ &-right {
66
+ display: flex;
67
+ color: var(--banner-char-color);
68
+ opacity: 0;
69
+ }
70
+
71
+ &-left {
72
+ border-left: 1px solid var(--banner-line-color);
73
+ border-right: 0px solid rgba(var(--yun-c-primary-rgb), 0.1);
74
+ border-right-width: 0px;
75
+ animation-name: char-move-left;
76
+ animation-duration: $char-animation-duration;
77
+ animation-delay: $line-animation-duration;
78
+ animation-fill-mode: forwards;
79
+ animation-timing-function: ease-out;
80
+ }
81
+
82
+ &-right {
83
+ border-left: 0px solid rgba(var(--yun-c-primary-rgb), 0.1);
84
+ border-right: 1px solid var(--banner-line-color);
85
+ border-left-width: 0px;
86
+ animation-name: char-move-right;
87
+ animation-duration: $char-animation-duration;
88
+ animation-delay: $line-animation-duration;
89
+ animation-fill-mode: forwards;
90
+ animation-timing-function: ease-out;
91
+ }
92
+ }
93
+
94
+ @keyframes char-move-left {
95
+ from {
96
+ opacity: 0;
97
+ border-right-width: 0;
98
+ }
99
+
100
+ to {
101
+ opacity: 1;
102
+ border-right-width: var(--banner-empty-border-size, var(--banner-char-size));
103
+ }
104
+ }
105
+
106
+ @keyframes char-move-right {
107
+ from {
108
+ opacity: 0;
109
+ border-left-width: 0;
110
+ }
111
+
112
+ to {
113
+ opacity: 1;
114
+ border-left-width: var(--banner-empty-border-size, var(--banner-char-size));
115
+ }
116
+ }
@@ -0,0 +1,3 @@
1
+ import type { ViteSSGContext } from 'vite-ssg'
2
+
3
+ export type UserModule = (ctx: ViteSSGContext) => void
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 生成介于 min 与 max 之间的随机数
3
+ * @returns
4
+ */
5
+ export function random(min: number, max: number) {
6
+ return Math.random() * (max - min) + min
7
+ }
8
+
9
+ /**
10
+ * wrap node
11
+ * @param className
12
+ */
13
+ export function wrap(el: HTMLElement, className: string) {
14
+ const wrapper = document.createElement('div')
15
+ wrapper.className = className
16
+ el.parentNode!.insertBefore(wrapper, el)
17
+ el.parentNode!.removeChild(el)
18
+ wrapper.appendChild(el)
19
+ }
20
+
21
+ /**
22
+ * 包裹表格,添加 class 以控制 table 样式
23
+ */
24
+ export const wrapTable = (container: HTMLElement | Document = document) => {
25
+ container.querySelectorAll('table').forEach((el) => {
26
+ const container = document.createElement('div')
27
+ container.className = 'table-container'
28
+ wrap(el, 'table-container')
29
+ })
30
+ }
@@ -0,0 +1,2 @@
1
+ export * from './helper'
2
+ export * from './time'
@@ -0,0 +1,23 @@
1
+ import dayjs from 'dayjs'
2
+ import type { Post } from 'valaxy'
3
+
4
+ export function formatDate(date: string | number | Date, template = 'YYYY-MM-DD') {
5
+ const today = dayjs(date)
6
+ return today.format(template)
7
+ }
8
+
9
+ /**
10
+ * sort posts by date
11
+ * @param posts
12
+ * @param desc
13
+ */
14
+ export function sortByDate(posts: Post[], desc = true) {
15
+ return posts.sort((a, b) => {
16
+ const aDate = +new Date(a.date || '')
17
+ const bDate = +new Date(b.date || '')
18
+ if (desc)
19
+ return bDate - aDate
20
+ else
21
+ return aDate - bDate
22
+ })
23
+ }
@@ -0,0 +1,51 @@
1
+ // @ts-expect-error virtual module @valaxyjs/config
2
+ import valaxyConfig from '@valaxyjs/config'
3
+ import type { ComputedRef, InjectionKey } from 'vue'
4
+ import { computed, inject, readonly, shallowRef } from 'vue'
5
+ import type { ThemeConfig } from 'valaxy-theme-yun'
6
+ import type { ValaxyConfig } from '../types'
7
+
8
+ /**
9
+ * parse valaxy config
10
+ * @param data
11
+ * @returns
12
+ */
13
+ function parse(data: string): ValaxyConfig {
14
+ const parsed = JSON.parse(data)
15
+ return (import.meta.env.DEV ? readonly(parsed) : parsed) as ValaxyConfig
16
+ }
17
+
18
+ export const valaxyConfigSymbol: InjectionKey<ComputedRef<ValaxyConfig<ThemeConfig>>> = Symbol('valaxy:config')
19
+ export const valaxyConfigRef = shallowRef<ValaxyConfig>(parse(valaxyConfig))
20
+
21
+ // hmr
22
+ if (import.meta.hot) {
23
+ // /@valaxyjs/config must be static string
24
+ import.meta.hot.accept('/@valaxyjs/config', (m) => {
25
+ valaxyConfigRef.value = parse(m.default)
26
+ })
27
+ }
28
+
29
+ export function initConfig() {
30
+ return computed(() => valaxyConfigRef.value)
31
+ }
32
+
33
+ /*
34
+ * get Config
35
+ * @returns
36
+ */
37
+ export function useConfig() {
38
+ const config = inject(valaxyConfigSymbol)
39
+ if (!config)
40
+ throw new Error('[Valaxy] config not properly injected in qpp')
41
+ return config!
42
+ }
43
+
44
+ /**
45
+ * getThemeConfig
46
+ * @returns
47
+ */
48
+ export function useThemeConfig() {
49
+ const config = useConfig()
50
+ return computed(() => config!.value.themeConfig)
51
+ }
@@ -0,0 +1,5 @@
1
+ export * from '../client/composables'
2
+ export * from '../client/utils'
3
+
4
+ export * from './config'
5
+ export * from './utils'
@@ -0,0 +1 @@
1
+ export const isDev = import.meta.env.DEV === true
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './core'
2
+ export * from './types'
@@ -0,0 +1,12 @@
1
+ import type { InlineConfig } from 'vite'
2
+ import { mergeConfig, build as viteBuild } from 'vite'
3
+ import type { ResolvedValaxyOptions } from './options'
4
+ import { createViteConfig } from './vite'
5
+
6
+ export async function build(
7
+ options: ResolvedValaxyOptions,
8
+ viteConfig: InlineConfig = {},
9
+ ) {
10
+ const inlineConfig = mergeConfig(viteConfig, createViteConfig(options))
11
+ await viteBuild(inlineConfig)
12
+ }
@@ -0,0 +1,177 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+ import { exec } from 'child_process'
4
+ import type { Argv } from 'yargs'
5
+ import yargs from 'yargs'
6
+ import type { InlineConfig, LogLevel } from 'vite'
7
+ import openBrowser from 'open'
8
+
9
+ // @ts-expect-error https://github.com/antfu/vite-ssg/pull/225
10
+ import { build as ssgBuild } from 'vite-ssg/node'
11
+
12
+ import consola from 'consola'
13
+
14
+ import { version } from '../../package.json'
15
+ import { resolveOptions } from './options'
16
+ import { bindShortcut, initServer, printInfo } from './utils/cli'
17
+
18
+ const cli = yargs.scriptName('valaxy')
19
+ .usage('$0 [args]')
20
+ .version(version)
21
+ .showHelpOnFail(false)
22
+ .alias('h', 'help')
23
+ .alias('v', 'version')
24
+
25
+ cli.command(
26
+ '* [root]',
27
+ 'Start a local server for Valaxy',
28
+ args =>
29
+ commonOptions(args)
30
+ .option('port', {
31
+ alias: 'p',
32
+ type: 'number',
33
+ describe: 'port',
34
+ })
35
+ .option('open', {
36
+ alias: 'o',
37
+ default: false,
38
+ type: 'boolean',
39
+ describe: 'open in browser',
40
+ })
41
+ .option('remote', {
42
+ default: true,
43
+ type: 'boolean',
44
+ describe: 'listen public host and enable remote control',
45
+ })
46
+ .option('log', {
47
+ default: 'warn',
48
+ type: 'string',
49
+ choices: ['error', 'warn', 'info', 'silent'],
50
+ describe: 'log level',
51
+ })
52
+ .strict()
53
+ .help()
54
+ ,
55
+ async({ root, port: userPort, open, remote, log }) => {
56
+ if (!fs.existsSync(path.resolve(root, 'pages')))
57
+ process.exit(0)
58
+
59
+ const port = userPort || 4859
60
+ const options = await resolveOptions({ userRoot: root })
61
+
62
+ const viteConfig: InlineConfig = {
63
+ server: {
64
+ watch: {
65
+ // watch theme updated
66
+ ignored: [`!${options.themeRoot}/**`, `${options.userRoot}/**.md`],
67
+ },
68
+
69
+ port,
70
+ strictPort: true,
71
+ open,
72
+ host: remote ? '0.0.0.0' : 'localhost',
73
+ },
74
+ logLevel: log as LogLevel,
75
+ }
76
+ await initServer(options, viteConfig)
77
+ printInfo(options, port, remote)
78
+
79
+ const SHORTCUTS = [
80
+ {
81
+ name: 'r',
82
+ fullName: 'restart',
83
+ action() {
84
+ initServer(options, viteConfig)
85
+ },
86
+ },
87
+ {
88
+ name: 'o',
89
+ fullName: 'open',
90
+ action() {
91
+ openBrowser(`http://localhost:${port}`)
92
+ },
93
+ },
94
+ {
95
+ name: 'e',
96
+ fullName: 'edit',
97
+ action() {
98
+ exec(`code "${root}"`)
99
+ },
100
+ },
101
+ ]
102
+ bindShortcut(SHORTCUTS)
103
+ })
104
+
105
+ cli.command(
106
+ 'build [root]',
107
+ 'build your blog to static content',
108
+ args => commonOptions(args)
109
+ .option('ssg', {
110
+ alias: 's',
111
+ type: 'boolean',
112
+ // https://github.com/antfu/vite-ssg/pull/219
113
+ // to be true, when vite-ssg export build
114
+ default: false,
115
+ describe: 'static site generate',
116
+ })
117
+ .option('output', {
118
+ alias: 'o',
119
+ type: 'string',
120
+ default: 'dist',
121
+ describe: 'output dir',
122
+ }).option('base', {
123
+ type: 'string',
124
+ describe: 'output base',
125
+ })
126
+ .strict()
127
+ .help(),
128
+ async({ ssg, root, base, output }) => {
129
+ const options = await resolveOptions({ userRoot: root })
130
+ printInfo(options)
131
+
132
+ if (ssg) {
133
+ consola.info('use vite-ssg to do ssg build...')
134
+ try {
135
+ // wait vite-ssg can pass custom options
136
+ // https://github.com/antfu/vite-ssg/issues/226
137
+ await ssgBuild({
138
+ mode: 'production',
139
+ })
140
+ }
141
+ catch (e) {
142
+ consola.error('[vite-ssg] An internal error occurred.')
143
+ console.log(e)
144
+ }
145
+ }
146
+ else {
147
+ const { build } = await import('./build')
148
+
149
+ consola.info('use vite do spa build...')
150
+ await build(options, {
151
+ base,
152
+ build: {
153
+ // make out dir empty, https://vitejs.dev/config/#build-emptyoutdir
154
+ emptyOutDir: true,
155
+ outDir: path.resolve(options.userRoot, output),
156
+ },
157
+ })
158
+ }
159
+ },
160
+ )
161
+
162
+ /**
163
+ * set common options for cli
164
+ * @param args
165
+ * @returns
166
+ */
167
+ function commonOptions(args: Argv<{}>) {
168
+ return args.positional('root', {
169
+ default: '.',
170
+ type: 'string',
171
+ describe: 'root folder of your source files',
172
+ })
173
+ }
174
+
175
+ export function run() {
176
+ cli.help().parse()
177
+ }
@@ -0,0 +1,43 @@
1
+ // import { loadConfig } from 'c12'
2
+ import { loadConfig } from 'unconfig'
3
+ import defu from 'defu'
4
+ import type { ValaxyConfig } from '../types'
5
+ import { defaultValaxyConfig } from '../types'
6
+ import type { ValaxyEntryOptions } from './options'
7
+
8
+ // for user config
9
+ export async function resolveConfig(options: ValaxyEntryOptions = {}) {
10
+ // c12 merge array twice, so i deprecated it
11
+ // const { config, configFile } = await loadConfig<ValaxyConfig>({
12
+ // name: 'valaxy',
13
+ // defaults: defaultValaxyConfig,
14
+ // })
15
+
16
+ const { config: userConfig, sources } = await loadConfig<ValaxyConfig>({
17
+ sources: [
18
+ {
19
+ files: 'valaxy.config',
20
+ extensions: ['ts', 'js', 'mjs', 'cjs', 'json'],
21
+ },
22
+ ],
23
+ merge: false,
24
+ })
25
+ const configFile = sources[0]
26
+ const config = defu(userConfig, defaultValaxyConfig)
27
+
28
+ const theme = options.theme || config.theme || 'yun'
29
+
30
+ try {
31
+ const { defaultThemeConfig } = await import(`valaxy-theme-${theme}`)
32
+ config.themeConfig = defu(config.themeConfig, defaultThemeConfig)
33
+ }
34
+ catch (e) {
35
+ console.error(`valaxy-theme-${theme} doesn't have default config`)
36
+ }
37
+
38
+ return {
39
+ config,
40
+ configFile,
41
+ theme,
42
+ }
43
+ }
@@ -0,0 +1 @@
1
+ export * from './server'
@@ -0,0 +1,24 @@
1
+ // ref vitepress
2
+ import type MarkdownIt from 'markdown-it'
3
+ import type { MarkdownRenderer } from '../markdown'
4
+ import { deeplyParseHeader } from './parseHeader'
5
+ import { slugify } from './slugify'
6
+
7
+ export const headingPlugin = (md: MarkdownIt, include = ['h2', 'h3']) => {
8
+ md.renderer.rules.heading_open = (tokens, i, options, env, self) => {
9
+ const token = tokens[i]
10
+ if (include.includes(token.tag)) {
11
+ const title = tokens[i + 1].content
12
+ const idAttr = token.attrs!.find(([name]) => name === 'id')
13
+ const slug = idAttr && idAttr[1]
14
+ const data = (md as MarkdownRenderer).__data
15
+ const headers = data.headers || (data.headers = [])
16
+ headers.push({
17
+ level: parseInt(token.tag.slice(1), 10),
18
+ title: deeplyParseHeader(title),
19
+ slug: slug || slugify(title),
20
+ })
21
+ }
22
+ return self.renderToken(tokens, i, options)
23
+ }
24
+ }
@@ -0,0 +1,74 @@
1
+ import type MarkdownIt from 'markdown-it'
2
+
3
+ import Anchor from 'markdown-it-anchor'
4
+ import Emoji from 'markdown-it-emoji'
5
+ import Prism from 'markdown-it-prism'
6
+ import LinkAttributes from 'markdown-it-link-attributes'
7
+ import TOC from 'markdown-it-table-of-contents'
8
+
9
+ import type { KatexOptions } from 'katex'
10
+ import Katex from '../markdown/markdown-it-katex'
11
+ import { containerPlugin } from '../markdown/markdown-it-container'
12
+ import { headingPlugin } from '../markdown/headings'
13
+ import { slugify } from './slugify'
14
+ import { parseHeader } from './parseHeader'
15
+
16
+ export interface Header {
17
+ level: number
18
+ title: string
19
+ slug: string
20
+ }
21
+
22
+ export interface MarkdownParsedData {
23
+ hoistedTags?: string[]
24
+ links?: string[]
25
+ headers?: Header[]
26
+ }
27
+ export interface MarkdownRenderer extends MarkdownIt {
28
+ __data: MarkdownParsedData
29
+ }
30
+
31
+ export interface MarkdownOptions extends MarkdownIt.Options {
32
+ config?: (md: MarkdownIt) => void
33
+ anchor?: {
34
+ permalink?: Anchor.AnchorOptions['permalink']
35
+ }
36
+ // https://github.com/Oktavilla/markdown-it-table-of-contents
37
+ toc?: any
38
+ katex?: KatexOptions
39
+ }
40
+
41
+ export function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions = {}) {
42
+ md
43
+ .use(containerPlugin)
44
+ .use(headingPlugin)
45
+ // https://prismjs.com/
46
+ md.use(Prism)
47
+ md.use(LinkAttributes, {
48
+ matcher: (link: string) => /^https?:\/\//.test(link),
49
+ attrs: {
50
+ target: '_blank',
51
+ rel: 'noopener',
52
+ },
53
+ })
54
+ md.use(Katex, mdOptions.katex)
55
+ .use(Anchor, {
56
+ slugify,
57
+ permalink: Anchor.permalink.ariaHidden({}),
58
+ })
59
+ .use(TOC, {
60
+ slugify,
61
+ includeLevel: [2, 3],
62
+ format: parseHeader,
63
+ ...mdOptions.toc,
64
+ })
65
+ .use(Emoji)
66
+
67
+ const originalRender = md.render
68
+ md.render = (...args) => {
69
+ (md as MarkdownRenderer).__data = {}
70
+ return originalRender.call(md, ...args)
71
+ }
72
+
73
+ return md as MarkdownRenderer
74
+ }
@@ -0,0 +1,53 @@
1
+ // ref vitepress
2
+ // src/node/markdown/plugins/containers.ts
3
+
4
+ import type MarkdownIt from 'markdown-it'
5
+ import type Token from 'markdown-it/lib/token'
6
+ import container from 'markdown-it-container'
7
+
8
+ type ContainerArgs = [
9
+ typeof container,
10
+ string,
11
+ {
12
+ render(tokens: Token[], idx: number): string
13
+ },
14
+ ]
15
+
16
+ function createContainer(classes: string, defaultTitle: string): ContainerArgs {
17
+ return [
18
+ container,
19
+ classes,
20
+ {
21
+ render(tokens, idx) {
22
+ const token = tokens[idx]
23
+ const info = token.info.trim().slice(classes.length).trim()
24
+ if (token.nesting === 1) {
25
+ if (classes === 'details') {
26
+ return `<details class="${classes} custom-block">${
27
+ info ? `<summary>${info}</summary>` : ''
28
+ }\n`
29
+ }
30
+ return `<div class="${classes} custom-block"><p class="custom-block-title">${
31
+ info || defaultTitle
32
+ }</p>\n`
33
+ }
34
+ else {
35
+ return classes === 'details' ? '</details>\n' : '</div>\n'
36
+ }
37
+ },
38
+ },
39
+ ]
40
+ }
41
+
42
+ export const containerPlugin = (md: MarkdownIt) => {
43
+ md.use(...createContainer('tip', 'TIP'))
44
+ .use(...createContainer('info', 'INFO'))
45
+ .use(...createContainer('warning', 'WARNING'))
46
+ .use(...createContainer('danger', 'WARNING'))
47
+ .use(...createContainer('details', 'Details'))
48
+ // explicitly escape Vue syntax
49
+ .use(container, 'v-pre', {
50
+ render: (tokens: Token[], idx: number) =>
51
+ tokens[idx].nesting === 1 ? '<div v-pre>\n' : '</div>\n',
52
+ })
53
+ }