create-riebeckite 0.0.18 → 0.0.19

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 CHANGED
@@ -7,7 +7,7 @@ Create a new Riebeckite site from an official starter preset.
7
7
  ## Usage
8
8
 
9
9
  Interactive (recommended): run without arguments and answer the prompts for
10
- the project name, preset, content source, and deployment.
10
+ the project name, preset, project files, content source, and deployment.
11
11
 
12
12
  ```sh
13
13
  npx create-riebeckite
@@ -30,6 +30,7 @@ The prompts ask, in order:
30
30
  | --- | --- | --- |
31
31
  | Project name | the folder to create (empty input uses the default name) | any name, e.g. `my-site` |
32
32
  | Preset | `starter`, `minimal`, `showcase`, `empty` | `starter` for most sites |
33
+ | Project files | `.editorconfig`, `.gitattributes`, `biome.json`, `.npmrc`, `.vscode/settings.json` | the recommended set is pre-selected |
33
34
  | Content source | `This project`, `Separate GitHub repository` | `This project` to start |
34
35
  | Deployment | `GitHub Actions + Cloudflare Workers`, `Not now` | `Not now` for local development |
35
36
 
@@ -45,6 +46,7 @@ Deployment can be added later, described in
45
46
  | --- | --- |
46
47
  | `[directory]` | Directory to scaffold into (default: the current directory) |
47
48
  | `--preset <name>` | Starter composition, e.g. `showcase` (default: `starter`) |
49
+ | `--utilities <names>` | Comma-separated project files to generate: `editorconfig`, `gitattributes`, `biome`, `npmrc`, `vscode`, or `none` (default: `editorconfig,gitattributes,biome`) |
48
50
  | `--force` | Scaffold even when the target directory is not empty |
49
51
  | `--list-presets` | Print the available presets and their descriptions, then exit |
50
52
  | `--github-actions` | Generate the Cloudflare deployment workflow |
@@ -57,6 +59,27 @@ For example, scaffold the complete feature tour:
57
59
  npx create-riebeckite my-site --preset showcase
58
60
  ```
59
61
 
62
+ ## Project files
63
+
64
+ Alongside the preset, `create-riebeckite` writes optional project files. In
65
+ interactive mode the `Extra project files` prompt pre-selects the recommended
66
+ set; toggle any of them there. Non-interactive runs select them with a
67
+ comma-separated `--utilities` value.
68
+
69
+ | Name | File | Default |
70
+ | --- | --- | --- |
71
+ | `editorconfig` | `.editorconfig` | yes |
72
+ | `gitattributes` | `.gitattributes` | yes |
73
+ | `biome` | `biome.json` | yes |
74
+ | `npmrc` | `.npmrc` | no |
75
+ | `vscode` | `.vscode/settings.json` | no |
76
+
77
+ Pass `none` to write no project files, or list the ones you want:
78
+
79
+ ```sh
80
+ npx create-riebeckite my-site --utilities editorconfig,npmrc,vscode
81
+ ```
82
+
60
83
  ## External content repository
61
84
 
62
85
  To use a separate content repository and deploy after its `main` branch is
package/README_ja.md CHANGED
@@ -8,7 +8,7 @@ CLI ツールです。
8
8
  ## 使い方
9
9
 
10
10
  対話モード(推奨): 引数なしで実行すると、プロジェクト名・preset・
11
- コンテンツの格納場所・デプロイについて順に確認します。
11
+ プロジェクトファイル・コンテンツの格納場所・デプロイについて順に確認します。
12
12
 
