@techninja/clearstack 0.3.39 → 0.3.41

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.
@@ -40,13 +40,13 @@ Both are driven by the same `clearstack.routes.json` config and data sources.
40
40
 
41
41
  ### Fields
42
42
 
43
- | Field | Required | Description |
44
- | -------------- | -------- | ------------------------------------------------------- |
45
- | `title` | yes | Template string with `{path.to.data}` interpolation |
46
- | `description` | yes | Template string for meta description |
47
- | `image` | no | Template string for og:image URL |
48
- | `data` | no | Data source — `filepath:jsonPath` (supports arrays/objects) |
49
- | `ogTemplate` | no | Template name → resolves to `src/og-templates/{name}.html` |
43
+ | Field | Required | Description |
44
+ | ------------- | -------- | ----------------------------------------------------------- |
45
+ | `title` | yes | Template string with `{path.to.data}` interpolation |
46
+ | `description` | yes | Template string for meta description |
47
+ | `image` | no | Template string for og:image URL |
48
+ | `data` | no | Data source — `filepath:jsonPath` (supports arrays/objects) |
49
+ | `ogTemplate` | no | Template name → resolves to `src/og-templates/{name}.html` |
50
50
 
51
51
  ### Data Sources
52
52
 
@@ -75,15 +75,15 @@ Templates are HTML files at `src/og-templates/` rendered by Playwright at
75
75
 
76
76
  ### Available Context Variables
77
77
 
78
- | Variable | Source |
79
- | -------------------- | ----------------------------------- |
80
- | `{title}` | Resolved + truncated route title |
81
- | `{description}` | Resolved + truncated description |
82
- | `{image}` | Resolved image URL |
83
- | `{emoji}` | From item data |
84
- | `{bg}`, `{primary}` | From project CSS tokens |
85
- | `{variantsFormatted}`| Formatted number (K/M suffix) |
86
- | All item fields | Spread directly (e.g. `{name}`, `{pgs_count}`) |
78
+ | Variable | Source |
79
+ | --------------------- | ---------------------------------------------- |
80
+ | `{title}` | Resolved + truncated route title |
81
+ | `{description}` | Resolved + truncated description |
82
+ | `{image}` | Resolved image URL |
83
+ | `{emoji}` | From item data |
84
+ | `{bg}`, `{primary}` | From project CSS tokens |
85
+ | `{variantsFormatted}` | Formatted number (K/M suffix) |
86
+ | All item fields | Spread directly (e.g. `{name}`, `{pgs_count}`) |
87
87
 
88
88
  ## CLI Commands
89
89
 
@@ -103,13 +103,13 @@ clearstack build all --url=https://mysite.com --site=MySite --out=dist
103
103
 
104
104
  ### Flags
105
105
 
106
- | Flag | Description |
107
- | ---------- | ------------------------------------ |
108
- | `--out` | Output directory (default: `dist`) |
109
- | `--url` | Base URL for og:url tags |
110
- | `--site` | Site name for badge/branding |
111
- | `--logo` | Logo path or URL |
112
- | `--slug` | Single item slug (fast iteration) |
106
+ | Flag | Description |
107
+ | -------- | ---------------------------------- |
108
+ | `--out` | Output directory (default: `dist`) |
109
+ | `--url` | Base URL for og:url tags |
110
+ | `--site` | Site name for badge/branding |
111
+ | `--logo` | Logo path or URL |
112
+ | `--slug` | Single item slug (fast iteration) |
113
113
 
114
114
  ## Requirements
115
115
 
@@ -104,13 +104,13 @@ keyboard handlers, and large template literals.
104
104
 
105
105
  Extraction priority (most reusable → most specific):
106
106
 
107
- | What to extract | Where to put it | When |
108
- |----------------|-----------------|------|
109
- | Data loading/caching | `src/utils/{feature}Loader.js` | >20 lines of fetch/transform |
110
- | Keyboard/event handlers | `src/utils/{feature}Keys.js` | >10 lines of handler logic |
111
- | Repeated template fragments | `src/utils/{feature}Template.js` | Used in 2+ views |
112
- | Render sub-sections | `src/utils/{feature}Render.js` | Single view, but >30 lines |
113
- | Shared UI (header, breadcrumb) | `src/components/` | Used site-wide |
107
+ | What to extract | Where to put it | When |
108
+ | ------------------------------ | -------------------------------- | ---------------------------- |
109
+ | Data loading/caching | `src/utils/{feature}Loader.js` | >20 lines of fetch/transform |
110
+ | Keyboard/event handlers | `src/utils/{feature}Keys.js` | >10 lines of handler logic |
111
+ | Repeated template fragments | `src/utils/{feature}Template.js` | Used in 2+ views |
112
+ | Render sub-sections | `src/utils/{feature}Render.js` | Single view, but >30 lines |
113
+ | Shared UI (header, breadcrumb) | `src/components/` | Used site-wide |
114
114
 
