@leadertechie/personal-site-kit 0.1.0-alpha.16 → 0.1.0-alpha.18

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
@@ -1,6 +1,6 @@
1
1
  # @leadertechie/personal-site-kit
2
2
 
3
- A high-performance, modular engine for building personal websites and professional portfolios. Powered by Cloudflare Workers, R2 Storage, and Lit Web Components.
3
+ A high-performance, modular engine for building personal websites and professional portfolios. Powered by Cloudflare Workers, R2 Storage, Lit Web Components, and the **@leadertechie** ecosystem.
4
4
 
5
5
  ## Features
6
6
 
@@ -8,18 +8,21 @@ A high-performance, modular engine for building personal websites and profession
8
8
  - **🛠️ 4-Section Engine**: Fully integrated logic for **API**, **UI**, **Prerender**, and **Admin**.
9
9
  - **🎨 Modern Layout**: Semantic grid system with responsive `main-column` and `sidebar-column` components.
10
10
  - **🌓 Theme Engine**: Built-in light/dark mode support with persistent user preferences.
11
- - **📝 Content Driven**: Dynamic Markdown rendering with frontmatter support via `@leadertechie/md2html`.
11
+ - **📝 Content Driven**: Dynamic Markdown rendering with frontmatter support via `@leadertechie/md2html` (v2).
12
12
  - **⚙️ Remote Config**: Manage site settings (title, copyright, social links) directly from R2 without re-deploying.
13
13
  - **🔍 SEO Optimized**: Server-side prerendering ensures search engines see your content perfectly.
14
+ - **🔄 SWR Caching**: Stale-while-revalidate caching via `@leadertechie/r2tohtml` for optimal performance.
15
+ - **⚡ Client-Side Interactivity**: DOM interaction patterns (poll, live-update, click-toggle, infinite-scroll, form-live) via `@leadertechie/md2interact`.
16
+ - **🎯 CSS Hydration**: Inline critical CSS, layer injection, and theme toggle support.
14
17
 
15
18
  ## Architecture
16
19
 
17
20
  The kit is divided into four logical subpaths:
18
21
 
19
- 1. **/shared**: Common interfaces, types, and the reactive `SiteStore`.
20
- 2. **/ui**: Web components for the Banner, Footer, About Me, and Admin Portal.
21
- 3. **/api**: Standard handlers for Cloudflare Workers to manage R2 content.
22
- 4. **/prerender**: SEO engine to generate static HTML for crawlers.
22
+ 1. **/shared**: Common interfaces, types, the reactive `SiteStore`, and the `WebsiteUI` bootstrap.
23
+ 2. **/ui**: Web components for the Banner, Footer, About Me, Blog Viewer, Story Viewer, and Admin Portal.
24
+ 3. **/api**: Standard handlers for Cloudflare Workers to manage R2 content with v2 caching.
25
+ 4. **/prerender**: SEO engine to generate static HTML for crawlers with SWR caching.
23
26
 
24
27
  ## Installation
25
28
 
@@ -29,26 +32,100 @@ npm install @leadertechie/personal-site-kit
29
32
 
30
33
  ## Quick Start (Usage)
31
34
 
32
- ### 1. API Worker (`api.ts`)
35
+ ### 1. API Worker (`api/index.ts`)
36
+
33
37
  ```typescript
34
- import { handleAPIRoute } from '@leadertechie/personal-site-kit/api';
38
+ import { WebsiteAPI } from '@leadertechie/personal-site-kit/api';
39
+
40
+ export default new WebsiteAPI();
41
+ ```
42
+
43
+ ### 2. UI Entry (`ui/index.ts`)
35
44
 
