@dominikcz/greg 0.9.35 → 0.9.36

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
@@ -16,7 +16,7 @@ For unattended/default setup (no prompts):
16
16
  npx @dominikcz/greg init --defaults
17
17
  ```
18
18
 
19
- The interactive wizard will ask for docs path, site title, TypeScript preference, and the type of initial documentation (empty, sample, or generated fake docs). It can also install all required dependencies for you.
19
+ The interactive wizard asks for docs path, site title, TypeScript preference, config mode (minimal or full), and starter docs type (empty, sample, or generated fake docs). It also creates a sensible `.gitignore`, copies default `public/` assets, and can install all required dependencies for you.
20
20
 
21
21
  At the end you only need:
22
22
 
package/bin/init.js CHANGED
@@ -18,6 +18,7 @@ import { fork, spawnSync } from 'node:child_process';
18
18
  const __dirname = dirname(fileURLToPath(import.meta.url));
19
19
  const cliArgs = new Set(process.argv.slice(2));
20
20
  const useDefaultsMode = cliArgs.has('--defaults') || cliArgs.has('--yes');
21
+ const forceLocalDependency = cliArgs.has('--local-dependency') || process.env.GREG_INIT_LOCAL_DEP === '1';
21
22
 
22
23
  // ── ANSI helpers (used for file-creation log lines) ───────────────────────────
23
24
  const g = (s) => `\x1b[32m${s}\x1b[0m`; // green
@@ -120,12 +121,7 @@ function isTransientCacheSpec(spec) {
120
121
 
121
122
  function resolveGregDependencySpec(version) {
122
123
  const packageRoot = join(__dirname, '..');
123
- const npmView = spawnSync('npm', ['view', `@dominikcz/greg@${version}`, 'version'], {
124
- stdio: 'pipe',
125
- shell: true,
126
- });
127
-
128
- if (npmView.status === 0) {
124
+ if (!forceLocalDependency) {
129
125
  return { spec: `^${version}`, source: 'registry' };
130
126
  }
131
127
 
@@ -158,6 +154,7 @@ async function main() {
158
154
  let desc = 'Documentation';
159
155
  let useTS = true;
160
156
  let addScripts = true;
157
+ let fullConfig = false;
161
158
  let docsType = '1';
162
159
 
163
160
  if (!useDefaultsMode) {
@@ -166,6 +163,7 @@ async function main() {
166
163
  desc = orCancel(await p.text({ message: 'Site description', initialValue: 'Documentation' }));
167
164
  useTS = orCancel(await p.confirm({ message: 'Use TypeScript for configuration?', initialValue: true }));
168
165
  addScripts = orCancel(await p.confirm({ message: 'Add greg scripts to package.json?', initialValue: true }));
166
+ fullConfig = orCancel(await p.confirm({ message: 'Generate full greg.config template?', initialValue: false }));
169
167
  docsType = orCancel(await p.select({
170
168
  message: 'Documentation contents',
171
169
  options: [
@@ -189,6 +187,9 @@ async function main() {
189
187
  const rootPath = '';
190
188
  const ext = useTS ? 'ts' : 'js';
191
189
  const vars = { TITLE: title, DESCRIPTION: desc, DOCS_DIR: docsDir, ROOT_PATH: rootPath, EXT: ext };
190
+ const gregConfigTemplate = useTS
191
+ ? (fullConfig ? 'greg.config.full.ts' : 'greg.config.ts')
192
+ : (fullConfig ? 'greg.config.full.js' : 'greg.config.js');
192
193
 
193
194
  p.log.step('Creating files…');
194
195
 
@@ -199,7 +200,14 @@ async function main() {
199
200
  ensure('src/app.css', tpl('src/app.css'));
200
201
  ensure(`vite.config.${ext}`, tpl('vite.config.js', vars)); // same content for .js and .ts
201
202
  ensure('svelte.config.js', tpl('svelte.config.js')); // always .js — vite-plugin-svelte requires it
202
- ensure(`greg.config.${ext}`, tpl(useTS ? 'greg.config.ts' : 'greg.config.js', vars));
203
+ ensure(`greg.config.${ext}`, tpl(gregConfigTemplate, vars));
204
+ ensure('.gitignore', tpl('.gitignore'));
205
+ const packagePublicDir = join(__dirname, '..', 'public');
206
+ if (existsSync(packagePublicDir)) {
207
+ copyRawDir(packagePublicDir, 'public');
208
+ } else {
209
+ p.log.warn('public assets not found in package; skipping public/ scaffold');
210
+ }
203
211
 
204
212
  if (useTS) {
205
213
  ensure('tsconfig.json', tpl('tsconfig.json'));
@@ -244,7 +252,7 @@ async function main() {
244
252
  let changed = false;
245
253
  if (addScripts) {
246
254
  pkg.scripts ??= {};
247
- for (const [k, v] of [['dev', 'greg dev'], ['build', 'greg build'], ['preview', 'greg preview']]) {
255
+ for (const [k, v] of [['greg', 'greg'], ['dev', 'greg dev'], ['build', 'greg build'], ['preview', 'greg preview']]) {
248
256
  if (!pkg.scripts[k]) { pkg.scripts[k] = v; changed = true; }
249
257
  }
250
258
  }
@@ -259,6 +267,18 @@ async function main() {
259
267
  pkg.devDependencies['@dominikcz/greg'] = gregDependencySpec;
260
268
  changed = true;
261
269
  }
270
+ const peerDepsMap = {
271
+ '@sveltejs/vite-plugin-svelte': gregDevDeps['@sveltejs/vite-plugin-svelte'] ?? '^6',
272
+ svelte: gregDevDeps.svelte ?? '^5',
273
+ vite: gregDevDeps.vite ?? '^7',
274
+ ...(useTS ? { typescript: '^5' } : {}),
275
+ };
276
+ for (const [depName, depVersion] of Object.entries(peerDepsMap)) {
277
+ if (!pkg.devDependencies[depName]) {
278
+ pkg.devDependencies[depName] = depVersion;
279
+ changed = true;
280
+ }
281
+ }
262
282
  if (changed) {
263
283
  writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
264
284
  p.log.success('package.json ' + d('(updated)'));
@@ -273,8 +293,14 @@ async function main() {
273
293
  name: 'my-docs',
274
294
  version: '0.0.1',
275
295
  type: 'module',
276
- ...(addScripts ? { scripts: { dev: 'greg dev', build: 'greg build', preview: 'greg preview' } } : {}),
277
- devDependencies: { '@dominikcz/greg': gregDependencySpec },
296
+ ...(addScripts ? { scripts: { greg: 'greg', dev: 'greg dev', build: 'greg build', preview: 'greg preview' } } : {}),
297
+ devDependencies: {
298
+ '@dominikcz/greg': gregDependencySpec,
299
+ '@sveltejs/vite-plugin-svelte': gregDevDeps['@sveltejs/vite-plugin-svelte'] ?? '^6',
300
+ svelte: gregDevDeps.svelte ?? '^5',
301
+ vite: gregDevDeps.vite ?? '^7',
302
+ ...(useTS ? { typescript: '^5' } : {}),
303
+ },
278
304
  };
279
305
  writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
280
306
  console.log(` ${g('+')} package.json`);
@@ -283,16 +309,8 @@ async function main() {
283
309
 
284
310
  // ── Install dependencies ──────────────────────────────────────────────────
285
311
  // @dominikcz/greg is already in package.json devDependencies — install only peer deps.
286
- const peerDepsArr = [
287
- `@sveltejs/vite-plugin-svelte@${gregDevDeps['@sveltejs/vite-plugin-svelte'] ?? '^6'}`,
288
- `svelte@${gregDevDeps.svelte ?? '^5'}`,
289
- `vite@${gregDevDeps.vite ?? '^7'}`,
290
- ...(useTS ? ['typescript'] : []),
291
- ];
292
312
  const pm = detectPm();
293
- const installArgs = pm === 'npm'
294
- ? ['install', '--save-dev', ...peerDepsArr]
295
- : ['add', '-D', ...peerDepsArr];
313
+ const installArgs = ['install'];
296
314
 
297
315
  const installNow = useDefaultsMode
298
316
  ? true
@@ -325,8 +343,8 @@ async function main() {
325
343
 
326
344
  p.outro(
327
345
  installNow
328
- ? `${b(g('Done!'))} Start your project:\n\n ${c('npm run dev')}`
329
- : `${b(g('Done!'))} Next steps:\n\n ${c(`${pm} ${installArgs.join(' ')}`)}\n ${c('npm run dev')}`
346
+ ? `${b(g('Done!'))} Start your project:\n\n ${c('npm run dev')}\n ${c('npx greg --help')}`
347
+ : `${b(g('Done!'))} Next steps:\n\n ${c(`${pm} ${installArgs.join(' ')}`)}\n ${c('npm run dev')}\n ${c('npx greg --help')}`
330
348
  );
331
349
  }
332
350
 
@@ -346,6 +364,26 @@ function copyTemplateDir(srcDir, destRel, vars) {
346
364
  }
347
365
  }
348
366
 
367
+ function copyRawDir(srcDir, destRel) {
368
+ for (const entry of readdirSync(srcDir)) {
369
+ const srcPath = join(srcDir, entry);
370
+ const destPath = join(destRel, entry);
371
+ if (statSync(srcPath).isDirectory()) {
372
+ copyRawDir(srcPath, destPath);
373
+ } else {
374
+ const full = join(cwd, destPath);
375
+ if (existsSync(full)) {
376
+ console.log(` ${y('~')} ${destPath} ${d('(skipped – already exists)')}`);
377
+ continue;
378
+ }
379
+ const dir = dirname(full);
380
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
381
+ writeFileSync(full, readFileSync(srcPath));
382
+ console.log(` ${g('+')} ${destPath}`);
383
+ }
384
+ }
385
+ }
386
+
349
387
  main().catch((err) => {
350
388
  console.error(err);
351
389
  process.exit(1);
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @type {import('@dominikcz/greg').GregConfig}
3
+ */
4
+ export default {
5
+ base: '/',
6
+ outDir: 'dist',
7
+ srcDir: '{{DOCS_DIR}}',
8
+ docsBase: '',
9
+ mainTitle: '{{TITLE}}',
10
+ useDynamicPageTitle: true,
11
+ sidebar: 'auto',
12
+ outline: [2, 3],
13
+ nav: [
14
+ { text: 'Guide', link: '/guide' },
15
+ { text: 'Reference', link: '/reference' },
16
+ ],
17
+ search: {
18
+ provider: 'local',
19
+ fuzzy: {
20
+ threshold: 0.35,
21
+ minMatchCharLength: 2,
22
+ },
23
+ },
24
+ // versioning: {
25
+ // strategy: 'branches',
26
+ // default: 'latest',
27
+ // aliases: { latest: '1.0' },
28
+ // branches: [
29
+ // { version: '1.0', branch: 'main', title: '1.0' },
30
+ // ],
31
+ // },
32
+ }
@@ -0,0 +1,31 @@
1
+ import type { GregConfig } from '@dominikcz/greg'
2
+
3
+ export default {
4
+ base: '/',
5
+ outDir: 'dist',
6
+ srcDir: '{{DOCS_DIR}}',
7
+ docsBase: '',
8
+ mainTitle: '{{TITLE}}',
9
+ useDynamicPageTitle: true,
10
+ sidebar: 'auto',
11
+ outline: [2, 3],
12
+ nav: [
13
+ { text: 'Guide', link: '/guide' },
14
+ { text: 'Reference', link: '/reference' },
15
+ ],
16
+ search: {
17
+ provider: 'local',
18
+ fuzzy: {
19
+ threshold: 0.35,
20
+ minMatchCharLength: 2,
21
+ },
22
+ },
23
+ // versioning: {
24
+ // strategy: 'branches',
25
+ // default: 'latest',
26
+ // aliases: { latest: '1.0' },
27
+ // branches: [
28
+ // { version: '1.0', branch: 'main', title: '1.0' },
29
+ // ],
30
+ // },
31
+ } satisfies GregConfig
@@ -2,38 +2,14 @@
2
2
  * @type {import('@dominikcz/greg').GregConfig}
3
3
  */
4
4
  export default {
5
- // VitePress-compatible build options:
6
- // base: '/',
7
- // outDir: 'dist',
8
- srcDir: '',
9
- docsBase: '',
5
+ base: '/',
6
+ outDir: 'dist',
7
+ srcDir: '{{DOCS_DIR}}',
10
8
  mainTitle: '{{TITLE}}',
9
+ // useDynamicPageTitle: true,
11
10
  sidebar: 'auto',
12
- // versioning: {
13
- // strategy: 'branches', // default
14
- // default: 'latest',
15
- // aliases: {
16
- // latest: '2.1',
17
- // stable: '2.0',
18
- // },
19
- // ui: {
20
- // versionMenuLabel: 'Version',
21
- // manifestUnavailableText: 'Version selector unavailable',
22
- // showManifestUnavailableStatus: false,
23
- // outdatedVersionMessage: 'You are viewing an older version ({current}). Recommended: {default}.',
24
- // outdatedVersionActionLabel: 'Go to latest',
25
- // },
26
- // locales: {
27
- // '/': {
28
- // ui: { versionMenuLabel: 'Version' },
29
- // },
30
- // '/pl/': {
31
- // ui: { versionMenuLabel: 'Wersja' },
32
- // },
33
- // },
34
- // branches: [
35
- // { version: '2.1', branch: 'main', title: '2.1' },
36
- // { version: '2.0', branch: 'release/2.0', title: '2.0' },
37
- // ],
11
+ // search: {
12
+ // provider: 'local',
13
+ // // fuzzy: { threshold: 0.35, minMatchCharLength: 2 },
38
14
  // },
39
15
  }
@@ -1,38 +1,14 @@
1
1
  import type { GregConfig } from '@dominikcz/greg'
2
2
 
3
3
  export default {
4
- // VitePress-compatible build options:
5
- // base: '/',
6
- // outDir: 'dist',
7
- srcDir: '',
8
- docsBase: '',
4
+ base: '/',
5
+ outDir: 'dist',
6
+ srcDir: '{{DOCS_DIR}}',
9
7
  mainTitle: '{{TITLE}}',
8
+ // useDynamicPageTitle: true,
10
9
  sidebar: 'auto',
11
- // versioning: {
12
- // strategy: 'branches', // default
13
- // default: 'latest',
14
- // aliases: {
15
- // latest: '2.1',
16
- // stable: '2.0',
17
- // },
18
- // ui: {
19
- // versionMenuLabel: 'Version',
20
- // manifestUnavailableText: 'Version selector unavailable',
21
- // showManifestUnavailableStatus: false,
22
- // outdatedVersionMessage: 'You are viewing an older version ({current}). Recommended: {default}.',
23
- // outdatedVersionActionLabel: 'Go to latest',
24
- // },
25
- // locales: {
26
- // '/': {
27
- // ui: { versionMenuLabel: 'Version' },
28
- // },
29
- // '/pl/': {
30
- // ui: { versionMenuLabel: 'Wersja' },
31
- // },
32
- // },
33
- // branches: [
34
- // { version: '2.1', branch: 'main', title: '2.1' },
35
- // { version: '2.0', branch: 'release/2.0', title: '2.0' },
36
- // ],
10
+ // search: {
11
+ // provider: 'local',
12
+ // // fuzzy: { threshold: 0.35, minMatchCharLength: 2 },
37
13
  // },
38
14
  } satisfies GregConfig
@@ -55,11 +55,13 @@ The wizard asks a handful of questions:
55
55
  | **Site title** | Shown in the browser tab and the site header |
56
56
  | **Description** | Used in the HTML `<meta>` tag |
57
57
  | **TypeScript** | Creates `.ts` config files instead of `.js` |
58
- | **Add npm scripts** | Adds `dev`, `build` and `preview` to `package.json` |
58
+ | **Config mode** | Choose **minimal** (default) or **full** `greg.config` template |
59
+ | **Add npm scripts** | Adds `greg`, `dev`, `build` and `preview` to `package.json` |
59
60
  | **Starter content** | _Empty_ — bare minimum; _Sample_ — example pages; _Generated_ — large fake docs set |
60
61
  | **Install now** | Runs `npm install` (or your package manager) right away |
61
62
 
62
63
  When it finishes, you will see a summary of created files.
64
+ The scaffold also includes a default `.gitignore` and copies baseline assets into `public/`.
63
65
 
64
66
  ### 3. Start the development server
65
67
 
@@ -133,6 +133,23 @@ Name of the project shown in the top-left header.
133
133
  <MarkdownDocs srcDir="/" version="1.0.0" mainTitle="My Project" />
134
134
  ```
135
135
 
136
+ ### `useDynamicPageTitle`
137
+
138
+ - **Type:** `boolean`
139
+ - **Default:** `true`
140
+
141
+ Controls browser tab title behavior:
142
+
143
+ - `true` (default): tab title follows active page title (for example `Getting Started | My Project`)
144
+ - `false`: tab title stays fixed to `mainTitle`
145
+
146
+ ```js
147
+ export default {
148
+ mainTitle: 'My Project',
149
+ useDynamicPageTitle: false,
150
+ }
151
+ ```
152
+
136
153
  ### `outline`
137
154
 
138
155
  - **Type:** `false | number | [number, number] | 'deep' | { level?: …, label?: string }`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dominikcz/greg",
3
- "version": "0.9.35",
3
+ "version": "0.9.36",
4
4
  "type": "module",
5
5
  "types": "./types/index.d.ts",
6
6
  "bin": {
@@ -87,6 +87,8 @@
87
87
  children?: Snippet;
88
88
  version?: string;
89
89
  mainTitle?: string;
90
+ /** Keep browser tab title in sync with active page title. Default: true. */
91
+ useDynamicPageTitle?: boolean;
90
92
  carbonAds?: CarbonAdsOptions;
91
93
  /** VitePress-compatible outline option. false = disabled, [2,3] = default. */
92
94
  outline?: OutlineOption | boolean;
@@ -206,6 +208,7 @@
206
208
  ),
207
209
  version: globalVersion = (gregConfig as any).version ?? "",
208
210
  mainTitle: globalMainTitle = (gregConfig as any).mainTitle ?? "Greg",
211
+ useDynamicPageTitle = (gregConfig as any).useDynamicPageTitle ?? true,
209
212
  carbonAds = (gregConfig as any).carbonAds,
210
213
  outline: globalOutline =
211
214
  (gregConfig as any).outline ?? ([2, 3] as [number, number]),
@@ -1345,6 +1348,28 @@
1345
1348
  }
1346
1349
 
1347
1350
  const title = $derived(router.title(flat));
1351
+ const browserTitle = $derived.by(() => {
1352
+ if (!useDynamicPageTitle) {
1353
+ const fixedTitle = String(mainTitle ?? "").trim();
1354
+ return fixedTitle || "Greg";
1355
+ }
1356
+ const brand =
1357
+ siteTitle === false
1358
+ ? String(mainTitle || "").trim()
1359
+ : String(siteTitle ?? mainTitle ?? "").trim();
1360
+ const pageTitle = String(title ?? "").trim();
1361
+ if (!brand) return pageTitle || "Greg";
1362
+ if (!pageTitle || pageTitle === brand) return brand;
1363
+ return `${pageTitle} | ${brand}`;
1364
+ });
1365
+
1366
+ $effect(() => {
1367
+ if (typeof document === "undefined") return;
1368
+ if (!browserTitle) return;
1369
+ if (document.title !== browserTitle) {
1370
+ document.title = browserTitle;
1371
+ }
1372
+ });
1348
1373
 
1349
1374
  // -- Content fetch -----------------------------------------------------------
1350
1375
  async function fetchMarkdown(mdPath: string): Promise<string> {