@leavepulse/ui 0.23.0 → 0.24.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/{LpAppShell-CaQYQKZV.js → LpAppShell-B5k0J3Cf.js} +1 -1
- package/dist/chunks/{LpAvatar-D-jHoHR7.js → LpAvatar-CzCE5cXg.js} +17 -5
- package/dist/chunks/LpBreadcrumbs-5uvViCXi.js +60 -0
- package/dist/chunks/{LpCodeBlock-CSiOSPs8.js → LpCodeBlock-rS_6mO3D.js} +1 -1
- package/dist/chunks/{LpDisclosure-DP6yfgfM.js → LpDisclosure-BnwP4Q-b.js} +1 -1
- package/dist/chunks/LpEmptyState-BV3q7Qyi.js +49 -0
- package/dist/chunks/{LpFileTree-CN0IOIY7.js → LpFileTree-H7Ho8uoq.js} +2 -2
- package/dist/chunks/{LpFileTreeNode-D7WgUPcJ.js → LpFileTreeNode-BEZIvxHi.js} +1 -1
- package/dist/chunks/{LpLink-DU9kkKGW.js → LpLink-Bu01SZzB.js} +1 -1
- package/dist/chunks/{LpNotificationBell-a08cl0yY.js → LpNotificationBell-X1M30e0X.js} +1 -1
- package/dist/chunks/{LpSidebar-D3GGLSE7.js → LpSidebar-7Vpy2IJc.js} +1 -1
- package/dist/chunks/{LpSidebarNav-X14xMdPa.js → LpSidebarNav-CFX5NxGs.js} +1 -1
- package/dist/chunks/{LpStepper-5dFTrW21.js → LpStepper-Wtl-6nUh.js} +27 -10
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpAvatar.vue.d.ts +7 -3
- package/dist/components/LpAvatar.vue.js +1 -1
- package/dist/components/LpBreadcrumbs.vue.d.ts +13 -1
- package/dist/components/LpBreadcrumbs.vue.js +1 -1
- package/dist/components/LpCodeBlock.vue.js +1 -1
- package/dist/components/LpDisclosure.vue.js +1 -1
- package/dist/components/LpEmptyState.vue.d.ts +5 -0
- package/dist/components/LpEmptyState.vue.js +1 -1
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpLink.vue.d.ts +4 -2
- package/dist/components/LpLink.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpStepper.vue.d.ts +15 -1
- package/dist/components/LpStepper.vue.js +1 -1
- package/dist/index.js +11 -11
- package/package.json +1 -1
- package/src/components/LpAvatar.vue +18 -2
- package/src/components/LpBreadcrumbs.vue +30 -7
- package/src/components/LpCodeBlock.vue +1 -1
- package/src/components/LpDisclosure.vue +1 -1
- package/src/components/LpEmptyState.vue +18 -5
- package/src/components/LpFileTreeNode.vue +4 -1
- package/src/components/LpLink.vue +8 -2
- package/src/components/LpSidebarNav.vue +1 -1
- package/src/components/LpStepper.vue +49 -9
- package/dist/chunks/LpBreadcrumbs-B7Aqatzw.js +0 -42
- package/dist/chunks/LpEmptyState-CrfyRJUG.js +0 -47
|
@@ -3,7 +3,7 @@ import { _ as _sfc_main$2 } from "./LpButton-5VXXCjwF.js";
|
|
|
3
3
|
import { _ as _sfc_main$3 } from "./LpIcon-CCnX5_2j.js";
|
|
4
4
|
import { _ as _sfc_main$5 } from "./LpScrollArea-D8xyKXcF.js";
|
|
5
5
|
import { _ as _sfc_main$4 } from "./LpShift-DXNsauQZ.js";
|
|
6
|
-
import { _ as _sfc_main$1 } from "./LpSidebar-
|
|
6
|
+
import { _ as _sfc_main$1 } from "./LpSidebar-7Vpy2IJc.js";
|
|
7
7
|
const _hoisted_1 = { class: "flex h-dvh overflow-hidden bg-surface text-ink" };
|
|
8
8
|
const _hoisted_2 = { class: "flex min-w-0 flex-1 flex-col" };
|
|
9
9
|
const _hoisted_3 = { class: "flex h-16 shrink-0 items-center gap-3 border-b border-line bg-surface px-4 md:px-6" };
|
|
@@ -11,6 +11,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
11
11
|
alt: {},
|
|
12
12
|
fallback: {},
|
|
13
13
|
size: { default: "md" },
|
|
14
|
+
pixelSize: {},
|
|
14
15
|
shape: { default: "circle" },
|
|
15
16
|
ring: { type: Boolean, default: false },
|
|
16
17
|
menuItems: {}
|
|
@@ -20,9 +21,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
20
21
|
base: "inline-flex shrink-0 select-none items-center justify-center overflow-hidden bg-surface-soft font-medium text-muted-strong",
|
|
21
22
|
variants: {
|
|
22
23
|
size: {
|
|
24
|
+
xs: "size-5 text-[10px]",
|
|
23
25
|
sm: "size-7 text-xs",
|
|
24
26
|
md: "size-9 text-sm",
|
|
25
|
-
lg: "size-12 text-base"
|
|
27
|
+
lg: "size-12 text-base",
|
|
28
|
+
xl: "size-16 text-lg"
|
|
26
29
|
},
|
|
27
30
|
// People read as circles; things (servers, projects, orgs) read as
|
|
28
31
|
// rounded squares — the same distinction platform icons make.
|
|
@@ -36,6 +39,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
36
39
|
defaultVariants: { size: "md", shape: "circle", ring: false }
|
|
37
40
|
});
|
|
38
41
|
const props = __props;
|
|
42
|
+
const sizeStyle = computed(
|
|
43
|
+
() => props.pixelSize ? {
|
|
44
|
+
width: `${props.pixelSize}px`,
|
|
45
|
+
height: `${props.pixelSize}px`,
|
|
46
|
+
fontSize: `${Math.max(10, Math.round(props.pixelSize * 0.4))}px`
|
|
47
|
+
} : void 0
|
|
48
|
+
);
|
|
39
49
|
const initials = computed(
|
|
40
50
|
() => props.fallback ?? props.alt?.slice(0, 2).toUpperCase() ?? "?"
|
|
41
51
|
);
|
|
@@ -50,7 +60,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
50
60
|
}, {
|
|
51
61
|
default: withCtx(() => [
|
|
52
62
|
createVNode(unref(AvatarRoot), mergeProps({
|
|
53
|
-
class: unref(avatar)({ size: __props.size, shape: __props.shape, ring: __props.ring })
|
|
63
|
+
class: unref(avatar)({ size: __props.pixelSize ? void 0 : __props.size, shape: __props.shape, ring: __props.ring }),
|
|
64
|
+
style: sizeStyle.value
|
|
54
65
|
}, _ctx.$attrs), {
|
|
55
66
|
default: withCtx(() => [
|
|
56
67
|
__props.src && mounted.value ? (openBlock(), createBlock(unref(AvatarImage), {
|
|
@@ -67,12 +78,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
67
78
|
})
|
|
68
79
|
]),
|
|
69
80
|
_: 1
|
|
70
|
-
}, 16, ["class"])
|
|
81
|
+
}, 16, ["class", "style"])
|
|
71
82
|
]),
|
|
72
83
|
_: 1
|
|
73
84
|
}, 8, ["items"])) : (openBlock(), createBlock(unref(AvatarRoot), mergeProps({
|
|
74
85
|
key: 1,
|
|
75
|
-
class: unref(avatar)({ size: __props.size, shape: __props.shape, ring: __props.ring })
|
|
86
|
+
class: unref(avatar)({ size: __props.pixelSize ? void 0 : __props.size, shape: __props.shape, ring: __props.ring }),
|
|
87
|
+
style: sizeStyle.value
|
|
76
88
|
}, _ctx.$attrs), {
|
|
77
89
|
default: withCtx(() => [
|
|
78
90
|
__props.src ? (openBlock(), createBlock(unref(AvatarImage), {
|
|
@@ -89,7 +101,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
89
101
|
})
|
|
90
102
|
]),
|
|
91
103
|
_: 1
|
|
92
|
-
}, 16, ["class"]));
|
|
104
|
+
}, 16, ["class", "style"]));
|
|
93
105
|
};
|
|
94
106
|
}
|
|
95
107
|
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { defineComponent, openBlock, createElementBlock, Fragment, renderList, createBlock, createCommentVNode, resolveDynamicComponent, withCtx, createTextVNode, toDisplayString, normalizeClass } from "vue";
|
|
2
|
+
import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
|
|
3
|
+
const _hoisted_1 = {
|
|
4
|
+
class: "flex items-center gap-1.5 text-sm",
|
|
5
|
+
"aria-label": "Breadcrumb"
|
|
6
|
+
};
|
|
7
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
8
|
+
__name: "LpBreadcrumbs",
|
|
9
|
+
props: {
|
|
10
|
+
items: {},
|
|
11
|
+
as: { default: "a" }
|
|
12
|
+
},
|
|
13
|
+
emits: ["navigate"],
|
|
14
|
+
setup(__props) {
|
|
15
|
+
return (_ctx, _cache) => {
|
|
16
|
+
return openBlock(), createElementBlock("nav", _hoisted_1, [
|
|
17
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item, i) => {
|
|
18
|
+
return openBlock(), createElementBlock(Fragment, { key: i }, [
|
|
19
|
+
i > 0 ? (openBlock(), createBlock(_sfc_main$1, {
|
|
20
|
+
key: 0,
|
|
21
|
+
name: "lucide:chevron-right",
|
|
22
|
+
size: 14,
|
|
23
|
+
class: "text-muted"
|
|
24
|
+
})) : createCommentVNode("", true),
|
|
25
|
+
(item.href || item.to) && i < __props.items.length - 1 ? (openBlock(), createBlock(resolveDynamicComponent(__props.as), {
|
|
26
|
+
key: 1,
|
|
27
|
+
href: __props.as === "a" ? item.href : void 0,
|
|
28
|
+
to: __props.as === "a" ? void 0 : item.to,
|
|
29
|
+
class: "inline-flex items-center gap-1.5 rounded-xs text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring",
|
|
30
|
+
onClick: ($event) => _ctx.$emit("navigate", item, i)
|
|
31
|
+
}, {
|
|
32
|
+
default: withCtx(() => [
|
|
33
|
+
item.icon ? (openBlock(), createBlock(_sfc_main$1, {
|
|
34
|
+
key: 0,
|
|
35
|
+
name: item.icon,
|
|
36
|
+
size: 14
|
|
37
|
+
}, null, 8, ["name"])) : createCommentVNode("", true),
|
|
38
|
+
createTextVNode(" " + toDisplayString(item.label), 1)
|
|
39
|
+
]),
|
|
40
|
+
_: 2
|
|
41
|
+
}, 1032, ["href", "to", "onClick"])) : (openBlock(), createElementBlock("span", {
|
|
42
|
+
key: 2,
|
|
43
|
+
class: normalizeClass(["inline-flex items-center gap-1.5", i === __props.items.length - 1 ? "text-ink" : "text-muted"])
|
|
44
|
+
}, [
|
|
45
|
+
item.icon ? (openBlock(), createBlock(_sfc_main$1, {
|
|
46
|
+
key: 0,
|
|
47
|
+
name: item.icon,
|
|
48
|
+
size: 14
|
|
49
|
+
}, null, 8, ["name"])) : createCommentVNode("", true),
|
|
50
|
+
createTextVNode(" " + toDisplayString(item.label), 1)
|
|
51
|
+
], 2))
|
|
52
|
+
], 64);
|
|
53
|
+
}), 128))
|
|
54
|
+
]);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
export {
|
|
59
|
+
_sfc_main as _
|
|
60
|
+
};
|
|
@@ -212,7 +212,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
212
212
|
}), 128)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
213
213
|
createElementVNode("button", {
|
|
214
214
|
type: "button",
|
|
215
|
-
class: "lp-fold-toggle flex w-full items-center gap-1.5 rounded px-1 py-0.5 text-left text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring",
|
|
215
|
+
class: "lp-fold-toggle flex w-full items-center gap-1.5 rounded px-1 py-0.5 text-left text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
|
|
216
216
|
"aria-expanded": openState[seg.id],
|
|
217
217
|
onClick: ($event) => toggleFold(seg.id)
|
|
218
218
|
}, [
|
|
@@ -36,7 +36,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
36
36
|
"onUpdate:open": onToggle
|
|
37
37
|
}, {
|
|
38
38
|
default: withCtx(() => [
|
|
39
|
-
createVNode(unref(CollapsibleTrigger), { class: "group flex w-full items-center gap-2 px-3 py-2.5 text-sm font-semibold text-ink outline-none focus-visible:ring-2 focus-visible:ring-ring" }, {
|
|
39
|
+
createVNode(unref(CollapsibleTrigger), { class: "group flex w-full items-center gap-2 px-3 py-2.5 text-sm font-semibold text-ink outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" }, {
|
|
40
40
|
default: withCtx(() => [
|
|
41
41
|
__props.icon ? (openBlock(), createBlock(_sfc_main$1, {
|
|
42
42
|
key: 0,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { defineComponent, openBlock, createElementBlock, normalizeClass, createVNode, createCommentVNode, createElementVNode, toDisplayString, renderSlot } from "vue";
|
|
2
|
+
import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
|
|
3
|
+
const _hoisted_1 = { class: "flex flex-col gap-1" };
|
|
4
|
+
const _hoisted_2 = {
|
|
5
|
+
key: 0,
|
|
6
|
+
class: "max-w-sm text-sm text-muted"
|
|
7
|
+
};
|
|
8
|
+
const _hoisted_3 = {
|
|
9
|
+
key: 1,
|
|
10
|
+
class: "mt-1"
|
|
11
|
+
};
|
|
12
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
13
|
+
__name: "LpEmptyState",
|
|
14
|
+
props: {
|
|
15
|
+
icon: {},
|
|
16
|
+
title: {},
|
|
17
|
+
description: {},
|
|
18
|
+
compact: { type: Boolean }
|
|
19
|
+
},
|
|
20
|
+
setup(__props) {
|
|
21
|
+
return (_ctx, _cache) => {
|
|
22
|
+
return openBlock(), createElementBlock("div", {
|
|
23
|
+
class: normalizeClass(["flex flex-col items-center px-6 text-center", __props.compact ? "gap-2 py-6" : "gap-3 py-12"])
|
|
24
|
+
}, [
|
|
25
|
+
__props.icon ? (openBlock(), createElementBlock("div", {
|
|
26
|
+
key: 0,
|
|
27
|
+
class: normalizeClass(["flex items-center justify-center rounded-pill bg-surface-soft text-muted", __props.compact ? "size-9" : "size-12"])
|
|
28
|
+
}, [
|
|
29
|
+
createVNode(_sfc_main$1, {
|
|
30
|
+
name: __props.icon,
|
|
31
|
+
size: __props.compact ? 16 : 22
|
|
32
|
+
}, null, 8, ["name", "size"])
|
|
33
|
+
], 2)) : createCommentVNode("", true),
|
|
34
|
+
createElementVNode("div", _hoisted_1, [
|
|
35
|
+
createElementVNode("p", {
|
|
36
|
+
class: normalizeClass(["font-semibold text-ink", __props.compact ? "text-sm" : ""])
|
|
37
|
+
}, toDisplayString(__props.title), 3),
|
|
38
|
+
__props.description ? (openBlock(), createElementBlock("p", _hoisted_2, toDisplayString(__props.description), 1)) : createCommentVNode("", true)
|
|
39
|
+
]),
|
|
40
|
+
_ctx.$slots.default ? (openBlock(), createElementBlock("div", _hoisted_3, [
|
|
41
|
+
renderSlot(_ctx.$slots, "default")
|
|
42
|
+
])) : createCommentVNode("", true)
|
|
43
|
+
], 2);
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
export {
|
|
48
|
+
_sfc_main as _
|
|
49
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineComponent, ref, watch, computed, openBlock, createElementBlock, Fragment, renderList, normalizeStyle, createBlock, createVNode, withCtx, createElementVNode, renderSlot, mergeProps, normalizeProps, guardReactiveProps, createTextVNode, toDisplayString, createCommentVNode } from "vue";
|
|
2
2
|
import { computeStats, formatSize, sortNodes, subtreeIds, ancestorIds } from "../components/fileTree.js";
|
|
3
|
-
import { _ as _sfc_main$1 } from "./LpEmptyState-
|
|
4
|
-
import { _ as _sfc_main$3 } from "./LpFileTreeNode-
|
|
3
|
+
import { _ as _sfc_main$1 } from "./LpEmptyState-BV3q7Qyi.js";
|
|
4
|
+
import { _ as _sfc_main$3 } from "./LpFileTreeNode-BEZIvxHi.js";
|
|
5
5
|
import { _ as _sfc_main$2 } from "./LpScrollArea-D8xyKXcF.js";
|
|
6
6
|
const _hoisted_1 = {
|
|
7
7
|
key: 0,
|
|
@@ -127,7 +127,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
127
127
|
createElementVNode("div", {
|
|
128
128
|
"data-node-id": __props.node.id,
|
|
129
129
|
tabindex: isFocused.value ? 0 : -1,
|
|
130
|
-
class: normalizeClass(["group/row relative flex min-w-0 cursor-pointer select-none items-center gap-1.5 rounded-control py-1 pr-2 text-sm outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-ring", [
|
|
130
|
+
class: normalizeClass(["group/row relative flex min-w-0 cursor-pointer select-none items-center gap-1.5 rounded-control py-1 pr-2 text-sm outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", [
|
|
131
131
|
__props.node.disabled ? "cursor-not-allowed text-muted/50" : isSelected.value ? "bg-brand-soft text-ink" : "text-muted hover:bg-surface-soft hover:text-ink"
|
|
132
132
|
]]),
|
|
133
133
|
style: normalizeStyle({ paddingLeft: `${__props.depth * 14 + 6}px` }),
|
|
@@ -35,7 +35,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
35
35
|
rel: rel.value,
|
|
36
36
|
class: normalizeClass(["inline-flex items-center gap-1 underline-offset-2 outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring", [
|
|
37
37
|
colorClass.value,
|
|
38
|
-
__props.variant === "reveal" ? revealClass : "hover:underline"
|
|
38
|
+
__props.variant === "reveal" ? revealClass : __props.variant === "underline" ? "underline decoration-current/40 hover:decoration-current" : "hover:underline"
|
|
39
39
|
]])
|
|
40
40
|
}, {
|
|
41
41
|
default: withCtx(() => [
|
|
@@ -2,7 +2,7 @@ import { defineComponent, computed, useModel, openBlock, createBlock, withCtx, c
|
|
|
2
2
|
import { _ as _sfc_main$8 } from "./LpBadge-BPodVcJa.js";
|
|
3
3
|
import { _ as _sfc_main$7 } from "./LpButton-5VXXCjwF.js";
|
|
4
4
|
import { _ as _sfc_main$5 } from "./LpContextMenu-D0mzXqA7.js";
|
|
5
|
-
import { _ as _sfc_main$3 } from "./LpEmptyState-
|
|
5
|
+
import { _ as _sfc_main$3 } from "./LpEmptyState-BV3q7Qyi.js";
|
|
6
6
|
import { _ as _sfc_main$6 } from "./LpIcon-CCnX5_2j.js";
|
|
7
7
|
import { _ as _sfc_main$1 } from "./LpPopover-8268UmlC.js";
|
|
8
8
|
import { _ as _sfc_main$4 } from "./LpScrollArea-D8xyKXcF.js";
|
|
@@ -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
2
|
import { _ as _sfc_main$2 } from "./LpDrawer-DAJN5rGK.js";
|
|
3
|
-
import { _ as _sfc_main$1 } from "./LpSidebarNav-
|
|
3
|
+
import { _ as _sfc_main$1 } from "./LpSidebarNav-CFX5NxGs.js";
|
|
4
4
|
const _hoisted_1 = {
|
|
5
5
|
key: 1,
|
|
6
6
|
class: "mt-2 flex shrink-0 flex-col gap-2"
|
|
@@ -74,7 +74,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
74
74
|
disabled: item.href ? void 0 : item.disabled,
|
|
75
75
|
"aria-current": __props.itemActive(item) ? "page" : void 0,
|
|
76
76
|
"aria-disabled": item.disabled || void 0,
|
|
77
|
-
class: normalizeClass(["group/item relative flex items-center gap-3 rounded-control px-3 py-2 text-sm font-medium outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-ring", item.disabled ? "cursor-not-allowed text-muted/50" : __props.itemActive(item) ? "text-ink" : "text-muted hover:text-ink"]),
|
|
77
|
+
class: normalizeClass(["group/item relative flex items-center gap-3 rounded-control px-3 py-2 text-sm font-medium outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", item.disabled ? "cursor-not-allowed text-muted/50" : __props.itemActive(item) ? "text-ink" : "text-muted hover:text-ink"]),
|
|
78
78
|
onClick: ($event) => emit("activate", item)
|
|
79
79
|
}, {
|
|
80
80
|
default: withCtx(() => [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineComponent, openBlock, createElementBlock, Fragment, renderList, createElementVNode, normalizeClass, createBlock, createTextVNode, toDisplayString, createCommentVNode } from "vue";
|
|
1
|
+
import { defineComponent, computed, openBlock, createElementBlock, Fragment, renderList, createElementVNode, normalizeClass, createBlock, createTextVNode, toDisplayString, createCommentVNode } from "vue";
|
|
2
2
|
import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
|
|
3
3
|
const _hoisted_1 = { class: "flex items-center gap-2" };
|
|
4
4
|
const _hoisted_2 = ["aria-current"];
|
|
@@ -8,39 +8,56 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
8
8
|
__name: "LpStepper",
|
|
9
9
|
props: {
|
|
10
10
|
steps: {},
|
|
11
|
-
current: {}
|
|
11
|
+
current: {},
|
|
12
|
+
completed: {}
|
|
12
13
|
},
|
|
13
14
|
setup(__props) {
|
|
15
|
+
const props = __props;
|
|
16
|
+
const currentIndex = computed(() => {
|
|
17
|
+
if (typeof props.current === "number") return props.current;
|
|
18
|
+
return props.steps.findIndex((s) => s.key === props.current);
|
|
19
|
+
});
|
|
20
|
+
function isCompleted(step, i) {
|
|
21
|
+
if (!props.completed) return i < currentIndex.value;
|
|
22
|
+
return props.completed.includes(i) || !!step.key && props.completed.includes(step.key);
|
|
23
|
+
}
|
|
24
|
+
function isCurrent(i) {
|
|
25
|
+
return i === currentIndex.value;
|
|
26
|
+
}
|
|
14
27
|
return (_ctx, _cache) => {
|
|
15
28
|
return openBlock(), createElementBlock("ol", _hoisted_1, [
|
|
16
29
|
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.steps, (step, i) => {
|
|
17
30
|
return openBlock(), createElementBlock("li", {
|
|
18
|
-
key: i,
|
|
31
|
+
key: step.key ?? i,
|
|
19
32
|
class: "flex flex-1 items-center gap-2 last:flex-none",
|
|
20
|
-
"aria-current": i
|
|
33
|
+
"aria-current": isCurrent(i) ? "step" : void 0
|
|
21
34
|
}, [
|
|
22
35
|
createElementVNode("div", _hoisted_3, [
|
|
23
36
|
createElementVNode("span", {
|
|
24
|
-
class: normalizeClass(["flex size-7 shrink-0 items-center justify-center rounded-pill border text-xs font-semibold transition-colors", i
|
|
37
|
+
class: normalizeClass(["flex size-7 shrink-0 items-center justify-center rounded-pill border text-xs font-semibold transition-colors", isCompleted(step, i) ? "border-transparent bg-brand text-ink-inverse" : isCurrent(i) ? "border-brand text-brand" : "border-line text-muted"])
|
|
25
38
|
}, [
|
|
26
|
-
i
|
|
39
|
+
isCompleted(step, i) ? (openBlock(), createBlock(_sfc_main$1, {
|
|
27
40
|
key: 0,
|
|
28
41
|
name: "lucide:check",
|
|
29
42
|
size: 14
|
|
30
|
-
})) : (openBlock(),
|
|
43
|
+
})) : step.icon ? (openBlock(), createBlock(_sfc_main$1, {
|
|
44
|
+
key: 1,
|
|
45
|
+
name: step.icon,
|
|
46
|
+
size: 14
|
|
47
|
+
}, null, 8, ["name"])) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [
|
|
31
48
|
createTextVNode(toDisplayString(i + 1), 1)
|
|
32
49
|
], 64))
|
|
33
50
|
], 2),
|
|
34
51
|
createElementVNode("span", {
|
|
35
|
-
class: normalizeClass(["text-sm", i
|
|
52
|
+
class: normalizeClass(["text-sm", isCompleted(step, i) || isCurrent(i) ? "text-ink" : "text-muted"])
|
|
36
53
|
}, [
|
|
37
54
|
createTextVNode(toDisplayString(step.label) + " ", 1),
|
|
38
|
-
createElementVNode("span", _hoisted_4, toDisplayString(i
|
|
55
|
+
createElementVNode("span", _hoisted_4, toDisplayString(isCompleted(step, i) ? "(completed)" : isCurrent(i) ? "(current step)" : ""), 1)
|
|
39
56
|
], 2)
|
|
40
57
|
]),
|
|
41
58
|
i < __props.steps.length - 1 ? (openBlock(), createElementBlock("span", {
|
|
42
59
|
key: 0,
|
|
43
|
-
class: normalizeClass(["h-px flex-1", i
|
|
60
|
+
class: normalizeClass(["h-px flex-1", isCompleted(step, i) ? "bg-brand" : "bg-line"])
|
|
44
61
|
}, null, 2)) : createCommentVNode("", true)
|
|
45
62
|
], 8, _hoisted_2);
|
|
46
63
|
}), 128))
|
|
@@ -5,7 +5,9 @@ declare const __VLS_export: import('vue').DefineComponent<{
|
|
|
5
5
|
src?: string;
|
|
6
6
|
alt?: string;
|
|
7
7
|
fallback?: string;
|
|
8
|
-
size?: "sm" | "md" | "lg" | undefined;
|
|
8
|
+
size?: "sm" | "md" | "lg" | "xs" | "xl" | undefined;
|
|
9
|
+
/** Explicit pixel size, wins over `size` — for avatars keyed to a layout. */
|
|
10
|
+
pixelSize?: number;
|
|
9
11
|
/** Silhouette: circle for people, soft/square for servers and projects. */
|
|
10
12
|
shape?: "circle" | "square" | "soft" | undefined;
|
|
11
13
|
/** Draws a hairline ring, for avatars laid over imagery or other avatars. */
|
|
@@ -16,7 +18,9 @@ declare const __VLS_export: import('vue').DefineComponent<{
|
|
|
16
18
|
src?: string;
|
|
17
19
|
alt?: string;
|
|
18
20
|
fallback?: string;
|
|
19
|
-
size?: "sm" | "md" | "lg" | undefined;
|
|
21
|
+
size?: "sm" | "md" | "lg" | "xs" | "xl" | undefined;
|
|
22
|
+
/** Explicit pixel size, wins over `size` — for avatars keyed to a layout. */
|
|
23
|
+
pixelSize?: number;
|
|
20
24
|
/** Silhouette: circle for people, soft/square for servers and projects. */
|
|
21
25
|
shape?: "circle" | "square" | "soft" | undefined;
|
|
22
26
|
/** Draws a hairline ring, for avatars laid over imagery or other avatars. */
|
|
@@ -24,7 +28,7 @@ declare const __VLS_export: import('vue').DefineComponent<{
|
|
|
24
28
|
/** Right-click menu (e.g. account quick actions). Consumer-supplied. */
|
|
25
29
|
menuItems?: ContextMenuItemDef[];
|
|
26
30
|
}> & Readonly<{}>, {
|
|
27
|
-
size: "sm" | "md" | "lg";
|
|
31
|
+
size: "sm" | "md" | "lg" | "xs" | "xl";
|
|
28
32
|
shape: "circle" | "square" | "soft";
|
|
29
33
|
ring: boolean;
|
|
30
34
|
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
@@ -1,14 +1,26 @@
|
|
|
1
|
+
import { Component } from 'vue';
|
|
1
2
|
export interface Crumb {
|
|
2
3
|
label: string;
|
|
3
4
|
href?: string;
|
|
5
|
+
/** Destination for router links; passed straight to the `as` component. */
|
|
6
|
+
to?: string | Record<string, unknown>;
|
|
7
|
+
/** Leading icon, for crumbs that carry a glyph (a home root, a section). */
|
|
8
|
+
icon?: string;
|
|
4
9
|
}
|
|
5
10
|
type __VLS_Props = {
|
|
6
11
|
items: Crumb[];
|
|
12
|
+
/**
|
|
13
|
+
* Root element/component for linked crumbs. Defaults to a native <a>;
|
|
14
|
+
* pass a router link component to keep client-side navigation.
|
|
15
|
+
*/
|
|
16
|
+
as?: string | Component;
|
|
7
17
|
};
|
|
8
18
|
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
9
19
|
navigate: (item: Crumb, index: number) => any;
|
|
10
20
|
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
21
|
onNavigate?: ((item: Crumb, index: number) => any) | undefined;
|
|
12
|
-
}>, {
|
|
22
|
+
}>, {
|
|
23
|
+
as: string | Component;
|
|
24
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
13
25
|
declare const _default: typeof __VLS_export;
|
|
14
26
|
export default _default;
|
|
@@ -2,6 +2,11 @@ type __VLS_Props = {
|
|
|
2
2
|
icon?: string;
|
|
3
3
|
title: string;
|
|
4
4
|
description?: string;
|
|
5
|
+
/**
|
|
6
|
+
* Tightens the block for empty states nested inside a card or a panel,
|
|
7
|
+
* where the full-page padding would dwarf its container.
|
|
8
|
+
*/
|
|
9
|
+
compact?: boolean;
|
|
5
10
|
};
|
|
6
11
|
declare var __VLS_6: {};
|
|
7
12
|
type __VLS_Slots = {} & {
|
|
@@ -21,11 +21,13 @@ type __VLS_Props = {
|
|
|
21
21
|
as?: string | Component;
|
|
22
22
|
/**
|
|
23
23
|
* "default" — plain hover underline.
|
|
24
|
+
* "underline" — underlined at rest; for links inside running prose,
|
|
25
|
+
* where hover-only underlines leave the link invisible until pointed at.
|
|
24
26
|
* "reveal" — an underline bar that grows in from the left on hover
|
|
25
27
|
* (origin-left scale-x 0→1). The LeavePulse landing "monitoring" link feel;
|
|
26
28
|
* good for inline prose links and nav items that want a bit of motion.
|
|
27
29
|
*/
|
|
28
|
-
variant?: "default" | "reveal";
|
|
30
|
+
variant?: "default" | "underline" | "reveal";
|
|
29
31
|
};
|
|
30
32
|
declare var __VLS_8: {};
|
|
31
33
|
type __VLS_Slots = {} & {
|
|
@@ -33,7 +35,7 @@ type __VLS_Slots = {} & {
|
|
|
33
35
|
};
|
|
34
36
|
declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
35
37
|
as: string | Component;
|
|
36
|
-
variant: "default" | "reveal";
|
|
38
|
+
variant: "default" | "underline" | "reveal";
|
|
37
39
|
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
38
40
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
39
41
|
declare const _default: typeof __VLS_export;
|
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
export interface Step {
|
|
2
2
|
label: string;
|
|
3
|
+
/** Stable id, for flows whose steps are addressed by name rather than order. */
|
|
4
|
+
key?: string;
|
|
5
|
+
/** Replaces the step number while the step is pending or current. */
|
|
6
|
+
icon?: string;
|
|
3
7
|
}
|
|
4
8
|
type __VLS_Props = {
|
|
5
9
|
steps: Step[];
|
|
6
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The active step: an index, or a step `key` for keyed flows.
|
|
12
|
+
*/
|
|
13
|
+
current: number | string;
|
|
14
|
+
/**
|
|
15
|
+
* Which steps count as done. Omit it and everything before `current` is
|
|
16
|
+
* complete, which is the linear case. Pass keys (or indices) when a flow can
|
|
17
|
+
* finish steps out of order — a verification that succeeds before its
|
|
18
|
+
* prerequisite is filled in, say.
|
|
19
|
+
*/
|
|
20
|
+
completed?: Array<string | number>;
|
|
7
21
|
};
|
|
8
22
|
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
9
23
|
declare const _default: typeof __VLS_export;
|
package/dist/index.js
CHANGED
|
@@ -3,26 +3,26 @@ import { _ as _2 } from "./chunks/LpAddressInput-BTqnUXZG.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-B5k0J3Cf.js";
|
|
7
7
|
import { _ as _6 } from "./chunks/LpAutocomplete-DExlIZe_.js";
|
|
8
|
-
import { _ as _7 } from "./chunks/LpAvatar-
|
|
8
|
+
import { _ as _7 } from "./chunks/LpAvatar-CzCE5cXg.js";
|
|
9
9
|
import { _ as _8 } from "./chunks/LpBadge-BPodVcJa.js";
|
|
10
|
-
import { _ as _9 } from "./chunks/LpBreadcrumbs-
|
|
10
|
+
import { _ as _9 } from "./chunks/LpBreadcrumbs-5uvViCXi.js";
|
|
11
11
|
import { _ as _10 } from "./chunks/LpButton-5VXXCjwF.js";
|
|
12
12
|
import { _ as _11 } from "./chunks/LpCalendar-B7ZL0ty3.js";
|
|
13
13
|
import { _ as _12 } from "./chunks/LpCard-BmrTvWOe.js";
|
|
14
14
|
import { _ as _13 } from "./chunks/LpCheckbox-BO0zuuPh.js";
|
|
15
|
-
import { _ as _14 } from "./chunks/LpCodeBlock-
|
|
15
|
+
import { _ as _14 } from "./chunks/LpCodeBlock-rS_6mO3D.js";
|
|
16
16
|
import { default as default2 } from "./components/LpCommandPalette.vue.js";
|
|
17
17
|
import { _ as _15 } from "./chunks/LpConfirmDialog-CObRah9c.js";
|
|
18
18
|
import { _ as _16 } from "./chunks/LpContextMenu-D0mzXqA7.js";
|
|
19
19
|
import { _ as _17 } from "./chunks/LpDatePicker-dY2q4dr4.js";
|
|
20
|
-
import { _ as _18 } from "./chunks/LpDisclosure-
|
|
20
|
+
import { _ as _18 } from "./chunks/LpDisclosure-BnwP4Q-b.js";
|
|
21
21
|
import { _ as _19 } from "./chunks/LpDivider-CUX46KR0.js";
|
|
22
22
|
import { _ as _20 } from "./chunks/LpDrawer-DAJN5rGK.js";
|
|
23
23
|
import { _ as _21 } from "./chunks/LpDropdownMenu-DJpoqRCb.js";
|
|
24
|
-
import { _ as _22 } from "./chunks/LpEmptyState-
|
|
25
|
-
import { _ as _23 } from "./chunks/LpFileTree-
|
|
24
|
+
import { _ as _22 } from "./chunks/LpEmptyState-BV3q7Qyi.js";
|
|
25
|
+
import { _ as _23 } from "./chunks/LpFileTree-H7Ho8uoq.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-CesaPWPO.js";
|
|
28
28
|
import { _ as _25 } from "./chunks/LpIcon-CCnX5_2j.js";
|
|
@@ -30,10 +30,10 @@ import { _ as _26 } from "./chunks/LpInfraNode-qIL3l7IO.js";
|
|
|
30
30
|
import { _ as _27 } from "./chunks/LpInput-jwqXlAy0.js";
|
|
31
31
|
import { _ as _28 } from "./chunks/LpLightbox-Ci35Y_xP.js";
|
|
32
32
|
import { fileNameOf } from "./components/lightbox.js";
|
|
33
|
-
import { _ as _29 } from "./chunks/LpLink-
|
|
33
|
+
import { _ as _29 } from "./chunks/LpLink-Bu01SZzB.js";
|
|
34
34
|
import { _ as _30 } from "./chunks/LpLogViewer-B1aLUVdz.js";
|
|
35
35
|
import { _ as _31 } from "./chunks/LpModal-D_o-56To.js";
|
|
36
|
-
import { _ as _32 } from "./chunks/LpNotificationBell-
|
|
36
|
+
import { _ as _32 } from "./chunks/LpNotificationBell-X1M30e0X.js";
|
|
37
37
|
import { _ as _33 } from "./chunks/LpNumberField-B3JuQFol.js";
|
|
38
38
|
import { _ as _34 } from "./chunks/LpOtpInput-DqaT0Z75.js";
|
|
39
39
|
import { _ as _35 } from "./chunks/LpPagination-CeGuNe_q.js";
|
|
@@ -50,11 +50,11 @@ import { _ as _44 } from "./chunks/LpSelect-Cw8-gL5F.js";
|
|
|
50
50
|
import { _ as _45 } from "./chunks/LpServiceNode-D8uJ8sGk.js";
|
|
51
51
|
import { _ as _46 } from "./chunks/LpShift-DXNsauQZ.js";
|
|
52
52
|
import { default as default3 } from "./components/LpShortcutsDialog.vue.js";
|
|
53
|
-
import { _ as _47 } from "./chunks/LpSidebar-
|
|
53
|
+
import { _ as _47 } from "./chunks/LpSidebar-7Vpy2IJc.js";
|
|
54
54
|
import { _ as _48 } from "./chunks/LpSkeleton-eSFIo4kD.js";
|
|
55
55
|
import { _ as _49 } from "./chunks/LpSlider-B1SF3pRV.js";
|
|
56
56
|
import { _ as _50 } from "./chunks/LpStat-CdbEFOvn.js";
|
|
57
|
-
import { _ as _51 } from "./chunks/LpStepper-
|
|
57
|
+
import { _ as _51 } from "./chunks/LpStepper-Wtl-6nUh.js";
|
|
58
58
|
import { _ as _52 } from "./chunks/LpSwitch-v6fnccSM.js";
|
|
59
59
|
import { _ as _53 } from "./chunks/LpTable-DTj52qlg.js";
|
|
60
60
|
import { _ as _54 } from "./chunks/LpTableOfContents-CjvxPMpU.js";
|
package/package.json
CHANGED
|
@@ -15,9 +15,11 @@ const avatar = tv({
|
|
|
15
15
|
base: "inline-flex shrink-0 select-none items-center justify-center overflow-hidden bg-surface-soft font-medium text-muted-strong",
|
|
16
16
|
variants: {
|
|
17
17
|
size: {
|
|
18
|
+
xs: "size-5 text-[10px]",
|
|
18
19
|
sm: "size-7 text-xs",
|
|
19
20
|
md: "size-9 text-sm",
|
|
20
21
|
lg: "size-12 text-base",
|
|
22
|
+
xl: "size-16 text-lg",
|
|
21
23
|
},
|
|
22
24
|
// People read as circles; things (servers, projects, orgs) read as
|
|
23
25
|
// rounded squares — the same distinction platform icons make.
|
|
@@ -39,6 +41,8 @@ const props = withDefaults(
|
|
|
39
41
|
alt?: string
|
|
40
42
|
fallback?: string
|
|
41
43
|
size?: AvatarVariants["size"]
|
|
44
|
+
/** Explicit pixel size, wins over `size` — for avatars keyed to a layout. */
|
|
45
|
+
pixelSize?: number
|
|
42
46
|
/** Silhouette: circle for people, soft/square for servers and projects. */
|
|
43
47
|
shape?: AvatarVariants["shape"]
|
|
44
48
|
/** Draws a hairline ring, for avatars laid over imagery or other avatars. */
|
|
@@ -49,6 +53,18 @@ const props = withDefaults(
|
|
|
49
53
|
{ size: "md", shape: "circle", ring: false },
|
|
50
54
|
)
|
|
51
55
|
|
|
56
|
+
// A pixel size drives both box and glyph, so the initials keep their
|
|
57
|
+
// proportion instead of staying at the preset's step.
|
|
58
|
+
const sizeStyle = computed(() =>
|
|
59
|
+
props.pixelSize
|
|
60
|
+
? {
|
|
61
|
+
width: `${props.pixelSize}px`,
|
|
62
|
+
height: `${props.pixelSize}px`,
|
|
63
|
+
fontSize: `${Math.max(10, Math.round(props.pixelSize * 0.4))}px`,
|
|
64
|
+
}
|
|
65
|
+
: undefined,
|
|
66
|
+
)
|
|
67
|
+
|
|
52
68
|
const initials = computed(
|
|
53
69
|
() => props.fallback ?? props.alt?.slice(0, 2).toUpperCase() ?? "?",
|
|
54
70
|
)
|
|
@@ -67,12 +83,12 @@ onMounted(() => {
|
|
|
67
83
|
|
|
68
84
|
<template>
|
|
69
85
|
<LpContextMenu v-if="menuItems?.length" :items="menuItems">
|
|
70
|
-
<AvatarRoot :class="avatar({ size, shape, ring })" v-bind="$attrs">
|
|
86
|
+
<AvatarRoot :class="avatar({ size: pixelSize ? undefined : size, shape, ring })" :style="sizeStyle" v-bind="$attrs">
|
|
71
87
|
<AvatarImage v-if="src && mounted" :src="src" :alt="alt" class="size-full object-cover" />
|
|
72
88
|
<AvatarFallback>{{ initials }}</AvatarFallback>
|
|
73
89
|
</AvatarRoot>
|
|
74
90
|
</LpContextMenu>
|
|
75
|
-
<AvatarRoot v-else :class="avatar({ size, shape, ring })" v-bind="$attrs">
|
|
91
|
+
<AvatarRoot v-else :class="avatar({ size: pixelSize ? undefined : size, shape, ring })" :style="sizeStyle" v-bind="$attrs">
|
|
76
92
|
<AvatarImage v-if="src" :src="src" :alt="alt" class="size-full object-cover" />
|
|
77
93
|
<AvatarFallback>{{ initials }}</AvatarFallback>
|
|
78
94
|
</AvatarRoot>
|
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { Component } from "vue"
|
|
2
3
|
import LpIcon from "./LpIcon.vue"
|
|
3
4
|
|
|
4
5
|
export interface Crumb {
|
|
5
6
|
label: string
|
|
6
7
|
href?: string
|
|
8
|
+
/** Destination for router links; passed straight to the `as` component. */
|
|
9
|
+
to?: string | Record<string, unknown>
|
|
10
|
+
/** Leading icon, for crumbs that carry a glyph (a home root, a section). */
|
|
11
|
+
icon?: string
|
|
7
12
|
}
|
|
8
13
|
|
|
9
|
-
|
|
14
|
+
withDefaults(
|
|
15
|
+
defineProps<{
|
|
16
|
+
items: Crumb[]
|
|
17
|
+
/**
|
|
18
|
+
* Root element/component for linked crumbs. Defaults to a native <a>;
|
|
19
|
+
* pass a router link component to keep client-side navigation.
|
|
20
|
+
*/
|
|
21
|
+
as?: string | Component
|
|
22
|
+
}>(),
|
|
23
|
+
{ as: "a" },
|
|
24
|
+
)
|
|
10
25
|
defineEmits<{ (e: "navigate", item: Crumb, index: number): void }>()
|
|
11
26
|
</script>
|
|
12
27
|
|
|
@@ -19,15 +34,23 @@ defineEmits<{ (e: "navigate", item: Crumb, index: number): void }>()
|
|
|
19
34
|
:size="14"
|
|
20
35
|
class="text-muted"
|
|
21
36
|
/>
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
37
|
+
<component
|
|
38
|
+
:is="as"
|
|
39
|
+
v-if="(item.href || item.to) && i < items.length - 1"
|
|
40
|
+
:href="as === 'a' ? item.href : undefined"
|
|
41
|
+
:to="as === 'a' ? undefined : item.to"
|
|
42
|
+
class="inline-flex items-center gap-1.5 rounded-xs text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
|
|
26
43
|
@click="$emit('navigate', item, i)"
|
|
27
44
|
>
|
|
45
|
+
<LpIcon v-if="item.icon" :name="item.icon" :size="14" />
|
|
28
46
|
{{ item.label }}
|
|
29
|
-
</
|
|
30
|
-
<span
|
|
47
|
+
</component>
|
|
48
|
+
<span
|
|
49
|
+
v-else
|
|
50
|
+
class="inline-flex items-center gap-1.5"
|
|
51
|
+
:class="i === items.length - 1 ? 'text-ink' : 'text-muted'"
|
|
52
|
+
>
|
|
53
|
+
<LpIcon v-if="item.icon" :name="item.icon" :size="14" />
|
|
31
54
|
{{ item.label }}
|
|
32
55
|
</span>
|
|
33
56
|
</template>
|
|
@@ -268,7 +268,7 @@ function onInput(e: Event) {
|
|
|
268
268
|
v-else
|
|
269
269
|
><button
|
|
270
270
|
type="button"
|
|
271
|
-
class="lp-fold-toggle flex w-full items-center gap-1.5 rounded px-1 py-0.5 text-left text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
|
|
271
|
+
class="lp-fold-toggle flex w-full items-center gap-1.5 rounded px-1 py-0.5 text-left text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
|
|
272
272
|
:aria-expanded="openState[seg.id]"
|
|
273
273
|
@click="toggleFold(seg.id)"
|
|
274
274
|
><LpIcon
|
|
@@ -61,7 +61,7 @@ function onToggle(value: boolean) {
|
|
|
61
61
|
@update:open="onToggle"
|
|
62
62
|
>
|
|
63
63
|
<CollapsibleTrigger
|
|
64
|
-
class="group flex w-full items-center gap-2 px-3 py-2.5 text-sm font-semibold text-ink outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
64
|
+
class="group flex w-full items-center gap-2 px-3 py-2.5 text-sm font-semibold text-ink outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
|
|
65
65
|
>
|
|
66
66
|
<LpIcon v-if="icon" :name="icon" :size="14" class="text-muted" />
|
|
67
67
|
<span class="min-w-0 flex-1 text-left">
|
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import LpIcon from "./LpIcon.vue"
|
|
3
3
|
|
|
4
|
-
defineProps<{
|
|
4
|
+
defineProps<{
|
|
5
|
+
icon?: string
|
|
6
|
+
title: string
|
|
7
|
+
description?: string
|
|
8
|
+
/**
|
|
9
|
+
* Tightens the block for empty states nested inside a card or a panel,
|
|
10
|
+
* where the full-page padding would dwarf its container.
|
|
11
|
+
*/
|
|
12
|
+
compact?: boolean
|
|
13
|
+
}>()
|
|
5
14
|
</script>
|
|
6
15
|
|
|
7
16
|
<template>
|
|
8
|
-
<div
|
|
17
|
+
<div
|
|
18
|
+
class="flex flex-col items-center px-6 text-center"
|
|
19
|
+
:class="compact ? 'gap-2 py-6' : 'gap-3 py-12'"
|
|
20
|
+
>
|
|
9
21
|
<div
|
|
10
22
|
v-if="icon"
|
|
11
|
-
class="flex
|
|
23
|
+
class="flex items-center justify-center rounded-pill bg-surface-soft text-muted"
|
|
24
|
+
:class="compact ? 'size-9' : 'size-12'"
|
|
12
25
|
>
|
|
13
|
-
<LpIcon :name="icon" :size="22" />
|
|
26
|
+
<LpIcon :name="icon" :size="compact ? 16 : 22" />
|
|
14
27
|
</div>
|
|
15
28
|
<div class="flex flex-col gap-1">
|
|
16
|
-
<p class="font-semibold text-ink">{{ title }}</p>
|
|
29
|
+
<p class="font-semibold text-ink" :class="compact ? 'text-sm' : ''">{{ title }}</p>
|
|
17
30
|
<p v-if="description" class="max-w-sm text-sm text-muted">{{ description }}</p>
|
|
18
31
|
</div>
|
|
19
32
|
<div v-if="$slots.default" class="mt-1"><slot /></div>
|
|
@@ -163,10 +163,13 @@ function onActivate() {
|
|
|
163
163
|
>
|
|
164
164
|
<!-- Passthrough when the node has no menu, so the row keeps the native one. -->
|
|
165
165
|
<LpContextMenu :items="node.menu ?? []">
|
|
166
|
+
<!-- The ring is drawn inset, like LpTable's rows: a row spans the full
|
|
167
|
+
width of the branch, and a branch clips its overflow to animate its
|
|
168
|
+
height, so an outset ring loses its left and right edge. -->
|
|
166
169
|
<div
|
|
167
170
|
:data-node-id="node.id"
|
|
168
171
|
:tabindex="isFocused ? 0 : -1"
|
|
169
|
-
class="group/row relative flex min-w-0 cursor-pointer select-none items-center gap-1.5 rounded-control py-1 pr-2 text-sm outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-ring"
|
|
172
|
+
class="group/row relative flex min-w-0 cursor-pointer select-none items-center gap-1.5 rounded-control py-1 pr-2 text-sm outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
|
|
170
173
|
:class="[
|
|
171
174
|
node.disabled
|
|
172
175
|
? 'cursor-not-allowed text-muted/50'
|
|
@@ -24,11 +24,13 @@ const props = withDefaults(
|
|
|
24
24
|
as?: string | Component
|
|
25
25
|
/**
|
|
26
26
|
* "default" — plain hover underline.
|
|
27
|
+
* "underline" — underlined at rest; for links inside running prose,
|
|
28
|
+
* where hover-only underlines leave the link invisible until pointed at.
|
|
27
29
|
* "reveal" — an underline bar that grows in from the left on hover
|
|
28
30
|
* (origin-left scale-x 0→1). The LeavePulse landing "monitoring" link feel;
|
|
29
31
|
* good for inline prose links and nav items that want a bit of motion.
|
|
30
32
|
*/
|
|
31
|
-
variant?: "default" | "reveal"
|
|
33
|
+
variant?: "default" | "underline" | "reveal"
|
|
32
34
|
}>(),
|
|
33
35
|
{ variant: "default", as: "a" },
|
|
34
36
|
)
|
|
@@ -72,7 +74,11 @@ const revealClass =
|
|
|
72
74
|
class="inline-flex items-center gap-1 underline-offset-2 outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring"
|
|
73
75
|
:class="[
|
|
74
76
|
colorClass,
|
|
75
|
-
variant === 'reveal'
|
|
77
|
+
variant === 'reveal'
|
|
78
|
+
? revealClass
|
|
79
|
+
: variant === 'underline'
|
|
80
|
+
? 'underline decoration-current/40 hover:decoration-current'
|
|
81
|
+
: 'hover:underline',
|
|
76
82
|
]"
|
|
77
83
|
>
|
|
78
84
|
<slot />
|
|
@@ -78,7 +78,7 @@ const pillTransition = usePillTransition()
|
|
|
78
78
|
:disabled="item.href ? undefined : item.disabled"
|
|
79
79
|
:aria-current="itemActive(item) ? 'page' : undefined"
|
|
80
80
|
:aria-disabled="item.disabled || undefined"
|
|
81
|
-
class="group/item relative flex items-center gap-3 rounded-control px-3 py-2 text-sm font-medium outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-ring"
|
|
81
|
+
class="group/item relative flex items-center gap-3 rounded-control px-3 py-2 text-sm font-medium outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
|
|
82
82
|
:class="item.disabled
|
|
83
83
|
? 'cursor-not-allowed text-muted/50'
|
|
84
84
|
: itemActive(item)
|
|
@@ -1,45 +1,85 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { computed } from "vue"
|
|
2
3
|
import LpIcon from "./LpIcon.vue"
|
|
3
4
|
|
|
4
5
|
export interface Step {
|
|
5
6
|
label: string
|
|
7
|
+
/** Stable id, for flows whose steps are addressed by name rather than order. */
|
|
8
|
+
key?: string
|
|
9
|
+
/** Replaces the step number while the step is pending or current. */
|
|
10
|
+
icon?: string
|
|
6
11
|
}
|
|
7
12
|
|
|
8
|
-
defineProps<{
|
|
13
|
+
const props = defineProps<{
|
|
14
|
+
steps: Step[]
|
|
15
|
+
/**
|
|
16
|
+
* The active step: an index, or a step `key` for keyed flows.
|
|
17
|
+
*/
|
|
18
|
+
current: number | string
|
|
19
|
+
/**
|
|
20
|
+
* Which steps count as done. Omit it and everything before `current` is
|
|
21
|
+
* complete, which is the linear case. Pass keys (or indices) when a flow can
|
|
22
|
+
* finish steps out of order — a verification that succeeds before its
|
|
23
|
+
* prerequisite is filled in, say.
|
|
24
|
+
*/
|
|
25
|
+
completed?: Array<string | number>
|
|
26
|
+
}>()
|
|
27
|
+
|
|
28
|
+
const currentIndex = computed(() => {
|
|
29
|
+
if (typeof props.current === "number") return props.current
|
|
30
|
+
return props.steps.findIndex((s) => s.key === props.current)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
function isCompleted(step: Step, i: number): boolean {
|
|
34
|
+
if (!props.completed) return i < currentIndex.value
|
|
35
|
+
return props.completed.includes(i) || (!!step.key && props.completed.includes(step.key))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function isCurrent(i: number): boolean {
|
|
39
|
+
return i === currentIndex.value
|
|
40
|
+
}
|
|
9
41
|
</script>
|
|
10
42
|
|
|
11
43
|
<template>
|
|
12
44
|
<ol class="flex items-center gap-2">
|
|
13
45
|
<li
|
|
14
46
|
v-for="(step, i) in steps"
|
|
15
|
-
:key="i"
|
|
47
|
+
:key="step.key ?? i"
|
|
16
48
|
class="flex flex-1 items-center gap-2 last:flex-none"
|
|
17
|
-
:aria-current="i
|
|
49
|
+
:aria-current="isCurrent(i) ? 'step' : undefined"
|
|
18
50
|
>
|
|
19
51
|
<div class="flex items-center gap-2">
|
|
20
52
|
<span
|
|
21
53
|
class="flex size-7 shrink-0 items-center justify-center rounded-pill border text-xs font-semibold transition-colors"
|
|
22
|
-
:class="i
|
|
54
|
+
:class="isCompleted(step, i)
|
|
23
55
|
? 'border-transparent bg-brand text-ink-inverse'
|
|
24
|
-
: i
|
|
56
|
+
: isCurrent(i)
|
|
25
57
|
? 'border-brand text-brand'
|
|
26
58
|
: 'border-line text-muted'"
|
|
27
59
|
>
|
|
28
|
-
<LpIcon v-if="i
|
|
60
|
+
<LpIcon v-if="isCompleted(step, i)" name="lucide:check" :size="14" />
|
|
61
|
+
<LpIcon v-else-if="step.icon" :name="step.icon" :size="14" />
|
|
29
62
|
<template v-else>{{ i + 1 }}</template>
|
|
30
63
|
</span>
|
|
31
|
-
<span
|
|
64
|
+
<span
|
|
65
|
+
class="text-sm"
|
|
66
|
+
:class="isCompleted(step, i) || isCurrent(i) ? 'text-ink' : 'text-muted'"
|
|
67
|
+
>
|
|
32
68
|
{{ step.label }}
|
|
33
69
|
<!-- Status for screen readers; the colour/check are visual only. -->
|
|
34
70
|
<span class="sr-only">{{
|
|
35
|
-
|
|
71
|
+
isCompleted(step, i)
|
|
72
|
+
? "(completed)"
|
|
73
|
+
: isCurrent(i)
|
|
74
|
+
? "(current step)"
|
|
75
|
+
: ""
|
|
36
76
|
}}</span>
|
|
37
77
|
</span>
|
|
38
78
|
</div>
|
|
39
79
|
<span
|
|
40
80
|
v-if="i < steps.length - 1"
|
|
41
81
|
class="h-px flex-1"
|
|
42
|
-
:class="i
|
|
82
|
+
:class="isCompleted(step, i) ? 'bg-brand' : 'bg-line'"
|
|
43
83
|
/>
|
|
44
84
|
</li>
|
|
45
85
|
</ol>
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { defineComponent, openBlock, createElementBlock, Fragment, renderList, createBlock, createCommentVNode, toDisplayString, normalizeClass } from "vue";
|
|
2
|
-
import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
|
|
3
|
-
const _hoisted_1 = {
|
|
4
|
-
class: "flex items-center gap-1.5 text-sm",
|
|
5
|
-
"aria-label": "Breadcrumb"
|
|
6
|
-
};
|
|
7
|
-
const _hoisted_2 = ["href", "onClick"];
|
|
8
|
-
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
9
|
-
__name: "LpBreadcrumbs",
|
|
10
|
-
props: {
|
|
11
|
-
items: {}
|
|
12
|
-
},
|
|
13
|
-
emits: ["navigate"],
|
|
14
|
-
setup(__props) {
|
|
15
|
-
return (_ctx, _cache) => {
|
|
16
|
-
return openBlock(), createElementBlock("nav", _hoisted_1, [
|
|
17
|
-
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item, i) => {
|
|
18
|
-
return openBlock(), createElementBlock(Fragment, { key: i }, [
|
|
19
|
-
i > 0 ? (openBlock(), createBlock(_sfc_main$1, {
|
|
20
|
-
key: 0,
|
|
21
|
-
name: "lucide:chevron-right",
|
|
22
|
-
size: 14,
|
|
23
|
-
class: "text-muted"
|
|
24
|
-
})) : createCommentVNode("", true),
|
|
25
|
-
item.href && i < __props.items.length - 1 ? (openBlock(), createElementBlock("a", {
|
|
26
|
-
key: 1,
|
|
27
|
-
href: item.href,
|
|
28
|
-
class: "rounded-xs text-muted outline-none transition-colors duration-[var(--duration-fast)] hover:text-ink focus-visible:ring-2 focus-visible:ring-ring",
|
|
29
|
-
onClick: ($event) => _ctx.$emit("navigate", item, i)
|
|
30
|
-
}, toDisplayString(item.label), 9, _hoisted_2)) : (openBlock(), createElementBlock("span", {
|
|
31
|
-
key: 2,
|
|
32
|
-
class: normalizeClass(i === __props.items.length - 1 ? "text-ink" : "text-muted")
|
|
33
|
-
}, toDisplayString(item.label), 3))
|
|
34
|
-
], 64);
|
|
35
|
-
}), 128))
|
|
36
|
-
]);
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
export {
|
|
41
|
-
_sfc_main as _
|
|
42
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { defineComponent, openBlock, createElementBlock, createVNode, createCommentVNode, createElementVNode, toDisplayString, renderSlot } from "vue";
|
|
2
|
-
import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
|
|
3
|
-
const _hoisted_1 = { class: "flex flex-col items-center gap-3 px-6 py-12 text-center" };
|
|
4
|
-
const _hoisted_2 = {
|
|
5
|
-
key: 0,
|
|
6
|
-
class: "flex size-12 items-center justify-center rounded-pill bg-surface-soft text-muted"
|
|
7
|
-
};
|
|
8
|
-
const _hoisted_3 = { class: "flex flex-col gap-1" };
|
|
9
|
-
const _hoisted_4 = { class: "font-semibold text-ink" };
|
|
10
|
-
const _hoisted_5 = {
|
|
11
|
-
key: 0,
|
|
12
|
-
class: "max-w-sm text-sm text-muted"
|
|
13
|
-
};
|
|
14
|
-
const _hoisted_6 = {
|
|
15
|
-
key: 1,
|
|
16
|
-
class: "mt-1"
|
|
17
|
-
};
|
|
18
|
-
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
19
|
-
__name: "LpEmptyState",
|
|
20
|
-
props: {
|
|
21
|
-
icon: {},
|
|
22
|
-
title: {},
|
|
23
|
-
description: {}
|
|
24
|
-
},
|
|
25
|
-
setup(__props) {
|
|
26
|
-
return (_ctx, _cache) => {
|
|
27
|
-
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
28
|
-
__props.icon ? (openBlock(), createElementBlock("div", _hoisted_2, [
|
|
29
|
-
createVNode(_sfc_main$1, {
|
|
30
|
-
name: __props.icon,
|
|
31
|
-
size: 22
|
|
32
|
-
}, null, 8, ["name"])
|
|
33
|
-
])) : createCommentVNode("", true),
|
|
34
|
-
createElementVNode("div", _hoisted_3, [
|
|
35
|
-
createElementVNode("p", _hoisted_4, toDisplayString(__props.title), 1),
|
|
36
|
-
__props.description ? (openBlock(), createElementBlock("p", _hoisted_5, toDisplayString(__props.description), 1)) : createCommentVNode("", true)
|
|
37
|
-
]),
|
|
38
|
-
_ctx.$slots.default ? (openBlock(), createElementBlock("div", _hoisted_6, [
|
|
39
|
-
renderSlot(_ctx.$slots, "default")
|
|
40
|
-
])) : createCommentVNode("", true)
|
|
41
|
-
]);
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
export {
|
|
46
|
-
_sfc_main as _
|
|
47
|
-
};
|