narrarium-astro-reader 0.1.8 → 0.1.10

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.
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAKA,KAAK,eAAe,GAAG;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;;;;;GAmGxF"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAKA,KAAK,eAAe,GAAG;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;;;;;GAsGxF"}
@@ -13,14 +13,17 @@ export async function scaffoldReaderSite(targetDir, options = {}) {
13
13
  await mkdir(path.join(targetRoot, "src", "lib"), { recursive: true });
14
14
  await mkdir(path.join(targetRoot, "src", "pages"), { recursive: true });
15
15
  await mkdir(path.join(targetRoot, "src", "components"), { recursive: true });
16
+ await mkdir(path.join(targetRoot, "src", "styles"), { recursive: true });
16
17
  await mkdir(path.join(targetRoot, "scripts"), { recursive: true });
17
18
  await mkdir(path.join(targetRoot, ".github", "workflows"), { recursive: true });
18
19
  await mkdir(path.join(targetRoot, "public", "downloads"), { recursive: true });
19
20
  await Promise.all([
20
21
  copyFile(path.join(packageRoot, "astro.config.mjs"), path.join(targetRoot, "astro.config.mjs")),
21
22
  copyFile(path.join(packageRoot, "tsconfig.json"), path.join(targetRoot, "tsconfig.json")),
23
+ copyFile(path.join(packageRoot, "src", "middleware.ts"), path.join(targetRoot, "src", "middleware.ts")),
22
24
  cp(path.join(packageRoot, "scripts"), path.join(targetRoot, "scripts"), { recursive: true }),
23
25
  cp(path.join(packageRoot, "src", "components"), path.join(targetRoot, "src", "components"), { recursive: true }),
26
+ cp(path.join(packageRoot, "src", "styles"), path.join(targetRoot, "src", "styles"), { recursive: true }),
24
27
  cp(path.join(packageRoot, "src", "lib"), path.join(targetRoot, "src", "lib"), { recursive: true }),
25
28
  cp(path.join(packageRoot, "src", "layouts"), path.join(targetRoot, "src", "layouts"), { recursive: true }),
26
29
  cp(path.join(packageRoot, "src", "pages"), path.join(targetRoot, "src", "pages"), { recursive: true }),
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,6BAA6B,EAAE,uBAAuB,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AAStH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAiB,EAAE,UAA2B,EAAE;IACvF,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7F,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;IAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,gBAAgB,CAAC,UAAU,CAAC,CAAC;IACxE,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,IAAI,MAAM,yBAAyB,CAAC,WAAW,CAAC,EAAE,CAAC;IACpG,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IAE7D,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1E,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtE,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxE,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7E,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/E,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;QAC/F,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;QACzF,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC5F,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAChH,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAClG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC1G,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KACvG,CAAC,CAAC;IAEH,MAAM,SAAS,CACb,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,EACrC,IAAI,CAAC,SAAS,CACZ;QACE,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,aAAa,EAAE,gCAAgC;YAC/C,MAAM,EAAE,2BAA2B;YACnC,GAAG,EAAE,wBAAwB;YAC7B,KAAK,EAAE,oCAAoC;YAC3C,OAAO,EAAE,eAAe;SACzB;QACD,YAAY,EAAE;YACZ,WAAW,EAAE,cAAc;YAC3B,KAAK,EAAE,SAAS;YAChB,QAAQ,EAAE,QAAQ;YAClB,SAAS,EAAE,SAAS;YACpB,MAAM,EAAE,SAAS;SAClB;QACD,eAAe,EAAE;YACf,aAAa,EAAE,SAAS;YACxB,UAAU,EAAE,QAAQ;SACrB;KACF,EACD,IAAI,EACJ,CAAC,CACF,GAAG,IAAI,EACR,MAAM,CACP,CAAC;IAEF,MAAM,SAAS,CACb,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,CAAC,EACrD,kCAAkC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,EACxE,MAAM,CACP,CAAC;IAEF,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,iBAAiB,CAAC,EAAE,qBAAqB,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;IAC9G,MAAM,SAAS,CACb,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,kBAAkB,CAAC,EACjE,kBAAkB,CAAC,WAAW,CAAC,EAC/B,MAAM,CACP,CAAC;IAEF,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,GAAG,WAAW,IAAI,EAAE,MAAM,CAAC,CAAC;IACxF,CAAC;IAED,MAAM,SAAS,CACb,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,EACrC,kBAAkB,CAAC,QAAQ,CAAC,EAC5B,MAAM,CACP,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,OAAO,GAAG,kBAAkB,CAAC,WAAW,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IACtE,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QAC5B,MAAM,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,0DAA0D,EAAE,MAAM,CAAC,CAAC;IACzH,MAAM,SAAS,CACb,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,EAClC,iBAAiB,CAAC,QAAQ,CAAC,EAC3B,MAAM,CACP,CAAC;IAEF,OAAO;QACL,UAAU;QACV,WAAW;QACX,cAAc;QACd,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAgB;IACzC,OAAO;;;;;;;;;sBASa,OAAO,CAAC,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCtC,CAAC;AACF,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAgB;IAC7C,OAAO,kCAAkC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC;AAClF,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,OAAO;QACL,uBAAuB,OAAO,CAAC,QAAQ,CAAC,EAAE;QAC1C,oCAAoC;QACpC,2BAA2B;QAC3B,iDAAiD;QACjD,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAS,kBAAkB,CAAC,eAA8B,EAAE,QAAgB,EAAE,UAAkB;IAC9F,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;QAC7B,OAAO,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAClE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAG,IAAI,CAAC;QACf,MAAM,YAAY,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,IAAI,YAAY,IAAI,CAAC,6BAA6B,CAAC,YAAY,CAAC,IAAI,8BAA8B,CAAC,YAAY,EAAE,UAAU,CAAC,EAAE,CAAC;YAC7H,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,WAAW,EAAE,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,KAAK,eAAe,EAAE,CAAC;AACzE,CAAC;AAED,SAAS,kBAAkB,CAAC,WAAoB;IAC9C,MAAM,QAAQ,GAAG,WAAW;QAC1B,CAAC,CAAC,CAAC,wBAAwB,EAAE,+BAA+B,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACrF,CAAC,CAAC,4DAA4D,CAAC;IAEjE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuCP,QAAQ;;;;;;;;;;;;;;;;;;CAkBT,CAAC;AACF,CAAC;AAED,SAAS,OAAO,CAAC,KAAa;IAC5B,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAkB;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;SACnC,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,uBAAuB,CAAC;IACtD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,yBAAyB,CAAC,WAAmB;IAC1D,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyB,CAAC;IACvD,OAAO,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "narrarium-astro-reader",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "description": "Astro reader and scaffolding CLI for Narrarium book repositories.",
6
6
  "license": "MIT",
@@ -51,35 +51,66 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
51
51
  <button type="button" class="reader-overlay__close" data-reader-close aria-label="Close reading settings">x</button>
52
52
  <p class="eyebrow">Reading Settings</p>
53
53
  <h2>Reader</h2>
54
- <div class="reader-control-grid">
55
- <label class="reader-control">
56
- <span class="label">Font Size</span>
57
- <input type="range" min="0.92" max="1.22" step="0.02" value="1" data-reader-font-scale />
58
- </label>
59
- <label class="reader-control">
60
- <span class="label">Line Height</span>
61
- <input type="range" min="1.45" max="1.95" step="0.05" value="1.72" data-reader-line-height />
62
- </label>
63
- <label class="reader-control">
64
- <span class="label">Measure</span>
65
- <select data-reader-measure>
66
- <option value="60ch">Compact</option>
67
- <option value="72ch">Classic</option>
68
- <option value="84ch">Wide</option>
69
- </select>
70
- </label>
71
- <label class="reader-control">
72
- <span class="label">Body Font</span>
73
- <select data-reader-font-family>
74
- <option value="classic">Classic Serif</option>
75
- <option value="modern">Modern Serif</option>
76
- <option value="sans">Quiet Sans</option>
77
- </select>
78
- </label>
79
- <label class="reader-control" data-reader-spoiler-wrap hidden>
80
- <span class="label">Spoiler Limit</span>
81
- <select data-reader-spoiler-limit></select>
82
- </label>
54
+ <div class="reader-section">
55
+ <p class="reader-section__label">Appearance</p>
56
+ <div class="reader-control-grid">
57
+ <label class="reader-control">
58
+ <span class="label">Color theme</span>
59
+ <select data-reader-theme>
60
+ <option value="system">System default</option>
61
+ <option value="light">Light</option>
62
+ <option value="dark">Dark</option>
63
+ </select>
64
+ </label>
65
+ </div>
66
+ </div>
67
+ <hr class="reader-section-divider" />
68
+ <div class="reader-section">
69
+ <p class="reader-section__label">Typography</p>
70
+ <div class="reader-control-grid">
71
+ <label class="reader-control">
72
+ <span class="label">Font Size</span>
73
+ <input type="range" min="0.92" max="1.22" step="0.02" value="1" data-reader-font-scale />
74
+ </label>
75
+ <label class="reader-control">
76
+ <span class="label">Line Height</span>
77
+ <input type="range" min="1.45" max="1.95" step="0.05" value="1.72" data-reader-line-height />
78
+ </label>
79
+ <label class="reader-control">
80
+ <span class="label">Measure</span>
81
+ <select data-reader-measure>
82
+ <option value="60ch">Compact</option>
83
+ <option value="72ch">Classic</option>
84
+ <option value="84ch">Wide</option>
85
+ </select>
86
+ </label>
87
+ <label class="reader-control">
88
+ <span class="label">Body Font</span>
89
+ <select data-reader-font-family>
90
+ <option value="classic">Classic Serif</option>
91
+ <option value="modern">Modern Serif</option>
92
+ <option value="sans">Quiet Sans</option>
93
+ </select>
94
+ </label>
95
+ <label class="reader-control" data-reader-spoiler-wrap hidden>
96
+ <span class="label">Spoiler Limit</span>
97
+ <select data-reader-spoiler-limit></select>
98
+ </label>
99
+ </div>
100
+ </div>
101
+ <hr class="reader-section-divider" />
102
+ <div class="reader-section">
103
+ <p class="reader-section__label">Canon access</p>
104
+ <div class="reader-control-grid">
105
+ <label class="reader-control">
106
+ <span class="label">View mode</span>
107
+ <select data-reader-canon-mode>
108
+ <option value="public">Public reader</option>
109
+ <option value="full">Full canon (author)</option>
110
+ </select>
111
+ </label>
112
+ </div>
113
+ <p class="reader-section__note">Full canon shows all hidden character, faction, and item data. Reloads the page. Effective in dev server only; for production, set NARRARIUM_READER_CANON_MODE=full in .env.</p>
83
114
  </div>
84
115
  </aside>
85
116
  </div>
@@ -132,31 +163,20 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
132
163
  initializeThemeToggle();
133
164
  initializeReaderPreferences();
134
165
  initializeReaderSettings();
166
+ initializeSearchOverlay();
167
+ initializeCanonModeToggle();
135
168
  initializeReadingProgress();
136
169
  initializeCanonMentions();
137
170
  initializeReadAloud();
138
171
 
139
172
  function initializeThemeToggle() {
140
- const root = document.documentElement;
141
- const toggle = document.querySelector("[data-theme-toggle]");
142
- if (!toggle) return;
143
-
144
173
  const saved = readStorage(themeStorageKey);
145
174
  const initialTheme = saved || (prefersDarkTheme() ? "dark" : "light");
146
175
  applyTheme(initialTheme);
147
-
148
- toggle.addEventListener("click", () => {
149
- applyTheme(root.dataset.theme === "dark" ? "light" : "dark", true);
150
- });
151
176
  }
152
177
 
153
178
  function applyTheme(theme, persist) {
154
179
  document.documentElement.dataset.theme = theme;
155
- const toggle = document.querySelector("[data-theme-toggle]");
156
- if (toggle) {
157
- toggle.textContent = theme === "dark" ? "Light mode" : "Dark mode";
158
- toggle.setAttribute("aria-label", theme === "dark" ? "Switch to light mode" : "Switch to dark mode");
159
- }
160
180
  if (persist) {
161
181
  writeStorage(themeStorageKey, theme);
162
182
  }
@@ -211,6 +231,21 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
211
231
  if (measureInput) measureInput.value = preferences.measure || "72ch";
212
232
  if (fontFamilyInput) fontFamilyInput.value = preferences.fontFamily || "classic";
213
233
 
234
+ const themeInput = overlay.querySelector("[data-reader-theme]");
235
+ if (themeInput) {
236
+ const savedTheme = readStorage(themeStorageKey);
237
+ themeInput.value = savedTheme || "system";
238
+ themeInput.addEventListener("change", () => {
239
+ const value = themeInput.value;
240
+ if (value === "system") {
241
+ applyTheme(prefersDarkTheme() ? "dark" : "light", false);
242
+ removeStorage(themeStorageKey);
243
+ } else {
244
+ applyTheme(value, true);
245
+ }
246
+ });
247
+ }
248
+
214
249
  if (Number.isFinite(currentPageChapterNumber) && spoilerWrap && spoilerLimitInput) {
215
250
  spoilerWrap.hidden = false;
216
251
  const options = [{ label: "Current chapter", value: String(currentPageChapterNumber) }].concat(
@@ -1210,6 +1245,73 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
1210
1245
  }
1211
1246
  }
1212
1247
 
1248
+ function initializeSearchOverlay() {
1249
+ const overlay = document.querySelector("[data-search-overlay]");
1250
+ const toggle = document.querySelector("[data-search-toggle]");
1251
+ if (!overlay || !toggle) return;
1252
+
1253
+ toggle.addEventListener("click", () => {
1254
+ overlay.hidden = false;
1255
+ document.body.classList.add("has-overlay");
1256
+ const input = overlay.querySelector("[data-search-input]");
1257
+ if (input instanceof HTMLElement) {
1258
+ setTimeout(() => input.focus(), 50);
1259
+ }
1260
+ });
1261
+
1262
+ overlay.addEventListener("click", (event) => {
1263
+ const target = event.target;
1264
+ if (!(target instanceof Element)) return;
1265
+ if (target.closest("[data-search-close]")) {
1266
+ closeSearchOverlay();
1267
+ }
1268
+ });
1269
+
1270
+ document.addEventListener("keydown", (event) => {
1271
+ if (event.key === "Escape" && !overlay.hidden) {
1272
+ closeSearchOverlay();
1273
+ return;
1274
+ }
1275
+ if (
1276
+ overlay.hidden &&
1277
+ (event.key === "/" || ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k")) &&
1278
+ !(document.activeElement instanceof HTMLInputElement) &&
1279
+ !(document.activeElement instanceof HTMLTextAreaElement)
1280
+ ) {
1281
+ event.preventDefault();
1282
+ overlay.hidden = false;
1283
+ document.body.classList.add("has-overlay");
1284
+ const input = overlay.querySelector("[data-search-input]");
1285
+ if (input instanceof HTMLElement) {
1286
+ setTimeout(() => input.focus(), 50);
1287
+ }
1288
+ }
1289
+ });
1290
+ }
1291
+
1292
+ function closeSearchOverlay() {
1293
+ const overlay = document.querySelector("[data-search-overlay]");
1294
+ if (!overlay) return;
1295
+ overlay.hidden = true;
1296
+ document.body.classList.remove("has-overlay");
1297
+ }
1298
+
1299
+ function initializeCanonModeToggle() {
1300
+ const select = document.querySelector("[data-reader-canon-mode]");
1301
+ if (!select) return;
1302
+ const fullCanon = document.body.dataset.fullCanon === "true";
1303
+ select.value = fullCanon ? "full" : "public";
1304
+ select.addEventListener("change", () => {
1305
+ const value = select.value;
1306
+ if (value === "full") {
1307
+ document.cookie = "narrarium-canon=full; path=/; SameSite=Strict";
1308
+ } else {
1309
+ document.cookie = "narrarium-canon=; path=/; max-age=0; SameSite=Strict";
1310
+ }
1311
+ window.location.reload();
1312
+ });
1313
+ }
1314
+
1213
1315
  function escapeRegex(value) {
1214
1316
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1215
1317
  }
@@ -13,23 +13,32 @@ const filters = [
13
13
  ];
14
14
  ---
15
15
 
16
- <div class="site-search" data-site-search>
17
- <label class="site-search__field">
18
- <span class="label">Search</span>
19
- <input type="search" placeholder="Search chapters, scenes, and canon..." data-search-input />
20
- </label>
21
- <div class="site-search__filters" data-search-filters>
22
- {filters.map((filter, index) => (
23
- <button
24
- type="button"
25
- class:list={["site-search__filter", index === 0 && "is-active"]}
26
- data-search-filter={filter.key}
27
- >
28
- {filter.label}
29
- </button>
30
- ))}
16
+ <div class="search-overlay" data-search-overlay hidden>
17
+ <button type="button" class="search-overlay__backdrop" data-search-close aria-label="Close search"></button>
18
+ <div class="search-overlay__panel">
19
+ <div class="search-overlay__head">
20
+ <span class="eyebrow">Search</span>
21
+ <button type="button" class="icon-btn" data-search-close aria-label="Close search">×</button>
22
+ </div>
23
+ <div class="site-search" data-site-search>
24
+ <label class="site-search__field">
25
+ <span class="label">Search</span>
26
+ <input type="search" placeholder="Search chapters, scenes, and canon..." data-search-input />
27
+ </label>
28
+ <div class="site-search__filters" data-search-filters>
29
+ {filters.map((filter, index) => (
30
+ <button
31
+ type="button"
32
+ class:list={["site-search__filter", index === 0 && "is-active"]}
33
+ data-search-filter={filter.key}
34
+ >
35
+ {filter.label}
36
+ </button>
37
+ ))}
38
+ </div>
39
+ <div class="site-search__results" data-search-results hidden></div>
40
+ </div>
31
41
  </div>
32
- <div class="site-search__results" data-search-results hidden></div>
33
42
  </div>
34
43
 
35
44
  <script type="application/json" id="reader-search-data" set:html={entriesJson}></script>
@@ -91,16 +100,6 @@ const filters = [
91
100
  renderResults(input.value);
92
101
  });
93
102
  });
94
- document.addEventListener("click", (event) => {
95
- if (!(event.target instanceof Node) || searchRoot.contains(event.target)) return;
96
- results.hidden = true;
97
- });
98
- document.addEventListener("keydown", (event) => {
99
- if ((event.key === "/" && document.activeElement !== input) || ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k")) {
100
- event.preventDefault();
101
- input.focus();
102
- }
103
- });
104
103
  }
105
104
 
106
105
  function getSpoilerLimit() {
@@ -58,7 +58,7 @@ const isChapterPage = Number.isFinite(currentChapterNumber);
58
58
  })();
