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.
Files changed (45) hide show
  1. package/.editorconfig +19 -0
  2. package/.prettierrc +10 -0
  3. package/LICENSE +203 -0
  4. package/banner.txt +6 -0
  5. package/bin/methanol.js +24 -0
  6. package/index.js +22 -0
  7. package/package.json +42 -9
  8. package/src/assets.js +30 -0
  9. package/src/build-system.js +200 -0
  10. package/src/components.js +145 -0
  11. package/src/config.js +355 -0
  12. package/src/dev-server.js +559 -0
  13. package/src/main.js +87 -0
  14. package/src/mdx.js +254 -0
  15. package/src/node-loader.js +88 -0
  16. package/src/pagefind.js +99 -0
  17. package/src/pages.js +638 -0
  18. package/src/preview-server.js +58 -0
  19. package/src/public-assets.js +73 -0
  20. package/src/register-loader.js +29 -0
  21. package/src/rehype-plugins/link-resolve.js +89 -0
  22. package/src/rehype-plugins/methanol-ctx.js +89 -0
  23. package/src/renderer.js +25 -0
  24. package/src/rewind.js +117 -0
  25. package/src/stage-logger.js +59 -0
  26. package/src/state.js +159 -0
  27. package/src/virtual-module/inject.js +30 -0
  28. package/src/virtual-module/loader.js +116 -0
  29. package/src/virtual-module/pagefind.js +108 -0
  30. package/src/vite-plugins.js +173 -0
  31. package/themes/default/components/ThemeColorSwitch.client.jsx +95 -0
  32. package/themes/default/components/ThemeColorSwitch.static.jsx +23 -0
  33. package/themes/default/components/ThemeSearchBox.client.jsx +287 -0
  34. package/themes/default/components/ThemeSearchBox.static.jsx +41 -0
  35. package/themes/default/components/ThemeToCContainer.client.jsx +154 -0
  36. package/themes/default/components/ThemeToCContainer.static.jsx +61 -0
  37. package/themes/default/components/pre.client.jsx +84 -0
  38. package/themes/default/components/pre.jsx +27 -0
  39. package/themes/default/heading.jsx +35 -0
  40. package/themes/default/index.js +50 -0
  41. package/themes/default/page.jsx +249 -0
  42. package/themes/default/pages/404.mdx +8 -0
  43. package/themes/default/pages/index.mdx +9 -0
  44. package/themes/default/public/logo.png +0 -0
  45. 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
@@ -0,0 +1,8 @@
1
+ # Page Not Found
2
+
3
+ The page you're looking for doesn't exist.
4
+
5
+ ## What you can do:
6
+
7
+ - Check the URL for typos
8
+ - Go back to the [home page](/)
@@ -0,0 +1,9 @@
1
+ ---
2
+ title: Welcome
3
+ ---
4
+
5
+ # Welcome to Methanol
6
+
7
+ Start by adding docs under `pages/` (or `docs/`) as `.mdx` files, and place shared UI in `components/`.
8
+
9
+ Add your own `pages/index.md` or `pages/index.mdx` to replace this page.
Binary file