methanol 0.0.0 → 0.0.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/LICENSE +203 -0
- package/README.md +58 -0
- package/banner.txt +6 -0
- package/bin/methanol.js +24 -0
- package/index.js +22 -0
- package/package.json +51 -9
- package/src/assets.js +30 -0
- package/src/build-system.js +200 -0
- package/src/components.js +145 -0
- package/src/config.js +396 -0
- package/src/dev-server.js +632 -0
- package/src/main.js +133 -0
- package/src/mdx.js +406 -0
- package/src/node-loader.js +88 -0
- package/src/pagefind.js +107 -0
- package/src/pages.js +771 -0
- package/src/preview-server.js +58 -0
- package/src/public-assets.js +73 -0
- package/src/register-loader.js +29 -0
- package/src/rehype-plugins/link-resolve.js +116 -0
- package/src/rehype-plugins/methanol-ctx.js +89 -0
- package/src/renderer.js +25 -0
- package/src/rewind.js +117 -0
- package/src/stage-logger.js +59 -0
- package/src/state.js +179 -0
- package/src/virtual-module/inject.js +30 -0
- package/src/virtual-module/loader.js +116 -0
- package/src/virtual-module/pagefind.js +108 -0
- package/src/vite-plugins.js +173 -0
- package/themes/default/components/ThemeAccentSwitch.client.jsx +95 -0
- package/themes/default/components/ThemeAccentSwitch.static.jsx +23 -0
- package/themes/default/components/ThemeColorSwitch.client.jsx +95 -0
- package/themes/default/components/ThemeColorSwitch.static.jsx +23 -0
- package/themes/default/components/ThemeSearchBox.client.jsx +324 -0
- package/themes/default/components/ThemeSearchBox.static.jsx +40 -0
- package/themes/default/components/ThemeToCContainer.client.jsx +154 -0
- package/themes/default/components/ThemeToCContainer.static.jsx +61 -0
- package/themes/default/components/pre.client.jsx +84 -0
- package/themes/default/components/pre.static.jsx +27 -0
- package/themes/default/heading.jsx +35 -0
- package/themes/default/index.js +41 -0
- package/themes/default/page.jsx +303 -0
- package/themes/default/pages/404.mdx +8 -0
- package/themes/default/pages/index.mdx +31 -0
- package/themes/default/public/favicon.png +0 -0
- package/themes/default/public/logo.png +0 -0
- package/themes/default/sources/prefetch.js +49 -0
- package/themes/default/sources/style.css +1660 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* Copyright Yukino Song, SudoMaker Ltd.
|
|
2
|
+
*
|
|
3
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
* or more contributor license agreements. See the NOTICE file
|
|
5
|
+
* distributed with this work for additional information
|
|
6
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
* to you under the Apache License, Version 2.0 (the
|
|
8
|
+
* "License"); you may not use this file except in compliance
|
|
9
|
+
* with the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing,
|
|
14
|
+
* software distributed under the License is distributed on an
|
|
15
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
* KIND, either express or implied. See the License for the
|
|
17
|
+
* specific language governing permissions and limitations
|
|
18
|
+
* under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const buildTocItems = (items = []) => {
|
|
22
|
+
const nodes = []
|
|
23
|
+
for (const item of items) {
|
|
24
|
+
const childNodes = item?.children?.length ? buildTocItems(item.children) : []
|
|
25
|
+
const children = childNodes.length ? <ul>{childNodes}</ul> : null
|
|
26
|
+
if (item.depth < 2 || item.depth > 4) {
|
|
27
|
+
if (childNodes.length) {
|
|
28
|
+
nodes.push(...childNodes)
|
|
29
|
+
}
|
|
30
|
+
continue
|
|
31
|
+
}
|
|
32
|
+
nodes.push(
|
|
33
|
+
<li class={`toc-depth-${item.depth}`}>
|
|
34
|
+
<a href={`#${item.id}`}>{item.value}</a>
|
|
35
|
+
{children}
|
|
36
|
+
</li>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
return nodes
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const renderToc = (toc = []) => {
|
|
43
|
+
const items = buildTocItems(toc)
|
|
44
|
+
if (!items.length) return null
|
|
45
|
+
return items
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default function (props, ...children) {
|
|
49
|
+
if (!children.length) {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<aside class="toc-panel">
|
|
55
|
+
<div class="toc">
|
|
56
|
+
<h4>On this page</h4>
|
|
57
|
+
<ul>{...children}</ul>
|
|
58
|
+
</div>
|
|
59
|
+
</aside>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/* Copyright Yukino Song, SudoMaker Ltd.
|
|
2
|
+
*
|
|
3
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
* or more contributor license agreements. See the NOTICE file
|
|
5
|
+
* distributed with this work for additional information
|
|
6
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
* to you under the Apache License, Version 2.0 (the
|
|
8
|
+
* "License"); you may not use this file except in compliance
|
|
9
|
+
* with the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing,
|
|
14
|
+
* software distributed under the License is distributed on an
|
|
15
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
* KIND, either express or implied. See the License for the
|
|
17
|
+
* specific language governing permissions and limitations
|
|
18
|
+
* under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { signal } from 'refui'
|
|
22
|
+
|
|
23
|
+
export default function (props, ...children) {
|
|
24
|
+
const el = signal()
|
|
25
|
+
const copied = signal(false)
|
|
26
|
+
|
|
27
|
+
const copy = async function () {
|
|
28
|
+
if (el.value) {
|
|
29
|
+
try {
|
|
30
|
+
await navigator.clipboard.writeText(el.value.textContent)
|
|
31
|
+
copied.value = true
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
copied.value = false
|
|
34
|
+
}, 2000)
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.error('Failed to copy: ', err)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const Btn = copied.choose(
|
|
42
|
+
() => (
|
|
43
|
+
<svg
|
|
44
|
+
attr:width="14"
|
|
45
|
+
attr:height="14"
|
|
46
|
+
attr:viewBox="0 0 24 24"
|
|
47
|
+
attr:fill="none"
|
|
48
|
+
attr:stroke="currentColor"
|
|
49
|
+
attr:stroke-width="2.5"
|
|
50
|
+
attr:stroke-linecap="round"
|
|
51
|
+
attr:stroke-linejoin="round"
|
|
52
|
+
class="text-accent"
|
|
53
|
+
>
|
|
54
|
+
<polyline attr:points="20 6 9 17 4 12"></polyline>
|
|
55
|
+
</svg>
|
|
56
|
+
),
|
|
57
|
+
() => (
|
|
58
|
+
<svg
|
|
59
|
+
attr:width="14"
|
|
60
|
+
attr:height="14"
|
|
61
|
+
attr:viewBox="0 0 24 24"
|
|
62
|
+
attr:fill="none"
|
|
63
|
+
attr:stroke="currentColor"
|
|
64
|
+
attr:stroke-width="2"
|
|
65
|
+
attr:stroke-linecap="round"
|
|
66
|
+
attr:stroke-linejoin="round"
|
|
67
|
+
>
|
|
68
|
+
<rect attr:x="9" attr:y="9" attr:width="13" attr:height="13" attr:rx="2" attr:ry="2"></rect>
|
|
69
|
+
<path attr:d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
|
70
|
+
</svg>
|
|
71
|
+
)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div class="code-block-container">
|
|
76
|
+
<button class="copy-btn" on:click={copy} attr:aria-label="Copy code">
|
|
77
|
+
<Btn />
|
|
78
|
+
</button>
|
|
79
|
+
<pre {...props} $ref={el}>
|
|
80
|
+
{...children}
|
|
81
|
+
</pre>
|
|
82
|
+
</div>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* Copyright Yukino Song, SudoMaker Ltd.
|
|
2
|
+
*
|
|
3
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
* or more contributor license agreements. See the NOTICE file
|
|
5
|
+
* distributed with this work for additional information
|
|
6
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
* to you under the Apache License, Version 2.0 (the
|
|
8
|
+
* "License"); you may not use this file except in compliance
|
|
9
|
+
* with the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing,
|
|
14
|
+
* software distributed under the License is distributed on an
|
|
15
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
* KIND, either express or implied. See the License for the
|
|
17
|
+
* specific language governing permissions and limitations
|
|
18
|
+
* under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export default function (props, ...children) {
|
|
22
|
+
return (
|
|
23
|
+
<div class="code-block-container">
|
|
24
|
+
<pre {...props}>{...children}</pre>
|
|
25
|
+
</div>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* Copyright Yukino Song, SudoMaker Ltd.
|
|
2
|
+
*
|
|
3
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
* or more contributor license agreements. See the NOTICE file
|
|
5
|
+
* distributed with this work for additional information
|
|
6
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
* to you under the Apache License, Version 2.0 (the
|
|
8
|
+
* "License"); you may not use this file except in compliance
|
|
9
|
+
* with the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing,
|
|
14
|
+
* software distributed under the License is distributed on an
|
|
15
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
* KIND, either express or implied. See the License for the
|
|
17
|
+
* specific language governing permissions and limitations
|
|
18
|
+
* under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export function heading(Tag) {
|
|
22
|
+
return (props, ...children) => (
|
|
23
|
+
<Tag {...props}>
|
|
24
|
+
{props.id && <a class="heading-anchor" href={`#${props.id}`} aria-hidden />}
|
|
25
|
+
{...children}
|
|
26
|
+
</Tag>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createHeadings() {
|
|
31
|
+
return Object.fromEntries([1,2,3,4,5,6].map((i) => {
|
|
32
|
+
const tag = `h${i}`
|
|
33
|
+
return [tag, heading(tag)]
|
|
34
|
+
}))
|
|
35
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/* Copyright Yukino Song, SudoMaker Ltd.
|
|
2
|
+
*
|
|
3
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
* or more contributor license agreements. See the NOTICE file
|
|
5
|
+
* distributed with this work for additional information
|
|
6
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
* to you under the Apache License, Version 2.0 (the
|
|
8
|
+
* "License"); you may not use this file except in compliance
|
|
9
|
+
* with the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing,
|
|
14
|
+
* software distributed under the License is distributed on an
|
|
15
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
* KIND, either express or implied. See the License for the
|
|
17
|
+
* specific language governing permissions and limitations
|
|
18
|
+
* under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { readFileSync } from 'fs'
|
|
22
|
+
import { fileURLToPath } from 'url'
|
|
23
|
+
import { dirname, resolve } from 'path'
|
|
24
|
+
import PAGE_TEMPLATE from './page.jsx'
|
|
25
|
+
import { createHeadings } from './heading.jsx'
|
|
26
|
+
|
|
27
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
28
|
+
const __dirname = dirname(__filename)
|
|
29
|
+
|
|
30
|
+
export default () => {
|
|
31
|
+
return {
|
|
32
|
+
root: __dirname,
|
|
33
|
+
sources: {
|
|
34
|
+
'/.methanol_theme_default': './sources'
|
|
35
|
+
},
|
|
36
|
+
components: {
|
|
37
|
+
...createHeadings()
|
|
38
|
+
},
|
|
39
|
+
template: PAGE_TEMPLATE
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/* Copyright Yukino Song, SudoMaker Ltd.
|
|
2
|
+
*
|
|
3
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
* or more contributor license agreements. See the NOTICE file
|
|
5
|
+
* distributed with this work for additional information
|
|
6
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
* to you under the Apache License, Version 2.0 (the
|
|
8
|
+
* "License"); you may not use this file except in compliance
|
|
9
|
+
* with the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing,
|
|
14
|
+
* software distributed under the License is distributed on an
|
|
15
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
* KIND, either express or implied. See the License for the
|
|
17
|
+
* specific language governing permissions and limitations
|
|
18
|
+
* under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { HTMLRenderer as R } from 'methanol'
|
|
22
|
+
import { renderToc } from './components/ThemeToCContainer.static.jsx'
|
|
23
|
+
|
|
24
|
+
const renderPageTree = (nodes = [], currentRoute, depth = 0) => {
|
|
25
|
+
const items = []
|
|
26
|
+
let hasActive = false
|
|
27
|
+
for (const node of nodes) {
|
|
28
|
+
const nodeRoute = node.routeHref || node.routePath || ''
|
|
29
|
+
if (node.type === 'directory') {
|
|
30
|
+
const label = node.title || node.name
|
|
31
|
+
const isActive = nodeRoute === currentRoute
|
|
32
|
+
const href = node.routePath ? encodeURI(node.routeHref || node.routePath) : null
|
|
33
|
+
const childResult = renderPageTree(node.children || [], currentRoute, depth + 1)
|
|
34
|
+
const isOpen = depth < 1 || isActive || childResult.hasActive
|
|
35
|
+
if (isOpen) hasActive = true
|
|
36
|
+
const header = href ? (
|
|
37
|
+
<a class={isActive ? 'nav-dir-link active' : 'nav-dir-link'} href={href}>
|
|
38
|
+
{label}
|
|
39
|
+
</a>
|
|
40
|
+
) : (
|
|
41
|
+
<span class="nav-dir-label">{label}</span>
|
|
42
|
+
)
|
|
43
|
+
items.push(
|
|
44
|
+
<li class={isActive ? 'is-active' : null}>
|
|
45
|
+
<details class="sidebar-collapsible" open={isOpen ? true : null}>
|
|
46
|
+
<summary class="sb-dir-header">{header}</summary>
|
|
47
|
+
{childResult.items.length ? <ul data-depth={depth + 1}>{childResult.items}</ul> : null}
|
|
48
|
+
</details>
|
|
49
|
+
</li>
|
|
50
|
+
)
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
const label = node.title || (node.isIndex ? 'Home' : node.name)
|
|
54
|
+
const isActive = nodeRoute === currentRoute
|
|
55
|
+
if (isActive) hasActive = true
|
|
56
|
+
const href = encodeURI(node.routeHref || node.routePath)
|
|
57
|
+
items.push(
|
|
58
|
+
<li>
|
|
59
|
+
<a class={isActive ? 'active' : null} href={href}>
|
|
60
|
+
{label}
|
|
61
|
+
</a>
|
|
62
|
+
</li>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
return { items, hasActive }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const PAGE_TEMPLATE = ({ Page, ExtraHead, components, ctx }) => {
|
|
69
|
+
const page = ctx.page
|
|
70
|
+
const pagesByRoute = ctx.pagesByRoute
|
|
71
|
+
const pages = ctx.pages || []
|
|
72
|
+
const pagesTree = ctx.pagesTree || []
|
|
73
|
+
const siteName = ctx.site?.name || 'Methanol Site'
|
|
74
|
+
const title = page?.title || siteName
|
|
75
|
+
const currentRoute = page?.routeHref || page?.routePath || ''
|
|
76
|
+
const baseHref = page?.routePath === '/404' ? ctx.site?.base || '/' : null
|
|
77
|
+
const toc = page?.toc?.length ? renderToc(page.toc) : null
|
|
78
|
+
const hasToc = Boolean(toc)
|
|
79
|
+
const layoutClass = hasToc ? 'layout-container' : 'layout-container no-toc'
|
|
80
|
+
const tree = renderPageTree(pagesTree, currentRoute, 0)
|
|
81
|
+
const { ThemeSearchBox, ThemeColorSwitch, ThemeAccentSwitch, ThemeToCContainer } = components
|
|
82
|
+
const rootPage = pagesByRoute?.get?.('/') || pages.find((entry) => entry.routePath === '/')
|
|
83
|
+
const pageFrontmatter = page?.frontmatter || {}
|
|
84
|
+
const rootFrontmatter = rootPage?.frontmatter || {}
|
|
85
|
+
const themeLogo = '/logo.png'
|
|
86
|
+
const themeFavIcon = '/favicon.png'
|
|
87
|
+
const logo = pageFrontmatter.logo ?? rootFrontmatter.logo ?? ctx.site?.logo ?? themeLogo
|
|
88
|
+
const favicon = pageFrontmatter.favicon ?? rootFrontmatter.favicon ?? ctx.site?.favicon ?? themeFavIcon
|
|
89
|
+
const excerpt = pageFrontmatter.excerpt ?? null
|
|
90
|
+
const ogTitle = pageFrontmatter.ogTitle ?? null
|
|
91
|
+
const ogDescription = pageFrontmatter.ogDescription ?? null
|
|
92
|
+
const ogImage = pageFrontmatter.ogImage ?? null
|
|
93
|
+
const ogUrl = pageFrontmatter.ogUrl ?? null
|
|
94
|
+
const twitterTitle = pageFrontmatter.twitterTitle ?? ogTitle
|
|
95
|
+
const twitterDescription = pageFrontmatter.twitterDescription ?? ogDescription ?? excerpt
|
|
96
|
+
const twitterImage = pageFrontmatter.twitterImage ?? ogImage
|
|
97
|
+
const twitterCard = pageFrontmatter.twitterCard ?? (twitterImage ? 'summary_large_image' : null)
|
|
98
|
+
const siblings = typeof page?.getSiblings === 'function' ? page.getSiblings() : null
|
|
99
|
+
const prevPage = siblings?.prev || null
|
|
100
|
+
const nextPage = siblings?.next || null
|
|
101
|
+
const languages = Array.isArray(ctx.languages) ? ctx.languages : []
|
|
102
|
+
const currentLanguageHref = ctx.language?.href || ctx.language?.routePath || null
|
|
103
|
+
const languageCode =
|
|
104
|
+
pageFrontmatter.langCode ?? rootFrontmatter.langCode ?? ctx.language?.code ?? 'en'
|
|
105
|
+
const htmlLang = typeof languageCode === 'string' && languageCode.trim() ? languageCode : 'en'
|
|
106
|
+
const pagefindEnabled = ctx.site?.pagefind?.enabled !== false
|
|
107
|
+
const pagefindOptions = ctx.site?.pagefind?.options || null
|
|
108
|
+
const languageSelector = languages.length ? (
|
|
109
|
+
<div class="lang-switch-wrapper">
|
|
110
|
+
<select
|
|
111
|
+
class="lang-switch-select"
|
|
112
|
+
aria-label="Select language"
|
|
113
|
+
onchange="location.href=this.value"
|
|
114
|
+
value={currentLanguageHref || undefined}
|
|
115
|
+
>
|
|
116
|
+
{languages.map((lang) => {
|
|
117
|
+
const optionValue = lang.href || lang.routePath
|
|
118
|
+
const isSelected = optionValue && optionValue === currentLanguageHref
|
|
119
|
+
return (
|
|
120
|
+
<option value={optionValue} selected={isSelected ? true : null}>
|
|
121
|
+
{lang.label}
|
|
122
|
+
</option>
|
|
123
|
+
)
|
|
124
|
+
})}
|
|
125
|
+
</select>
|
|
126
|
+
<div class="lang-switch-icon">
|
|
127
|
+
<svg
|
|
128
|
+
width="18"
|
|
129
|
+
height="18"
|
|
130
|
+
viewBox="0 0 24 24"
|
|
131
|
+
fill="none"
|
|
132
|
+
stroke="currentColor"
|
|
133
|
+
stroke-width="2"
|
|
134
|
+
stroke-linecap="round"
|
|
135
|
+
stroke-linejoin="round"
|
|
136
|
+
>
|
|
137
|
+
<circle cx="12" cy="12" r="10"></circle>
|
|
138
|
+
<line x1="2" y1="12" x2="22" y2="12"></line>
|
|
139
|
+
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path>
|
|
140
|
+
</svg>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
) : null
|
|
144
|
+
return (
|
|
145
|
+
<>
|
|
146
|
+
{R.rawHTML`<!DOCTYPE html>`}
|
|
147
|
+
<html lang={htmlLang}>
|
|
148
|
+
<head>
|
|
149
|
+
<meta charset="UTF-8" />
|
|
150
|
+
<meta name="viewport" content="width=device-width" />
|
|
151
|
+
<title>
|
|
152
|
+
{title} | {siteName}
|
|
153
|
+
</title>
|
|
154
|
+
{baseHref ? <base href={baseHref} /> : null}
|
|
155
|
+
<link rel="icon" href={favicon} />
|
|
156
|
+
{excerpt ? <meta name="description" content={excerpt} /> : null}
|
|
157
|
+
{ogTitle ? <meta property="og:title" content={ogTitle} /> : null}
|
|
158
|
+
{ogDescription ? <meta property="og:description" content={ogDescription} /> : null}
|
|
159
|
+
{ogImage ? <meta property="og:image" content={ogImage} /> : null}
|
|
160
|
+
{ogUrl ? <meta property="og:url" content={ogUrl} /> : null}
|
|
161
|
+
{twitterCard ? <meta name="twitter:card" content={twitterCard} /> : null}
|
|
162
|
+
{twitterTitle ? <meta name="twitter:title" content={twitterTitle} /> : null}
|
|
163
|
+
{twitterDescription ? <meta name="twitter:description" content={twitterDescription} /> : null}
|
|
164
|
+
{twitterImage ? <meta name="twitter:image" content={twitterImage} /> : null}
|
|
165
|
+
<ExtraHead />
|
|
166
|
+
<link rel="preload stylesheet" as="style" href="/.methanol_theme_default/style.css" />
|
|
167
|
+
{R.rawHTML`
|
|
168
|
+
<script>
|
|
169
|
+
(function() {
|
|
170
|
+
const savedTheme = localStorage.getItem('methanol-theme');
|
|
171
|
+
const systemTheme = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
|
172
|
+
const theme = savedTheme || systemTheme;
|
|
173
|
+
document.documentElement.classList.toggle('light', theme === 'light');
|
|
174
|
+
document.documentElement.classList.toggle('dark', theme === 'dark');
|
|
175
|
+
|
|
176
|
+
const savedAccent = localStorage.getItem('methanol-accent');
|
|
177
|
+
if (savedAccent && savedAccent !== 'default') {
|
|
178
|
+
document.documentElement.classList.add('accent-' + savedAccent);
|
|
179
|
+
}
|
|
180
|
+
})();
|
|
181
|
+
</script>
|
|
182
|
+
`}
|
|
183
|
+
<script type="module" src="/.methanol_theme_default/prefetch.js" defer></script>
|
|
184
|
+
</head>
|
|
185
|
+
<body>
|
|
186
|
+
<input type="checkbox" id="nav-toggle" class="nav-toggle" />
|
|
187
|
+
<label class="nav-toggle-label" for="nav-toggle" aria-label="Toggle navigation">
|
|
188
|
+
<svg
|
|
189
|
+
width="24"
|
|
190
|
+
height="24"
|
|
191
|
+
viewBox="0 0 24 24"
|
|
192
|
+
fill="none"
|
|
193
|
+
stroke="currentColor"
|
|
194
|
+
stroke-width="2"
|
|
195
|
+
stroke-linecap="round"
|
|
196
|
+
stroke-linejoin="round"
|
|
197
|
+
>
|
|
198
|
+
<line x1="3" y1="12" x2="21" y2="12"></line>
|
|
199
|
+
<line x1="3" y1="6" x2="21" y2="6"></line>
|
|
200
|
+
<line x1="3" y1="18" x2="21" y2="18"></line>
|
|
201
|
+
</svg>
|
|
202
|
+
</label>
|
|
203
|
+
{pagefindEnabled ? (
|
|
204
|
+
<button
|
|
205
|
+
class="search-toggle-label"
|
|
206
|
+
aria-label="Open search"
|
|
207
|
+
onclick="window.__methanolSearchOpen()"
|
|
208
|
+
>
|
|
209
|
+
<svg
|
|
210
|
+
width="24"
|
|
211
|
+
height="24"
|
|
212
|
+
viewBox="0 0 24 24"
|
|
213
|
+
fill="none"
|
|
214
|
+
stroke="currentColor"
|
|
215
|
+
stroke-width="2"
|
|
216
|
+
stroke-linecap="round"
|
|
217
|
+
stroke-linejoin="round"
|
|
218
|
+
>
|
|
219
|
+
<circle cx="11" cy="11" r="8"></circle>
|
|
220
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
|
221
|
+
</svg>
|
|
222
|
+
</button>
|
|
223
|
+
) : null}
|
|
224
|
+
{hasToc ? (
|
|
225
|
+
<>
|
|
226
|
+
<input type="checkbox" id="toc-toggle" class="toc-toggle" />
|
|
227
|
+
<label class="toc-toggle-label" for="toc-toggle" aria-label="Toggle table of contents">
|
|
228
|
+
<svg
|
|
229
|
+
width="20"
|
|
230
|
+
height="20"
|
|
231
|
+
viewBox="0 0 24 24"
|
|
232
|
+
fill="none"
|
|
233
|
+
stroke="currentColor"
|
|
234
|
+
stroke-width="2"
|
|
235
|
+
stroke-linecap="round"
|
|
236
|
+
stroke-linejoin="round"
|
|
237
|
+
>
|
|
238
|
+
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
|
|
239
|
+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
|
|
240
|
+
</svg>
|
|
241
|
+
</label>
|
|
242
|
+
</>
|
|
243
|
+
) : null}
|
|
244
|
+
<label class="nav-scrim nav-scrim-nav" for="nav-toggle" aria-label="Close navigation"></label>
|
|
245
|
+
{hasToc ? (
|
|
246
|
+
<label class="nav-scrim nav-scrim-toc" for="toc-toggle" aria-label="Close table of contents"></label>
|
|
247
|
+
) : null}
|
|
248
|
+
<div class={layoutClass}>
|
|
249
|
+
<aside class="sidebar">
|
|
250
|
+
<div class="sidebar-header">
|
|
251
|
+
<div class="logo">
|
|
252
|
+
<img src={logo} />
|
|
253
|
+
<span>{siteName}</span>
|
|
254
|
+
</div>
|
|
255
|
+
{pagefindEnabled ? <ThemeSearchBox options={pagefindOptions} /> : null}
|
|
256
|
+
</div>
|
|
257
|
+
<nav>
|
|
258
|
+
<ul data-depth="0">{tree.items}</ul>
|
|
259
|
+
</nav>
|
|
260
|
+
<div class="sidebar-footer">
|
|
261
|
+
{languageSelector}
|
|
262
|
+
<ThemeColorSwitch />
|
|
263
|
+
<ThemeAccentSwitch />
|
|
264
|
+
</div>
|
|
265
|
+
</aside>
|
|
266
|
+
<main class="main-content" data-pagefind-body={pagefindEnabled ? '' : null}>
|
|
267
|
+
<Page />
|
|
268
|
+
{prevPage || nextPage ? (
|
|
269
|
+
<nav class="page-nav">
|
|
270
|
+
{prevPage ? (
|
|
271
|
+
<a class="page-nav-card prev" href={prevPage.routeHref || prevPage.routePath}>
|
|
272
|
+
<span class="page-nav-label">Previous</span>
|
|
273
|
+
<span class="page-nav-title">{prevPage.title || prevPage.routePath}</span>
|
|
274
|
+
</a>
|
|
275
|
+
) : <div class="page-nav-spacer"></div>}
|
|
276
|
+
{nextPage ? (
|
|
277
|
+
<a class="page-nav-card next" href={nextPage.routeHref || nextPage.routePath}>
|
|
278
|
+
<span class="page-nav-label">Next</span>
|
|
279
|
+
<span class="page-nav-title">{nextPage.title || nextPage.routePath}</span>
|
|
280
|
+
</a>
|
|
281
|
+
) : null}
|
|
282
|
+
</nav>
|
|
283
|
+
) : null}
|
|
284
|
+
{page ? (
|
|
285
|
+
<footer class="page-meta">
|
|
286
|
+
<div class="page-meta-item">
|
|
287
|
+
Updated: {page.updatedAt || '-'}
|
|
288
|
+
</div>
|
|
289
|
+
<div class="page-meta-item">
|
|
290
|
+
Powered by <a href="https://github.com/SudoMaker/Methanol" target="_blank" rel="noopener noreferrer" class="methanol-link">Methanol</a>
|
|
291
|
+
</div>
|
|
292
|
+
</footer>
|
|
293
|
+
) : null}
|
|
294
|
+
</main>
|
|
295
|
+
{hasToc ? <ThemeToCContainer>{...toc}</ThemeToCContainer> : null}
|
|
296
|
+
</div>
|
|
297
|
+
</body>
|
|
298
|
+
</html>
|
|
299
|
+
</>
|
|
300
|
+
)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export default PAGE_TEMPLATE
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Welcome
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Welcome to Methanol
|
|
6
|
+
|
|
7
|
+
Methanol turns your content folder into a static site with rEFui and MDX, file-based routing, and a fast dev server.
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx methanol dev
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Open `http://localhost:5173`.
|
|
16
|
+
|
|
17
|
+
## Your Content Folder
|
|
18
|
+
|
|
19
|
+
Pages are currently read from the configured `pagesDir`:
|
|
20
|
+
|
|
21
|
+
<p><code>{ctx.site?.pagesDir || 'pages/'}</code></p>
|
|
22
|
+
|
|
23
|
+
You can change this with `pagesDir` in your config or `--input` on the CLI. Create an `index.mdx` in that folder to replace this page.
|
|
24
|
+
|
|
25
|
+
## Common Folders
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
components/ # JSX/TSX components for MDX
|
|
29
|
+
public/ # static assets copied as-is
|
|
30
|
+
dist/ # production output
|
|
31
|
+
```
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* Copyright Yukino Song, SudoMaker Ltd.
|
|
2
|
+
*
|
|
3
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
* or more contributor license agreements. See the NOTICE file
|
|
5
|
+
* distributed with this work for additional information
|
|
6
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
* to you under the Apache License, Version 2.0 (the
|
|
8
|
+
* "License"); you may not use this file except in compliance
|
|
9
|
+
* with the License. You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing,
|
|
14
|
+
* software distributed under the License is distributed on an
|
|
15
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
* KIND, either express or implied. See the License for the
|
|
17
|
+
* specific language governing permissions and limitations
|
|
18
|
+
* under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
(() => {
|
|
22
|
+
const prefetched = new Set()
|
|
23
|
+
const canPrefetch = (anchor) => {
|
|
24
|
+
if (!anchor || !anchor.href) return false
|
|
25
|
+
if (anchor.dataset && anchor.dataset.prefetch === 'false') return false
|
|
26
|
+
if (anchor.hasAttribute('download')) return false
|
|
27
|
+
if (anchor.target && anchor.target !== '_self') return false
|
|
28
|
+
const url = new URL(anchor.href, window.location.href)
|
|
29
|
+
if (url.origin !== window.location.origin) return false
|
|
30
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') return false
|
|
31
|
+
if (url.pathname === window.location.pathname && url.search === window.location.search) {
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
return true
|
|
35
|
+
}
|
|
36
|
+
const onHover = (event) => {
|
|
37
|
+
const anchor = event.target && event.target.closest ? event.target.closest('a') : null
|
|
38
|
+
if (!canPrefetch(anchor)) return
|
|
39
|
+
const href = anchor.href
|
|
40
|
+
if (prefetched.has(href)) return
|
|
41
|
+
prefetched.add(href)
|
|
42
|
+
const link = document.createElement('link')
|
|
43
|
+
link.rel = 'prefetch'
|
|
44
|
+
link.as = 'document'
|
|
45
|
+
link.href = href
|
|
46
|
+
document.head.appendChild(link)
|
|
47
|
+
}
|
|
48
|
+
document.addEventListener('pointerover', onHover, { capture: true, passive: true })
|
|
49
|
+
})()
|