59
59
  </script>
60
60
  </head>
61
- <body class:list={[isChapterPage && "page-chapter"]} data-reader-chapter-number={currentChapterNumber}>
61
+ <body class:list={[isChapterPage && "page-chapter"]} data-reader-chapter-number={currentChapterNumber} data-full-canon={fullCanonMode ? "true" : "false"}>
62
62
  <main class="shell">
63
63
  <header class="masthead">
64
64
  <a class="brand" href="./">Narrarium</a>
@@ -73,14 +73,14 @@ const isChapterPage = Number.isFinite(currentChapterNumber);
73
73
  <a class:list={["nav-link", activeSection === "timeline" && "is-active"]} href="timeline/">Timeline</a>
74
74
  </nav>
75
75
  <div class="masthead-actions">
76
- <SiteSearch entries={searchIndex} />
77
76
  <a class="chip reader-status" data-continue-link href="./" hidden>Continue reading</a>
78
- <button type="button" class="theme-toggle" data-reader-settings-toggle aria-label="Open reading settings">Settings</button>
79
- <button type="button" class="theme-toggle" data-theme-toggle aria-label="Switch theme">Dark mode</button>
77
+ <button type="button" class="masthead-btn" data-search-toggle aria-label="Search">🔍</button>
78
+ <button type="button" class="masthead-btn" data-reader-settings-toggle aria-label="Open reading settings">⚙</button>
80
79
  </div>
