methanol 0.0.7 → 0.0.9
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/README.md +5 -0
- package/package.json +2 -1
- package/src/assets.js +1 -1
- package/src/build-system.js +9 -2
- package/src/config.js +134 -4
- package/src/dev-server.js +51 -27
- package/src/logger.js +80 -0
- package/src/main.js +10 -1
- package/src/mdx.js +43 -33
- package/src/pagefind.js +16 -5
- package/src/pages.js +85 -76
- package/src/preview-server.js +1 -1
- package/src/rehype-plugins/link-resolve.js +0 -1
- package/src/stage-logger.js +7 -4
- package/src/state.js +19 -3
- package/src/utils.js +9 -0
- package/src/virtual-module/inject.js +3 -4
- package/src/virtual-module/{pagefind.js → pagefind-loader.js} +23 -2
- package/src/vite-plugins.js +50 -6
- package/themes/default/components/ThemeSearchBox.client.jsx +9 -2
- package/themes/default/page.jsx +54 -26
- package/themes/default/sources/style.css +194 -1
package/src/state.js
CHANGED
|
@@ -103,10 +103,9 @@ const withCommonOptions = (y) =>
|
|
|
103
103
|
})
|
|
104
104
|
.option('code-highlighting', {
|
|
105
105
|
describe: 'Enable or disable code highlighting',
|
|
106
|
-
type: '
|
|
106
|
+
type: 'boolean',
|
|
107
107
|
coerce: (value) => {
|
|
108
108
|
if (value == null) return null
|
|
109
|
-
if (value === true || value === '') return true
|
|
110
109
|
if (typeof value === 'boolean') return value
|
|
111
110
|
const normalized = String(value).trim().toLowerCase()
|
|
112
111
|
if (normalized === 'true') return true
|
|
@@ -114,6 +113,18 @@ const withCommonOptions = (y) =>
|
|
|
114
113
|
return null
|
|
115
114
|
}
|
|
116
115
|
})
|
|
116
|
+
.option('verbose', {
|
|
117
|
+
alias: 'v',
|
|
118
|
+
describe: 'Enable verbose output',
|
|
119
|
+
type: 'boolean',
|
|
120
|
+
default: false
|
|
121
|
+
})
|
|
122
|
+
.option('base', {
|
|
123
|
+
describe: 'Base URL override',
|
|
124
|
+
type: 'string',
|
|
125
|
+
requiresArg: true,
|
|
126
|
+
nargs: 1
|
|
127
|
+
})
|
|
117
128
|
|
|
118
129
|
const parser = yargs(hideBin(process.argv))
|
|
119
130
|
.scriptName('methanol')
|
|
@@ -141,13 +152,17 @@ export const cli = {
|
|
|
141
152
|
CLI_OUTPUT_DIR: argv.output || null,
|
|
142
153
|
CLI_CONFIG_PATH: argv.config || null,
|
|
143
154
|
CLI_SITE_NAME: argv['site-name'] || null,
|
|
144
|
-
CLI_CODE_HIGHLIGHTING: typeof argv['code-highlighting'] === 'boolean' ? argv['code-highlighting'] : null
|
|
155
|
+
CLI_CODE_HIGHLIGHTING: typeof argv['code-highlighting'] === 'boolean' ? argv['code-highlighting'] : null,
|
|
156
|
+
CLI_VERBOSE: Boolean(argv.verbose),
|
|
157
|
+
CLI_BASE: argv.base || null
|
|
145
158
|
}
|
|
146
159
|
|
|
147
160
|
export const state = {
|
|
148
161
|
PROJECT_ROOT,
|
|
149
162
|
ROOT_DIR: PROJECT_ROOT,
|
|
150
163
|
SITE_NAME: 'Methanol Site',
|
|
164
|
+
SITE_BASE: null,
|
|
165
|
+
VITE_BASE: null,
|
|
151
166
|
PAGES_DIR: resolve(PROJECT_ROOT, 'pages'),
|
|
152
167
|
COMPONENTS_DIR: resolve(PROJECT_ROOT, 'components'),
|
|
153
168
|
STATIC_DIR: resolve(PROJECT_ROOT, 'public'),
|
|
@@ -178,6 +193,7 @@ export const state = {
|
|
|
178
193
|
THEME_POST_BUNDLE_HOOKS: [],
|
|
179
194
|
STARRY_NIGHT_ENABLED: false,
|
|
180
195
|
STARRY_NIGHT_OPTIONS: null,
|
|
196
|
+
GFM_ENABLED: true,
|
|
181
197
|
CURRENT_MODE: 'production',
|
|
182
198
|
RESOLVED_MDX_CONFIG: undefined,
|
|
183
199
|
RESOLVED_VITE_CONFIG: undefined
|
package/src/utils.js
ADDED
|
@@ -21,10 +21,9 @@
|
|
|
21
21
|
import { createDOMRenderer } from 'refui/dom'
|
|
22
22
|
import { defaults } from 'refui/browser'
|
|
23
23
|
import { lazy } from 'refui'
|
|
24
|
-
import { init } from '
|
|
25
|
-
|
|
26
|
-
const reg = import('/.methanol_virtual_module/registry.js')
|
|
24
|
+
import { init } from 'methanol:loader'
|
|
25
|
+
import { registry } from 'methanol:registry'
|
|
27
26
|
|
|
28
27
|
const R = createDOMRenderer(defaults)
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
init(registry, R)
|
|
@@ -22,6 +22,27 @@ let pagefindInit = null
|
|
|
22
22
|
let pagefindUiInit = null
|
|
23
23
|
let pagefindUiReady = false
|
|
24
24
|
|
|
25
|
+
const resolveBasePrefix = () => {
|
|
26
|
+
let base = import.meta.env?.BASE_URL || '/'
|
|
27
|
+
if (!base || base === '/' || base === './') return ''
|
|
28
|
+
if (base.startsWith('http://') || base.startsWith('https://')) {
|
|
29
|
+
try {
|
|
30
|
+
base = new URL(base).pathname
|
|
31
|
+
} catch {
|
|
32
|
+
return ''
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (!base.startsWith('/')) return ''
|
|
36
|
+
if (base.endsWith('/')) base = base.slice(0, -1)
|
|
37
|
+
return base
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const withBase = (path) => {
|
|
41
|
+
const prefix = resolveBasePrefix()
|
|
42
|
+
if (!prefix || path.startsWith(`${prefix}/`)) return path
|
|
43
|
+
return `${prefix}${path}`
|
|
44
|
+
}
|
|
45
|
+
|
|
25
46
|
const dynamicImport = (path) => {
|
|
26
47
|
try {
|
|
27
48
|
const importer = new Function('p', 'return import(p)')
|
|
@@ -38,7 +59,7 @@ export const loadPagefind = async () => {
|
|
|
38
59
|
resolve(null)
|
|
39
60
|
return
|
|
40
61
|
}
|
|
41
|
-
dynamicImport('/pagefind/pagefind.js')
|
|
62
|
+
dynamicImport(withBase('/pagefind/pagefind.js'))
|
|
42
63
|
.then((mod) => {
|
|
43
64
|
if (!mod) return resolve(null)
|
|
44
65
|
if (mod.search) return resolve(mod)
|
|
@@ -89,7 +110,7 @@ export const loadPagefindUI = async (options = {}) => {
|
|
|
89
110
|
return
|
|
90
111
|
}
|
|
91
112
|
const script = document.createElement('script')
|
|
92
|
-
script.src = '/pagefind/pagefind-ui.js'
|
|
113
|
+
script.src = withBase('/pagefind/pagefind-ui.js')
|
|
93
114
|
script.async = true
|
|
94
115
|
script.onload = () => done(initPagefindUI(options))
|
|
95
116
|
script.onerror = () => done(false)
|
package/src/vite-plugins.js
CHANGED
|
@@ -24,8 +24,9 @@ import { existsSync } from 'node:fs'
|
|
|
24
24
|
import { resolve } from 'node:path'
|
|
25
25
|
import { normalizePath } from 'vite'
|
|
26
26
|
import { state } from './state.js'
|
|
27
|
+
import { resolveBasePrefix } from './config.js'
|
|
27
28
|
import { genRegistryScript } from './components.js'
|
|
28
|
-
import { INJECT_SCRIPT, LOADER_SCRIPT,
|
|
29
|
+
import { INJECT_SCRIPT, LOADER_SCRIPT, PAGEFIND_LOADER_SCRIPT } from './assets.js'
|
|
29
30
|
import { projectRequire } from './node-loader.js'
|
|
30
31
|
|
|
31
32
|
const require = createRequire(import.meta.url)
|
|
@@ -60,6 +61,9 @@ export const methanolPreviewRoutingPlugin = (distDir, notFoundPath) => ({
|
|
|
60
61
|
cachedHtml = await readFile(notFoundPath, 'utf-8')
|
|
61
62
|
return cachedHtml
|
|
62
63
|
}
|
|
64
|
+
|
|
65
|
+
const basePrefix = resolveBasePrefix()
|
|
66
|
+
|
|
63
67
|
const handler = async (req, res, next) => {
|
|
64
68
|
if (!req.url || req.method !== 'GET') {
|
|
65
69
|
return next()
|
|
@@ -69,6 +73,13 @@ export const methanolPreviewRoutingPlugin = (distDir, notFoundPath) => ({
|
|
|
69
73
|
try {
|
|
70
74
|
pathname = new URL(req.url, 'http://methanol').pathname
|
|
71
75
|
pathname = decodeURIComponent(pathname)
|
|
76
|
+
if (basePrefix) {
|
|
77
|
+
if (pathname.startsWith(basePrefix)) {
|
|
78
|
+
pathname = pathname.slice(basePrefix.length)
|
|
79
|
+
} else {
|
|
80
|
+
return next()
|
|
81
|
+
}
|
|
82
|
+
}
|
|
72
83
|
} catch {}
|
|
73
84
|
const hasTrailingSlash = pathname.endsWith('/') && pathname !== '/'
|
|
74
85
|
if (pathname.includes('.') && !pathname.endsWith('.html')) {
|
|
@@ -109,20 +120,43 @@ export const methanolPreviewRoutingPlugin = (distDir, notFoundPath) => ({
|
|
|
109
120
|
|
|
110
121
|
const virtualModulePrefix = '/.methanol_virtual_module/'
|
|
111
122
|
const resolvedVirtualModulePrefix = '\0' + virtualModulePrefix
|
|
123
|
+
const virtualModuleScheme = 'methanol:'
|
|
112
124
|
|
|
113
125
|
const virtualModuleMap = {
|
|
126
|
+
get registry() {
|
|
127
|
+
return `export const registry = ${genRegistryScript()}`
|
|
128
|
+
},
|
|
114
129
|
get 'registry.js'() {
|
|
115
130
|
return `export const registry = ${genRegistryScript()}`
|
|
116
131
|
},
|
|
117
|
-
|
|
132
|
+
loader: LOADER_SCRIPT,
|
|
118
133
|
'inject.js': INJECT_SCRIPT,
|
|
119
|
-
'pagefind
|
|
134
|
+
'pagefind-loader': PAGEFIND_LOADER_SCRIPT
|
|
120
135
|
}
|
|
121
136
|
|
|
122
137
|
const getModuleIdSegment = (id, start) => {
|
|
123
138
|
return new URL(id.slice(start), 'http://methanol').pathname.slice(1)
|
|
124
139
|
}
|
|
125
140
|
|
|
141
|
+
const getSchemeModuleKey = (id) => {
|
|
142
|
+
if (!id.startsWith(virtualModuleScheme)) return null
|
|
143
|
+
return id.slice(virtualModuleScheme.length)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const resolveVirtualModuleId = (id) => {
|
|
147
|
+
if (id.startsWith(virtualModulePrefix)) {
|
|
148
|
+
return id
|
|
149
|
+
}
|
|
150
|
+
const basePrefix = resolveBasePrefix()
|
|
151
|
+
if (basePrefix) {
|
|
152
|
+
const prefixed = `${basePrefix}${virtualModulePrefix}`
|
|
153
|
+
if (id.startsWith(prefixed)) {
|
|
154
|
+
return id.slice(basePrefix.length)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return null
|
|
158
|
+
}
|
|
159
|
+
|
|
126
160
|
export const methanolResolverPlugin = () => {
|
|
127
161
|
return {
|
|
128
162
|
name: 'methanol-resolver',
|
|
@@ -139,10 +173,16 @@ export const methanolResolverPlugin = () => {
|
|
|
139
173
|
return require.resolve(id)
|
|
140
174
|
}
|
|
141
175
|
|
|
142
|
-
|
|
143
|
-
|
|
176
|
+
const schemeKey = getSchemeModuleKey(id)
|
|
177
|
+
if (schemeKey && Object.prototype.hasOwnProperty.call(virtualModuleMap, schemeKey)) {
|
|
178
|
+
return '\0' + id
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const virtualId = resolveVirtualModuleId(id)
|
|
182
|
+
if (virtualId) {
|
|
183
|
+
const _moduleId = getModuleIdSegment(virtualId, virtualModulePrefix.length)
|
|
144
184
|
if (Object.prototype.hasOwnProperty.call(virtualModuleMap, _moduleId)) {
|
|
145
|
-
return '\0' +
|
|
185
|
+
return '\0' + virtualId
|
|
146
186
|
}
|
|
147
187
|
}
|
|
148
188
|
|
|
@@ -164,6 +204,10 @@ export const methanolResolverPlugin = () => {
|
|
|
164
204
|
}
|
|
165
205
|
},
|
|
166
206
|
load(id) {
|
|
207
|
+
if (id.startsWith('\0' + virtualModuleScheme)) {
|
|
208
|
+
const key = id.slice(1 + virtualModuleScheme.length)
|
|
209
|
+
return virtualModuleMap[key]
|
|
210
|
+
}
|
|
167
211
|
if (id.startsWith(resolvedVirtualModulePrefix)) {
|
|
168
212
|
const _moduleId = getModuleIdSegment(id, resolvedVirtualModulePrefix.length)
|
|
169
213
|
return virtualModuleMap[_moduleId]
|
|
@@ -20,7 +20,13 @@
|
|
|
20
20
|
|
|
21
21
|
import { signal, $, t, If, For, onCondition } from 'refui'
|
|
22
22
|
import { createPortal } from 'refui/extras'
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
let pagefindModule = null
|
|
25
|
+
const loadPagefindModule = async () => {
|
|
26
|
+
if (pagefindModule) return pagefindModule
|
|
27
|
+
pagefindModule = import('methanol:pagefind-loader')
|
|
28
|
+
return pagefindModule
|
|
29
|
+
}
|
|
24
30
|
|
|
25
31
|
let keybindReady = false
|
|
26
32
|
let cachedPagefind = null
|
|
@@ -35,7 +41,8 @@ const resolveShortcutLabel = () => {
|
|
|
35
41
|
|
|
36
42
|
const ensurePagefind = async (options) => {
|
|
37
43
|
if (cachedPagefind) return cachedPagefind
|
|
38
|
-
const
|
|
44
|
+
const module = await loadPagefindModule()
|
|
45
|
+
const pagefind = await module?.loadPagefind?.()
|
|
39
46
|
if (!pagefind) return null
|
|
40
47
|
if (pagefind.options) {
|
|
41
48
|
const nextOptions = { excerptLength: 30, ...(options || {}) }
|
package/themes/default/page.jsx
CHANGED
|
@@ -27,11 +27,11 @@ const renderPageTree = (nodes = [], currentRoute, depth = 0) => {
|
|
|
27
27
|
const items = []
|
|
28
28
|
let hasActive = false
|
|
29
29
|
for (const node of nodes) {
|
|
30
|
-
const nodeRoute = node.routeHref ||
|
|
30
|
+
const nodeRoute = node.routeHref || ''
|
|
31
31
|
if (node.type === 'directory') {
|
|
32
32
|
const label = node.title || node.name
|
|
33
33
|
const isActive = nodeRoute === currentRoute
|
|
34
|
-
const href = node.
|
|
34
|
+
const href = node.routeHref
|
|
35
35
|
const childResult = renderPageTree(node.children || [], currentRoute, depth + 1)
|
|
36
36
|
const isOpen = depth < 1 || isActive || childResult.hasActive
|
|
37
37
|
if (isOpen) hasActive = true
|
|
@@ -55,7 +55,7 @@ const renderPageTree = (nodes = [], currentRoute, depth = 0) => {
|
|
|
55
55
|
const label = node.title || (node.isIndex ? 'Home' : node.name)
|
|
56
56
|
const isActive = nodeRoute === currentRoute
|
|
57
57
|
if (isActive) hasActive = true
|
|
58
|
-
const href =
|
|
58
|
+
const href = node.routeHref
|
|
59
59
|
items.push(
|
|
60
60
|
<li>
|
|
61
61
|
<a class={isActive ? 'active' : null} href={href}>
|
|
@@ -67,27 +67,27 @@ const renderPageTree = (nodes = [], currentRoute, depth = 0) => {
|
|
|
67
67
|
return { items, hasActive }
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const PAGE_TEMPLATE = ({
|
|
70
|
+
const PAGE_TEMPLATE = ({ PageContent, ExtraHead, components, ctx }) => {
|
|
71
71
|
const page = ctx.page
|
|
72
72
|
const pagesByRoute = ctx.pagesByRoute
|
|
73
73
|
const pages = ctx.pages || []
|
|
74
74
|
const pagesTree = ctx.pagesTree || []
|
|
75
|
-
const siteName = ctx.site
|
|
76
|
-
const title = page
|
|
77
|
-
const currentRoute = page
|
|
78
|
-
const baseHref = page
|
|
79
|
-
const toc = page
|
|
75
|
+
const siteName = ctx.site.name || 'Methanol Site'
|
|
76
|
+
const title = page.title || siteName
|
|
77
|
+
const currentRoute = page.routeHref || ''
|
|
78
|
+
const baseHref = page.routeHref === '/404' ? ctx.site.base || '/' : null
|
|
79
|
+
const toc = page.toc?.length ? renderToc(page.toc) : null
|
|
80
80
|
const hasToc = Boolean(toc)
|
|
81
81
|
const layoutClass = hasToc ? 'layout-container' : 'layout-container no-toc'
|
|
82
82
|
const tree = renderPageTree(pagesTree, currentRoute, 0)
|
|
83
83
|
const { ThemeSearchBox, ThemeColorSwitch, ThemeAccentSwitch, ThemeToCContainer } = components
|
|
84
|
-
const rootPage = pagesByRoute
|
|
85
|
-
const pageFrontmatter = page
|
|
86
|
-
const rootFrontmatter = rootPage
|
|
84
|
+
const rootPage = pagesByRoute.get('/') || pages.find((entry) => entry.routeHref === '/')
|
|
85
|
+
const pageFrontmatter = page.frontmatter || {}
|
|
86
|
+
const rootFrontmatter = rootPage.frontmatter || {}
|
|
87
87
|
const themeLogo = '/logo.png'
|
|
88
88
|
const themeFavIcon = '/favicon.png'
|
|
89
|
-
const logo = pageFrontmatter.logo ?? rootFrontmatter.logo ?? ctx.site
|
|
90
|
-
const favicon = pageFrontmatter.favicon ?? rootFrontmatter.favicon ?? ctx.site
|
|
89
|
+
const logo = pageFrontmatter.logo ?? rootFrontmatter.logo ?? ctx.site.logo ?? themeLogo
|
|
90
|
+
const favicon = pageFrontmatter.favicon ?? rootFrontmatter.favicon ?? ctx.site.favicon ?? themeFavIcon
|
|
91
91
|
const excerpt = pageFrontmatter.excerpt ?? `${title} | ${siteName} - Powered by Methanol`
|
|
92
92
|
const _ogTitle = pageFrontmatter.ogTitle ?? title ?? null
|
|
93
93
|
const ogTitle = _ogTitle ? `${_ogTitle} | ${siteName}` : null
|
|
@@ -98,15 +98,18 @@ const PAGE_TEMPLATE = ({ Page, ExtraHead, components, ctx }) => {
|
|
|
98
98
|
const twitterDescription = pageFrontmatter.twitterDescription ?? ogDescription ?? excerpt
|
|
99
99
|
const twitterImage = pageFrontmatter.twitterImage ?? ogImage
|
|
100
100
|
const twitterCard = pageFrontmatter.twitterCard ?? (twitterImage ? 'summary_large_image' : null)
|
|
101
|
-
const siblings =
|
|
101
|
+
const siblings = page.getSiblings()
|
|
102
102
|
const prevPage = siblings?.prev || null
|
|
103
103
|
const nextPage = siblings?.next || null
|
|
104
104
|
const languages = Array.isArray(ctx.languages) ? ctx.languages : []
|
|
105
|
-
const currentLanguageHref = ctx.language?.href || ctx.language?.
|
|
105
|
+
const currentLanguageHref = ctx.language?.href || ctx.language?.routeHref || null
|
|
106
106
|
const languageCode = pageFrontmatter.langCode ?? rootFrontmatter.langCode ?? ctx.language?.code ?? 'en'
|
|
107
107
|
const htmlLang = typeof languageCode === 'string' && languageCode.trim() ? languageCode : 'en'
|
|
108
|
-
const pagefindEnabled = ctx.site
|
|
109
|
-
const pagefindOptions = ctx.site
|
|
108
|
+
const pagefindEnabled = ctx.site.pagefind?.enabled !== false
|
|
109
|
+
const pagefindOptions = ctx.site.pagefind?.options || null
|
|
110
|
+
const repoBase = ctx.site.repoBase
|
|
111
|
+
const sourceUrl = pageFrontmatter.sourceURL
|
|
112
|
+
const editUrl = sourceUrl || (repoBase && page.relativePath ? new URL(page.relativePath, repoBase).href : null)
|
|
110
113
|
const languageSelector = languages.length ? (
|
|
111
114
|
<div class="lang-switch-wrapper">
|
|
112
115
|
<select
|
|
@@ -116,7 +119,7 @@ const PAGE_TEMPLATE = ({ Page, ExtraHead, components, ctx }) => {
|
|
|
116
119
|
value={currentLanguageHref || undefined}
|
|
117
120
|
>
|
|
118
121
|
{languages.map((lang) => {
|
|
119
|
-
const optionValue = lang.href || lang.
|
|
122
|
+
const optionValue = lang.href || lang.routeHref
|
|
120
123
|
const isSelected = optionValue && optionValue === currentLanguageHref
|
|
121
124
|
return (
|
|
122
125
|
<option value={optionValue} selected={isSelected ? true : null}>
|
|
@@ -165,7 +168,11 @@ const PAGE_TEMPLATE = ({ Page, ExtraHead, components, ctx }) => {
|
|
|
165
168
|
{twitterDescription ? <meta name="twitter:description" content={twitterDescription} /> : null}
|
|
166
169
|
{twitterImage ? <meta name="twitter:image" content={twitterImage} /> : null}
|
|
167
170
|
<ExtraHead />
|
|
168
|
-
<link
|
|
171
|
+
<link
|
|
172
|
+
rel="preload stylesheet"
|
|
173
|
+
as="style"
|
|
174
|
+
href="/.methanol_theme_default/style.css"
|
|
175
|
+
/>
|
|
169
176
|
<script src="/theme-prepare.js"></script>
|
|
170
177
|
</head>
|
|
171
178
|
<body>
|
|
@@ -246,28 +253,49 @@ const PAGE_TEMPLATE = ({ Page, ExtraHead, components, ctx }) => {
|
|
|
246
253
|
</div>
|
|
247
254
|
</aside>
|
|
248
255
|
<main class="main-content" data-pagefind-body={pagefindEnabled ? '' : null}>
|
|
249
|
-
<
|
|
256
|
+
<PageContent />
|
|
250
257
|
{prevPage || nextPage ? (
|
|
251
258
|
<nav class="page-nav">
|
|
252
259
|
{prevPage ? (
|
|
253
|
-
<a
|
|
260
|
+
<a
|
|
261
|
+
class="page-nav-card prev"
|
|
262
|
+
href={prevPage.routeHref}
|
|
263
|
+
>
|
|
254
264
|
<span class="page-nav-label">Previous</span>
|
|
255
|
-
<span class="page-nav-title">{prevPage.title || prevPage.
|
|
265
|
+
<span class="page-nav-title">{prevPage.title || prevPage.routeHref}</span>
|
|
256
266
|
</a>
|
|
257
267
|
) : (
|
|
258
268
|
<div class="page-nav-spacer"></div>
|
|
259
269
|
)}
|
|
260
270
|
{nextPage ? (
|
|
261
|
-
<a
|
|
271
|
+
<a
|
|
272
|
+
class="page-nav-card next"
|
|
273
|
+
href={nextPage.routeHref}
|
|
274
|
+
>
|
|
262
275
|
<span class="page-nav-label">Next</span>
|
|
263
|
-
<span class="page-nav-title">{nextPage.title || nextPage.
|
|
276
|
+
<span class="page-nav-title">{nextPage.title || nextPage.routeHref}</span>
|
|
264
277
|
</a>
|
|
265
278
|
) : null}
|
|
266
279
|
</nav>
|
|
267
280
|
) : null}
|
|
268
281
|
{page ? (
|
|
269
282
|
<footer class="page-meta">
|
|
270
|
-
<div class="page-meta-item">
|
|
283
|
+
<div class="page-meta-item">
|
|
284
|
+
{editUrl ? (
|
|
285
|
+
<>
|
|
286
|
+
<a
|
|
287
|
+
href={editUrl}
|
|
288
|
+
target="_blank"
|
|
289
|
+
rel="noopener noreferrer"
|
|
290
|
+
class="page-meta-link"
|
|
291
|
+
>
|
|
292
|
+
Edit this page
|
|
293
|
+
</a>
|
|
294
|
+
<span style="margin: 0 0.5rem; opacity: 0.5;">•</span>
|
|
295
|
+
</>
|
|
296
|
+
) : null}
|
|
297
|
+
Updated: {page.updatedAt || '-'}
|
|
298
|
+
</div>
|
|
271
299
|
<div class="page-meta-item">
|
|
272
300
|
Powered by{' '}
|
|
273
301
|
<a
|
|
@@ -1374,11 +1374,11 @@ a {
|
|
|
1374
1374
|
align-items: center;
|
|
1375
1375
|
}
|
|
1376
1376
|
|
|
1377
|
+
.page-meta-link,
|
|
1377
1378
|
.methanol-link {
|
|
1378
1379
|
font-weight: 600;
|
|
1379
1380
|
color: var(--text);
|
|
1380
1381
|
text-decoration: none !important;
|
|
1381
|
-
margin-left: 0.25rem;
|
|
1382
1382
|
transition: all 0.2s ease;
|
|
1383
1383
|
border-bottom: 1px solid transparent;
|
|
1384
1384
|
|
|
@@ -1388,6 +1388,10 @@ a {
|
|
|
1388
1388
|
}
|
|
1389
1389
|
}
|
|
1390
1390
|
|
|
1391
|
+
.methanol-link {
|
|
1392
|
+
margin-left: 0.25rem;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1391
1395
|
@media (max-width: 640px) {
|
|
1392
1396
|
.page-meta {
|
|
1393
1397
|
flex-direction: column;
|
|
@@ -1731,6 +1735,47 @@ a {
|
|
|
1731
1735
|
justify-content: flex-end;
|
|
1732
1736
|
}
|
|
1733
1737
|
|
|
1738
|
+
/* --- Tables (GFM) --- */
|
|
1739
|
+
|
|
1740
|
+
.main-content table {
|
|
1741
|
+
width: 100%;
|
|
1742
|
+
border-collapse: collapse;
|
|
1743
|
+
margin: 1.5rem 0;
|
|
1744
|
+
font-size: 0.95rem;
|
|
1745
|
+
overflow-x: auto;
|
|
1746
|
+
display: block; /* Enables horizontal scroll for large tables */
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
.main-content table thead tr {
|
|
1750
|
+
border-bottom: 2px solid var(--border);
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
.main-content table th {
|
|
1754
|
+
text-align: left;
|
|
1755
|
+
padding: 0.75rem 1rem;
|
|
1756
|
+
font-weight: 600;
|
|
1757
|
+
color: var(--text);
|
|
1758
|
+
white-space: nowrap;
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
.main-content table tbody tr {
|
|
1762
|
+
border-bottom: 1px solid var(--border);
|
|
1763
|
+
transition: background-color 0.1s ease;
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
.main-content table tbody tr:last-child {
|
|
1767
|
+
border-bottom: none;
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
.main-content table td {
|
|
1771
|
+
padding: 0.75rem 1rem;
|
|
1772
|
+
color: var(--muted);
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
.main-content table tbody tr:hover {
|
|
1776
|
+
background-color: var(--hover-bg);
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1734
1779
|
/* --- View Transitions --- */
|
|
1735
1780
|
|
|
1736
1781
|
@view-transition {
|
|
@@ -1743,3 +1788,151 @@ a {
|
|
|
1743
1788
|
view-transition-name: active-sidebar-bg;
|
|
1744
1789
|
contain: layout paint;
|
|
1745
1790
|
}
|
|
1791
|
+
|
|
1792
|
+
/* --- Print Styles --- */
|
|
1793
|
+
|
|
1794
|
+
@media print {
|
|
1795
|
+
:root {
|
|
1796
|
+
--bg: #ffffff;
|
|
1797
|
+
--surface: #ffffff;
|
|
1798
|
+
--surface-muted: #f4f4f5;
|
|
1799
|
+
--surface-elevated: #ffffff;
|
|
1800
|
+
--text: #09090b;
|
|
1801
|
+
--muted: #52525b;
|
|
1802
|
+
--border: #e4e4e7;
|
|
1803
|
+
--accent: #000000;
|
|
1804
|
+
--accent-soft: #f4f4f5;
|
|
1805
|
+
--hover-bg: transparent;
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
body {
|
|
1809
|
+
background-color: white !important;
|
|
1810
|
+
background-image: none !important;
|
|
1811
|
+
color: black !important;
|
|
1812
|
+
width: 100% !important;
|
|
1813
|
+
margin: 0 !important;
|
|
1814
|
+
padding: 0 !important;
|
|
1815
|
+
overflow: visible !important;
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
/* Hide UI Elements */
|
|
1819
|
+
.sidebar,
|
|
1820
|
+
.toc-panel,
|
|
1821
|
+
.nav-toggle-label,
|
|
1822
|
+
.toc-toggle-label,
|
|
1823
|
+
.search-toggle-label,
|
|
1824
|
+
.search-modal,
|
|
1825
|
+
.page-nav,
|
|
1826
|
+
.copy-btn,
|
|
1827
|
+
.heading-anchor,
|
|
1828
|
+
.theme-switch-wrapper,
|
|
1829
|
+
.lang-switch-wrapper,
|
|
1830
|
+
.page-meta {
|
|
1831
|
+
display: none !important;
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
/* Layout Overrides */
|
|
1835
|
+
.layout-container,
|
|
1836
|
+
.layout-container.no-toc {
|
|
1837
|
+
display: block !important;
|
|
1838
|
+
max-width: none !important;
|
|
1839
|
+
width: 100% !important;
|
|
1840
|
+
margin: 0 !important;
|
|
1841
|
+
padding: 0 !important;
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
.main-content {
|
|
1845
|
+
padding: 0 !important;
|
|
1846
|
+
width: 100% !important;
|
|
1847
|
+
max-width: none !important;
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
/* Typography & Content */
|
|
1851
|
+
body {
|
|
1852
|
+
font-size: 11pt !important;
|
|
1853
|
+
line-height: 1.5 !important;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
.main-content {
|
|
1857
|
+
h1 {
|
|
1858
|
+
font-size: 24pt !important;
|
|
1859
|
+
margin-bottom: 1rem !important;
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
h2 {
|
|
1863
|
+
font-size: 18pt !important;
|
|
1864
|
+
margin-top: 1.5rem !important;
|
|
1865
|
+
margin-bottom: 0.75rem !important;
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
h3 {
|
|
1869
|
+
font-size: 14pt !important;
|
|
1870
|
+
margin-top: 1.25rem !important;
|
|
1871
|
+
margin-bottom: 0.5rem !important;
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
p, li {
|
|
1875
|
+
font-size: 11pt !important;
|
|
1876
|
+
margin-bottom: 0.75rem !important;
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
pre, code {
|
|
1880
|
+
font-size: 10pt !important;
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
h1, h2, h3, h4, h5, h6 {
|
|
1885
|
+
color: black !important;
|
|
1886
|
+
page-break-after: avoid;
|
|
1887
|
+
break-after: avoid;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
h2 {
|
|
1891
|
+
border-bottom: 1px solid #000 !important;
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
p, li {
|
|
1895
|
+
orphans: 3;
|
|
1896
|
+
widows: 3;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
a {
|
|
1900
|
+
text-decoration: underline !important;
|
|
1901
|
+
color: black !important;
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
/* Expand external links */
|
|
1905
|
+
a[href^="http"]::after {
|
|
1906
|
+
content: " (" attr(href) ")";
|
|
1907
|
+
font-size: 0.85em;
|
|
1908
|
+
color: #555;
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
/* Clean up code blocks */
|
|
1912
|
+
pre {
|
|
1913
|
+
border: 1px solid #ccc !important;
|
|
1914
|
+
white-space: pre-wrap !important;
|
|
1915
|
+
break-inside: avoid;
|
|
1916
|
+
background: #fafafa !important;
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
/* Blockquotes */
|
|
1920
|
+
blockquote {
|
|
1921
|
+
border-left: 3px solid #ccc !important;
|
|
1922
|
+
background: transparent !important;
|
|
1923
|
+
color: #333 !important;
|
|
1924
|
+
break-inside: avoid;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
/* Tables */
|
|
1928
|
+
table {
|
|
1929
|
+
break-inside: avoid;
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
/* Page Setup */
|
|
1933
|
+
@page {
|
|
1934
|
+
margin: 2cm;
|
|
1935
|
+
size: auto;
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
|