@humanforest/slidev-theme 0.1.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 (124) hide show
  1. package/LICENSE +67 -0
  2. package/README.md +577 -0
  3. package/assetUrl.js +38 -0
  4. package/components/Alert.vue +209 -0
  5. package/components/AreaBox.vue +152 -0
  6. package/components/AreaChart.vue +145 -0
  7. package/components/Avatar.vue +267 -0
  8. package/components/AvatarGroup.vue +94 -0
  9. package/components/BadgeStrip.vue +203 -0
  10. package/components/Bars.vue +207 -0
  11. package/components/BoroughShape.vue +127 -0
  12. package/components/BrowserFrame.vue +484 -0
  13. package/components/CalendarGrid.vue +480 -0
  14. package/components/Card.vue +70 -0
  15. package/components/Carousel.vue +266 -0
  16. package/components/ChartFrame.vue +426 -0
  17. package/components/ChordChart.vue +264 -0
  18. package/components/ComposedChart.vue +187 -0
  19. package/components/Contents.vue +86 -0
  20. package/components/DataTable.vue +244 -0
  21. package/components/DeckMap.vue +409 -0
  22. package/components/DeviceFrame.vue +331 -0
  23. package/components/DonutChart.vue +103 -0
  24. package/components/DottedMap.vue +126 -0
  25. package/components/Endorsement.vue +76 -0
  26. package/components/Grid.vue +169 -0
  27. package/components/GroupedBarChart.vue +141 -0
  28. package/components/IconTile.vue +116 -0
  29. package/components/Kpi.vue +188 -0
  30. package/components/LineChart.vue +133 -0
  31. package/components/Logo.vue +203 -0
  32. package/components/LondonMap.vue +348 -0
  33. package/components/MarkPair.vue +109 -0
  34. package/components/Marquee.vue +263 -0
  35. package/components/NestedDonutChart.vue +295 -0
  36. package/components/Placeholder.vue +88 -0
  37. package/components/SankeyChart.vue +223 -0
  38. package/components/ScatterChart.vue +142 -0
  39. package/components/StackedBarChart.vue +143 -0
  40. package/components/StatCard.vue +134 -0
  41. package/components/StatusTrack.vue +334 -0
  42. package/components/Timeline.vue +249 -0
  43. package/components/TimelineChart.vue +329 -0
  44. package/components/TreemapChart.vue +267 -0
  45. package/components/backgrounds.js +135 -0
  46. package/components/boroughGeometry.ts +59 -0
  47. package/components/chartData.ts +277 -0
  48. package/components/chartTip.ts +201 -0
  49. package/components/codeTheme.ts +239 -0
  50. package/components/deckPalette.ts +157 -0
  51. package/components/dottedMapGeometry.js +60 -0
  52. package/components/iconSlugs.js +55 -0
  53. package/components/iconUrl.js +51 -0
  54. package/components/mermaidTheme.ts +972 -0
  55. package/components/motionDuration.ts +41 -0
  56. package/components/tableRules.ts +257 -0
  57. package/confidential-mark.vue +151 -0
  58. package/custom-nav-controls.vue +79 -0
  59. package/endorsements/b-corp-black.svg +30 -0
  60. package/endorsements/b-corp-white.svg +30 -0
  61. package/global-top.vue +1662 -0
  62. package/icons/forest/bike-asterisk.svg +21 -0
  63. package/icons/forest/bike-down.svg +19 -0
  64. package/icons/forest/bike-off.svg +20 -0
  65. package/icons/forest/bike-up.svg +19 -0
  66. package/icons/forest/bike-x.svg +19 -0
  67. package/icons/forest/bike.svg +18 -0
  68. package/icons/forest/mark-fill.svg +6 -0
  69. package/icons/forest/mark.svg +6 -0
  70. package/icons/forest/parking.svg +3 -0
  71. package/icons/forest/star-fill.svg +4 -0
  72. package/icons/forest/star.svg +4 -0
  73. package/icons/forest/traffic-light-caution.svg +8 -0
  74. package/icons/forest/traffic-light-go.svg +8 -0
  75. package/icons/forest/traffic-light-lit.svg +8 -0
  76. package/icons/forest/traffic-light-stop.svg +8 -0
  77. package/icons/forest/traffic-light.svg +8 -0
  78. package/icons/lucide/battery.svg +1 -0
  79. package/icons/lucide/bike.svg +1 -0
  80. package/icons/lucide/chart-line.svg +1 -0
  81. package/icons/lucide/check.svg +1 -0
  82. package/icons/lucide/circle-check.svg +1 -0
  83. package/icons/lucide/clock.svg +1 -0
  84. package/icons/lucide/code.svg +1 -0
  85. package/icons/lucide/component.svg +1 -0
  86. package/icons/lucide/frame.svg +1 -0
  87. package/icons/lucide/layout-grid.svg +1 -0
  88. package/icons/lucide/map-pin.svg +1 -0
  89. package/icons/lucide/map.svg +1 -0
  90. package/icons/lucide/palette.svg +1 -0
  91. package/icons/lucide/table.svg +1 -0
  92. package/icons/lucide/triangle-alert.svg +1 -0
  93. package/icons/lucide/type.svg +1 -0
  94. package/icons/lucide/wrench.svg +1 -0
  95. package/layouts/bleed.vue +317 -0
  96. package/layouts/cover.vue +1514 -0
  97. package/layouts/default.vue +187 -0
  98. package/layouts/divider.vue +286 -0
  99. package/layouts/end.vue +384 -0
  100. package/layouts/quote.vue +218 -0
  101. package/layouts/split.vue +1875 -0
  102. package/layouts/stack.vue +944 -0
  103. package/layouts/statement.vue +67 -0
  104. package/manifest/chrome.ts +36 -0
  105. package/manifest/components.ts +49 -0
  106. package/manifest/index.ts +57 -0
  107. package/manifest/layouts.ts +37 -0
  108. package/manifest/manifest.json +6514 -0
  109. package/manifest/presets.ts +635 -0
  110. package/notch.js +458 -0
  111. package/notchPath.js +188 -0
  112. package/package.json +77 -0
  113. package/section.js +110 -0
  114. package/setup/mermaid-renderer.ts +2120 -0
  115. package/setup/mermaid.ts +30 -0
  116. package/setup/shiki.ts +44 -0
  117. package/setup/shortcuts.ts +28 -0
  118. package/slide-bottom.vue +305 -0
  119. package/slide-top.vue +268 -0
  120. package/styles/base.css +2611 -0
  121. package/styles/index.ts +71 -0
  122. package/styles/tokens.css +144 -0
  123. package/uno.config.ts +231 -0
  124. package/useNotchCuts.js +200 -0