36
- export default {
37
- async fetch(request, env) {
38
- return handleAPIRoute(request, env);
45
+ ```typescript
46
+ import { WebsiteUI } from '@leadertechie/personal-site-kit/shared';
47
+ import '@leadertechie/personal-site-kit/styles/theme.css';
48
+ import '@leadertechie/personal-site-kit/ui';
49
+
50
+ // Bootstrap the UI — md2interact is automatically initialized
51
+ WebsiteUI.getInstance({
52
+ apiUrl: window.location.origin,
53
+ // Optional: configure md2interact interactions
54
+ interactConfig: {
55
+ interactions: {
56
+ 'poll': { selector: '[data-interact="poll"]' },
57
+ 'live-update': { selector: '[data-interact="live-update"]' },
58
+ 'click-toggle': { selector: '[data-interact="click-toggle"]' },
59
+ 'infinite-scroll': { selector: '[data-interact="infinite-scroll"]' },
60
+ 'form-live': { selector: '[data-interact="form-live"]' }
61
+ },
62
+ cssHydration: {
63
+ inlineCritical: true,
64
+ layerInjection: true,
65
+ themeToggle: true
66
+ }
39
67
  }
40
- };
68
+ }).bootstrap();
41
69
  ```
42
70
 
43
- ### 2. UI Entry (`main.ts`)
71
+ ### 3. Prerender (`prerender/index.ts`)
72
+
44
73
  ```typescript
45
- import { SiteStore } from '@leadertechie/personal-site-kit/shared';
46
- import '@leadertechie/personal-site-kit/ui/banner';
74
+ import { WebsitePrerender } from '@leadertechie/personal-site-kit/prerender';
47
75
 
48
- const store = SiteStore.getInstance();
49
- await store.init({ apiUrl: 'https://api.yourdomain.com' });
76
+ export default new WebsitePrerender();
50
77
  ```
51
78
 
79
+ ## Client-Side Interactivity with md2interact
80
+
81
+ The kit automatically initializes `@leadertechie/md2interact` during `WebsiteUI.bootstrap()`. This enables:
82
+
83
+ ### DOM Interaction Patterns
84
+
85
+ Markdown content with frontmatter can declare interaction patterns:
86
+
87
+ ```markdown
88
+ ---
89
+ interaction: poll
90
+ interactConfig:
91
+ url: /api/data
92
+ interval: 5000
93
+ ---
94
+
95
+ # Live Poll Data
96
+ ```
97
+
98
+ Supported patterns: `poll`, `live-update`, `click-toggle`, `infinite-scroll`, `form-live`, `mfe`, `custom`
99
+
100
+ ### CSS Hydration
101
+
102
+ - **inlineCritical**: Injects critical CSS directly into the DOM
103
+ - **layerInjection**: Uses CSS `@layer` for organized style injection
104
+ - **themeToggle**: Enables light/dark theme toggling
105
+
106
+ ### SPA Navigation
107
+
108
+ After dynamic content loads (e.g., blog detail pages), call `reinitInteract()` to re-scan the DOM:
109
+
110
+ ```typescript
111
+ const ui = WebsiteUI.getInstance();
112
+ ui.reinitInteract();
113
+ ```
114
+
115
+ ## Caching Strategy (v2)
116
+
117
+ The kit uses `@leadertechie/r2tohtml` with a multi-tier caching strategy:
118
+
119
+ | Tier | Cache | TTL |
120
+ |------|-------|-----|
121
+ | In-Memory | `ContentCacheV2` with SWR | 5 min fresh, 30 min stale |
122
+ | Cloudflare Edge | `cfCache` | 5 min |
123
+
124
+ This means:
125
+ - **Fresh**: Served instantly from memory
126
+ - **Stale**: Served from memory while revalidating in background (SWR)
127
+ - **Miss**: Fetched from R2, cached at edge and in-memory
128
+
52
129
  ## Deployment
53
130
 
54
131
  This kit is designed to be deployed to **Cloudflare**. Ensure your `wrangler.toml` is configured with an R2 bucket named `CONTENT_BUCKET`.
@@ -1 +1 @@
1
- {"version":3,"file":"content-utils.d.ts","sourceRoot":"","sources":["../../src/api/content-utils.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAS,SAAQ,eAAe;IAC/C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAU,SAAQ,eAAe;IAChD,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAStF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAUvD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CA6BhG;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,QAAQ,GAAG,IAAI,CAK5D;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAqB1H;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAiB1H;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,QAAQ,GAAG,SAAS,CAAC,EAAE,CAAC,CA2BjG"}
1
+ {"version":3,"file":"content-utils.d.ts","sourceRoot":"","sources":["../../src/api/content-utils.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAS,SAAQ,eAAe;IAC/C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAU,SAAQ,eAAe;IAChD,OAAO,EAAE,MAAM,CAAC;CACjB;AASD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAoBtF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAMvD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CA6BhG;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG,QAAQ,GAAG,IAAI,CAK5D;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAqB1H;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAiB1H;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,QAAQ,GAAG,SAAS,CAAC,EAAE,CAAC,CA2BjG"}
@@ -1 +1 @@
1
- {"version":3,"file":"about-me.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/about-me.ts"],"names":[],"mappings":"AA4CA,wBAAgB,iBAAiB,SAEhC;AAED,wBAAsB,aAAa,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4DhE"}
1
+ {"version":3,"file":"about-me.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/about-me.ts"],"names":[],"mappings":"AA0DA,wBAAgB,iBAAiB,SAEhC;AAED,wBAAsB,aAAa,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4DhE"}
@@ -1 +1 @@
1
- {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/content.ts"],"names":[],"mappings":"AAoBA,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqElG"}
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/content.ts"],"names":[],"mappings":"AAqBA,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqElG"}
@@ -1 +1 @@
1
- {"version":3,"file":"home.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/home.ts"],"names":[],"mappings":"AAiCA,wBAAgB,iBAAiB,SAEhC;AAED,wBAAsB,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwC7D"}
1
+ {"version":3,"file":"home.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/home.ts"],"names":[],"mappings":"AA+CA,wBAAgB,iBAAiB,SAEhC;AAED,wBAAsB,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwC7D"}
package/dist/api.js CHANGED
@@ -1,5 +1,5 @@
1
- import { W as WebsiteAPI } from "./chunks/website-api-C3lGjXdD.js";
2
- import { A, B, M, R, c, a, g, b, d, h, e, r, s, v } from "./chunks/website-api-C3lGjXdD.js";
1
+ import { W as WebsiteAPI } from "./chunks/website-api-DBEh24zq.js";
2
+ import { A, B, M, R, c, a, g, b, d, h, e, r, s, v } from "./chunks/website-api-DBEh24zq.js";
3
3
  const defaultAPI = new WebsiteAPI();
4
4
  export {
5
5
  A as AUTH_KV,
@@ -2385,9 +2385,20 @@ var __privateMethod$1 = (obj, member, method) => (__accessCheck$1(obj, member, "
2385
2385
  var _error_dec$1, _loading_dec$1, _blogPost_dec, _slug_dec$1, _a$1, _BlogViewer_decorators, _init$1, _slug$1, _blogPost, _loading$1, _error$1;
2386
2386
  const pipeline$1 = new MarkdownPipeline({
2387
2387
  imagePathPrefix: "images/",
2388
+ preserveRawHTML: true,
2389
+ errorRecovery: "warn",
2390
+ maxRecursionDepth: 50,
2388
2391
  styleOptions: {
2389
2392
  classPrefix: "md-",
2390
- addHeadingIds: true
2393
+ addHeadingIds: true,
2394
+ emitScopeAnchors: true
2395
+ },
2396
+ slotPattern: /\[\[(.*?)\]\]/g,
2397
+ onSlot: (name) => {
2398
+ const slotMap = {
2399
+ "CURRENT_YEAR": (/* @__PURE__ */ new Date()).getFullYear().toString()
2400
+ };
2401
+ return slotMap[name] || `[[${name}]]`;
2391
2402
  }
2392
2403
  });
2393
2404
  _BlogViewer_decorators = [customElement("my-blog-viewer")];
@@ -2583,9 +2594,20 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
2583
2594
  var _error_dec, _loading_dec, _storyPost_dec, _slug_dec, _a, _StoryViewer_decorators, _init, _slug, _storyPost, _loading, _error;
2584
2595
  const pipeline = new MarkdownPipeline({
2585
2596
  imagePathPrefix: "images/",
2597
+ preserveRawHTML: true,
2598
+ errorRecovery: "warn",
2599
+ maxRecursionDepth: 50,
2586
2600
  styleOptions: {
2587
2601
  classPrefix: "md-",
2588
- addHeadingIds: true
2602
+ addHeadingIds: true,
2603
+ emitScopeAnchors: true
2604
+ },
2605
+ slotPattern: /\[\[(.*?)\]\]/g,
2606
+ onSlot: (name) => {
2607
+ const slotMap = {
2608
+ "CURRENT_YEAR": (/* @__PURE__ */ new Date()).getFullYear().toString()
2609
+ };
2610
+ return slotMap[name] || `[[${name}]]`;
2589
2611
  }
2590
2612
  });
2591
2613
  _StoryViewer_decorators = [customElement("my-story-viewer")];
@@ -1,10 +1,23 @@
1
1
  import { S as SiteStore } from "./site-store-CGV9c2DI.js";
2
2
  import { MarkdownPipeline } from "@leadertechie/r2tohtml";
3
+ import { init, reinit } from "@leadertechie/md2interact";
3
4
  const pipeline = new MarkdownPipeline({
4
5
  imagePathPrefix: "images/",
6
+ preserveRawHTML: true,
7
+ errorRecovery: "warn",
8
+ maxRecursionDepth: 50,
5
9
  styleOptions: {
6
10
  classPrefix: "md-",
7
- addHeadingIds: true
11
+ addHeadingIds: true,
12
+ emitScopeAnchors: true
13
+ },
14
+ slotPattern: /\[\[(.*?)\]\]/g,
15
+ onSlot: (name) => {
16
+ const slotMap = {
17
+ "SITE_TITLE": document?.querySelector("title")?.textContent || "My Site",
18
+ "CURRENT_YEAR": (/* @__PURE__ */ new Date()).getFullYear().toString()
19
+ };
20
+ return slotMap[name] || `[[${name}]]`;
8
21
  }
9
22
  });
10
23
  const renderMarkdown = (content) => {
@@ -277,6 +290,13 @@ class Router {
277
290
  }
278
291
  canonicalLink.setAttribute("href", url);
279
292
  }
293
+ /**
294
+ * After rendering new content, reinitialize md2interact so it
295
+ * re-scans the DOM for interaction elements (poll, live-update, etc.)
296
+ */
297
+ afterRender() {
298
+ this.ui.reinitInteract();
299
+ }
280
300
  async renderHomePage() {
281
301
  let blogs = [];
282
302
  let stories = [];
@@ -311,6 +331,7 @@ class Router {
311
331
  });
312
332
  if (this.appElement) this.appElement.innerHTML = pageContent.content;
313
333
  this.setPageMeta(pageContent.title, pageContent.description, pageContent.canonicalUrl);
334
+ this.afterRender();
314
335
  }
315
336
  renderAboutMePage() {
316
337
  const pageContent = generatePageContent("/about-me", this.routes, this.footerLinks, {
@@ -320,6 +341,7 @@ class Router {
320
341
  });
321
342
  if (this.appElement) this.appElement.innerHTML = pageContent.content;
322
343
  this.setPageMeta(pageContent.title, pageContent.description, pageContent.canonicalUrl);
344
+ this.afterRender();
323
345
  }
324
346
  async renderContentListPage(pathname) {
325
347
  const type = pathname === "/blogs" ? "blogs" : "stories";
@@ -338,6 +360,7 @@ class Router {
338
360
  });
339
361
  if (this.appElement) this.appElement.innerHTML = pageContent.content;
340
362
  this.setPageMeta(pageContent.title, pageContent.description, pageContent.canonicalUrl);
363
+ this.afterRender();
341
364
  }
342
365
  async renderContentDetailPage(pathname) {
343
366
  const isBlog = pathname.startsWith("/blogs/");
@@ -357,6 +380,7 @@ class Router {
357
380
  });
358
381
  if (this.appElement) this.appElement.innerHTML = pageContent.content;
359
382
  this.setPageMeta(`${slug.replace(/-/g, " ")} - ${this.siteTitle}`, "Read more content", window.location.href);
383
+ this.afterRender();
360
384
  }
361
385
  async renderAdminPage() {
362
386
  generatePageContent("/admin", this.routes, this.footerLinks, {
@@ -377,11 +401,13 @@ class Router {
377
401
  <my-footer copyright="${this.copyright}" footerLinks='${JSON.stringify(this.footerLinks)}'></my-footer>
378
402
  `;
379
403
  }
404
+ this.afterRender();
380
405
  }
381
406
  }
382
407
  class WebsiteUI {
383
408
  constructor(config = {}) {
384
409
  this.router = null;
410
+ this.interactInitialized = false;
385
411
  this.store = SiteStore.getInstance();
386
412
  this.config = config;
387
413
  }
@@ -411,11 +437,44 @@ class WebsiteUI {
411
437
  this.updateBanner(this.store.getConfig());
412
438
  this.router = new Router(this);
413
439
  this.router.init(this.config.appElementId || "app");
440
+ this.initInteract();
414
441
  if (this.config.onBootstrap) {
415
442
  await this.config.onBootstrap(this);
416
443
  }
417
444
  console.log("WebsiteUI bootstrapped");
418
445
  }
446
+ /**
447
+ * Initialize md2interact for client-side DOM interactions,
448
+ * CSS hydration, and event bus communication.
449
+ */
450
+ initInteract() {
451
+ if (this.interactInitialized) return;
452
+ const interactCfg = this.config.interactConfig || {};
453
+ init({
454
+ interactions: interactCfg.interactions || {
455
+ "poll": { selector: '[data-interact="poll"]' },
456
+ "live-update": { selector: '[data-interact="live-update"]' },
457
+ "click-toggle": { selector: '[data-interact="click-toggle"]' },
458
+ "infinite-scroll": { selector: '[data-interact="infinite-scroll"]' },
459
+ "form-live": { selector: '[data-interact="form-live"]' }
460
+ },
461
+ cssHydration: interactCfg.cssHydration || {
462
+ inlineCritical: true,
463
+ layerInjection: true,
464
+ themeToggle: true
465
+ }
466
+ });
467
+ this.interactInitialized = true;
468
+ }
469
+ /**
470
+ * Reinitialize md2interact after dynamic content changes (e.g., SPA navigation).
471
+ * This re-scans the DOM for new interaction elements.
472
+ */
473
+ reinitInteract() {
474
+ if (this.interactInitialized) {
475
+ reinit();
476
+ }
477
+ }
419
478
  updateBanner(config) {
420
479
  const banner = document.querySelector("my-banner");
421
480
  if (banner) {
@@ -493,13 +552,12 @@ class ThemeToggle extends HTMLElement {
493
552
  cursor: pointer;
494
553
  font-size: 1.5rem;
495
554
  padding: 0.5rem;
496
- color: var(--text-color, #213547); /* Default for light mode */
555
+ color: var(--text-color, #213547);
497
556
  transition: color 0.3s ease;
498
557
  }
499
558
  button:hover {
500
- color: var(--primary-color, #747bff); /* Hover color */
559
+ color: var(--primary-color, #747bff);
501
560
  }
502
- /* Dark mode specific styles for the button */
503
561
  html[data-theme='dark'] button {
504
562
  color: var(--dark-mode-text-color, rgba(255, 255, 255, 0.87));
505
563
  }
@@ -508,7 +566,7 @@ class ThemeToggle extends HTMLElement {
508
566
  }
509
567
  </style>
510
568
  <button id="theme-toggle" aria-label="Toggle theme">
511
- <span class="icon">${this.getSunIcon()}</span> <!-- Default to sun for light mode -->
569
+ <span class="icon">${this.getSunIcon()}</span>
512
570
  </button>
513
571
  `;
514
572
  }
@@ -1,4 +1,4 @@
1
- import { R2ContentLoader } from "@leadertechie/r2tohtml";
1
+ import { ContentCacheV2, R2ContentLoader } from "@leadertechie/r2tohtml";
2
2
  function createJSONResponse(data, status = 200) {
3
3
  return new Response(JSON.stringify(data), {
4
4
  status,
@@ -9,6 +9,14 @@ function createErrorResponse(message, status = 500) {
9
9
  return createJSONResponse({ error: message }, status);
10
10
  }
11
11
  let loader$1 = null;
12
+ new ContentCacheV2(
13
+ 5 * 60 * 1e3,
14
+ // TTL: 5 minutes fresh
15
+ true,
16
+ // enabled
17
+ 30 * 60 * 1e3
18
+ // SWR TTL: 30 minutes stale window
19
+ );
12
20
  function getLoader$1(env) {
13
21
  if (!env?.CONTENT_BUCKET) {
14
22
  return null;
@@ -17,14 +25,24 @@ function getLoader$1(env) {
17
25
  loader$1 = new R2ContentLoader(
18
26
  {
19
27
  bucket: env.CONTENT_BUCKET,
20
- cacheTTL: 5 * 60 * 1e3
28
+ cacheTTL: 5 * 60 * 1e3,
29
+ cfCache: true,
30
+ // Enable Cloudflare edge cache tier
31
+ cfCacheTTL: 300,
32
+ // CF cache for 5 minutes
33
+ swrTTL: 30 * 60 * 1e3
34
+ // SWR window: 30 minutes
21
35
  },
22
36
  {
23
37
  md2html: {
24
38
  imagePathPrefix: "images/",
39
+ preserveRawHTML: true,
40
+ errorRecovery: "warn",
41
+ maxRecursionDepth: 50,
25
42
  styleOptions: {
26
43
  classPrefix: "md-",
27
- addHeadingIds: true
44
+ addHeadingIds: true,
45
+ emitScopeAnchors: true
28
46
  }
29
47
  }
30
48
  }
@@ -32,7 +50,7 @@ function getLoader$1(env) {
32
50
  }
33
51
  return loader$1;
34
52
  }
35
- function clearContentCache$1() {
53
+ function clearContentCache$2() {
36
54
  loader$1?.clearCache();
37
55
  }
38
56
  async function handleAboutMe(env) {
@@ -89,19 +107,37 @@ async function handleAboutMe(env) {
89
107
  }
90
108
  }
91
109
  let loader = null;
110
+ new ContentCacheV2(
111
+ 5 * 60 * 1e3,
112
+ // TTL: 5 minutes fresh
113
+ true,
114
+ // enabled
115
+ 30 * 60 * 1e3
116
+ // SWR TTL: 30 minutes stale window
117
+ );
92
118
  function getLoader(env) {
93
119
  if (!loader && env?.CONTENT_BUCKET) {
94
120
  loader = new R2ContentLoader(
95
121
  {
96
122
  bucket: env.CONTENT_BUCKET,
97
- cacheTTL: 5 * 60 * 1e3
123
+ cacheTTL: 5 * 60 * 1e3,
124
+ cfCache: true,
125
+ // Enable Cloudflare edge cache tier
126
+ cfCacheTTL: 300,
127
+ // CF cache for 5 minutes
128
+ swrTTL: 30 * 60 * 1e3
129
+ // SWR window: 30 minutes
98
130
  },
99
131
  {
100
132
  md2html: {
101
133
  imagePathPrefix: "images/",
134
+ preserveRawHTML: true,
135
+ errorRecovery: "warn",
136
+ maxRecursionDepth: 50,
102
137
  styleOptions: {
103
138
  classPrefix: "md-",
104
- addHeadingIds: true
139
+ addHeadingIds: true,
140
+ emitScopeAnchors: true
105
141
  }
106
142
  }
107
143
  }
@@ -109,7 +145,7 @@ function getLoader(env) {
109
145
  }
110
146
  return loader;
111
147
  }
112
- function clearContentCache() {
148
+ function clearContentCache$1() {
113
149
  loader?.clearCache();
114
150
  }
115
151
  async function handleHome(env) {
@@ -259,6 +295,128 @@ async function verifyCredentials(env, username, password) {
259
295
  function getClientIP(request) {
260
296
  return request.headers.get("CF-Connecting-IP") || request.headers.get("X-Forwarded-For")?.split(",")[0]?.trim() || "unknown";
261
297
  }
298
+ const contentCache = new ContentCacheV2(
299
+ 5 * 60 * 1e3,
300
+ // TTL: 5 minutes fresh
301
+ true,
302
+ // enabled
303
+ 30 * 60 * 1e3
304
+ // SWR TTL: 30 minutes stale window
305
+ );
306
+ function getCachedOrFetch(key, fetchFn) {
307
+ const cached = contentCache.get(key);
308
+ if (cached) {
309
+ if (!cached.stale) {
310
+ return Promise.resolve(cached.data);
311
+ }
312
+ fetchFn().then((data) => {
313
+ contentCache.set(key, data);
314
+ contentCache.refresh(key);
315
+ }).catch(() => {
316
+ });
317
+ return Promise.resolve(cached.data);
318
+ }
319
+ return fetchFn().then((data) => {
320
+ contentCache.set(key, data);
321
+ return data;
322
+ });
323
+ }
324
+ function clearContentCache(prefix) {
325
+ {
326
+ contentCache.clear();
327
+ }
328
+ }
329
+ function parseFrontmatter(content) {
330
+ const lines = content.split("\n");
331
+ const metadata = {};
332
+ let contentStart = 0;
333
+ if (lines[0]?.trim() === "---") {
334
+ for (let i = 1; i < lines.length; i++) {
335
+ if (lines[i]?.trim() === "---") {
336
+ contentStart = i + 1;
337
+ break;
338
+ }
339
+ const colonIdx = lines[i].indexOf(":");
340
+ if (colonIdx > 0) {
341
+ const key = lines[i].slice(0, colonIdx).trim();
342
+ let value = lines[i].slice(colonIdx + 1).trim();
343
+ if (value.startsWith("[") && value.endsWith("]")) {
344
+ value = value.slice(1, -1);
345
+ metadata[key] = value.split(",").map((v) => v.trim());
346
+ } else {
347
+ metadata[key] = value;
348
+ }
349
+ }
350
+ }
351
+ }
352
+ return {
353
+ metadata,
354
+ content: lines.slice(contentStart).join("\n").trim()
355
+ };
356
+ }
357
+ function checkContentBucket(env) {
358
+ if (!env?.CONTENT_BUCKET) {
359
+ return createErrorResponse("Content bucket not configured", 500);
360
+ }
361
+ return null;
362
+ }
363
+ async function fetchContentItem(bucket, type, slug) {
364
+ const mdObj = await bucket.get(`${type}/${slug}.md`);
365
+ const jsonObj = await bucket.get(`${type}/${slug}.json`);
366
+ if (!mdObj && !jsonObj) throw new Error(`${type.slice(0, -1)} not found`);
367
+ let metadata = {};
368
+ if (jsonObj) {
369
+ metadata = await jsonObj.json();
370
+ }
371
+ let content = "";
372
+ if (mdObj) {
373
+ const text = await mdObj.text();
374
+ const parsed = parseFrontmatter(text);
375
+ content = parsed.content;
376
+ metadata = { ...parsed.metadata, ...metadata };
377
+ }
378
+ return { ...metadata, slug, content };
379
+ }
380
+ async function fetchContentList(bucket, type, latest) {
381
+ const list = await bucket.list({ prefix: `${type}/` });
382
+ const items = [];
383
+ for (const item of list.objects) {
384
+ if (item.key.endsWith(".json")) {
385
+ const obj = await bucket.get(item.key);
386
+ if (obj) {
387
+ const metadata = await obj.json();
388
+ const slug = item.key.replace(`${type}/`, "").replace(".json", "");
389
+ items.push({ ...metadata, slug });
390
+ }
391
+ }
392
+ }
393
+ const sorted = items.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
394
+ return latest ? sorted.slice(0, latest) : sorted;
395
+ }
396
+ async function searchContent(bucket, query) {
397
+ const q = query.toLowerCase();
398
+ const results = [];
399
+ const [blogsList, storiesList] = await Promise.all([
400
+ bucket.list({ prefix: "blogs/" }),
401
+ bucket.list({ prefix: "stories/" })
402
+ ]);
403
+ for (const item of [...blogsList.objects, ...storiesList.objects]) {
404
+ if (item.key.endsWith(".md")) {
405
+ const obj = await bucket.get(item.key);
406
+ if (obj) {
407
+ const text = await obj.text();
408
+ const { metadata } = parseFrontmatter(text);
409
+ const matchTitle = metadata.title?.toLowerCase().includes(q);
410
+ const matchDesc = metadata.description?.toLowerCase().includes(q);
411
+ const matchTags = metadata.tags?.some((t) => t.toLowerCase().includes(q));
412
+ if (matchTitle || matchDesc || matchTags) {
413
+ results.push(metadata);
414
+ }
415
+ }
416
+ }
417
+ }
418
+ return results;
419
+ }
262
420
  function getSessionToken(request) {
263
421
  const cookieHeader = request.headers.get("Cookie");
264
422
  if (!cookieHeader) return null;
@@ -363,8 +521,9 @@ async function handleWrite(request, bucket, subpath, env, method) {
363
521
  options.httpMetadata = { contentType };
364
522
  }
365
523
  await bucket.put(subpath, request.body, options);
366
- clearContentCache();
367
524
  clearContentCache$1();
525
+ clearContentCache$2();
526
+ clearContentCache();
368
527
  return createJSONResponse({ success: true, key: subpath });
369
528
  } catch (e) {
370
529
  return createErrorResponse("Failed to upload content: " + e.message, 500);
@@ -373,8 +532,9 @@ async function handleWrite(request, bucket, subpath, env, method) {
373
532
  if (method === "DELETE" && subpath) {
374
533
  try {
375
534
  await bucket.delete(subpath);
376
- clearContentCache();
377
535
  clearContentCache$1();
536
+ clearContentCache$2();
537
+ clearContentCache();
378
538
  return createJSONResponse({ success: true, key: subpath });
379
539
  } catch (e) {
380
540
  return createErrorResponse("Failed to delete content: " + e.message, 500);
@@ -543,109 +703,6 @@ async function handleLogout(request, env) {
543
703
  }
544
704
  });
545
705
  }
546
- const contentCache = /* @__PURE__ */ new Map();
547
- const CACHE_TTL = 5 * 60 * 1e3;
548
- function getCachedOrFetch(key, fetchFn) {
549
- const cached = contentCache.get(key);
550
- if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
551
- return Promise.resolve(cached.data);
552
- }
553
- return fetchFn().then((data) => {
554
- contentCache.set(key, { data, timestamp: Date.now() });
555
- return data;
556
- });
557
- }
558
- function parseFrontmatter(content) {
559
- const lines = content.split("\n");
560
- const metadata = {};
561
- let contentStart = 0;
562
- if (lines[0]?.trim() === "---") {
563
- for (let i = 1; i < lines.length; i++) {
564
- if (lines[i]?.trim() === "---") {
565
- contentStart = i + 1;
566
- break;
567
- }
568
- const colonIdx = lines[i].indexOf(":");
569
- if (colonIdx > 0) {
570
- const key = lines[i].slice(0, colonIdx).trim();
571
- let value = lines[i].slice(colonIdx + 1).trim();
572
- if (value.startsWith("[") && value.endsWith("]")) {
573
- value = value.slice(1, -1);
574
- metadata[key] = value.split(",").map((v) => v.trim());
575
- } else {
576
- metadata[key] = value;
577
- }
578
- }
579
- }
580
- }
581
- return {
582
- metadata,
583
- content: lines.slice(contentStart).join("\n").trim()
584
- };
585
- }
586
- function checkContentBucket(env) {
587
- if (!env?.CONTENT_BUCKET) {
588
- return createErrorResponse("Content bucket not configured", 500);
589
- }
590
- return null;
591
- }
592
- async function fetchContentItem(bucket, type, slug) {
593
- const mdObj = await bucket.get(`${type}/${slug}.md`);
594
- const jsonObj = await bucket.get(`${type}/${slug}.json`);
595
- if (!mdObj && !jsonObj) throw new Error(`${type.slice(0, -1)} not found`);
596
- let metadata = {};
597
- if (jsonObj) {
598
- metadata = await jsonObj.json();
599
- }
600
- let content = "";
601
- if (mdObj) {
602
- const text = await mdObj.text();
603
- const parsed = parseFrontmatter(text);
604
- content = parsed.content;
605
- metadata = { ...parsed.metadata, ...metadata };
606
- }
607
- return { ...metadata, slug, content };
608
- }
609
- async function fetchContentList(bucket, type, latest) {
610
- const list = await bucket.list({ prefix: `${type}/` });
611
- const items = [];
612
- for (const item of list.objects) {
613
- if (item.key.endsWith(".json")) {
614
- const obj = await bucket.get(item.key);
615
- if (obj) {
616
- const metadata = await obj.json();
617
- const slug = item.key.replace(`${type}/`, "").replace(".json", "");
618
- items.push({ ...metadata, slug });
619
- }
620
- }
621
- }
622
- const sorted = items.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
623
- return latest ? sorted.slice(0, latest) : sorted;
624
- }
625
- async function searchContent(bucket, query) {
626
- const q = query.toLowerCase();
627
- const results = [];
628
- const [blogsList, storiesList] = await Promise.all([
629
- bucket.list({ prefix: "blogs/" }),
630
- bucket.list({ prefix: "stories/" })
631
- ]);
632
- for (const item of [...blogsList.objects, ...storiesList.objects]) {
633
- if (item.key.endsWith(".md")) {
634
- const obj = await bucket.get(item.key);
635
- if (obj) {
636
- const text = await obj.text();
637
- const { metadata } = parseFrontmatter(text);
638
- const matchTitle = metadata.title?.toLowerCase().includes(q);
639
- const matchDesc = metadata.description?.toLowerCase().includes(q);
640
- const matchTags = metadata.tags?.some((t) => t.toLowerCase().includes(q));
641
- if (matchTitle || matchDesc || matchTags) {
642
- results.push(metadata);
643
- }
644
- }
645
- }
646
- }
647
- return results;
648
- }
649
706
  async function handleBlogs(env, slug, latest) {
650
707
  const bucketCheck = checkContentBucket(env);
651
708
  if (bucketCheck) return bucketCheck;
@@ -874,7 +931,7 @@ class WebsiteAPI {
874
931
  if (!session || session.expiresAt < Date.now()) {
875
932
  return this.addAdminCORSHeaders(createErrorResponse("Unauthorized", 401), origin);
876
933
  }
877
- clearContentCache$1();
934
+ clearContentCache$2();
878
935
  return this.addAdminCORSHeaders(new Response(JSON.stringify({ success: true, message: "Cache cleared" }), { status: 200, headers: { "Content-Type": "application/json" } }), origin);
879
936
  case "aboutme":
880
937
  return this.addAdminCORSHeaders(await handleAboutMe(env), origin);
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { A, B, M, R, W, c, a, g, b, d, h, e, r, s, v } from "./chunks/website-api-C3lGjXdD.js";
1
+ import { A, B, M, R, W, c, a, g, b, d, h, e, r, s, v } from "./chunks/website-api-DBEh24zq.js";
2
2
  import { WebsitePrerender } from "./prerender.js";
3
- import { A as A2, a as a2, b as b2, c as c2, d as d2, e as e2, f, g as g2, h as h2, i, B as B2, F, M as M2, j, S, k } from "./chunks/index-B2jGIzSi.js";
3
+ import { A as A2, a as a2, b as b2, c as c2, d as d2, e as e2, f, g as g2, h as h2, i, B as B2, F, M as M2, j, S, k } from "./chunks/index-DAog9TQE.js";
4
4
  import { S as S2, g as g3, i as i2, r as r2 } from "./chunks/site-store-CGV9c2DI.js";
5
- import { R as R2, T, W as W2, b as b3, c as c3, g as g4, r as r3 } from "./chunks/template-DXUSp0BG.js";
5
+ import { R as R2, T, W as W2, b as b3, c as c3, g as g4, r as r3 } from "./chunks/template-DUdadCrH.js";
6
6
  export {
7
7
  A as AUTH_KV,
8
8
  A2 as AdminAboutMeSection,
@@ -1 +1 @@
1
- {"version":3,"file":"data-fetcher.d.ts","sourceRoot":"","sources":["../../src/prerender/data-fetcher.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAeD,wBAAsB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAQpE;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAO5D;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAOzD;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAgB/F;AAED,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAgBhG"}
1
+ {"version":3,"file":"data-fetcher.d.ts","sourceRoot":"","sources":["../../src/prerender/data-fetcher.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAwCD,wBAAsB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAQpE;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAO5D;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAOzD;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAgB/F;AAED,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAgBhG"}
@@ -1 +1 @@
1
- {"version":3,"file":"page-content.d.ts","sourceRoot":"","sources":["../../src/prerender/page-content.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAuFD,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,EAChB,QAAQ,MAAM,EAAE,EAChB,aAAa,WAAW,EAAE,EAC1B,MAAM,GAAG,KACR,OAAO,CAAC,WAAW,CAqJrB,CAAC"}
1
+ {"version":3,"file":"page-content.d.ts","sourceRoot":"","sources":["../../src/prerender/page-content.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAgHD,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,EAChB,QAAQ,MAAM,EAAE,EAChB,aAAa,WAAW,EAAE,EAC1B,MAAM,GAAG,KACR,OAAO,CAAC,WAAW,CAqJrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/prerender/template.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAsDD,eAAO,MAAM,kBAAkB,GAAU,8FAStC,aAAa,KAAG,OAAO,CAAC,MAAM,CAmChC,CAAC"}
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/prerender/template.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAsDD,eAAO,MAAM,kBAAkB,GAAU,8FAStC,aAAa,KAAG,OAAO,CAAC,MAAM,CAuDhC,CAAC"}
package/dist/prerender.js CHANGED
@@ -1,4 +1,4 @@
1
- import { R2ContentLoader } from "@leadertechie/r2tohtml";
1
+ import { ContentCacheV2, R2ContentLoader } from "@leadertechie/r2tohtml";
2
2
  let cachedAssets = null;
3
3
  let isDiscovering = false;
4
4
  async function getAssetPaths(baseSiteUrl) {
@@ -73,6 +73,26 @@ const createHtmlTemplate = async ({
73
73
  <link rel="canonical" href="${canonicalUrl}" />
74
74
  <link rel="stylesheet" crossorigin href="${css}" />
75
75
  <script type="module" crossorigin src="${js}"><\/script>
76
+ <!-- md2interact: client-side DOM interactions, CSS hydration, and event bus -->
77
+ <script type="module">
78
+ import { init } from '@leadertechie/md2interact';
79
+ document.addEventListener('DOMContentLoaded', () => {
80
+ init({
81
+ interactions: {
82
+ 'poll': { selector: '[data-interact="poll"]' },
83
+ 'live-update': { selector: '[data-interact="live-update"]' },
84
+ 'click-toggle': { selector: '[data-interact="click-toggle"]' },
85
+ 'infinite-scroll': { selector: '[data-interact="infinite-scroll"]' },
86
+ 'form-live': { selector: '[data-interact="form-live"]' }
87
+ },
88
+ cssHydration: {
89
+ inlineCritical: true,
90
+ layerInjection: true,
91
+ themeToggle: true
92
+ }
93
+ });
94
+ });
95
+ <\/script>
76
96
  </head>
77
97
  <body>
78
98
  ${hydrationData}
@@ -83,12 +103,41 @@ const createHtmlTemplate = async ({
83
103
  </html>`;
84
104
  };
85
105
  let loader = null;
106
+ new ContentCacheV2(
107
+ 5 * 60 * 1e3,
108
+ // TTL: 5 minutes fresh
109
+ true,
110
+ // enabled
111
+ 30 * 60 * 1e3
112
+ // SWR TTL: 30 minutes stale window
113
+ );
86
114
  function getLoader(env) {
87
115
  if (!loader) {
88
116
  if (!env?.CONTENT_BUCKET) return null;
89
117
  loader = new R2ContentLoader(
90
- { bucket: env.CONTENT_BUCKET, cacheTTL: 5 * 60 * 1e3 },
91
- { md2html: { imagePathPrefix: "images/", styleOptions: { classPrefix: "md-", addHeadingIds: true } } }
118
+ {
119
+ bucket: env.CONTENT_BUCKET,
120
+ cacheTTL: 5 * 60 * 1e3,
121
+ cfCache: true,
122
+ // Enable Cloudflare edge cache tier
123
+ cfCacheTTL: 300,
124
+ // CF cache for 5 minutes
125
+ swrTTL: 30 * 60 * 1e3
126
+ // SWR window: 30 minutes
127
+ },
128
+ {
129
+ md2html: {
130
+ imagePathPrefix: "images/",
131
+ preserveRawHTML: true,
132
+ errorRecovery: "warn",
133
+ maxRecursionDepth: 50,
134
+ styleOptions: {
135
+ classPrefix: "md-",
136
+ addHeadingIds: true,
137
+ emitScopeAnchors: true
138
+ }
139
+ }
140
+ }
92
141
  );
93
142
  }
94
143
  return loader;
@@ -1 +1 @@
1
- {"version":3,"file":"theme-toggle.d.ts","sourceRoot":"","sources":["../../../src/shared/core/theme-toggle.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAY,SAAQ,WAAW;;IAQ1C,iBAAiB;IAIjB,oBAAoB;IAIpB,MAAM;IAkCN,0BAA0B;IAc1B,WAAW,aAOT;IAEF,kBAAkB,CAAC,KAAK,EAAE,MAAM;IAUhC,UAAU,IAAI,MAAM;IAgBpB,WAAW,IAAI,MAAM;IAQrB,wBAAwB,CAAC,KAAK,EAAE,MAAM;CAQvC"}
1
+ {"version":3,"file":"theme-toggle.d.ts","sourceRoot":"","sources":["../../../src/shared/core/theme-toggle.ts"],"names":[],"mappings":"AAEA,qBAAa,WAAY,SAAQ,WAAW;;IAQ1C,iBAAiB;IAIjB,oBAAoB;IAIpB,MAAM;IAiCN,0BAA0B;IAc1B,WAAW,aAOT;IAEF,kBAAkB,CAAC,KAAK,EAAE,MAAM;IAUhC,UAAU,IAAI,MAAM;IAgBpB,WAAW,IAAI,MAAM;IAQrB,wBAAwB,CAAC,KAAK,EAAE,MAAM;CAQvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"page-content.d.ts","sourceRoot":"","sources":["../../src/shared/page-content.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AAGpC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAUD,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,MAGhD,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,EAChB,QAAQ,MAAM,EAAE,EAChB,aAAa,WAAW,EAAE,EAC1B,OAAO;IACL,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,KACA,WA0JF,CAAC"}
1
+ {"version":3,"file":"page-content.d.ts","sourceRoot":"","sources":["../../src/shared/page-content.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AAGpC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAwBD,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,MAGhD,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,EAChB,QAAQ,MAAM,EAAE,EAChB,aAAa,WAAW,EAAE,EAC1B,OAAO;IACL,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,KACA,WA0JF,CAAC"}
@@ -14,6 +14,11 @@ export declare class Router {
14
14
  private setupEventListeners;
15
15
  navigate(path: string): Promise<void>;
16
16
  private setPageMeta;
17
+ /**
18
+ * After rendering new content, reinitialize md2interact so it
19
+ * re-scans the DOM for interaction elements (poll, live-update, etc.)
20
+ */
21
+ private afterRender;
17
22
  private renderHomePage;
18
23
  private renderAboutMePage;
19
24
  private renderContentListPage;
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/shared/router.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,qBAAa,MAAM;IAML,OAAO,CAAC,EAAE;IALtB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,UAAU,CAA4B;gBAE1B,EAAE,EAAE,SAAS;IAejC,OAAO,KAAK,MAAM,GAEjB;IAED,OAAO,KAAK,SAAS,GAEpB;IAED,OAAO,KAAK,SAAS,GAEpB;IAED,OAAO,KAAK,WAAW,GAatB;IAEM,IAAI,CAAC,YAAY,GAAE,MAAc;IAWxC,OAAO,CAAC,mBAAmB;IAmCd,QAAQ,CAAC,IAAI,EAAE,MAAM;IA6BlC,OAAO,CAAC,WAAW;YAgCL,cAAc;IAkC5B,OAAO,CAAC,iBAAiB;YAQX,qBAAqB;YAiBrB,uBAAuB;YAmBvB,eAAe;CAqB9B"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/shared/router.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,qBAAa,MAAM;IAML,OAAO,CAAC,EAAE;IALtB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,UAAU,CAA4B;gBAE1B,EAAE,EAAE,SAAS;IAejC,OAAO,KAAK,MAAM,GAEjB;IAED,OAAO,KAAK,SAAS,GAEpB;IAED,OAAO,KAAK,SAAS,GAEpB;IAED,OAAO,KAAK,WAAW,GAatB;IAEM,IAAI,CAAC,YAAY,GAAE,MAAc;IAWxC,OAAO,CAAC,mBAAmB;IAmCd,QAAQ,CAAC,IAAI,EAAE,MAAM;IA6BlC,OAAO,CAAC,WAAW;IAgCnB;;;OAGG;IACH,OAAO,CAAC,WAAW;YAIL,cAAc;IAmC5B,OAAO,CAAC,iBAAiB;YASX,qBAAqB;YAkBrB,uBAAuB;YAoBvB,eAAe;CAsB9B"}
@@ -13,15 +13,36 @@ export interface UIConfig {
13
13
  customCss?: string;
14
14
  };
15
15
  onBootstrap?: (ui: WebsiteUI) => void | Promise<void>;
16
+ interactConfig?: {
17
+ interactions?: Record<string, {
18
+ selector: string;
19
+ }>;
20
+ cssHydration?: {
21
+ inlineCritical?: boolean;
22
+ layerInjection?: boolean;
23
+ themeToggle?: boolean;
24
+ };
25
+ };
16
26
  }
17
27
  export declare class WebsiteUI {
18
28
  private static instance;
19
29
  private store;
20
30
  private config;
21
31
  private router;
32
+ private interactInitialized;
22
33
  private constructor();
23
34
  static getInstance(config?: UIConfig): WebsiteUI;
24
35
  bootstrap(): Promise<void>;
36
+ /**
37
+ * Initialize md2interact for client-side DOM interactions,
38
+ * CSS hydration, and event bus communication.
39
+ */
40
+ private initInteract;
41
+ /**
42
+ * Reinitialize md2interact after dynamic content changes (e.g., SPA navigation).
43
+ * This re-scans the DOM for new interaction elements.
44
+ */
45
+ reinitInteract(): void;
25
46
  private updateBanner;
26
47
  private applyTheme;
27
48
  private updateFavicon;
@@ -1 +1 @@
1
- {"version":3,"file":"website-ui.d.ts","sourceRoot":"","sources":["../../src/shared/website-ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAY;IACnC,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,MAAM,CAAuB;IAErC,OAAO;WAKO,WAAW,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS;IAU1C,SAAS;IAsCtB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,aAAa;IAad,QAAQ;IAIR,SAAS;IAIT,SAAS;CAGjB;AAED,eAAO,MAAM,SAAS,GAAI,SAAS,QAAQ,kBAA8C,CAAC"}
1
+ {"version":3,"file":"website-ui.d.ts","sourceRoot":"","sources":["../../src/shared/website-ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,cAAc,CAAC,EAAE;QACf,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACpD,YAAY,CAAC,EAAE;YACb,cAAc,CAAC,EAAE,OAAO,CAAC;YACzB,cAAc,CAAC,EAAE,OAAO,CAAC;YACzB,WAAW,CAAC,EAAE,OAAO,CAAC;SACvB,CAAC;KACH,CAAC;CACH;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAY;IACnC,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,mBAAmB,CAAS;IAEpC,OAAO;WAKO,WAAW,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS;IAU1C,SAAS;IAyCtB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAuBpB;;;OAGG;IACI,cAAc;IAMrB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,aAAa;IAad,QAAQ;IAIR,SAAS;IAIT,SAAS;CAGjB;AAED,eAAO,MAAM,SAAS,GAAI,SAAS,QAAQ,kBAA8C,CAAC"}
package/dist/shared.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { S, g, i, r } from "./chunks/site-store-CGV9c2DI.js";
2
- import { R, T, W, b, c, g as g2, r as r2 } from "./chunks/template-DXUSp0BG.js";
2
+ import { R, T, W, b, c, g as g2, r as r2 } from "./chunks/template-DUdadCrH.js";
3
3
  export {
4
4
  R as Router,
5
5
  S as SiteStore,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/blog-viewer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAc5C,UAAU,QAAQ;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBACa,UAAW,SAAQ,UAAU;IACxC,MAAM,CAAC,MAAM,0BAAoB;IAGjC,QAAQ,CAAC,IAAI,SAAM;IAGnB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAQ;IAG1C,QAAQ,CAAC,OAAO,UAAQ;IAGxB,QAAQ,CAAC,KAAK,SAAM;IAEpB,OAAO,KAAK,UAAU,GAMrB;IAED,iBAAiB;IAOjB,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAM/C,QAAQ;IA4BR,MAAM;IA+BN,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;CAKxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/blog-viewer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AA0B5C,UAAU,QAAQ;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBACa,UAAW,SAAQ,UAAU;IACxC,MAAM,CAAC,MAAM,0BAAoB;IAGjC,QAAQ,CAAC,IAAI,SAAM;IAGnB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAQ;IAG1C,QAAQ,CAAC,OAAO,UAAQ;IAGxB,QAAQ,CAAC,KAAK,SAAM;IAEpB,OAAO,KAAK,UAAU,GAMrB;IAED,iBAAiB;IAOjB,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAM/C,QAAQ;IA4BR,MAAM;IA+BN,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;CAKxC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/story-viewer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAc5C,UAAU,SAAS;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBACa,WAAY,SAAQ,UAAU;IACzC,MAAM,CAAC,MAAM,0BAAqB;IAGlC,QAAQ,CAAC,IAAI,SAAM;IAGnB,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAQ;IAG5C,QAAQ,CAAC,OAAO,UAAQ;IAGxB,QAAQ,CAAC,KAAK,SAAM;IAEpB,OAAO,KAAK,UAAU,GAKrB;IAEK,iBAAiB;IAOvB,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC;IAMrC,SAAS;IAuBf,MAAM;IA+BN,OAAO,CAAC,cAAc;CAKvB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/story-viewer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AA0B5C,UAAU,SAAS;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBACa,WAAY,SAAQ,UAAU;IACzC,MAAM,CAAC,MAAM,0BAAqB;IAGlC,QAAQ,CAAC,IAAI,SAAM;IAGnB,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAQ;IAG5C,QAAQ,CAAC,OAAO,UAAQ;IAGxB,QAAQ,CAAC,KAAK,SAAM;IAEpB,OAAO,KAAK,UAAU,GAKrB;IAEK,iBAAiB;IAOvB,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC;IAMrC,SAAS;IAuBf,MAAM;IA+BN,OAAO,CAAC,cAAc;CAKvB"}
package/dist/ui.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A, a, b, c, d, e, f, g, h, i, B, F, M, j, S, k } from "./chunks/index-B2jGIzSi.js";
1
+ import { A, a, b, c, d, e, f, g, h, i, B, F, M, j, S, k } from "./chunks/index-DAog9TQE.js";
2
2
  export {
3
3
  A as AdminAboutMeSection,
4
4
  a as AdminBlogsSection,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leadertechie/personal-site-kit",
3
- "version": "0.1.0-alpha.16",
3
+ "version": "0.1.0-alpha.18",
4
4
  "type": "module",
5
5
  "description": "A high-performance personal website engine for Cloudflare Workers and R2",
6
6
  "repository": {
@@ -43,8 +43,9 @@
43
43
  "test": "vitest run"
44
44
  },
45
45
  "dependencies": {
46
- "@leadertechie/md2html": "^0.1.0-alpha.13",
47
- "@leadertechie/r2tohtml": "^0.1.0-alpha.12",
46
+ "@leadertechie/md2html": "^0.1.0-alpha.15",
47
+ "@leadertechie/md2interact": "^0.1.0-alpha.1",
48
+ "@leadertechie/r2tohtml": "^0.1.0-alpha.14",
48
49
  "lit": "^3.2.1"
49
50
  },
50
51
  "devDependencies": {