81
80
  </header>
82
81
  <slot />
83
82
  </main>
84
83
  <ReaderRuntime glossary={canonGlossary} chapters={readerChapters} currentChapterNumber={currentChapterNumber} />
84
+ <SiteSearch entries={searchIndex} />
85
85
  </body>
86
86
  </html>
@@ -0,0 +1,24 @@
1
+ import { defineMiddleware } from "astro:middleware";
2
+
3
+ // Reads the `narrarium-canon=full` cookie and temporarily sets
4
+ // process.env.NARRARIUM_READER_CANON_MODE for the duration of the request.
5
+ // This lets the dev server honour the in-browser canon-mode toggle without
6
+ // restarting the server. It is a no-op during production static builds
7
+ // because there are no cookies at build time.
8
+ export const onRequest = defineMiddleware(async (context, next) => {
9
+ const cookie = context.request.headers.get("cookie") ?? "";
10
+ const cookieRequiresFull = cookie.split(";").some((part) => part.trim() === "narrarium-canon=full");
11
+ const envAlreadyFull = Boolean(process.env.NARRARIUM_READER_CANON_MODE);
12
+
13
+ if (cookieRequiresFull && !envAlreadyFull) {
14
+ process.env.NARRARIUM_READER_CANON_MODE = "full";
15
+ }
16
+
17
+ const response = await next();
18
+
19
+ if (cookieRequiresFull && !envAlreadyFull) {
20
+ delete process.env.NARRARIUM_READER_CANON_MODE;
21
+ }
22
+
23
+ return response;
24
+ });
package/src/scaffold.ts CHANGED
@@ -22,6 +22,7 @@ export async function scaffoldReaderSite(targetDir: string, options: ScaffoldOpt
22
22
  await mkdir(path.join(targetRoot, "src", "lib"), { recursive: true });
23
23
  await mkdir(path.join(targetRoot, "src", "pages"), { recursive: true });
24
24
  await mkdir(path.join(targetRoot, "src", "components"), { recursive: true });
25
+ await mkdir(path.join(targetRoot, "src", "styles"), { recursive: true });
25
26
  await mkdir(path.join(targetRoot, "scripts"), { recursive: true });
26
27
  await mkdir(path.join(targetRoot, ".github", "workflows"), { recursive: true });
27
28
  await mkdir(path.join(targetRoot, "public", "downloads"), { recursive: true });
@@ -29,8 +30,10 @@ export async function scaffoldReaderSite(targetDir: string, options: ScaffoldOpt
29
30
  await Promise.all([
30
31
  copyFile(path.join(packageRoot, "astro.config.mjs"), path.join(targetRoot, "astro.config.mjs")),
31
32
  copyFile(path.join(packageRoot, "tsconfig.json"), path.join(targetRoot, "tsconfig.json")),
33
+ copyFile(path.join(packageRoot, "src", "middleware.ts"), path.join(targetRoot, "src", "middleware.ts")),
32
34
  cp(path.join(packageRoot, "scripts"), path.join(targetRoot, "scripts"), { recursive: true }),
33
35
  cp(path.join(packageRoot, "src", "components"), path.join(targetRoot, "src", "components"), { recursive: true }),
36
+ cp(path.join(packageRoot, "src", "styles"), path.join(targetRoot, "src", "styles"), { recursive: true }),
34
37
  cp(path.join(packageRoot, "src", "lib"), path.join(targetRoot, "src", "lib"), { recursive: true }),
35
38
  cp(path.join(packageRoot, "src", "layouts"), path.join(targetRoot, "src", "layouts"), { recursive: true }),
36
39
  cp(path.join(packageRoot, "src", "pages"), path.join(targetRoot, "src", "pages"), { recursive: true }),
@@ -249,52 +249,29 @@ body.tts-enabled .shell {
249
249
  }
250
250
 
251
251
  /* ─── Icon buttons (masthead controls) ──────────────────────── */
252
- .theme-toggle {
252
+ .masthead-btn {
253
253
  display: inline-flex;
254
254
  align-items: center;
255
255
  justify-content: center;
256
- gap: 0.3rem;
256
+ width: 2.1rem;
257
257
  height: 2.1rem;
258
- padding: 0 0.7rem;
259
258
  border: 1px solid var(--line);
260
259
  border-radius: 8px;
261
260
  background: transparent;
262
261
  color: var(--text-muted);
263
- font: inherit;
264
- font-size: 0.82rem;
265
- font-weight: 500;
262
+ font-size: 1rem;
263
+ line-height: 1;
266
264
  cursor: pointer;
265
+ padding: 0;
267
266
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
268
- white-space: nowrap;
269
267
  }
270
268
 
271
- .theme-toggle:hover {
269
+ .masthead-btn:hover {
272
270
  background: var(--surface-muted);
273
271
  color: var(--text);
274
272
  border-color: color-mix(in srgb, var(--accent) 25%, var(--line));
275
273
  }
276
274
 
277
- /* Theme icon via CSS pseudo-element – JS still sets textContent */
278
- [data-theme-toggle]::before {
279
- font-size: 0.95em;
280
- line-height: 1;
281
- }
282
-
283
- html[data-theme="dark"] [data-theme-toggle]::before {
284
- content: "☀ ";
285
- }
286
-
287
- :root:not([data-theme="dark"]) [data-theme-toggle]::before {
288
- content: "🌙 ";
289
- }
290
-
291
- /* Settings button icon */
292
- [data-reader-settings-toggle]::before {
293
- content: "⚙ ";
294
- font-size: 0.9em;
295
- line-height: 1;
296
- }
297
-
298
275
  /* Primary TTS play button */
299
276
  .tts-button.is-primary {
300
277
  background: var(--accent);
@@ -1156,6 +1133,109 @@ mark {
1156
1133
  font-size: 1.1rem;
1157
1134
  }
1158
1135
 
1136
+ /* ─── Search overlay ─────────────────────────────────────────── */
1137
+ .search-overlay {
1138
+ position: fixed;
1139
+ inset: 0;
1140
+ z-index: 50;
1141
+ display: flex;
1142
+ align-items: flex-start;
1143
+ justify-content: center;
1144
+ padding-top: 5rem;
1145
+ }
1146
+
1147
+ .search-overlay__backdrop {
1148
+ position: absolute;
1149
+ inset: 0;
1150
+ border: 0;
1151
+ background: rgba(0, 0, 0, 0.45);
1152
+ backdrop-filter: blur(4px);
1153
+ -webkit-backdrop-filter: blur(4px);
1154
+ cursor: default;
1155
+ }
1156
+
1157
+ .search-overlay__panel {
1158
+ position: relative;
1159
+ z-index: 1;
1160
+ width: min(640px, calc(100vw - 2rem));
1161
+ max-height: calc(100vh - 7rem);
1162
+ overflow: auto;
1163
+ background: var(--surface);
1164
+ border: 1px solid var(--line);
1165
+ border-radius: 16px;
1166
+ box-shadow: var(--shadow);
1167
+ padding: 1.25rem;
1168
+ }
1169
+
1170
+ .search-overlay__head {
1171
+ display: flex;
1172
+ align-items: center;
1173
+ justify-content: space-between;
1174
+ margin-bottom: 1rem;
1175
+ }
1176
+
1177
+ .search-overlay .site-search {
1178
+ min-width: 0;
1179
+ width: 100%;
1180
+ }
1181
+
1182
+ .search-overlay .site-search__results {
1183
+ position: static;
1184
+ border: 0;
1185
+ box-shadow: none;
1186
+ border-radius: 0;
1187
+ padding: 0;
1188
+ margin-top: 0.5rem;
1189
+ }
1190
+
1191
+ .icon-btn {
1192
+ display: inline-flex;
1193
+ align-items: center;
1194
+ justify-content: center;
1195
+ width: 2rem;
1196
+ height: 2rem;
1197
+ border: 1px solid var(--line);
1198
+ border-radius: 8px;
1199
+ background: var(--surface-muted);
1200
+ color: var(--text-muted);
1201
+ font-size: 1.1rem;
1202
+ line-height: 1;
1203
+ cursor: pointer;
1204
+ transition: background 120ms ease, color 120ms ease;
1205
+ }
1206
+
1207
+ .icon-btn:hover {
1208
+ background: var(--surface-strong);
1209
+ color: var(--text);
1210
+ }
1211
+
1212
+ /* ─── Reader settings sections ───────────────────────────────── */
1213
+ .reader-section {
1214
+ margin-top: 1.25rem;
1215
+ }
1216
+
1217
+ .reader-section__label {
1218
+ color: var(--text-muted);
1219
+ font-size: 0.75rem;
1220
+ font-weight: 600;
1221
+ letter-spacing: 0.09em;
1222
+ text-transform: uppercase;
1223
+ margin: 0 0 0.25rem;
1224
+ }
1225
+
1226
+ .reader-section__note {
1227
+ margin: 0.6rem 0 0;
1228
+ color: var(--text-muted);
1229
+ font-size: 0.82rem;
1230
+ line-height: 1.55;
1231
+ }
1232
+
1233
+ .reader-section-divider {
1234
+ border: 0;
1235
+ border-top: 1px solid var(--line);
1236
+ margin: 1.25rem 0 0;
1237
+ }
1238
+
1159
1239
  /* ─── Responsive ─────────────────────────────────────────────── */
1160
1240
  @media (max-width: 900px) {
1161
1241
  .masthead {
@@ -1208,7 +1288,7 @@ mark {
1208
1288
  min-width: 0;
1209
1289
  }
1210
1290
 
1211
- .theme-toggle,
1291
+ .masthead-btn,
1212
1292
  .focus-rail__button,
1213
1293
  .focus-rail__link {
1214
1294
  width: 100%;