methanol 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +19 -0
- package/.prettierrc +10 -0
- package/LICENSE +203 -0
- package/banner.txt +6 -0
- package/bin/methanol.js +24 -0
- package/index.js +22 -0
- package/package.json +42 -9
- package/src/assets.js +30 -0
- package/src/build-system.js +200 -0
- package/src/components.js +145 -0
- package/src/config.js +355 -0
- package/src/dev-server.js +559 -0
- package/src/main.js +87 -0
- package/src/mdx.js +254 -0
- package/src/node-loader.js +88 -0
- package/src/pagefind.js +99 -0
- package/src/pages.js +638 -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 +89 -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 +159 -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/ThemeColorSwitch.client.jsx +95 -0
- package/themes/default/components/ThemeColorSwitch.static.jsx +23 -0
- package/themes/default/components/ThemeSearchBox.client.jsx +287 -0
- package/themes/default/components/ThemeSearchBox.static.jsx +41 -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.jsx +27 -0
- package/themes/default/heading.jsx +35 -0
- package/themes/default/index.js +50 -0
- package/themes/default/page.jsx +249 -0
- package/themes/default/pages/404.mdx +8 -0
- package/themes/default/pages/index.mdx +9 -0
- package/themes/default/public/logo.png +0 -0
- package/themes/default/resources/style.css +1089 -0
|
@@ -0,0 +1,50 @@
|
|
|
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 rehypeStarryNight from 'rehype-starry-night'
|
|
25
|
+
|
|
26
|
+
import PAGE_TEMPLATE from './page.jsx'
|
|
27
|
+
import { createHeadings } from './heading.jsx'
|
|
28
|
+
|
|
29
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
30
|
+
const __dirname = dirname(__filename)
|
|
31
|
+
|
|
32
|
+
export default ({ starryNight = true, starryNightOptions } = {}) => {
|
|
33
|
+
return {
|
|
34
|
+
root: __dirname,
|
|
35
|
+
// componentsDir: './components',
|
|
36
|
+
// pagesDir: './pages',
|
|
37
|
+
resources: {
|
|
38
|
+
'/.methanol_theme_default': './resources'
|
|
39
|
+
},
|
|
40
|
+
components: {
|
|
41
|
+
...createHeadings()
|
|
42
|
+
},
|
|
43
|
+
template: PAGE_TEMPLATE,
|
|
44
|
+
mdx: {
|
|
45
|
+
rehypePlugins: [
|
|
46
|
+
starryNight && [rehypeStarryNight, starryNightOptions]
|
|
47
|
+
].filter(Boolean)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
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, 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 logo = pageFrontmatter.logo ?? rootFrontmatter.logo ?? ctx.site?.logo ?? themeLogo
|
|
87
|
+
const favicon = pageFrontmatter.favicon ?? rootFrontmatter.favicon ?? ctx.site?.favicon ?? logo ?? themeLogo
|
|
88
|
+
const excerpt = pageFrontmatter.excerpt ?? null
|
|
89
|
+
const ogTitle = pageFrontmatter.ogTitle ?? null
|
|
90
|
+
const ogDescription = pageFrontmatter.ogDescription ?? null
|
|
91
|
+
const ogImage = pageFrontmatter.ogImage ?? null
|
|
92
|
+
const ogUrl = pageFrontmatter.ogUrl ?? null
|
|
93
|
+
const twitterTitle = pageFrontmatter.twitterTitle ?? ogTitle
|
|
94
|
+
const twitterDescription = pageFrontmatter.twitterDescription ?? ogDescription ?? excerpt
|
|
95
|
+
const twitterImage = pageFrontmatter.twitterImage ?? ogImage
|
|
96
|
+
const twitterCard = pageFrontmatter.twitterCard ?? (twitterImage ? 'summary_large_image' : null)
|
|
97
|
+
const languages = Array.isArray(ctx.languages) ? ctx.languages : []
|
|
98
|
+
const currentLanguageHref = ctx.language?.href || ctx.language?.routePath || null
|
|
99
|
+
const pagefindEnabled = ctx.site?.pagefind?.enabled !== false
|
|
100
|
+
const pagefindOptions = ctx.site?.pagefind?.options || null
|
|
101
|
+
const languageSelector = languages.length ? (
|
|
102
|
+
<div class="lang-switch-wrapper">
|
|
103
|
+
<select
|
|
104
|
+
class="lang-switch-select"
|
|
105
|
+
aria-label="Select language"
|
|
106
|
+
onchange="location.href=this.value"
|
|
107
|
+
value={currentLanguageHref || undefined}
|
|
108
|
+
>
|
|
109
|
+
{languages.map((lang) => {
|
|
110
|
+
const optionValue = lang.href || lang.routePath
|
|
111
|
+
const isSelected = optionValue && optionValue === currentLanguageHref
|
|
112
|
+
return (
|
|
113
|
+
<option value={optionValue} selected={isSelected ? true : null}>
|
|
114
|
+
{lang.label}
|
|
115
|
+
</option>
|
|
116
|
+
)
|
|
117
|
+
})}
|
|
118
|
+
</select>
|
|
119
|
+
<div class="lang-switch-icon">
|
|
120
|
+
<svg
|
|
121
|
+
width="18"
|
|
122
|
+
height="18"
|
|
123
|
+
viewBox="0 0 24 24"
|
|
124
|
+
fill="none"
|
|
125
|
+
stroke="currentColor"
|
|
126
|
+
stroke-width="2"
|
|
127
|
+
stroke-linecap="round"
|
|
128
|
+
stroke-linejoin="round"
|
|
129
|
+
>
|
|
130
|
+
<circle cx="12" cy="12" r="10"></circle>
|
|
131
|
+
<line x1="2" y1="12" x2="22" y2="12"></line>
|
|
132
|
+
<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>
|
|
133
|
+
</svg>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
) : null
|
|
137
|
+
return (
|
|
138
|
+
<>
|
|
139
|
+
{R.rawHTML`<!DOCTYPE html>`}
|
|
140
|
+
<html lang="en">
|
|
141
|
+
<head>
|
|
142
|
+
<meta charset="UTF-8" />
|
|
143
|
+
<meta name="viewport" content="width=device-width" />
|
|
144
|
+
<title>
|
|
145
|
+
{title} | {siteName}
|
|
146
|
+
</title>
|
|
147
|
+
{baseHref ? <base href={baseHref} /> : null}
|
|
148
|
+
<link rel="icon" href={favicon} />
|
|
149
|
+
{excerpt ? <meta name="description" content={excerpt} /> : null}
|
|
150
|
+
{ogTitle ? <meta property="og:title" content={ogTitle} /> : null}
|
|
151
|
+
{ogDescription ? <meta property="og:description" content={ogDescription} /> : null}
|
|
152
|
+
{ogImage ? <meta property="og:image" content={ogImage} /> : null}
|
|
153
|
+
{ogUrl ? <meta property="og:url" content={ogUrl} /> : null}
|
|
154
|
+
{twitterCard ? <meta name="twitter:card" content={twitterCard} /> : null}
|
|
155
|
+
{twitterTitle ? <meta name="twitter:title" content={twitterTitle} /> : null}
|
|
156
|
+
{twitterDescription ? <meta name="twitter:description" content={twitterDescription} /> : null}
|
|
157
|
+
{twitterImage ? <meta name="twitter:image" content={twitterImage} /> : null}
|
|
158
|
+
<link rel="preload stylesheet" as="style" href="/.methanol_theme_default/style.css" />
|
|
159
|
+
{R.rawHTML`
|
|
160
|
+
<script>
|
|
161
|
+
(function() {
|
|
162
|
+
const savedTheme = localStorage.getItem('methanol-theme');
|
|
163
|
+
const systemTheme = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
|
164
|
+
const theme = savedTheme || systemTheme;
|
|
165
|
+
document.documentElement.classList.toggle('light', theme === 'light');
|
|
166
|
+
document.documentElement.classList.toggle('dark', theme === 'dark');
|
|
167
|
+
})();
|
|
168
|
+
</script>
|
|
169
|
+
`}
|
|
170
|
+
<ExtraHead />
|
|
171
|
+
</head>
|
|
172
|
+
<body>
|
|
173
|
+
<input type="checkbox" id="nav-toggle" class="nav-toggle" />
|
|
174
|
+
<label class="nav-toggle-label" for="nav-toggle" aria-label="Toggle navigation">
|
|
175
|
+
<svg
|
|
176
|
+
width="24"
|
|
177
|
+
height="24"
|
|
178
|
+
viewBox="0 0 24 24"
|
|
179
|
+
fill="none"
|
|
180
|
+
stroke="currentColor"
|
|
181
|
+
stroke-width="2"
|
|
182
|
+
stroke-linecap="round"
|
|
183
|
+
stroke-linejoin="round"
|
|
184
|
+
>
|
|
185
|
+
<line x1="3" y1="12" x2="21" y2="12"></line>
|
|
186
|
+
<line x1="3" y1="6" x2="21" y2="6"></line>
|
|
187
|
+
<line x1="3" y1="18" x2="21" y2="18"></line>
|
|
188
|
+
</svg>
|
|
189
|
+
</label>
|
|
190
|
+
{hasToc ? (
|
|
191
|
+
<>
|
|
192
|
+
<input type="checkbox" id="toc-toggle" class="toc-toggle" />
|
|
193
|
+
<label class="toc-toggle-label" for="toc-toggle" aria-label="Toggle table of contents">
|
|
194
|
+
<svg
|
|
195
|
+
width="20"
|
|
196
|
+
height="20"
|
|
197
|
+
viewBox="0 0 24 24"
|
|
198
|
+
fill="none"
|
|
199
|
+
stroke="currentColor"
|
|
200
|
+
stroke-width="2"
|
|
201
|
+
stroke-linecap="round"
|
|
202
|
+
stroke-linejoin="round"
|
|
203
|
+
>
|
|
204
|
+
<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>
|
|
205
|
+
<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>
|
|
206
|
+
</svg>
|
|
207
|
+
</label>
|
|
208
|
+
</>
|
|
209
|
+
) : null}
|
|
210
|
+
<label class="nav-scrim nav-scrim-nav" for="nav-toggle" aria-label="Close navigation"></label>
|
|
211
|
+
{hasToc ? (
|
|
212
|
+
<label class="nav-scrim nav-scrim-toc" for="toc-toggle" aria-label="Close table of contents"></label>
|
|
213
|
+
) : null}
|
|
214
|
+
<div class={layoutClass}>
|
|
215
|
+
<aside class="sidebar">
|
|
216
|
+
<div class="sidebar-header">
|
|
217
|
+
<div class="logo">
|
|
218
|
+
<img src={logo} />
|
|
219
|
+
<span>{siteName}</span>
|
|
220
|
+
</div>
|
|
221
|
+
{pagefindEnabled ? <ThemeSearchBox options={pagefindOptions} /> : null}
|
|
222
|
+
</div>
|
|
223
|
+
<nav>
|
|
224
|
+
<ul data-depth="0">{tree.items}</ul>
|
|
225
|
+
</nav>
|
|
226
|
+
<div class="sidebar-footer">
|
|
227
|
+
{languageSelector}
|
|
228
|
+
<ThemeColorSwitch />
|
|
229
|
+
</div>
|
|
230
|
+
</aside>
|
|
231
|
+
<main class="main-content" data-pagefind-body={pagefindEnabled ? '' : null}>
|
|
232
|
+
<Page />
|
|
233
|
+
{page ? (
|
|
234
|
+
<footer class="page-meta">
|
|
235
|
+
Updated: {page.updatedAt || '-'}
|
|
236
|
+
<br />
|
|
237
|
+
Powered by Methanol
|
|
238
|
+
</footer>
|
|
239
|
+
) : null}
|
|
240
|
+
</main>
|
|
241
|
+
{hasToc ? <ThemeToCContainer>{...toc}</ThemeToCContainer> : null}
|
|
242
|
+
</div>
|
|
243
|
+
</body>
|
|
244
|
+
</html>
|
|
245
|
+
</>
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export default PAGE_TEMPLATE
|
|
Binary file
|