@brandon_m_behring/book-scaffold-astro 4.4.0 → 4.5.1

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/dist/index.d.ts CHANGED
@@ -1,8 +1,24 @@
1
1
  import { AstroUserConfig, AstroIntegration } from 'astro';
2
- import { c as BookConfigOptions, f as BookScaffoldIntegrationOptions, Q as volatilityLevels, h as ChaptersRenderer, n as Style } from './types-BhlCranN.js';
3
- export { A as AcademicChapter, B as BOOK_PRESETS, a as BOOK_PROFILES, b as BookConfigError, d as BookPreset, e as BookProfile, g as BookSchemasOptions, C as ChapterFor, i as CourseNotesChapter, F as FreshnessAffordance, j as FrontmatterRouteConfig, M as MinimalChapter, P as PartKey, k as PartialRouteToggles, l as ProfileDefinition, R as ResearchPortfolioChapter, m as RouteToggles, S as StatusBadge, o as StyleInput, T as ToolsChapter, V as VolatilityBadge, p as academicChapterSchema, q as academicParts, r as changeKinds, s as changelogSchema, t as chapterStatus, u as composeStyles, v as courseNotesChapterSchema, w as defineProfile, x as defineStyle, y as minimalChapterSchema, z as normalizeFrontmatterConfig, D as patternCategories, E as patternsSchema, G as researchPortfolioChapterSchema, H as resolvePreset, I as resolveProfile, J as sourceTiers, K as sourceTiersResearch, L as sourcesSchema, N as toolSlugs, O as toolsChapterSchema } from './types-BhlCranN.js';
2
+ import { c as BookConfigOptions, f as BookScaffoldIntegrationOptions, Q as volatilityLevels, h as ChaptersRenderer, n as Style } from './types-DLIpEgTm.js';
3
+ export { A as AcademicChapter, B as BOOK_PRESETS, a as BOOK_PROFILES, b as BookConfigError, d as BookPreset, e as BookProfile, g as BookSchemasOptions, C as ChapterFor, i as CourseNotesChapter, F as FreshnessAffordance, j as FrontmatterRouteConfig, M as MinimalChapter, P as PartKey, k as PartialRouteToggles, l as ProfileDefinition, R as ResearchPortfolioChapter, m as RouteToggles, S as StatusBadge, o as StyleInput, T as ToolsChapter, V as VolatilityBadge, p as academicChapterSchema, q as academicParts, r as changeKinds, s as changelogSchema, t as chapterStatus, u as composeStyles, v as courseNotesChapterSchema, w as defineProfile, x as defineStyle, y as minimalChapterSchema, z as normalizeFrontmatterConfig, D as patternCategories, E as patternsSchema, G as researchPortfolioChapterSchema, H as resolvePreset, I as resolveProfile, J as sourceTiers, K as sourceTiersResearch, L as sourcesSchema, N as toolSlugs, O as toolsChapterSchema } from './types-DLIpEgTm.js';
4
4
  import 'astro/zod';
5
5
 
6
+ /**
7
+ * v4.5.0: Default portfolio backlink baked into the scaffold. Rendered in
8
+ * the auto-injected `/` landing footer for every consumer that doesn't
9
+ * explicitly override `portfolio` in defineBookConfig.
10
+ *
11
+ * Single source of truth for the brandon-behring.dev URL across all
12
+ * consumers — update here, bump scaffold version, every consumer inherits
13
+ * on next build. This is the intentional Brandon-specific default
14
+ * discussed in plan §Phase 6-pre. Consumers outside the brandon-behring.dev
15
+ * ecosystem set `portfolio: false` (no link) or pass `{ url, label }` to
16
+ * override.
17
+ */
18
+ declare const BRANDON_PORTFOLIO_DEFAULT: {
19
+ readonly url: "https://brandon-behring.dev";
20
+ readonly label: "brandon-behring.dev";
21
+ };
6
22
  declare function defineBookConfig(opts: BookConfigOptions): Promise<AstroUserConfig>;
7
23
 
8
24
  declare function bookScaffoldIntegration(opts: BookScaffoldIntegrationOptions): AstroIntegration;
