@poveste/app 0.19.0 → 0.20.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 (39) hide show
  1. package/dist/bundled/app.css +174 -1
  2. package/dist/bundled/components/HomeView.vue_vue_type_script_setup_true_lang.js +3 -3
  3. package/dist/bundled/components/app/AppLogo.vue_vue_type_script_setup_true_lang.js +4 -4
  4. package/dist/bundled/components/app/TopBarChipItem.js +10 -6
  5. package/dist/bundled/components/layout/LayoutItem.js +1 -0
  6. package/dist/bundled/components/layout/LayoutItem.vue_vue_type_script_setup_true_lang.js +20 -23
  7. package/dist/bundled/components/panel/ComponentDocs.js +7 -0
  8. package/dist/bundled/components/panel/ComponentDocs.vue_vue_type_script_setup_true_lang.js +132 -0
  9. package/dist/bundled/components/panel/StoryDocs.vue_vue_type_script_setup_true_lang.js +32 -21
  10. package/dist/bundled/components/panel/StorySourceCode.js +1 -1
  11. package/dist/bundled/components/panel/StorySourceCode.vue_vue_type_script_setup_true_lang.js +20 -4
  12. package/dist/bundled/components/story/GenericMountStory.vue_vue_type_script_setup_true_lang.js +3 -7
  13. package/dist/bundled/components/story/GenericRenderStory.vue_vue_type_script_setup_true_lang.js +3 -10
  14. package/dist/bundled/components/toolbar/DevOnlyToolbarOpenInEditor.vue_vue_type_script_setup_true_lang.js +0 -1
  15. package/dist/bundled/router.js +15 -12
  16. package/dist/bundled/util/client-plugin.js +22 -0
  17. package/dist/bundled/util/component-docs-data.js +1 -0
  18. package/dist/bundled/util/component-docs.js +57 -0
  19. package/dist/bundled/util/docs.js +1 -1
  20. package/dist/bundled/util/icons.generated.js +2 -2
  21. package/dist/bundled/util/mapping.js +1 -5
  22. package/dist/style.css +5 -46
  23. package/package.json +15 -15
  24. package/src/app/components/HomeView.vue +2 -2
  25. package/src/app/components/app/AppLogo.vue +4 -6
  26. package/src/app/components/app/TopBarChipItem.vue +55 -6
  27. package/src/app/components/layout/LayoutItem.vue +56 -6
  28. package/src/app/components/panel/ComponentDocs.vue +257 -0
  29. package/src/app/components/panel/StoryDocs.vue +11 -2
  30. package/src/app/components/panel/StorySourceCode.vue +27 -3
  31. package/src/app/components/story/GenericMountStory.vue +3 -5
  32. package/src/app/components/story/GenericRenderStory.vue +4 -12
  33. package/src/app/components/toolbar/DevOnlyToolbarOpenInEditor.vue +0 -1
  34. package/src/app/router.ts +26 -15
  35. package/src/app/util/client-plugin.ts +33 -0
  36. package/src/app/util/component-docs-data.ts +3 -0
  37. package/src/app/util/component-docs.ts +78 -0
  38. package/src/app/util/icons.generated.ts +2 -2
  39. package/src/app/util/mapping.ts +1 -5
@@ -1,5 +1,5 @@
1
+ import { loadClientPlugin } from "../../util/client-plugin.js";
1
2
  import { createBlock, createCommentVNode, defineComponent, markRaw, mergeProps, openBlock, ref, resolveDynamicComponent, watchEffect } from "@poveste/vendors/vue";
2
- import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
3
3
  var GenericMountStory_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
4
4
  inheritAttrs: false,
5
5
  __name: "GenericMountStory",
@@ -8,12 +8,8 @@ var GenericMountStory_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
8
8
  const props = __props;
9
9
  const mountComponent = ref(null);
