create-riebeckite 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.
Files changed (58) hide show
  1. package/README.md +27 -4
  2. package/README_ja.md +26 -2
  3. package/dist/src/arguments.d.ts +2 -0
  4. package/dist/src/index.js +140 -28
  5. package/dist/src/interactive.d.ts +3 -0
  6. package/dist/src/scaffold/index.d.ts +1 -0
  7. package/dist/src/scaffold/index.js +115 -25
  8. package/dist/src/scaffold/options.d.ts +2 -0
  9. package/dist/src/scaffold/templates.d.ts +2 -0
  10. package/dist/src/scaffold/utilities.d.ts +14 -0
  11. package/dist/src/scaffold/version.d.ts +1 -1
  12. package/dist/src/scaffold/wrangler-defaults.d.ts +1 -1
  13. package/package.json +2 -2
  14. package/templates/scaffold/base/app/global.d.ts +9 -3
  15. package/templates/scaffold/base/app/server.ts +2 -2
  16. package/templates/scaffold/base/vite.config.ts +3 -25
  17. package/templates/scaffold/presets/empty/app/routes/_404.tsx +18 -0
  18. package/templates/scaffold/presets/empty/app/routes/_renderer.tsx +1 -1
  19. package/templates/scaffold/presets/empty/app/routes/index.tsx +1 -1
  20. package/templates/scaffold/presets/empty/app/style.css +11 -0
  21. package/templates/scaffold/presets/minimal/app/components/article.tsx +29 -47
  22. package/templates/scaffold/presets/minimal/app/routes/[slug{.+}].tsx +13 -32
  23. package/templates/scaffold/presets/minimal/app/routes/_404.tsx +18 -0
  24. package/templates/scaffold/presets/minimal/app/routes/_renderer.tsx +17 -53
  25. package/templates/scaffold/presets/minimal/app/routes/index.tsx +9 -19
  26. package/templates/scaffold/presets/minimal/app/style.css +15 -22
  27. package/templates/scaffold/presets/minimal/content/index.en.md +16 -6
  28. package/templates/scaffold/presets/showcase/app/components/article.tsx +31 -40
  29. package/templates/scaffold/presets/showcase/app/components/site-header.tsx +10 -64
  30. package/templates/scaffold/presets/showcase/app/routes/[slug{.+}].tsx +15 -34
  31. package/templates/scaffold/presets/showcase/app/routes/_404.tsx +18 -0
  32. package/templates/scaffold/presets/showcase/app/routes/_renderer.tsx +31 -49
  33. package/templates/scaffold/presets/showcase/app/routes/index.tsx +19 -25
  34. package/templates/scaffold/presets/showcase/app/style.css +27 -42
  35. package/templates/scaffold/presets/showcase/content/Daily/2026-09-28.md +8 -0
  36. package/templates/scaffold/presets/showcase/content/Daily/2026-09-30.md +8 -0
  37. package/templates/scaffold/presets/showcase/content/Daily/2026-10-02.md +11 -0
  38. package/templates/scaffold/presets/showcase/content/index.de.md +16 -5
  39. package/templates/scaffold/presets/showcase/content/index.en.md +16 -5
  40. package/templates/scaffold/presets/showcase/content/index.es.md +16 -5
  41. package/templates/scaffold/presets/showcase/content/index.fr.md +16 -5
  42. package/templates/scaffold/presets/showcase/content/index.ja.md +16 -5
  43. package/templates/scaffold/presets/showcase/content/index.ko.md +16 -5
  44. package/templates/scaffold/presets/showcase/content/index.zh-CN.md +16 -5
  45. package/templates/scaffold/presets/starter/app/components/article.tsx +31 -40
  46. package/templates/scaffold/presets/starter/app/components/site-header.tsx +10 -64
  47. package/templates/scaffold/presets/starter/app/routes/[slug{.+}].tsx +15 -34
  48. package/templates/scaffold/presets/starter/app/routes/_404.tsx +18 -0
  49. package/templates/scaffold/presets/starter/app/routes/_renderer.tsx +31 -49
  50. package/templates/scaffold/presets/starter/app/routes/index.tsx +17 -25
  51. package/templates/scaffold/presets/starter/app/style.css +27 -42
  52. package/templates/scaffold/utilities/biome/biome.json +22 -0
  53. package/templates/scaffold/utilities/editorconfig/.editorconfig +12 -0
  54. package/templates/scaffold/utilities/gitattributes/.gitattributes +5 -0
  55. package/templates/scaffold/utilities/vscode/.vscode/settings.json +6 -0
  56. package/templates/scaffold/base/app/config.ts +0 -18
  57. package/templates/scaffold/base/app/constants/paths.ts +0 -10
  58. package/templates/scaffold/base/app/content.ts +0 -12
