@orbytes/astrolab 0.3.0

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.
Files changed (94) hide show
  1. package/LICENSE +37 -0
  2. package/README.md +410 -0
  3. package/bin/lab-cull.mjs +401 -0
  4. package/bin/pin-gallery.mjs +121 -0
  5. package/defaults.mjs +120 -0
  6. package/dist/core/astro-integration.js +130 -0
  7. package/dist/core/index.js +6 -0
  8. package/dist/core/lib-paths.js +29 -0
  9. package/dist/core/options.js +173 -0
  10. package/dist/core/utils/get-exports.js +52 -0
  11. package/dist/core/utils/invariant.js +12 -0
  12. package/dist/core/utils/kebab-case.js +15 -0
  13. package/dist/core/utils/path-builder.js +22 -0
  14. package/dist/core/utils/path.js +53 -0
  15. package/dist/core/virtual-module/get-story-modules.js +60 -0
  16. package/dist/core/virtual-module/story-modules.js +8 -0
  17. package/dist/core/virtual-module/virtual-module-ids.js +22 -0
  18. package/dist/core/virtual-module/virtual-routes.js +83 -0
  19. package/dist/core/virtual-module/vite-plugin.js +98 -0
  20. package/docs/PIN-CONTRACT.md +263 -0
  21. package/docs/PIN.md +429 -0
  22. package/index.d.ts +279 -0
  23. package/index.mjs +347 -0
  24. package/package.json +93 -0
  25. package/src/Empty.astro +4 -0
  26. package/src/Home.astro +298 -0
  27. package/src/LabHead.astro +1102 -0
  28. package/src/core/LICENSE-astrobook +166 -0
  29. package/src/core/astro-integration.ts +166 -0
  30. package/src/core/client.ts +89 -0
  31. package/src/core/index.ts +7 -0
  32. package/src/core/lib/components/empty.astro +1 -0
  33. package/src/core/lib/components/head.astro +1 -0
  34. package/src/core/lib/components/home.astro +8 -0
  35. package/src/core/lib/components/with-decorators.astro +22 -0
  36. package/src/core/lib/pages/app.astro +19 -0
  37. package/src/core/lib/pages/preview.astro +17 -0
  38. package/src/core/lib/pages/story.astro +16 -0
  39. package/src/core/lib-paths.ts +72 -0
  40. package/src/core/options.ts +262 -0
  41. package/src/core/utils/get-exports.ts +59 -0
  42. package/src/core/utils/invariant.ts +13 -0
  43. package/src/core/utils/kebab-case.ts +30 -0
  44. package/src/core/utils/path-builder.ts +45 -0
  45. package/src/core/utils/path.ts +80 -0
  46. package/src/core/virtual-module/get-story-modules.ts +110 -0
  47. package/src/core/virtual-module/story-modules.ts +9 -0
  48. package/src/core/virtual-module/virtual-module-ids.ts +17 -0
  49. package/src/core/virtual-module/virtual-routes.ts +130 -0
  50. package/src/core/virtual-module/vite-plugin.ts +125 -0
  51. package/src/pin/board.mjs +1521 -0
  52. package/src/pin/index.mjs +666 -0
  53. package/src/pin/shot.mjs +427 -0
  54. package/src/pin/source-stamp.mjs +159 -0
  55. package/src/pin/tickets.mjs +697 -0
  56. package/src/pin/toolbar.js +3181 -0
  57. package/src/shell/Browse.astro +371 -0
  58. package/src/shell/CardGrid.astro +297 -0
  59. package/src/shell/Viewport.astro +1330 -0
  60. package/src/shell/index.json.ts +12 -0
  61. package/src/shell/lab-index.ts +344 -0
  62. package/src/shell/lab-params.ts +245 -0
  63. package/src/shell/live-files.mjs +164 -0
  64. package/src/shell/marks.mjs +136 -0
  65. package/src/types/index.ts +6 -0
  66. package/src/types/types.ts +239 -0
  67. package/src/types/virtual.d.ts +29 -0
  68. package/src/ui/components/app.astro +13 -0
  69. package/src/ui/components/build-path.ts +13 -0
  70. package/src/ui/components/build-tree.ts +108 -0
  71. package/src/ui/components/collapse-duration.ts +28 -0
  72. package/src/ui/components/compress-terms.ts +10 -0
  73. package/src/ui/components/dashboard-layout.astro +39 -0
  74. package/src/ui/components/home.astro +65 -0
  75. package/src/ui/components/layout.astro +110 -0
  76. package/src/ui/components/preview-layout.astro +109 -0
  77. package/src/ui/components/sidebar-button-fullscreen.astro +38 -0
  78. package/src/ui/components/sidebar-button-search.astro +23 -0
  79. package/src/ui/components/sidebar-button-theme.astro +9 -0
  80. package/src/ui/components/sidebar-button.astro +24 -0
  81. package/src/ui/components/sidebar-resize-handle.astro +74 -0
  82. package/src/ui/components/sidebar-search-panel.astro +41 -0
  83. package/src/ui/components/sidebar-search-script.ts +103 -0
  84. package/src/ui/components/sidebar-title.astro +17 -0
  85. package/src/ui/components/sidebar-tree-node.astro +143 -0
  86. package/src/ui/components/sidebar-tree.astro +84 -0
  87. package/src/ui/components/sidebar.astro +29 -0
  88. package/src/ui/components/theme-message.ts +26 -0
  89. package/src/ui/components/theme-script.astro +71 -0
  90. package/src/ui/components/theme-toggle.astro +63 -0
  91. package/src/ui/components/theme.ts +32 -0
  92. package/src/ui/index.ts +4 -0
  93. package/src/ui/lab.css +549 -0
  94. package/virtual.d.ts +42 -0
