valaxy 0.1.2 → 0.2.2
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/dist/chunk-2K6ROMWQ.mjs +88 -0
- package/dist/chunk-NBGVYWSW.js +88 -0
- package/dist/chunk-TSLYS2VY.js +1 -0
- package/dist/chunk-U4ZDCBEC.mjs +1 -0
- package/dist/{config-d6527c8c.d.ts → config-24b4f209.d.ts} +16 -2
- package/dist/index.d.ts +37 -7
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/node/cli.js +44 -5
- package/dist/node/cli.mjs +44 -5
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.js +1 -1
- package/dist/node/index.mjs +1 -1
- package/package.json +15 -13
- package/src/client/components/PostCard.vue +15 -16
- package/src/client/components/ValaxyMd.vue +1 -1
- package/src/client/components/ValaxySidebar.vue +0 -2
- package/src/client/components/ValaxyToc.vue +1 -1
- package/src/client/composables/category.ts +24 -5
- package/src/client/composables/comments/index.ts +1 -0
- package/src/client/composables/comments/twikoo.ts +37 -0
- package/src/client/composables/comments/waline.ts +0 -1
- package/src/client/composables/common.ts +2 -1
- package/src/client/composables/post.ts +26 -1
- package/src/client/composables/tag.ts +9 -2
- package/src/client/index.html +5 -0
- package/src/client/layouts/404.vue +5 -1
- package/src/client/main.ts +1 -3
- package/src/client/modules/valaxy.ts +3 -2
- package/src/client/shims.d.ts +0 -5
- package/src/client/styles/common/code.scss +181 -9
- package/src/client/styles/common/custom-blocks.scss +84 -0
- package/src/client/styles/common/markdown.scss +1 -4
- package/src/client/styles/css-vars.scss +12 -5
- package/src/client/styles/global/i18n.scss +20 -0
- package/src/client/styles/index.scss +21 -8
- package/src/client/styles/palette.scss +57 -48
- package/src/node/cli.ts +15 -0
- package/src/node/markdown/headings.ts +3 -2
- package/src/node/markdown/highlight.ts +50 -0
- package/src/node/markdown/highlightLines.ts +96 -0
- package/src/node/markdown/index.ts +20 -11
- package/src/node/markdown/markdown-it-container.ts +9 -1
- package/src/node/plugins/index.ts +1 -1
- package/src/node/plugins/preset.ts +2 -2
- package/src/node/plugins/unocss.ts +9 -12
- package/src/node/rss.ts +127 -0
- package/src/node/shims.d.ts +10 -0
- package/src/types/config.ts +28 -2
- package/src/types/posts.ts +6 -1
- package/dist/chunk-5D7M5SQP.js +0 -1
- package/dist/chunk-CF6MGLH2.mjs +0 -84
- package/dist/chunk-L22LX2G6.mjs +0 -1
- package/dist/chunk-W5MJCUNY.js +0 -84
- package/src/client/pages/posts/index.md +0 -5
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
// import common and light/dark css vars in main.ts
|
|
2
2
|
|
|
3
|
+
$c-primary: #0078e7 !default;
|
|
4
|
+
|
|
3
5
|
// global css
|
|
4
|
-
@use
|
|
5
|
-
@use
|
|
6
|
-
@use
|
|
7
|
-
@use
|
|
6
|
+
@use "./global/reset.scss" as *;
|
|
7
|
+
@use "./global/helper.scss" as *;
|
|
8
|
+
@use "./global/index.scss" as *;
|
|
9
|
+
@use "./global/i18n.scss" as *;
|
|
10
|
+
@use "./global/nprogress.scss" as *;
|
|
8
11
|
|
|
9
12
|
// common
|
|
10
|
-
@use
|
|
11
|
-
@use
|
|
12
|
-
@use
|
|
13
|
+
@use "./common/button.scss" as *;
|
|
14
|
+
@use "./common/code.scss" as *;
|
|
15
|
+
@use "./common/custom-blocks.scss" as *;
|
|
16
|
+
@use "./common/hamburger.scss" as *;
|
|
17
|
+
|
|
13
18
|
@use "./common/scrollbar.scss" as *;
|
|
14
19
|
@use "./common/sidebar.scss" as *;
|
|
15
20
|
@use "./common/transition.scss" as *;
|
|
16
21
|
|
|
17
22
|
// banner
|
|
18
|
-
@use
|
|
23
|
+
@use "./widgets/banner.scss" as *;
|
|
24
|
+
|
|
25
|
+
// markdown
|
|
26
|
+
@use "./common/markdown.scss";
|
|
27
|
+
@forward "star-markdown-css/src/scss/theme/yun.scss" with (
|
|
28
|
+
$colors: (
|
|
29
|
+
"primary": $c-primary,
|
|
30
|
+
)
|
|
31
|
+
);
|
|
@@ -4,64 +4,73 @@
|
|
|
4
4
|
@use "./mixins" as *;
|
|
5
5
|
|
|
6
6
|
$palette: () !default;
|
|
7
|
-
$palette: map.merge(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
$palette: map.merge(
|
|
8
|
+
(
|
|
9
|
+
"white": #ffffff,
|
|
10
|
+
"black": #1a1a1a,
|
|
11
|
+
"gray": #8e8e8e,
|
|
12
|
+
"danger": #db2828,
|
|
13
|
+
"warning": #f2711c,
|
|
14
|
+
),
|
|
15
|
+
$palette
|
|
16
|
+
);
|
|
14
17
|
|
|
15
18
|
$colors: () !default;
|
|
16
|
-
$colors: map.merge(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
$colors: map.merge(
|
|
20
|
+
(
|
|
21
|
+
"primary": #0078e7,
|
|
22
|
+
),
|
|
23
|
+
$colors
|
|
24
|
+
);
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
// $yun-c-primary: #0078E7 !default;
|
|
22
|
-
// @if meta.variable-exists('yun-c-primary') {
|
|
23
|
-
// $colors: map.merge((
|
|
24
|
-
// 'primary': $yun-c-primary,
|
|
25
|
-
// ), $colors);
|
|
26
|
-
// }
|
|
27
|
-
|
|
28
|
-
$c-primary: map.get($colors, 'primary') !default;
|
|
29
|
-
|
|
30
|
-
$colors: map.merge((
|
|
31
|
-
'primary-light': lighten($c-primary, 15%),
|
|
32
|
-
'primary-lighter': lighten($c-primary, 30%),
|
|
33
|
-
'primary-dark': darken($c-primary, 5%),
|
|
34
|
-
), $colors);
|
|
26
|
+
$c-primary: map.get($colors, "primary") !default;
|
|
35
27
|
|
|
28
|
+
$colors: map.merge(
|
|
29
|
+
(
|
|
30
|
+
"primary-light": lighten($c-primary, 15%),
|
|
31
|
+
"primary-lighter": lighten($c-primary, 30%),
|
|
32
|
+
"primary-dark": darken($c-primary, 5%),
|
|
33
|
+
),
|
|
34
|
+
$colors
|
|
35
|
+
);
|
|
36
36
|
|
|
37
37
|
$light: () !default;
|
|
38
|
-
$light: map.merge(
|
|
39
|
-
|
|
38
|
+
$light: map.merge(
|
|
39
|
+
(
|
|
40
|
+
"border-color": #222,
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
"c-bg": white,
|
|
43
|
+
"c-bg-light": white,
|
|
44
|
+
"c-bg-dark": #fafafa,
|
|
45
|
+
"c-text": #333,
|
|
46
|
+
"c-text-light": #555,
|
|
47
|
+
"c-text-dark": #111,
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
"c-primary-rgb": #{red($c-primary),
|
|
50
|
+
green(
|
|
51
|
+
$c-primary,
|
|
52
|
+
),
|
|
53
|
+
blue($c-primary)},
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
),
|
|
55
|
+
"c-link": get-css-var("c-primary-dark"),
|
|
56
|
+
),
|
|
57
|
+
$light
|
|
58
|
+
);
|
|
52
59
|
|
|
53
60
|
$dark: () !default;
|
|
54
|
-
$dark: map.merge(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
'c-bg': #1a1a1a,
|
|
58
|
-
'c-bg-light': #22252e,
|
|
59
|
-
'c-bg-dark': #1a1a1a,
|
|
61
|
+
$dark: map.merge(
|
|
62
|
+
(
|
|
63
|
+
"border-color": #e6e6e6,
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
'c-text-dark': rgba(#ebebeb, 0.8),
|
|
65
|
+
"c-bg": #1a1a1a,
|
|
66
|
+
"c-bg-light": #22252e,
|
|
67
|
+
"c-bg-dark": #1a1a1a,
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
"c-text": #f2f2f2,
|
|
70
|
+
"c-text-light": #eee,
|
|
71
|
+
"c-text-lighter": #ddd,
|
|
72
|
+
"c-text-dark": rgba(#ebebeb, 0.8),
|
|
73
|
+
"c-link": map.get($colors, "primary-light"),
|
|
74
|
+
),
|
|
75
|
+
$dark
|
|
76
|
+
);
|
package/src/node/cli.ts
CHANGED
|
@@ -14,6 +14,8 @@ import { bindShortcut, initServer, printInfo } from './utils/cli'
|
|
|
14
14
|
|
|
15
15
|
// build
|
|
16
16
|
import { build, ssgBuild } from './build'
|
|
17
|
+
// rss
|
|
18
|
+
import { build as rssBuild } from './rss'
|
|
17
19
|
|
|
18
20
|
const cli = yargs.scriptName('valaxy')
|
|
19
21
|
.usage('$0 [args]')
|
|
@@ -157,6 +159,19 @@ cli.command(
|
|
|
157
159
|
},
|
|
158
160
|
)
|
|
159
161
|
|
|
162
|
+
cli.command(
|
|
163
|
+
'rss [root]',
|
|
164
|
+
'generate rss feed',
|
|
165
|
+
args => commonOptions(args)
|
|
166
|
+
.strict()
|
|
167
|
+
.help(),
|
|
168
|
+
async({ root }) => {
|
|
169
|
+
consola.info('Generate RSS ...')
|
|
170
|
+
const options = await resolveOptions({ userRoot: root }, 'build')
|
|
171
|
+
await rssBuild(options)
|
|
172
|
+
},
|
|
173
|
+
)
|
|
174
|
+
|
|
160
175
|
/**
|
|
161
176
|
* set common options for cli
|
|
162
177
|
* @param args
|
|
@@ -4,10 +4,11 @@ import type { MarkdownRenderer } from '../markdown'
|
|
|
4
4
|
import { deeplyParseHeader } from './parseHeader'
|
|
5
5
|
import { slugify } from './slugify'
|
|
6
6
|
|
|
7
|
-
export const headingPlugin = (md: MarkdownIt, include = [
|
|
7
|
+
export const headingPlugin = (md: MarkdownIt, include = [1, 2, 3, 4]) => {
|
|
8
8
|
md.renderer.rules.heading_open = (tokens, i, options, env, self) => {
|
|
9
9
|
const token = tokens[i]
|
|
10
|
-
|
|
10
|
+
const tags = include.map(item => `h${item}`)
|
|
11
|
+
if (tags.includes(token.tag)) {
|
|
11
12
|
const title = tokens[i + 1].content
|
|
12
13
|
const idAttr = token.attrs!.find(([name]) => name === 'id')
|
|
13
14
|
const slug = idAttr && idAttr[1]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import consola from 'consola'
|
|
2
|
+
import escapeHtml from 'escape-html'
|
|
3
|
+
import prism from 'prismjs'
|
|
4
|
+
|
|
5
|
+
// prism is listed as actual dep so it's ok to require
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
7
|
+
const loadLanguages = require('prismjs/components/index')
|
|
8
|
+
|
|
9
|
+
// required to make embedded highlighting work...
|
|
10
|
+
loadLanguages(['markup', 'css', 'javascript'])
|
|
11
|
+
|
|
12
|
+
function wrap(code: string, lang: string): string {
|
|
13
|
+
if (lang === 'text')
|
|
14
|
+
code = escapeHtml(code)
|
|
15
|
+
|
|
16
|
+
return `<pre v-pre><code>${code}</code></pre>`
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const highlight = (str: string, lang: string) => {
|
|
20
|
+
if (!lang)
|
|
21
|
+
return wrap(str, 'text')
|
|
22
|
+
|
|
23
|
+
lang = lang.toLowerCase()
|
|
24
|
+
const rawLang = lang
|
|
25
|
+
if (lang === 'vue' || lang === 'html')
|
|
26
|
+
lang = 'markup'
|
|
27
|
+
|
|
28
|
+
if (lang === 'md')
|
|
29
|
+
lang = 'markdown'
|
|
30
|
+
|
|
31
|
+
if (lang === 'ts')
|
|
32
|
+
lang = 'typescript'
|
|
33
|
+
|
|
34
|
+
if (lang === 'py')
|
|
35
|
+
lang = 'python'
|
|
36
|
+
|
|
37
|
+
if (!prism.languages[lang]) {
|
|
38
|
+
try {
|
|
39
|
+
loadLanguages([lang])
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
consola.warn(`[valaxy] Syntax highlight for language "${lang}" is not supported.`)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (prism.languages[lang]) {
|
|
46
|
+
const code = prism.highlight(str, prism.languages[lang], lang)
|
|
47
|
+
return wrap(code, rawLang)
|
|
48
|
+
}
|
|
49
|
+
return wrap(str, 'text')
|
|
50
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Modified from https://github.com/egoist/markdown-it-highlight-lines
|
|
2
|
+
import type MarkdownIt from 'markdown-it'
|
|
3
|
+
|
|
4
|
+
const wrapperRE = /^<pre .*?><code>/
|
|
5
|
+
|
|
6
|
+
export const highlightLinePlugin = (md: MarkdownIt) => {
|
|
7
|
+
const fence = md.renderer.rules.fence!
|
|
8
|
+
md.renderer.rules.fence = (...args) => {
|
|
9
|
+
const [tokens, idx, options] = args
|
|
10
|
+
const token = tokens[idx]
|
|
11
|
+
|
|
12
|
+
// due to use of markdown-it-attrs, the {0} syntax would have been converted
|
|
13
|
+
// to attrs on the token
|
|
14
|
+
const attr = token.attrs && token.attrs[0]
|
|
15
|
+
if (!attr)
|
|
16
|
+
return fence(...args)
|
|
17
|
+
|
|
18
|
+
const lines = attr[0]
|
|
19
|
+
if (!lines || !/[\d,-]+/.test(lines))
|
|
20
|
+
return fence(...args)
|
|
21
|
+
|
|
22
|
+
const lineNumbers = lines
|
|
23
|
+
.split(',')
|
|
24
|
+
.map(v => v.split('-').map(v => parseInt(v, 10)))
|
|
25
|
+
|
|
26
|
+
const code = options.highlight
|
|
27
|
+
? options.highlight(token.content, token.info, '')
|
|
28
|
+
: token.content
|
|
29
|
+
|
|
30
|
+
const rawCode = code.replace(wrapperRE, '')
|
|
31
|
+
const highlightLinesCode = rawCode
|
|
32
|
+
.split('\n')
|
|
33
|
+
.map((split, index) => {
|
|
34
|
+
const lineNumber = index + 1
|
|
35
|
+
const inRange = lineNumbers.some(([start, end]) => {
|
|
36
|
+
if (start && end)
|
|
37
|
+
return lineNumber >= start && lineNumber <= end
|
|
38
|
+
|
|
39
|
+
return lineNumber === start
|
|
40
|
+
})
|
|
41
|
+
if (inRange)
|
|
42
|
+
return '<div class="highlighted"> </div>'
|
|
43
|
+
|
|
44
|
+
return '<br>'
|
|
45
|
+
})
|
|
46
|
+
.join('')
|
|
47
|
+
|
|
48
|
+
const highlightLinesWrapperCode = `<div class="highlight-lines">${highlightLinesCode}</div>`
|
|
49
|
+
|
|
50
|
+
return highlightLinesWrapperCode + code
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// markdown-it plugin for wrapping <pre> ... </pre>.
|
|
55
|
+
//
|
|
56
|
+
// If your plugin was chained before preWrapper, you can add additional element directly.
|
|
57
|
+
// If your plugin was chained after preWrapper, you can use these slots:
|
|
58
|
+
// 1. <!--beforebegin-->
|
|
59
|
+
// 2. <!--afterbegin-->
|
|
60
|
+
// 3. <!--beforeend-->
|
|
61
|
+
// 4. <!--afterend-->
|
|
62
|
+
export const preWrapperPlugin = (md: MarkdownIt) => {
|
|
63
|
+
const fence = md.renderer.rules.fence!
|
|
64
|
+
md.renderer.rules.fence = (...args) => {
|
|
65
|
+
const [tokens, idx] = args
|
|
66
|
+
const token = tokens[idx]
|
|
67
|
+
const rawCode = fence(...args)
|
|
68
|
+
return `<div class="language-${token.info.trim()}">${rawCode}</div>`
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// markdown-it plugin for generating line numbers.
|
|
73
|
+
// It depends on preWrapper plugin.
|
|
74
|
+
export const lineNumberPlugin = (md: MarkdownIt) => {
|
|
75
|
+
const fence = md.renderer.rules.fence!
|
|
76
|
+
md.renderer.rules.fence = (...args) => {
|
|
77
|
+
const rawCode = fence(...args)
|
|
78
|
+
const code = rawCode.slice(
|
|
79
|
+
rawCode.indexOf('<code>'),
|
|
80
|
+
rawCode.indexOf('</code>'),
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
const lines = code.split('\n')
|
|
84
|
+
const lineNumbersCode = [...Array(lines.length - 1)]
|
|
85
|
+
.map((line, index) => `<span class="line-number">${index + 1}</span><br>`)
|
|
86
|
+
.join('')
|
|
87
|
+
|
|
88
|
+
const lineNumbersWrapperCode = `<div class="line-numbers-wrapper">${lineNumbersCode}</div>`
|
|
89
|
+
|
|
90
|
+
const finalCode = rawCode
|
|
91
|
+
.replace(/<\/div>$/, `${lineNumbersWrapperCode}</div>`)
|
|
92
|
+
.replace(/"(language-\w+)"/, '"$1 line-numbers-mode"')
|
|
93
|
+
|
|
94
|
+
return finalCode
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -2,10 +2,10 @@ import type MarkdownIt from 'markdown-it'
|
|
|
2
2
|
|
|
3
3
|
import Anchor from 'markdown-it-anchor'
|
|
4
4
|
import Emoji from 'markdown-it-emoji'
|
|
5
|
-
import Prism from 'markdown-it-prism'
|
|
6
5
|
import LinkAttributes from 'markdown-it-link-attributes'
|
|
7
6
|
import TOC from 'markdown-it-table-of-contents'
|
|
8
7
|
import TaskLists from 'markdown-it-task-lists'
|
|
8
|
+
import attrs from 'markdown-it-attrs'
|
|
9
9
|
|
|
10
10
|
import type { KatexOptions } from 'katex'
|
|
11
11
|
import Katex from '../markdown/markdown-it-katex'
|
|
@@ -13,6 +13,8 @@ import { containerPlugin } from '../markdown/markdown-it-container'
|
|
|
13
13
|
import { headingPlugin } from '../markdown/headings'
|
|
14
14
|
import { slugify } from './slugify'
|
|
15
15
|
import { parseHeader } from './parseHeader'
|
|
16
|
+
import { highlight } from './highlight'
|
|
17
|
+
import { highlightLinePlugin, preWrapperPlugin } from './highlightLines'
|
|
16
18
|
|
|
17
19
|
export interface Header {
|
|
18
20
|
level: number
|
|
@@ -40,18 +42,25 @@ export interface MarkdownOptions extends MarkdownIt.Options {
|
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
export function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions = {}) {
|
|
45
|
+
md.set({
|
|
46
|
+
highlight,
|
|
47
|
+
})
|
|
43
48
|
md
|
|
49
|
+
.use(highlightLinePlugin)
|
|
50
|
+
.use(preWrapperPlugin)
|
|
44
51
|
.use(containerPlugin)
|
|
45
|
-
.use(headingPlugin)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
.use(headingPlugin, mdOptions?.toc?.includeLevel)
|
|
53
|
+
// .use(lineNumberPlugin)
|
|
54
|
+
// https://github.com/arve0/markdown-it-attrs
|
|
55
|
+
// add classes
|
|
56
|
+
md.use(attrs)
|
|
57
|
+
.use(LinkAttributes, {
|
|
58
|
+
matcher: (link: string) => /^https?:\/\//.test(link),
|
|
59
|
+
attrs: {
|
|
60
|
+
target: '_blank',
|
|
61
|
+
rel: 'noopener',
|
|
62
|
+
},
|
|
63
|
+
})
|
|
55
64
|
md.use(Katex, mdOptions.katex)
|
|
56
65
|
.use(Anchor, {
|
|
57
66
|
slugify,
|
|
@@ -24,7 +24,7 @@ function createContainer(classes: string, defaultTitle: string): ContainerArgs {
|
|
|
24
24
|
if (token.nesting === 1) {
|
|
25
25
|
if (classes === 'details') {
|
|
26
26
|
return `<details class="${classes} custom-block">${
|
|
27
|
-
|
|
27
|
+
`<summary>${info}</summary>`
|
|
28
28
|
}\n`
|
|
29
29
|
}
|
|
30
30
|
return `<div class="${classes} custom-block"><p class="custom-block-title">${
|
|
@@ -50,4 +50,12 @@ export const containerPlugin = (md: MarkdownIt) => {
|
|
|
50
50
|
render: (tokens: Token[], idx: number) =>
|
|
51
51
|
tokens[idx].nesting === 1 ? '<div v-pre>\n' : '</div>\n',
|
|
52
52
|
})
|
|
53
|
+
|
|
54
|
+
const languages = ['zh-CN', 'en']
|
|
55
|
+
languages.forEach((lang) => {
|
|
56
|
+
md.use(container, lang, {
|
|
57
|
+
render: (tokens: Token[], idx: number) =>
|
|
58
|
+
tokens[idx].nesting === 1 ? `<div lang="${lang}">\n` : '</div>\n',
|
|
59
|
+
})
|
|
60
|
+
})
|
|
53
61
|
}
|
|
@@ -42,7 +42,7 @@ function generateLocales(roots: string[]) {
|
|
|
42
42
|
roots.forEach((root, i) => {
|
|
43
43
|
languages.forEach((lang) => {
|
|
44
44
|
const langYml = `${root}/locales/${lang}.yml`
|
|
45
|
-
if (fs.existsSync(langYml)) {
|
|
45
|
+
if (fs.existsSync(langYml) && fs.readFileSync(langYml, 'utf-8')) {
|
|
46
46
|
const varName = lang.replace('-', '') + i
|
|
47
47
|
imports.push(`import ${varName} from "${langYml}"`)
|
|
48
48
|
imports.push(`Object.assign(messages['${lang}'], ${varName})`)
|
|
@@ -89,7 +89,7 @@ export async function ViteValaxyPlugins(
|
|
|
89
89
|
},
|
|
90
90
|
},
|
|
91
91
|
},
|
|
92
|
-
})
|
|
92
|
+
}),
|
|
93
93
|
|
|
94
94
|
ValaxyPlugin,
|
|
95
95
|
MarkdownPlugin,
|
|
@@ -210,7 +210,7 @@ export async function ViteValaxyPlugins(
|
|
|
210
210
|
runtimeOnly: true,
|
|
211
211
|
compositionOnly: true,
|
|
212
212
|
include: roots.map(root => `${root}/locales/**`),
|
|
213
|
-
})
|
|
213
|
+
}),
|
|
214
214
|
|
|
215
215
|
// https://github.com/antfu/vite-plugin-inspect
|
|
216
216
|
// Visit http://localhost:3333/__inspect/ to see the inspector
|
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
transformerVariantGroup,
|
|
13
13
|
} from 'unocss'
|
|
14
14
|
import type { ValaxyConfig } from 'valaxy'
|
|
15
|
-
import type { ThemeUserConfig } from 'valaxy-theme-yun
|
|
15
|
+
import type { ThemeUserConfig } from 'valaxy-theme-yun'
|
|
16
|
+
import { generateSafelist } from 'valaxy-theme-yun'
|
|
16
17
|
import type { ResolvedValaxyOptions } from '../options'
|
|
17
18
|
|
|
18
19
|
export const createSafelist = (config: ValaxyConfig<ThemeUserConfig>) => {
|
|
@@ -24,26 +25,22 @@ export const createSafelist = (config: ValaxyConfig<ThemeUserConfig>) => {
|
|
|
24
25
|
'i-ri-cloud-line',
|
|
25
26
|
]
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
let themeSafelist: string[] = []
|
|
29
|
+
if (typeof generateSafelist === 'function')
|
|
30
|
+
themeSafelist = generateSafelist(config.themeConfig)
|
|
31
|
+
|
|
32
|
+
const safelist = 'animate-fade-in m-auto text-left'.split(' ').concat([
|
|
28
33
|
'rotate-y-180',
|
|
29
|
-
]).concat(safeIcons)
|
|
34
|
+
]).concat(safeIcons).concat(themeSafelist)
|
|
35
|
+
|
|
30
36
|
// generate icon safelist
|
|
31
37
|
if (config.social.length)
|
|
32
38
|
config.social.forEach(item => safelist.push(item.icon))
|
|
33
39
|
|
|
34
|
-
if (config.themeConfig.footer?.icon?.name)
|
|
35
|
-
safelist.push(config.themeConfig.footer?.icon?.name)
|
|
36
|
-
|
|
37
40
|
// sponsor icon
|
|
38
41
|
if (config.sponsor.methods.length)
|
|
39
42
|
config.sponsor.methods.forEach(item => safelist.push(item.icon))
|
|
40
43
|
|
|
41
|
-
const types = config.themeConfig.types
|
|
42
|
-
if (types) {
|
|
43
|
-
for (const type in types)
|
|
44
|
-
safelist.push(types[type].icon)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
44
|
return safelist
|
|
48
45
|
}
|
|
49
46
|
|
package/src/node/rss.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { dirname } from 'path'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
|
|
4
|
+
import fg from 'fast-glob'
|
|
5
|
+
import fs from 'fs-extra'
|
|
6
|
+
import matter from 'gray-matter'
|
|
7
|
+
import MarkdownIt from 'markdown-it'
|
|
8
|
+
import type { Author, FeedOptions, Item } from 'feed'
|
|
9
|
+
import { Feed } from 'feed'
|
|
10
|
+
import consola from 'consola'
|
|
11
|
+
import type { ResolvedValaxyOptions } from './options'
|
|
12
|
+
|
|
13
|
+
const markdown = MarkdownIt({
|
|
14
|
+
html: true,
|
|
15
|
+
breaks: true,
|
|
16
|
+
linkify: true,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* generate rss
|
|
21
|
+
* @param options
|
|
22
|
+
* @returns
|
|
23
|
+
*/
|
|
24
|
+
export async function build(options: ResolvedValaxyOptions) {
|
|
25
|
+
const { config } = options
|
|
26
|
+
|
|
27
|
+
if (!config.url) {
|
|
28
|
+
consola.error('You must set "config.url" to generate rss.')
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const siteUrl = config.url.endsWith('/') ? config.url : `${config.url}/`
|
|
33
|
+
const DOMAIN = config.url.endsWith('/') ? config.url.slice(0, -1) : config.url
|
|
34
|
+
const author: Author = {
|
|
35
|
+
name: options.config.author.name,
|
|
36
|
+
email: options.config.author.email,
|
|
37
|
+
link: options.config.author.link,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
consola.info(`RSS Site Url: ${chalk.cyan(siteUrl)}`)
|
|
41
|
+
|
|
42
|
+
const ccVersion = (config.license.type === 'zero') ? '1.0' : '4.0'
|
|
43
|
+
const feedOptions: FeedOptions = {
|
|
44
|
+
title: config.title,
|
|
45
|
+
description: config.description,
|
|
46
|
+
id: siteUrl || 'valaxy',
|
|
47
|
+
link: siteUrl,
|
|
48
|
+
copyright: `CC ${config.license.type.toUpperCase()} ${ccVersion} ${new Date().getFullYear()} © ${config.author.name}`,
|
|
49
|
+
feedLinks: {
|
|
50
|
+
json: `${siteUrl}feed.json`,
|
|
51
|
+
atom: `${siteUrl}feed.atom`,
|
|
52
|
+
rss: `${siteUrl}feed.xml`,
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// generate
|
|
57
|
+
const files = await fg(`${options.userRoot}/pages/posts/**/*.md`)
|
|
58
|
+
|
|
59
|
+
const posts: Item[] = []
|
|
60
|
+
files
|
|
61
|
+
.forEach((i) => {
|
|
62
|
+
const raw = fs.readFileSync(i, 'utf-8')
|
|
63
|
+
const { data, content, excerpt } = matter(raw)
|
|
64
|
+
|
|
65
|
+
// not add to posts
|
|
66
|
+
if (!data.date) {
|
|
67
|
+
consola.warn(`Do you forget to write date for ${chalk.dim(i)}`)
|
|
68
|
+
return false
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (data.draft) {
|
|
72
|
+
consola.warn(`Ignore draft post: ${chalk.dim(i)}`)
|
|
73
|
+
return false
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// todo i18n
|
|
77
|
+
|
|
78
|
+
// render excerpt
|
|
79
|
+
const html = markdown.render(excerpt || content)
|
|
80
|
+
.replace('src="/', `src="${DOMAIN}/`)
|
|
81
|
+
|
|
82
|
+
if (data.image?.startsWith('/'))
|
|
83
|
+
data.image = DOMAIN + data.image
|
|
84
|
+
|
|
85
|
+
posts.push({
|
|
86
|
+
title: '',
|
|
87
|
+
...data,
|
|
88
|
+
id: (data.id || '').toString(),
|
|
89
|
+
date: new Date(data.date),
|
|
90
|
+
published: new Date(data.updated || data.date),
|
|
91
|
+
content: html,
|
|
92
|
+
author: [author],
|
|
93
|
+
link: DOMAIN + i.replace(`${options.userRoot}/pages`, '').replace(/\.md$/, ''),
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
// sort by updated
|
|
98
|
+
posts.sort((a, b) => +new Date(b.published || b.date) - +new Date(a.published || a.date))
|
|
99
|
+
// await writeFeed('feed', feedOptions, posts)
|
|
100
|
+
|
|
101
|
+
// write
|
|
102
|
+
feedOptions.author = author
|
|
103
|
+
feedOptions.image = config.author.avatar.startsWith('http') ? config.author.avatar : `${DOMAIN}${config.author.avatar}`
|
|
104
|
+
feedOptions.favicon = `${DOMAIN}/${config.feed.favicon}`
|
|
105
|
+
|
|
106
|
+
const feed = new Feed(feedOptions)
|
|
107
|
+
posts.forEach(item => feed.addItem(item))
|
|
108
|
+
// items.forEach(i=> console.log(i.title, i.date))
|
|
109
|
+
|
|
110
|
+
await fs.ensureDir(dirname(`./dist/${config.feed.name}`))
|
|
111
|
+
const path = './dist'
|
|
112
|
+
|
|
113
|
+
const types = ['xml', 'atom', 'json']
|
|
114
|
+
types.forEach((type) => {
|
|
115
|
+
let data = ''
|
|
116
|
+
let name = `${path}/${config.feed.name || 'feed'}.${type}`
|
|
117
|
+
if (type === 'xml') { data = feed.rss2() }
|
|
118
|
+
else if (type === 'atom') {
|
|
119
|
+
if (!config.feed.name)
|
|
120
|
+
name = `${path}/atom.xml`
|
|
121
|
+
data = feed.atom1()
|
|
122
|
+
}
|
|
123
|
+
else if (type === 'json') { data = feed.json1() }
|
|
124
|
+
fs.writeFileSync(name, data, 'utf-8')
|
|
125
|
+
consola.info(`${type}: ${name}`)
|
|
126
|
+
})
|
|
127
|
+
}
|
package/src/node/shims.d.ts
CHANGED