@@ -633,7 +633,7 @@ var minimalTheme = {
633
633
  };
634
634
  var empty = {
635
635
  name: "empty",
636
- description: "A blank application shell: no plugins, no theme, no content, no components.",
636
+ description: "A blank canvas with only the Riebeckite wiring. Add the theme, plugins, and content yourself.",
637
637
  languages: [],
638
638
  theme: null,
639
639
  plugins: [],
@@ -642,7 +642,7 @@ var empty = {
642
642
  };
643
643
  var minimal = {
644
644
  name: "minimal",
645
- description: "The smallest useful site: Obsidian Markdown, the minimal theme, and one page.",
645
+ description: "The smallest readable site, for learning how a Riebeckite site is assembled.",
646
646
  languages: ["en"],
647
647
  theme: minimalTheme,
648
648
  plugins: [obsidianMarkdown],
@@ -651,7 +651,7 @@ var minimal = {
651
651
  };
652
652
  var starter = {
653
653
  name: "starter",
654
- description: "Recommended for most sites: a practical Markdown garden with search, discovery, and reading essentials.",
654
+ description: "Recommended default: a practical Markdown garden with search, navigation, and reading essentials.",
655
655
  languages: [...SCAFFOLD_LANGUAGES],
656
656
  theme: defaultTheme,
657
657
  plugins: [
@@ -679,7 +679,7 @@ var starter = {
679
679
  };
680
680
  var showcase = {
681
681
  name: "showcase",
682
- description: "Explore the complete Riebeckite ecosystem with rendered examples, reference pages, and local fixtures.",
682
+ description: "A feature-rich example that demonstrates the Riebeckite plugin ecosystem with rendered samples and references.",
683
683
  languages: [...SCAFFOLD_LANGUAGES],
684
684
  theme: showCaseTheme,
685
685
  plugins: [
@@ -776,8 +776,8 @@ function resolveScaffoldPreset(value) {
776
776
 
777
777
  // src/scaffold/content-pages.ts
778
778
  var HELPERS = {
779
- en: "https://github.com/Rerurate514/riebeckite/blob/main/docs/README.en.md",
780
- ja: "https://github.com/Rerurate514/riebeckite/blob/main/docs/README.md"
779
+ en: "https://github.com/Rerurate514/riebeckite/blob/main/docs/README.md",
780
+ ja: "https://github.com/Rerurate514/riebeckite/blob/main/docs/README.ja.md"
781
781
  };
782
782
  var PLUGIN_INDEX_URL = "https://github.com/Rerurate514/riebeckite/tree/main/packages/plugins";
783
783
  var THEMES_INDEX_URL = "https://github.com/Rerurate514/riebeckite/tree/main/packages/themes";
@@ -936,7 +936,7 @@ var PLUGIN_MARKDOWN_GUIDES = {
936
936
  },
937
937
  "@riebeckite/plugin-shortcodes": {
938
938
  summary: "Expands built-in shortcode syntax inside Markdown.",
939
- markdown: '{{< youtube dQw4w9WgXcQ >}}\n\n{{< figure src="/images/demo.png" caption="Demo image" >}}'
939
+ markdown: '::youtube[id=dQw4w9WgXcQ]\n\n::figure[Demo image]{src="/images/demo.png"}'
940
940
  },
941
941
  "@riebeckite/plugin-series": {
942
942
  summary: "Groups Markdown pages into a reading series using frontmatter.",
@@ -2175,8 +2175,91 @@ function referenceThemesContent(preset) {
2175
2175
  return lines.join("\n");
2176
2176
  }
2177
2177
 
2178
+ // src/scaffold/utilities.ts
2179
+ var SCAFFOLD_UTILITY_NAMES = [
2180
+ "editorconfig",
2181
+ "gitattributes",
2182
+ "biome",
2183
+ "npmrc",
2184
+ "vscode"
2185
+ ];
2186
+ var SCAFFOLD_UTILITIES = [
2187
+ {
2188
+ name: "editorconfig",
2189
+ label: ".editorconfig",
2190
+ description: "Shared editor indentation, newline, and encoding defaults."
2191
+ },
2192
+ {
2193
+ name: "gitattributes",
2194
+ label: ".gitattributes",
2195
+ description: "Line-ending normalization and text detection for Git."
2196
+ },
2197
+ {
2198
+ name: "biome",
2199
+ label: "biome.json",
2200
+ description: "Biome formatter and linter configuration."
2201
+ },
2202
+ {
2203
+ name: "npmrc",
2204
+ label: ".npmrc",
2205
+ description: "npm settings such as exact dependency versions."
2206
+ },
2207
+ {
2208
+ name: "vscode",
2209
+ label: ".vscode/settings.json",
2210
+ description: "Recommended VS Code workspace settings."
2211
+ }
2212
+ ];
2213
+ var SCAFFOLD_DEFAULT_UTILITIES = [
2214
+ "editorconfig",
2215
+ "gitattributes",
2216
+ "biome"
2217
+ ];
2218
+ var SCAFFOLD_NO_UTILITIES = "none";
2219
+ function isScaffoldUtilityName(value) {
2220
+ return SCAFFOLD_UTILITY_NAMES.includes(value);
2221
+ }
2222
+ function parseScaffoldUtilities(value) {
2223
+ const tokens = value.split(",").map((token) => token.trim()).filter((token) => token.length > 0);
2224
+ if (tokens.length === 0) {
2225
+ throw new Error(
2226
+ "--utilities requires a comma-separated list of utility names."
2227
+ );
2228
+ }
2229
+ if (tokens.length === 1 && tokens[0] === SCAFFOLD_NO_UTILITIES) {
2230
+ return [];
2231
+ }
2232
+ const utilities = [];
2233
+ for (const token of tokens) {
2234
+ if (token === SCAFFOLD_NO_UTILITIES) {
2235
+ throw new Error(
2236
+ `"${SCAFFOLD_NO_UTILITIES}" cannot be combined with other utility names.`
2237
+ );
2238
+ }
2239
+ if (!isScaffoldUtilityName(token)) {
2240
+ throw new Error(
2241
+ `Unknown utility: ${token}. Available utilities: ${SCAFFOLD_UTILITY_NAMES.join(", ")}, ${SCAFFOLD_NO_UTILITIES}.`
2242
+ );
2243
+ }
2244
+ if (!utilities.includes(token)) utilities.push(token);
2245
+ }
2246
+ return utilities;
2247
+ }
2248
+ function utilityTemplateFiles(utilities) {
2249
+ const seen = /* @__PURE__ */ new Set();
2250
+ const files = [];
2251
+ for (const name of utilities) {
2252
+ for (const file of copyTemplateTree(`utilities/${name}`)) {
2253
+ if (seen.has(file.path)) continue;
2254
+ seen.add(file.path);
2255
+ files.push(file);
2256
+ }
2257
+ }
2258
+ return files;
2259
+ }
2260
+
2178
2261
  // src/scaffold/version.ts
2179
- var RIEBECKITE_VERSION = "^0.0.18";
2262
+ var RIEBECKITE_VERSION = "^0.0.20";
2180
2263
 
2181
2264
  // src/scaffold/templates.ts
2182
2265
  function siteTemplateFiles(preset, variables, options = {}) {
@@ -2187,6 +2270,7 @@ function siteTemplateFiles(preset, variables, options = {}) {
2187
2270
  content: riebeckiteConfig(preset, variables)
2188
2271
  },
2189
2272
  ...copyTemplateTree("base"),
2273
+ ...utilityTemplateFiles(options.utilities ?? SCAFFOLD_DEFAULT_UTILITIES),
2190
2274
  ...copyTemplateTree(
2191
2275
  `presets/${preset.name}`,
2192
2276
  {},
@@ -2329,16 +2413,16 @@ var README_INTRO = {
2329
2413
  ja: "空の Riebeckite アプリケーションシェルです。テーマもプラグインもコンポーネントもコンテンツもなく、すべてを自由に追加できます。"
2330
2414
  },
2331
2415
  minimal: {
2332
- en: "The smallest useful Riebeckite site: Obsidian Markdown, the minimal theme, and a single page.",
2333
- ja: "最小限で実用的な Riebeckite サイトです。Obsidian マークダウン・minimal テーマ・1 ページ構成。"
2416
+ en: "The smallest readable Riebeckite site: Obsidian Markdown, the minimal theme, and a single page you can read end to end.",
2417
+ ja: "最小で読みやすい Riebeckite サイトです。Obsidian マークダウン・minimal テーマ・1 ページだけで、サイトの組み立て方を学べます。"
2334
2418
  },
2335
2419
  starter: {
2336
- en: "Recommended for most sites: a practical Markdown garden with search, discovery, and reading essentials.",
2337
- ja: "大半のサイトにおすすめの構成です。検索・発見・閲覧に必要な機能を備えた実用的な Markdown サイトを作れます。"
2420
+ en: "Recommended default: a practical Markdown garden with search, navigation, and reading essentials.",
2421
+ ja: "大半のサイトにおすすめの既定構成です。検索・ナビゲーション・閲覧に必要な機能を備えた実用的な Markdown サイトを作れます。"
2338
2422
  },
2339
2423
  showcase: {
2340
- en: "Explore the complete Riebeckite ecosystem with rendered examples, reference pages, and local fixtures.",
2341
- ja: "描画例・リファレンスページ・ローカルのフィクスチャで、Riebeckite のエコシステム全体を確認できる構成です。"
2424
+ en: "A feature-rich example that demonstrates the Riebeckite plugin ecosystem with rendered samples, reference pages, and local fixtures.",
2425
+ ja: "Riebeckite の Plugin エコシステムを実際に確認できる機能紹介用の構成です。描画例・リファレンスページ・ローカルのフィクスチャを含みます。"
2342
2426
  }
2343
2427
  };
2344
2428
  var README_WORDS = {
@@ -2357,7 +2441,7 @@ var README_WORDS = {
2357
2441
  noPlugins: "no plugins",
2358
2442
  single: "single language",
2359
2443
  configReference: "Configuration reference",
2360
- configReferenceBody: "`riebeckite.config.ts` already registers every plugin below with its full option set — the file doubles as the settings reference. Every option is documented in the plugin's package README.",
2444
+ configReferenceBody: "`riebeckite.config.ts` registers every plugin below with its full option set. Treat it as a starting point; the documented options live in the [configuration reference](https://riebeckite.dev/docs/reference/configuration-reference) and each plugin's package README.",
2361
2445
  factory: "Factory",
2362
2446
  options: "Options",
2363
2447
  emDash: "—",
@@ -2381,7 +2465,7 @@ var README_WORDS = {
2381
2465
  noPlugins: "プラグインなし",
2382
2466
  single: "単一言語",
2383
2467
  configReference: "設定リファレンス",
2384
- configReferenceBody: "`riebeckite.config.ts` には、以下の全プラグインがあらかじめ全オプション付きで登録されています。このファイル自体を設定リファレンスとして利用できます。各オプションの詳しい説明はプラグインパッケージの README を参照してください。",
2468
+ configReferenceBody: "`riebeckite.config.ts` には、以下の全プラグインが全オプション付きで登録されています。これは出発点として使い、設定の仕様は[設定リファレンス](https://riebeckite.dev/docs/reference/configuration-reference)と各プラグインパッケージの README を確認してください。",
2385
2469
  factory: "ファクトリ",
2386
2470
  options: "オプション",
2387
2471
  emDash: "—",
@@ -2449,8 +2533,8 @@ function readmeEn(preset, variables) {
2449
2533
  lines.push(`## ${words.extending}`, "");
2450
2534
  lines.push(words.extendingBody, "");
2451
2535
  lines.push(
2452
- `- Docs: [English](${REPO}/blob/main/docs/README.en.md)`,
2453
- ` · [日本語](${REPO}/blob/main/docs/README.md)`,
2536
+ `- Docs: [English](${REPO}/blob/main/docs/README.md)`,
2537
+ ` · [日本語](${REPO}/blob/main/docs/README.ja.md)`,
2454
2538
  ""
2455
2539
  );
2456
2540
  }
@@ -2510,8 +2594,8 @@ function readmeJa(preset, variables) {
2510
2594
  lines.push(`## ${words.extending}`, "");
2511
2595
  lines.push(words.extendingBody, "");
2512
2596
  lines.push(
2513
- `- ドキュメント: [English](${REPO}/blob/main/docs/README.en.md)`,
2514
- ` · [日本語](${REPO}/blob/main/docs/README.md)`,
2597
+ `- ドキュメント: [English](${REPO}/blob/main/docs/README.md)`,
2598
+ ` · [日本語](${REPO}/blob/main/docs/README.ja.md)`,
2515
2599
  ""
2516
2600
  );
2517
2601
  }
@@ -2541,7 +2625,7 @@ function deploymentSecretLines(language) {
2541
2625
  `- \`${GITHUB_ACTIONS_SECRETS.SITE_DISPATCH_TOKEN}\` — in the **content repository**. Lets its \`notify-site.yml\` dispatch updates to this site. Use a fine-grained token scoped to this site repository with **Contents: read and write**.`,
2542
2626
  `- \`${GITHUB_ACTIONS_SECRETS.CLOUDFLARE_API_TOKEN}\` and \`${GITHUB_ACTIONS_SECRETS.CLOUDFLARE_ACCOUNT_ID}\` — in **this site repository** for the Cloudflare deploy.`,
2543
2627
  "",
2544
- `The workflows reference these secret names and never contain their values. Never commit the values. See the [separate content repository guide](${REPO}/blob/main/docs/docs/guides/deployment/separate-content-repository.en.md) for the full setup.`,
2628
+ `The workflows reference these secret names and never contain their values. Never commit the values. See the [separate content repository guide](${REPO}/blob/main/docs/docs/guides/deployment/separate-content-repository.md) for the full setup.`,
2545
2629
  ""
2546
2630
  ];
2547
2631
  }
@@ -2784,15 +2868,15 @@ var README_DEMOS = {
2784
2868
  " - title: Default",
2785
2869
  " description: A clean, typographic theme.",
2786
2870
  " meta: v0.0.5",
2787
- " href: https://example.com/themes/default/",
2871
+ " href: https://riebeckite.dev/docs/themes/default",
2788
2872
  " - title: Minimal",
2789
2873
  " description: Stripped back to the essentials.",
2790
2874
  " meta: v0.0.5",
2791
- " href: https://example.com/themes/minimal/",
2875
+ " href: https://riebeckite.dev/docs/themes/minimal",
2792
2876
  " - title: Gruvbox",
2793
2877
  " description: A warm, high-contrast palette.",
2794
2878
  " meta: v0.0.5",
2795
- " href: https://example.com/themes/gruvbox/"
2879
+ " href: https://riebeckite.dev/docs/themes/gruvbox"
2796
2880
  ].join("\n")
2797
2881
  )
2798
2882
  },
@@ -3044,7 +3128,8 @@ async function scaffoldRiebeckiteSite(options) {
3044
3128
  }
3045
3129
  const files = [
3046
3130
  ...siteTemplateFiles(preset, templateVariables(options, targetDirectory), {
3047
- cloudflareWorkers: deployment.type === "cloudflare-workers"
3131
+ cloudflareWorkers: deployment.type === "cloudflare-workers",
3132
+ utilities: options.utilities
3048
3133
  }),
3049
3134
  ...deploymentTemplateOrConfig(deployment, targetDirectory)
3050
3135
  ];
@@ -3123,11 +3208,16 @@ function isNotFoundError(error) {
3123
3208
  export {
3124
3209
  GITHUB_ACTIONS_SECRETS,
3125
3210
  SCAFFOLD_DEFAULT_PRESET,
3211
+ SCAFFOLD_DEFAULT_UTILITIES,
3126
3212
  SCAFFOLD_PRESETS,
3213
+ SCAFFOLD_UTILITIES,
3214
+ SCAFFOLD_UTILITY_NAMES,
3127
3215
  ScaffoldSiteError,
3128
3216
  deploymentWorkflow,
3129
3217
  formatScaffoldNextSteps,
3130
3218
  isScaffoldPresetName,
3219
+ isScaffoldUtilityName,
3220
+ parseScaffoldUtilities,
3131
3221
  scaffoldDeploymentFromFlags,
3132
3222
  scaffoldRiebeckiteSite,
3133
3223
  wranglerConfigForDirectory
@@ -1,4 +1,5 @@
1
1
  import type { ScaffoldPresetName } from "./presets.js";
2
+ import type { ScaffoldUtilityName } from "./utilities.js";
2
3
  export type ScaffoldSiteMetadata = {
3
4
  readonly title?: string;
4
5
  readonly description?: string;
@@ -25,6 +26,7 @@ export type ScaffoldSiteOptions = {
25
26
  readonly name?: string;
26
27
  readonly site?: ScaffoldSiteMetadata;
27
28
  readonly preset?: ScaffoldPresetName;
29
+ readonly utilities?: readonly ScaffoldUtilityName[];
28
30
  readonly deployment?: ScaffoldDeployment;
29
31
  readonly overwrite?: boolean;
30
32
  };
@@ -1,4 +1,5 @@
1
1
  import { type ScaffoldOptionContext, type ScaffoldOptions, type ScaffoldPreset } from "./presets.js";
2
+ import { type ScaffoldUtilityName } from "./utilities.js";
2
3
  export type SiteTemplateVariables = {
3
4
  readonly name: string;
4
5
  readonly title: string;
@@ -9,6 +10,7 @@ export type SiteTemplateVariables = {
9
10
  };
10
11
  export type SiteTemplateOptions = {
11
12
  readonly cloudflareWorkers?: boolean;
13
+ readonly utilities?: readonly ScaffoldUtilityName[];
12
14
  };
13
15
  export type SiteTemplateFile = {
14
16
  readonly path: string;
@@ -0,0 +1,14 @@
1
+ import type { SiteTemplateFile } from "./templates.js";
2
+ export declare const SCAFFOLD_UTILITY_NAMES: readonly ["editorconfig", "gitattributes", "biome", "npmrc", "vscode"];
3
+ export type ScaffoldUtilityName = (typeof SCAFFOLD_UTILITY_NAMES)[number];
4
+ export type ScaffoldUtilitySummary = {
5
+ readonly name: ScaffoldUtilityName;
6
+ readonly label: string;
7
+ readonly description: string;
8
+ };
9
+ export declare const SCAFFOLD_UTILITIES: readonly ScaffoldUtilitySummary[];
10
+ export declare const SCAFFOLD_DEFAULT_UTILITIES: readonly ScaffoldUtilityName[];
11
+ export declare const SCAFFOLD_NO_UTILITIES = "none";
12
+ export declare function isScaffoldUtilityName(value: string): value is ScaffoldUtilityName;
13
+ export declare function parseScaffoldUtilities(value: string): readonly ScaffoldUtilityName[];
14
+ export declare function utilityTemplateFiles(utilities: readonly ScaffoldUtilityName[]): readonly SiteTemplateFile[];
@@ -1 +1 @@
1
- export declare const RIEBECKITE_VERSION = "^0.0.18";
1
+ export declare const RIEBECKITE_VERSION = "^0.0.20";
@@ -37,7 +37,7 @@ export declare const PACKAGE_MANAGER: "npm";
37
37
  /** Lockfile name that must be committed */
38
38
  export declare const LOCKFILE_NAME: "package-lock.json";
39
39
  /** Files/directories that must be in .gitignore */
40
- export declare const GITIGNORE_REQUIRED: readonly ["node_modules/", "dist/", ".riebeckite/", "app/.riebeckite/"];
40
+ export declare const GITIGNORE_REQUIRED: readonly ["node_modules/", "dist/", ".riebeckite/", "app/.riebeckite/", ".wrangler/", ".dev.vars"];
41
41
  /** Files that must NOT be in .gitignore */
42
42
  export declare const GITIGNORE_FORBIDDEN: readonly ["package-lock.json"];
43
43
  /** Starter preset content pages (base names without language suffixes) */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-riebeckite",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "devDependencies": {
41
41
  "esbuild": "^0.28.2",
42
- "@riebeckite/test": "0.0.18"
42
+ "@riebeckite/test": "0.0.20"
43
43
  },
44
44
  "repository": {
45
45
  "type": "git",
@@ -1,13 +1,19 @@
1
- import type { PluginHeadTag } from "@riebeckite/core";
2
-
3
1
  declare module "virtual:riebeckite/client" {
4
2
  export function initRiebeckiteClient(): void;
5
3
  }
6
4
 
5
+ declare module "virtual:riebeckite/config" {
6
+ export const config: import("@riebeckite/core").ResolvedRiebeckiteConfig;
7
+ }
8
+
9
+ declare module "virtual:riebeckite/content" {
10
+ export const content: import("@riebeckite/core").ContentManager;
11
+ }
12
+
7
13
  declare module "hono" {
8
14
  interface Env {
9
15
  Variables: {
10
- headTags?: readonly PluginHeadTag[];
16
+ headTags?: readonly import("@riebeckite/core").PluginHeadTag[];
11
17
  htmlLanguage?: string;
12
18
  };
13
19
  Bindings: Record<string, never>;
@@ -1,7 +1,7 @@
1
1
  import { mountRiebeckiteEndpoints } from "@riebeckite/honox/server";
2
2
  import { createApp } from "honox/server";
3
- import { config } from "./config";
4
- import { content } from "./content";
3
+ import { config } from "virtual:riebeckite/config";
4
+ import { content } from "virtual:riebeckite/content";
5
5
 
6
6
  const app = createApp({
7
7
  init: (app) => {
@@ -1,34 +1,12 @@
1
- import path from "node:path";
2
- import { fileURLToPath } from "node:url";
3
1
  import build from "@hono/vite-build/node";
4
- import {
5
- defaultSsrExternals,
6
- riebeckite,
7
- riebeckiteSsg,
8
- riebeckiteSsgExtensionMap,
9
- } from "@riebeckite/honox";
2
+ import { riebeckiteVite } from "@riebeckite/honox";
10
3
  import honox from "honox/vite";
11
4
  import { defineConfig } from "vite";
12
5
 
13
- const appRoot = fileURLToPath(new URL(".", import.meta.url));
14
-
15
6
  export default defineConfig({
16
7
  plugins: [
17
- honox({
18
- client: { input: ["/app/client.ts", "/app/style.css"] },
19
- }),
20
- riebeckite({ appRoot }),
8
+ honox({ client: { input: ["/app/client.ts", "/app/style.css"] } }),
9
+ ...riebeckiteVite(),
21
10
  build(),
22
- riebeckiteSsg({
23
- entry: path.join(appRoot, "app/server.ts"),
24
- extensionMap: riebeckiteSsgExtensionMap(),
25
- }),
26
11
  ],
27
- environments: {
28
- ssr: {
29
- resolve: {
30
- external: [...defaultSsrExternals],
31
- },
32
- },
33
- },
34
12
  });
@@ -0,0 +1,18 @@
1
+ import type { NotFoundHandler } from "hono";
2
+
3
+ const handler: NotFoundHandler = (c) => {
4
+ c.status(404);
5
+
6
+ return c.render(
7
+ <main class="not-found">
8
+ <p class="not-found__status">404</p>
9
+ <h1>Page not found</h1>
10
+ <p>The page you requested does not exist or is not available.</p>
11
+ <p>
12
+ <a href="/">Back to home</a>
13
+ </p>
14
+ </main>,
15
+ );
16
+ };
17
+
18
+ export default handler;
@@ -1,6 +1,6 @@
1
1
  import { jsxRenderer } from "hono/jsx-renderer";
2
2
  import { Link, Script } from "honox/server";
3
- import { config } from "../config";
3
+ import { config } from "virtual:riebeckite/config";
4
4
 
5
5
  // Riebeckite plugin client entries need the HonoX client bundle even without
6
6
  // an island component.
@@ -1,5 +1,5 @@
1
1
  import { createRoute } from "honox/factory";
2
- import { config } from "../config";
2
+ import { config } from "virtual:riebeckite/config";
3
3
 
4
4
  export default createRoute((c) =>
5
5
  c.render(
@@ -15,3 +15,14 @@ body {
15
15
  padding: 4rem 1rem;
16
16
  margin: 0 auto;
17
17
  }
18
+
19
+ .not-found {
20
+ max-width: 48rem;
21
+ padding: 4rem 1rem;
22
+ margin: 0 auto;
23
+ }
24
+
25
+ .not-found__status {
26
+ margin: 0;
27
+ font-weight: 700;
28
+ }
@@ -1,65 +1,47 @@
1
- import type { PostContent } from "@riebeckite/core";
2
- import { Article, ArticleContent, ArticleLayout } from "@riebeckite/honox/ui";
1
+ import type { ContentBodySlots, PostContent } from "@riebeckite/core";
2
+ import {
3
+ Article,
4
+ ArticleBody,
5
+ ArticleContent,
6
+ ArticleLayout,
7
+ ContentSlot,
8
+ } from "@riebeckite/honox/ui";
3
9
 
4
10
  export function SiteArticle({
5
11
  post,
6
12
  bodySlots,
7
13
  asideContent,
8
- afterContent,
9
- footerContent,
10
14
  }: {
11
15
  post: PostContent;
12
- bodySlots?: Readonly<Record<string, string>>;
16
+ bodySlots?: ContentBodySlots;
13
17
  asideContent?: unknown;
14
- afterContent?: unknown;
15
- footerContent?: unknown;
16
18
  }) {
17
19
  return (
18
20
  <Article class="site-article">
19
21
  <ArticleLayout>
20
22
  {asideContent}
21
- {bodySlots?.["article.aside"] ? (
22
- <div
23
- class="site-article__aside"
24
- dangerouslySetInnerHTML={{ __html: bodySlots["article.aside"] }}
25
- />
26
- ) : null}
23
+
24
+ <ContentSlot
25
+ slots={bodySlots}
26
+ name="article.aside"
27
+ class="site-article__aside"
28
+ />
29
+
27
30
  <ArticleContent>
28
- {bodySlots?.["article.header"] ? (
29
- <div
30
- class="site-article__header"
31
- dangerouslySetInnerHTML={{ __html: bodySlots["article.header"] }}
32
- />
33
- ) : null}
34
- {bodySlots?.["article.metadata"] ? (
35
- <div
36
- class="site-article__metadata"
37
- dangerouslySetInnerHTML={{ __html: bodySlots["article.metadata"] }}
38
- />
39
- ) : null}
40
- {bodySlots?.["article.before-content"] ? (
41
- <div
42
- class="site-article__before-content"
43
- dangerouslySetInnerHTML={{ __html: bodySlots["article.before-content"] }}
44
- />
45
- ) : null}
46
- <div dangerouslySetInnerHTML={{ __html: post.html ?? "" }} />
47
- {afterContent}
48
- {bodySlots?.["article.after-content"] ? (
49
- <div
50
- class="site-article__after-content"
51
- dangerouslySetInnerHTML={{ __html: bodySlots["article.after-content"] }}
52
- />
53
- ) : null}
31
+ <ContentSlot slots={bodySlots} name="article.header" />
32
+ <ContentSlot slots={bodySlots} name="article.metadata" />
33
+ <ContentSlot slots={bodySlots} name="article.before-content" />
34
+
35
+ <ArticleBody html={post.html ?? ""} />
36
+
37
+ <ContentSlot slots={bodySlots} name="article.after-content" />
54
38
  </ArticleContent>
55
- {bodySlots?.["article.footer"] || footerContent ? (
56
- <div class="site-article__footer">
57
- {bodySlots?.["article.footer"] ? (
58
- <div dangerouslySetInnerHTML={{ __html: bodySlots["article.footer"] }} />
59
- ) : null}
60
- {footerContent}
61
- </div>
62
- ) : null}
39
+
40
+ <ContentSlot
41
+ slots={bodySlots}
42
+ name="article.footer"
43
+ class="site-article__footer"
44
+ />
63
45
  </ArticleLayout>
64
46
  </Article>
65
47
  );
@@ -1,48 +1,29 @@
1
- import { getEntryLanguage } from "@riebeckite/core";
2
1
  import {
3
2
  contentRouteSsgParams,
4
- pluginPageSsgParams,
5
- resolveRiebeckiteRoute,
3
+ resolveRiebeckiteContentRequest,
4
+ riebeckiteSsgParams,
6
5
  } from "@riebeckite/honox/server";
6
+ import { PageBody } from "@riebeckite/honox/ui";
7
7
  import { createRoute } from "honox/factory";
8
8
  import { SiteArticle } from "../components/article";
9
- import { content } from "../content";
9
+ import { content } from "virtual:riebeckite/content";
10
10
 
11
11
  export default createRoute(
12
- contentRouteSsgParams("/:slug{.+}", async () => {
13
- const manifest = await content.getManifest();
14
- const contentPaths = manifest.publicEntries
15
- .filter((entry) => entry.permalink !== "/")
16
- .map((entry) => ({ slug: entry.permalink.replace(/^\/+/, "") }));
17
- return [...contentPaths, ...(await pluginPageSsgParams(content))];
18
- }),
12
+ contentRouteSsgParams("/:slug{.+}", () => riebeckiteSsgParams(content)),
19
13
  async (c) => {
20
- const requestedSlug = c.req.param("slug");
21
- if (!requestedSlug) return c.notFound();
22
- if (/\.[a-zA-Z0-9]+$/.test(requestedSlug)) return c.notFound();
14
+ const resolved = await resolveRiebeckiteContentRequest(c, content);
23
15
 
24
- const route = await resolveRiebeckiteRoute(content, c.req.path);
25
- if (!route) return c.notFound();
26
- if (route.kind === "redirect")
27
- return c.redirect(route.location, route.status);
28
- if (route.kind === "page") {
29
- c.set("headTags", route.page.headTags ?? []);
30
- c.set("htmlLanguage", route.page.language);
31
- return c.render(
32
- <div dangerouslySetInnerHTML={{ __html: route.page.body }} />,
33
- );
34
- }
35
-
36
- const post = await content.getProcessedContent(route.entry.slug);
16
+ if (resolved.kind === "response") return resolved.response;
37
17
 
38
- c.set("htmlLanguage", getEntryLanguage(route.entry));
39
- c.set("headTags", route.entry.headTags ?? []);
18
+ if (resolved.kind === "page") {
19
+ return c.render(<PageBody html={resolved.page.body} />);
20
+ }
40
21
 
41
22
  return c.render(
42
23
  <SiteArticle
43
- post={post}
44
- bodySlots={route.entry.bodySlots}
24
+ post={resolved.post}
25
+ bodySlots={resolved.entry.bodySlots}
45
26
  />,
46
27
  );
47
28
  },
48
- );
29
+ );
@@ -0,0 +1,18 @@
1
+ import type { NotFoundHandler } from "hono";
2
+
3
+ const handler: NotFoundHandler = (c) => {
4
+ c.status(404);
5
+
6
+ return c.render(
7
+ <main class="not-found">
8
+ <p class="not-found__status">404</p>
9
+ <h1>Page not found</h1>
10
+ <p>The page you requested does not exist or is not available.</p>
11
+ <p>
12
+ <a href="/">Back to home</a>
13
+ </p>
14
+ </main>,
15
+ );
16
+ };
17
+
18
+ export default handler;