package/package.json ADDED
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "@orbytes/astrolab",
3
+ "version": "0.3.0",
4
+ "type": "module",
5
+ "description": "The orbytes component lab and pin board — an Astrobook shell for Astro sites (live/used-by pills, a viewport configurator, responsive and cull marks, a parameters panel) plus a dev-only click-to-ticket feedback board at /pin.",
6
+ "keywords": [
7
+ "astro",
8
+ "astro-integration",
9
+ "component-lab",
10
+ "dev-toolbar",
11
+ "feedback",
12
+ "orbytes"
13
+ ],
14
+ "author": "William Teig <william@orbytes.io>",
15
+ "license": "MIT",
16
+ "engines": {
17
+ "node": ">=22.12.0"
18
+ },
19
+ "workspaces": [
20
+ "testbeds/*"
21
+ ],
22
+ "scripts": {
23
+ "build:core": "node scripts/build-core.mjs",
24
+ "prepare": "npm run build:core",
25
+ "prepack": "npm run build:core",
26
+ "dev": "npm --workspace testbed-orbytes-v2 run dev",
27
+ "build": "npm --workspace testbed-orbytes-v2 run build",
28
+ "preview": "npm --workspace testbed-orbytes-v2 run preview",
29
+ "build:staging": "npm --workspace testbed-orbytes-v2 run build:staging",
30
+ "check:isolation": "npm --workspace testbed-orbytes-v2 run check:isolation",
31
+ "verify": "npm --workspace testbed-orbytes-v2 run verify"
32
+ },
33
+ "bin": {
34
+ "orbytes-lab-cull": "bin/lab-cull.mjs",
35
+ "orbytes-pin-gallery": "bin/pin-gallery.mjs"
36
+ },
37
+ "main": "./index.mjs",
38
+ "types": "./index.d.ts",
39
+ "exports": {
40
+ ".": {
41
+ "types": "./index.d.ts",
42
+ "default": "./index.mjs"
43
+ },
44
+ "./params": "./src/shell/lab-params.ts",
45
+ "./head": "./src/LabHead.astro",
46
+ "./home": "./src/Home.astro",
47
+ "./defaults": "./defaults.mjs",
48
+ "./pin": "./src/pin/index.mjs",
49
+ "./pin/board": "./src/pin/board.mjs",
50
+ "./pin/tickets": "./src/pin/tickets.mjs",
51
+ "./pin/source-stamp": "./src/pin/source-stamp.mjs",
52
+ "./pin/shot": "./src/pin/shot.mjs",
53
+ "./pin/toolbar": "./src/pin/toolbar.js",
54
+ "./shell/*": "./src/shell/*",
55
+ "./core": "./src/core/index.ts",
56
+ "./core/client": "./src/core/client.ts",
57
+ "./core/components/*": "./src/core/lib/components/*",
58
+ "./core/pages/*": "./src/core/lib/pages/*",
59
+ "./ui/*": "./src/ui/*",
60
+ "./package.json": "./package.json"
61
+ },
62
+ "files": [
63
+ "README.md",
64
+ "bin",
65
+ "defaults.mjs",
66
+ "dist",
67
+ "docs",
68
+ "index.d.ts",
69
+ "index.mjs",
70
+ "src",
71
+ "virtual.d.ts"
72
+ ],
73
+ "dependencies": {
74
+ "@sveltejs/acorn-typescript": "^1.0.12",
75
+ "acorn": "^8.18.0",
76
+ "fdir": "^6.5.0",
77
+ "slash": "^5.1.0",
78
+ "yoctocolors": "^2.2.0"
79
+ },
80
+ "peerDependencies": {
81
+ "astro": ">=7",
82
+ "playwright": ">=1.50.0"
83
+ },
84
+ "peerDependenciesMeta": {
85
+ "playwright": {
86
+ "optional": true
87
+ }
88
+ },
89
+ "devDependencies": {
90
+ "esbuild": "^0.28.2",
91
+ "playwright": "^1.63.0"
92
+ }
93
+ }
@@ -0,0 +1,4 @@
1
+ ---
2
+ // The stand-in for the consumer's `head` component when it does not pass one. LabHead.astro always
3
+ // mounts something, so nothing there has to branch on whether a site contributed a head.
4
+ ---
package/src/Home.astro ADDED
@@ -0,0 +1,298 @@
1
+ ---
2
+ // Lab home — Astrobook's `home` component, given to it by the integration (../index.mjs).
3
+ // Replaces the stock splash with the lab index: a row of tier cards (each opening its folder page
4
+ // at <subpath>/browse/<tier>), then every story as a live thumbnail card grouped by tier, each
5
+ // card carrying its derived pill — live slot, used-by, or nothing.
6
+ //
7
+ // Everything drawn here comes from ./shell/lab-index.ts, which reads Astrobook's own story list
8
+ // (so ids and URLs never drift from what it routes) and derives "live" from what the pages under
9
+ // src/pages/ actually mount. The cards themselves are ./shell/CardGrid.astro, shared with the
10
+ // folder pages.
11
+ import { execSync } from "node:child_process";
12
+ import labConfig from "virtual:orbytes-lab/config.mjs";
13
+ import CardGrid from "./shell/CardGrid.astro";
14
+ import {
15
+ buildLabIndex,
16
+ labBase,
17
+ liveCountOf,
18
+ sortTiers,
19
+ STAGING_URL,
20
+ tierLabel,
21
+ } from "./shell/lab-index";
22
+
23
+ const index = buildLabIndex();
24
+ const tiers = sortTiers([...new Set(index.items.map((item) => item.tier))]).map((tier) => {
25
+ const items = index.items.filter((item) => item.tier === tier);
26
+ return {
27
+ tier,
28
+ label: tierLabel(tier),
29
+ href: tier ? `${labBase}/browse/${tier}` : `${labBase}/browse`,
30
+ count: items.length,
31
+ live: liveCountOf(items),
32
+ items,
33
+ };
34
+ });
35
+
36
+ // Local branches → per-branch preview builds, when the consumer configured a URL template.
37
+ // `previewUrlTemplate` is a string with a {branch} placeholder rather than a function because the
38
+ // config crosses a virtual module and has to stay JSON-serialisable. No template, no branch list:
39
+ // a host that does not build branches has nothing to link to.
40
+ const previewTemplate = labConfig.previewUrlTemplate;
41
+ let branches: string[] = [];
42
+ if (previewTemplate) {
43
+ try {
44
+ branches = execSync('git branch --format="%(refname:short)"', { encoding: "utf8" })
45
+ .split("\n")
46
+ .map((line) => line.trim())
47
+ .filter(Boolean);
48
+ } catch {
49
+ branches = [];
50
+ }
51
+ }
52
+ const previewAlias = (branch: string) =>
53
+ (previewTemplate ?? "").replace(
54
+ /\{branch\}/g,
55
+ branch
56
+ .toLowerCase()
57
+ .replace(/[^a-z0-9]+/g, "-")
58
+ .replace(/^-+|-+$/g, ""),
59
+ );
60
+ ---
61
+
62
+ <div class="lab-home lab-chrome">
63
+ <header class="lab-home__header">
64
+ <p class="lab-home__eyebrow">// component lab</p>
65
+ <h1 class="lab-home__title">{labConfig.title}</h1>
66
+ <p class="lab-home__intro">
67
+ Every section, component and exploration in the build, rendered live. Cards open the story
68
+ in the dashboard; thumbnails are the bare renders themselves, scaled down. A white pill means
69
+ a page mounts that component right now, and names the page when it is not the home page. On
70
+ section versions a second pill says whether that version has been made responsive; tick it in
71
+ the sidebar. Where a deployed lab is configured, each card also links to the same story
72
+ there — the real minified build, which this dev server is not — and, locally, to the
73
+ component in VS Code.
74
+ </p>
75
+ {
76
+ STAGING_URL && (
77
+ <a class="lab-home__staging" href={STAGING_URL} target="_blank" rel="noopener">
78
+ Staging site
79
+ <span aria-hidden="true">&nbsp;&#8599;</span>
80
+ </a>
81
+ )
82
+ }
83
+ </header>
84
+
85
+ <section class="lab-home__tiers">
86
+ {
87
+ tiers.map((tier) => (
88
+ <a class="tier-card" href={tier.href}>
89
+ <span class="tier-card__eyebrow">// {tier.tier || "root"}</span>
90
+ <span class="tier-card__name">{tier.label}</span>
91
+ <span class="tier-card__meta">
92
+ <span>
93
+ {tier.count} stor{tier.count === 1 ? "y" : "ies"}
94
+ </span>
95
+ {tier.live > 0 && <span class="tier-card__live">{tier.live} live</span>}
96
+ </span>
97
+ </a>
98
+ ))
99
+ }
100
+ </section>
101
+
102
+ {
103
+ branches.length > 0 && (
104
+ <section class="lab-home__branches">
105
+ <h2 class="lab-home__group-title">Branches</h2>
106
+ <ul>
107
+ {branches.map((branch) => (
108
+ <li>
109
+ <code>{branch}</code>
110
+ <a href={previewAlias(branch)} target="_blank" rel="noopener">
111
+ branch preview
112
+ </a>
113
+ </li>
114
+ ))}
115
+ </ul>
116
+ </section>
117
+ )
118
+ }
119
+
120
+ {
121
+ tiers.map((tier) => (
122
+ <section class="lab-home__group">
123
+ <h2 class="lab-home__group-title">
124
+ <a href={tier.href}>{tier.label}</a>
125
+ </h2>
126
+ <CardGrid items={tier.items} />
127
+ </section>
128
+ ))
129
+ }
130
+ </div>
131
+
132
+ <style>
133
+ .lab-home {
134
+ background-color: var(--lab-color-bg);
135
+ color: var(--lab-color-text);
136
+ font-family: var(--lab-font-body);
137
+ min-height: 100%;
138
+ padding: 3em 2.5em 5em;
139
+ }
140
+
141
+ .lab-home__eyebrow {
142
+ font-family: var(--lab-font-mono);
143
+ font-weight: 500;
144
+ color: var(--lab-color-text-muted);
145
+ margin-bottom: 0.75em;
146
+ }
147
+
148
+ .lab-home__title {
149
+ font-family: var(--lab-font-heading);
150
+ color: var(--lab-color-text-strong);
151
+ font-size: 2.25em;
152
+ font-weight: 500;
153
+ letter-spacing: -0.5px;
154
+ margin-bottom: 0.4em;
155
+ }
156
+
157
+ .lab-home__intro {
158
+ max-width: 42em;
159
+ color: var(--lab-color-text-faint);
160
+ line-height: 1.55;
161
+ margin-bottom: 1.5em;
162
+ }
163
+
164
+ .lab-home__staging {
165
+ display: inline-block;
166
+ font-family: var(--lab-font-mono);
167
+ font-weight: 500;
168
+ color: var(--lab-color-text-strong);
169
+ text-decoration: none;
170
+ border: 1px solid var(--lab-color-border);
171
+ border-left: 1px solid var(--lab-color-text-strong);
172
+ padding: 0.75em 1.25em;
173
+ transition: background-color var(--lab-transition), color var(--lab-transition);
174
+ }
175
+
176
+ .lab-home__staging:hover,
177
+ .lab-home__staging:focus-visible {
178
+ background-color: var(--lab-color-text-strong);
179
+ color: var(--lab-color-accent-text);
180
+ }
181
+
182
+ .lab-home__tiers {
183
+ display: grid;
184
+ grid-template-columns: repeat(auto-fit, minmax(14em, 1fr));
185
+ gap: 1em;
186
+ margin-top: 2.5em;
187
+ }
188
+
189
+ .tier-card {
190
+ display: flex;
191
+ flex-direction: column;
192
+ gap: 0.5em;
193
+ text-decoration: none;
194
+ border: 1px solid var(--lab-color-border);
195
+ background-color: var(--lab-color-surface);
196
+ padding: 1.25em 1.5em;
197
+ transition: border-color var(--lab-transition);
198
+ }
199
+
200
+ .tier-card:hover,
201
+ .tier-card:focus-visible {
202
+ border-color: var(--lab-color-border-strong);
203
+ }
204
+
205
+ .tier-card__eyebrow {
206
+ font-family: var(--lab-font-mono);
207
+ font-weight: 500;
208
+ font-size: 0.75em;
209
+ color: var(--lab-color-text-faint);
210
+ }
211
+
212
+ .tier-card__name {
213
+ font-family: var(--lab-font-heading);
214
+ font-size: 1.4em;
215
+ font-weight: 500;
216
+ color: var(--lab-color-text-strong);
217
+ }
218
+
219
+ .tier-card__meta {
220
+ display: flex;
221
+ align-items: baseline;
222
+ justify-content: space-between;
223
+ gap: 1em;
224
+ font-family: var(--lab-font-mono);
225
+ font-size: 0.8em;
226
+ color: var(--lab-color-text-faint);
227
+ }
228
+
229
+ .tier-card__live {
230
+ font-weight: 500;
231
+ line-height: 1;
232
+ padding: 0.45em 0.85em;
233
+ border-radius: var(--lab-radius-pill);
234
+ background-color: var(--lab-color-accent);
235
+ color: var(--lab-color-accent-text);
236
+ }
237
+
238
+ .lab-home__branches {
239
+ margin-top: 2.5em;
240
+ }
241
+
242
+ .lab-home__branches ul {
243
+ list-style: none;
244
+ padding: 0;
245
+ margin: 0;
246
+ }
247
+
248
+ .lab-home__branches li {
249
+ display: flex;
250
+ align-items: baseline;
251
+ gap: 1em;
252
+ padding: 0.5em 0;
253
+ border-bottom: 1px solid var(--lab-color-border);
254
+ }
255
+
256
+ .lab-home__branches code {
257
+ font-family: var(--lab-font-mono);
258
+ color: var(--lab-color-text-strong);
259
+ }
260
+
261
+ .lab-home__branches a {
262
+ font-family: var(--lab-font-mono);
263
+ font-size: 0.85em;
264
+ color: var(--lab-color-text-faint);
265
+ text-decoration: none;
266
+ }
267
+
268
+ .lab-home__branches a:hover,
269
+ .lab-home__branches a:focus-visible {
270
+ color: var(--lab-color-text-strong);
271
+ text-decoration: underline;
272
+ }
273
+
274
+ .lab-home__group {
275
+ margin-top: 3em;
276
+ }
277
+
278
+ .lab-home__group-title {
279
+ font-family: var(--lab-font-mono);
280
+ font-weight: 500;
281
+ font-size: 1em;
282
+ color: var(--lab-color-text-muted);
283
+ margin-bottom: 1em;
284
+ padding-bottom: 0.5em;
285
+ border-bottom: 1px solid var(--lab-color-border);
286
+ }
287
+
288
+ .lab-home__group-title a {
289
+ color: inherit;
290
+ text-decoration: none;
291
+ }
292
+
293
+ .lab-home__group-title a:hover,
294
+ .lab-home__group-title a:focus-visible {
295
+ color: var(--lab-color-text-strong);
296
+ text-decoration: underline;
297
+ }
298
+ </style>