13
13
  ```sh
14
14
  npx create-riebeckite
@@ -31,6 +31,7 @@ npm exec riebeckite build
31
31
  | --- | --- | --- |
32
32
  | Project name | 作るフォルダ名(空なら既定の名前) | 任意。例: `my-site` |
33
33
  | Preset | `starter`、`minimal`、`showcase`、`empty` | 大半のサイトは `starter` |
34
+ | Project files | `.editorconfig`、`.gitattributes`、`biome.json`、`.npmrc`、`.vscode/settings.json` | 推奨セットをあらかじめ選択 |
34
35
  | Content source | `This project`、`Separate GitHub repository` | 最初は `This project` |
35
36
  | デプロイ設定 | `GitHub Actions + Cloudflare Workers`、`Not now` | 手元で試すなら `Not now` |
36
37
 
@@ -42,6 +43,7 @@ npm exec riebeckite build
42
43
  | --- | --- |
43
44
  | `[directory]` | 生成先ディレクトリ(既定はカレントディレクトリ) |
44
45
  | `--preset <name>` | 使用するスターター構成(既定は `starter`) |
46
+ | `--utilities <names>` | 生成するプロジェクトファイルをカンマ区切りで指定する(`editorconfig`、`gitattributes`、`biome`、`npmrc`、`vscode`、または `none`。既定は `editorconfig,gitattributes,biome`) |
45
47
  | `--force` | 空でないディレクトリにも展開する |
46
48
  | `--list-presets` | 利用可能な preset と説明を一覧表示して終了する |
47
49
  | `--github-actions` | Cloudflare へのデプロイ workflow を生成する |
@@ -54,6 +56,28 @@ npm exec riebeckite build
54
56
  npx create-riebeckite my-site --preset showcase
55
57
  ```
56
58
 
59
+ ## Project files
60
+
61
+ preset とは別に、`create-riebeckite` は任意のプロジェクトファイルを生成します。
62
+ 対話モードでは `Extra project files` の質問で推奨セットがあらかじめ選択されて
63
+ いるので、そこから個別に切り替えられます。非対話で実行する場合は、
64
+ カンマ区切りの `--utilities` で選択します。
65
+
66
+ | 名前 | ファイル | 既定 |
67
+ | --- | --- | --- |
68
+ | `editorconfig` | `.editorconfig` | 生成する |
69
+ | `gitattributes` | `.gitattributes` | 生成する |
70
+ | `biome` | `biome.json` | 生成する |
71
+ | `npmrc` | `.npmrc` | 生成しない |
72
+ | `vscode` | `.vscode/settings.json` | 生成しない |
73
+
74
+ `none` を渡すとプロジェクトファイルを一切生成しません。個別に選ぶ場合は
75
+ 次のように指定します。
76
+
77
+ ```sh
78
+ npx create-riebeckite my-site --utilities editorconfig,npmrc,vscode
79
+ ```
80
+
57
81
  ## External content repository
58
82
 
59
83
  別の記事リポジトリを使い、その `main` への push でデプロイする場合は、共通の
@@ -1,9 +1,11 @@
1
1
  import type { ScaffoldDeployment } from "./scaffold/options.js";
2
2
  import { type ScaffoldPresetName } from "./scaffold/presets.js";
3
+ import { type ScaffoldUtilityName } from "./scaffold/utilities.js";
3
4
  export type CreateRiebeckiteOptions = {
4
5
  readonly directory: string;
5
6
  readonly force: boolean;
6
7
  readonly preset: ScaffoldPresetName;
8
+ readonly utilities: readonly ScaffoldUtilityName[];
7
9
  readonly listPresets: boolean;
8
10
  readonly deployment: ScaffoldDeployment;
9
11
  };
package/dist/src/index.js CHANGED
@@ -774,11 +774,95 @@ function resolveScaffoldPreset(value) {
774
774
  return preset;
775
775
  }
776
776
 
