@riebeckite/honox 0.0.18 → 0.0.20
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 +16 -4
- package/README_ja.md +10 -4
- package/dist/index.js +179 -78
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +16 -0
- package/dist/server.d.ts +2 -2
- package/dist/server.js +48 -1
- package/dist/src/asset_entries.d.ts +1 -0
- package/dist/src/config_loader.d.ts +1 -1
- package/dist/src/content_route.d.ts +43 -1
- package/dist/src/resolved_config.d.ts +7 -0
- package/dist/src/runtime_modules.d.ts +11 -0
- package/dist/src/ui/primitives.d.ts +87 -10
- package/dist/src/ui/primitives.js +99 -17
- package/dist/src/vite_runner.d.ts +3 -1
- package/package.json +18 -6
- package/style.css +55 -0
package/README.md
CHANGED
|
@@ -84,6 +84,18 @@ imported from. Installed npm consumers do not need `workspaceRoot`.
|
|
|
84
84
|
- Types: `RiebeckiteSsgOptions`, `ResolveHonoxApplicationOptions`,
|
|
85
85
|
`ResolvedHonoxApplication`
|
|
86
86
|
|
|
87
|
+
The plugin also provides the bootstrap modules a generated site imports:
|
|
88
|
+
`virtual:riebeckite/config` (the resolved config) and
|
|
89
|
+
`virtual:riebeckite/content` (a configured `ContentManager`). Sites therefore no
|
|
90
|
+
longer need `app/config.ts`, `app/content.ts`, or `app/constants/paths.ts`.
|
|
91
|
+
|
|
92
|
+
### `@riebeckite/honox/runtime`
|
|
93
|
+
|
|
94
|
+
- `resolveHonoxConfig(config, appRoot)` — applies `appRoot` to a resolved
|
|
95
|
+
config (build/output directories and absolute `content.directory`). It is a
|
|
96
|
+
lightweight subpath, so scripts outside the Vite pipeline can resolve the same
|
|
97
|
+
values without loading the Vite plugin.
|
|
98
|
+
|
|
87
99
|
### `@riebeckite/honox/server`
|
|
88
100
|
|
|
89
101
|
- `mountRiebeckiteEndpoints(app, { config, content })`
|
|
@@ -100,8 +112,8 @@ layout, islands, and CSS.
|
|
|
100
112
|
|
|
101
113
|
## See also
|
|
102
114
|
|
|
103
|
-
- [HonoX Integration](../../../docs/docs/framework/honox-integration.
|
|
104
|
-
- [CLI Reference](../../../docs/docs/reference/cli.
|
|
105
|
-
- [Configuration](../../../docs/docs/reference/configuration.
|
|
106
|
-
- [Plugin System](../../../docs/docs/reference/plugin-api.
|
|
115
|
+
- [HonoX Integration](../../../docs/docs/framework/honox-integration.md)
|
|
116
|
+
- [CLI Reference](../../../docs/docs/reference/cli.md)
|
|
117
|
+
- [Configuration](../../../docs/docs/reference/configuration.md)
|
|
118
|
+
- [Plugin System](../../../docs/docs/reference/plugin-api.md) / [Theme System](../../../docs/docs/reference/theme-api.md)
|
|
107
119
|
|
package/README_ja.md
CHANGED
|
@@ -72,6 +72,12 @@ const app = createApp({
|
|
|
72
72
|
- `resolveHonoxApplication`、`resolveHonoxApplicationRoot`、`buildHonoxApplication`、`startHonoxDevServer`
|
|
73
73
|
- 型: `RiebeckiteSsgOptions`、`ResolveHonoxApplicationOptions`、`ResolvedHonoxApplication`
|
|
74
74
|
|
|
75
|
+
Plugin は generated Site が import する bootstrap module も提供します。`virtual:riebeckite/config`(解決済み config)と `virtual:riebeckite/content`(構成済み `ContentManager`)です。そのため Site が `app/config.ts`、`app/content.ts`、`app/constants/paths.ts` を持つ必要はありません。
|
|
76
|
+
|
|
77
|
+
### `@riebeckite/honox/runtime`
|
|
78
|
+
|
|
79
|
+
- `resolveHonoxConfig(config, appRoot)` — 解決済み config に `appRoot` を適用します(build / output directory と絶対 `content.directory`)。Vite の外で動く script が Vite Plugin を読み込まずに同じ値を解決できる軽量な subpath です。
|
|
80
|
+
|
|
75
81
|
### `@riebeckite/honox/server`
|
|
76
82
|
|
|
77
83
|
- `mountRiebeckiteEndpoints(app, { config, content })`
|
|
@@ -84,8 +90,8 @@ const app = createApp({
|
|
|
84
90
|
|
|
85
91
|
## 関連資料
|
|
86
92
|
|
|
87
|
-
- [HonoX Integration](../../../docs/docs/framework/honox-integration.md)
|
|
88
|
-
- [CLI Reference](../../../docs/docs/reference/cli.md)
|
|
89
|
-
- [Configuration](../../../docs/docs/reference/configuration.md)
|
|
90
|
-
- [Plugin System](../../../docs/docs/reference/plugin-api.md) / [Theme System](../../../docs/docs/reference/theme-api.md)
|
|
93
|
+
- [HonoX Integration](../../../docs/docs/framework/honox-integration.ja.md)
|
|
94
|
+
- [CLI Reference](../../../docs/docs/reference/cli.ja.md)
|
|
95
|
+
- [Configuration](../../../docs/docs/reference/configuration.ja.md)
|
|
96
|
+
- [Plugin System](../../../docs/docs/reference/plugin-api.ja.md) / [Theme System](../../../docs/docs/reference/theme-api.ja.md)
|
|
91
97
|
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/config_loader.ts
|
|
2
2
|
import fs2 from "node:fs/promises";
|
|
3
|
-
import
|
|
3
|
+
import path3 from "node:path";
|
|
4
4
|
import { build as buildWithEsbuild } from "esbuild";
|
|
5
5
|
|
|
6
6
|
// src/workspace_packages.ts
|
|
@@ -107,18 +107,32 @@ function escapeRegExp(value) {
|
|
|
107
107
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
// src/resolved_config.ts
|
|
111
|
+
import path2 from "node:path";
|
|
112
|
+
function resolveHonoxConfig(config, appRoot) {
|
|
113
|
+
return {
|
|
114
|
+
...config,
|
|
115
|
+
buildDirectory: path2.join(appRoot, ".riebeckite"),
|
|
116
|
+
outputDirectory: path2.join(appRoot, "dist"),
|
|
117
|
+
content: {
|
|
118
|
+
...config.content,
|
|
119
|
+
directory: path2.resolve(appRoot, config.content.directory)
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
110
124
|
// src/config_loader.ts
|
|
111
125
|
async function loadRiebeckiteConfig(options) {
|
|
112
126
|
const configFile = options.configFile ?? "riebeckite.config.ts";
|
|
113
127
|
const temporaryDirectory = await fs2.mkdtemp(
|
|
114
|
-
|
|
128
|
+
path3.join(options.configRoot, ".riebeckite-config-")
|
|
115
129
|
);
|
|
116
|
-
const outputFile =
|
|
130
|
+
const outputFile = path3.join(temporaryDirectory, "config.mjs");
|
|
117
131
|
try {
|
|
118
132
|
await buildWithEsbuild({
|
|
119
133
|
stdin: {
|
|
120
134
|
contents: `
|
|
121
|
-
import rawConfig from ${JSON.stringify(
|
|
135
|
+
import rawConfig from ${JSON.stringify(path3.resolve(options.configRoot, configFile))};
|
|
122
136
|
import { resolveConfigModule } from "@riebeckite/core";
|
|
123
137
|
export default resolveConfigModule(rawConfig);
|
|
124
138
|
`,
|
|
@@ -140,24 +154,13 @@ async function loadRiebeckiteConfig(options) {
|
|
|
140
154
|
await fs2.rm(temporaryDirectory, { recursive: true, force: true });
|
|
141
155
|
}
|
|
142
156
|
}
|
|
143
|
-
function resolveHonoxConfig(config, appRoot) {
|
|
144
|
-
return {
|
|
145
|
-
...config,
|
|
146
|
-
buildDirectory: path2.join(appRoot, ".riebeckite"),
|
|
147
|
-
outputDirectory: path2.join(appRoot, "dist"),
|
|
148
|
-
content: {
|
|
149
|
-
...config.content,
|
|
150
|
-
directory: path2.resolve(appRoot, config.content.directory)
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
157
|
function pathToFileUrl(filePath) {
|
|
155
158
|
return `file:///${filePath.replace(/\\/g, "/").replace(/^([A-Za-z]):/, "$1:")}`;
|
|
156
159
|
}
|
|
157
160
|
|
|
158
161
|
// src/honox_islands.ts
|
|
159
162
|
import fs3 from "node:fs/promises";
|
|
160
|
-
import
|
|
163
|
+
import path4 from "node:path";
|
|
161
164
|
import { parse } from "@babel/parser";
|
|
162
165
|
var honoxIslandDependencyPluginName = "inject-importing-islands";
|
|
163
166
|
var importingIslandsExport = "__importing_islands";
|
|
@@ -184,8 +187,8 @@ function scopedIslandDependencyPlugin() {
|
|
|
184
187
|
return {
|
|
185
188
|
name: "riebeckite-inject-importing-islands",
|
|
186
189
|
configResolved(config) {
|
|
187
|
-
appDirectory =
|
|
188
|
-
islandDirectory =
|
|
190
|
+
appDirectory = path4.resolve(config.root, "app");
|
|
191
|
+
islandDirectory = path4.join(appDirectory, "islands");
|
|
189
192
|
},
|
|
190
193
|
async transform(sourceCode, id) {
|
|
191
194
|
const modulePath = toFilePath(id);
|
|
@@ -248,8 +251,8 @@ function toFilePath(id) {
|
|
|
248
251
|
return id.split("?", 1)[0] ?? id;
|
|
249
252
|
}
|
|
250
253
|
function isInDirectory(filePath, directory) {
|
|
251
|
-
const relativePath =
|
|
252
|
-
return relativePath !== "" && !relativePath.startsWith(`..${
|
|
254
|
+
const relativePath = path4.relative(directory, filePath);
|
|
255
|
+
return relativePath !== "" && !relativePath.startsWith(`..${path4.sep}`) && !path4.isAbsolute(relativePath);
|
|
253
256
|
}
|
|
254
257
|
function isJavaScriptModule(filePath) {
|
|
255
258
|
return /\.[cm]?[jt]sx?$/.test(filePath);
|
|
@@ -275,7 +278,7 @@ import {
|
|
|
275
278
|
|
|
276
279
|
// src/content_assets.ts
|
|
277
280
|
import fs4 from "node:fs/promises";
|
|
278
|
-
import
|
|
281
|
+
import path6 from "node:path";
|
|
279
282
|
import {
|
|
280
283
|
isIgnoredContentPath as isIgnoredContentPath2,
|
|
281
284
|
isImagePath as isImagePath2,
|
|
@@ -283,13 +286,72 @@ import {
|
|
|
283
286
|
} from "@riebeckite/core";
|
|
284
287
|
|
|
285
288
|
// src/content_watch.ts
|
|
286
|
-
import
|
|
289
|
+
import path5 from "node:path";
|
|
287
290
|
import {
|
|
288
291
|
isAttachmentPath,
|
|
289
292
|
isIgnoredContentPath,
|
|
290
293
|
isImagePath,
|
|
291
294
|
normalizeContentPath
|
|
292
295
|
} from "@riebeckite/core";
|
|
296
|
+
|
|
297
|
+
// src/runtime_modules.ts
|
|
298
|
+
var riebeckiteConfigModuleId = "virtual:riebeckite/config";
|
|
299
|
+
var riebeckiteContentModuleId = "virtual:riebeckite/content";
|
|
300
|
+
var runtimeModuleIds = [
|
|
301
|
+
riebeckiteConfigModuleId,
|
|
302
|
+
riebeckiteContentModuleId
|
|
303
|
+
];
|
|
304
|
+
var resolvedConfigModuleId = `\0${riebeckiteConfigModuleId}`;
|
|
305
|
+
var resolvedContentModuleId = `\0${riebeckiteContentModuleId}`;
|
|
306
|
+
function riebeckiteRuntimeModules(getApplication) {
|
|
307
|
+
return {
|
|
308
|
+
name: "riebeckite-runtime-modules",
|
|
309
|
+
resolveId(id) {
|
|
310
|
+
if (id === riebeckiteConfigModuleId) return resolvedConfigModuleId;
|
|
311
|
+
if (id === riebeckiteContentModuleId) return resolvedContentModuleId;
|
|
312
|
+
return null;
|
|
313
|
+
},
|
|
314
|
+
load(id) {
|
|
315
|
+
if (id === resolvedConfigModuleId) {
|
|
316
|
+
const { appRoot, configFile } = getApplication();
|
|
317
|
+
return createConfigModule(appRoot, configFile);
|
|
318
|
+
}
|
|
319
|
+
if (id === resolvedContentModuleId) return createContentModule();
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
function isRiebeckiteRuntimeModuleId(id) {
|
|
325
|
+
if (!id) return false;
|
|
326
|
+
return runtimeModuleIds.some(
|
|
327
|
+
(moduleId) => id === moduleId || id === `\0${moduleId}`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
function createConfigModule(appRoot, configFile) {
|
|
331
|
+
const configSpecifier = configFile.replace(/\\/g, "/");
|
|
332
|
+
return `import * as rawConfigModule from ${JSON.stringify(configSpecifier)};
|
|
333
|
+
import { resolveConfigModule } from "@riebeckite/core";
|
|
334
|
+
import { resolveHonoxConfig } from "@riebeckite/honox/runtime";
|
|
335
|
+
|
|
336
|
+
export const config = resolveHonoxConfig(
|
|
337
|
+
resolveConfigModule(rawConfigModule),
|
|
338
|
+
${JSON.stringify(appRoot)},
|
|
339
|
+
);
|
|
340
|
+
`;
|
|
341
|
+
}
|
|
342
|
+
function createContentModule() {
|
|
343
|
+
return `import { ContentManager } from "@riebeckite/core";
|
|
344
|
+
import { config } from ${JSON.stringify(riebeckiteConfigModuleId)};
|
|
345
|
+
|
|
346
|
+
export const content = new ContentManager(
|
|
347
|
+
config.content.directory,
|
|
348
|
+
config.content.exclude,
|
|
349
|
+
{ config, plugins: config.plugins },
|
|
350
|
+
);
|
|
351
|
+
`;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// src/content_watch.ts
|
|
293
355
|
var CONTENT_RELOAD_DEBOUNCE_MS = 60;
|
|
294
356
|
var configuredWatchers = /* @__PURE__ */ new WeakSet();
|
|
295
357
|
function riebeckiteContentWatch(options) {
|
|
@@ -345,24 +407,27 @@ function isPathInsideDirectory(directory, file) {
|
|
|
345
407
|
}
|
|
346
408
|
function toLogicalPath(directory, file) {
|
|
347
409
|
return normalizeContentPath(
|
|
348
|
-
|
|
410
|
+
path5.relative(normalizeContentPath(directory), normalizeContentPath(file))
|
|
349
411
|
);
|
|
350
412
|
}
|
|
351
413
|
function invalidateApplicationRuntime(server, appRoot) {
|
|
352
414
|
const moduleGraph = server.environments?.ssr?.moduleGraph;
|
|
353
415
|
if (!moduleGraph) return 0;
|
|
354
|
-
const appDirectory =
|
|
416
|
+
const appDirectory = path5.join(appRoot, "app") + path5.sep;
|
|
355
417
|
const seen = /* @__PURE__ */ new Set();
|
|
356
418
|
const timestamp = Date.now();
|
|
357
419
|
let invalidated = 0;
|
|
358
420
|
for (const mod of moduleGraph.idToModuleMap.values()) {
|
|
359
|
-
|
|
360
|
-
if (!file || !isPathInsideDirectory(appDirectory, file)) continue;
|
|
421
|
+
if (!isApplicationRuntimeModule(mod, appDirectory)) continue;
|
|
361
422
|
moduleGraph.invalidateModule(mod, seen, timestamp);
|
|
362
423
|
invalidated += 1;
|
|
363
424
|
}
|
|
364
425
|
return invalidated;
|
|
365
426
|
}
|
|
427
|
+
function isApplicationRuntimeModule(mod, appDirectory) {
|
|
428
|
+
if (mod.file && isPathInsideDirectory(appDirectory, mod.file)) return true;
|
|
429
|
+
return isRiebeckiteRuntimeModuleId(mod.id);
|
|
430
|
+
}
|
|
366
431
|
function suppressRestartOnContentEvents(server, isContentFile) {
|
|
367
432
|
for (const event of ["add", "unlink"]) {
|
|
368
433
|
const listeners = server.watcher.rawListeners(event).slice();
|
|
@@ -397,7 +462,7 @@ function riebeckiteContentAssets(options) {
|
|
|
397
462
|
enforce: "pre",
|
|
398
463
|
configureServer(server) {
|
|
399
464
|
const contentRoot = options.contentRoot();
|
|
400
|
-
const entry =
|
|
465
|
+
const entry = path6.join(options.appRoot(), "app", "server.ts");
|
|
401
466
|
const base = server.config.base;
|
|
402
467
|
const publicDir = server.config.publicDir;
|
|
403
468
|
let cachedManifest;
|
|
@@ -437,7 +502,7 @@ function riebeckiteContentAssets(options) {
|
|
|
437
502
|
next();
|
|
438
503
|
return;
|
|
439
504
|
}
|
|
440
|
-
const file =
|
|
505
|
+
const file = path6.join(contentRoot, logicalPath);
|
|
441
506
|
if (!isPathInsideDirectory(contentRoot, file)) {
|
|
442
507
|
next();
|
|
443
508
|
return;
|
|
@@ -484,16 +549,16 @@ function collectPublicImagePaths(manifest) {
|
|
|
484
549
|
async function collectSiteOwnedOutputPaths(publicDir) {
|
|
485
550
|
const paths = /* @__PURE__ */ new Set();
|
|
486
551
|
if (!publicDir) return paths;
|
|
487
|
-
const root =
|
|
552
|
+
const root = path6.resolve(publicDir);
|
|
488
553
|
const walk = async (directory) => {
|
|
489
554
|
const entries = await fs4.readdir(directory, { withFileTypes: true }).catch(() => void 0);
|
|
490
555
|
if (!entries) return;
|
|
491
556
|
for (const entry of entries) {
|
|
492
|
-
const full =
|
|
557
|
+
const full = path6.join(directory, entry.name);
|
|
493
558
|
if (entry.isDirectory()) {
|
|
494
559
|
await walk(full);
|
|
495
560
|
} else {
|
|
496
|
-
paths.add(
|
|
561
|
+
paths.add(path6.relative(root, full).replaceAll("\\", "/"));
|
|
497
562
|
}
|
|
498
563
|
}
|
|
499
564
|
};
|
|
@@ -528,7 +593,7 @@ function imageContentType(logicalPath) {
|
|
|
528
593
|
}
|
|
529
594
|
async function hasSiteOwnedFile(publicDir, logicalPath) {
|
|
530
595
|
if (!publicDir) return false;
|
|
531
|
-
const file =
|
|
596
|
+
const file = path6.join(publicDir, logicalPath);
|
|
532
597
|
try {
|
|
533
598
|
return (await fs4.stat(file)).isFile();
|
|
534
599
|
} catch {
|
|
@@ -737,7 +802,7 @@ function riebeckiteSsg(options = {}) {
|
|
|
737
802
|
outputChangeSet.affected.filter((output) => output.kind === "generated").map((output) => output.path)
|
|
738
803
|
) : void 0,
|
|
739
804
|
siteOwnedOutputPaths,
|
|
740
|
-
(
|
|
805
|
+
(path10) => shadowedOutputs.add(path10)
|
|
741
806
|
)
|
|
742
807
|
);
|
|
743
808
|
if (!outputChangeSet)
|
|
@@ -745,21 +810,21 @@ function riebeckiteSsg(options = {}) {
|
|
|
745
810
|
if (canUseIncremental) {
|
|
746
811
|
await measure(timingsMs, "unchangedOutputReuse", async () => {
|
|
747
812
|
for (const output of outputChangeSet.unchanged) {
|
|
748
|
-
const
|
|
749
|
-
if (siteOwnedOutputPaths.has(
|
|
750
|
-
shadowedOutputs.add(
|
|
813
|
+
const path10 = output.path;
|
|
814
|
+
if (siteOwnedOutputPaths.has(path10)) {
|
|
815
|
+
shadowedOutputs.add(path10);
|
|
751
816
|
continue;
|
|
752
817
|
}
|
|
753
|
-
const cached = previousOutputCache.outputs[
|
|
818
|
+
const cached = previousOutputCache.outputs[path10];
|
|
754
819
|
if (!cached) continue;
|
|
755
820
|
this.emitFile({
|
|
756
821
|
type: "asset",
|
|
757
|
-
fileName:
|
|
822
|
+
fileName: path10,
|
|
758
823
|
source: decodeOutput(cached)
|
|
759
824
|
});
|
|
760
825
|
metrics.emittedOutputCount += 1;
|
|
761
826
|
metrics.reusedOutputCount += 1;
|
|
762
|
-
nextOutputCache.outputs[
|
|
827
|
+
nextOutputCache.outputs[path10] = cached;
|
|
763
828
|
}
|
|
764
829
|
});
|
|
765
830
|
}
|
|
@@ -791,6 +856,9 @@ function riebeckiteSsg(options = {}) {
|
|
|
791
856
|
);
|
|
792
857
|
}
|
|
793
858
|
await writeSsgOutputMetrics(metrics);
|
|
859
|
+
this.info(
|
|
860
|
+
`SSG outputs: ${metrics.renderedOutputCount} rendered · ${metrics.reusedOutputCount} reused · ${metrics.deletedOutputCount} removed`
|
|
861
|
+
);
|
|
794
862
|
inspectGeneratedHtmlPages(module, generatedHtml, {
|
|
795
863
|
warn: (message) => this.warn(message),
|
|
796
864
|
info: (message) => this.info(message)
|
|
@@ -820,16 +888,16 @@ async function findOversizedAssets(directory, relativeDirectory = "") {
|
|
|
820
888
|
);
|
|
821
889
|
const nestedAssets = await Promise.all(
|
|
822
890
|
entries.map(async (entry) => {
|
|
823
|
-
const
|
|
891
|
+
const path10 = join(directory, entry.name);
|
|
824
892
|
const relativePath = join(relativeDirectory, entry.name).replaceAll(
|
|
825
893
|
"\\",
|
|
826
894
|
"/"
|
|
827
895
|
);
|
|
828
896
|
if (entry.isDirectory()) {
|
|
829
|
-
return findOversizedAssets(
|
|
897
|
+
return findOversizedAssets(path10, relativePath);
|
|
830
898
|
}
|
|
831
899
|
if (!entry.isFile()) return [];
|
|
832
|
-
const size = (await stat(
|
|
900
|
+
const size = (await stat(path10)).size;
|
|
833
901
|
return size > cloudflareWorkerAssetLimit ? [{ path: relativePath, size }] : [];
|
|
834
902
|
})
|
|
835
903
|
);
|
|
@@ -846,8 +914,8 @@ function shouldApplyRiebeckiteSsg(_config, env) {
|
|
|
846
914
|
}
|
|
847
915
|
function findBuildOutputSiteCollisions(buildOutputPaths, siteOwnedOutputPaths) {
|
|
848
916
|
const collisions = /* @__PURE__ */ new Set();
|
|
849
|
-
for (const
|
|
850
|
-
if (siteOwnedOutputPaths.has(
|
|
917
|
+
for (const path10 of buildOutputPaths) {
|
|
918
|
+
if (siteOwnedOutputPaths.has(path10)) collisions.add(path10);
|
|
851
919
|
}
|
|
852
920
|
return [...collisions].sort();
|
|
853
921
|
}
|
|
@@ -922,14 +990,14 @@ async function collectAppFiles(directory, files) {
|
|
|
922
990
|
}
|
|
923
991
|
}
|
|
924
992
|
}
|
|
925
|
-
async function loadOutputCache(
|
|
993
|
+
async function loadOutputCache(path10, timingsMs, log = () => {
|
|
926
994
|
}) {
|
|
927
995
|
let raw;
|
|
928
996
|
try {
|
|
929
997
|
raw = await measure(
|
|
930
998
|
timingsMs,
|
|
931
999
|
"outputCacheRead",
|
|
932
|
-
() => readFile(
|
|
1000
|
+
() => readFile(path10, "utf8")
|
|
933
1001
|
);
|
|
934
1002
|
} catch (error) {
|
|
935
1003
|
if (isNotFoundError(error)) return void 0;
|
|
@@ -966,10 +1034,10 @@ function isOutputCacheEntries(value) {
|
|
|
966
1034
|
(entry) => typeof entry === "object" && entry !== null && typeof entry.source === "string" && (entry.encoding === "utf8" || entry.encoding === "base64")
|
|
967
1035
|
);
|
|
968
1036
|
}
|
|
969
|
-
async function saveOutputCache(
|
|
970
|
-
const directory = dirname(
|
|
1037
|
+
async function saveOutputCache(path10, state, timingsMs) {
|
|
1038
|
+
const directory = dirname(path10);
|
|
971
1039
|
await mkdir(directory, { recursive: true });
|
|
972
|
-
const temporaryPath = `${
|
|
1040
|
+
const temporaryPath = `${path10}.${randomUUID()}.tmp`;
|
|
973
1041
|
const serialized = measureSync(
|
|
974
1042
|
timingsMs,
|
|
975
1043
|
"outputCacheSerialize",
|
|
@@ -985,7 +1053,7 @@ async function saveOutputCache(path9, state, timingsMs) {
|
|
|
985
1053
|
await measure(
|
|
986
1054
|
timingsMs,
|
|
987
1055
|
"outputCacheRename",
|
|
988
|
-
() => replaceFile(temporaryPath,
|
|
1056
|
+
() => replaceFile(temporaryPath, path10)
|
|
989
1057
|
);
|
|
990
1058
|
} catch (error) {
|
|
991
1059
|
await rm(temporaryPath, { force: true }).catch(() => void 0);
|
|
@@ -1088,16 +1156,23 @@ function createRiebeckiteSsg(options = {}) {
|
|
|
1088
1156
|
}
|
|
1089
1157
|
|
|
1090
1158
|
// src/vite_plugin.ts
|
|
1091
|
-
import
|
|
1159
|
+
import path9 from "node:path";
|
|
1092
1160
|
|
|
1093
1161
|
// src/asset_entries.ts
|
|
1094
1162
|
import fs5 from "node:fs";
|
|
1095
|
-
import
|
|
1163
|
+
import path7 from "node:path";
|
|
1096
1164
|
import { uniqueStrings } from "@riebeckite/core";
|
|
1097
1165
|
function writeRiebeckiteAssetEntries(config, paths) {
|
|
1166
|
+
writeGeneratedFile(paths.frameworkStyles, createFrameworkStylesEntry());
|
|
1098
1167
|
writeGeneratedFile(paths.pluginStyles, createPluginStylesEntry(config));
|
|
1099
1168
|
writeGeneratedFile(paths.themeStyles, createThemeStylesEntry(config));
|
|
1100
1169
|
}
|
|
1170
|
+
function createFrameworkStylesEntry() {
|
|
1171
|
+
return createStylesheetEntry(
|
|
1172
|
+
["@riebeckite/honox/style.css"],
|
|
1173
|
+
"Framework structural styles. Generated by @riebeckite/honox; do not edit. Import this before the plugin and theme stylesheets."
|
|
1174
|
+
);
|
|
1175
|
+
}
|
|
1101
1176
|
function createPluginStylesEntry(config) {
|
|
1102
1177
|
return createStylesheetEntry(
|
|
1103
1178
|
collectPluginStyleSpecifiers(config),
|
|
@@ -1126,7 +1201,7 @@ ${imports}
|
|
|
1126
1201
|
}
|
|
1127
1202
|
function writeGeneratedFile(filePath, contents) {
|
|
1128
1203
|
if (readGeneratedFile(filePath) === contents) return;
|
|
1129
|
-
fs5.mkdirSync(
|
|
1204
|
+
fs5.mkdirSync(path7.dirname(filePath), { recursive: true });
|
|
1130
1205
|
fs5.writeFileSync(filePath, contents);
|
|
1131
1206
|
}
|
|
1132
1207
|
function readGeneratedFile(filePath) {
|
|
@@ -1200,15 +1275,15 @@ ${initializers.map((initializer) => ` ${initializer};`).join("\n")}
|
|
|
1200
1275
|
|
|
1201
1276
|
// src/vite_runner.ts
|
|
1202
1277
|
import fs6 from "node:fs/promises";
|
|
1203
|
-
import
|
|
1278
|
+
import path8 from "node:path";
|
|
1204
1279
|
import { build, createServer as createServer2 } from "vite";
|
|
1205
1280
|
var viteConfigFileNames = [
|
|
1206
1281
|
"vite.config.ts",
|
|
1207
1282
|
"vite.config.js",
|
|
1208
1283
|
"vite.config.mjs"
|
|
1209
1284
|
];
|
|
1210
|
-
async function resolveHonoxApplicationRoot(configRoot) {
|
|
1211
|
-
const roots = await findViteApplicationRoots(configRoot);
|
|
1285
|
+
async function resolveHonoxApplicationRoot(configRoot, startDirectory) {
|
|
1286
|
+
const roots = await findViteApplicationRoots(configRoot, startDirectory);
|
|
1212
1287
|
if (roots.length === 1) return roots[0];
|
|
1213
1288
|
if (roots.length === 0) {
|
|
1214
1289
|
throw new HonoxApplicationRootError(
|
|
@@ -1226,9 +1301,13 @@ var HonoxApplicationRootError = class extends Error {
|
|
|
1226
1301
|
}
|
|
1227
1302
|
};
|
|
1228
1303
|
async function resolveHonoxApplication(options) {
|
|
1229
|
-
const configRoot =
|
|
1230
|
-
const appRoot = options.appRoot ?
|
|
1304
|
+
const configRoot = path8.resolve(options.configRoot);
|
|
1305
|
+
const appRoot = options.appRoot ? path8.resolve(options.appRoot) : await resolveHonoxApplicationRoot(configRoot, options.startDirectory);
|
|
1231
1306
|
const workspaceRoot = options.workspaceRoot ?? await findWorkspaceRoot(configRoot);
|
|
1307
|
+
const configFile = path8.resolve(
|
|
1308
|
+
configRoot,
|
|
1309
|
+
options.configFile ?? "riebeckite.config.ts"
|
|
1310
|
+
);
|
|
1232
1311
|
const rawConfig = await loadRiebeckiteConfig({
|
|
1233
1312
|
configRoot,
|
|
1234
1313
|
configFile: options.configFile,
|
|
@@ -1238,20 +1317,21 @@ async function resolveHonoxApplication(options) {
|
|
|
1238
1317
|
return {
|
|
1239
1318
|
config,
|
|
1240
1319
|
configRoot,
|
|
1320
|
+
configFile,
|
|
1241
1321
|
appRoot,
|
|
1242
1322
|
contentRoot: config.content.directory
|
|
1243
1323
|
};
|
|
1244
1324
|
}
|
|
1245
1325
|
async function findWorkspaceRoot(configRoot) {
|
|
1246
1326
|
try {
|
|
1247
|
-
const workspaceConfig =
|
|
1327
|
+
const workspaceConfig = path8.join(configRoot, "pnpm-workspace.yaml");
|
|
1248
1328
|
return (await fs6.stat(workspaceConfig)).isFile() ? configRoot : void 0;
|
|
1249
1329
|
} catch {
|
|
1250
1330
|
return void 0;
|
|
1251
1331
|
}
|
|
1252
1332
|
}
|
|
1253
1333
|
async function startHonoxDevServer(options) {
|
|
1254
|
-
const root =
|
|
1334
|
+
const root = path8.resolve(options.root);
|
|
1255
1335
|
await withWorkingDirectory(root, async () => {
|
|
1256
1336
|
const server = await createServer2({ root });
|
|
1257
1337
|
await server.listen();
|
|
@@ -1260,7 +1340,7 @@ async function startHonoxDevServer(options) {
|
|
|
1260
1340
|
});
|
|
1261
1341
|
}
|
|
1262
1342
|
async function buildHonoxApplication(options) {
|
|
1263
|
-
const root =
|
|
1343
|
+
const root = path8.resolve(options.root);
|
|
1264
1344
|
await withWorkingDirectory(root, async () => {
|
|
1265
1345
|
await runTraced(
|
|
1266
1346
|
options.tracer,
|
|
@@ -1296,7 +1376,9 @@ async function waitForShutdown(server) {
|
|
|
1296
1376
|
process.once("SIGTERM", close);
|
|
1297
1377
|
});
|
|
1298
1378
|
}
|
|
1299
|
-
async function findViteApplicationRoots(root) {
|
|
1379
|
+
async function findViteApplicationRoots(root, startDirectory) {
|
|
1380
|
+
const applicationRoot = startDirectory ? await findViteApplicationRootFrom(startDirectory, root) : void 0;
|
|
1381
|
+
if (applicationRoot) return [applicationRoot];
|
|
1300
1382
|
const directories = [root];
|
|
1301
1383
|
const applicationRoots = [];
|
|
1302
1384
|
while (directories.length > 0) {
|
|
@@ -1308,15 +1390,29 @@ async function findViteApplicationRoots(root) {
|
|
|
1308
1390
|
if (!entry.isDirectory() || entry.name === "node_modules" || entry.name === ".git" || entry.name === "tests") {
|
|
1309
1391
|
continue;
|
|
1310
1392
|
}
|
|
1311
|
-
directories.push(
|
|
1393
|
+
directories.push(path8.join(directory, entry.name));
|
|
1312
1394
|
}
|
|
1313
1395
|
}
|
|
1314
1396
|
return applicationRoots;
|
|
1315
1397
|
}
|
|
1398
|
+
async function findViteApplicationRootFrom(startDirectory, configRoot) {
|
|
1399
|
+
let directory = path8.resolve(startDirectory);
|
|
1400
|
+
while (isWithin(configRoot, directory)) {
|
|
1401
|
+
if (await hasViteConfig(directory)) return directory;
|
|
1402
|
+
const parent = path8.dirname(directory);
|
|
1403
|
+
if (parent === directory) return void 0;
|
|
1404
|
+
directory = parent;
|
|
1405
|
+
}
|
|
1406
|
+
return void 0;
|
|
1407
|
+
}
|
|
1408
|
+
function isWithin(parent, target) {
|
|
1409
|
+
const relative2 = path8.relative(parent, target);
|
|
1410
|
+
return relative2 === "" || !relative2.startsWith("..") && !path8.isAbsolute(relative2);
|
|
1411
|
+
}
|
|
1316
1412
|
async function hasViteConfig(directory) {
|
|
1317
1413
|
for (const fileName of viteConfigFileNames) {
|
|
1318
1414
|
try {
|
|
1319
|
-
if ((await fs6.stat(
|
|
1415
|
+
if ((await fs6.stat(path8.join(directory, fileName))).isFile()) return true;
|
|
1320
1416
|
} catch {
|
|
1321
1417
|
}
|
|
1322
1418
|
}
|
|
@@ -1336,7 +1432,7 @@ var defaultSsrExternals = [
|
|
|
1336
1432
|
];
|
|
1337
1433
|
function riebeckite(options = {}) {
|
|
1338
1434
|
let resolvedConfig;
|
|
1339
|
-
let
|
|
1435
|
+
let application;
|
|
1340
1436
|
const getConfig = () => {
|
|
1341
1437
|
if (!resolvedConfig) {
|
|
1342
1438
|
throw new Error("Riebeckite config has not been loaded yet.");
|
|
@@ -1347,19 +1443,23 @@ function riebeckite(options = {}) {
|
|
|
1347
1443
|
{
|
|
1348
1444
|
name: "riebeckite-host-integration",
|
|
1349
1445
|
async config(userConfig) {
|
|
1350
|
-
const root = userConfig.root ?
|
|
1446
|
+
const root = userConfig.root ? path9.resolve(userConfig.root) : process.cwd();
|
|
1351
1447
|
const appRoot = options.appRoot ?? root;
|
|
1352
|
-
const
|
|
1448
|
+
const resolvedApplication = await resolveHonoxApplication({
|
|
1353
1449
|
configRoot: options.configRoot ?? appRoot,
|
|
1354
1450
|
configFile: options.configFile,
|
|
1355
1451
|
appRoot,
|
|
1356
1452
|
workspaceRoot: options.workspaceRoot
|
|
1357
1453
|
});
|
|
1358
|
-
resolvedConfig =
|
|
1359
|
-
|
|
1454
|
+
resolvedConfig = resolvedApplication.config;
|
|
1455
|
+
application = resolvedApplication;
|
|
1360
1456
|
writeRiebeckiteAssetEntries(resolvedConfig, {
|
|
1361
|
-
|
|
1362
|
-
|
|
1457
|
+
frameworkStyles: path9.join(
|
|
1458
|
+
appRoot,
|
|
1459
|
+
"app/.riebeckite/framework-styles.css"
|
|
1460
|
+
),
|
|
1461
|
+
pluginStyles: path9.join(appRoot, "app/.riebeckite/plugin-styles.css"),
|
|
1462
|
+
themeStyles: path9.join(appRoot, "app/.riebeckite/theme-styles.css")
|
|
1363
1463
|
});
|
|
1364
1464
|
return {
|
|
1365
1465
|
define: {
|
|
@@ -1377,22 +1477,23 @@ function riebeckite(options = {}) {
|
|
|
1377
1477
|
}
|
|
1378
1478
|
},
|
|
1379
1479
|
riebeckiteClientModule(getConfig),
|
|
1480
|
+
riebeckiteRuntimeModules(() => requireApplication(application)),
|
|
1380
1481
|
riebeckiteContentAssets({
|
|
1381
|
-
appRoot: () =>
|
|
1382
|
-
contentRoot: () =>
|
|
1482
|
+
appRoot: () => requireApplication(application).appRoot,
|
|
1483
|
+
contentRoot: () => requireApplication(application).contentRoot
|
|
1383
1484
|
}),
|
|
1384
1485
|
riebeckiteContentWatch({
|
|
1385
|
-
appRoot: () =>
|
|
1386
|
-
contentRoot: () =>
|
|
1486
|
+
appRoot: () => requireApplication(application).appRoot,
|
|
1487
|
+
contentRoot: () => requireApplication(application).contentRoot,
|
|
1387
1488
|
exclude: () => getConfig().content.exclude ?? []
|
|
1388
1489
|
})
|
|
1389
1490
|
];
|
|
1390
1491
|
}
|
|
1391
|
-
function
|
|
1392
|
-
if (!
|
|
1492
|
+
function requireApplication(application) {
|
|
1493
|
+
if (!application) {
|
|
1393
1494
|
throw new Error("Riebeckite application has not been resolved yet.");
|
|
1394
1495
|
}
|
|
1395
|
-
return
|
|
1496
|
+
return application;
|
|
1396
1497
|
}
|
|
1397
1498
|
function riebeckiteVite(options = {}) {
|
|
1398
1499
|
const { ssg, ssrExternals, ...integration } = options;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { resolveHonoxConfig } from "./src/resolved_config.js";
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/resolved_config.ts
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
function resolveHonoxConfig(config, appRoot) {
|
|
4
|
+
return {
|
|
5
|
+
...config,
|
|
6
|
+
buildDirectory: path.join(appRoot, ".riebeckite"),
|
|
7
|
+
outputDirectory: path.join(appRoot, "dist"),
|
|
8
|
+
content: {
|
|
9
|
+
...config.content,
|
|
10
|
+
directory: path.resolve(appRoot, config.content.directory)
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
resolveHonoxConfig
|
|
16
|
+
};
|
package/dist/server.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type { ResolvedContentRoute, ResolvedRiebeckiteRoute, } from "./src/content_route.js";
|
|
2
|
-
export { contentRouteSsgParams, pluginPageSsgParams, resolveContentRoute, resolveRiebeckiteRoute, riebeckiteSsgParams, ssgEnumerableHandler, } from "./src/content_route.js";
|
|
1
|
+
export type { ResolvedContentRequest, ResolvedContentRoute, ResolvedRiebeckiteRoute, } from "./src/content_route.js";
|
|
2
|
+
export { applyRiebeckiteRouteContext, contentRouteSsgParams, pluginPageSsgParams, resolveContentRoute, resolveRiebeckiteContentRequest, resolveRiebeckiteHomeRequest, resolveRiebeckiteRoute, riebeckiteSsgParams, ssgEnumerableHandler, } from "./src/content_route.js";
|
|
3
3
|
export { mountRiebeckiteEndpoints } from "./src/endpoints.js";
|
package/dist/server.js
CHANGED
|
@@ -1,10 +1,54 @@
|
|
|
1
1
|
// src/content_route.ts
|
|
2
|
-
import { htmlOutputPath } from "@riebeckite/core";
|
|
2
|
+
import { getEntryLanguage, htmlOutputPath } from "@riebeckite/core";
|
|
3
3
|
async function resolveRiebeckiteRoute(content, pathname) {
|
|
4
4
|
const page = await content.resolvePage(pathname);
|
|
5
5
|
if (page) return { kind: "page", page };
|
|
6
6
|
return resolveContentRoute(await content.getManifest(), pathname);
|
|
7
7
|
}
|
|
8
|
+
function applyRiebeckiteRouteContext(c, route) {
|
|
9
|
+
if (route.kind === "page") {
|
|
10
|
+
c.set("headTags", route.page.headTags ?? []);
|
|
11
|
+
c.set("htmlLanguage", route.page.language);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (route.kind === "content") {
|
|
15
|
+
c.set("headTags", route.entry.headTags ?? []);
|
|
16
|
+
c.set("htmlLanguage", getEntryLanguage(route.entry));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
var contentExtensionPattern = /\.[a-zA-Z0-9]+$/;
|
|
20
|
+
async function resolveRouteRequest(c, content) {
|
|
21
|
+
const route = await resolveRiebeckiteRoute(content, c.req.path);
|
|
22
|
+
if (!route) return { kind: "response", response: c.notFound() };
|
|
23
|
+
if (route.kind === "redirect") {
|
|
24
|
+
return {
|
|
25
|
+
kind: "response",
|
|
26
|
+
response: c.redirect(route.location, route.status)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
applyRiebeckiteRouteContext(c, route);
|
|
30
|
+
if (route.kind === "page") return { kind: "page", page: route.page };
|
|
31
|
+
const post = await content.getProcessedContent(route.entry.slug);
|
|
32
|
+
return { kind: "content", entry: route.entry, post };
|
|
33
|
+
}
|
|
34
|
+
async function resolveRiebeckiteContentRequest(c, content, parameter = "slug") {
|
|
35
|
+
const requestedSlug = c.req.param(parameter);
|
|
36
|
+
if (!requestedSlug) return { kind: "response", response: c.notFound() };
|
|
37
|
+
if (contentExtensionPattern.test(requestedSlug)) {
|
|
38
|
+
return { kind: "response", response: c.notFound() };
|
|
39
|
+
}
|
|
40
|
+
return resolveRouteRequest(c, content);
|
|
41
|
+
}
|
|
42
|
+
async function resolveRiebeckiteHomeRequest(c, content) {
|
|
43
|
+
const indexEntry = (await content.getManifest()).bySlug.get("index");
|
|
44
|
+
if (indexEntry && indexEntry.permalink !== "/") {
|
|
45
|
+
return {
|
|
46
|
+
kind: "response",
|
|
47
|
+
response: c.redirect(indexEntry.permalink, 308)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return resolveRouteRequest(c, content);
|
|
51
|
+
}
|
|
8
52
|
async function pluginPageSsgParams(content, parameter = "slug") {
|
|
9
53
|
const paths = await content.getPagePaths();
|
|
10
54
|
return paths.filter((path) => path !== "/").map((path) => ({ [parameter]: path.replace(/^\/+/, "") }));
|
|
@@ -192,10 +236,13 @@ function findHeader(headers, name) {
|
|
|
192
236
|
return key ? headers[key] : void 0;
|
|
193
237
|
}
|
|
194
238
|
export {
|
|
239
|
+
applyRiebeckiteRouteContext,
|
|
195
240
|
contentRouteSsgParams,
|
|
196
241
|
mountRiebeckiteEndpoints,
|
|
197
242
|
pluginPageSsgParams,
|
|
198
243
|
resolveContentRoute,
|
|
244
|
+
resolveRiebeckiteContentRequest,
|
|
245
|
+
resolveRiebeckiteHomeRequest,
|
|
199
246
|
resolveRiebeckiteRoute,
|
|
200
247
|
riebeckiteSsgParams,
|
|
201
248
|
ssgEnumerableHandler
|
|
@@ -5,4 +5,4 @@ export type RiebeckiteConfigLoaderOptions = {
|
|
|
5
5
|
workspaceRoot?: string;
|
|
6
6
|
};
|
|
7
7
|
export declare function loadRiebeckiteConfig(options: RiebeckiteConfigLoaderOptions): Promise<ResolvedRiebeckiteConfig>;
|
|
8
|
-
export
|
|
8
|
+
export { resolveHonoxConfig } from "./resolved_config.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContentManager, ContentManifest, ContentManifestEntry, ResolvedPluginPage } from "@riebeckite/core";
|
|
1
|
+
import type { ContentManager, ContentManifest, ContentManifestEntry, PostContent, ResolvedPluginPage } from "@riebeckite/core";
|
|
2
2
|
import type { Context, Handler, MiddlewareHandler } from "hono";
|
|
3
3
|
export type ResolvedContentRoute = {
|
|
4
4
|
kind: "content";
|
|
@@ -18,6 +18,48 @@ export type ResolvedRiebeckiteRoute = Exclude<ResolvedContentRoute, null> | {
|
|
|
18
18
|
* HonoX routes themselves.
|
|
19
19
|
*/
|
|
20
20
|
export declare function resolveRiebeckiteRoute(content: Pick<ContentManager, "resolvePage" | "getManifest">, pathname: string): Promise<ResolvedRiebeckiteRoute>;
|
|
21
|
+
/**
|
|
22
|
+
* The resolved route request a Site consumes from a catch-all content route.
|
|
23
|
+
*
|
|
24
|
+
* `content` carries everything the Site composition needs; `page` and
|
|
25
|
+
* `response` are framework mechanics the Site forwards without interpreting.
|
|
26
|
+
*/
|
|
27
|
+
export type ResolvedContentRequest = {
|
|
28
|
+
kind: "content";
|
|
29
|
+
entry: ContentManifestEntry;
|
|
30
|
+
post: PostContent;
|
|
31
|
+
} | {
|
|
32
|
+
kind: "page";
|
|
33
|
+
page: ResolvedPluginPage;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "response";
|
|
36
|
+
response: Response | Promise<Response>;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Assigns the resolved route metadata to the request context.
|
|
40
|
+
*
|
|
41
|
+
* Plugins and primitives read `htmlLanguage` and `headTags` from the context,
|
|
42
|
+
* so the resolver owns their values instead of each route rebuilding them.
|
|
43
|
+
*/
|
|
44
|
+
export declare function applyRiebeckiteRouteContext(c: Context, route: Exclude<ResolvedRiebeckiteRoute, null>): void;
|
|
45
|
+
type RouteContent = Pick<ContentManager, "resolvePage" | "getManifest" | "getProcessedContent">;
|
|
46
|
+
/**
|
|
47
|
+
* Resolves a catch-all content request into what a Site should render.
|
|
48
|
+
*
|
|
49
|
+
* Owns the route mechanics a Site must not repeat: the wildcard and content
|
|
50
|
+
* extension guards, plugin page vs content resolution, redirect and not-found
|
|
51
|
+
* responses, context assignment, and loading the processed content.
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveRiebeckiteContentRequest(c: Context, content: RouteContent, parameter?: string): Promise<ResolvedContentRequest>;
|
|
54
|
+
/**
|
|
55
|
+
* Resolves the `/` Homepage request into what a Site should render.
|
|
56
|
+
*
|
|
57
|
+
* Shares every catch-all mechanic with `resolveRiebeckiteContentRequest` but
|
|
58
|
+
* has no wildcard parameter to guard. It additionally owns the configured-index
|
|
59
|
+
* redirect: when the `index` content is permalinked away from `/`, the root
|
|
60
|
+
* forwards there instead of resolving another route.
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveRiebeckiteHomeRequest(c: Context, content: RouteContent): Promise<ResolvedContentRequest>;
|
|
21
63
|
/** Returns catch-all parameters for every plugin page registered for SSG. */
|
|
22
64
|
export declare function pluginPageSsgParams(content: Pick<ContentManager, "getPagePaths">, parameter?: string): Promise<Record<string, string>[]>;
|
|
23
65
|
export declare function riebeckiteSsgParams(content: Pick<ContentManager, "getManifest" | "getOutputChangeSet" | "getPagePaths">, parameter?: string): Promise<Record<string, string>[]>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ResolvedRiebeckiteConfig } from "@riebeckite/core";
|
|
2
|
+
/**
|
|
3
|
+
* Applies the application root to a resolved Riebeckite configuration. The
|
|
4
|
+
* generated site bootstrap imports this through `@riebeckite/honox/runtime`
|
|
5
|
+
* so the resolved config and content runtime stay framework-owned.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveHonoxConfig(config: ResolvedRiebeckiteConfig, appRoot: string): ResolvedRiebeckiteConfig;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
import type { ResolvedHonoxApplication } from "./vite_runner.js";
|
|
3
|
+
export declare const riebeckiteConfigModuleId = "virtual:riebeckite/config";
|
|
4
|
+
export declare const riebeckiteContentModuleId = "virtual:riebeckite/content";
|
|
5
|
+
/**
|
|
6
|
+
* Provides the framework-owned bootstrap modules a generated site imports
|
|
7
|
+
* instead of keeping resolved-config and content-manager ceremony in
|
|
8
|
+
* `app/config.ts` and `app/content.ts`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function riebeckiteRuntimeModules(getApplication: () => ResolvedHonoxApplication): Plugin;
|
|
11
|
+
export declare function isRiebeckiteRuntimeModuleId(id: string | null | undefined): boolean;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ContentBodySlot, ContentBodySlots, PluginHeadTag, ResolvedRiebeckiteConfig } from "@riebeckite/core";
|
|
1
2
|
export type PrimitiveChildren = unknown;
|
|
2
3
|
export type PrimitiveProps = {
|
|
3
4
|
children?: PrimitiveChildren;
|
|
@@ -11,9 +12,7 @@ export type PrimitiveClassProps = {
|
|
|
11
12
|
export type ArticleProps = PrimitiveProps & {
|
|
12
13
|
"data-slot"?: string;
|
|
13
14
|
};
|
|
14
|
-
export type ArticleLayoutProps = PrimitiveProps
|
|
15
|
-
aside?: PrimitiveChildren;
|
|
16
|
-
};
|
|
15
|
+
export type ArticleLayoutProps = PrimitiveProps;
|
|
17
16
|
export type ArticleHeaderProps = (PrimitiveClassProps & {
|
|
18
17
|
dangerouslySetInnerHTML: {
|
|
19
18
|
__html: string;
|
|
@@ -23,15 +22,10 @@ export type ArticleHeaderProps = (PrimitiveClassProps & {
|
|
|
23
22
|
dangerouslySetInnerHTML?: never;
|
|
24
23
|
children?: PrimitiveChildren;
|
|
25
24
|
});
|
|
26
|
-
export type ArticleContentProps =
|
|
27
|
-
html: string;
|
|
28
|
-
children?: never;
|
|
29
|
-
"data-slot"?: string;
|
|
30
|
-
}) | (PrimitiveClassProps & {
|
|
31
|
-
html?: never;
|
|
25
|
+
export type ArticleContentProps = PrimitiveClassProps & {
|
|
32
26
|
children?: PrimitiveChildren;
|
|
33
27
|
"data-slot"?: string;
|
|
34
|
-
}
|
|
28
|
+
};
|
|
35
29
|
export type ArticleMetaProps = PrimitiveProps & {
|
|
36
30
|
label?: string;
|
|
37
31
|
};
|
|
@@ -44,5 +38,88 @@ export declare function ArticleLayout(props: ArticleLayoutProps): import("hono/j
|
|
|
44
38
|
export declare function ArticleHeader(props: ArticleHeaderProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
45
39
|
export declare function ArticleMeta(props: ArticleMetaProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
46
40
|
export declare function ArticleContent(props: ArticleContentProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
41
|
+
export type ArticleBodyProps = PrimitiveClassProps & {
|
|
42
|
+
html: string;
|
|
43
|
+
};
|
|
44
|
+
export type ContentSlotProps = PrimitiveClassProps & {
|
|
45
|
+
slots?: ContentBodySlots;
|
|
46
|
+
name: ContentBodySlot;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Whether a body slot holds renderable content.
|
|
50
|
+
*
|
|
51
|
+
* A slot is absent when its source map is missing, the value is missing, or
|
|
52
|
+
* the value is whitespace-only. This is the same check `ContentSlot` uses.
|
|
53
|
+
*/
|
|
54
|
+
export declare function hasSlot(slots: ContentBodySlots | undefined, name: ContentBodySlot): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Renders a Plugin-provided body slot fragment at the position the Site chose.
|
|
57
|
+
*
|
|
58
|
+
* The Site owns placement; this primitive owns the lookup, empty handling, and
|
|
59
|
+
* HTML injection. It renders nothing when the slot is absent or blank.
|
|
60
|
+
*/
|
|
61
|
+
export declare function ContentSlot(props: ContentSlotProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
62
|
+
/**
|
|
63
|
+
* Renders Markdown-produced HTML as the canonical article body.
|
|
64
|
+
*
|
|
65
|
+
* Owns the `.rb-article-content` Stable Hook so Sites never hand-write it.
|
|
66
|
+
*/
|
|
67
|
+
export declare function ArticleBody(props: ArticleBodyProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
68
|
+
export type PageBodyProps = PrimitiveClassProps & {
|
|
69
|
+
html: string;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Renders framework-resolved Plugin Page HTML.
|
|
73
|
+
*
|
|
74
|
+
* Owns the raw injection of a `PluginPageType` body so Sites never hand-write
|
|
75
|
+
* `dangerouslySetInnerHTML` for a resolved page.
|
|
76
|
+
*/
|
|
77
|
+
export declare function PageBody(props: PageBodyProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
47
78
|
export declare function ArticleFooter(props: ArticleFooterProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
48
79
|
export declare function Sidebar(props: SidebarProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
80
|
+
export type ThemeRootProps = {
|
|
81
|
+
theme: ResolvedRiebeckiteConfig["theme"];
|
|
82
|
+
lang?: string;
|
|
83
|
+
children?: PrimitiveChildren;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Derives the `<html>` attributes from a resolved theme.
|
|
87
|
+
*
|
|
88
|
+
* Combines the theme's custom `data-*` attributes with the reserved
|
|
89
|
+
* color-mode, name, typography, and article-layout attributes.
|
|
90
|
+
*/
|
|
91
|
+
export declare function themeRootAttributes(theme: ResolvedRiebeckiteConfig["theme"]): Record<string, string | undefined>;
|
|
92
|
+
/**
|
|
93
|
+
* Root `<html>` element carrying the resolved theme's attributes.
|
|
94
|
+
*
|
|
95
|
+
* The Site keeps ownership of the document composition by rendering its own
|
|
96
|
+
* `<head>` and `<body>` as children.
|
|
97
|
+
*/
|
|
98
|
+
export declare function ThemeRoot(props: ThemeRootProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
99
|
+
export type PluginHeadTagsProps = {
|
|
100
|
+
tags?: readonly PluginHeadTag[];
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Renders Plugin-provided head tags as `meta` / `link` / `script` elements.
|
|
104
|
+
*
|
|
105
|
+
* The Site owns placement; this primitive owns the conversion and ordering.
|
|
106
|
+
*/
|
|
107
|
+
export declare function PluginHeadTags(props: PluginHeadTagsProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
108
|
+
export type RiebeckiteHeadProps = {
|
|
109
|
+
title: string;
|
|
110
|
+
headTags?: readonly PluginHeadTag[];
|
|
111
|
+
faviconHref?: string | null;
|
|
112
|
+
colorModeScript?: boolean;
|
|
113
|
+
stylesheets?: readonly string[];
|
|
114
|
+
clientSrc?: string | null;
|
|
115
|
+
prod?: boolean;
|
|
116
|
+
children?: PrimitiveChildren;
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Renders the standard Riebeckite `<head>` contents.
|
|
120
|
+
*
|
|
121
|
+
* Owns the charset, viewport, default title, favicon, color-mode bootstrap,
|
|
122
|
+
* stylesheet and client entries, and Plugin head tags. The Site keeps the
|
|
123
|
+
* surrounding `<head>` so it can add its own elements next to this primitive.
|
|
124
|
+
*/
|
|
125
|
+
export declare function RiebeckiteHead(props: RiebeckiteHeadProps): import("hono/jsx/jsx-dev-runtime").JSX.Element;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// src/ui/primitives.tsx
|
|
2
|
-
import {
|
|
2
|
+
import { ColorModeScript } from "@riebeckite/plugin-color-mode";
|
|
3
|
+
import { Link, Script } from "honox/server";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
5
|
+
import { createElement } from "hono/jsx";
|
|
3
6
|
function Article(props) {
|
|
4
7
|
return /* @__PURE__ */ jsx(
|
|
5
8
|
"article",
|
|
@@ -11,14 +14,11 @@ function Article(props) {
|
|
|
11
14
|
);
|
|
12
15
|
}
|
|
13
16
|
function ArticleLayout(props) {
|
|
14
|
-
return /* @__PURE__ */
|
|
17
|
+
return /* @__PURE__ */ jsx(
|
|
15
18
|
"div",
|
|
16
19
|
{
|
|
17
20
|
class: joinClassNames("rb-article-layout", props.class, props.className),
|
|
18
|
-
children:
|
|
19
|
-
props.children,
|
|
20
|
-
props.aside
|
|
21
|
-
]
|
|
21
|
+
children: props.children
|
|
22
22
|
}
|
|
23
23
|
);
|
|
24
24
|
}
|
|
@@ -56,18 +56,43 @@ function ArticleContent(props) {
|
|
|
56
56
|
props.className
|
|
57
57
|
);
|
|
58
58
|
const dataSlot = props["data-slot"] ?? "article-body";
|
|
59
|
-
if (props.html !== void 0) {
|
|
60
|
-
return /* @__PURE__ */ jsx(
|
|
61
|
-
"div",
|
|
62
|
-
{
|
|
63
|
-
class: className,
|
|
64
|
-
"data-slot": dataSlot,
|
|
65
|
-
dangerouslySetInnerHTML: { __html: props.html }
|
|
66
|
-
}
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
59
|
return /* @__PURE__ */ jsx("div", { class: className, "data-slot": dataSlot, children: props.children });
|
|
70
60
|
}
|
|
61
|
+
function hasSlot(slots, name) {
|
|
62
|
+
return Boolean(slots?.[name]?.trim());
|
|
63
|
+
}
|
|
64
|
+
function ContentSlot(props) {
|
|
65
|
+
const html = props.slots?.[props.name];
|
|
66
|
+
if (!html?.trim()) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return /* @__PURE__ */ jsx(
|
|
70
|
+
"div",
|
|
71
|
+
{
|
|
72
|
+
"data-slot": props.name,
|
|
73
|
+
class: joinClassNames(props.class, props.className) || void 0,
|
|
74
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
function ArticleBody(props) {
|
|
79
|
+
return /* @__PURE__ */ jsx(
|
|
80
|
+
"div",
|
|
81
|
+
{
|
|
82
|
+
class: joinClassNames("rb-article-content", props.class, props.className),
|
|
83
|
+
dangerouslySetInnerHTML: { __html: props.html }
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
function PageBody(props) {
|
|
88
|
+
return /* @__PURE__ */ jsx(
|
|
89
|
+
"div",
|
|
90
|
+
{
|
|
91
|
+
class: joinClassNames(props.class, props.className) || void 0,
|
|
92
|
+
dangerouslySetInnerHTML: { __html: props.html }
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
}
|
|
71
96
|
function ArticleFooter(props) {
|
|
72
97
|
return /* @__PURE__ */ jsx(
|
|
73
98
|
"footer",
|
|
@@ -87,15 +112,72 @@ function Sidebar(props) {
|
|
|
87
112
|
}
|
|
88
113
|
);
|
|
89
114
|
}
|
|
115
|
+
function themeRootAttributes(theme) {
|
|
116
|
+
return {
|
|
117
|
+
...theme.attributes,
|
|
118
|
+
"data-theme": theme.colorMode === "system" ? void 0 : theme.colorMode,
|
|
119
|
+
"data-theme-name": theme.name,
|
|
120
|
+
"data-typography": theme.typography,
|
|
121
|
+
"data-article-layout": theme.articleLayout
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function ThemeRoot(props) {
|
|
125
|
+
return /* @__PURE__ */ jsx("html", { lang: props.lang, ...themeRootAttributes(props.theme), children: props.children });
|
|
126
|
+
}
|
|
127
|
+
function PluginHeadTags(props) {
|
|
128
|
+
return /* @__PURE__ */ jsx(Fragment, { children: props.tags?.map(renderPluginHeadTag) });
|
|
129
|
+
}
|
|
130
|
+
function renderPluginHeadTag(tag, index) {
|
|
131
|
+
const key = `${tag.tag}-${index}`;
|
|
132
|
+
if (tag.tag === "meta") {
|
|
133
|
+
return /* @__PURE__ */ createElement("meta", { ...tag.attrs, key });
|
|
134
|
+
}
|
|
135
|
+
if (tag.tag === "link") {
|
|
136
|
+
return /* @__PURE__ */ createElement("link", { ...tag.attrs, key });
|
|
137
|
+
}
|
|
138
|
+
return /* @__PURE__ */ createElement(
|
|
139
|
+
"script",
|
|
140
|
+
{
|
|
141
|
+
...tag.attrs,
|
|
142
|
+
key,
|
|
143
|
+
dangerouslySetInnerHTML: tag.children ? { __html: tag.children } : void 0
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
function RiebeckiteHead(props) {
|
|
148
|
+
const faviconHref = props.faviconHref === void 0 ? "/favicon.ico" : props.faviconHref;
|
|
149
|
+
const stylesheets = props.stylesheets ?? ["/app/style.css"];
|
|
150
|
+
const clientSrc = props.clientSrc === void 0 ? "/app/client.ts" : props.clientSrc;
|
|
151
|
+
const colorModeScript = props.colorModeScript ?? true;
|
|
152
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
153
|
+
/* @__PURE__ */ jsx("meta", { charset: "utf-8" }),
|
|
154
|
+
/* @__PURE__ */ jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }),
|
|
155
|
+
/* @__PURE__ */ jsx("title", { children: props.title }),
|
|
156
|
+
faviconHref ? /* @__PURE__ */ jsx("link", { rel: "icon", href: faviconHref }) : null,
|
|
157
|
+
colorModeScript ? /* @__PURE__ */ jsx(ColorModeScript, {}) : null,
|
|
158
|
+
stylesheets.map((href) => /* @__PURE__ */ jsx(Link, { href, rel: "stylesheet", prod: props.prod }, href)),
|
|
159
|
+
/* @__PURE__ */ jsx(PluginHeadTags, { tags: props.headTags }),
|
|
160
|
+
clientSrc ? /* @__PURE__ */ jsx(Script, { src: clientSrc, async: true, prod: props.prod }) : null,
|
|
161
|
+
props.children
|
|
162
|
+
] });
|
|
163
|
+
}
|
|
90
164
|
function joinClassNames(...classNames) {
|
|
91
165
|
return classNames.filter(Boolean).join(" ");
|
|
92
166
|
}
|
|
93
167
|
export {
|
|
94
168
|
Article,
|
|
169
|
+
ArticleBody,
|
|
95
170
|
ArticleContent,
|
|
96
171
|
ArticleFooter,
|
|
97
172
|
ArticleHeader,
|
|
98
173
|
ArticleLayout,
|
|
99
174
|
ArticleMeta,
|
|
100
|
-
|
|
175
|
+
ContentSlot,
|
|
176
|
+
PageBody,
|
|
177
|
+
PluginHeadTags,
|
|
178
|
+
RiebeckiteHead,
|
|
179
|
+
Sidebar,
|
|
180
|
+
ThemeRoot,
|
|
181
|
+
hasSlot,
|
|
182
|
+
themeRootAttributes
|
|
101
183
|
};
|
|
@@ -7,13 +7,15 @@ export type HonoxApplicationOptions = {
|
|
|
7
7
|
export type ResolvedHonoxApplication = {
|
|
8
8
|
config: ResolvedRiebeckiteConfig;
|
|
9
9
|
configRoot: string;
|
|
10
|
+
configFile: string;
|
|
10
11
|
appRoot: string;
|
|
11
12
|
contentRoot: string;
|
|
12
13
|
};
|
|
13
14
|
export type ResolveHonoxApplicationOptions = RiebeckiteConfigLoaderOptions & {
|
|
14
15
|
appRoot?: string;
|
|
16
|
+
startDirectory?: string;
|
|
15
17
|
};
|
|
16
|
-
export declare function resolveHonoxApplicationRoot(configRoot: string): Promise<string>;
|
|
18
|
+
export declare function resolveHonoxApplicationRoot(configRoot: string, startDirectory?: string): Promise<string>;
|
|
17
19
|
export declare class HonoxApplicationRootError extends Error {
|
|
18
20
|
constructor(message: string);
|
|
19
21
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/honox",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,23 +18,32 @@
|
|
|
18
18
|
"source": "./server.ts",
|
|
19
19
|
"default": "./dist/server.js"
|
|
20
20
|
},
|
|
21
|
+
"./runtime": {
|
|
22
|
+
"types": "./dist/runtime.d.ts",
|
|
23
|
+
"import": "./dist/runtime.js",
|
|
24
|
+
"source": "./runtime.ts",
|
|
25
|
+
"default": "./dist/runtime.js"
|
|
26
|
+
},
|
|
21
27
|
"./ui": {
|
|
22
28
|
"types": "./dist/src/ui/primitives.d.ts",
|
|
23
29
|
"import": "./dist/src/ui/primitives.js",
|
|
24
30
|
"source": "./src/ui/primitives.tsx",
|
|
25
31
|
"default": "./dist/src/ui/primitives.js"
|
|
26
|
-
}
|
|
32
|
+
},
|
|
33
|
+
"./style.css": "./style.css"
|
|
27
34
|
},
|
|
28
35
|
"dependencies": {
|
|
29
36
|
"@babel/parser": "^7.29.3",
|
|
30
37
|
"esbuild": "^0.28.2",
|
|
31
38
|
"hono": "^4.12.25",
|
|
39
|
+
"honox": "0.1.56",
|
|
32
40
|
"vite": "^8.0.9",
|
|
33
|
-
"@riebeckite/core": "0.0.
|
|
41
|
+
"@riebeckite/core": "0.0.20",
|
|
42
|
+
"@riebeckite/plugin-color-mode": "0.0.20"
|
|
34
43
|
},
|
|
35
44
|
"devDependencies": {
|
|
36
45
|
"tsx": "^4.22.4",
|
|
37
|
-
"@riebeckite/test": "0.0.
|
|
46
|
+
"@riebeckite/test": "0.0.20"
|
|
38
47
|
},
|
|
39
48
|
"publishConfig": {
|
|
40
49
|
"access": "public"
|
|
@@ -43,7 +52,8 @@
|
|
|
43
52
|
"LICENSE",
|
|
44
53
|
"README.md",
|
|
45
54
|
"README_ja.md",
|
|
46
|
-
"dist"
|
|
55
|
+
"dist",
|
|
56
|
+
"style.css"
|
|
47
57
|
],
|
|
48
58
|
"repository": {
|
|
49
59
|
"type": "git",
|
|
@@ -64,7 +74,9 @@
|
|
|
64
74
|
"engines": {
|
|
65
75
|
"node": "^20.19.0 || >=22.12.0"
|
|
66
76
|
},
|
|
67
|
-
"sideEffects":
|
|
77
|
+
"sideEffects": [
|
|
78
|
+
"./style.css"
|
|
79
|
+
],
|
|
68
80
|
"scripts": {
|
|
69
81
|
"build": "node ../../../scripts/build_package.mjs",
|
|
70
82
|
"test": "node --import tsx --test \"test/*.test.ts\""
|
package/style.css
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.rb-article-layout {
|
|
3
|
+
display: grid;
|
|
4
|
+
grid-template-columns: minmax(0, var(--rb-layout-article-max, 48rem));
|
|
5
|
+
justify-content: center;
|
|
6
|
+
column-gap: var(--rb-layout-gap, 2rem);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.rb-article-body {
|
|
10
|
+
min-width: 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
:is(:root, .rb-theme-root)[data-article-layout="full-width"]
|
|
14
|
+
.rb-article-layout {
|
|
15
|
+
grid-template-columns: minmax(0, 1fr);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@media (min-width: 88rem) {
|
|
19
|
+
:is(:root, .rb-theme-root)[data-article-layout="sidebar"]
|
|
20
|
+
.rb-article-layout {
|
|
21
|
+
grid-template-columns:
|
|
22
|
+
minmax(0, var(--rb-layout-article-max, 48rem))
|
|
23
|
+
var(--rb-layout-sidebar, 14rem);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
:is(:root, .rb-theme-root)[data-article-layout="article"]
|
|
27
|
+
.rb-article-layout {
|
|
28
|
+
position: relative;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:is(:root, .rb-theme-root)[data-article-layout="article"] .rb-article-body,
|
|
32
|
+
:is(:root, .rb-theme-root)[data-article-layout="sidebar"] .rb-article-body {
|
|
33
|
+
grid-column: 1;
|
|
34
|
+
grid-row: 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.rb-skip-link {
|
|
39
|
+
position: absolute;
|
|
40
|
+
top: 0;
|
|
41
|
+
left: 0;
|
|
42
|
+
z-index: 100;
|
|
43
|
+
padding: var(--rb-space-2, 1rem) var(--rb-space-3, 1.5rem);
|
|
44
|
+
border: var(--rb-rule-width, 1px) solid var(--rb-color-border-strong);
|
|
45
|
+
border-radius: var(--rb-default-radius-sm, 0.25rem);
|
|
46
|
+
background: var(--rb-color-surface);
|
|
47
|
+
color: var(--rb-color-ink);
|
|
48
|
+
text-decoration: none;
|
|
49
|
+
transform: translateY(-200%);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.rb-skip-link:focus {
|
|
53
|
+
transform: translateY(0);
|
|
54
|
+
}
|
|
55
|
+
}
|