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.
- package/LICENSE +21 -0
- package/README.md +1 -1
- package/bin/valaxy.js +11 -0
- package/dist/build-OOT6HK6S.js +1 -0
- package/dist/build-SG32QSQ3.mjs +1 -0
- package/dist/chunk-7JDYOPID.js +1 -0
- package/dist/chunk-JJEBEWGI.mjs +1 -0
- package/dist/chunk-L3EDI35I.js +1 -0
- package/dist/chunk-L5SNNWFJ.js +78 -0
- package/dist/chunk-MVJUGWXR.mjs +1 -0
- package/dist/chunk-QI435Q25.mjs +78 -0
- package/dist/config-d6527c8c.d.ts +174 -0
- package/dist/node/cli.d.ts +3 -0
- package/dist/node/cli.js +6 -0
- package/dist/node/cli.mjs +6 -0
- package/dist/node/index.d.ts +45 -0
- package/dist/node/index.js +1 -0
- package/dist/node/index.mjs +1 -0
- package/dist/types/index.d.ts +110 -0
- package/dist/types/index.js +1 -0
- package/dist/types/index.mjs +1 -0
- package/package.json +75 -3
- package/src/client/App.vue +16 -0
- package/src/client/components/AppLink.vue +20 -0
- package/src/client/components/PostCard.vue +69 -0
- package/src/client/components/PostList.vue +50 -0
- package/src/client/components/README.md +7 -0
- package/src/client/components/ValaxyCopyright.vue +80 -0
- package/src/client/components/ValaxyFooter.vue +53 -0
- package/src/client/components/ValaxyHamburger.vue +21 -0
- package/src/client/components/ValaxyMd.vue +71 -0
- package/src/client/components/ValaxyOverlay.vue +44 -0
- package/src/client/components/ValaxyPagination.vue +122 -0
- package/src/client/components/ValaxyRightSidebar.vue +32 -0
- package/src/client/components/ValaxySidebar.vue +35 -0
- package/src/client/components/ValaxyToc.vue +70 -0
- package/src/client/composables/category.ts +101 -0
- package/src/client/composables/comments/index.ts +1 -0
- package/src/client/composables/comments/waline.ts +60 -0
- package/src/client/composables/common.ts +27 -0
- package/src/client/composables/dark.ts +4 -0
- package/src/client/composables/features/index.ts +1 -0
- package/src/client/composables/features/katex.ts +15 -0
- package/src/client/composables/helper.ts +26 -0
- package/src/client/composables/index.ts +17 -0
- package/src/client/composables/layout.ts +7 -0
- package/src/client/composables/post.ts +96 -0
- package/src/client/composables/search/algolia.ts +114 -0
- package/src/client/composables/search/index.ts +0 -0
- package/src/client/composables/sidebar.ts +128 -0
- package/src/client/composables/tag.ts +70 -0
- package/src/client/composables/widgets/aplayer.ts +23 -0
- package/src/client/composables/widgets/backToTop.ts +28 -0
- package/src/client/composables/widgets/codepen.ts +12 -0
- package/src/client/composables/widgets/index.ts +3 -0
- package/src/client/index.html +24 -0
- package/src/client/layouts/404.vue +25 -0
- package/src/client/layouts/README.md +14 -0
- package/src/client/locales/README.md +7 -0
- package/src/client/locales/en.yml +107 -0
- package/src/client/locales/zh-CN.yml +106 -0
- package/src/client/main.ts +30 -0
- package/src/client/modules/README.md +11 -0
- package/src/client/modules/nprogress.ts +14 -0
- package/src/client/modules/pinia.ts +17 -0
- package/src/client/modules/pwa.ts +12 -0
- package/src/client/modules/valaxy.ts +42 -0
- package/src/client/pages/README.md +20 -0
- package/src/client/pages/[...all].vue +15 -0
- package/src/client/pages/about/index.md +5 -0
- package/src/client/pages/hi/[name].vue +52 -0
- package/src/client/pages/index.vue +3 -0
- package/src/client/pages/page/[page].vue +12 -0
- package/src/client/pages/posts/index.md +5 -0
- package/src/client/public/_headers +3 -0
- package/src/client/public/favicon.svg +21 -0
- package/src/client/public/pwa-192x192.png +0 -0
- package/src/client/public/pwa-512x512.png +0 -0
- package/src/client/public/safari-pinned-tab.svg +41 -0
- package/src/client/shims.d.ts +36 -0
- package/src/client/stores/app.ts +14 -0
- package/src/client/stores/user.ts +35 -0
- package/src/client/styles/common/button.scss +29 -0
- package/src/client/styles/common/code.scss +35 -0
- package/src/client/styles/common/hamburger.scss +56 -0
- package/src/client/styles/common/markdown.scss +43 -0
- package/src/client/styles/common/scrollbar.scss +34 -0
- package/src/client/styles/common/sidebar.scss +30 -0
- package/src/client/styles/common/transition.scss +23 -0
- package/src/client/styles/css-vars/dark.scss +17 -0
- package/src/client/styles/css-vars/index.scss +18 -0
- package/src/client/styles/css-vars/light.scss +9 -0
- package/src/client/styles/global/helper.scss +3 -0
- package/src/client/styles/global/index.scss +38 -0
- package/src/client/styles/global/nprogress.scss +14 -0
- package/src/client/styles/global/reset.scss +20 -0
- package/src/client/styles/index.scss +18 -0
- package/src/client/styles/mixins/config.scss +1 -0
- package/src/client/styles/mixins/index.scss +2 -0
- package/src/client/styles/mixins/size.scss +49 -0
- package/src/client/styles/mixins/variable.scss +30 -0
- package/src/client/styles/palette.scss +61 -0
- package/src/client/styles/vars.scss +39 -0
- package/src/client/styles/widgets/banner.scss +116 -0
- package/src/client/types.ts +3 -0
- package/src/client/utils/helper.ts +30 -0
- package/src/client/utils/index.ts +2 -0
- package/src/client/utils/time.ts +23 -0
- package/src/core/config.ts +51 -0
- package/src/core/index.ts +5 -0
- package/src/core/utils.ts +1 -0
- package/src/index.ts +2 -0
- package/src/node/build.ts +12 -0
- package/src/node/cli.ts +177 -0
- package/src/node/config.ts +43 -0
- package/src/node/index.ts +1 -0
- package/src/node/markdown/headings.ts +24 -0
- package/src/node/markdown/index.ts +74 -0
- package/src/node/markdown/markdown-it-container.ts +53 -0
- package/src/node/markdown/markdown-it-katex.ts +200 -0
- package/src/node/markdown/parseHeader.ts +70 -0
- package/src/node/markdown/slugify.ts +24 -0
- package/src/node/options.ts +90 -0
- package/src/node/plugins/extendConfig.ts +28 -0
- package/src/node/plugins/index.ts +91 -0
- package/src/node/plugins/markdown.ts +62 -0
- package/src/node/plugins/preset.ts +174 -0
- package/src/node/plugins/unocss.ts +106 -0
- package/src/node/plugins/valaxy.ts +1 -0
- package/src/node/server.ts +21 -0
- package/src/node/shims.d.ts +23 -0
- package/src/node/utils/cli.ts +105 -0
- package/src/node/utils/index.ts +26 -0
- package/src/node/vite.ts +83 -0
- package/src/types/config.ts +250 -0
- package/src/types/index.ts +2 -0
- package/src/types/posts.ts +107 -0
- package/tsup.config.ts +17 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// copy from https://github.com/slidevjs/slidev/blob/main/packages/slidev/node/plugins/markdown-it-katex.ts
|
|
2
|
+
// Ported from https://github.com/waylonflinn/markdown-it-katex
|
|
3
|
+
|
|
4
|
+
/* Process inline math */
|
|
5
|
+
/*
|
|
6
|
+
Like markdown-it-simplemath, this is a stripped down, simplified version of:
|
|
7
|
+
https://github.com/runarberg/markdown-it-math
|
|
8
|
+
|
|
9
|
+
It differs in that it takes (a subset of) LaTeX as input and relies on KaTeX
|
|
10
|
+
for rendering output.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { KatexOptions } from 'katex'
|
|
14
|
+
import katex from 'katex'
|
|
15
|
+
|
|
16
|
+
// Test if potential opening or closing delimieter
|
|
17
|
+
// Assumes that there is a "$" at state.src[pos]
|
|
18
|
+
function isValidDelim(state: any, pos: number) {
|
|
19
|
+
const max = state.posMax
|
|
20
|
+
let can_open = true
|
|
21
|
+
let can_close = true
|
|
22
|
+
|
|
23
|
+
const prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1
|
|
24
|
+
const nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1
|
|
25
|
+
|
|
26
|
+
// Check non-whitespace conditions for opening and closing, and
|
|
27
|
+
// check that closing delimeter isn't followed by a number
|
|
28
|
+
if (prevChar === 0x20/* " " */ || prevChar === 0x09
|
|
29
|
+
||/* \t */ (nextChar >= 0x30/* "0" */ && nextChar <= 0x39/* "9" */))
|
|
30
|
+
can_close = false
|
|
31
|
+
|
|
32
|
+
if (nextChar === 0x20/* " " */ || nextChar === 0x09/* \t */)
|
|
33
|
+
can_open = false
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
can_open,
|
|
37
|
+
can_close,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function math_inline(state: any, silent: boolean) {
|
|
42
|
+
let match, token, res, pos
|
|
43
|
+
|
|
44
|
+
if (state.src[state.pos] !== '$') return false
|
|
45
|
+
|
|
46
|
+
res = isValidDelim(state, state.pos)
|
|
47
|
+
if (!res.can_open) {
|
|
48
|
+
if (!silent) state.pending += '$'
|
|
49
|
+
state.pos += 1
|
|
50
|
+
return true
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// First check for and bypass all properly escaped delimieters
|
|
54
|
+
// This loop will assume that the first leading backtick can not
|
|
55
|
+
// be the first character in state.src, which is known since
|
|
56
|
+
// we have found an opening delimieter already.
|
|
57
|
+
const start = state.pos + 1
|
|
58
|
+
match = start
|
|
59
|
+
// eslint-disable-next-line no-cond-assign
|
|
60
|
+
while ((match = state.src.indexOf('$', match)) !== -1) {
|
|
61
|
+
// Found potential $, look for escapes, pos will point to
|
|
62
|
+
// first non escape when complete
|
|
63
|
+
pos = match - 1
|
|
64
|
+
while (state.src[pos] === '\\') pos -= 1
|
|
65
|
+
|
|
66
|
+
// Even number of escapes, potential closing delimiter found
|
|
67
|
+
if (((match - pos) % 2) === 1) break
|
|
68
|
+
match += 1
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// No closing delimter found. Consume $ and continue.
|
|
72
|
+
if (match === -1) {
|
|
73
|
+
if (!silent) state.pending += '$'
|
|
74
|
+
state.pos = start
|
|
75
|
+
return true
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Check if we have empty content, ie: $$. Do not parse.
|
|
79
|
+
if (match - start === 0) {
|
|
80
|
+
if (!silent) state.pending += '$$'
|
|
81
|
+
state.pos = start + 1
|
|
82
|
+
return true
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Check for valid closing delimiter
|
|
86
|
+
res = isValidDelim(state, match)
|
|
87
|
+
if (!res.can_close) {
|
|
88
|
+
if (!silent) state.pending += '$'
|
|
89
|
+
state.pos = start
|
|
90
|
+
return true
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!silent) {
|
|
94
|
+
token = state.push('math_inline', 'math', 0)
|
|
95
|
+
token.markup = '$'
|
|
96
|
+
token.content = state.src.slice(start, match)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
state.pos = match + 1
|
|
100
|
+
return true
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function math_block(state: any, start: number, end: number, silent: boolean) {
|
|
104
|
+
let firstLine; let lastLine; let next; let lastPos
|
|
105
|
+
let found = false
|
|
106
|
+
let pos = state.bMarks[start] + state.tShift[start]
|
|
107
|
+
let max = state.eMarks[start]
|
|
108
|
+
|
|
109
|
+
if (pos + 2 > max) return false
|
|
110
|
+
if (state.src.slice(pos, pos + 2) !== '$$') return false
|
|
111
|
+
|
|
112
|
+
pos += 2
|
|
113
|
+
firstLine = state.src.slice(pos, max)
|
|
114
|
+
|
|
115
|
+
if (silent) return true
|
|
116
|
+
if (firstLine.trim().slice(-2) === '$$') {
|
|
117
|
+
// Single line expression
|
|
118
|
+
firstLine = firstLine.trim().slice(0, -2)
|
|
119
|
+
found = true
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (next = start; !found;) {
|
|
123
|
+
next++
|
|
124
|
+
|
|
125
|
+
if (next >= end) break
|
|
126
|
+
|
|
127
|
+
pos = state.bMarks[next] + state.tShift[next]
|
|
128
|
+
max = state.eMarks[next]
|
|
129
|
+
|
|
130
|
+
if (pos < max && state.tShift[next] < state.blkIndent) {
|
|
131
|
+
// non-empty line with negative indent should stop the list:
|
|
132
|
+
break
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (state.src.slice(pos, max).trim().slice(-2) === '$$') {
|
|
136
|
+
lastPos = state.src.slice(0, max).lastIndexOf('$$')
|
|
137
|
+
lastLine = state.src.slice(pos, lastPos)
|
|
138
|
+
found = true
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
state.line = next + 1
|
|
143
|
+
|
|
144
|
+
const token = state.push('math_block', 'math', 0)
|
|
145
|
+
token.block = true
|
|
146
|
+
token.content = (firstLine && firstLine.trim() ? `${firstLine}\n` : '')
|
|
147
|
+
+ state.getLines(start + 1, next, state.tShift[start], true)
|
|
148
|
+
+ (lastLine && lastLine.trim() ? lastLine : '')
|
|
149
|
+
token.map = [start, state.line]
|
|
150
|
+
token.markup = '$$'
|
|
151
|
+
return true
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export default function math_plugin(md: any, options: KatexOptions) {
|
|
155
|
+
// Default options
|
|
156
|
+
|
|
157
|
+
options = options || {}
|
|
158
|
+
|
|
159
|
+
// set KaTeX as the renderer for markdown-it-simplemath
|
|
160
|
+
const katexInline = function(latex: string) {
|
|
161
|
+
options.displayMode = false
|
|
162
|
+
try {
|
|
163
|
+
return katex.renderToString(latex, options)
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
if (options.throwOnError)
|
|
167
|
+
// eslint-disable-next-line no-console
|
|
168
|
+
console.warn(error)
|
|
169
|
+
return latex
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const inlineRenderer = function(tokens: any, idx: number) {
|
|
174
|
+
return katexInline(tokens[idx].content)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const katexBlock = function(latex: string) {
|
|
178
|
+
options.displayMode = true
|
|
179
|
+
try {
|
|
180
|
+
return `<p>${katex.renderToString(latex, options)}</p>`
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
if (options.throwOnError)
|
|
184
|
+
// eslint-disable-next-line no-console
|
|
185
|
+
console.warn(error)
|
|
186
|
+
return latex
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const blockRenderer = function(tokens: any, idx: number) {
|
|
191
|
+
return `${katexBlock(tokens[idx].content)}\n`
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
md.inline.ruler.after('escape', 'math_inline', math_inline)
|
|
195
|
+
md.block.ruler.after('blockquote', 'math_block', math_block, {
|
|
196
|
+
alt: ['paragraph', 'reference', 'blockquote', 'list'],
|
|
197
|
+
})
|
|
198
|
+
md.renderer.rules.math_inline = inlineRenderer
|
|
199
|
+
md.renderer.rules.math_block = blockRenderer
|
|
200
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// ref vitepress
|
|
2
|
+
|
|
3
|
+
// Since VuePress needs to extract the header from the markdown source
|
|
4
|
+
// file and display it in the sidebar or title (#238), this file simply
|
|
5
|
+
// removes some unnecessary elements to make header displays well at
|
|
6
|
+
// sidebar or title.
|
|
7
|
+
//
|
|
8
|
+
// But header's parsing in the markdown content is done by the markdown
|
|
9
|
+
// loader based on markdown-it. markdown-it parser will will always keep
|
|
10
|
+
// HTML in headers, so in VuePress, after being parsed by the markdown
|
|
11
|
+
// loader, the raw HTML in headers will finally be parsed by Vue-loader.
|
|
12
|
+
// so that we can write HTML/Vue in the header. One exception is the HTML
|
|
13
|
+
// wrapped by <code>(markdown token: '`') tag.
|
|
14
|
+
import emojiData from 'markdown-it-emoji/lib/data/full.json'
|
|
15
|
+
|
|
16
|
+
const parseEmojis = (str: string) => {
|
|
17
|
+
return str.replace(
|
|
18
|
+
/:(.+?):/g,
|
|
19
|
+
(placeholder, key) => (emojiData as any)[key] || placeholder,
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const unescapeHtml = (html: string) =>
|
|
24
|
+
html
|
|
25
|
+
.replace(/"/g, '"')
|
|
26
|
+
.replace(/'/g, '\'')
|
|
27
|
+
.replace(/:/g, ':')
|
|
28
|
+
.replace(/</g, '<')
|
|
29
|
+
.replace(/>/g, '>')
|
|
30
|
+
|
|
31
|
+
const removeMarkdownTokens = (str: string) =>
|
|
32
|
+
str
|
|
33
|
+
.replace(/(\[(.[^\]]+)\]\((.[^)]+)\))/g, '$2') // []()
|
|
34
|
+
.replace(/(`|\*{1,3}|_)(.*?[^\\])\1/g, '$2') // `{t}` | *{t}* | **{t}** | ***{t}*** | _{t}_
|
|
35
|
+
.replace(/(\\)(\*|_|`|\!|<|\$)/g, '$2') // remove escape char '\'
|
|
36
|
+
|
|
37
|
+
const remvoeCustomAnchor = (str: string) =>
|
|
38
|
+
str.replace(/\{#([a-z0-9\-_]+?)\}\s*$/, '') // {#custom-header}
|
|
39
|
+
|
|
40
|
+
const trim = (str: string) => str.trim()
|
|
41
|
+
|
|
42
|
+
// This method remove the raw HTML but reserve the HTML wrapped by `<code>`.
|
|
43
|
+
// e.g.
|
|
44
|
+
// Input: "<a> b", Output: "b"
|
|
45
|
+
// Input: "`<a>` b", Output: "`<a>` b"
|
|
46
|
+
export const removeNonCodeWrappedHTML = (str: string) => {
|
|
47
|
+
return String(str).replace(/(^|[^><`\\])<.*>([^><`]|$)/g, '$1$2')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const compose = (...processors: ((str: string) => string)[]) => {
|
|
51
|
+
if (processors.length === 0) return (input: string) => input
|
|
52
|
+
if (processors.length === 1) return processors[0]
|
|
53
|
+
return processors.reduce((prev, next) => {
|
|
54
|
+
return str => next(prev(str))
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Unescape html, parse emojis and remove some md tokens.
|
|
59
|
+
export const parseHeader = compose(
|
|
60
|
+
unescapeHtml,
|
|
61
|
+
parseEmojis,
|
|
62
|
+
remvoeCustomAnchor,
|
|
63
|
+
removeMarkdownTokens,
|
|
64
|
+
trim,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
// Also clean the html that isn't wrapped by code.
|
|
68
|
+
// Because we want to support using VUE components in headers.
|
|
69
|
+
// e.g. https://vuepress.vuejs.org/guide/using-vue.html#badge
|
|
70
|
+
export const deeplyParseHeader = compose(removeNonCodeWrappedHTML, parseHeader)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// ref vitepress
|
|
2
|
+
import { remove as removeDiacritics } from 'diacritics'
|
|
3
|
+
// eslint-disable-next-line no-control-regex
|
|
4
|
+
const rControl = /[\u0000-\u001F]/g
|
|
5
|
+
// add '…'
|
|
6
|
+
const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'<>,.…?/]+/g
|
|
7
|
+
|
|
8
|
+
export const slugify = (str: string): string => {
|
|
9
|
+
return (
|
|
10
|
+
removeDiacritics(str)
|
|
11
|
+
// Remove control characters
|
|
12
|
+
.replace(rControl, '')
|
|
13
|
+
// Replace special characters
|
|
14
|
+
.replace(rSpecial, '-')
|
|
15
|
+
// Remove continuous separators
|
|
16
|
+
.replace(/\-{2,}/g, '-')
|
|
17
|
+
// Remove prefixing and trailing separators
|
|
18
|
+
.replace(/^\-+|\-+$/g, '')
|
|
19
|
+
// ensure it doesn't start with a number (#121)
|
|
20
|
+
.replace(/^(\d)/, '_$1')
|
|
21
|
+
// lowercase
|
|
22
|
+
.toLowerCase()
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { dirname, resolve } from 'path'
|
|
2
|
+
import _debug from 'debug'
|
|
3
|
+
import type { ValaxyConfig } from '../types'
|
|
4
|
+
import { resolveConfig } from './config'
|
|
5
|
+
import { resolveImportPath } from './utils'
|
|
6
|
+
|
|
7
|
+
const debug = _debug('valaxy:options')
|
|
8
|
+
|
|
9
|
+
// for cli entry
|
|
10
|
+
export interface ValaxyEntryOptions {
|
|
11
|
+
/**
|
|
12
|
+
* theme name
|
|
13
|
+
*/
|
|
14
|
+
theme?: string
|
|
15
|
+
userRoot?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ResolvedValaxyOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Client root path
|
|
21
|
+
* @default 'valaxy/src/client'
|
|
22
|
+
*/
|
|
23
|
+
clientRoot: string
|
|
24
|
+
/**
|
|
25
|
+
* User root path
|
|
26
|
+
* @default process.cwd()
|
|
27
|
+
*/
|
|
28
|
+
userRoot: string
|
|
29
|
+
/**
|
|
30
|
+
* Theme root path
|
|
31
|
+
*/
|
|
32
|
+
themeRoot: string
|
|
33
|
+
/**
|
|
34
|
+
* Theme name
|
|
35
|
+
*/
|
|
36
|
+
theme: string
|
|
37
|
+
/**
|
|
38
|
+
* Valaxy Config
|
|
39
|
+
*/
|
|
40
|
+
config: ValaxyConfig
|
|
41
|
+
/**
|
|
42
|
+
* config file path
|
|
43
|
+
*/
|
|
44
|
+
configFile: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ValaxyServerOptions {
|
|
48
|
+
onConfigReload?: (newConfig: ValaxyConfig, config: ValaxyConfig) => void
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function isPath(name: string) {
|
|
52
|
+
return name.startsWith('/') || /^\.\.?[\/\\]/.test(name)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* get theme roots
|
|
57
|
+
* @param name
|
|
58
|
+
* @param entry
|
|
59
|
+
* @returns
|
|
60
|
+
*/
|
|
61
|
+
export function getThemeRoot(name: string, entry: string) {
|
|
62
|
+
if (!name)
|
|
63
|
+
return ''
|
|
64
|
+
|
|
65
|
+
if (isPath(name))
|
|
66
|
+
return resolve(dirname(entry), name)
|
|
67
|
+
else
|
|
68
|
+
return resolveImportPath(`valaxy-theme-${name}/package.json`)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// for cli options
|
|
72
|
+
export async function resolveOptions(options: ValaxyEntryOptions) {
|
|
73
|
+
const clientRoot = resolve(resolveImportPath('valaxy/package.json'), 'src/client')
|
|
74
|
+
const userRoot = resolve(options.userRoot || process.cwd())
|
|
75
|
+
|
|
76
|
+
const { config: valaxyConfig, configFile, theme } = await resolveConfig(options)
|
|
77
|
+
const themeRoot = getThemeRoot(theme, userRoot)
|
|
78
|
+
|
|
79
|
+
const valaxyOptions: ResolvedValaxyOptions = {
|
|
80
|
+
clientRoot,
|
|
81
|
+
userRoot,
|
|
82
|
+
themeRoot,
|
|
83
|
+
theme,
|
|
84
|
+
config: valaxyConfig,
|
|
85
|
+
configFile: configFile || '',
|
|
86
|
+
}
|
|
87
|
+
debug(valaxyOptions)
|
|
88
|
+
|
|
89
|
+
return valaxyOptions
|
|
90
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { resolve } from 'path'
|
|
2
|
+
import type { InlineConfig, Plugin } from 'vite'
|
|
3
|
+
import { mergeConfig } from 'vite'
|
|
4
|
+
import type { ResolvedValaxyOptions } from '../options'
|
|
5
|
+
import { toAtFS } from '../utils'
|
|
6
|
+
|
|
7
|
+
export function createConfigPlugin(options: ResolvedValaxyOptions): Plugin {
|
|
8
|
+
return {
|
|
9
|
+
name: 'valaxy:config',
|
|
10
|
+
config(config) {
|
|
11
|
+
const injection: InlineConfig = {
|
|
12
|
+
resolve: {
|
|
13
|
+
alias: {
|
|
14
|
+
'@/': `${toAtFS(options.userRoot)}/`,
|
|
15
|
+
'~/': `${toAtFS(options.clientRoot)}/`,
|
|
16
|
+
'@valaxyjs/client': `${toAtFS(options.clientRoot)}/`,
|
|
17
|
+
'@valaxyjs/config': '/@valaxyjs/config',
|
|
18
|
+
'valaxy/package.json': toAtFS(resolve(options.clientRoot, '../../package.json')),
|
|
19
|
+
'valaxy': toAtFS(resolve(options.clientRoot, '..')),
|
|
20
|
+
'@valaxyjs/core': toAtFS(resolve(options.clientRoot, '../core')),
|
|
21
|
+
[`valaxy-theme-${options.theme}`]: `${toAtFS(resolve(options.themeRoot))}/`,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
return mergeConfig(config, injection)
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
|
|
3
|
+
import { join } from 'path'
|
|
4
|
+
import type { Plugin } from 'vite'
|
|
5
|
+
// import consola from 'consola'
|
|
6
|
+
import { resolveConfig } from '../config'
|
|
7
|
+
import type { ResolvedValaxyOptions, ValaxyServerOptions } from '../options'
|
|
8
|
+
import { toAtFS } from '../utils'
|
|
9
|
+
import { VALAXY_CONFIG_ID } from './valaxy'
|
|
10
|
+
|
|
11
|
+
export function createValaxyPlugin(options: ResolvedValaxyOptions, serverOptions: ValaxyServerOptions = {}): Plugin {
|
|
12
|
+
const valaxyPrefix = '/@valaxy'
|
|
13
|
+
|
|
14
|
+
let valaxyConfig = options.config
|
|
15
|
+
|
|
16
|
+
const roots = [options.userRoot, options.themeRoot]
|
|
17
|
+
|
|
18
|
+
function generateUserStyles() {
|
|
19
|
+
const imports: string[] = []
|
|
20
|
+
|
|
21
|
+
for (const root of roots) {
|
|
22
|
+
const styles = [
|
|
23
|
+
join(root, 'styles', 'vars.scss'),
|
|
24
|
+
join(root, 'styles', 'index.css'),
|
|
25
|
+
join(root, 'styles', 'index.scss'),
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
for (const style of styles) {
|
|
29
|
+
if (fs.existsSync(style)) {
|
|
30
|
+
imports.push(`import "${toAtFS(style)}"`)
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return imports.join('\n')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
name: 'Valaxy',
|
|
41
|
+
|
|
42
|
+
configureServer(server) {
|
|
43
|
+
server.watcher.add([
|
|
44
|
+
options.configFile,
|
|
45
|
+
options.userRoot,
|
|
46
|
+
options.themeRoot,
|
|
47
|
+
])
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
resolveId(id) {
|
|
51
|
+
if (id.startsWith(valaxyPrefix))
|
|
52
|
+
return id
|
|
53
|
+
return null
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
load(id) {
|
|
57
|
+
if (id === `/${VALAXY_CONFIG_ID}`)
|
|
58
|
+
// stringify twice for \"
|
|
59
|
+
return `export default ${JSON.stringify(JSON.stringify(valaxyConfig))}`
|
|
60
|
+
|
|
61
|
+
// generate styles
|
|
62
|
+
if (id === '/@valaxyjs/styles')
|
|
63
|
+
return generateUserStyles()
|
|
64
|
+
|
|
65
|
+
if (id.startsWith(valaxyPrefix))
|
|
66
|
+
return ''
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
async handleHotUpdate(ctx) {
|
|
70
|
+
// handle valaxy.config.ts hmr
|
|
71
|
+
const { file, server } = ctx
|
|
72
|
+
if (file !== options.configFile) return
|
|
73
|
+
|
|
74
|
+
const { config } = await resolveConfig()
|
|
75
|
+
|
|
76
|
+
serverOptions.onConfigReload?.(config, options.config)
|
|
77
|
+
Object.assign(options.config, config)
|
|
78
|
+
|
|
79
|
+
// if (config.base !== options.config.base)
|
|
80
|
+
// consola.warn('[valaxy]: config.base has changed. Please restart the dev server.')
|
|
81
|
+
valaxyConfig = config
|
|
82
|
+
|
|
83
|
+
const moduleIds = [`/${VALAXY_CONFIG_ID}`]
|
|
84
|
+
const moduleEntries = [
|
|
85
|
+
...Array.from(moduleIds).map(id => server.moduleGraph.getModuleById(id)),
|
|
86
|
+
].filter(<T>(item: T): item is NonNullable<T> => !!item)
|
|
87
|
+
|
|
88
|
+
return moduleEntries
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import Markdown from 'vite-plugin-md'
|
|
3
|
+
|
|
4
|
+
import type { Plugin } from 'vite'
|
|
5
|
+
import type { ResolvedValaxyOptions } from '../options'
|
|
6
|
+
|
|
7
|
+
import type { MarkdownRenderer } from '../markdown'
|
|
8
|
+
import { setupMarkdownPlugins } from '../markdown'
|
|
9
|
+
import { slash } from '../utils'
|
|
10
|
+
// import { useRoute } from 'vue-router'
|
|
11
|
+
|
|
12
|
+
export type ViteMdOptions = Parameters<typeof Markdown>[0]
|
|
13
|
+
|
|
14
|
+
export const excerpt_separator = '<!-- more -->'
|
|
15
|
+
|
|
16
|
+
// https://github.com/antfu/vite-plugin-md
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
18
|
+
export function createMarkdownPlugin(options: ResolvedValaxyOptions): Plugin[] {
|
|
19
|
+
let _md: MarkdownRenderer
|
|
20
|
+
|
|
21
|
+
const mdOptions = options.config.markdownIt
|
|
22
|
+
|
|
23
|
+
const defaultOptions: ViteMdOptions = {
|
|
24
|
+
wrapperComponent: 'ValaxyMd',
|
|
25
|
+
|
|
26
|
+
headEnabled: true,
|
|
27
|
+
frontmatter: true,
|
|
28
|
+
|
|
29
|
+
excerpt: excerpt_separator,
|
|
30
|
+
|
|
31
|
+
builders: [
|
|
32
|
+
// avoid conflict with markdown-it-anchor link
|
|
33
|
+
// link(),
|
|
34
|
+
// seems bug, override frontmatter
|
|
35
|
+
// meta(),
|
|
36
|
+
],
|
|
37
|
+
|
|
38
|
+
markdownItSetup(md) {
|
|
39
|
+
if (mdOptions.config)
|
|
40
|
+
mdOptions.config(md)
|
|
41
|
+
|
|
42
|
+
_md = setupMarkdownPlugins(md, mdOptions)
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
return [Markdown(Object.assign(defaultOptions, options.config.markdown)), {
|
|
46
|
+
name: 'valaxy:md',
|
|
47
|
+
handleHotUpdate(ctx) {
|
|
48
|
+
const { file, server } = ctx
|
|
49
|
+
// send headers
|
|
50
|
+
if (file.endsWith('.md')) {
|
|
51
|
+
server.ws.send({
|
|
52
|
+
type: 'custom',
|
|
53
|
+
event: 'valaxy:pageHeaders',
|
|
54
|
+
data: {
|
|
55
|
+
path: `/${slash(path.relative(`${options.userRoot}/pages`, file))}`,
|
|
56
|
+
pageHeaders: _md.__data.headers,
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
}]
|
|
62
|
+
}
|