777
+ // src/scaffold/utilities.ts
778
+ var SCAFFOLD_UTILITY_NAMES = [
779
+ "editorconfig",
780
+ "gitattributes",
781
+ "biome",
782
+ "npmrc",
783
+ "vscode"
784
+ ];
785
+ var SCAFFOLD_UTILITIES = [
786
+ {
787
+ name: "editorconfig",
788
+ label: ".editorconfig",
789
+ description: "Shared editor indentation, newline, and encoding defaults."
790
+ },
791
+ {
792
+ name: "gitattributes",
793
+ label: ".gitattributes",
794
+ description: "Line-ending normalization and text detection for Git."
795
+ },
796
+ {
797
+ name: "biome",
798
+ label: "biome.json",
799
+ description: "Biome formatter and linter configuration."
800
+ },
801
+ {
802
+ name: "npmrc",
803
+ label: ".npmrc",
804
+ description: "npm settings such as exact dependency versions."
805
+ },
806
+ {
807
+ name: "vscode",
808
+ label: ".vscode/settings.json",
809
+ description: "Recommended VS Code workspace settings."
810
+ }
811
+ ];
812
+ var SCAFFOLD_DEFAULT_UTILITIES = [
813
+ "editorconfig",
814
+ "gitattributes",
815
+ "biome"
816
+ ];
817
+ var SCAFFOLD_NO_UTILITIES = "none";
818
+ function isScaffoldUtilityName(value) {
819
+ return SCAFFOLD_UTILITY_NAMES.includes(value);
820
+ }
821
+ function parseScaffoldUtilities(value) {
822
+ const tokens = value.split(",").map((token) => token.trim()).filter((token) => token.length > 0);
823
+ if (tokens.length === 0) {
824
+ throw new Error(
825
+ "--utilities requires a comma-separated list of utility names."
826
+ );
827
+ }
828
+ if (tokens.length === 1 && tokens[0] === SCAFFOLD_NO_UTILITIES) {
829
+ return [];
830
+ }
831
+ const utilities = [];
832
+ for (const token of tokens) {
833
+ if (token === SCAFFOLD_NO_UTILITIES) {
834
+ throw new Error(
835
+ `"${SCAFFOLD_NO_UTILITIES}" cannot be combined with other utility names.`
836
+ );
837
+ }
838
+ if (!isScaffoldUtilityName(token)) {
839
+ throw new Error(
840
+ `Unknown utility: ${token}. Available utilities: ${SCAFFOLD_UTILITY_NAMES.join(", ")}, ${SCAFFOLD_NO_UTILITIES}.`
841
+ );
842
+ }
843
+ if (!utilities.includes(token)) utilities.push(token);
844
+ }
845
+ return utilities;
846
+ }
847
+ function utilityTemplateFiles(utilities) {
848
+ const seen = /* @__PURE__ */ new Set();
849
+ const files = [];
850
+ for (const name of utilities) {
851
+ for (const file of copyTemplateTree(`utilities/${name}`)) {
852
+ if (seen.has(file.path)) continue;
853
+ seen.add(file.path);
854
+ files.push(file);
855
+ }
856
+ }
857
+ return files;
858
+ }
859
+
777
860
  // src/arguments.ts