@@ -0,0 +1,55 @@
1
+ // Every icon slug `<IconTile icon="…">` will accept, derived from the generated collections
2
+ // rather than restated — the same shape backgrounds.js already fixes for background names (see that
3
+ // file's own doc comment for the defect this pattern exists to prevent).
4
+ //
5
+ // task-7-fix-1.md CRITICAL 1: `IconTile.icon` shipped `type: String, required: true` with no
6
+ // validator at all, so nothing — not the manifest, not a gate, not this package's own vitest
7
+ // suite — could tell a real icon slug apart from an invented one. A preset's `fill` prose (Task 7)
8
+ // named "a check icon"; `packages/ui/icons/forest/` has no tick, only bike variants, mark,
9
+ // mark-fill, parking, star, star-fill and traffic-light variants. Every consumer of `<IconTile>`
10
+ // falls back to the Forest mark on a miss (IconTile.vue's own `FALLBACK_ICON`), silently — the
11
+ // slug was never checked against anything real.
12
+ //
13
+ // task-8b (this file): the deck was Forest-only, but Jose's own direction is "icons should come
14
+ // from lucide or from our own icon library" — the design system HAS a tick, in Lucide, the
15
+ // `checklist` preset's own regression just never reached for it. `ICON_SLUGS` now spans BOTH
16
+ // sets, each entry carrying its own namespace prefix (`forest:bike`, `lucide:check`) — a bare,
17
+ // unprefixed name is never valid. That's not pedantry: both sets carry a `bike`, a `star` and a
18
+ // `parking` of their own, so a flat merged namespace would be a real collision the moment both
19
+ // are in play, not a hypothetical one. `FOREST_SLUGS` and `LUCIDE_SLUGS` are exported
20
+ // individually too — `FOREST_SLUGS` is what scripts/deckShowcase.ts's own exhaustive coverage
21
+ // check should track against (every FOREST icon appearing somewhere in the showcase is a
22
+ // meaningful, small, achievable guarantee; the same demand across all ~1,774 Lucide names would
23
+ // not be — nobody is meant to showcase the whole Lucide set, only draw from it).
24
+ //
25
+ // `scripts/icons.ts` already reads `packages/ui/icons/forest/*.svg` with `readdirSync()` and the
26
+ // installed `@iconify-json/lucide/icons.json`'s own key list, writing both into
27
+ // `packages/ui/src/icons.ts`'s `FOREST_ICON_NAMES`/`LUCIDE_ICON_NAMES` exports — re-deriving
28
+ // either list a second time here (a second `readdirSync`, a second `icons.json` read) would be
29
+ // exactly the anti-pattern backgrounds.js itself was written to close: two independent places
30
+ // deriving what should be one list, free to disagree the moment either one changes.
31
+ //
32
+ // Named re-exports, not a default import of the whole module: `forestIcons`' own SVG path data
33
+ // lives in the same source file but is never referenced past this line, so a real bundler's
34
+ // dead-code elimination drops it from anything that imports only these names —
35
+ // packages/slidev-theme/test/manifest.static.test.ts checks the resolution chain; IconTile.vue's
36
+ // own `import.meta.env.DEV` guard on its validator is what actually keeps the ~1,790-name array
37
+ // itself out of a deck's PRODUCTION bundle (see that file's doc comment for why a name array, cheap
38
+ // as it is next to Lucide's 543 KB of path data, still isn't worth paying for in every deck build
39
+ // just to back a check Vue never runs outside dev).
40
+ //
41
+ // Reached by relative path across the package boundary, not a `@humanforest/ui` package
42
+ // specifier — the same trick Kpi.vue already uses for kpiDelta.ts/kpiFormat.ts, and for the same
43
+ // reason: `@humanforest/ui`'s own entry point drags in Nuxt UI, reka-ui and mapbox-gl, none of
44
+ // which a slide needs. `packages/ui/src/icons.ts` has zero imports of its own — a dependency-free
45
+ // leaf, the same standard those two files are held to.
46
+ import { FOREST_ICON_NAMES, LUCIDE_ICON_NAMES } from '@humanforest/ui/icons';
47
+
48
+ /** Every Forest icon, namespaced — `bike-off` → `forest:bike-off`. */
49
+ export const FOREST_SLUGS = FOREST_ICON_NAMES.map((name) => `forest:${name}`);
50
+
51
+ /** Every Lucide icon, namespaced — `check` → `lucide:check`. */
52
+ export const LUCIDE_SLUGS = LUCIDE_ICON_NAMES.map((name) => `lucide:${name}`);
53
+
54
+ /** Every slug `<IconTile icon="…">` resolves — both sets, namespace preserved, never merged flat. */
55
+ export const ICON_SLUGS = [...FOREST_SLUGS, ...LUCIDE_SLUGS];
@@ -0,0 +1,51 @@
1
+ /*
2
+ Resolving a namespaced icon slug to a URL a CSS mask can draw. Extracted from IconTile.vue when
3
+ Marquee needed the same thing — a second copy would have re-derived the scanner trap below by
4
+ hand, and that trap is invisible when you get it wrong.
5
+
6
+ ★ THE ICON IS DRAWN AS A CSS MASK, NOT THROUGH UnoCSS'S `i-forest-*` UTILITY. That utility only
7
+ exists once UnoCSS's static scanner sees the literal class string in source — and an `icon` prop
8
+ means the class would have to be assembled at runtime (`i-forest-${icon}`), a string the scanner
9
+ never sees, so the rule for it is silently never generated. Masking the SVG straight from the
10
+ shared icon source sidesteps the scanner entirely.
11
+
12
+ ★ THE GLOB PATHS ARE RELATIVE TO THIS DIRECTORY. This file has to stay in components/ beside its
13
+ callers: `import.meta.glob` is resolved against the importing MODULE's own path at build time, so
14
+ moving it one directory up silently resolves nothing and every icon falls back.
15
+ */
16
+
17
+ // Eager + `?url`: this is sixteen-odd URL strings, not the SVG bodies, so resolving the whole set
18
+ // up front costs nothing and keeps the lookup below synchronous.
19
+ const FOREST_ICONS = import.meta.glob('../icons/forest/*.svg', { eager: true, query: '?url', import: 'default' });
20
+ const forestIconPath = (name) => `../icons/forest/${name}.svg`;
21
+
22
+ // The Lucide half of the SAME technique, but sourced differently: there is no per-icon file to
23
+ // glob — @iconify-json/lucide ships one 543 KB icons.json for its whole ~1,774-icon set.
24
+ // scripts/deckIcons.ts pre-extracts ONLY the Lucide names this repo's decks actually reference into
25
+ // packages/slidev-theme/icons/lucide/*.svg, so this glob only ever picks up icons in real use.
26
+ const LUCIDE_ICONS = import.meta.glob('../icons/lucide/*.svg', { eager: true, query: '?url', import: 'default' });
27
+ const lucideIconPath = (name) => `../icons/lucide/${name}.svg`;
28
+
29
+ /* A slug with no matching file masks the glyph out entirely — an invisible shape, no console error,
30
+ and deckAudit measures geometry only, so it passes. Falling back to a real, always-present icon
31
+ turns that into "visibly the wrong icon" instead of "gone". */
32
+ export const FALLBACK_ICON = 'mark-fill';
33
+
34
+ /**
35
+ * `icon` is always "<namespace>:<name>". The namespace is never optional: Forest's own set and
36
+ * Lucide's each have a `bike`, a `star` and a `parking`, so a bare name is a real collision.
37
+ * Anything unrecognised returns undefined and the caller applies FALLBACK_ICON.
38
+ */
39
+ export const resolveIconUrl = (icon) => {
40
+ if (typeof icon !== 'string') return undefined;
41
+ const i = icon.indexOf(':');
42
+ if (i < 0) return undefined;
43
+ const namespace = icon.slice(0, i);
44
+ const name = icon.slice(i + 1);
45
+ if (namespace === 'forest') return FOREST_ICONS[forestIconPath(name)];
46
+ if (namespace === 'lucide') return LUCIDE_ICONS[lucideIconPath(name)];
47
+ return undefined;
48
+ };
49
+
50
+ /** The same resolution with the fallback already applied — what a caller drawing a mask wants. */
51
+ export const iconUrlOrFallback = (icon) => resolveIconUrl(icon) ?? FOREST_ICONS[forestIconPath(FALLBACK_ICON)];