@@ -244,4 +260,4 @@ type TipsConfigInput = Omit<TipsConfig, typeof TipsConfigBrand | '__tipsConfigVe
244
260
  */
245
261
  declare function defineTips(opts: TipsConfigInput): TipsConfig;
246
262
 
247
- export { BUILTIN_STYLES, BookConfigOptions, BookScaffoldIntegrationOptions, ChaptersRenderer, type Freshness, type FreshnessStatus, Style, type TipsConfig, type TipsConfigInput, type VolatilityLevel, academicChaptersRenderer, academicStyle, bookScaffoldIntegration, chapterSortKey, courseNotesStyle, defineBookConfig, defineMdxComponents, defineTips, fallbackChaptersRenderer, freshnessLabel, getFreshness, minimalStyle, researchPortfolioStyle, toolsChaptersRenderer, toolsStyle, volatilityLevels };
263
+ export { BRANDON_PORTFOLIO_DEFAULT, BUILTIN_STYLES, BookConfigOptions, BookScaffoldIntegrationOptions, ChaptersRenderer, type Freshness, type FreshnessStatus, Style, type TipsConfig, type TipsConfigInput, type VolatilityLevel, academicChaptersRenderer, academicStyle, bookScaffoldIntegration, chapterSortKey, courseNotesStyle, defineBookConfig, defineMdxComponents, defineTips, fallbackChaptersRenderer, freshnessLabel, getFreshness, minimalStyle, researchPortfolioStyle, toolsChaptersRenderer, toolsStyle, volatilityLevels };
package/dist/index.mjs CHANGED
@@ -380,8 +380,10 @@ var academicProfile = defineProfile({
380
380
  // opt-in per book; see #7
381
381
  tips: false,
382
382
  // v4.3.0 #70: opt-in per book; requires build-tips
383
- exercises: false
383
+ exercises: false,
384
384
  // v4.4.0: opt-in per book; requires build-exercises
385
+ landing: true
386
+ // v4.5.0: auto-inject minimal root landing; consumers override via src/pages/index.astro
385
387
  },
386
388
  styles: ["tokens.css", "layout.css", "callouts.css", "chapter.css", "typography.css", "print.css"],
387
389
  katex: true,
@@ -498,8 +500,10 @@ var toolsProfile = defineProfile({
498
500
  // opt-in per book; see #7
499
501
  tips: false,
500
502
  // v4.3.0 #70: opt-in per book
501
- exercises: false
503
+ exercises: false,
502
504
  // v4.4.0: opt-in per book
505
+ landing: true
506
+ // v4.5.0: auto-inject minimal root landing
503
507
  },
504
508
  styles: [
505
509
  "tokens.css",
@@ -580,8 +584,10 @@ var minimalProfile = defineProfile({
580
584
  // opt-in per book; see #7
581
585
  tips: false,
582
586
  // v4.3.0 #70: opt-in per book
583
- exercises: false
587
+ exercises: false,
584
588
  // v4.4.0: opt-in per book
589
+ landing: true
590
+ // v4.5.0: auto-inject minimal root landing
585
591
  },
586
592
  styles: ["tokens.css", "layout.css", "callouts.css", "chapter.css", "typography.css", "print.css"],
587
593
  // v3.7.0 (#35): minimal aliases tools schema; fallback renderer field-dispatches if a consumer opts into routes.chapters
@@ -603,8 +609,10 @@ var courseNotesProfile = defineProfile({
603
609
  // opt-in per book; see #7
604
610
  tips: false,
605
611
  // v4.3.0 #70: opt-in per book
606
- exercises: false
612
+ exercises: false,
607
613
  // v4.4.0: opt-in per book
614
+ landing: true
615
+ // v4.5.0: auto-inject minimal root landing
608
616
  },
609
617
  styles: ["tokens.css", "layout.css", "callouts.css", "chapter.css", "typography.css", "print.css"],
610
618
  // v3.7.0 (#35): course-notes schema has tools-style fields (chapter, volatility, sources) — fallback renderer dispatches via tools renderer
@@ -627,8 +635,10 @@ var researchPortfolioProfile = defineProfile({
627
635
  // portfolios universally need title/disclosure/banner pages
628
636
  tips: false,
629
637
  // v4.3.0 #70: opt-in per book
630
- exercises: false
638
+ exercises: false,
631
639
  // v4.4.0: opt-in per book
640
+ landing: true
641
+ // v4.5.0: auto-inject minimal root landing
632
642
  },
633
643
  styles: ["tokens.css", "layout.css", "callouts.css", "chapter.css", "typography.css", "print.css"],
634
644
  katex: true,
@@ -814,6 +824,23 @@ function defineMdxComponents(components) {
814
824
  }
815
825
 
816
826
  // src/integration.ts
827
+ var LANDING_VIRTUAL_ID = "virtual:book-scaffold/landing-config";
828
+ var LANDING_RESOLVED_ID = "\0" + LANDING_VIRTUAL_ID;
829
+ function makeLandingConfigVitePlugin(config) {
830
+ const serialized = `export default ${JSON.stringify(config)};`;
831
+ return {
832
+ name: "book-scaffold:landing-config",
833
+ enforce: "pre",
834
+ resolveId(id) {
835
+ if (id === LANDING_VIRTUAL_ID) return LANDING_RESOLVED_ID;
836
+ return null;
837
+ },
838
+ load(id) {
839
+ if (id !== LANDING_RESOLVED_ID) return null;
840
+ return serialized;
841
+ }
842
+ };
843
+ }
817
844
  var PACKAGE_NAME = "@brandon_m_behring/book-scaffold-astro";
818
845
  var ROUTE_REGISTRY = {
819
846
  references: { pattern: "/references", file: "references.astro" },
@@ -833,6 +860,11 @@ var ROUTE_REGISTRY = {
833
860
  // v4.4.0: exercises index by chapter. Opt-in via routes.exercises: true;
834
861
  // pairs with build-exercises script + <ExerciseSolutions auto /> mode.
835
862
  exercises: { pattern: "/exercises", file: "exercises.astro" },
863
+ // v4.5.0: minimal root landing page. Reads title/description/portfolio/routes
864
+ // from vite.define-injected import.meta.env vars. Default-on per profile;
865
+ // consumers with their own src/pages/index.astro override (file-system route
866
+ // wins over injectRoute).
867
+ landing: { pattern: "/", file: "index.astro" },
836
868
  // v3.4.0 (#7): consumer-collection-backed frontmatter route. Opt-in via
837
869
  // routes: { frontmatter: true } AND content.config.ts defining the
838
870
  // collection (use frontmatterCollection() helper from /schemas subpath).
@@ -850,7 +882,16 @@ function resolvePage(file) {
850
882
  return fileURLToPath(new URL(`../pages/${file}`, import.meta.url));
851
883
  }
852
884
  function bookScaffoldIntegration(opts) {
853
- const { profile, routes: userOverrides = {}, extraStyles = [], mdxComponentsModule } = opts;
885
+ const {
886
+ profile,
887
+ routes: userOverrides = {},
888
+ extraStyles = [],
889
+ mdxComponentsModule,
890
+ // v4.5.0: landing-page data, propagated via vite.define to /index.astro.
891
+ title,
892
+ description,
893
+ portfolio
894
+ } = opts;
854
895
  const def = PROFILES[profile];
855
896
  const fmNormalized = normalizeFrontmatterConfig(userOverrides.frontmatter);
856
897
  const fmEnabled = fmNormalized?.enabled ?? def.routes.frontmatter;
@@ -891,10 +932,23 @@ function bookScaffoldIntegration(opts) {
891
932
  const consumerRoot = fileURLToPath(config.root);
892
933
  const resolvedMdxPath = resolveMdxComponentsPath(consumerRoot, mdxComponentsModule);
893
934
  const presetLiteral = JSON.stringify(profile);
935
+ const enabledRouteNames = Object.entries(enabledRoutes).filter(([, on]) => on).map(([name]) => name);
894
936
  updateConfig({
895
937
  vite: {
896
- plugins: [makeMdxComponentsVitePlugin(resolvedMdxPath)],
938
+ plugins: [
939
+ makeMdxComponentsVitePlugin(resolvedMdxPath),
940
+ makeLandingConfigVitePlugin({
941
+ title: title ?? null,
942
+ description: description ?? null,
943
+ portfolio: portfolio ?? false,
944
+ enabledRoutes: enabledRouteNames
945
+ })
946
+ ],
897
947
  define: {
948
+ // Preset/profile stay as env vars — preference-flag pattern where
949
+ // env-based override IS the convention (resolvePreset reads from
950
+ // process.env / .env explicitly). Config values (title, etc.) now
951
+ // route through the virtual module above to avoid that override.
898
952
  "import.meta.env.BOOK_PRESET": presetLiteral,
899
953
  "import.meta.env.BOOK_PROFILE": presetLiteral
900
954
  }
@@ -906,6 +960,10 @@ function bookScaffoldIntegration(opts) {
906
960
  }
907
961
 
908
962
  // src/config.ts
963
+ var BRANDON_PORTFOLIO_DEFAULT = {
964
+ url: "https://brandon-behring.dev",
965
+ label: "brandon-behring.dev"
966
+ };
909
967
  function v3MigrationError(opts) {
910
968
  const v3Value = opts.preset ?? opts.profile;
911
969
  const v3FieldUsed = "preset" in opts ? "preset" : "profile";
@@ -986,6 +1044,7 @@ async function defineBookConfig(opts) {
986
1044
  }
987
1045
  ]);
988
1046
  }
1047
+ const resolvedPortfolio = opts.portfolio === false ? false : opts.portfolio ?? BRANDON_PORTFOLIO_DEFAULT;
989
1048
  const integrations = [
990
1049
  mdx(),
991
1050
  preact(),
@@ -993,7 +1052,12 @@ async function defineBookConfig(opts) {
993
1052
  profile,
994
1053
  routes: mergedRoutes,
995
1054
  mdxComponentsModule,
996
- extraStyles: mergedExtraStyles
1055
+ extraStyles: mergedExtraStyles,
1056
+ // v4.5.0: pass landing-page data through to the integration so it can
1057
+ // be exposed to the auto-injected /index.astro via vite.define.
1058
+ title: opts.title,
1059
+ description: opts.description,
1060
+ portfolio: resolvedPortfolio
997
1061
  }),
998
1062
  ...mergedExtraIntegrations
999
1063
  ];
@@ -1028,6 +1092,10 @@ async function defineBookConfig(opts) {
1028
1092
  extraStyles: _extraStyles,
1029
1093
  markdown: _markdown,
1030
1094
  katexMacros: _katexMacros,
1095
+ // v4.5.0: strip new landing-related opts so they don't leak into AstroUserConfig.
1096
+ title: _title,
1097
+ description: _description,
1098
+ portfolio: _portfolio,
1031
1099
  ...rest
1032
1100
  } = opts;
1033
1101
  void _styles;
@@ -1039,6 +1107,9 @@ async function defineBookConfig(opts) {
1039
1107
  void _extraStyles;
1040
1108
  void _markdown;
1041
1109
  void _katexMacros;
1110
+ void _title;
1111
+ void _description;
1112
+ void _portfolio;
1042
1113
  const katexExternals = wantsKatex ? [] : ["remark-math", "rehype-katex", "katex"];
1043
1114
  const config = {
1044
1115
  site,
@@ -1115,6 +1186,7 @@ function defineTips(opts) {
1115
1186
  export {
1116
1187
  BOOK_PRESETS,
1117
1188
  BOOK_PROFILES,
1189
+ BRANDON_PORTFOLIO_DEFAULT,
1118
1190
  BUILTIN_STYLES,
1119
1191
  BookConfigError,
1120
1192
  academicChapterSchema,
package/dist/schemas.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { defineCollection } from 'astro:content';
2
- import { g as BookSchemasOptions } from './types-BhlCranN.js';
2
+ import { g as BookSchemasOptions } from './types-DLIpEgTm.js';
3
3
  import 'astro';
4
4
  import 'astro/zod';
5
5
 
package/dist/schemas.mjs CHANGED
@@ -265,8 +265,10 @@ var academicProfile = defineProfile({
265
265
  // opt-in per book; see #7
266
266
  tips: false,
267
267
  // v4.3.0 #70: opt-in per book; requires build-tips
268
- exercises: false
268
+ exercises: false,
269
269
  // v4.4.0: opt-in per book; requires build-exercises
270
+ landing: true
271
+ // v4.5.0: auto-inject minimal root landing; consumers override via src/pages/index.astro
270
272
  },
271
273
  styles: ["tokens.css", "layout.css", "callouts.css", "chapter.css", "typography.css", "print.css"],
272
274
  katex: true,
@@ -383,8 +385,10 @@ var toolsProfile = defineProfile({
383
385
  // opt-in per book; see #7
384
386
  tips: false,
385
387
  // v4.3.0 #70: opt-in per book
386
- exercises: false
388
+ exercises: false,
387
389
  // v4.4.0: opt-in per book
390
+ landing: true
391
+ // v4.5.0: auto-inject minimal root landing
388
392
  },
389
393
  styles: [
390
394
  "tokens.css",
@@ -465,8 +469,10 @@ var minimalProfile = defineProfile({
465
469
  // opt-in per book; see #7
466
470
  tips: false,
467
471
  // v4.3.0 #70: opt-in per book
468
- exercises: false
472
+ exercises: false,
469
473
  // v4.4.0: opt-in per book
474
+ landing: true
475
+ // v4.5.0: auto-inject minimal root landing
470
476
  },
471
477
  styles: ["tokens.css", "layout.css", "callouts.css", "chapter.css", "typography.css", "print.css"],
472
478
  // v3.7.0 (#35): minimal aliases tools schema; fallback renderer field-dispatches if a consumer opts into routes.chapters
@@ -488,8 +494,10 @@ var courseNotesProfile = defineProfile({
488
494
  // opt-in per book; see #7
489
495
  tips: false,
490
496
  // v4.3.0 #70: opt-in per book
491
- exercises: false
497
+ exercises: false,
492
498
  // v4.4.0: opt-in per book
499
+ landing: true
500
+ // v4.5.0: auto-inject minimal root landing
493
501
  },
494
502
  styles: ["tokens.css", "layout.css", "callouts.css", "chapter.css", "typography.css", "print.css"],
495
503
  // v3.7.0 (#35): course-notes schema has tools-style fields (chapter, volatility, sources) — fallback renderer dispatches via tools renderer
@@ -512,8 +520,10 @@ var researchPortfolioProfile = defineProfile({
512
520
  // portfolios universally need title/disclosure/banner pages
513
521
  tips: false,
514
522
  // v4.3.0 #70: opt-in per book
515
- exercises: false
523
+ exercises: false,
516
524
  // v4.4.0: opt-in per book
525
+ landing: true
526
+ // v4.5.0: auto-inject minimal root landing
517
527
  },
518
528
  styles: ["tokens.css", "layout.css", "callouts.css", "chapter.css", "typography.css", "print.css"],
519
529
  katex: true,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@brandon_m_behring/book-scaffold-astro",
3
3
  "description": "Astro 6 + MDX toolkit for long-form technical books. Profile-aware (academic / tools / minimal); ships Tufte typography, KaTeX, BibTeX citations, Pagefind, Cloudflare Workers deploy. See PACKAGE_DESIGN.md for the API contract.",
4
- "version": "4.4.0",
4
+ "version": "4.5.1",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": "Brandon Behring",
@@ -0,0 +1,118 @@
1
+ ---
2
+ /**
3
+ * /index — minimal default landing page (v4.5.0; landing-config source
4
+ * refactored in v4.5.1 from env vars to virtual module).
5
+ *
6
+ * Auto-injected by bookScaffoldIntegration when routes.landing === true
7
+ * (default for every profile). Consumers with their own src/pages/index.astro
8
+ * override automatically — file-system routes win over injectRoute, no extra
9
+ * config needed.
10
+ *
11
+ * Reads book identity + portfolio + enabled-routes from the
12
+ * `virtual:book-scaffold/landing-config` virtual module exposed by
13
+ * makeLandingConfigVitePlugin (see integration.ts §4.5.1). v4.5.0 used
14
+ * import.meta.env.BOOK_* env vars; that pattern was vulnerable to silent
15
+ * override by consumer .env files (caught during DML deploy when a stale
16
+ * `BOOK_TITLE=web` in web/.env overrode defineBookConfig({title})). The
17
+ * virtual module isolates landing config from any env-based override.
18
+ *
19
+ * Renders:
20
+ * - h1 with book title (fallback: 'book-scaffold-astro')
21
+ * - lead paragraph with description (omitted if not set)
22
+ * - "Read" list of links to enabled scaffold routes (filtered to only
23
+ * routes the integration actually injected; respects routes.<x>: false)
24
+ * - portfolio backlink in the footer (omitted if portfolio: false)
25
+ *
26
+ * Override paths:
27
+ * - Disable entirely: defineBookConfig({ routes: { landing: false } })
28
+ * - Compose differently: create src/pages/index.astro in your consumer
29
+ * repo (file wins; this page never renders)
30
+ * - Change portfolio target: defineBookConfig({ portfolio: { url, label } })
31
+ * or defineBookConfig({ portfolio: false })
32
+ */
33
+ import Base from '../layouts/Base.astro';
34
+ import bookConfig from 'virtual:book-scaffold/landing-config';
35
+
36
+ const title = bookConfig.title ?? 'book-scaffold-astro';
37
+ const description = bookConfig.description;
38
+ const portfolio = bookConfig.portfolio;
39
+ const enabledRoutes = bookConfig.enabledRoutes;
40
+
41
+ // Map from internal route name → display label + URL. Only routes that
42
+ // produce a single landing-list entry are listed here (frontmatter is a
43
+ // slug pattern; chaptersSlug is dynamic; landing IS this page).
44
+ const ROUTE_LABELS: Record<string, { label: string; href: string }> = {
45
+ chapters: { label: 'Chapters', href: '/chapters/' },
46
+ search: { label: 'Search', href: '/search/' },
47
+ references: { label: 'References', href: '/references/' },
48
+ print: { label: 'Print view', href: '/print/' },
49
+ convergence: { label: 'Convergence', href: '/convergence/' },
50
+ tips: { label: 'Tips', href: '/tips/' },
51
+ exercises: { label: 'Exercises', href: '/exercises/' },
52
+ };
53
+
54
+ const visibleRoutes = enabledRoutes
55
+ .filter((name) => name in ROUTE_LABELS)
56
+ .map((name) => ROUTE_LABELS[name]!);
57
+ ---
58
+
59
+ <Base title={title} description={description ?? undefined}>
60
+ <article class="prose landing">
61
+ <h1>{title}</h1>
62
+ {description && <p class="lead">{description}</p>}
63
+
64
+ {visibleRoutes.length > 0 && (
65
+ <>
66
+ <h2 class="read-heading">Read</h2>
67
+ <ul class="route-list">
68
+ {visibleRoutes.map((r) => (
69
+ <li><a href={r.href}>{r.label}</a></li>
70
+ ))}
71
+ </ul>
72
+ </>
73
+ )}
74
+
75
+ {portfolio && portfolio !== false && (
76
+ <p class="portfolio-footer">
77
+ <small>
78
+ Part of <a href={portfolio.url}>{portfolio.label}</a>
79
+ </small>
80
+ </p>
81
+ )}
82
+ </article>
83
+ </Base>
84
+
85
+ <style>
86
+ .landing {
87
+ max-width: 60ch;
88
+ margin: 2rem auto;
89
+ }
90
+ .lead {
91
+ font-size: 1.1rem;
92
+ line-height: 1.5;
93
+ margin: 1.25rem 0 2.5rem 0;
94
+ }
95
+ .read-heading {
96
+ font-size: 0.85rem;
97
+ text-transform: uppercase;
98
+ letter-spacing: 0.08em;
99
+ color: var(--color-text-muted, #555);
100
+ margin-top: 2.5rem;
101
+ margin-bottom: 0.75rem;
102
+ }
103
+ .route-list {
104
+ list-style: none;
105
+ padding: 0;
106
+ margin: 0;
107
+ }
108
+ .route-list li {
109
+ padding: 0.4rem 0;
110
+ font-family: var(--font-sans, sans-serif);
111
+ font-size: 1rem;
112
+ }
113
+ .portfolio-footer {
114
+ margin-top: 3rem;
115
+ color: var(--color-text-muted, #555);
116
+ font-family: var(--font-sans, sans-serif);
117
+ }
118
+ </style>
@@ -41,6 +41,16 @@ export interface RouteToggles {
41
41
  print: boolean;
42
42
  chapters: boolean;
43
43
  convergence: boolean;
44
+ /**
45
+ * v4.5.0: auto-inject a minimal `/` landing page that reads the book's
46
+ * `title`, `description`, and `portfolio` from defineBookConfig and
47
+ * renders a route list (filtered to enabled routes). Defaults to `true`
48
+ * on every profile. Consumers with their own `src/pages/index.astro` keep
49
+ * their custom landing (file-system routes win over `injectRoute`). Set
50
+ * to `false` to suppress the auto-injection entirely without writing
51
+ * a custom landing.
52
+ */
53
+ landing: boolean;
44
54
  /**
45
55
  * v3.4.0 (closes #7): auto-inject `/frontmatter/[slug]/` rendering a
46
56
  * consumer-defined `frontmatter` content collection. Default `false` per
@@ -25,6 +25,7 @@ export const academicProfile = defineProfile({
25
25
  frontmatter: false, // opt-in per book; see #7
26
26
  tips: false, // v4.3.0 #70: opt-in per book; requires build-tips
27
27
  exercises: false, // v4.4.0: opt-in per book; requires build-exercises
28
+ landing: true, // v4.5.0: auto-inject minimal root landing; consumers override via src/pages/index.astro
28
29
  },
29
30
  styles: ['tokens.css', 'layout.css', 'callouts.css', 'chapter.css', 'typography.css', 'print.css'],
30
31
  katex: true,
@@ -27,6 +27,7 @@ export const courseNotesProfile = defineProfile({
27
27
  frontmatter: false, // opt-in per book; see #7
28
28
  tips: false, // v4.3.0 #70: opt-in per book
29
29
  exercises: false, // v4.4.0: opt-in per book
30
+ landing: true, // v4.5.0: auto-inject minimal root landing
30
31
  },
31
32
  styles: ['tokens.css', 'layout.css', 'callouts.css', 'chapter.css', 'typography.css', 'print.css'],
32
33
  // v3.7.0 (#35): course-notes schema has tools-style fields (chapter, volatility, sources) — fallback renderer dispatches via tools renderer
@@ -22,6 +22,7 @@ export const minimalProfile = defineProfile({
22
22
  frontmatter: false, // opt-in per book; see #7
23
23
  tips: false, // v4.3.0 #70: opt-in per book
24
24
  exercises: false, // v4.4.0: opt-in per book
25
+ landing: true, // v4.5.0: auto-inject minimal root landing
25
26
  },
26
27
  styles: ['tokens.css', 'layout.css', 'callouts.css', 'chapter.css', 'typography.css', 'print.css'],
27
28
  // v3.7.0 (#35): minimal aliases tools schema; fallback renderer field-dispatches if a consumer opts into routes.chapters
@@ -38,6 +38,7 @@ export const researchPortfolioProfile = defineProfile({
38
38
  frontmatter: true, // portfolios universally need title/disclosure/banner pages
39
39
  tips: false, // v4.3.0 #70: opt-in per book
40
40
  exercises: false, // v4.4.0: opt-in per book
41
+ landing: true, // v4.5.0: auto-inject minimal root landing
41
42
  },
42
43
  styles: ['tokens.css', 'layout.css', 'callouts.css', 'chapter.css', 'typography.css', 'print.css'],
43
44
  katex: true, // math is common in research content
@@ -22,6 +22,7 @@ export const toolsProfile = defineProfile({
22
22
  frontmatter: false, // opt-in per book; see #7
23
23
  tips: false, // v4.3.0 #70: opt-in per book
24
24
  exercises: false, // v4.4.0: opt-in per book
25
+ landing: true, // v4.5.0: auto-inject minimal root landing
25
26
  },
26
27
  styles: [
27
28
  'tokens.css', 'layout.css', 'callouts.css', 'chapter.css',