10
10
  watchEffect(async () => {
11
- const supportPluginId = props.story.file?.supportPluginId;
12
- const clientPlugin = supportPluginId ? clientSupportPlugins[supportPluginId] : void 0;
13
- if (clientPlugin) {
14
- const pluginModule = await clientPlugin();
15
- mountComponent.value = markRaw(pluginModule.MountStory);
16
- }
11
+ const pluginModule = await loadClientPlugin(props.story.file?.supportPluginId);
12
+ if (pluginModule) mountComponent.value = markRaw(pluginModule.MountStory);
17
13
  });
18
14
  return (_ctx, _cache) => {
19
15
  return mountComponent.value ? (openBlock(), createBlock(resolveDynamicComponent(mountComponent.value), mergeProps({
@@ -1,5 +1,5 @@
1
+ import { loadClientPlugin } from "../../util/client-plugin.js";
1
2
  import { createBlock, createCommentVNode, defineComponent, markRaw, mergeProps, openBlock, ref, resolveDynamicComponent, watchEffect } from "@poveste/vendors/vue";
2
- import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
3
3
  var GenericRenderStory_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
4
4
  inheritAttrs: false,
5
5
  __name: "GenericRenderStory",
@@ -8,15 +8,8 @@ var GenericRenderStory_vue_vue_type_script_setup_true_lang_default = /*@__PURE__
8
8
  const props = __props;
9
9
  const mountComponent = ref(null);
10
10
  watchEffect(async () => {
11
- const supportPluginId = props.story.file?.supportPluginId;
12
- const clientPlugin = supportPluginId ? clientSupportPlugins[supportPluginId] : void 0;
13
- if (clientPlugin) try {
14
- const pluginModule = await clientPlugin();
15
- mountComponent.value = markRaw(pluginModule.RenderStory);
16
- } catch (e) {
17
- console.error(e);
18
- throw e;
19
- }
11
+ const pluginModule = await loadClientPlugin(props.story.file?.supportPluginId);
12
+ if (pluginModule) mountComponent.value = markRaw(pluginModule.RenderStory);
20
13
  });
21
14
  return (_ctx, _cache) => {
22
15
  return mountComponent.value ? (openBlock(), createBlock(resolveDynamicComponent(mountComponent.value), mergeProps({
@@ -15,7 +15,6 @@ var DevOnlyToolbarOpenInEditor_vue_vue_type_script_setup_true_lang_default = /*@
15
15
  return openBlock(), createBlock(unref(HstTooltip), { content: __props.tooltip }, {
16
16
  default: withCtx(() => [createVNode(TopBarChipItem_default, {
17
17
  "aria-label": "Open story in editor",
18
- target: "_blank",
19
18
  class: "poveste-toolbar-open-in-editor",
20
19
  onClick: _cache[0] || (_cache[0] = ($event) => unref(openInEditor)(__props.file))
21
20
  }, {
@@ -8,17 +8,20 @@ function createRouterHistory() {
8
8
  default: return createWebHistory(base);
9
9
  }
10
10
  }
11
- var router = createRouter({
12
- history: createRouterHistory(),
13
- routes: [{
14
- path: "/",
15
- name: "home",
16
- component: () => import("./components/HomeView.js")
17
- }, {
18
- path: "/story/:storyId",
19
- name: "story",
20
- component: () => import("./components/story/StoryView.js")
21
- }]
22
- });
11
+ function newRouter() {
12
+ return createRouter({
13
+ history: createRouterHistory(),
14
+ routes: [{
15
+ path: "/",
16
+ name: "home",
17
+ component: () => import("./components/HomeView.js")
18
+ }, {
19
+ path: "/story/:storyId",
20
+ name: "story",
21
+ component: () => import("./components/story/StoryView.js")
22
+ }]
23
+ });
24
+ }
25
+ var router = import.meta.hot ? import.meta.hot.data.router ??= newRouter() : newRouter();
23
26
  //#endregion
24
27
  export { base, router };
@@ -0,0 +1,22 @@
1
+ import { occupant } from "./occupant.js";
2
+ import { reportStoryError, toStoryError } from "@poveste/shared";
3
+ import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
4
+ //#region src/app/util/client-plugin.ts
5
+ async function loadClientPlugin(supportPluginId) {
6
+ const load = supportPluginId ? clientSupportPlugins[supportPluginId] : void 0;
7
+ if (!load) return;
8
+ try {
9
+ return await load();
10
+ } catch (error) {
11
+ const { message, stack } = toStoryError(error);
12
+ const reported = Object.assign(/* @__PURE__ */ new Error(`The story renderer failed to load, and it imports the setup file: ${message}`), { stack });
13
+ reportStoryError(reported, {
14
+ storyId: occupant.storyId ?? void 0,
15
+ variantId: occupant.variantId ?? void 0
16
+ });
17
+ console.error(error);
18
+ return;
19
+ }
20
+ }
21
+ //#endregion
22
+ export { loadClientPlugin };
@@ -0,0 +1 @@
1
+ export { componentDocs } from "virtual:$poveste-component-docs";
@@ -0,0 +1,57 @@
1
+ import { onBeforeUnmount, ref, watch } from "@poveste/vendors/vue";
2
+ //#region src/app/util/component-docs.ts
3
+ function toEntries(result) {
4
+ return Object.entries(result.components).map(([file, { doc, error }]) => ({
5
+ file,
6
+ name: file.split("/").pop().replace(/\.[^.]+$/, ""),
7
+ ...doc ? { doc } : {},
8
+ ...error ? { error } : {}
9
+ }));
10
+ }
11
+ function tagText(tags, name) {
12
+ const tag = tags.find((tag) => tag.name === name);
13
+ return tag ? tag.text ?? "" : void 0;
14
+ }
15
+ /** A `@see` or `@link` points somewhere only when it carries a URL. */
16
+ function tagHref(text) {
17
+ return /https?:\/\/\S+/.exec(text)?.[0];
18
+ }
19
+ /**
20
+ * The components a story imports, documented. In dev they are asked of the server
21
+ * when this is first used, which is what starts extraction at all (#1159); in a
22
+ * built book they come from what `poveste build` extracted.
23
+ */
24
+ function useComponentDocs(storyId) {
25
+ const components = ref();
26
+ const hot = import.meta.hot;
27
+ if (!hot) {
28
+ watch(storyId, async (id) => {
29
+ const { componentDocs } = await import("./component-docs-data.js");
30
+ const docs = id ? componentDocs[id] : void 0;
31
+ components.value = id && docs ? toEntries({
32
+ storyId: id,
33
+ components: docs
34
+ }) : void 0;
35
+ }, { immediate: true });
36
+ return { components };
37
+ }
38
+ function ask() {
39
+ if (storyId.value) hot.send("poveste:docgen-request", { storyId: storyId.value });
40
+ }
41
+ function onResult(result) {
42
+ if (result.storyId === storyId.value) components.value = toEntries(result);
43
+ }
44
+ hot.on("poveste:docgen-result", onResult);
45
+ hot.on("poveste:docgen-stale", ask);
46
+ onBeforeUnmount(() => {
47
+ hot.off("poveste:docgen-result", onResult);
48
+ hot.off("poveste:docgen-stale", ask);
49
+ });
50
+ watch(storyId, () => {
51
+ components.value = void 0;
52
+ ask();
53
+ }, { immediate: true });
54
+ return { components };
55
+ }
56
+ //#endregion
57
+ export { tagHref, tagText, toEntries, useComponentDocs };
@@ -1,5 +1,5 @@
1
- import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
2
1
  import { unindent } from "@poveste/shared";
2
+ import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
3
3
  //#region src/app/util/docs.ts
4
4
  /** What the variant declares, or what its framework generates from it; `undefined` when neither has anything. */
5
5
  async function getDynamicSourceCode(variant, generate) {
@@ -56,7 +56,7 @@ var iconCollections = [
56
56
  "view-off": { "body": "<path fill=\"currentColor\" d=\"m5.24 22.51l1.43-1.42A14.06 14.06 0 0 1 3.07 16C5.1 10.93 10.7 7 16 7a12.4 12.4 0 0 1 4 .72l1.55-1.56A14.7 14.7 0 0 0 16 5A16.69 16.69 0 0 0 1.06 15.66a1 1 0 0 0 0 .68a16 16 0 0 0 4.18 6.17\"/><path fill=\"currentColor\" d=\"M12 15.73a4 4 0 0 1 3.7-3.7l1.81-1.82a6 6 0 0 0-7.33 7.33Zm18.94-.07a16.4 16.4 0 0 0-5.74-7.44L30 3.41L28.59 2L2 28.59L3.41 30l5.1-5.1A15.3 15.3 0 0 0 16 27a16.69 16.69 0 0 0 14.94-10.66a1 1 0 0 0 0-.68M20 16a4 4 0 0 1-6 3.44L19.44 14a4 4 0 0 1 .56 2m-4 9a13.05 13.05 0 0 1-6-1.58l2.54-2.54a6 6 0 0 0 8.35-8.35l2.87-2.87A14.54 14.54 0 0 1 28.93 16C26.9 21.07 21.3 25 16 25\"/>" },
57
57
  "warning-alt": { "body": "<path fill=\"currentColor\" d=\"M16 23a1.5 1.5 0 1 0 1.5 1.5A1.5 1.5 0 0 0 16 23m-1-11h2v9h-2z\"/><path fill=\"currentColor\" d=\"M29 30H3a1 1 0 0 1-.887-1.461l13-25a1 1 0 0 1 1.774 0l13 25A1 1 0 0 1 29 30M4.65 28h22.7l.001-.003L16.002 6.17h-.004L4.648 27.997Z\"/>" }
58
58
  },
59
- "lastModified": 1789034045,
59
+ "lastModified": 1790421921,
60
60
  "aliases": { "software-resource-resource": { "parent": "software-resource-reference" } },
61
61
  "width": 32,
62
62
  "height": 32
@@ -75,7 +75,7 @@ var iconCollections = [
75
75
  "height": 16
76
76
  }
77
77
  },
78
- "lastModified": 1789279072,
78
+ "lastModified": 1791785206,
79
79
  "width": 20,
80
80
  "height": 20
81
81
  },
@@ -46,11 +46,7 @@ function mapVariant(variant, existingVariant) {
46
46
  _hPropDefs: {}
47
47
  }),
