@leavepulse/ui 0.17.2 → 0.18.1
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/dist/chunks/{LpAddressInput-ChT1JQg0.js → LpAddressInput-Dfyn88Dd.js} +1 -1
- package/dist/chunks/{LpAppShell-C6Mj82LS.js → LpAppShell-CiHAD6PN.js} +2 -2
- package/dist/chunks/{LpConfirmDialog-3_Qu4hnA.js → LpConfirmDialog-BxBU4Pj9.js} +1 -1
- package/dist/chunks/{LpDrawer-Fxk7ViQ-.js → LpDrawer-DaCsNuW3.js} +1 -1
- package/dist/chunks/{LpFileTree-CXg3KDth.js → LpFileTree-DXb3yKzH.js} +1 -1
- package/dist/chunks/{LpLogViewer-D7DNEYaG.js → LpLogViewer-tmKPNTuU.js} +1 -1
- package/dist/chunks/{LpModal-J-KRPO7F.js → LpModal-CYKAaSHO.js} +1 -1
- package/dist/chunks/{LpNotificationBell-D8sdQLgu.js → LpNotificationBell-DHze8wYN.js} +1 -1
- package/dist/chunks/{LpScrollArea-CKhOx0_l.js → LpScrollArea-DQ0Yudfu.js} +2 -2
- package/dist/chunks/{LpSidebar-Bk7SrINq.js → LpSidebar-BBG9NhAn.js} +2 -2
- package/dist/chunks/{LpSidebarNav-Cpd-yHXb.js → LpSidebarNav-DSDa5mAY.js} +1 -1
- package/dist/chunks/{LpTable-X3ieZmbr.js → LpTable-DqZ-L4Au.js} +1 -1
- package/dist/chunks/{LpThemeSwitcher-DC6QygnU.js → LpThemeSwitcher-Ct-lnXMa.js} +16 -2
- package/dist/components/LpAddressInput.vue.js +1 -1
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.js +1 -1
- package/dist/components/LpConfirmDialog.vue.js +1 -1
- package/dist/components/LpDrawer.vue.js +1 -1
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpLogViewer.vue.js +1 -1
- package/dist/components/LpModal.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpScrollArea.vue.js +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpTable.vue.js +1 -1
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +17 -15
- package/dist/theme/useTheme.d.ts +10 -0
- package/package.json +1 -1
- package/src/components/LpScrollArea.vue +8 -2
- package/src/index.ts +2 -0
- package/src/nuxt.ts +33 -7
- package/src/runtime/theme.plugin.ts +62 -0
- package/src/theme/useTheme.ts +41 -0
|
@@ -6,7 +6,7 @@ import { _ as _sfc_main$3 } from "./LpButton-5VXXCjwF.js";
|
|
|
6
6
|
import { _ as _sfc_main$1 } from "./LpFormField-Bn-ZwC6z.js";
|
|
7
7
|
import { _ as _sfc_main$4 } from "./LpIcon-CCnX5_2j.js";
|
|
8
8
|
import { _ as _sfc_main$5 } from "./LpInput-BauZRyzm.js";
|
|
9
|
-
import { _ as _sfc_main$7 } from "./LpModal-
|
|
9
|
+
import { _ as _sfc_main$7 } from "./LpModal-CYKAaSHO.js";
|
|
10
10
|
import { _ as _sfc_main$6 } from "./LpSelect-D5mU4cZO.js";
|
|
11
11
|
const _hoisted_1 = { class: "flex flex-col gap-3" };
|
|
12
12
|
const _hoisted_2 = { class: "flex items-stretch gap-2" };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { defineComponent, computed, watch, openBlock, createElementBlock, createVNode, createSlots, withCtx, renderSlot, normalizeProps, guardReactiveProps, createElementVNode, normalizeClass, toDisplayString, createCommentVNode, createBlock } from "vue";
|
|
2
2
|
import { _ as _sfc_main$2 } from "./LpButton-5VXXCjwF.js";
|
|
3
3
|
import { _ as _sfc_main$3 } from "./LpIcon-CCnX5_2j.js";
|
|
4
|
-
import { _ as _sfc_main$4 } from "./LpScrollArea-
|
|
5
|
-
import { _ as _sfc_main$1 } from "./LpSidebar-
|
|
4
|
+
import { _ as _sfc_main$4 } from "./LpScrollArea-DQ0Yudfu.js";
|
|
5
|
+
import { _ as _sfc_main$1 } from "./LpSidebar-BBG9NhAn.js";
|
|
6
6
|
const _hoisted_1 = { class: "flex h-dvh overflow-hidden bg-surface text-ink" };
|
|
7
7
|
const _hoisted_2 = { class: "flex min-w-0 flex-1 flex-col" };
|
|
8
8
|
const _hoisted_3 = { class: "flex h-16 shrink-0 items-center gap-3 border-b border-line bg-surface px-4 md:px-6" };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineComponent, openBlock, createBlock, withCtx, renderSlot, createVNode, createTextVNode, toDisplayString } from "vue";
|
|
2
2
|
import { _ as _sfc_main$2 } from "./LpButton-5VXXCjwF.js";
|
|
3
|
-
import { _ as _sfc_main$1 } from "./LpModal-
|
|
3
|
+
import { _ as _sfc_main$1 } from "./LpModal-CYKAaSHO.js";
|
|
4
4
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
5
5
|
__name: "LpConfirmDialog",
|
|
6
6
|
props: {
|
|
@@ -3,7 +3,7 @@ import { usePointerSwipe } from "@vueuse/core";
|
|
|
3
3
|
import { DrawerRoot, DrawerPortal, DrawerOverlay, DrawerContent, DrawerHandle, DrawerTitle, DrawerDescription, DrawerClose } from "vaul-vue";
|
|
4
4
|
import { CLOSE_ICON } from "../components/dropdown.js";
|
|
5
5
|
import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
|
|
6
|
-
import { _ as _sfc_main$2 } from "./LpScrollArea-
|
|
6
|
+
import { _ as _sfc_main$2 } from "./LpScrollArea-DQ0Yudfu.js";
|
|
7
7
|
const _hoisted_1 = { class: "text-base font-semibold text-ink" };
|
|
8
8
|
const _hoisted_2 = { class: "flex flex-col gap-1" };
|
|
9
9
|
const _hoisted_3 = ["data-vaul-no-drag"];
|
|
@@ -2,7 +2,7 @@ import { defineComponent, ref, watch, computed, openBlock, createElementBlock, F
|
|
|
2
2
|
import { formatSize, sortNodes, computeStats, subtreeIds, ancestorIds } from "../components/fileTree.js";
|
|
3
3
|
import { _ as _sfc_main$1 } from "./LpEmptyState-CrfyRJUG.js";
|
|
4
4
|
import { _ as _sfc_main$3 } from "./LpFileTreeNode-DFg4PhOK.js";
|
|
5
|
-
import { _ as _sfc_main$2 } from "./LpScrollArea-
|
|
5
|
+
import { _ as _sfc_main$2 } from "./LpScrollArea-DQ0Yudfu.js";
|
|
6
6
|
const _hoisted_1 = {
|
|
7
7
|
key: 0,
|
|
8
8
|
class: "flex h-full w-full min-w-0 flex-col gap-1 overflow-hidden"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineComponent, computed, ref, watch, nextTick, onMounted, onBeforeUnmount, openBlock, createElementBlock, createVNode, normalizeStyle, withCtx, createElementVNode, toDisplayString, createCommentVNode, Fragment, createBlock, resolveDynamicComponent, TransitionGroup, mergeProps, renderList, normalizeClass, createTextVNode, Transition } from "vue";
|
|
2
2
|
import { _ as _sfc_main$3 } from "./LpContextMenu-D0mzXqA7.js";
|
|
3
3
|
import { _ as _sfc_main$2 } from "./LpIcon-CCnX5_2j.js";
|
|
4
|
-
import { _ as _sfc_main$1 } from "./LpScrollArea-
|
|
4
|
+
import { _ as _sfc_main$1 } from "./LpScrollArea-DQ0Yudfu.js";
|
|
5
5
|
const _hoisted_1 = { class: "relative overflow-hidden rounded-card border border-line bg-surface font-mono text-xs leading-relaxed" };
|
|
6
6
|
const _hoisted_2 = {
|
|
7
7
|
key: 0,
|
|
@@ -2,7 +2,7 @@ import { defineComponent, computed, useSlots, openBlock, createBlock, unref, wit
|
|
|
2
2
|
import { DialogRoot, DialogPortal, DialogOverlay, DialogContent, DialogTitle, DialogDescription, DialogClose } from "reka-ui";
|
|
3
3
|
import { CLOSE_ICON } from "../components/dropdown.js";
|
|
4
4
|
import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
|
|
5
|
-
import { _ as _sfc_main$2 } from "./LpScrollArea-
|
|
5
|
+
import { _ as _sfc_main$2 } from "./LpScrollArea-DQ0Yudfu.js";
|
|
6
6
|
const _hoisted_1 = { class: "fixed inset-0 z-(--z-modal) flex items-center justify-center pointer-events-none" };
|
|
7
7
|
const _hoisted_2 = {
|
|
8
8
|
key: 0,
|
|
@@ -5,7 +5,7 @@ import { _ as _sfc_main$4 } from "./LpContextMenu-D0mzXqA7.js";
|
|
|
5
5
|
import { _ as _sfc_main$2 } from "./LpEmptyState-CrfyRJUG.js";
|
|
6
6
|
import { _ as _sfc_main$5 } from "./LpIcon-CCnX5_2j.js";
|
|
7
7
|
import { _ as _sfc_main$1 } from "./LpPopover-8268UmlC.js";
|
|
8
|
-
import { _ as _sfc_main$3 } from "./LpScrollArea-
|
|
8
|
+
import { _ as _sfc_main$3 } from "./LpScrollArea-DQ0Yudfu.js";
|
|
9
9
|
const _hoisted_1 = { class: "flex items-center justify-between gap-2 px-3 py-2.5" };
|
|
10
10
|
const _hoisted_2 = { class: "text-sm font-semibold" };
|
|
11
11
|
const _hoisted_3 = {
|
|
@@ -30,7 +30,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
30
30
|
style: normalizeStyle(__props.barInsetTop ? { marginTop: __props.barInsetTop } : void 0)
|
|
31
31
|
}, {
|
|
32
32
|
default: withCtx(() => [
|
|
33
|
-
createVNode(unref(ScrollAreaThumb), { class: "w-1 rounded-l-pill bg-brand/40 transition-[width,background-color] duration-[var(--duration-fast)] group-hover:w-1.5 group-hover:bg-brand" })
|
|
33
|
+
createVNode(unref(ScrollAreaThumb), { class: "min-w-1 rounded-l-pill bg-brand/40 transition-[min-width,background-color] duration-[var(--duration-fast)] group-hover:min-w-1.5 group-hover:bg-brand" })
|
|
34
34
|
]),
|
|
35
35
|
_: 1
|
|
36
36
|
}, 8, ["style"]),
|
|
@@ -39,7 +39,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
39
39
|
class: normalizeClass(["group flex h-3.5 flex-col touch-none select-none justify-end px-px pb-px pt-2.5", barFade])
|
|
40
40
|
}, {
|
|
41
41
|
default: withCtx(() => [
|
|
42
|
-
createVNode(unref(ScrollAreaThumb), { class: "h-1 rounded-t-pill bg-brand/40 transition-[height,background-color] duration-[var(--duration-fast)] group-hover:h-1.5 group-hover:bg-brand" })
|
|
42
|
+
createVNode(unref(ScrollAreaThumb), { class: "min-h-1 rounded-t-pill bg-brand/40 transition-[min-height,background-color] duration-[var(--duration-fast)] group-hover:min-h-1.5 group-hover:bg-brand" })
|
|
43
43
|
]),
|
|
44
44
|
_: 1
|
|
45
45
|
}),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineComponent, computed, useId, openBlock, createElementBlock, Fragment, createElementVNode, mergeProps, normalizeClass, renderSlot, createCommentVNode, createVNode, createSlots, withCtx, normalizeProps, guardReactiveProps, createBlock } from "vue";
|
|
2
|
-
import { _ as _sfc_main$2 } from "./LpDrawer-
|
|
3
|
-
import { _ as _sfc_main$1 } from "./LpSidebarNav-
|
|
2
|
+
import { _ as _sfc_main$2 } from "./LpDrawer-DaCsNuW3.js";
|
|
3
|
+
import { _ as _sfc_main$1 } from "./LpSidebarNav-DSDa5mAY.js";
|
|
4
4
|
const _hoisted_1 = {
|
|
5
5
|
key: 1,
|
|
6
6
|
class: "mt-2 flex shrink-0 flex-col gap-2"
|
|
@@ -4,7 +4,7 @@ import { usePillTransition } from "../composables/usePillTransition.js";
|
|
|
4
4
|
import { _ as _sfc_main$4 } from "./LpBadge-CXzBPnwO.js";
|
|
5
5
|
import { _ as _sfc_main$2 } from "./LpContextMenu-D0mzXqA7.js";
|
|
6
6
|
import { _ as _sfc_main$3 } from "./LpIcon-CCnX5_2j.js";
|
|
7
|
-
import { _ as _sfc_main$1 } from "./LpScrollArea-
|
|
7
|
+
import { _ as _sfc_main$1 } from "./LpScrollArea-DQ0Yudfu.js";
|
|
8
8
|
const _hoisted_1 = {
|
|
9
9
|
key: 0,
|
|
10
10
|
class: "flex min-h-0 flex-1 flex-col gap-4"
|
|
@@ -2,7 +2,7 @@ import { defineComponent, computed, ref, watch, onBeforeUnmount, openBlock, crea
|
|
|
2
2
|
import { _ as _sfc_main$2 } from "./LpCheckbox-BO0zuuPh.js";
|
|
3
3
|
import { _ as _sfc_main$4 } from "./LpContextMenu-D0mzXqA7.js";
|
|
4
4
|
import { _ as _sfc_main$3 } from "./LpIcon-CCnX5_2j.js";
|
|
5
|
-
import { _ as _sfc_main$1 } from "./LpScrollArea-
|
|
5
|
+
import { _ as _sfc_main$1 } from "./LpScrollArea-DQ0Yudfu.js";
|
|
6
6
|
const _hoisted_1 = { class: "w-full border-collapse text-sm" };
|
|
7
7
|
const _hoisted_2 = { class: "border-b border-line bg-surface-soft" };
|
|
8
8
|
const _hoisted_3 = {
|
|
@@ -429,6 +429,18 @@ function cacheTheme(theme) {
|
|
|
429
429
|
localStorage.setItem(CACHE_KEY, serializeTheme(theme));
|
|
430
430
|
} catch {
|
|
431
431
|
}
|
|
432
|
+
writeThemeCookie(theme.name);
|
|
433
|
+
}
|
|
434
|
+
const THEME_COOKIE = "lp-theme";
|
|
435
|
+
const COOKIE_MAX_AGE = 60 * 60 * 24 * 365;
|
|
436
|
+
function writeThemeCookie(name) {
|
|
437
|
+
if (typeof document === "undefined") return;
|
|
438
|
+
document.cookie = `${THEME_COOKIE}=${encodeURIComponent(name)}; path=/; max-age=${COOKIE_MAX_AGE}; samesite=lax`;
|
|
439
|
+
}
|
|
440
|
+
function themeFromCookie(cookieValue, themes) {
|
|
441
|
+
if (!cookieValue) return null;
|
|
442
|
+
const name = decodeURIComponent(cookieValue);
|
|
443
|
+
return themes.find((theme) => theme.name === name) ?? null;
|
|
432
444
|
}
|
|
433
445
|
function useTheme() {
|
|
434
446
|
hydrateOnce();
|
|
@@ -588,6 +600,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
588
600
|
});
|
|
589
601
|
export {
|
|
590
602
|
DEFAULT_SURFACE as D,
|
|
603
|
+
THEME_COOKIE as T,
|
|
591
604
|
_sfc_main as _,
|
|
592
605
|
parseTheme as a,
|
|
593
606
|
amber as b,
|
|
@@ -597,13 +610,14 @@ export {
|
|
|
597
610
|
dark as f,
|
|
598
611
|
light as g,
|
|
599
612
|
lime as h,
|
|
600
|
-
|
|
613
|
+
themeToCssRule as i,
|
|
614
|
+
themeToCssVars as j,
|
|
601
615
|
leavepulse as l,
|
|
602
616
|
nord as n,
|
|
603
617
|
presets as p,
|
|
604
618
|
rose as r,
|
|
605
619
|
serializeTheme as s,
|
|
606
|
-
|
|
620
|
+
themeFromCookie as t,
|
|
607
621
|
useTheme as u,
|
|
608
622
|
violet as v
|
|
609
623
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineComponent, ref, computed, watch, nextTick, onMounted, onBeforeUnmount, openBlock, createBlock, unref, withCtx, createVNode, withModifiers, createTextVNode, createElementVNode, withDirectives, withKeys, vModelText, createElementBlock, toDisplayString, createCommentVNode, Fragment, renderList, normalizeClass } from "vue";
|
|
2
2
|
import { DialogRoot, DialogPortal, DialogOverlay, DialogContent, DialogTitle, DialogDescription } from "reka-ui";
|
|
3
3
|
import { _ as _sfc_main$1 } from "../chunks/LpIcon-CCnX5_2j.js";
|
|
4
|
-
import { _ as _sfc_main$2 } from "../chunks/LpScrollArea-
|
|
4
|
+
import { _ as _sfc_main$2 } from "../chunks/LpScrollArea-DQ0Yudfu.js";
|
|
5
5
|
import '../assets/LpCommandPalette-D315B47-.css';const _hoisted_1 = { class: "flex shrink-0 items-center gap-2.5 border-b border-line px-4" };
|
|
6
6
|
const _hoisted_2 = ["placeholder", "onKeydown"];
|
|
7
7
|
const _hoisted_3 = {
|
package/dist/index.d.ts
CHANGED
|
@@ -96,7 +96,7 @@ export { blockTitle, defineBlocks } from './layout/registry';
|
|
|
96
96
|
export type { BlockDef, BlockRegistry } from './layout/registry';
|
|
97
97
|
export { useLayout } from './layout/useLayout';
|
|
98
98
|
export type { UseLayout, UseLayoutOptions } from './layout/useLayout';
|
|
99
|
-
export { applyTheme, applyThemeWithTransition, bootstrapTheme, parseTheme, serializeTheme, themeToCssRule, themeToCssVars, useTheme, } from './theme/useTheme';
|
|
99
|
+
export { applyTheme, applyThemeWithTransition, bootstrapTheme, parseTheme, serializeTheme, THEME_COOKIE, themeFromCookie, themeToCssRule, themeToCssVars, useTheme, } from './theme/useTheme';
|
|
100
100
|
export type { RevealOrigin } from './theme/useTheme';
|
|
101
101
|
export { DEFAULT_SURFACE } from './theme/tokens';
|
|
102
102
|
export { defineTheme } from './theme/define';
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { _ } from "./chunks/LayoutCanvas-Dd20boUG.js";
|
|
2
|
-
import { _ as _2 } from "./chunks/LpAddressInput-
|
|
2
|
+
import { _ as _2 } from "./chunks/LpAddressInput-Dfyn88Dd.js";
|
|
3
3
|
import { _ as _3 } from "./chunks/LpMapPicker-DFKrd1Ne.js";
|
|
4
4
|
import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
|
|
5
5
|
import { _ as _4 } from "./chunks/LpAlert-BAYHDSS1.js";
|
|
6
|
-
import { _ as _5 } from "./chunks/LpAppShell-
|
|
6
|
+
import { _ as _5 } from "./chunks/LpAppShell-CiHAD6PN.js";
|
|
7
7
|
import { _ as _6 } from "./chunks/LpAutocomplete-DIgXmtCA.js";
|
|
8
8
|
import { _ as _7 } from "./chunks/LpAvatar-B1Ez0ZAx.js";
|
|
9
9
|
import { _ as _8 } from "./chunks/LpBadge-CXzBPnwO.js";
|
|
@@ -14,15 +14,15 @@ import { _ as _12 } from "./chunks/LpCard-BmrTvWOe.js";
|
|
|
14
14
|
import { _ as _13 } from "./chunks/LpCheckbox-BO0zuuPh.js";
|
|
15
15
|
import { _ as _14 } from "./chunks/LpCodeBlock-CSiOSPs8.js";
|
|
16
16
|
import { default as default2 } from "./components/LpCommandPalette.vue.js";
|
|
17
|
-
import { _ as _15 } from "./chunks/LpConfirmDialog-
|
|
17
|
+
import { _ as _15 } from "./chunks/LpConfirmDialog-BxBU4Pj9.js";
|
|
18
18
|
import { _ as _16 } from "./chunks/LpContextMenu-D0mzXqA7.js";
|
|
19
19
|
import { _ as _17 } from "./chunks/LpDatePicker-dY2q4dr4.js";
|
|
20
20
|
import { _ as _18 } from "./chunks/LpDisclosure-DP6yfgfM.js";
|
|
21
21
|
import { _ as _19 } from "./chunks/LpDivider-CUX46KR0.js";
|
|
22
|
-
import { _ as _20 } from "./chunks/LpDrawer-
|
|
22
|
+
import { _ as _20 } from "./chunks/LpDrawer-DaCsNuW3.js";
|
|
23
23
|
import { _ as _21 } from "./chunks/LpDropdownMenu-DJpoqRCb.js";
|
|
24
24
|
import { _ as _22 } from "./chunks/LpEmptyState-CrfyRJUG.js";
|
|
25
|
-
import { _ as _23 } from "./chunks/LpFileTree-
|
|
25
|
+
import { _ as _23 } from "./chunks/LpFileTree-DXb3yKzH.js";
|
|
26
26
|
import { ancestorIds, checkStateOf, checkedCount, computeStats, fileIcon, formatModified, formatSize, sortNodes, subtreeIds, subtreeSize } from "./components/fileTree.js";
|
|
27
27
|
import { _ as _24 } from "./chunks/LpFormField-Bn-ZwC6z.js";
|
|
28
28
|
import { _ as _25 } from "./chunks/LpIcon-CCnX5_2j.js";
|
|
@@ -31,9 +31,9 @@ import { _ as _27 } from "./chunks/LpInput-BauZRyzm.js";
|
|
|
31
31
|
import { _ as _28 } from "./chunks/LpLightbox-CWdIsthW.js";
|
|
32
32
|
import { fileNameOf } from "./components/lightbox.js";
|
|
33
33
|
import { _ as _29 } from "./chunks/LpLink-DHwOEp4e.js";
|
|
34
|
-
import { _ as _30 } from "./chunks/LpLogViewer-
|
|
35
|
-
import { _ as _31 } from "./chunks/LpModal-
|
|
36
|
-
import { _ as _32 } from "./chunks/LpNotificationBell-
|
|
34
|
+
import { _ as _30 } from "./chunks/LpLogViewer-tmKPNTuU.js";
|
|
35
|
+
import { _ as _31 } from "./chunks/LpModal-CYKAaSHO.js";
|
|
36
|
+
import { _ as _32 } from "./chunks/LpNotificationBell-DHze8wYN.js";
|
|
37
37
|
import { _ as _33 } from "./chunks/LpNumberField-C5ar-OwE.js";
|
|
38
38
|
import { _ as _34 } from "./chunks/LpOtpInput-DqaT0Z75.js";
|
|
39
39
|
import { _ as _35 } from "./chunks/LpPagination-CeGuNe_q.js";
|
|
@@ -44,22 +44,22 @@ import { _ as _38 } from "./chunks/LpPopover-8268UmlC.js";
|
|
|
44
44
|
import { _ as _39 } from "./chunks/LpProgress-BhI0IbjC.js";
|
|
45
45
|
import { _ as _40 } from "./chunks/LpRadio-CL-pI0_O.js";
|
|
46
46
|
import { _ as _41 } from "./chunks/LpRadioGroup-B4yDTmi6.js";
|
|
47
|
-
import { _ as _42 } from "./chunks/LpScrollArea-
|
|
47
|
+
import { _ as _42 } from "./chunks/LpScrollArea-DQ0Yudfu.js";
|
|
48
48
|
import { _ as _43 } from "./chunks/LpSegmented-BmpanyAo.js";
|
|
49
49
|
import { _ as _44 } from "./chunks/LpSelect-D5mU4cZO.js";
|
|
50
50
|
import { _ as _45 } from "./chunks/LpServiceNode-Dc-Ut5RS.js";
|
|
51
|
-
import { _ as _46 } from "./chunks/LpSidebar-
|
|
51
|
+
import { _ as _46 } from "./chunks/LpSidebar-BBG9NhAn.js";
|
|
52
52
|
import { _ as _47 } from "./chunks/LpSkeleton-eSFIo4kD.js";
|
|
53
53
|
import { _ as _48 } from "./chunks/LpSlider-B1SF3pRV.js";
|
|
54
54
|
import { _ as _49 } from "./chunks/LpStat-CdbEFOvn.js";
|
|
55
55
|
import { _ as _50 } from "./chunks/LpStepper-5dFTrW21.js";
|
|
56
56
|
import { _ as _51 } from "./chunks/LpSwitch-v6fnccSM.js";
|
|
57
|
-
import { _ as _52 } from "./chunks/LpTable-
|
|
57
|
+
import { _ as _52 } from "./chunks/LpTable-DqZ-L4Au.js";
|
|
58
58
|
import { _ as _53 } from "./chunks/LpTableOfContents-CjvxPMpU.js";
|
|
59
59
|
import { _ as _54 } from "./chunks/LpTabs-D7aTVPOb.js";
|
|
60
60
|
import { _ as _55 } from "./chunks/LpTextarea-CRAkhemZ.js";
|
|
61
|
-
import { p as presets, a as parseTheme, s as serializeTheme } from "./chunks/LpThemeSwitcher-
|
|
62
|
-
import { D, _ as _56, b, c, d, e, f, l, g, h, n, r, t, i, u, v } from "./chunks/LpThemeSwitcher-
|
|
61
|
+
import { p as presets, a as parseTheme, s as serializeTheme } from "./chunks/LpThemeSwitcher-Ct-lnXMa.js";
|
|
62
|
+
import { D, _ as _56, T, b, c, d, e, f, l, g, h, n, r, t, i, j, u, v } from "./chunks/LpThemeSwitcher-Ct-lnXMa.js";
|
|
63
63
|
import { _ as _57 } from "./chunks/LpTilt-DuyKbpkA.js";
|
|
64
64
|
import { _ as _58 } from "./chunks/LpToaster-gDB1EaU3.js";
|
|
65
65
|
import { _ as _59 } from "./chunks/LpTooltip-CIwoRCag.js";
|
|
@@ -168,6 +168,7 @@ export {
|
|
|
168
168
|
_60 as LpTopologyCanvas,
|
|
169
169
|
_61 as LpUptimeBar,
|
|
170
170
|
OSM_TILES,
|
|
171
|
+
T as THEME_COOKIE,
|
|
171
172
|
UI_CONFIG_VERSION,
|
|
172
173
|
addLeaf,
|
|
173
174
|
addTab,
|
|
@@ -218,8 +219,9 @@ export {
|
|
|
218
219
|
sortNodes,
|
|
219
220
|
subtreeIds,
|
|
220
221
|
subtreeSize,
|
|
221
|
-
t as
|
|
222
|
-
i as
|
|
222
|
+
t as themeFromCookie,
|
|
223
|
+
i as themeToCssRule,
|
|
224
|
+
j as themeToCssVars,
|
|
223
225
|
tileUrl,
|
|
224
226
|
unproject,
|
|
225
227
|
useInputFilter,
|
package/dist/theme/useTheme.d.ts
CHANGED
|
@@ -15,6 +15,16 @@ export declare function themeToCssRule(theme: TokenSet, selector?: string): stri
|
|
|
15
15
|
export declare function parseTheme(json: string): TokenSet;
|
|
16
16
|
export declare function bootstrapTheme(fallback: TokenSet): TokenSet;
|
|
17
17
|
export declare function cacheTheme(theme: TokenSet): void;
|
|
18
|
+
export declare const THEME_COOKIE = "lp-theme";
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a theme name (as read from the `lp-theme` cookie) against a set of
|
|
21
|
+
* known themes. Returns `null` when the name is absent or unknown, so the caller
|
|
22
|
+
* can fall back to its own default.
|
|
23
|
+
*
|
|
24
|
+
* Server-side counterpart to `cacheTheme`: pair it with `themeToCssRule` to
|
|
25
|
+
* inline the right variables into `<head>` during SSR.
|
|
26
|
+
*/
|
|
27
|
+
export declare function themeFromCookie(cookieValue: string | null | undefined, themes: readonly TokenSet[]): TokenSet | null;
|
|
18
28
|
export interface UseTheme {
|
|
19
29
|
/** The active theme, kept in sync by the kit. Null until hydrated (SSR/first
|
|
20
30
|
* paint) — reactive, so a switcher binds straight to it. */
|
package/package.json
CHANGED
|
@@ -83,8 +83,14 @@ const barFade =
|
|
|
83
83
|
:class="barFade"
|
|
84
84
|
:style="barInsetTop ? { marginTop: barInsetTop } : undefined"
|
|
85
85
|
>
|
|
86
|
+
<!-- Sized with min-width, not width: reka sets an inline
|
|
87
|
+
`width: var(--reka-scroll-area-thumb-width)` on the thumb, and for a
|
|
88
|
+
VERTICAL bar it only ever defines the height variable — the width one
|
|
89
|
+
stays empty, so the inline rule resolves to 0 and beat a plain `w-1`,
|
|
90
|
+
leaving an invisible thumb. A minimum wins over that without fighting
|
|
91
|
+
the positioning reka owns. -->
|
|
86
92
|
<ScrollAreaThumb
|
|
87
|
-
class="w-1 rounded-l-pill bg-brand/40 transition-[width,background-color] duration-[var(--duration-fast)] group-hover:w-1.5 group-hover:bg-brand"
|
|
93
|
+
class="min-w-1 rounded-l-pill bg-brand/40 transition-[min-width,background-color] duration-[var(--duration-fast)] group-hover:min-w-1.5 group-hover:bg-brand"
|
|
88
94
|
/>
|
|
89
95
|
</ScrollAreaScrollbar>
|
|
90
96
|
|
|
@@ -94,7 +100,7 @@ const barFade =
|
|
|
94
100
|
:class="barFade"
|
|
95
101
|
>
|
|
96
102
|
<ScrollAreaThumb
|
|
97
|
-
class="h-1 rounded-t-pill bg-brand/40 transition-[height,background-color] duration-[var(--duration-fast)] group-hover:h-1.5 group-hover:bg-brand"
|
|
103
|
+
class="min-h-1 rounded-t-pill bg-brand/40 transition-[min-height,background-color] duration-[var(--duration-fast)] group-hover:min-h-1.5 group-hover:bg-brand"
|
|
98
104
|
/>
|
|
99
105
|
</ScrollAreaScrollbar>
|
|
100
106
|
|
package/src/index.ts
CHANGED
package/src/nuxt.ts
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Nuxt module — auto-registers every kit component globally so consuming apps
|
|
3
3
|
* use <LpButton> / <LpThemeSwitcher> / … with no per-app component list to
|
|
4
|
-
* maintain. Add it to a Nuxt app's `modules`:
|
|
4
|
+
* maintain, and wires the SSR theme handoff. Add it to a Nuxt app's `modules`:
|
|
5
5
|
*
|
|
6
6
|
* export default defineNuxtConfig({ modules: ["@leavepulse/ui/nuxt"] })
|
|
7
7
|
*
|
|
8
|
-
* The list comes from the generated component-names file (kept in sync
|
|
9
|
-
* actual components at build), so a NEW component is available
|
|
10
|
-
* no consumer change.
|
|
8
|
+
* The component list comes from the generated component-names file (kept in sync
|
|
9
|
+
* with the actual components at build), so a NEW component is available
|
|
10
|
+
* everywhere with no consumer change.
|
|
11
|
+
*
|
|
12
|
+
* Options (nuxt.config `leavepulseUi`):
|
|
13
|
+
* theme false to skip the theme plugin entirely (default: true)
|
|
14
|
+
* defaultTheme preset name used when the visitor has no saved theme
|
|
11
15
|
*/
|
|
12
|
-
import { addComponent, defineNuxtModule } from "@nuxt/kit"
|
|
16
|
+
import { addComponent, addPlugin, createResolver, defineNuxtModule } from "@nuxt/kit"
|
|
13
17
|
import { COMPONENT_NAMES } from "./component-names"
|
|
14
18
|
|
|
15
|
-
export
|
|
19
|
+
export interface LeavepulseUiOptions {
|
|
20
|
+
/** Register the SSR theme plugin. Disable to wire theming yourself. */
|
|
21
|
+
theme?: boolean
|
|
22
|
+
/** Preset name to fall back to when nothing is saved (default "LeavePulse"). */
|
|
23
|
+
defaultTheme?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default defineNuxtModule<LeavepulseUiOptions>({
|
|
16
27
|
meta: { name: "@leavepulse/ui", configKey: "leavepulseUi" },
|
|
17
|
-
|
|
28
|
+
defaults: { theme: true },
|
|
29
|
+
setup(options: LeavepulseUiOptions, nuxt: { options: { runtimeConfig: { public: Record<string, unknown> } } }) {
|
|
18
30
|
for (const name of COMPONENT_NAMES) {
|
|
19
31
|
// Point each component at its own dist chunk rather than the barrel
|
|
20
32
|
// ("@leavepulse/ui"). Importing through the barrel makes the bundler pull
|
|
@@ -27,5 +39,19 @@ export default defineNuxtModule({
|
|
|
27
39
|
filePath: `@leavepulse/ui/dist/components/${name}.vue.js`,
|
|
28
40
|
})
|
|
29
41
|
}
|
|
42
|
+
|
|
43
|
+
if (options.theme === false) return
|
|
44
|
+
|
|
45
|
+
// The plugin reads its options from runtimeConfig rather than closing over
|
|
46
|
+
// them, so they survive the build into the server bundle.
|
|
47
|
+
nuxt.options.runtimeConfig.public.leavepulseUi = {
|
|
48
|
+
...(nuxt.options.runtimeConfig.public.leavepulseUi ?? {}),
|
|
49
|
+
defaultTheme: options.defaultTheme,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
addPlugin({
|
|
53
|
+
src: createResolver(import.meta.url).resolve("./runtime/theme.plugin"),
|
|
54
|
+
mode: "all",
|
|
55
|
+
})
|
|
30
56
|
},
|
|
31
57
|
})
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Nuxt runtime plugin — paints the user's theme during SSR, so a reload shows
|
|
3
|
+
* the right colours in the first frame instead of flashing the default.
|
|
4
|
+
*
|
|
5
|
+
* Registered automatically by the kit's Nuxt module; a consuming app needs no
|
|
6
|
+
* plugin of its own. Opt out (or point it at custom themes) via nuxt.config:
|
|
7
|
+
*
|
|
8
|
+
* leavepulseUi: { theme: false } // no theme handling at all
|
|
9
|
+
* leavepulseUi: { defaultTheme: "Nord" } // different fallback preset
|
|
10
|
+
*
|
|
11
|
+
* How it avoids the flash: the kit mirrors the chosen theme's NAME into the
|
|
12
|
+
* `lp-theme` cookie (see cacheTheme), which unlike localStorage travels with the
|
|
13
|
+
* request. Here the server reads it, resolves it against the built-in presets,
|
|
14
|
+
* and inlines that theme's CSS variables into <head>. On the client
|
|
15
|
+
* bootstrapTheme() still runs before mount, so a localStorage choice — which
|
|
16
|
+
* holds the full token values, including themes the server cannot name — keeps
|
|
17
|
+
* winning.
|
|
18
|
+
*/
|
|
19
|
+
// Imported through the package barrel on purpose. This file is shipped as
|
|
20
|
+
// source and compiled by the CONSUMING app, where "@leavepulse/ui" resolves to
|
|
21
|
+
// dist — the same module instance the kit's components use. A relative "../theme/…"
|
|
22
|
+
// would load a second copy of the theme singleton from src/, leaving components
|
|
23
|
+
// subscribed to a different reactive state than the one this plugin drives.
|
|
24
|
+
import {
|
|
25
|
+
bootstrapTheme,
|
|
26
|
+
leavepulse,
|
|
27
|
+
presets,
|
|
28
|
+
THEME_COOKIE,
|
|
29
|
+
themeFromCookie,
|
|
30
|
+
themeToCssRule,
|
|
31
|
+
type TokenSet,
|
|
32
|
+
} from "@leavepulse/ui"
|
|
33
|
+
// "#imports" is Nuxt's virtual module: it resolves in the consuming app, which
|
|
34
|
+
// is what compiles this file. (No @ts-expect-error here — the kit's own build
|
|
35
|
+
// excludes src/runtime, so the directive would be unused there and error in the
|
|
36
|
+
// consumer, where the import type-checks fine.)
|
|
37
|
+
import { defineNuxtPlugin, useCookie, useHead, useRuntimeConfig } from "#imports"
|
|
38
|
+
|
|
39
|
+
export default defineNuxtPlugin(() => {
|
|
40
|
+
const options = (useRuntimeConfig().public.leavepulseUi ?? {}) as {
|
|
41
|
+
defaultTheme?: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const themes = Object.values(presets) as TokenSet[]
|
|
45
|
+
const fallback =
|
|
46
|
+
themes.find((theme) => theme.name === options.defaultTheme) ?? leavepulse
|
|
47
|
+
|
|
48
|
+
// Read-only here: the cookie is written by cacheTheme() in the browser, which
|
|
49
|
+
// is the one place a theme choice is recorded.
|
|
50
|
+
const cookie = useCookie<string | null>(THEME_COOKIE, { readonly: true })
|
|
51
|
+
const initial = themeFromCookie(cookie.value, themes) ?? fallback
|
|
52
|
+
|
|
53
|
+
useHead({
|
|
54
|
+
style: [{ id: "lp-ui-theme", innerHTML: themeToCssRule(initial) }],
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// `initial` as the fallback (not the preset default) so a visitor who only
|
|
58
|
+
// has the cookie keeps the theme the server just painted.
|
|
59
|
+
if (import.meta.client) {
|
|
60
|
+
bootstrapTheme(initial)
|
|
61
|
+
}
|
|
62
|
+
})
|
package/src/theme/useTheme.ts
CHANGED
|
@@ -220,6 +220,47 @@ export function cacheTheme(theme: TokenSet): void {
|
|
|
220
220
|
} catch {
|
|
221
221
|
/* storage unavailable — non-fatal */
|
|
222
222
|
}
|
|
223
|
+
writeThemeCookie(theme.name)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/*
|
|
227
|
+
* SSR handoff. localStorage is invisible to the server, so an SSR app would
|
|
228
|
+
* render the default theme and only repaint after hydration — a visible flash on
|
|
229
|
+
* every reload. The cookie rides along with the request, letting the server
|
|
230
|
+
* inline the user's real theme in the first frame (see themeFromCookie).
|
|
231
|
+
*
|
|
232
|
+
* Only the NAME is stored: a full TokenSet is ~1KB of JSON that would be sent on
|
|
233
|
+
* every request. The server resolves the name against the themes it knows, and
|
|
234
|
+
* localStorage stays the client's source of truth for the full token values.
|
|
235
|
+
*/
|
|
236
|
+
export const THEME_COOKIE = "lp-theme"
|
|
237
|
+
|
|
238
|
+
const COOKIE_MAX_AGE = 60 * 60 * 24 * 365
|
|
239
|
+
|
|
240
|
+
function writeThemeCookie(name: string): void {
|
|
241
|
+
if (typeof document === "undefined") return
|
|
242
|
+
// lax: the theme must survive a top-level navigation (which is what SSR
|
|
243
|
+
// renders) without riding cross-site subrequests.
|
|
244
|
+
document.cookie =
|
|
245
|
+
`${THEME_COOKIE}=${encodeURIComponent(name)}` +
|
|
246
|
+
`; path=/; max-age=${COOKIE_MAX_AGE}; samesite=lax`
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Resolve a theme name (as read from the `lp-theme` cookie) against a set of
|
|
251
|
+
* known themes. Returns `null` when the name is absent or unknown, so the caller
|
|
252
|
+
* can fall back to its own default.
|
|
253
|
+
*
|
|
254
|
+
* Server-side counterpart to `cacheTheme`: pair it with `themeToCssRule` to
|
|
255
|
+
* inline the right variables into `<head>` during SSR.
|
|
256
|
+
*/
|
|
257
|
+
export function themeFromCookie(
|
|
258
|
+
cookieValue: string | null | undefined,
|
|
259
|
+
themes: readonly TokenSet[],
|
|
260
|
+
): TokenSet | null {
|
|
261
|
+
if (!cookieValue) return null
|
|
262
|
+
const name = decodeURIComponent(cookieValue)
|
|
263
|
+
return themes.find((theme) => theme.name === name) ?? null
|
|
223
264
|
}
|
|
224
265
|
|
|
225
266
|
export interface UseTheme {
|