115
115
  The goal isn't to have zero logic in view files — it's to keep each
116
116
  file answerable with "what does this do?" in one pass.
package/lib/build-og.js CHANGED
@@ -112,14 +112,9 @@ function resolveMeta(config, data, baseUrl, path) {
112
112
 
113
113
  /** Write a single HTML page to the output directory. */
114
114
  function writePage(outDir, routePath, shell, meta) {
115
- let filePath;
116
- if (routePath === '/') {
117
- filePath = resolve(outDir, 'index.html');
118
- } else {
119
- // Write as flat file (e.g. /dna-sources → dna-sources.html)
120
- // Cloudflare Pages serves dna-sources.html for /dna-sources without redirect
121
- filePath = resolve(outDir, routePath.slice(1) + '.html');
122
- }
115
+ const filePath = routePath === '/'
116
+ ? resolve(outDir, 'index.html')
117
+ : resolve(outDir, routePath.slice(1), 'index.html');
123
118
  mkdirSync(dirname(filePath), { recursive: true });
124
119
  writeFileSync(filePath, injectMeta(shell, meta));
125
120
  }
@@ -71,6 +71,8 @@ export function buildContext(config, itemData, site) {
71
71
  const title = interpolate(config.title, itemData);
72
72
  const desc = config.description ? interpolate(config.description, itemData) : '';
73
73
  const image = config.image ? interpolate(config.image, itemData) : '';
74
+ const baseUrl = itemData.store?.url || '';
75
+ const resolvedImage = image && !image.startsWith('http') ? `${baseUrl}${image}` : image;
74
76
  const item = itemData.item || {};
75
77
  const emoji = item.emoji || itemData.emoji || '';
76
78
 
@@ -84,11 +86,12 @@ export function buildContext(config, itemData, site) {
84
86
  accent: t['color-accent'] || '#34d399',
85
87
  text: t['color-text'] || '#e2e8f0',
86
88
  textMuted: t['color-text-muted'] || '#a8b8cc',
87
- emoji, image,
89
+ emoji, image: resolvedImage,
88
90
  variantsFormatted: formatNum(item.expected_variants),
89
91
  uniqueFormatted: formatNum(item.estimated_unique_variants),
90
- imageHtml: image ? `<img class="hero" src="${image}">` : '',
91
- cardClass: image ? 'card-with-image' : '',
92
+ priceFormatted: item.price ? `$${(item.price / 100).toFixed(2)}` : '',
93
+ imageHtml: resolvedImage ? `<img class="hero" src="${resolvedImage}">` : '',
94
+ cardClass: resolvedImage ? 'card-with-image' : '',
92
95
  logoHtml: site.logo ? `<img class="logo" src="${site.logo}">` : '',
93
96
  badgeHtml: site.siteName ? `<div class="badge">${site.siteName}</div>` : '',
94
97
  emojiHtml: emoji ? `<div class="emoji">${emoji}</div>` : '',
@@ -65,9 +65,9 @@ export function injectMeta(html, meta) {
65
65
  * @returns {string}
66
66
  */
67
67
  export function interpolate(template, data) {
68
- return template.replace(/\{([\w.]+)\}/g, (match, path) => {
68
+ return template.replace(/\{([\w.]+)\}/g, (_, path) => {
69
69
  const val = path.split('.').reduce((obj, key) => obj?.[key], data);
70
- return val !== null && val !== undefined ? String(val) : match;
70
+ return val !== null && val !== undefined ? String(val) : '';
71
71
  });
72
72
  }
73
73
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techninja/clearstack",
3
- "version": "0.3.39",
3
+ "version": "0.3.41",
4
4
  "type": "module",
5
5
  "description": "A no-build web component framework specification — scaffold, validate, and evolve spec-compliant projects",
6
6
  "bin": {
@@ -40,13 +40,13 @@ Both are driven by the same `clearstack.routes.json` config and data sources.
40
40
 
41
41
  ### Fields
42
42
 
43
- | Field | Required | Description |
44
- | -------------- | -------- | ------------------------------------------------------- |
45
- | `title` | yes | Template string with `{path.to.data}` interpolation |
46
- | `description` | yes | Template string for meta description |
47
- | `image` | no | Template string for og:image URL |
48
- | `data` | no | Data source — `filepath:jsonPath` (supports arrays/objects) |
49
- | `ogTemplate` | no | Template name → resolves to `src/og-templates/{name}.html` |
43
+ | Field | Required | Description |
44
+ | ------------- | -------- | ----------------------------------------------------------- |
45
+ | `title` | yes | Template string with `{path.to.data}` interpolation |
46
+ | `description` | yes | Template string for meta description |
47
+ | `image` | no | Template string for og:image URL |
48
+ | `data` | no | Data source — `filepath:jsonPath` (supports arrays/objects) |
49
+ | `ogTemplate` | no | Template name → resolves to `src/og-templates/{name}.html` |
50
50
 
51
51
  ### Data Sources
52
52
 
@@ -75,15 +75,15 @@ Templates are HTML files at `src/og-templates/` rendered by Playwright at
75
75
 
76
76
  ### Available Context Variables
77
77
 
78
- | Variable | Source |
79
- | -------------------- | ----------------------------------- |
80
- | `{title}` | Resolved + truncated route title |
81
- | `{description}` | Resolved + truncated description |
82
- | `{image}` | Resolved image URL |
83
- | `{emoji}` | From item data |
84
- | `{bg}`, `{primary}` | From project CSS tokens |
85
- | `{variantsFormatted}`| Formatted number (K/M suffix) |
86
- | All item fields | Spread directly (e.g. `{name}`, `{pgs_count}`) |
78
+ | Variable | Source |
79
+ | --------------------- | ---------------------------------------------- |
80
+ | `{title}` | Resolved + truncated route title |
81
+ | `{description}` | Resolved + truncated description |
82
+ | `{image}` | Resolved image URL |
83
+ | `{emoji}` | From item data |
84
+ | `{bg}`, `{primary}` | From project CSS tokens |
85
+ | `{variantsFormatted}` | Formatted number (K/M suffix) |
86
+ | All item fields | Spread directly (e.g. `{name}`, `{pgs_count}`) |
87
87
 
88
88
  ## CLI Commands
89
89
 
@@ -103,13 +103,13 @@ clearstack build all --url=https://mysite.com --site=MySite --out=dist
103
103
 
104
104
  ### Flags
105
105
 
106
- | Flag | Description |
107
- | ---------- | ------------------------------------ |
108
- | `--out` | Output directory (default: `dist`) |
109
- | `--url` | Base URL for og:url tags |
110
- | `--site` | Site name for badge/branding |
111
- | `--logo` | Logo path or URL |
112
- | `--slug` | Single item slug (fast iteration) |
106
+ | Flag | Description |
107
+ | -------- | ---------------------------------- |
108
+ | `--out` | Output directory (default: `dist`) |
109
+ | `--url` | Base URL for og:url tags |
110
+ | `--site` | Site name for badge/branding |
111
+ | `--logo` | Logo path or URL |
112
+ | `--slug` | Single item slug (fast iteration) |
113
113
 
114
114
  ## Requirements
115
115
 
@@ -104,13 +104,13 @@ keyboard handlers, and large template literals.
104
104
 
105
105
  Extraction priority (most reusable → most specific):
106
106
 
107
- | What to extract | Where to put it | When |
108
- |----------------|-----------------|------|
109
- | Data loading/caching | `src/utils/{feature}Loader.js` | >20 lines of fetch/transform |
110
- | Keyboard/event handlers | `src/utils/{feature}Keys.js` | >10 lines of handler logic |
111
- | Repeated template fragments | `src/utils/{feature}Template.js` | Used in 2+ views |
112
- | Render sub-sections | `src/utils/{feature}Render.js` | Single view, but >30 lines |
113
- | Shared UI (header, breadcrumb) | `src/components/` | Used site-wide |
107
+ | What to extract | Where to put it | When |
108
+ | ------------------------------ | -------------------------------- | ---------------------------- |
109
+ | Data loading/caching | `src/utils/{feature}Loader.js` | >20 lines of fetch/transform |
110
+ | Keyboard/event handlers | `src/utils/{feature}Keys.js` | >10 lines of handler logic |
111
+ | Repeated template fragments | `src/utils/{feature}Template.js` | Used in 2+ views |
112
+ | Render sub-sections | `src/utils/{feature}Render.js` | Single view, but >30 lines |
113
+ | Shared UI (header, breadcrumb) | `src/components/` | Used site-wide |
114
114
 
115
115
  The goal isn't to have zero logic in view files — it's to keep each
116
116
  file answerable with "what does this do?" in one pass.