@at-flux/astro-feature-flags 1.0.0 → 1.0.3
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 +32 -32
- package/dist/dev-toolbar-app.d.mts +0 -1
- package/dist/dev-toolbar-app.d.mts.map +1 -1
- package/dist/dev-toolbar-app.mjs +1 -1
- package/dist/dev-toolbar-app.mjs.map +1 -1
- package/dist/{dev-toolbar-flag-icon-BHCQJ53N.mjs → dev-toolbar-flag-icon-MQsIFekv.mjs} +1 -1
- package/dist/{dev-toolbar-flag-icon-BHCQJ53N.mjs.map → dev-toolbar-flag-icon-MQsIFekv.mjs.map} +1 -1
- package/dist/index.d.mts +0 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +19 -10
- package/dist/index.mjs.map +1 -1
- package/dist/runtime.d.mts +4 -11
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs.map +1 -1
- package/example/package.json +5 -5
- package/package.json +8 -8
- package/src/dev-inline-runtimes.ts +66 -18
- package/src/dev-outline-css.ts +6 -2
- package/src/dev-toolbar-app.ts +2 -4
- package/src/index.ts +11 -8
- package/src/inline-script.ts +3 -1
- package/src/runtime.ts +18 -11
package/README.md
CHANGED
|
@@ -24,10 +24,10 @@ Feature flags for Astro with a declarative config:
|
|
|
24
24
|
|
|
25
25
|
## Terminology (short)
|
|
26
26
|
|
|
27
|
-
| Term
|
|
28
|
-
|
|
|
29
|
-
| **Astro dev**
|
|
30
|
-
| **Non-dev build**
|
|
27
|
+
| Term | Meaning |
|
|
28
|
+
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
29
|
+
| **Astro dev** | Local `astro dev` — the built-in dev layer is active; all flags on at resolve time; dev toolbar only affects the browser. |
|
|
30
|
+
| **Non-dev build** | `astro build` / preview / deploy with a shipped layer (`prod`, `staging`, …): `environments.<key>.flags` drives SSR, HTML culling, and route pruning. |
|
|
31
31
|
| **`isAstroDev`** (virtual module) | `import.meta.env.DEV` — Vite’s compile-time flag for components. Layer selection still comes from `environments` / `forceEnvironment`; use `isAstroDev` when you need Astro’s literal dev detection. |
|
|
32
32
|
|
|
33
33
|
You cannot add an environment key named **`dev`** — that name is reserved and merged automatically (including its `when`; you do not set it in config).
|
|
@@ -180,18 +180,18 @@ The dev toolbar changes client-side preview state only.
|
|
|
180
180
|
|
|
181
181
|
### Top-level options
|
|
182
182
|
|
|
183
|
-
| Option | Type
|
|
184
|
-
| ------------------ |
|
|
185
|
-
| `configRoot` | `string`
|
|
186
|
-
| `jsonConfigPath` | `string`
|
|
187
|
-
| `forceEnvironment` | `string`
|
|
188
|
-
| `mode` | `string`
|
|
189
|
-
| `env` | `Record<string, string \| undefined>` | `process.env`
|
|
190
|
-
| `tokenNamespace` | `string`
|
|
191
|
-
| `flags` | `Record<string, FlagConfig>`
|
|
192
|
-
| `environments` | `Record<string, EnvironmentConfig>`
|
|
193
|
-
| `css` | `DevOutlineCssOptions`
|
|
194
|
-
| `staticMinify` | `boolean`
|
|
183
|
+
| Option | Type | Default | Notes |
|
|
184
|
+
| ------------------ | ------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
185
|
+
| `configRoot` | `string` | `process.cwd()` | Resolves relative `jsonConfigPath` values (root + per-environment). |
|
|
186
|
+
| `jsonConfigPath` | `string` | unset | Optional **root** JSON file merged after inline config (see merge order for per-environment files). |
|
|
187
|
+
| `forceEnvironment` | `string` | unset | Pin the active layer (skips `when` / `AFF_ENVIRONMENT` validation). |
|
|
188
|
+
| `mode` | `string` | `NODE_ENV` | Optional advanced override for runtime resolution (mainly tests/tooling). Most apps should omit this and rely on `NODE_ENV` + `environments.when`. |
|
|
189
|
+
| `env` | `Record<string, string \| undefined>` | `process.env` | `AFF_FEATURE_*` / `ASTRO_FEATURE_FLAGS` (not applied in `dev` layer). |
|
|
190
|
+
| `tokenNamespace` | `string` | `'ff'` | CSS var namespace (`--ff-c-*`). |
|
|
191
|
+
| `flags` | `Record<string, FlagConfig>` | `{}` | Flag declarations. |
|
|
192
|
+
| `environments` | `Record<string, EnvironmentConfig>` | _(see below)_ | Declare non-`dev` layers only; reserved `dev` is injected. At least one other key; exactly one `when: true` unless forced. |
|
|
193
|
+
| `css` | `DevOutlineCssOptions` | defaults | Global badge/outline layout and styling. |
|
|
194
|
+
| `staticMinify` | `boolean` | `true` | For static builds: route-prune disabled prefixes + cull gated HTML in `dist/`. Set `false` to keep emitted files untouched. |
|
|
195
195
|
|
|
196
196
|
If you omit `environments`, the integration injects a minimal reserved `dev` plus **`prod`** tied to `NODE_ENV` (or `mode` only if you explicitly override it) so `astroFeatureFlags()` still runs in small demos.
|
|
197
197
|
|
|
@@ -210,10 +210,10 @@ The key **`dev`** is reserved: do not list it under `environments`. The integrat
|
|
|
210
210
|
|
|
211
211
|
### `EnvironmentConfig`
|
|
212
212
|
|
|
213
|
-
| Field | Type | Default | Notes
|
|
214
|
-
| ---------------- | ------------------------- | ------- |
|
|
215
|
-
| `when` | `boolean` | unset | Exactly one environment must have `when: true` (unless forced).
|
|
216
|
-
| `flags` | `Record<string, boolean>` | `{}` | For non-`dev` layers: booleans per flag. Ignored for reserved `dev`.
|
|
213
|
+
| Field | Type | Default | Notes |
|
|
214
|
+
| ---------------- | ------------------------- | ------- | -------------------------------------------------------------------------------------------- |
|
|
215
|
+
| `when` | `boolean` | unset | Exactly one environment must have `when: true` (unless forced). |
|
|
216
|
+
| `flags` | `Record<string, boolean>` | `{}` | For non-`dev` layers: booleans per flag. Ignored for reserved `dev`. |
|
|
217
217
|
| `jsonConfigPath` | `string` | unset | Optional JSON merged when this environment is the active layer (not used on reserved `dev`). |
|
|
218
218
|
|
|
219
219
|
Merge order:
|
|
@@ -227,12 +227,12 @@ Layer select override: `AFF_ENVIRONMENT=prod`. **`forceEnvironment`** on the int
|
|
|
227
227
|
|
|
228
228
|
### DevOutlineCssOptions
|
|
229
229
|
|
|
230
|
-
| Field
|
|
231
|
-
|
|
|
232
|
-
| `elementBadgeHorizontalAlign`
|
|
233
|
-
| `elementBadgeHorizontalPercent`
|
|
234
|
-
| `elementBadgeVerticalShiftPercent`
|
|
235
|
-
| `elementBadgeVerticalAnchor`
|
|
230
|
+
| Field | Default | Meaning |
|
|
231
|
+
| ---------------------------------- | --------- | ----------------------------------------------------------------------------------------------- |
|
|
232
|
+
| `elementBadgeHorizontalAlign` | `'end'` | `'start'` \| `'center'` \| `'end'` — LTR: **`end`** = top-right. |
|
|
233
|
+
| `elementBadgeHorizontalPercent` | _(unset)_ | 0–100: horizontal anchor with pill centred (`translateX(-50%)`); overrides align. |
|
|
234
|
+
| `elementBadgeVerticalShiftPercent` | `80` | Vertical shift as **% of the pill height** (default keeps most of the label above the element). |
|
|
235
|
+
| `elementBadgeVerticalAnchor` | `'top'` | `'top'` or `'bottom'`. |
|
|
236
236
|
|
|
237
237
|
Per-element badge overrides (markup):
|
|
238
238
|
|
|
@@ -250,12 +250,12 @@ If your editor misses virtual module types, add one reference in `src/env.d.ts`.
|
|
|
250
250
|
|
|
251
251
|
## Dev toolbar
|
|
252
252
|
|
|
253
|
-
| Control | Effect
|
|
254
|
-
| ----------- |
|
|
253
|
+
| Control | Effect |
|
|
254
|
+
| ----------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
255
255
|
| **Enabled** | Off → hide nodes carrying that token in `data-ff` (including combined hosts/pages when any member token is Off). |
|
|
256
|
-
| **Outline** | Toggle outlines only (element and route frame). For combined hosts this is a non-layout-shifting overlay ring.
|
|
257
|
-
| **Badges** | Toggle badges only (element pills + route pill).
|
|
258
|
-
| **Colour** | `--<namespace>-c-<token>` (persisted).
|
|
256
|
+
| **Outline** | Toggle outlines only (element and route frame). For combined hosts this is a non-layout-shifting overlay ring. |
|
|
257
|
+
| **Badges** | Toggle badges only (element pills + route pill). |
|
|
258
|
+
| **Colour** | `--<namespace>-c-<token>` (persisted). |
|
|
259
259
|
|
|
260
260
|
## Virtual module
|
|
261
261
|
|
|
@@ -275,7 +275,7 @@ Remote percentage rollouts, per-user experiment assignment, analytics, or a host
|
|
|
275
275
|
|
|
276
276
|
## How-to
|
|
277
277
|
|
|
278
|
-
-
|
|
278
|
+
- [Hide feature locked pages from sitemaps in production builds](docs/how-to/hide-from-sitemaps.md)
|
|
279
279
|
|
|
280
280
|
## Example Pages
|
|
281
281
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-toolbar-app.d.mts","names":[],"sources":["../src/dev-toolbar-app.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"dev-toolbar-app.d.mts","names":[],"sources":["../src/dev-toolbar-app.ts"],"mappings":";;QASQ;YACI;IACR;MACE;MACA,SAAS;MACT;;;;cAmHA,kBAAkB"}
|
package/dist/dev-toolbar-app.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as DEV_TOOLBAR_FLAG_ICON_SVG } from "./dev-toolbar-flag-icon-
|
|
1
|
+
import { t as DEV_TOOLBAR_FLAG_ICON_SVG } from "./dev-toolbar-flag-icon-MQsIFekv.mjs";
|
|
2
2
|
import { defineToolbarApp } from "astro/toolbar";
|
|
3
3
|
import { closeOnOutsideClick, createWindowElement, synchronizePlacementOnUpdate } from "astro/runtime/client/dev-toolbar/apps/utils/window.js";
|
|
4
4
|
//#region src/dev-toolbar-app.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-toolbar-app.mjs","names":[],"sources":["../src/dev-toolbar-app.ts"],"sourcesContent":["import type { DevToolbarApp } from \"astro\";\nimport { defineToolbarApp } from \"astro/toolbar\";\nimport {\n closeOnOutsideClick,\n createWindowElement,\n synchronizePlacementOnUpdate,\n} from \"astro/runtime/client/dev-toolbar/apps/utils/window.js\";\nimport { DEV_TOOLBAR_FLAG_ICON_SVG } from \"./dev-toolbar-flag-icon\";\n\ndeclare global {\n interface Window {\n __AFF__?: {\n tokens: string[];\n colors?: Record<string, string>;\n namespace?: string;\n };\n }\n}\n\ntype AffState = {\n enabled: Record<string, boolean>;\n outline: Record<string, boolean>;\n badge: Record<string, boolean>;\n colors: Record<string, string>;\n};\n\nfunction toHexColor(raw: string | undefined, fallback: string): string {\n if (!raw) return fallback;\n const s = raw.trim();\n const hex7 = s.match(/^#([0-9a-fA-F]{6})$/);\n if (hex7) return `#${hex7[1]!.toLowerCase()}`;\n const rgb = s.match(/rgba?\\(\\s*([\\d.]+)[,\\s]+([\\d.]+)[,\\s]+([\\d.]+)/);\n if (rgb) {\n const r = Math.min(255, Math.round(Number(rgb[1])));\n const g = Math.min(255, Math.round(Number(rgb[2])));\n const b = Math.min(255, Math.round(Number(rgb[3])));\n return `#${[r, g, b].map((x) => x.toString(16).padStart(2, \"0\")).join(\"\")}`;\n }\n return fallback;\n}\n\nfunction readMeta(): {\n tokens: string[];\n colors: Record<string, string>;\n namespace: string;\n} {\n try {\n const raw = window.__AFF__;\n const tokens = raw && Array.isArray(raw.tokens) ? raw.tokens : [];\n const colors =\n raw?.colors && typeof raw.colors === \"object\" ? raw.colors : {};\n const namespace = raw?.namespace?.trim() ? raw.namespace.trim() : \"ff\";\n return { tokens, colors, namespace };\n } catch {\n return { tokens: [], colors: {}, namespace: \"ff\" };\n }\n}\n\nfunction storageKey(namespace: string): string {\n return `${namespace}.dev.v1`;\n}\n\nfunction loadState(tokens: string[], namespace: string): AffState {\n const next: AffState = {\n enabled: {},\n outline: {},\n badge: {},\n colors: {},\n };\n for (const t of tokens) {\n next.enabled[t] = true;\n next.outline[t] = true;\n next.badge[t] = true;\n }\n try {\n const raw =\n localStorage.getItem(storageKey(namespace)) ||\n localStorage.getItem(\"aff.dev.v1\");\n if (!raw) return next;\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n const outline = (parsed.outline ?? parsed.chrome) as\n | Record<string, boolean>\n | undefined;\n const enabled = (parsed.enabled ?? parsed.render) as\n | Record<string, boolean>\n | undefined;\n const badge = parsed.badge as Record<string, boolean> | undefined;\n const colors = parsed.colors as Record<string, string> | undefined;\n if (outline) Object.assign(next.outline, outline);\n if (enabled) Object.assign(next.enabled, enabled);\n if (badge) Object.assign(next.badge, badge);\n if (colors) Object.assign(next.colors, colors);\n } catch {\n /* ignore */\n }\n return next;\n}\n\nfunction persist(state: AffState, namespace: string) {\n try {\n localStorage.setItem(storageKey(namespace), JSON.stringify(state));\n } catch {\n /* ignore */\n }\n}\n\nfunction applyDom(\n tokens: string[],\n state: AffState,\n defaults: Record<string, string>,\n namespace: string,\n) {\n const root = document.documentElement;\n for (const t of tokens) {\n if (state.outline[t] !== false)\n root.removeAttribute(`data-ff-outline-${t}`);\n else root.setAttribute(`data-ff-outline-${t}`, \"off\");\n\n if (state.enabled[t] !== false)\n root.removeAttribute(`data-ff-enabled-${t}`);\n else root.setAttribute(`data-ff-enabled-${t}`, \"off\");\n\n if (state.badge[t] !== false) root.removeAttribute(`data-ff-badge-${t}`);\n else root.setAttribute(`data-ff-badge-${t}`, \"off\");\n\n const col = state.colors[t] ?? defaults[t];\n if (col) root.style.setProperty(`--${namespace}-c-${t}`, col);\n else root.style.removeProperty(`--${namespace}-c-${t}`);\n }\n}\n\nconst affDevToolbarApp: DevToolbarApp = defineToolbarApp({\n init(canvas, eventTarget) {\n let state = loadState([], \"ff\");\n let tokens: string[] = [];\n let namespace = \"ff\";\n\n function mount() {\n canvas.querySelector(\"astro-dev-toolbar-window\")?.remove();\n const {\n tokens: nextTokens,\n colors: defaultColors,\n namespace: ns,\n } = readMeta();\n tokens = nextTokens;\n namespace = ns;\n state = loadState(tokens, namespace);\n applyDom(tokens, state, defaultColors, namespace);\n\n const windowElement = createWindowElement(`\n\t\t\t\t<style>\n\t\t\t\t\t:host astro-dev-toolbar-window {\n\t\t\t\t\t\theight: min(520px, 78vh);\n\t\t\t\t\t\toverflow-y: auto;\n\t\t\t\t\t\tcolor-scheme: dark;\n\t\t\t\t\t\t--color-muted: rgba(191, 193, 201, 1);\n\t\t\t\t\t\t--color-purple: rgba(224, 204, 250, 1);\n\t\t\t\t\t}\n\t\t\t\t\theader {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tjustify-content: space-between;\n\t\t\t\t\t\tgap: 12px;\n\t\t\t\t\t}\n\t\t\t\t\th1 {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tgap: 8px;\n\t\t\t\t\t\tfont-weight: 600;\n\t\t\t\t\t\tcolor: #fff;\n\t\t\t\t\t\tmargin: 0;\n\t\t\t\t\t\tfont-size: 22px;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag-toolbar-icon {\n\t\t\t\t\t\tdisplay: inline-flex;\n\t\t\t\t\t\twidth: 1em;\n\t\t\t\t\t\theight: 1em;\n\t\t\t\t\t\tflex-shrink: 0;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tjustify-content: center;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag-toolbar-icon svg {\n\t\t\t\t\t\twidth: 100%;\n\t\t\t\t\t\theight: 100%;\n\t\t\t\t\t\tdisplay: block;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-intro {\n\t\t\t\t\t\tmargin: 0;\n\t\t\t\t\t\tfont-size: 14px;\n\t\t\t\t\t\tline-height: 1.5rem;\n\t\t\t\t\t\tcolor: var(--color-muted);\n margin-bottom: 1rem;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-top {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\talign-items: flex-start;\n\t\t\t\t\t\tjustify-content: space-between;\n\t\t\t\t\t\tgap: 12px;\n\t\t\t\t\t\tmargin: 1rem 0;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-top-left {\n\t\t\t\t\t\tflex: 1;\n\t\t\t\t\t\tmin-width: 0;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-help {\n\t\t\t\t\t\tdisplay: grid;\n\t\t\t\t\t\tgrid-template-columns: minmax(7.5rem, auto) 1fr;\n\t\t\t\t\t\tgap: 0.45rem 0.75rem;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-help code,\n\t\t\t\t\t.aff-help span {\n\t\t\t\t\t\tfont-size: 12px;\n\t\t\t\t\t\tline-height: 1.35;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-help code {\n\t\t\t\t\t\tjustify-self: start;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-actions {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\tjustify-content: flex-end;\n\t\t\t\t\t\tmargin: 0;\n\t\t\t\t\t\tflex-shrink: 0;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-reset {\n\t\t\t\t\t\tborder: 1px solid #343841;\n\t\t\t\t\t\tborder-radius: 0.5rem;\n\t\t\t\t\t\tbackground: #24262d;\n\t\t\t\t\t\tcolor: #fff;\n\t\t\t\t\t\tpadding: 0.3rem 0.55rem;\n\t\t\t\t\t\tfont-size: 12px;\n\t\t\t\t\t\tcursor: pointer;\n\t\t\t\t\t}\n\t\t\t\t\thr {\n\t\t\t\t\t\tborder: 1px solid rgba(27, 30, 36, 1);\n\t\t\t\t\t\tmargin: 1em 0;\n\t\t\t\t\t}\n\t\t\t\t\t.setting-row {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\tjustify-content: space-between;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tgap: 12px;\n\t\t\t\t\t\tmargin: 0 0 8px;\n\t\t\t\t\t}\n\t\t\t\t\t.setting-row section { flex: 1; min-width: 0; max-width: 54%; }\n\t\t\t\t\th3.aff-row-title {\n\t\t\t\t\t\tfont-size: 12px;\n\t\t\t\t\t\tfont-weight: 600;\n\t\t\t\t\t\tcolor: #fff;\n\t\t\t\t\t\tletter-spacing: 0.05em;\n\t\t\t\t\t\ttext-transform: uppercase;\n\t\t\t\t\t\tmargin: 0;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-radios {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\tgap: 8px;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tflex-shrink: 0;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-radios label {\n\t\t\t\t\t\tdisplay: inline-flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tgap: 4px;\n\t\t\t\t\t\tfont-size: 11px;\n\t\t\t\t\t\tcursor: pointer;\n\t\t\t\t\t\tcolor: var(--color-muted);\n\t\t\t\t\t\tletter-spacing: 0.04em;\n\t\t\t\t\t\ttext-transform: uppercase;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-radios input { accent-color: var(--color-purple); cursor: pointer; }\n\t\t\t\t\t.aff-flag {\n\t\t\t\t\t\tmargin: 0 0 12px;\n\t\t\t\t\t\tborder: 1px solid rgba(52, 56, 65, 1);\n\t\t\t\t\t\tborder-radius: 10px;\n\t\t\t\t\t\tpadding: 0 10px 10px;\n\t\t\t\t\t\tbackground: rgba(19, 21, 26, 0.55);\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag summary {\n\t\t\t\t\t\tlist-style: none;\n\t\t\t\t\t\tcursor: pointer;\n\t\t\t\t\t\tuser-select: none;\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tgap: 8px;\n\t\t\t\t\t\tpadding: 10px 0;\n\t\t\t\t\t\tfont-weight: 600;\n\t\t\t\t\t\tfont-size: 11px;\n\t\t\t\t\t\tletter-spacing: 0.06em;\n\t\t\t\t\t\ttext-transform: uppercase;\n\t\t\t\t\t\tcolor: #fff;\n\t\t\t\t\t\tjustify-content: space-between;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag summary::-webkit-details-marker { display: none; }\n\t\t\t\t\t.aff-flag summary::after {\n\t\t\t\t\t\tcontent: '▸';\n\t\t\t\t\t\tdisplay: inline-flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tjustify-content: center;\n\t\t\t\t\t\tmargin-left: auto;\n\t\t\t\t\t\tcolor: var(--color-muted);\n\t\t\t\t\t\tfont-size: 12px;\n\t\t\t\t\t\ttransform: rotate(0deg);\n\t\t\t\t\t\ttransition: transform 0.12s ease;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag[open] summary::after {\n\t\t\t\t\t\ttransform: rotate(90deg);\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag-summary-left {\n\t\t\t\t\t\tdisplay: inline-flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tgap: 8px;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-swatch {\n\t\t\t\t\t\twidth: 10px;\n\t\t\t\t\t\theight: 10px;\n\t\t\t\t\t\tborder-radius: 9999px;\n\t\t\t\t\t\tflex-shrink: 0;\n\t\t\t\t\t\tbox-shadow: inset 0 0 0 1px rgba(255,255,255,0.12);\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag-body { padding-top: 2px; }\n\t\t\t\t\t.aff-empty {\n\t\t\t\t\t\tmargin: 0;\n\t\t\t\t\t\tfont-size: 14px;\n\t\t\t\t\t\tline-height: 1.5rem;\n\t\t\t\t\t\tcolor: var(--color-muted);\n\t\t\t\t\t}\n\t\t\t\t\tcode {\n\t\t\t\t\t\tcolor: var(--color-purple);\n\t\t\t\t\t\tborder: 1px solid #343841;\n\t\t\t\t\t\tborder-radius: 0.35em;\n\t\t\t\t\t\tbackground-color: #24262d;\n\t\t\t\t\t\tpadding: 0.15em 0.35em;\n\t\t\t\t\t\tfont-size: 0.9em;\n\t\t\t\t\t}\n\t\t\t\t\tinput[type=\"color\"].aff-color {\n\t\t\t\t\t\twidth: 2.25rem;\n\t\t\t\t\t\theight: 1.75rem;\n\t\t\t\t\t\tpadding: 0;\n\t\t\t\t\t\tborder: 1px solid #343841;\n\t\t\t\t\t\tborder-radius: 6px;\n\t\t\t\t\t\tcursor: pointer;\n\t\t\t\t\t\tbackground: transparent;\n\t\t\t\t\t}\n\t\t\t\t</style>\n\t\t\t\t<header>\n\t\t\t\t\t<h1><span class=\"aff-flag-toolbar-icon\">${DEV_TOOLBAR_FLAG_ICON_SVG}</span> Feature flags</h1>\n\t\t\t\t\t<div class=\"aff-actions\"><button id=\"aff-reset\" class=\"aff-reset\" type=\"button\" title=\"Reset all flags to defaults\">Reset all</button></div>\n\t\t\t\t</header>\n\t\t\t\t<div class=\"aff-top\">\n\t\t\t\t\t<div class=\"aff-top-left\">\n\t\t\t\t\t\t<p class=\"aff-intro\">Per-flag preview for <code>data-${namespace}</code> regions.</p>\n\t\t\t\t<div class=\"aff-help\">\n\t\t\t\t\t<code>Enabled</code><span>Show/hide flagged regions in preview.</span>\n\t\t\t\t\t<code>Outline</code><span>Toggle flag outlines without changing layout.</span>\n\t\t\t\t\t<code>Badges</code><span>Toggle element and route labels.</span>\n\t\t\t\t\t<code>Colour</code><span>Set <code>--${namespace}-c-<token></code> on <code><html></code>.</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<hr />\n\t\t\t\t<div id=\"aff-body\"></div>\n\t\t\t`);\n\n const body = windowElement.querySelector(\"#aff-body\");\n const resetBtn = windowElement.querySelector(\n \"#aff-reset\",\n ) as HTMLButtonElement | null;\n\n if (body) {\n if (tokens.length === 0) {\n const p = document.createElement(\"p\");\n p.className = \"aff-empty\";\n p.textContent = \"No flags in ff.json.\";\n body.append(p);\n } else {\n for (const token of tokens) {\n const details = document.createElement(\"details\");\n details.className = \"aff-flag\";\n details.open = tokens.length <= 8;\n\n const summary = document.createElement(\"summary\");\n const summaryLeft = document.createElement(\"span\");\n summaryLeft.className = \"aff-flag-summary-left\";\n const swatch = document.createElement(\"span\");\n swatch.className = \"aff-swatch\";\n const name = document.createElement(\"span\");\n name.textContent = token;\n summaryLeft.append(swatch, name);\n summary.append(summaryLeft);\n\n const syncSwatch = () => {\n const c =\n state.colors[token] ?? defaultColors[token] ?? \"#888888\";\n swatch.style.background = c;\n };\n syncSwatch();\n\n const inner = document.createElement(\"div\");\n inner.className = \"aff-flag-body\";\n\n const row = (\n title: string,\n tooltip: string,\n key: keyof Pick<AffState, \"enabled\" | \"outline\" | \"badge\">,\n onLab: string,\n offLab: string,\n ) => {\n const label = document.createElement(\"label\");\n label.className = \"setting-row\";\n const section = document.createElement(\"section\");\n const h = document.createElement(\"h3\");\n h.className = \"aff-row-title\";\n h.textContent = title;\n section.append(h);\n const radios = document.createElement(\"div\");\n radios.className = \"aff-radios\";\n const mk = (on: boolean, lab: string) => {\n const wrap = document.createElement(\"label\");\n const inp = document.createElement(\"input\");\n inp.type = \"radio\";\n inp.name = `aff-${token}-${key}`;\n const cur = state[key][token] !== false;\n inp.checked = on ? cur : !cur;\n inp.addEventListener(\"change\", () => {\n if (!inp.checked) return;\n state[key][token] = on;\n applyDom(tokens, state, defaultColors, namespace);\n persist(state, namespace);\n });\n wrap.append(inp, document.createTextNode(lab));\n return wrap;\n };\n radios.append(mk(true, onLab), mk(false, offLab));\n label.append(section, radios);\n return label;\n };\n\n inner.append(\n row(\n \"Enabled\",\n \"When off, nodes with this flag token are hidden in preview.\",\n \"enabled\",\n \"On\",\n \"Off\",\n ),\n row(\n \"Outline\",\n \"Toggles dashed outline around flagged elements.\",\n \"outline\",\n \"On\",\n \"Off\",\n ),\n row(\n \"Badges\",\n \"Toggles element badges and top-right route pill.\",\n \"badge\",\n \"On\",\n \"Off\",\n ),\n );\n\n const colorRow = document.createElement(\"label\");\n colorRow.className = \"setting-row\";\n const csection = document.createElement(\"section\");\n const ch = document.createElement(\"h3\");\n ch.className = \"aff-row-title\";\n ch.textContent = \"Colour\";\n ch.title = `Maps to CSS --${namespace}-c-<token> on <html>.`;\n csection.append(ch);\n const cinp = document.createElement(\"input\");\n cinp.type = \"color\";\n cinp.className = \"aff-color\";\n cinp.title = `Set --${namespace}-c-${token}`;\n cinp.value = toHexColor(\n state.colors[token] ?? defaultColors[token],\n \"#888888\",\n );\n cinp.addEventListener(\"input\", () => {\n state.colors[token] = cinp.value;\n syncSwatch();\n applyDom(tokens, state, defaultColors, namespace);\n persist(state, namespace);\n });\n colorRow.append(csection, cinp);\n inner.append(colorRow);\n\n details.append(summary, inner);\n body.append(details);\n }\n }\n }\n\n if (resetBtn) {\n resetBtn.addEventListener(\"click\", () => {\n try {\n localStorage.removeItem(storageKey(namespace));\n localStorage.removeItem(\"aff.dev.v1\");\n } catch {\n // ignore\n }\n state = loadState(tokens, namespace);\n applyDom(tokens, state, defaultColors, namespace);\n mount();\n });\n }\n\n canvas.append(windowElement);\n }\n\n mount();\n document.addEventListener(\"astro:after-swap\", mount);\n closeOnOutsideClick(eventTarget);\n synchronizePlacementOnUpdate(eventTarget, canvas);\n },\n});\n\nexport default affDevToolbarApp;\n"],"mappings":";;;;AA0BA,SAAS,WAAW,KAAyB,UAA0B;AACrE,KAAI,CAAC,IAAK,QAAO;CACjB,MAAM,IAAI,IAAI,MAAM;CACpB,MAAM,OAAO,EAAE,MAAM,sBAAsB;AAC3C,KAAI,KAAM,QAAO,IAAI,KAAK,GAAI,aAAa;CAC3C,MAAM,MAAM,EAAE,MAAM,iDAAiD;AACrE,KAAI,IAIF,QAAO,IAAI;EAHD,KAAK,IAAI,KAAK,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,CAAC;EACzC,KAAK,IAAI,KAAK,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,CAAC;EACzC,KAAK,IAAI,KAAK,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,CAAC;EAC/B,CAAC,KAAK,MAAM,EAAE,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG;AAE3E,QAAO;;AAGT,SAAS,WAIP;AACA,KAAI;EACF,MAAM,MAAM,OAAO;AAKnB,SAAO;GAAE,QAJM,OAAO,MAAM,QAAQ,IAAI,OAAO,GAAG,IAAI,SAAS,EAAE;GAIhD,QAFf,KAAK,UAAU,OAAO,IAAI,WAAW,WAAW,IAAI,SAAS,EAAE;GAExC,WADP,KAAK,WAAW,MAAM,GAAG,IAAI,UAAU,MAAM,GAAG;GAC9B;SAC9B;AACN,SAAO;GAAE,QAAQ,EAAE;GAAE,QAAQ,EAAE;GAAE,WAAW;GAAM;;;AAItD,SAAS,WAAW,WAA2B;AAC7C,QAAO,GAAG,UAAU;;AAGtB,SAAS,UAAU,QAAkB,WAA6B;CAChE,MAAM,OAAiB;EACrB,SAAS,EAAE;EACX,SAAS,EAAE;EACX,OAAO,EAAE;EACT,QAAQ,EAAE;EACX;AACD,MAAK,MAAM,KAAK,QAAQ;AACtB,OAAK,QAAQ,KAAK;AAClB,OAAK,QAAQ,KAAK;AAClB,OAAK,MAAM,KAAK;;AAElB,KAAI;EACF,MAAM,MACJ,aAAa,QAAQ,WAAW,UAAU,CAAC,IAC3C,aAAa,QAAQ,aAAa;AACpC,MAAI,CAAC,IAAK,QAAO;EACjB,MAAM,SAAS,KAAK,MAAM,IAAI;EAC9B,MAAM,UAAW,OAAO,WAAW,OAAO;EAG1C,MAAM,UAAW,OAAO,WAAW,OAAO;EAG1C,MAAM,QAAQ,OAAO;EACrB,MAAM,SAAS,OAAO;AACtB,MAAI,QAAS,QAAO,OAAO,KAAK,SAAS,QAAQ;AACjD,MAAI,QAAS,QAAO,OAAO,KAAK,SAAS,QAAQ;AACjD,MAAI,MAAO,QAAO,OAAO,KAAK,OAAO,MAAM;AAC3C,MAAI,OAAQ,QAAO,OAAO,KAAK,QAAQ,OAAO;SACxC;AAGR,QAAO;;AAGT,SAAS,QAAQ,OAAiB,WAAmB;AACnD,KAAI;AACF,eAAa,QAAQ,WAAW,UAAU,EAAE,KAAK,UAAU,MAAM,CAAC;SAC5D;;AAKV,SAAS,SACP,QACA,OACA,UACA,WACA;CACA,MAAM,OAAO,SAAS;AACtB,MAAK,MAAM,KAAK,QAAQ;AACtB,MAAI,MAAM,QAAQ,OAAO,MACvB,MAAK,gBAAgB,mBAAmB,IAAI;MACzC,MAAK,aAAa,mBAAmB,KAAK,MAAM;AAErD,MAAI,MAAM,QAAQ,OAAO,MACvB,MAAK,gBAAgB,mBAAmB,IAAI;MACzC,MAAK,aAAa,mBAAmB,KAAK,MAAM;AAErD,MAAI,MAAM,MAAM,OAAO,MAAO,MAAK,gBAAgB,iBAAiB,IAAI;MACnE,MAAK,aAAa,iBAAiB,KAAK,MAAM;EAEnD,MAAM,MAAM,MAAM,OAAO,MAAM,SAAS;AACxC,MAAI,IAAK,MAAK,MAAM,YAAY,KAAK,UAAU,KAAK,KAAK,IAAI;MACxD,MAAK,MAAM,eAAe,KAAK,UAAU,KAAK,IAAI;;;AAI3D,MAAM,mBAAkC,iBAAiB,EACvD,KAAK,QAAQ,aAAa;CACxB,IAAI,QAAQ,UAAU,EAAE,EAAE,KAAK;CAC/B,IAAI,SAAmB,EAAE;CACzB,IAAI,YAAY;CAEhB,SAAS,QAAQ;AACf,SAAO,cAAc,2BAA2B,EAAE,QAAQ;EAC1D,MAAM,EACJ,QAAQ,YACR,QAAQ,eACR,WAAW,OACT,UAAU;AACd,WAAS;AACT,cAAY;AACZ,UAAQ,UAAU,QAAQ,UAAU;AACpC,WAAS,QAAQ,OAAO,eAAe,UAAU;EAEjD,MAAM,gBAAgB,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CAmMD,0BAA0B;;;;;6DAKZ,UAAU;;;;;4CAK3B,UAAU;;;;;;KAMjD;EAEC,MAAM,OAAO,cAAc,cAAc,YAAY;EACrD,MAAM,WAAW,cAAc,cAC7B,aACD;AAED,MAAI,KACF,KAAI,OAAO,WAAW,GAAG;GACvB,MAAM,IAAI,SAAS,cAAc,IAAI;AACrC,KAAE,YAAY;AACd,KAAE,cAAc;AAChB,QAAK,OAAO,EAAE;QAEd,MAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,UAAU,SAAS,cAAc,UAAU;AACjD,WAAQ,YAAY;AACpB,WAAQ,OAAO,OAAO,UAAU;GAEhC,MAAM,UAAU,SAAS,cAAc,UAAU;GACjD,MAAM,cAAc,SAAS,cAAc,OAAO;AAClD,eAAY,YAAY;GACxB,MAAM,SAAS,SAAS,cAAc,OAAO;AAC7C,UAAO,YAAY;GACnB,MAAM,OAAO,SAAS,cAAc,OAAO;AAC3C,QAAK,cAAc;AACnB,eAAY,OAAO,QAAQ,KAAK;AAChC,WAAQ,OAAO,YAAY;GAE3B,MAAM,mBAAmB;IACvB,MAAM,IACJ,MAAM,OAAO,UAAU,cAAc,UAAU;AACjD,WAAO,MAAM,aAAa;;AAE5B,eAAY;GAEZ,MAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,SAAM,YAAY;GAElB,MAAM,OACJ,OACA,SACA,KACA,OACA,WACG;IACH,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,UAAM,YAAY;IAClB,MAAM,UAAU,SAAS,cAAc,UAAU;IACjD,MAAM,IAAI,SAAS,cAAc,KAAK;AACtC,MAAE,YAAY;AACd,MAAE,cAAc;AAChB,YAAQ,OAAO,EAAE;IACjB,MAAM,SAAS,SAAS,cAAc,MAAM;AAC5C,WAAO,YAAY;IACnB,MAAM,MAAM,IAAa,QAAgB;KACvC,MAAM,OAAO,SAAS,cAAc,QAAQ;KAC5C,MAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,SAAI,OAAO;AACX,SAAI,OAAO,OAAO,MAAM,GAAG;KAC3B,MAAM,MAAM,MAAM,KAAK,WAAW;AAClC,SAAI,UAAU,KAAK,MAAM,CAAC;AAC1B,SAAI,iBAAiB,gBAAgB;AACnC,UAAI,CAAC,IAAI,QAAS;AAClB,YAAM,KAAK,SAAS;AACpB,eAAS,QAAQ,OAAO,eAAe,UAAU;AACjD,cAAQ,OAAO,UAAU;OACzB;AACF,UAAK,OAAO,KAAK,SAAS,eAAe,IAAI,CAAC;AAC9C,YAAO;;AAET,WAAO,OAAO,GAAG,MAAM,MAAM,EAAE,GAAG,OAAO,OAAO,CAAC;AACjD,UAAM,OAAO,SAAS,OAAO;AAC7B,WAAO;;AAGT,SAAM,OACJ,IACE,WACA,+DACA,WACA,MACA,MACD,EACD,IACE,WACA,mDACA,WACA,MACA,MACD,EACD,IACE,UACA,oDACA,SACA,MACA,MACD,CACF;GAED,MAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,YAAS,YAAY;GACrB,MAAM,WAAW,SAAS,cAAc,UAAU;GAClD,MAAM,KAAK,SAAS,cAAc,KAAK;AACvC,MAAG,YAAY;AACf,MAAG,cAAc;AACjB,MAAG,QAAQ,iBAAiB,UAAU;AACtC,YAAS,OAAO,GAAG;GACnB,MAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,QAAK,OAAO;AACZ,QAAK,YAAY;AACjB,QAAK,QAAQ,SAAS,UAAU,KAAK;AACrC,QAAK,QAAQ,WACX,MAAM,OAAO,UAAU,cAAc,QACrC,UACD;AACD,QAAK,iBAAiB,eAAe;AACnC,UAAM,OAAO,SAAS,KAAK;AAC3B,gBAAY;AACZ,aAAS,QAAQ,OAAO,eAAe,UAAU;AACjD,YAAQ,OAAO,UAAU;KACzB;AACF,YAAS,OAAO,UAAU,KAAK;AAC/B,SAAM,OAAO,SAAS;AAEtB,WAAQ,OAAO,SAAS,MAAM;AAC9B,QAAK,OAAO,QAAQ;;AAK1B,MAAI,SACF,UAAS,iBAAiB,eAAe;AACvC,OAAI;AACF,iBAAa,WAAW,WAAW,UAAU,CAAC;AAC9C,iBAAa,WAAW,aAAa;WAC/B;AAGR,WAAQ,UAAU,QAAQ,UAAU;AACpC,YAAS,QAAQ,OAAO,eAAe,UAAU;AACjD,UAAO;IACP;AAGJ,SAAO,OAAO,cAAc;;AAG9B,QAAO;AACP,UAAS,iBAAiB,oBAAoB,MAAM;AACpD,qBAAoB,YAAY;AAChC,8BAA6B,aAAa,OAAO;GAEpD,CAAC"}
|
|
1
|
+
{"version":3,"file":"dev-toolbar-app.mjs","names":[],"sources":["../src/dev-toolbar-app.ts"],"sourcesContent":["import type { DevToolbarApp } from \"astro\";\nimport { defineToolbarApp } from \"astro/toolbar\";\nimport {\n closeOnOutsideClick,\n createWindowElement,\n synchronizePlacementOnUpdate,\n} from \"astro/runtime/client/dev-toolbar/apps/utils/window.js\";\nimport { DEV_TOOLBAR_FLAG_ICON_SVG } from \"./dev-toolbar-flag-icon\";\n\ndeclare global {\n interface Window {\n __AFF__?: {\n tokens: string[];\n colors?: Record<string, string>;\n namespace?: string;\n };\n }\n}\n\ntype AffState = {\n enabled: Record<string, boolean>;\n outline: Record<string, boolean>;\n badge: Record<string, boolean>;\n colors: Record<string, string>;\n};\n\nfunction toHexColor(raw: string | undefined, fallback: string): string {\n if (!raw) return fallback;\n const s = raw.trim();\n const hex7 = s.match(/^#([0-9a-fA-F]{6})$/);\n if (hex7) return `#${hex7[1]!.toLowerCase()}`;\n const rgb = s.match(/rgba?\\(\\s*([\\d.]+)[,\\s]+([\\d.]+)[,\\s]+([\\d.]+)/);\n if (rgb) {\n const r = Math.min(255, Math.round(Number(rgb[1])));\n const g = Math.min(255, Math.round(Number(rgb[2])));\n const b = Math.min(255, Math.round(Number(rgb[3])));\n return `#${[r, g, b].map((x) => x.toString(16).padStart(2, \"0\")).join(\"\")}`;\n }\n return fallback;\n}\n\nfunction readMeta(): {\n tokens: string[];\n colors: Record<string, string>;\n namespace: string;\n} {\n try {\n const raw = window.__AFF__;\n const tokens = raw && Array.isArray(raw.tokens) ? raw.tokens : [];\n const colors =\n raw?.colors && typeof raw.colors === \"object\" ? raw.colors : {};\n const namespace = raw?.namespace?.trim() ? raw.namespace.trim() : \"ff\";\n return { tokens, colors, namespace };\n } catch {\n return { tokens: [], colors: {}, namespace: \"ff\" };\n }\n}\n\nfunction storageKey(namespace: string): string {\n return `${namespace}.dev.v1`;\n}\n\nfunction loadState(tokens: string[], namespace: string): AffState {\n const next: AffState = {\n enabled: {},\n outline: {},\n badge: {},\n colors: {},\n };\n for (const t of tokens) {\n next.enabled[t] = true;\n next.outline[t] = true;\n next.badge[t] = true;\n }\n try {\n const raw =\n localStorage.getItem(storageKey(namespace)) ||\n localStorage.getItem(\"aff.dev.v1\");\n if (!raw) return next;\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n const outline = (parsed.outline ?? parsed.chrome) as\n Record<string, boolean> | undefined;\n const enabled = (parsed.enabled ?? parsed.render) as\n Record<string, boolean> | undefined;\n const badge = parsed.badge as Record<string, boolean> | undefined;\n const colors = parsed.colors as Record<string, string> | undefined;\n if (outline) Object.assign(next.outline, outline);\n if (enabled) Object.assign(next.enabled, enabled);\n if (badge) Object.assign(next.badge, badge);\n if (colors) Object.assign(next.colors, colors);\n } catch {\n /* ignore */\n }\n return next;\n}\n\nfunction persist(state: AffState, namespace: string) {\n try {\n localStorage.setItem(storageKey(namespace), JSON.stringify(state));\n } catch {\n /* ignore */\n }\n}\n\nfunction applyDom(\n tokens: string[],\n state: AffState,\n defaults: Record<string, string>,\n namespace: string,\n) {\n const root = document.documentElement;\n for (const t of tokens) {\n if (state.outline[t] !== false)\n root.removeAttribute(`data-ff-outline-${t}`);\n else root.setAttribute(`data-ff-outline-${t}`, \"off\");\n\n if (state.enabled[t] !== false)\n root.removeAttribute(`data-ff-enabled-${t}`);\n else root.setAttribute(`data-ff-enabled-${t}`, \"off\");\n\n if (state.badge[t] !== false) root.removeAttribute(`data-ff-badge-${t}`);\n else root.setAttribute(`data-ff-badge-${t}`, \"off\");\n\n const col = state.colors[t] ?? defaults[t];\n if (col) root.style.setProperty(`--${namespace}-c-${t}`, col);\n else root.style.removeProperty(`--${namespace}-c-${t}`);\n }\n}\n\nconst affDevToolbarApp: DevToolbarApp = defineToolbarApp({\n init(canvas, eventTarget) {\n let state = loadState([], \"ff\");\n let tokens: string[] = [];\n let namespace = \"ff\";\n\n function mount() {\n canvas.querySelector(\"astro-dev-toolbar-window\")?.remove();\n const {\n tokens: nextTokens,\n colors: defaultColors,\n namespace: ns,\n } = readMeta();\n tokens = nextTokens;\n namespace = ns;\n state = loadState(tokens, namespace);\n applyDom(tokens, state, defaultColors, namespace);\n\n const windowElement = createWindowElement(`\n\t\t\t\t<style>\n\t\t\t\t\t:host astro-dev-toolbar-window {\n\t\t\t\t\t\theight: min(520px, 78vh);\n\t\t\t\t\t\toverflow-y: auto;\n\t\t\t\t\t\tcolor-scheme: dark;\n\t\t\t\t\t\t--color-muted: rgba(191, 193, 201, 1);\n\t\t\t\t\t\t--color-purple: rgba(224, 204, 250, 1);\n\t\t\t\t\t}\n\t\t\t\t\theader {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tjustify-content: space-between;\n\t\t\t\t\t\tgap: 12px;\n\t\t\t\t\t}\n\t\t\t\t\th1 {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tgap: 8px;\n\t\t\t\t\t\tfont-weight: 600;\n\t\t\t\t\t\tcolor: #fff;\n\t\t\t\t\t\tmargin: 0;\n\t\t\t\t\t\tfont-size: 22px;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag-toolbar-icon {\n\t\t\t\t\t\tdisplay: inline-flex;\n\t\t\t\t\t\twidth: 1em;\n\t\t\t\t\t\theight: 1em;\n\t\t\t\t\t\tflex-shrink: 0;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tjustify-content: center;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag-toolbar-icon svg {\n\t\t\t\t\t\twidth: 100%;\n\t\t\t\t\t\theight: 100%;\n\t\t\t\t\t\tdisplay: block;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-intro {\n\t\t\t\t\t\tmargin: 0;\n\t\t\t\t\t\tfont-size: 14px;\n\t\t\t\t\t\tline-height: 1.5rem;\n\t\t\t\t\t\tcolor: var(--color-muted);\n margin-bottom: 1rem;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-top {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\talign-items: flex-start;\n\t\t\t\t\t\tjustify-content: space-between;\n\t\t\t\t\t\tgap: 12px;\n\t\t\t\t\t\tmargin: 1rem 0;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-top-left {\n\t\t\t\t\t\tflex: 1;\n\t\t\t\t\t\tmin-width: 0;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-help {\n\t\t\t\t\t\tdisplay: grid;\n\t\t\t\t\t\tgrid-template-columns: minmax(7.5rem, auto) 1fr;\n\t\t\t\t\t\tgap: 0.45rem 0.75rem;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-help code,\n\t\t\t\t\t.aff-help span {\n\t\t\t\t\t\tfont-size: 12px;\n\t\t\t\t\t\tline-height: 1.35;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-help code {\n\t\t\t\t\t\tjustify-self: start;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-actions {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\tjustify-content: flex-end;\n\t\t\t\t\t\tmargin: 0;\n\t\t\t\t\t\tflex-shrink: 0;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-reset {\n\t\t\t\t\t\tborder: 1px solid #343841;\n\t\t\t\t\t\tborder-radius: 0.5rem;\n\t\t\t\t\t\tbackground: #24262d;\n\t\t\t\t\t\tcolor: #fff;\n\t\t\t\t\t\tpadding: 0.3rem 0.55rem;\n\t\t\t\t\t\tfont-size: 12px;\n\t\t\t\t\t\tcursor: pointer;\n\t\t\t\t\t}\n\t\t\t\t\thr {\n\t\t\t\t\t\tborder: 1px solid rgba(27, 30, 36, 1);\n\t\t\t\t\t\tmargin: 1em 0;\n\t\t\t\t\t}\n\t\t\t\t\t.setting-row {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\tjustify-content: space-between;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tgap: 12px;\n\t\t\t\t\t\tmargin: 0 0 8px;\n\t\t\t\t\t}\n\t\t\t\t\t.setting-row section { flex: 1; min-width: 0; max-width: 54%; }\n\t\t\t\t\th3.aff-row-title {\n\t\t\t\t\t\tfont-size: 12px;\n\t\t\t\t\t\tfont-weight: 600;\n\t\t\t\t\t\tcolor: #fff;\n\t\t\t\t\t\tletter-spacing: 0.05em;\n\t\t\t\t\t\ttext-transform: uppercase;\n\t\t\t\t\t\tmargin: 0;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-radios {\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\tgap: 8px;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tflex-shrink: 0;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-radios label {\n\t\t\t\t\t\tdisplay: inline-flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tgap: 4px;\n\t\t\t\t\t\tfont-size: 11px;\n\t\t\t\t\t\tcursor: pointer;\n\t\t\t\t\t\tcolor: var(--color-muted);\n\t\t\t\t\t\tletter-spacing: 0.04em;\n\t\t\t\t\t\ttext-transform: uppercase;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-radios input { accent-color: var(--color-purple); cursor: pointer; }\n\t\t\t\t\t.aff-flag {\n\t\t\t\t\t\tmargin: 0 0 12px;\n\t\t\t\t\t\tborder: 1px solid rgba(52, 56, 65, 1);\n\t\t\t\t\t\tborder-radius: 10px;\n\t\t\t\t\t\tpadding: 0 10px 10px;\n\t\t\t\t\t\tbackground: rgba(19, 21, 26, 0.55);\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag summary {\n\t\t\t\t\t\tlist-style: none;\n\t\t\t\t\t\tcursor: pointer;\n\t\t\t\t\t\tuser-select: none;\n\t\t\t\t\t\tdisplay: flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tgap: 8px;\n\t\t\t\t\t\tpadding: 10px 0;\n\t\t\t\t\t\tfont-weight: 600;\n\t\t\t\t\t\tfont-size: 11px;\n\t\t\t\t\t\tletter-spacing: 0.06em;\n\t\t\t\t\t\ttext-transform: uppercase;\n\t\t\t\t\t\tcolor: #fff;\n\t\t\t\t\t\tjustify-content: space-between;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag summary::-webkit-details-marker { display: none; }\n\t\t\t\t\t.aff-flag summary::after {\n\t\t\t\t\t\tcontent: '▸';\n\t\t\t\t\t\tdisplay: inline-flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tjustify-content: center;\n\t\t\t\t\t\tmargin-left: auto;\n\t\t\t\t\t\tcolor: var(--color-muted);\n\t\t\t\t\t\tfont-size: 12px;\n\t\t\t\t\t\ttransform: rotate(0deg);\n\t\t\t\t\t\ttransition: transform 0.12s ease;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag[open] summary::after {\n\t\t\t\t\t\ttransform: rotate(90deg);\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag-summary-left {\n\t\t\t\t\t\tdisplay: inline-flex;\n\t\t\t\t\t\talign-items: center;\n\t\t\t\t\t\tgap: 8px;\n\t\t\t\t\t}\n\t\t\t\t\t.aff-swatch {\n\t\t\t\t\t\twidth: 10px;\n\t\t\t\t\t\theight: 10px;\n\t\t\t\t\t\tborder-radius: 9999px;\n\t\t\t\t\t\tflex-shrink: 0;\n\t\t\t\t\t\tbox-shadow: inset 0 0 0 1px rgba(255,255,255,0.12);\n\t\t\t\t\t}\n\t\t\t\t\t.aff-flag-body { padding-top: 2px; }\n\t\t\t\t\t.aff-empty {\n\t\t\t\t\t\tmargin: 0;\n\t\t\t\t\t\tfont-size: 14px;\n\t\t\t\t\t\tline-height: 1.5rem;\n\t\t\t\t\t\tcolor: var(--color-muted);\n\t\t\t\t\t}\n\t\t\t\t\tcode {\n\t\t\t\t\t\tcolor: var(--color-purple);\n\t\t\t\t\t\tborder: 1px solid #343841;\n\t\t\t\t\t\tborder-radius: 0.35em;\n\t\t\t\t\t\tbackground-color: #24262d;\n\t\t\t\t\t\tpadding: 0.15em 0.35em;\n\t\t\t\t\t\tfont-size: 0.9em;\n\t\t\t\t\t}\n\t\t\t\t\tinput[type=\"color\"].aff-color {\n\t\t\t\t\t\twidth: 2.25rem;\n\t\t\t\t\t\theight: 1.75rem;\n\t\t\t\t\t\tpadding: 0;\n\t\t\t\t\t\tborder: 1px solid #343841;\n\t\t\t\t\t\tborder-radius: 6px;\n\t\t\t\t\t\tcursor: pointer;\n\t\t\t\t\t\tbackground: transparent;\n\t\t\t\t\t}\n\t\t\t\t</style>\n\t\t\t\t<header>\n\t\t\t\t\t<h1><span class=\"aff-flag-toolbar-icon\">${DEV_TOOLBAR_FLAG_ICON_SVG}</span> Feature flags</h1>\n\t\t\t\t\t<div class=\"aff-actions\"><button id=\"aff-reset\" class=\"aff-reset\" type=\"button\" title=\"Reset all flags to defaults\">Reset all</button></div>\n\t\t\t\t</header>\n\t\t\t\t<div class=\"aff-top\">\n\t\t\t\t\t<div class=\"aff-top-left\">\n\t\t\t\t\t\t<p class=\"aff-intro\">Per-flag preview for <code>data-${namespace}</code> regions.</p>\n\t\t\t\t<div class=\"aff-help\">\n\t\t\t\t\t<code>Enabled</code><span>Show/hide flagged regions in preview.</span>\n\t\t\t\t\t<code>Outline</code><span>Toggle flag outlines without changing layout.</span>\n\t\t\t\t\t<code>Badges</code><span>Toggle element and route labels.</span>\n\t\t\t\t\t<code>Colour</code><span>Set <code>--${namespace}-c-<token></code> on <code><html></code>.</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<hr />\n\t\t\t\t<div id=\"aff-body\"></div>\n\t\t\t`);\n\n const body = windowElement.querySelector(\"#aff-body\");\n const resetBtn = windowElement.querySelector(\n \"#aff-reset\",\n ) as HTMLButtonElement | null;\n\n if (body) {\n if (tokens.length === 0) {\n const p = document.createElement(\"p\");\n p.className = \"aff-empty\";\n p.textContent = \"No flags in ff.json.\";\n body.append(p);\n } else {\n for (const token of tokens) {\n const details = document.createElement(\"details\");\n details.className = \"aff-flag\";\n details.open = tokens.length <= 8;\n\n const summary = document.createElement(\"summary\");\n const summaryLeft = document.createElement(\"span\");\n summaryLeft.className = \"aff-flag-summary-left\";\n const swatch = document.createElement(\"span\");\n swatch.className = \"aff-swatch\";\n const name = document.createElement(\"span\");\n name.textContent = token;\n summaryLeft.append(swatch, name);\n summary.append(summaryLeft);\n\n const syncSwatch = () => {\n const c =\n state.colors[token] ?? defaultColors[token] ?? \"#888888\";\n swatch.style.background = c;\n };\n syncSwatch();\n\n const inner = document.createElement(\"div\");\n inner.className = \"aff-flag-body\";\n\n const row = (\n title: string,\n tooltip: string,\n key: keyof Pick<AffState, \"enabled\" | \"outline\" | \"badge\">,\n onLab: string,\n offLab: string,\n ) => {\n const label = document.createElement(\"label\");\n label.className = \"setting-row\";\n const section = document.createElement(\"section\");\n const h = document.createElement(\"h3\");\n h.className = \"aff-row-title\";\n h.textContent = title;\n section.append(h);\n const radios = document.createElement(\"div\");\n radios.className = \"aff-radios\";\n const mk = (on: boolean, lab: string) => {\n const wrap = document.createElement(\"label\");\n const inp = document.createElement(\"input\");\n inp.type = \"radio\";\n inp.name = `aff-${token}-${key}`;\n const cur = state[key][token] !== false;\n inp.checked = on ? cur : !cur;\n inp.addEventListener(\"change\", () => {\n if (!inp.checked) return;\n state[key][token] = on;\n applyDom(tokens, state, defaultColors, namespace);\n persist(state, namespace);\n });\n wrap.append(inp, document.createTextNode(lab));\n return wrap;\n };\n radios.append(mk(true, onLab), mk(false, offLab));\n label.append(section, radios);\n return label;\n };\n\n inner.append(\n row(\n \"Enabled\",\n \"When off, nodes with this flag token are hidden in preview.\",\n \"enabled\",\n \"On\",\n \"Off\",\n ),\n row(\n \"Outline\",\n \"Toggles dashed outline around flagged elements.\",\n \"outline\",\n \"On\",\n \"Off\",\n ),\n row(\n \"Badges\",\n \"Toggles element badges and top-right route pill.\",\n \"badge\",\n \"On\",\n \"Off\",\n ),\n );\n\n const colorRow = document.createElement(\"label\");\n colorRow.className = \"setting-row\";\n const csection = document.createElement(\"section\");\n const ch = document.createElement(\"h3\");\n ch.className = \"aff-row-title\";\n ch.textContent = \"Colour\";\n ch.title = `Maps to CSS --${namespace}-c-<token> on <html>.`;\n csection.append(ch);\n const cinp = document.createElement(\"input\");\n cinp.type = \"color\";\n cinp.className = \"aff-color\";\n cinp.title = `Set --${namespace}-c-${token}`;\n cinp.value = toHexColor(\n state.colors[token] ?? defaultColors[token],\n \"#888888\",\n );\n cinp.addEventListener(\"input\", () => {\n state.colors[token] = cinp.value;\n syncSwatch();\n applyDom(tokens, state, defaultColors, namespace);\n persist(state, namespace);\n });\n colorRow.append(csection, cinp);\n inner.append(colorRow);\n\n details.append(summary, inner);\n body.append(details);\n }\n }\n }\n\n if (resetBtn) {\n resetBtn.addEventListener(\"click\", () => {\n try {\n localStorage.removeItem(storageKey(namespace));\n localStorage.removeItem(\"aff.dev.v1\");\n } catch {\n // ignore\n }\n state = loadState(tokens, namespace);\n applyDom(tokens, state, defaultColors, namespace);\n mount();\n });\n }\n\n canvas.append(windowElement);\n }\n\n mount();\n document.addEventListener(\"astro:after-swap\", mount);\n closeOnOutsideClick(eventTarget);\n synchronizePlacementOnUpdate(eventTarget, canvas);\n },\n});\n\nexport default affDevToolbarApp;\n"],"mappings":"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"}
|
package/dist/{dev-toolbar-flag-icon-BHCQJ53N.mjs.map → dev-toolbar-flag-icon-MQsIFekv.mjs.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-toolbar-flag-icon-
|
|
1
|
+
{"version":3,"file":"dev-toolbar-flag-icon-MQsIFekv.mjs","names":[],"sources":["../src/dev-toolbar-flag-icon.ts"],"sourcesContent":["/**\n * Inline SVG for the dev toolbar app button and panel header (Heroicons-style flag, 20×20 in a 22×22 box).\n * `currentColor` matches built-in Astro toolbar icons.\n */\nexport const DEV_TOOLBAR_FLAG_ICON_SVG =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 22 22\" fill=\"currentColor\" aria-hidden=\"true\">' +\n '<path d=\"M4.25 3.25v15.5a.75.75 0 1 1-1.5 0V3.25a.75.75 0 0 1 1.5 0Z\"/>' +\n '<path d=\"M6.5 4.75v9.2a1 1 0 0 0 1.5.87l7.5-4.6a1 1 0 0 0 0-1.74l-7.5-4.6a1 1 0 0 0-1.5.87Z\"/>' +\n \"</svg>\";\n"],"mappings":";;;;;AAIA,MAAa,4BACX"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { FeatureFlagMap, ResolveFeatureRuntimeOptions, ResolvedFeatureRuntime, longestMatchingRoutePrefix, mergeFlagsWithProcessEnvOverrides, resolveFeatureFlagsByEnvironment, routePatternToPrefix } from "./runtime.mjs";
|
|
2
|
-
|
|
3
2
|
//#region src/badge-layout.d.ts
|
|
4
3
|
type ElementBadgeVerticalAnchor = "top" | "bottom";
|
|
5
4
|
/** Horizontal placement of the element pill: `end` = top-right (LTR), `start` = top-left, `center` = centred. */
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/badge-layout.ts","../src/dev-outline-css.ts","../src/production-html-cull.ts","../src/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/badge-layout.ts","../src/dev-outline-css.ts","../src/production-html-cull.ts","../src/index.ts"],"mappings":";;KAAY;;KAGA;;UAGK;;;;;EAKf,8BAA8B;;;;;EAK9B;;;;;EAKA;;EAEA,6BAA6B;;KAGnB;EAEN;EACA,iBAAiB;EACjB;EACA,gBAAgB;;EAGhB;EACA;EACA;EACA,gBAAgB;;iBAQN,4BACd,OAAO,wCACN;;;;iBA+Ba,0BACd,QAAQ;;;KCrEE;UAEK,6BAA6B;EAC5C;;EAEA;;EAEA,sBAAsB;EACtB;EACA;;EAGA;;EAEA;EACA,oBAAoB;EAEpB,iBAAiB;;;;EAKjB;;;;;;;iBAsEc,wBACd,SAAS,wBACT,MAAM;;;;;iBAyTQ,2BACd,SAAS;;;;;;;;iBC9UK,mBACd,cACA,SAAS;;;;iBAqCK,8BACd,gBACA,SAAS;;;UCtEM,iCAAiC;EAChD,MAAM;;EAEN;;;iBAIc,4BACd,oBAAoB,eAAe;iBAoCrB,0BACd,SAAS,wBACT,MAAM,sBACN,qBAAoB,eAAe,iBACnC;iBA8Kc,oBACd,UAAS,+BACR;iBAIa,qBACd,kBACA,SAAS;iBAkBa,kBACtB,UAAS"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as DEV_TOOLBAR_FLAG_ICON_SVG } from "./dev-toolbar-flag-icon-
|
|
1
|
+
import { t as DEV_TOOLBAR_FLAG_ICON_SVG } from "./dev-toolbar-flag-icon-MQsIFekv.mjs";
|
|
2
2
|
import { longestMatchingRoutePrefix, mergeFlagsWithProcessEnvOverrides, resolveFeatureFlagsByEnvironment, resolveFeatureRuntime, routePathsToPrune, routePatternToPrefix, shouldIncludeRoute, toEnumKey, toToken } from "./runtime.mjs";
|
|
3
3
|
import { readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -102,10 +102,15 @@ function affHeadInlineRuntime(payload) {
|
|
|
102
102
|
};
|
|
103
103
|
try {
|
|
104
104
|
const { featureFlagStyles, routeFlags: RF, flagNameToToken: M } = payload;
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
const ensureFeatureFlagStyles = () => {
|
|
106
|
+
if (document.querySelector("style[data-astro-feature-flags]")) return;
|
|
107
|
+
const s = document.createElement("style");
|
|
108
|
+
s.setAttribute("data-astro-feature-flags", "");
|
|
109
|
+
s.setAttribute("data-astro-transition-persist", "astro-feature-flags");
|
|
110
|
+
s.textContent = featureFlagStyles;
|
|
111
|
+
(document.head || document.documentElement).appendChild(s);
|
|
112
|
+
};
|
|
113
|
+
ensureFeatureFlagStyles();
|
|
109
114
|
const affPath = () => {
|
|
110
115
|
let p = typeof location !== "undefined" && location.pathname ? location.pathname : "/";
|
|
111
116
|
if (!p.endsWith("/")) p += "/";
|
|
@@ -163,6 +168,7 @@ function affHeadInlineRuntime(payload) {
|
|
|
163
168
|
pEl.textContent = `${disabled.length === 1 ? `Page disabled: ${flagsText} flag is disabled.` : `Page disabled: ${flagsText} flags are disabled.`}\nIn production builds, pages with disabled flags like this will not be emitted`;
|
|
164
169
|
};
|
|
165
170
|
const affApply = () => {
|
|
171
|
+
ensureFeatureFlagStyles();
|
|
166
172
|
document.documentElement.setAttribute("data-ff-route", affTokens(affPath()).join(" "));
|
|
167
173
|
affSyncDisabledOverlay();
|
|
168
174
|
};
|
|
@@ -1068,11 +1074,14 @@ function astroFeatureFlags(options = {}) {
|
|
|
1068
1074
|
icon: DEV_TOOLBAR_FLAG_ICON_SVG,
|
|
1069
1075
|
entrypoint: fileURLToPath(new URL("./dev-toolbar-app.mjs", import.meta.url))
|
|
1070
1076
|
});
|
|
1071
|
-
if (command === "dev" && runtime.isDev && typeof injectScript === "function")
|
|
1072
|
-
runtime,
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1077
|
+
if (command === "dev" && runtime.isDev && typeof injectScript === "function") {
|
|
1078
|
+
const styles = createFeatureFlagStyles(runtime, css);
|
|
1079
|
+
injectScript("head-inline", buildAffDevHeadInline({
|
|
1080
|
+
runtime,
|
|
1081
|
+
featureFlagStyles: styles,
|
|
1082
|
+
affDevBootstrap: bootstrap
|
|
1083
|
+
}));
|
|
1084
|
+
}
|
|
1076
1085
|
updateConfig({ vite: { plugins: [{
|
|
1077
1086
|
name: "astro-feature-flags:virtual-module",
|
|
1078
1087
|
resolveId(id) {
|