48
48
  setupApp: void 0,
49
- slots: () => ({
50
- default: void 0,
51
- controls: void 0,
52
- source: void 0
53
- }),
49
+ slots: () => ({}),
54
50
  previewReady: false
55
51
  };
56
52
  return result;
package/dist/style.css CHANGED
@@ -759,6 +759,8 @@
759
759
  --color-red-600: oklch(57.7% 0.245 27.325);
760
760
  --color-red-700: oklch(50.5% 0.213 27.518);
761
761
  --color-orange-500: oklch(70.5% 0.213 47.604);
762
+ --color-amber-400: oklch(82.8% 0.189 84.429);
763
+ --color-amber-600: oklch(66.6% 0.179 58.318);
762
764
  --color-gray-50: var(--_poveste-color-gray-50, #fafafa);
763
765
  --color-gray-100: var(--_poveste-color-gray-100, #f4f4f5);
764
766
  --color-gray-200: var(--_poveste-color-gray-200, #e4e4e7);
@@ -780,8 +782,6 @@
780
782
  --text-lg--line-height: calc(1.75 / 1.125);
781
783
  --text-2xl: 1.5rem;
782
784
  --text-2xl--line-height: calc(2 / 1.5);
783
- --text-5xl: 3rem;
784
- --text-5xl--line-height: 1;
785
785
  --font-weight-medium: 500;
786
786
  --font-weight-bold: 700;
787
787
  --tracking-wide: 0.025em;
@@ -1437,6 +1437,9 @@
1437
1437
  .inline-flex {
1438
1438
  display: inline-flex;
1439
1439
  }
1440
+ .table {
1441
+ display: table;
1442
+ }
1440
1443
  .h-2 {
1441
1444
  height: calc(var(--spacing) * 2);
1442
1445
  }
@@ -1467,12 +1470,6 @@
1467
1470
  .h-16 {
1468
1471
  height: calc(var(--spacing) * 16);
1469
1472
  }
1470
- .h-20 {
1471
- height: calc(var(--spacing) * 20);
1472
- }
1473
- .h-32 {
1474
- height: calc(var(--spacing) * 32);
1475
- }
1476
1473
  .h-48 {
1477
1474
  height: calc(var(--spacing) * 48);
1478
1475
  }
@@ -1497,9 +1494,6 @@
1497
1494
  .h-\[51px\] {
1498
1495
  height: 51px;
1499
1496
  }
1500
- .h-\[100px\] {
1501
- height: 100px;
1502
- }
1503
1497
  .h-fit {
1504
1498
  height: fit-content;
1505
1499
  }
@@ -1560,9 +1554,6 @@
1560
1554
  .w-28 {
1561
1555
  width: calc(var(--spacing) * 28);
1562
1556
  }
1563
- .w-32 {
1564
- width: calc(var(--spacing) * 32);
1565
- }
1566
1557
  .w-64 {
1567
1558
  width: calc(var(--spacing) * 64);
1568
1559
  }
@@ -1841,10 +1832,6 @@
1841
1832
  border-style: var(--tw-border-style);
1842
1833
  border-width: 0px;
1843
1834
  }
1844
- .border-2 {
1845
- border-style: var(--tw-border-style);
1846
- border-width: 2px;
1847
- }
1848
1835
  .border-8 {
1849
1836
  border-style: var(--tw-border-style);
1850
1837
  border-width: 8px;
@@ -1971,12 +1958,6 @@
1971
1958
  background-color: color-mix(in oklab, var(--color-gray-500) 20%, transparent);
1972
1959
  }
1973
1960
  }
1974
- .bg-gray-500\/50 {
1975
- background-color: var(--color-gray-500);
1976
- @supports (color: color-mix(in lab, red, red)) {
1977
- background-color: color-mix(in oklab, var(--color-gray-500) 50%, transparent);
1978
- }
1979
- }
1980
1961
  .bg-primary-50 {
1981
1962
  background-color: var(--color-primary-50);
1982
1963
  }
@@ -2149,10 +2130,6 @@
2149
2130
  font-size: var(--text-2xl);
2150
2131
  line-height: var(--tw-leading, var(--text-2xl--line-height));
2151
2132
  }