778
861
  function parseArguments(arguments_) {
779
862
  let directory;
780
863
  let force = false;
781
864
  let preset;
865
+ let utilities;
782
866
  let listPresets = false;
783
867
  let githubActions = false;
784
868
  let contentRepository;
@@ -818,12 +902,23 @@ function parseArguments(arguments_) {
818
902
  index += 1;
819
903
  continue;
820
904
  }
905
+ if (argument === "--utilities") {
906
+ const value = arguments_[index + 1];
907
+ if (value === void 0 || value.startsWith("-")) {
908
+ throw new Error(
909
+ "--utilities requires a comma-separated list of utility names."
910
+ );
911
+ }
912
+ utilities = parseScaffoldUtilities(value);
913
+ index += 1;
914
+ continue;
915
+ }
821
916
  if (argument.startsWith("-")) {
822
917
  throw new Error(`Unknown option: ${argument}`);
823
918
  }
824
919
  if (directory !== void 0) {
825
920
  throw new Error(
826
- "Usage: create-riebeckite [directory] [--preset <name>] [--github-actions] [--content-repository <owner/repository>] [--site-repository <owner/repository>] [--force]"
921
+ "Usage: create-riebeckite [directory] [--preset <name>] [--utilities <names>] [--github-actions] [--content-repository <owner/repository>] [--site-repository <owner/repository>] [--force]"
827
922
  );
828
923
  }
829
924
  directory = argument;
@@ -832,6 +927,7 @@ function parseArguments(arguments_) {
832
927
  directory: directory ?? ".",
833
928
  force,
834
929
  preset: preset ?? "starter",
930
+ utilities: utilities ?? SCAFFOLD_DEFAULT_UTILITIES,
835
931
  listPresets,
836
932
  deployment: scaffoldDeploymentFromFlags({
837
933
  githubActions,
@@ -849,7 +945,7 @@ function printPresets() {
849
945
  }
850
946
 
851
947
  // src/interactive.ts
852
- import { isCancel, log, select, text } from "@clack/prompts";
948
+ import { isCancel, log, multiselect, select, text } from "@clack/prompts";
853
949
  var DEFAULT_DIRECTORY = "my-riebeckite-site";
854
950
  var DEFAULT_INTERACTIVE_DEPLOYMENT = "none";
855
951
  function interactiveAnswersToOptions(answers) {
@@ -857,6 +953,7 @@ function interactiveAnswersToOptions(answers) {
857
953
  directory: answers.directory,
858
954
  force: false,
859
955
  preset: answers.preset,
956
+ utilities: answers.utilities,
860
957
  listPresets: false,
861
958
  deployment: deploymentFromAnswers(answers)
862
959
  };
@@ -898,6 +995,17 @@ async function promptInteractiveAnswers() {
898
995
  }))
899
996
  });
900
997
  if (isCancel(preset)) return null;
998
+ const utilities = await multiselect({
999
+ message: "Extra project files",
1000
+ options: SCAFFOLD_UTILITIES.map(({ name, label, description }) => ({
1001
+ value: name,
1002
+ label,
1003
+ hint: description
1004
+ })),
1005
+ initialValues: [...SCAFFOLD_DEFAULT_UTILITIES],
1006
+ required: false
1007
+ });
1008
+ if (isCancel(utilities)) return null;
901
1009
  const contentSource = await select({
902
1010
  message: "Where will you write content?",
903
1011
  initialValue: "local",
@@ -925,6 +1033,7 @@ async function promptInteractiveAnswers() {
925
1033
  answers = {
926
1034
  directory,
927
1035
  preset,
1036
+ utilities,
928
1037
  contentSource,
929
1038
  contentRepository: contentRepository.trim(),
930
1039
  siteRepository: siteRepository.trim()
@@ -948,7 +1057,7 @@ async function promptInteractiveAnswers() {
948
1057
  ]
949
1058
  });
950
1059
  if (isCancel(deployment)) return null;
951
- answers = { directory, preset, contentSource, deployment };
1060
+ answers = { directory, preset, utilities, contentSource, deployment };
952
1061
  }
953
1062
  log.step("Creating Riebeckite site...");
954
1063
  return answers;
@@ -2480,7 +2589,7 @@ function referenceThemesContent(preset) {
2480
2589
  }
2481
2590
 
2482
2591
  // src/scaffold/version.ts
2483
- var RIEBECKITE_VERSION = "^0.0.18";
2592
+ var RIEBECKITE_VERSION = "^0.0.19";
2484
2593
 
2485
2594
  // src/scaffold/templates.ts
2486
2595
  function siteTemplateFiles(preset, variables, options = {}) {
@@ -2491,6 +2600,7 @@ function siteTemplateFiles(preset, variables, options = {}) {
2491
2600
  content: riebeckiteConfig(preset, variables)
2492
2601
  },
2493
2602
  ...copyTemplateTree("base"),
2603
+ ...utilityTemplateFiles(options.utilities ?? SCAFFOLD_DEFAULT_UTILITIES),
2494
2604
  ...copyTemplateTree(
2495
2605
  `presets/${preset.name}`,
2496
2606
  {},
@@ -3348,7 +3458,8 @@ async function scaffoldRiebeckiteSite(options) {
3348
3458
  }
3349
3459
  const files = [
3350
3460
  ...siteTemplateFiles(preset, templateVariables(options, targetDirectory), {
3351
- cloudflareWorkers: deployment.type === "cloudflare-workers"
3461
+ cloudflareWorkers: deployment.type === "cloudflare-workers",
3462
+ utilities: options.utilities
3352
3463
  }),
3353
3464
  ...deploymentTemplateOrConfig(deployment, targetDirectory)
3354
3465
  ];
@@ -3441,6 +3552,7 @@ async function runCreateRiebeckite(arguments_) {
3441
3552
  targetDirectory,
3442
3553
  overwrite: options.force,
3443
3554
  preset: options.preset,
3555
+ utilities: options.utilities,
3444
3556
  deployment: options.deployment
3445
3557
  });
3446
3558
  } catch (error) {
@@ -1,16 +1,19 @@
1
1
  import type { CreateRiebeckiteOptions } from "./arguments.js";
2
2
  import { type ScaffoldPresetName } from "./scaffold/presets.js";
3
+ import { type ScaffoldUtilityName } from "./scaffold/utilities.js";
3
4
  export declare const DEFAULT_INTERACTIVE_DEPLOYMENT: InteractiveDeployment;
4
5
  export type InteractiveContentSource = "local" | "external";
5
6
  export type InteractiveDeployment = "cloudflare" | "github-actions" | "none";
6
7
  export type InteractiveAnswers = {
7
8
  readonly directory: string;
8
9
  readonly preset: ScaffoldPresetName;
10
+ readonly utilities: readonly ScaffoldUtilityName[];
9
11
  readonly contentSource: "local";
10
12
  readonly deployment: InteractiveDeployment;
11
13
  } | {
12
14
  readonly directory: string;
13
15
  readonly preset: ScaffoldPresetName;
16
+ readonly utilities: readonly ScaffoldUtilityName[];
14
17
  readonly contentSource: "external";
15
18
  readonly contentRepository: string;
16
19
  readonly siteRepository: string;
@@ -3,5 +3,6 @@ export { deploymentWorkflow, scaffoldDeploymentFromFlags, } from "./deployment.j
3
3
  export { formatScaffoldNextSteps, type ScaffoldNextStepsOptions, } from "./next-steps.js";
4
4
  export { type ScaffoldContentSource, type ScaffoldDeployment, type ScaffoldDeploymentFlags, ScaffoldSiteError, type ScaffoldSiteMetadata, type ScaffoldSiteOptions, type ScaffoldSiteResult, } from "./options.js";
5
5
  export { isScaffoldPresetName, SCAFFOLD_DEFAULT_PRESET, SCAFFOLD_PRESETS, type ScaffoldPresetName, type ScaffoldPresetSummary, } from "./presets.js";
6
+ export { isScaffoldUtilityName, parseScaffoldUtilities, SCAFFOLD_DEFAULT_UTILITIES, SCAFFOLD_UTILITIES, SCAFFOLD_UTILITY_NAMES, type ScaffoldUtilityName, type ScaffoldUtilitySummary, } from "./utilities.js";
6
7
  export { GITHUB_ACTIONS_SECRETS, wranglerConfigForDirectory, } from "./wrangler-defaults.js";
7
8
  export declare function scaffoldRiebeckiteSite(options: ScaffoldSiteOptions): Promise<ScaffoldSiteResult>;
@@ -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.19";
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
  {},
@@ -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.19";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-riebeckite",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
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.19"
43
43
  },
44
44
  "repository": {
45
45
  "type": "git",
@@ -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
  );
@@ -32,10 +32,11 @@ body {
32
32
  display: grid;
33
33
  grid-template-columns: minmax(0, var(--rb-layout-article-max, 48rem));
34
34
  justify-content: center;
35
- gap: var(--rb-layout-gap, 2rem);
35
+ column-gap: var(--rb-layout-gap, 2rem);
36
36
  }
37
37
 
38
- .rb-article-body {
38
+ .rb-article-body,
39
+ .site-article__footer {
39
40
  min-width: 0;
40
41
  padding-inline: var(--rb-space-2, 1rem);
41
42
  }
@@ -44,10 +45,6 @@ body {
44
45
  display: none;
45
46
  }
46
47
 
47
- .site-article__footer {
48
- min-width: 0;
49
- }
50
-
51
48
  @media (min-width: 88rem) {
52
49
  :is(:root, .rb-theme-root)[data-article-layout="article"] .rb-article-layout {
53
50
  grid-template-columns: minmax(0, var(--rb-layout-article-max, 48rem));
@@ -1,5 +1,13 @@
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
+ ArticleFooter,
7
+ ArticleLayout,
8
+ ContentSlot,
9
+ hasSlot,
10
+ } from "@riebeckite/honox/ui";
3
11
 
4
12
  export function SiteArticle({
5
13
  post,
@@ -9,7 +17,7 @@ export function SiteArticle({
9
17
  footerContent,
10
18
  }: {
11
19
  post: PostContent;
12
- bodySlots?: Readonly<Record<string, string>>;
20
+ bodySlots?: ContentBodySlots;
13
21
  asideContent?: unknown;
14
22
  afterContent?: unknown;
15
23
  footerContent?: unknown;
@@ -18,47 +26,30 @@ export function SiteArticle({
18
26
  <Article class="site-article">
19
27
  <ArticleLayout>
20
28
  {asideContent}
21
- {bodySlots?.["article.aside"] ? (
22
- <div
23
- class="site-article__aside"
24
- dangerouslySetInnerHTML={{ __html: bodySlots["article.aside"] }}
25
- />
26
- ) : null}
29
+
30
+ <ContentSlot
31
+ slots={bodySlots}
32
+ name="article.aside"
33
+ class="site-article__aside"
34
+ />
35
+
27
36
  <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 ?? "" }} />
37
+ <ContentSlot slots={bodySlots} name="article.header" />
38
+ <ContentSlot slots={bodySlots} name="article.metadata" />
39
+ <ContentSlot slots={bodySlots} name="article.before-content" />
40
+
41
+ <ArticleBody html={post.html ?? ""} />
42
+
47
43
  {afterContent}
48
- {bodySlots?.["article.after-content"] ? (
49
- <div
50
- class="site-article__after-content"
51
- dangerouslySetInnerHTML={{ __html: bodySlots["article.after-content"] }}
52
- />
53
- ) : null}
44
+
45
+ <ContentSlot slots={bodySlots} name="article.after-content" />
54
46
  </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}
47
+
48
+ {hasSlot(bodySlots, "article.footer") || footerContent ? (
49
+ <ArticleFooter class="site-article__footer">
50
+ <ContentSlot slots={bodySlots} name="article.footer" />
60
51
  {footerContent}
61
- </div>
52
+ </ArticleFooter>
62
53
  ) : null}
63
54
  </ArticleLayout>
64
55
  </Article>
@@ -175,10 +175,11 @@ body {
175
175
  display: grid;
176
176
  grid-template-columns: minmax(0, var(--rb-layout-article-max, 48rem));
177
177
  justify-content: center;
178
- gap: var(--rb-layout-gap, 2rem);
178
+ column-gap: var(--rb-layout-gap, 2rem);
179
179
  }
180
180
 
181
- .rb-article-body {
181
+ .rb-article-body,
182
+ .site-article__footer {
182
183
  min-width: 0;
183
184
  padding-inline: var(--rb-space-2, 1rem);
184
185
  }
@@ -187,10 +188,6 @@ body {
187
188
  display: none;
188
189
  }
189
190
 
190
- .site-article__footer {
191
- min-width: 0;
192
- }
193
-
194
191
  @media (min-width: 88rem) {
195
192
  :is(:root, .rb-theme-root)[data-article-layout="article"] .rb-article-layout {
196
193
  grid-template-columns: minmax(0, var(--rb-layout-article-max, 48rem));
@@ -1,5 +1,13 @@
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
+ ArticleFooter,
7
+ ArticleLayout,
8
+ ContentSlot,
9
+ hasSlot,
10
+ } from "@riebeckite/honox/ui";
3
11
 
4
12
  export function SiteArticle({
5
13
  post,
@@ -9,7 +17,7 @@ export function SiteArticle({
9
17
  footerContent,
10
18
  }: {
11
19
  post: PostContent;
12
- bodySlots?: Readonly<Record<string, string>>;
20
+ bodySlots?: ContentBodySlots;
13
21
  asideContent?: unknown;
14
22
  afterContent?: unknown;
15
23
  footerContent?: unknown;
@@ -18,47 +26,30 @@ export function SiteArticle({
18
26
  <Article class="site-article">
19
27
  <ArticleLayout>
20
28
  {asideContent}
21
- {bodySlots?.["article.aside"] ? (
22
- <div
23
- class="site-article__aside"
24
- dangerouslySetInnerHTML={{ __html: bodySlots["article.aside"] }}
25
- />
26
- ) : null}
29
+
30
+ <ContentSlot
31
+ slots={bodySlots}
32
+ name="article.aside"
33
+ class="site-article__aside"
34
+ />
35
+
27
36
  <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 ?? "" }} />
37
+ <ContentSlot slots={bodySlots} name="article.header" />
38
+ <ContentSlot slots={bodySlots} name="article.metadata" />
39
+ <ContentSlot slots={bodySlots} name="article.before-content" />
40
+
41
+ <ArticleBody html={post.html ?? ""} />
42
+
47
43
  {afterContent}
48
- {bodySlots?.["article.after-content"] ? (
49
- <div
50
- class="site-article__after-content"
51
- dangerouslySetInnerHTML={{ __html: bodySlots["article.after-content"] }}
52
- />
53
- ) : null}
44
+
45
+ <ContentSlot slots={bodySlots} name="article.after-content" />
54
46
  </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}
47
+
48
+ {hasSlot(bodySlots, "article.footer") || footerContent ? (
49
+ <ArticleFooter class="site-article__footer">
50
+ <ContentSlot slots={bodySlots} name="article.footer" />
60
51
  {footerContent}
61
- </div>
52
+ </ArticleFooter>
62
53
  ) : null}
63
54
  </ArticleLayout>
64
55
  </Article>
@@ -175,10 +175,11 @@ body {
175
175
  display: grid;
176
176
  grid-template-columns: minmax(0, var(--rb-layout-article-max, 48rem));
177
177
  justify-content: center;
178
- gap: var(--rb-layout-gap, 2rem);
178
+ column-gap: var(--rb-layout-gap, 2rem);
179
179
  }
180
180
 
181
- .rb-article-body {
181
+ .rb-article-body,
182
+ .site-article__footer {
182
183
  min-width: 0;
183
184
  padding-inline: var(--rb-space-2, 1rem);
184
185
  }
@@ -187,10 +188,6 @@ body {
187
188
  display: none;
188
189
  }
189
190
 
190
- .site-article__footer {
191
- min-width: 0;
192
- }
193
-
194
191
  @media (min-width: 88rem) {
195
192
  :is(:root, .rb-theme-root)[data-article-layout="article"] .rb-article-layout {
196
193
  grid-template-columns: minmax(0, var(--rb-layout-article-max, 48rem));
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.4.16/schema.json",
3
+ "root": false,
4
+ "formatter": {
5
+ "enabled": true,
6
+ "indentStyle": "space",
7
+ "indentWidth": 2,
8
+ "lineWidth": 80
9
+ },
10
+ "linter": {
11
+ "enabled": true,
12
+ "rules": {
13
+ "recommended": true
14
+ }
15
+ },
16
+ "javascript": {
17
+ "formatter": {
18
+ "quoteStyle": "double",
19
+ "semicolons": "always"
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,12 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ indent_style = space
8
+ indent_size = 2
9
+ trim_trailing_whitespace = true
10
+
11
+ [*.md]
12
+ trim_trailing_whitespace = false
@@ -0,0 +1,5 @@
1
+ * text=auto eol=lf
2
+
3
+ *.png binary
4
+ *.ico binary
5
+ *.pdf binary
@@ -0,0 +1,6 @@
1
+ {
2
+ "editor.formatOnSave": true,
3
+ "files.eol": "\n",
4
+ "files.insertFinalNewline": true,
5
+ "files.trimTrailingWhitespace": true
6
+ }