2152
- .text-5xl {
2153
- font-size: var(--text-5xl);
2154
- line-height: var(--tw-leading, var(--text-5xl--line-height));
2155
- }
2156
2133
  .text-lg {
2157
2134
  font-size: var(--text-lg);
2158
2135
  line-height: var(--tw-leading, var(--text-lg--line-height));
@@ -2558,12 +2535,6 @@
2558
2535
  background-color: color-mix(in oklab, var(--color-gray-600) 50%, transparent);
2559
2536
  }
2560
2537
  }
2561
- .active\:bg-white\/70:active {
2562
- background-color: color-mix(in srgb, #fff 70%, transparent);
2563
- @supports (color: color-mix(in lab, red, red)) {
2564
- background-color: color-mix(in oklab, var(--color-white) 70%, transparent);
2565
- }
2566
- }
2567
2538
  @media (width >= 40rem) {
2568
2539
  .sm\:h-4 {
2569
2540
  height: calc(var(--spacing) * 4);
@@ -2656,12 +2627,6 @@
2656
2627
  border-color: color-mix(in oklab, var(--color-white) 25%, transparent);
2657
2628
  }
2658
2629
  }
2659
- .dark\:bg-black:where(.ptw-dark, .ptw-dark *) {
2660
- background-color: var(--color-black);
2661
- }
2662
- .dark\:bg-gray-600:where(.ptw-dark, .ptw-dark *) {
2663
- background-color: var(--color-gray-600);
2664
- }
2665
2630
  .dark\:bg-gray-700:where(.ptw-dark, .ptw-dark *) {
2666
2631
  background-color: var(--color-gray-700);
2667
2632
  }
@@ -2804,12 +2769,6 @@
2804
2769
  .dark\:focus\:border-primary-500:where(.ptw-dark, .ptw-dark *):focus {
2805
2770
  border-color: var(--color-primary-500);
2806
2771
  }
2807
- .dark\:active\:bg-white\/15:where(.ptw-dark, .ptw-dark *):active {
2808
- background-color: color-mix(in srgb, #fff 15%, transparent);
2809
- @supports (color: color-mix(in lab, red, red)) {
2810
- background-color: color-mix(in oklab, var(--color-white) 15%, transparent);
2811
- }
2812
- }
2813
2772
  .poveste-story-list-folder-button:hover .\[\.poveste-story-list-folder-button\:hover_\&\]\:opacity-100 {
2814
2773
  opacity: 100%;
2815
2774
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@poveste/app",
3
3
  "type": "module",
4
- "version": "0.19.0",
4
+ "version": "0.20.0",
5
5
  "description": "Pre-bundled UI for Poveste",
6
6
  "author": {
7
7
  "name": "Sorin Gitlan",
@@ -36,16 +36,16 @@
36
36
  "node": ">=22.22.2"
37
37
  },
38
38
  "dependencies": {
39
- "@poveste/controls": "^0.19.0",
40
- "@poveste/shared": "^0.19.0",
41
- "@poveste/vendors": "^0.19.0",
39
+ "@poveste/controls": "^0.20.0",
40
+ "@poveste/shared": "^0.20.0",
41
+ "@poveste/vendors": "^0.20.0",
42
42
  "fuse.js": "^7.0.0",
43
- "shiki": "^4.4.3"
43
+ "shiki": "^4.5.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@fontsource/noto-sans-display": "^5.3.0",
47
- "@iconify-json/carbon": "^1.2.27",
48
- "@iconify-json/fluent": "1.2.58",
47
+ "@iconify-json/carbon": "^1.2.28",
48
+ "@iconify-json/fluent": "1.2.60",
49
49
  "@iconify-json/mdi": "^1.2.3",
50
50
  "@iconify-json/ri": "^1.2.10",
51
51
  "@iconify/utils": "^3.1.7",
@@ -53,11 +53,11 @@
53
53
  "@tailwindcss/postcss": "^4.3.3",
54
54
  "@tailwindcss/typography": "^0.5.20",
55
55
  "@types/fs-extra": "^11.0.4",
56
- "@types/node": "^26.6.3",
57
- "@vitejs/plugin-vue": "^6.0.9",
56
+ "@types/node": "^26.6.5",
57
+ "@vitejs/plugin-vue": "^6.0.10",
58
58
  "@vueuse/core": "^15.0.0",
59
59
  "chokidar": "^5.0.0",
60
- "concurrently": "^10.0.5",
60
+ "concurrently": "^10.0.6",
61
61
  "fs-extra": "^11.4.1",
62
62
  "globby": "^16.2.4",
63
63
  "pathe": "^2.0.3",
@@ -66,11 +66,11 @@
66
66
  "postcss-cli": "^12.0.0",
67
67
  "tailwindcss": "^4.3.3",
68
68
  "typescript": "6.0.3",
69
- "vite": "^8.3.1",
70
- "vitest": "^5.0.2",
71
- "vue": "^3.5.43",
72
- "vue-router": "^5.3.1",
73
- "vue-tsc": "^3.3.11"
69
+ "vite": "^8.3.4",
70
+ "vitest": "^5.0.4",
71
+ "vue": "^3.5.44",
72
+ "vue-router": "^5.4.0",
73
+ "vue-tsc": "^3.3.13"
74
74
  },
75
75
  "scripts": {
76
76
  "build": "pnpm run icons && rimraf dist && vite build && pnpm run build:css && node ./scripts/copy.mjs",
@@ -2,10 +2,10 @@
2
2
  import { computed } from 'vue'
3
3
  import PovesteLogo from '../assets/poveste.svg'
4
4
  import { useStoryStore } from '../stores/story'
5
- import { customLogos, povesteConfig } from '../util/config'
5
+ import { customLogos } from '../util/config'
6
6
  import HomeCounter from './app/HomeCounter.vue'
7
7
 
8
- const logoUrl = computed(() => povesteConfig.theme?.logo?.square ? customLogos?.square ?? PovesteLogo : PovesteLogo)
8
+ const logoUrl = computed(() => customLogos?.square ?? PovesteLogo)
9
9
  const storyStore = useStoryStore()
10
10
 
11
11
  const stats = computed(() => {
@@ -6,15 +6,13 @@ import PovesteLogoLight from '../../assets/poveste-text.svg'
6
6
  import { customLogos, povesteConfig } from '../../util/config'
7
7
  import { isDark } from '../../util/dark'
8
8
 
9
- // `theme.logo` is what the config asked for; `customLogos` is the resolved URL
10
- // map from the virtual module. Two objects, so a check on one narrows nothing
11
- // about the other — and falling back to the bundled logo beats rendering an
12
- // `<img>` with no `src` if they ever disagree.
9
+ // `customLogos` holds a served URL for each logo the config names. The config's
10
+ // own entries are paths on the machine that built the book, and are not sent (#1383).
13
11
  const logoUrl = computed(() => {
14
12
  if (isDark.value) {
15
- return povesteConfig.theme.logo?.dark ? customLogos?.dark ?? PovesteLogoDark : PovesteLogoDark
13
+ return customLogos?.dark ?? PovesteLogoDark
16
14
  }
17
- return povesteConfig.theme.logo?.light ? customLogos?.light ?? PovesteLogoLight : PovesteLogoLight
15
+ return customLogos?.light ?? PovesteLogoLight
18
16
  })
19
17
 
20
18
  const altText = computed(() => `${povesteConfig.theme.title} logo`)
@@ -1,10 +1,59 @@
1
1
  <template>
2
- <!-- Without an href this is not a link, so `aria-label` on it is prohibited and
3
- it has no accessible role. Chip items are used both ways (#310). -->
4
- <a
5
- :role="$attrs['href'] ? undefined : 'button'"
6
- class="poveste-top-bar-chip-item flex items-center gap-1 px-2.5 py-1.5 hover:bg-white/50 active:bg-white/70 dark:hover:bg-white/10 dark:active:bg-white/15 hover:text-primary-500 dark:hover:text-primary-400 cursor-pointer text-gray-900 dark:text-gray-100 transition-colors"
2
+ <!-- A link where it navigates, a button everywhere else. An `<a>` without an
3
+ href is not focusable, so a keyboard could not reach the chip (#1351). -->
4
+ <component
5
+ :is="$attrs['href'] ? 'a' : 'button'"
6
+ :type="$attrs['href'] ? undefined : 'button'"
7
+ class="poveste-top-bar-chip-item"
8
+ data-slot="top-bar-chip-item"
7
9
  >
8
10
  <slot />
9
- </a>
11
+ </component>
10
12
  </template>
13
+
14
+ <style lang="postcss">
15
+ .poveste-top-bar-chip-item {
16
+ display: flex;
17
+ align-items: center;
18
+ gap: .25rem;
19
+ padding: .375rem .625rem;
20
+ border: 0;
21
+ font: inherit;
22
+ color: var(--color-gray-900);
23
+ cursor: pointer;
24
+
25
+ @media (prefers-reduced-motion: no-preference) {
26
+ transition: color .15s ease-out, background-color .15s ease-out;
27
+ }
28
+
29
+ &:hover {
30
+ background-color: rgb(255 255 255 / .5);
31
+ color: var(--color-primary-500);
32
+ }
33
+
34
+ &:active {
35
+ background-color: rgb(255 255 255 / .7);
36
+ }
37
+
38
+ /* Inset: the chip clips its items to its rounded border. */
39
+ &:focus-visible {
40
+ outline: 2px solid var(--color-primary-500);
41
+ outline-offset: -2px;
42
+ }
43
+
44
+ /* Spelled out on the subject: `.ptw-dark` sits above the `@scope` root, so a
45
+ descendant rule keyed on it never matches from in here (#101). */
46
+ &:where(.ptw-dark, .ptw-dark *) {
47
+ color: var(--color-gray-100);
48
+
49
+ &:hover {
50
+ background-color: rgb(255 255 255 / .1);
51
+ color: var(--color-primary-400);
52
+ }
53
+
54
+ &:active {
55
+ background-color: rgb(255 255 255 / .15);
56
+ }
57
+ }
58
+ }
59
+ </style>
@@ -1,6 +1,5 @@
1
1
  <script setup lang="ts">
2
2
  import { Icon } from '@iconify/vue'
3
- import BaseListItem from '../base/BaseListItem.vue'
4
3
 
5
4
  defineProps<{
6
5
  title: string
@@ -15,10 +14,14 @@ defineEmits<{
15
14
  </script>
16
15
 
17
16
  <template>
18
- <BaseListItem
19
- :is-active="isActive"
20
- class="px-6 py-4 gap-4"
21
- @navigate="$emit('click')"
17
+ <!-- A button: `BaseListItem` is an `<a>` with no href, which a keyboard cannot
18
+ reach (#1351). -->
19
+ <button
20
+ type="button"
21
+ class="poveste-layout-item"
22
+ :class="{ active: isActive }"
23
+ data-slot="layout-item"
24
+ @click="$emit('click')"
22
25
  >
23
26
  <Icon
24
27
  class="w-4 h-4 flex-none"
@@ -32,5 +35,52 @@ defineEmits<{
32
35
  :icon="stateIcon"
33
36
  aria-hidden="true"
34
37
  />
35
- </BaseListItem>
38
+ </button>
36
39
  </template>
40
+
41
+ <style lang="postcss">
42
+ .poveste-layout-item {
43
+ display: flex;
44
+ align-items: center;
45
+ gap: 1rem;
46
+ width: 100%;
47
+ padding: 1rem 1.5rem;
48
+ border: 0;
49
+ font: inherit;
50
+ text-align: start;
51
+ color: var(--color-gray-900);
52
+ cursor: pointer;
53
+
54
+ &:hover {
55
+ background-color: var(--color-primary-100);
56
+ }
57
+
58
+ &:focus-visible {
59
+ outline: 2px solid var(--color-primary-500);
60
+ outline-offset: -2px;
61
+ }
62
+
63
+ &.active {
64
+ background-color: var(--color-primary-500);
65
+ color: var(--color-white);
66
+
67
+ &:hover {
68
+ background-color: var(--color-primary-600);
69
+ }
70
+ }
71
+
72
+ /* Spelled out on the subject: `.ptw-dark` sits above the `@scope` root, so a
73
+ descendant rule keyed on it never matches from in here (#101). */
74
+ &:where(.ptw-dark, .ptw-dark *) {
75
+ color: var(--color-gray-100);
76
+
77
+ &:hover {
78
+ background-color: var(--color-primary-900);
79
+ }
80
+
81
+ &.active {
82
+ color: var(--color-black);
83
+ }
84
+ }
85
+ }
86
+ </style>