@j-solution/components 1.6.1 → 1.8.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.
- package/README.md +8 -6
- package/assets/jwms-portal-frontend-BtHTA-UF.css +1 -0
- package/assets/styles/global-utilities.css +34 -0
- package/assets/styles/j-components.css +1 -1
- package/assets/styles/themes.css +128 -21
- package/components/atoms/JAvatar.vue.cjs +1 -1
- package/components/atoms/JAvatar.vue.cjs.map +1 -1
- package/components/atoms/JAvatar.vue.js +10 -7
- package/components/atoms/JAvatar.vue.js.map +1 -1
- package/components/atoms/JBadge.vue.cjs +1 -1
- package/components/atoms/JBadge.vue.cjs.map +1 -1
- package/components/atoms/JBadge.vue.js +7 -6
- package/components/atoms/JBadge.vue.js.map +1 -1
- package/components/atoms/JButton.vue.cjs +6 -1
- package/components/atoms/JButton.vue.cjs.map +1 -1
- package/components/atoms/JButton.vue.js +10 -85
- package/components/atoms/JButton.vue.js.map +1 -1
- package/components/atoms/JButton.vue2.cjs +1 -1
- package/components/atoms/JButton.vue2.cjs.map +1 -1
- package/components/atoms/JButton.vue2.js +85 -2
- package/components/atoms/JButton.vue2.js.map +1 -1
- package/components/atoms/JDatepicker.vue.cjs +1 -1
- package/components/atoms/JDatepicker.vue.cjs.map +1 -1
- package/components/atoms/JDatepicker.vue.js +10 -10
- package/components/atoms/JDatepicker.vue.js.map +1 -1
- package/components/atoms/JEditor.vue.cjs +1 -1
- package/components/atoms/JEditor.vue.js +1 -1
- package/components/atoms/JEditor.vue2.cjs +1 -1
- package/components/atoms/JEditor.vue2.cjs.map +1 -1
- package/components/atoms/JEditor.vue2.js +31 -17
- package/components/atoms/JEditor.vue2.js.map +1 -1
- package/components/atoms/JGrid.vue.cjs +1 -1
- package/components/atoms/JGrid.vue.js +2 -2
- package/components/atoms/JGrid.vue2.cjs +1 -1
- package/components/atoms/JGrid.vue2.cjs.map +1 -1
- package/components/atoms/JGrid.vue2.js +59 -43
- package/components/atoms/JGrid.vue2.js.map +1 -1
- package/components/atoms/JIcon.vue.cjs +1 -1
- package/components/atoms/JIcon.vue.cjs.map +1 -1
- package/components/atoms/JIcon.vue.js +14 -13
- package/components/atoms/JIcon.vue.js.map +1 -1
- package/components/atoms/JKbd.vue.cjs +1 -1
- package/components/atoms/JKbd.vue.cjs.map +1 -1
- package/components/atoms/JKbd.vue.js +13 -10
- package/components/atoms/JKbd.vue.js.map +1 -1
- package/components/atoms/JLabel.vue.cjs +1 -1
- package/components/atoms/JLabel.vue.cjs.map +1 -1
- package/components/atoms/JLabel.vue.js +26 -22
- package/components/atoms/JLabel.vue.js.map +1 -1
- package/components/atoms/JLink.vue.cjs +1 -1
- package/components/atoms/JLink.vue.cjs.map +1 -1
- package/components/atoms/JLink.vue.js +5 -5
- package/components/atoms/JLink.vue.js.map +1 -1
- package/components/atoms/JPreview.vue.cjs +1 -1
- package/components/atoms/JPreview.vue.js +2 -2
- package/components/atoms/JPreview.vue2.cjs +1 -1
- package/components/atoms/JPreview.vue2.cjs.map +1 -1
- package/components/atoms/JPreview.vue2.js +33 -20
- package/components/atoms/JPreview.vue2.js.map +1 -1
- package/components/atoms/JProgress.vue.cjs +1 -1
- package/components/atoms/JProgress.vue.cjs.map +1 -1
- package/components/atoms/JProgress.vue.js +15 -9
- package/components/atoms/JProgress.vue.js.map +1 -1
- package/components/atoms/JRadio.vue.cjs +1 -1
- package/components/atoms/JRadio.vue.cjs.map +1 -1
- package/components/atoms/JRadio.vue.js +1 -1
- package/components/atoms/JRadio.vue.js.map +1 -1
- package/components/atoms/JSearchCombo.vue.cjs +1 -1
- package/components/atoms/JSearchCombo.vue.cjs.map +1 -1
- package/components/atoms/JSearchCombo.vue.js +38 -37
- package/components/atoms/JSearchCombo.vue.js.map +1 -1
- package/components/atoms/JSectionTitle.vue.cjs +7 -0
- package/components/atoms/JSectionTitle.vue.cjs.map +1 -0
- package/components/atoms/JSectionTitle.vue.js +13 -0
- package/components/atoms/JSectionTitle.vue.js.map +1 -0
- package/components/atoms/JSectionTitle.vue2.cjs +2 -0
- package/components/atoms/JSectionTitle.vue2.cjs.map +1 -0
- package/components/atoms/JSectionTitle.vue2.js +67 -0
- package/components/atoms/JSectionTitle.vue2.js.map +1 -0
- package/components/atoms/JSpinner.vue.cjs +1 -1
- package/components/atoms/JSpinner.vue.cjs.map +1 -1
- package/components/atoms/JSpinner.vue.js +8 -7
- package/components/atoms/JSpinner.vue.js.map +1 -1
- package/components/atoms/JSplitter.vue.cjs +6 -1
- package/components/atoms/JSplitter.vue.cjs.map +1 -1
- package/components/atoms/JSplitter.vue.js +10 -54
- package/components/atoms/JSplitter.vue.js.map +1 -1
- package/components/atoms/JSplitter.vue2.cjs +1 -1
- package/components/atoms/JSplitter.vue2.cjs.map +1 -1
- package/components/atoms/JSplitter.vue2.js +59 -2
- package/components/atoms/JSplitter.vue2.js.map +1 -1
- package/components/atoms/JTooltip.vue.cjs +1 -1
- package/components/atoms/JTooltip.vue.cjs.map +1 -1
- package/components/atoms/JTooltip.vue.js +18 -15
- package/components/atoms/JTooltip.vue.js.map +1 -1
- package/components/examples/ExampleCrudPage.vue.cjs +1 -1
- package/components/examples/ExampleCrudPage.vue.cjs.map +1 -1
- package/components/examples/ExampleCrudPage.vue.js +265 -191
- package/components/examples/ExampleCrudPage.vue.js.map +1 -1
- package/components/examples/ExampleTabMappingPage.vue.cjs +1 -1
- package/components/examples/ExampleTabMappingPage.vue.cjs.map +1 -1
- package/components/examples/ExampleTabMappingPage.vue.js +349 -333
- package/components/examples/ExampleTabMappingPage.vue.js.map +1 -1
- package/components/molecules/JAlert.vue.cjs +1 -1
- package/components/molecules/JAlert.vue.cjs.map +1 -1
- package/components/molecules/JAlert.vue.js +18 -16
- package/components/molecules/JAlert.vue.js.map +1 -1
- package/components/molecules/JBreadcrumb.vue.cjs +1 -1
- package/components/molecules/JBreadcrumb.vue.cjs.map +1 -1
- package/components/molecules/JBreadcrumb.vue.js +3 -3
- package/components/molecules/JBreadcrumb.vue.js.map +1 -1
- package/components/molecules/JCard.vue.cjs +1 -1
- package/components/molecules/JCard.vue.cjs.map +1 -1
- package/components/molecules/JCard.vue.js +55 -39
- package/components/molecules/JCard.vue.js.map +1 -1
- package/components/molecules/JEmptyState.vue.cjs +7 -0
- package/components/molecules/JEmptyState.vue.cjs.map +1 -0
- package/components/molecules/JEmptyState.vue.js +13 -0
- package/components/molecules/JEmptyState.vue.js.map +1 -0
- package/components/molecules/JEmptyState.vue2.cjs +2 -0
- package/components/molecules/JEmptyState.vue2.cjs.map +1 -0
- package/components/molecules/JEmptyState.vue2.js +127 -0
- package/components/molecules/JEmptyState.vue2.js.map +1 -0
- package/components/molecules/JFormField.vue.cjs +6 -1
- package/components/molecules/JFormField.vue.cjs.map +1 -1
- package/components/molecules/JFormField.vue.js +10 -262
- package/components/molecules/JFormField.vue.js.map +1 -1
- package/components/molecules/JFormField.vue2.cjs +2 -0
- package/components/molecules/JFormField.vue2.cjs.map +1 -0
- package/components/molecules/JFormField.vue2.js +271 -0
- package/components/molecules/JFormField.vue2.js.map +1 -0
- package/components/molecules/JTabs.vue.cjs +1 -1
- package/components/molecules/JTabs.vue.js +1 -1
- package/components/molecules/JTabs.vue2.cjs +1 -1
- package/components/molecules/JTabs.vue2.cjs.map +1 -1
- package/components/molecules/JTabs.vue2.js +50 -56
- package/components/molecules/JTabs.vue2.js.map +1 -1
- package/components/molecules/JTitlebar.vue.cjs +1 -1
- package/components/molecules/JTitlebar.vue.cjs.map +1 -1
- package/components/molecules/JTitlebar.vue.js +49 -47
- package/components/molecules/JTitlebar.vue.js.map +1 -1
- package/components/organisms/JDynamicForm.vue2.cjs +1 -1
- package/components/organisms/JDynamicForm.vue2.cjs.map +1 -1
- package/components/organisms/JDynamicForm.vue2.js +35 -32
- package/components/organisms/JDynamicForm.vue2.js.map +1 -1
- package/components/organisms/JDynamicTabs.vue.cjs +1 -1
- package/components/organisms/JDynamicTabs.vue.cjs.map +1 -1
- package/components/organisms/JDynamicTabs.vue.js +47 -52
- package/components/organisms/JDynamicTabs.vue.js.map +1 -1
- package/components/organisms/JFilterBar.vue.cjs +6 -1
- package/components/organisms/JFilterBar.vue.cjs.map +1 -1
- package/components/organisms/JFilterBar.vue.js +10 -137
- package/components/organisms/JFilterBar.vue.js.map +1 -1
- package/components/organisms/JFilterBar.vue2.cjs +1 -1
- package/components/organisms/JFilterBar.vue2.cjs.map +1 -1
- package/components/organisms/JFilterBar.vue2.js +141 -2
- package/components/organisms/JFilterBar.vue2.js.map +1 -1
- package/components/organisms/JFormModal.vue.cjs +1 -1
- package/components/organisms/JFormModal.vue.cjs.map +1 -1
- package/components/organisms/JFormModal.vue.js +54 -49
- package/components/organisms/JFormModal.vue.js.map +1 -1
- package/components/organisms/JHeader.vue.cjs +1 -1
- package/components/organisms/JHeader.vue.cjs.map +1 -1
- package/components/organisms/JHeader.vue.js +211 -208
- package/components/organisms/JHeader.vue.js.map +1 -1
- package/components/organisms/JModal.vue.cjs +1 -1
- package/components/organisms/JModal.vue.cjs.map +1 -1
- package/components/organisms/JModal.vue.js +31 -26
- package/components/organisms/JModal.vue.js.map +1 -1
- package/components/organisms/JPageContainer.vue.cjs +1 -1
- package/components/organisms/JPageContainer.vue.cjs.map +1 -1
- package/components/organisms/JPageContainer.vue.js +22 -22
- package/components/organisms/JPageContainer.vue.js.map +1 -1
- package/components/organisms/JSearchPanel.vue2.cjs +1 -1
- package/components/organisms/JSearchPanel.vue2.cjs.map +1 -1
- package/components/organisms/JSearchPanel.vue2.js +34 -32
- package/components/organisms/JSearchPanel.vue2.js.map +1 -1
- package/components/organisms/JShuttle.vue.cjs +7 -0
- package/components/organisms/JShuttle.vue.cjs.map +1 -0
- package/components/organisms/JShuttle.vue.js +13 -0
- package/components/organisms/JShuttle.vue.js.map +1 -0
- package/components/organisms/JShuttle.vue2.cjs +2 -0
- package/components/organisms/JShuttle.vue2.cjs.map +1 -0
- package/components/organisms/JShuttle.vue2.js +216 -0
- package/components/organisms/JShuttle.vue2.js.map +1 -0
- package/components/organisms/JSidebarAdvanced.vue.cjs +1 -1
- package/components/organisms/JSidebarAdvanced.vue.js +7 -7
- package/components/organisms/JSidebarAdvanced.vue2.cjs +1 -1
- package/components/organisms/JSidebarAdvanced.vue2.cjs.map +1 -1
- package/components/organisms/JSidebarAdvanced.vue2.js +40 -40
- package/components/organisms/JSidebarAdvanced.vue2.js.map +1 -1
- package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.cjs +1 -1
- package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.cjs.map +1 -1
- package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.js +83 -63
- package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.js.map +1 -1
- package/components/organisms/JSidebarSimple.vue.cjs +1 -1
- package/components/organisms/JSidebarSimple.vue.js +2 -2
- package/components/organisms/JSidebarSimple.vue2.cjs +1 -1
- package/components/organisms/JSidebarSimple.vue2.cjs.map +1 -1
- package/components/organisms/JSidebarSimple.vue2.js +2 -2
- package/components/organisms/JSidebarSimple.vue2.js.map +1 -1
- package/components/shadcn/AccordionTrigger.vue.cjs +1 -1
- package/components/shadcn/AccordionTrigger.vue.cjs.map +1 -1
- package/components/shadcn/AccordionTrigger.vue.js +3 -3
- package/components/shadcn/AccordionTrigger.vue.js.map +1 -1
- package/components/shadcn/Card.vue.cjs +1 -1
- package/components/shadcn/Card.vue.cjs.map +1 -1
- package/components/shadcn/Card.vue.js +1 -1
- package/components/shadcn/Card.vue.js.map +1 -1
- package/components/shadcn/CardContent.vue.cjs +1 -1
- package/components/shadcn/CardContent.vue.cjs.map +1 -1
- package/components/shadcn/CardContent.vue.js +4 -4
- package/components/shadcn/CardContent.vue.js.map +1 -1
- package/components/shadcn/CardDescription.vue.cjs +1 -1
- package/components/shadcn/CardDescription.vue.cjs.map +1 -1
- package/components/shadcn/CardDescription.vue.js +1 -1
- package/components/shadcn/CardDescription.vue.js.map +1 -1
- package/components/shadcn/CardFooter.vue.cjs +1 -1
- package/components/shadcn/CardFooter.vue.cjs.map +1 -1
- package/components/shadcn/CardFooter.vue.js +7 -7
- package/components/shadcn/CardFooter.vue.js.map +1 -1
- package/components/shadcn/CardHeader.vue.cjs +1 -1
- package/components/shadcn/CardHeader.vue.cjs.map +1 -1
- package/components/shadcn/CardHeader.vue.js +8 -8
- package/components/shadcn/CardHeader.vue.js.map +1 -1
- package/components/shadcn/CardTitle.vue.cjs +1 -1
- package/components/shadcn/CardTitle.vue.cjs.map +1 -1
- package/components/shadcn/CardTitle.vue.js +5 -5
- package/components/shadcn/CardTitle.vue.js.map +1 -1
- package/components/shadcn/Input.vue.cjs +1 -1
- package/components/shadcn/Input.vue.cjs.map +1 -1
- package/components/shadcn/Input.vue.js +3 -3
- package/components/shadcn/Input.vue.js.map +1 -1
- package/components/shadcn/SelectTrigger.vue.cjs +1 -1
- package/components/shadcn/SelectTrigger.vue.cjs.map +1 -1
- package/components/shadcn/SelectTrigger.vue.js +2 -2
- package/components/shadcn/SelectTrigger.vue.js.map +1 -1
- package/components/shadcn/Switch.vue.cjs +1 -1
- package/components/shadcn/Switch.vue.cjs.map +1 -1
- package/components/shadcn/Switch.vue.js +2 -2
- package/components/shadcn/Switch.vue.js.map +1 -1
- package/components/shadcn/TabsContent.vue.cjs +1 -1
- package/components/shadcn/TabsContent.vue.cjs.map +1 -1
- package/components/shadcn/TabsContent.vue.js +1 -1
- package/components/shadcn/TabsContent.vue.js.map +1 -1
- package/components/shadcn/TabsList.vue.cjs +1 -1
- package/components/shadcn/TabsList.vue.cjs.map +1 -1
- package/components/shadcn/TabsList.vue.js +10 -10
- package/components/shadcn/TabsList.vue.js.map +1 -1
- package/components/shadcn/TabsTrigger.vue.cjs +1 -1
- package/components/shadcn/TabsTrigger.vue.cjs.map +1 -1
- package/components/shadcn/TabsTrigger.vue.js +4 -4
- package/components/shadcn/TabsTrigger.vue.js.map +1 -1
- package/components/shadcn/Textarea.vue.cjs +1 -1
- package/components/shadcn/Textarea.vue.cjs.map +1 -1
- package/components/shadcn/Textarea.vue.js +2 -2
- package/components/shadcn/Textarea.vue.js.map +1 -1
- package/components/shadcn/index.cjs +1 -1
- package/components/shadcn/index.cjs.map +1 -1
- package/components/shadcn/index.js +9 -8
- package/components/shadcn/index.js.map +1 -1
- package/components/templates/JLayout.vue.cjs.map +1 -1
- package/components/templates/JLayout.vue.js.map +1 -1
- package/index.cjs +1 -1
- package/index.js +73 -67
- package/package.json +1 -1
- package/types/index.d.ts +1025 -766
- package/assets/jwms-portal-frontend-DntSIcYt.css +0 -1
- package/components/molecules/JFormField.vue3.cjs +0 -2
- package/components/molecules/JFormField.vue3.cjs.map +0 -1
- package/components/molecules/JFormField.vue3.js +0 -6
- package/components/molecules/JFormField.vue3.js.map +0 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
import { useRouter as
|
|
3
|
-
import
|
|
4
|
-
import { hasMenuPermission as
|
|
5
|
-
const
|
|
1
|
+
import { defineComponent as P, computed as n, resolveComponent as I, createElementBlock as m, openBlock as l, normalizeClass as u, unref as v, createElementVNode as F, createCommentVNode as y, normalizeStyle as B, createBlock as C, toDisplayString as z, withModifiers as L, createVNode as R, Fragment as J, renderList as V } from "vue";
|
|
2
|
+
import { useRouter as $ } from "vue-router";
|
|
3
|
+
import b from "../../atoms/JIcon.vue.js";
|
|
4
|
+
import { hasMenuPermission as Y, cn as f } from "../../../lib/utils.js";
|
|
5
|
+
const j = {
|
|
6
6
|
key: 1,
|
|
7
7
|
class: "w-4 flex-shrink-0"
|
|
8
|
-
},
|
|
8
|
+
}, q = {
|
|
9
9
|
key: 0,
|
|
10
|
-
class: "
|
|
11
|
-
},
|
|
10
|
+
class: "border-l border-border/60 ml-[14px] pl-[6px]"
|
|
11
|
+
}, U = /* @__PURE__ */ P({
|
|
12
12
|
__name: "JDynamicMenuItem",
|
|
13
13
|
props: {
|
|
14
14
|
item: {},
|
|
@@ -26,96 +26,116 @@ const Y = {
|
|
|
26
26
|
activeKey: { default: null }
|
|
27
27
|
},
|
|
28
28
|
emits: ["menuClick", "expandChange"],
|
|
29
|
-
setup(e, { emit:
|
|
30
|
-
const t = e,
|
|
31
|
-
if (!
|
|
32
|
-
const
|
|
33
|
-
return t.expandedKeys?.has(
|
|
34
|
-
}),
|
|
35
|
-
if (
|
|
36
|
-
|
|
29
|
+
setup(e, { emit: S }) {
|
|
30
|
+
const t = e, c = S, w = $(), D = n(() => Y(t.item.menuKey, t.permissions)), h = n(() => t.activeKey !== void 0 && t.activeKey !== null ? t.item.menuKey === t.activeKey : !t.item.path || !t.activePath ? !1 : t.activePath === t.item.path), r = n(() => t.item.menuType === "F" || Array.isArray(t.item.children) && t.item.children.length > 0), x = n(() => {
|
|
31
|
+
if (!r.value) return !1;
|
|
32
|
+
const a = t.item.menuKey || t.item.label;
|
|
33
|
+
return t.expandedKeys?.has(a) ?? !1;
|
|
34
|
+
}), g = n(() => t.item.disabled || !D.value), A = n(() => ({ paddingLeft: "8px", paddingRight: "8px" })), E = (a) => {
|
|
35
|
+
if (g.value) {
|
|
36
|
+
a.preventDefault();
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
|
-
if (
|
|
40
|
-
const i = t.item.menuKey || t.item.label,
|
|
41
|
-
|
|
39
|
+
if (r.value) {
|
|
40
|
+
const i = t.item.menuKey || t.item.label, o = !x.value;
|
|
41
|
+
c("expandChange", i, o), c("menuClick", {
|
|
42
42
|
menuItem: t.item,
|
|
43
43
|
path: [t.item],
|
|
44
|
-
event:
|
|
44
|
+
event: a
|
|
45
45
|
});
|
|
46
46
|
} else
|
|
47
|
-
!t.disableNavigation && t.item.path &&
|
|
47
|
+
!t.disableNavigation && t.item.path && w.push(t.item.path), c("menuClick", {
|
|
48
48
|
menuItem: t.item,
|
|
49
49
|
path: [t.item],
|
|
50
50
|
// 단순화된 경로 (필요시 부모 경로 포함하도록 확장 가능)
|
|
51
|
-
event:
|
|
51
|
+
event: a
|
|
52
52
|
});
|
|
53
|
-
},
|
|
53
|
+
}, p = {
|
|
54
54
|
default: {
|
|
55
|
-
itemClass: "flex items-center gap-
|
|
56
|
-
labelClass: "flex-1 truncate",
|
|
55
|
+
itemClass: "flex items-center gap-1.5 py-1 rounded-md cursor-pointer transition-colors group",
|
|
56
|
+
labelClass: "flex-1 truncate text-xs",
|
|
57
57
|
iconSize: "sm"
|
|
58
58
|
},
|
|
59
59
|
minimal: {
|
|
60
|
-
itemClass: "flex items-center gap-1
|
|
60
|
+
itemClass: "flex items-center gap-1 py-1 rounded-md cursor-pointer transition-colors group",
|
|
61
61
|
labelClass: "flex-1 truncate text-xs",
|
|
62
62
|
iconSize: "sm"
|
|
63
63
|
// JIcon은 'xs'를 지원하지 않으므로 'sm' 사용
|
|
64
64
|
}
|
|
65
|
-
},
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
}, d = n(() => p[t.styletype] ?? p.default), N = n(() => x.value ? "chevronDown" : "chevronRight"), K = n(() => {
|
|
66
|
+
if (!r.value || !Array.isArray(t.item.children))
|
|
67
|
+
return 0;
|
|
68
|
+
const a = (i) => {
|
|
69
|
+
let o = 0;
|
|
70
|
+
for (const s of i)
|
|
71
|
+
o++, Array.isArray(s.children) && s.children.length > 0 && (o += a(s.children));
|
|
72
|
+
return o;
|
|
73
|
+
};
|
|
74
|
+
return a(t.item.children);
|
|
75
|
+
});
|
|
76
|
+
return (a, i) => {
|
|
77
|
+
const o = I("JDynamicMenuItem", !0);
|
|
78
|
+
return l(), m("div", {
|
|
79
|
+
class: u(v(f)("w-full", e.className))
|
|
70
80
|
}, [
|
|
71
81
|
F("div", {
|
|
72
|
-
class: u(
|
|
73
|
-
|
|
82
|
+
class: u(v(f)(
|
|
83
|
+
d.value.itemClass,
|
|
74
84
|
{
|
|
75
|
-
"bg-
|
|
76
|
-
"hover:bg-accent/50": !
|
|
77
|
-
"opacity-50 cursor-not-allowed":
|
|
78
|
-
"font-medium":
|
|
85
|
+
"bg-primary/5 text-primary border-l-2 border-primary shadow-sm": h.value,
|
|
86
|
+
"hover:bg-accent/50": !g.value && !h.value,
|
|
87
|
+
"opacity-50 cursor-not-allowed": g.value,
|
|
88
|
+
"font-medium": h.value,
|
|
89
|
+
"font-semibold": r.value
|
|
90
|
+
// 폴더인 경우 볼드체
|
|
79
91
|
}
|
|
80
92
|
)),
|
|
81
|
-
style:
|
|
82
|
-
onClick:
|
|
93
|
+
style: B(A.value),
|
|
94
|
+
onClick: E
|
|
83
95
|
}, [
|
|
84
|
-
|
|
96
|
+
r.value ? (l(), C(b, {
|
|
85
97
|
key: 0,
|
|
86
|
-
name:
|
|
87
|
-
size:
|
|
88
|
-
class: "flex-shrink-0"
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
name: N.value,
|
|
99
|
+
size: d.value.iconSize,
|
|
100
|
+
class: "flex-shrink-0 opacity-60",
|
|
101
|
+
style: { "stroke-width": "1.5" }
|
|
102
|
+
}, null, 8, ["name", "size"])) : (l(), m("span", j)),
|
|
103
|
+
e.item.icon && !r.value ? (l(), C(b, {
|
|
91
104
|
key: 2,
|
|
92
105
|
name: e.item.icon,
|
|
93
|
-
size:
|
|
106
|
+
size: d.value.iconSize,
|
|
94
107
|
class: "flex-shrink-0"
|
|
95
|
-
}, null, 8, ["name", "size"])) :
|
|
108
|
+
}, null, 8, ["name", "size"])) : y("", !0),
|
|
96
109
|
F("span", {
|
|
97
|
-
class: u(
|
|
98
|
-
},
|
|
99
|
-
|
|
110
|
+
class: u(d.value.labelClass)
|
|
111
|
+
}, z(e.item.label), 3),
|
|
112
|
+
r.value && K.value > 0 ? (l(), m("span", {
|
|
100
113
|
key: 3,
|
|
101
|
-
class: u(
|
|
114
|
+
class: u(v(f)(
|
|
115
|
+
"text-muted-foreground ml-1 flex-shrink-0",
|
|
116
|
+
t.styletype === "minimal" ? "text-[10px]" : "text-xs"
|
|
117
|
+
))
|
|
118
|
+
}, " (" + z(K.value) + ") ", 3)) : y("", !0),
|
|
119
|
+
e.item.menuKey && e.item.menuType === "L" && e.onFavoriteToggle ? (l(), m("button", {
|
|
120
|
+
key: 4,
|
|
121
|
+
class: u(v(f)(
|
|
102
122
|
"opacity-0 group-hover:opacity-100 transition-opacity hover:bg-accent rounded flex-shrink-0",
|
|
103
123
|
t.styletype === "minimal" ? "p-0.5" : "p-1",
|
|
104
124
|
e.isFavorite && e.isFavorite(e.item.menuKey) && "opacity-100"
|
|
105
125
|
)),
|
|
106
|
-
onClick: i[0] || (i[0] =
|
|
126
|
+
onClick: i[0] || (i[0] = L((s) => e.onFavoriteToggle(e.item.menuKey), ["stop"]))
|
|
107
127
|
}, [
|
|
108
|
-
|
|
128
|
+
R(b, {
|
|
109
129
|
name: (e.isFavorite && e.isFavorite(e.item.menuKey), "star"),
|
|
110
|
-
size:
|
|
130
|
+
size: d.value.iconSize,
|
|
111
131
|
class: u(e.isFavorite && e.isFavorite(e.item.menuKey) ? "text-yellow-500 fill-yellow-500" : "text-muted-foreground")
|
|
112
132
|
}, null, 8, ["name", "size", "class"])
|
|
113
|
-
], 2)) :
|
|
133
|
+
], 2)) : y("", !0)
|
|
114
134
|
], 6),
|
|
115
|
-
|
|
116
|
-
(
|
|
117
|
-
key:
|
|
118
|
-
item:
|
|
135
|
+
r.value && x.value && e.item.children && Array.isArray(e.item.children) && e.item.children.length > 0 && e.level + 1 < e.maxDepth ? (l(), m("div", q, [
|
|
136
|
+
(l(!0), m(J, null, V(e.item.children, (s, T) => (l(), C(o, {
|
|
137
|
+
key: s.menuKey || s.label || T,
|
|
138
|
+
item: s,
|
|
119
139
|
level: e.level + 1,
|
|
120
140
|
"max-depth": e.maxDepth,
|
|
121
141
|
permissions: e.permissions,
|
|
@@ -127,15 +147,15 @@ const Y = {
|
|
|
127
147
|
styletype: e.styletype,
|
|
128
148
|
"disable-navigation": e.disableNavigation,
|
|
129
149
|
"active-key": e.activeKey,
|
|
130
|
-
onMenuClick: i[1] || (i[1] = (
|
|
131
|
-
onExpandChange: i[2] || (i[2] = (
|
|
150
|
+
onMenuClick: i[1] || (i[1] = (k) => c("menuClick", k)),
|
|
151
|
+
onExpandChange: i[2] || (i[2] = (k, M) => c("expandChange", k, M))
|
|
132
152
|
}, null, 8, ["item", "level", "max-depth", "permissions", "active-path", "expanded-keys", "favorites", "on-favorite-toggle", "is-favorite", "styletype", "disable-navigation", "active-key"]))), 128))
|
|
133
|
-
])) :
|
|
153
|
+
])) : y("", !0)
|
|
134
154
|
], 2);
|
|
135
155
|
};
|
|
136
156
|
}
|
|
137
157
|
});
|
|
138
158
|
export {
|
|
139
|
-
|
|
159
|
+
U as default
|
|
140
160
|
};
|
|
141
161
|
//# sourceMappingURL=JDynamicMenuItem.vue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JDynamicMenuItem.vue.js","sources":["../../../../../src/components/organisms/JSidebarSimple/JDynamicMenuItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { computed } from 'vue'\r\nimport { useRouter } from 'vue-router'\r\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\r\nimport JIcon from '@/components/atoms/JIcon.vue'\r\nimport { cn, hasMenuPermission } from '@/lib/utils'\r\n\r\n/**\r\n * JDynamicMenuItem - 재귀적 메뉴 아이템 컴포넌트\r\n * Recursive Menu Item Component\r\n * \r\n * @description\r\n * 다단계 메뉴 구조를 재귀적으로 렌더링하는 컴포넌트입니다.\r\n * 폴더 타입 메뉴는 확장/축소가 가능하고, 링크 타입 메뉴는 클릭 시 라우팅합니다.\r\n */\r\n\r\ntype StyleType = 'default' | 'minimal'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 메뉴 아이템 */\r\n item: SidebarMenuItem\r\n /** 메뉴 레벨 (들여쓰기용, 0부터 시작) */\r\n level?: number\r\n /** 권한 목록 */\r\n permissions?: MenuPermission[]\r\n /** 활성화된 메뉴 경로 */\r\n activePath?: string\r\n /** 확장된 메뉴 키 목록 */\r\n expandedKeys?: Set<number | string>\r\n /** 즐겨찾기 메뉴 키 목록 */\r\n favorites?: (number | string)[]\r\n /** 즐겨찾기 변경 핸들러 */\r\n onFavoriteToggle?: (menuKey: number | string | undefined) => void\r\n /** 즐겨찾기 확인 함수 */\r\n isFavorite?: (menuKey: number | string | undefined) => boolean\r\n /** 스타일 타입 */\r\n styletype?: StyleType\r\n /** 추가 CSS 클래스 */\r\n className?: string\r\n /** 최대 깊이 제한 (무한 루프 방지, 기본값: 10) */\r\n maxDepth?: number\r\n /** 네비게이션 비활성화 (true일 때 router.push 건너뛰고 emit만 수행) */\r\n disableNavigation?: boolean\r\n /** 활성화된 메뉴 키 (menuKey 기반 활성화, activePath보다 우선) */\r\n activeKey?: number | string | null\r\n }>(),\r\n {\r\n level: 0,\r\n permissions: () => [],\r\n expandedKeys: () => new Set(),\r\n favorites: () => [],\r\n styletype: 'default',\r\n maxDepth: 10,\r\n disableNavigation: false,\r\n activeKey: null,\r\n },\r\n)\r\n\r\nconst emit = defineEmits<{\r\n /** 메뉴 클릭 이벤트 */\r\n menuClick: [event: MenuClickEvent]\r\n /** 확장 상태 변경 이벤트 */\r\n expandChange: [menuKey: number | string | undefined, expanded: boolean]\r\n}>()\r\n\r\nconst router = useRouter()\r\n\r\n/**\r\n * 권한 체크 함수\r\n * Permission check function\r\n * hasMenuPermission 유틸리티 함수를 사용하여 일관성 유지\r\n */\r\nconst checkPermission = computed(() => {\r\n return hasMenuPermission(props.item.menuKey, props.permissions)\r\n})\r\n\r\n/**\r\n * 메뉴가 활성화되어 있는지 여부\r\n * activeKey가 제공되면 menuKey 매칭, 아니면 경로 매칭\r\n */\r\nconst isActive = computed(() => {\r\n // activeKey가 제공되면 menuKey 기반 매칭 (우선순위 높음)\r\n if (props.activeKey !== undefined && props.activeKey !== null) {\r\n return props.item.menuKey === props.activeKey\r\n }\r\n // 경로 기반 매칭 (기본 동작)\r\n if (!props.item.path || !props.activePath) return false\r\n return props.activePath === props.item.path\r\n})\r\n\r\n/**\r\n * 메뉴 타입이 폴더인지 여부\r\n * 순환 참조 방지: children이 유효한 배열인지 확인\r\n */\r\nconst isFolder = computed(() => {\r\n return props.item.menuType === 'F' || (Array.isArray(props.item.children) && props.item.children.length > 0)\r\n})\r\n\r\n/**\r\n * 메뉴가 확장되어 있는지 여부\r\n */\r\nconst isExpanded = computed(() => {\r\n if (!isFolder.value) return false\r\n const key = props.item.menuKey || props.item.label\r\n return props.expandedKeys?.has(key) ?? false\r\n})\r\n\r\n/**\r\n * 메뉴가 비활성화되어 있는지 여부\r\n */\r\nconst isDisabled = computed(() => {\r\n return props.item.disabled || !checkPermission.value\r\n})\r\n\r\n/**\r\n * 레벨별 들여쓰기 스타일\r\n * Tailwind의 표준 클래스는 제한적이므로 인라인 스타일 사용\r\n */\r\nconst indentStyle = computed(() => {\r\n const basePadding = 12 // 기본 패딩 (px)\r\n const level = props.level || 0\r\n const levelPadding = level * 16 // 레벨당 16px\r\n const totalPadding = basePadding + levelPadding\r\n return { paddingLeft: `${totalPadding}px` }\r\n})\r\n\r\n/**\r\n * 메뉴 클릭 핸들러\r\n */\r\nconst handleMenuClick = (event: MouseEvent) => {\r\n if (isDisabled.value) {\r\n event.preventDefault()\r\n return\r\n }\r\n\r\n if (isFolder.value) {\r\n // 폴더 타입: 확장/축소 토글\r\n const key = props.item.menuKey || props.item.label\r\n const newExpanded = !isExpanded.value\r\n emit('expandChange', key, newExpanded)\r\n // 폴더도 메뉴 클릭 이벤트 발생\r\n emit('menuClick', {\r\n menuItem: props.item,\r\n path: [props.item],\r\n event,\r\n })\r\n } else {\r\n // 링크 타입: 라우팅 (disableNavigation이 false일 때만)\r\n if (!props.disableNavigation && props.item.path) {\r\n router.push(props.item.path)\r\n }\r\n \r\n // 메뉴 클릭 이벤트 발생\r\n emit('menuClick', {\r\n menuItem: props.item,\r\n path: [props.item], // 단순화된 경로 (필요시 부모 경로 포함하도록 확장 가능)\r\n event,\r\n })\r\n }\r\n}\r\n\r\n/**\r\n * 스타일 프리셋\r\n */\r\nconst STYLE_PRESETS: Record<StyleType, {\r\n itemClass: string\r\n labelClass: string\r\n iconSize: 'sm' | 'md'\r\n}> = {\r\n default: {\r\n itemClass: 'flex items-center gap-2 py-2 rounded-md cursor-pointer transition-colors group',\r\n labelClass: 'flex-1 truncate',\r\n iconSize: 'sm',\r\n },\r\n minimal: {\r\n itemClass: 'flex items-center gap-1.5 py-1.5 rounded-md cursor-pointer transition-colors group',\r\n labelClass: 'flex-1 truncate text-xs',\r\n iconSize: 'sm', // JIcon은 'xs'를 지원하지 않으므로 'sm' 사용\r\n },\r\n}\r\n\r\nconst preset = computed(() => {\r\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\r\n})\r\n\r\n/**\r\n * Chevron 아이콘 컴포넌트\r\n */\r\nconst ChevronIcon = computed(() => {\r\n return isExpanded.value ? 'chevronDown' : 'chevronRight'\r\n})\r\n</script>\r\n\r\n<template>\r\n <div :class=\"cn('w-full', className)\">\r\n <!-- 메뉴 아이템 -->\r\n <div\r\n :class=\"cn(\r\n preset.itemClass,\r\n {\r\n 'bg-accent text-accent-foreground': isActive,\r\n 'hover:bg-accent/50': !isDisabled && !isActive,\r\n 'opacity-50 cursor-not-allowed': isDisabled,\r\n 'font-medium': isActive,\r\n }\r\n )\"\r\n :style=\"indentStyle\"\r\n @click=\"handleMenuClick\"\r\n >\r\n <!-- Chevron 아이콘 (폴더 타입만) -->\r\n <JIcon\r\n v-if=\"isFolder\"\r\n :name=\"ChevronIcon\"\r\n :size=\"preset.iconSize\"\r\n class=\"flex-shrink-0\"\r\n />\r\n <span v-else class=\"w-4 flex-shrink-0\" /> <!-- 폴더가 아닐 때 공간 확보 -->\r\n\r\n <!-- 메뉴 아이콘 -->\r\n <JIcon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n :size=\"preset.iconSize\"\r\n class=\"flex-shrink-0\"\r\n />\r\n\r\n <!-- 메뉴 라벨 -->\r\n <span :class=\"preset.labelClass\">{{ item.label }}</span>\r\n \r\n <!-- 즐겨찾기 버튼 (menuType이 L인 경우만) -->\r\n <button\r\n v-if=\"item.menuKey && item.menuType === 'L' && onFavoriteToggle\"\r\n :class=\"cn(\r\n 'opacity-0 group-hover:opacity-100 transition-opacity hover:bg-accent rounded flex-shrink-0',\r\n props.styletype === 'minimal' ? 'p-0.5' : 'p-1',\r\n isFavorite && isFavorite(item.menuKey) && 'opacity-100'\r\n )\"\r\n @click.stop=\"onFavoriteToggle(item.menuKey)\"\r\n >\r\n <JIcon\r\n :name=\"isFavorite && isFavorite(item.menuKey) ? 'star' : 'star'\"\r\n :size=\"preset.iconSize\"\r\n :class=\"isFavorite && isFavorite(item.menuKey) ? 'text-yellow-500 fill-yellow-500' : 'text-muted-foreground'\"\r\n />\r\n </button>\r\n </div>\r\n\r\n <!-- 하위 메뉴 (폴더 타입이고 확장된 경우) -->\r\n <!-- 깊이 제한 체크: maxDepth를 초과하지 않는 경우에만 렌더링 -->\r\n <div\r\n v-if=\"isFolder && isExpanded && item.children && Array.isArray(item.children) && item.children.length > 0 && (level + 1) < maxDepth\"\r\n class=\"w-full\"\r\n >\r\n <JDynamicMenuItem\r\n v-for=\"(child, index) in item.children\"\r\n :key=\"child.menuKey || child.label || index\"\r\n :item=\"child\"\r\n :level=\"level + 1\"\r\n :max-depth=\"maxDepth\"\r\n :permissions=\"permissions\"\r\n :active-path=\"activePath\"\r\n :expanded-keys=\"expandedKeys\"\r\n :favorites=\"favorites\"\r\n :on-favorite-toggle=\"onFavoriteToggle\"\r\n :is-favorite=\"isFavorite\"\r\n :styletype=\"styletype\"\r\n :disable-navigation=\"disableNavigation\"\r\n :active-key=\"activeKey\"\r\n @menu-click=\"emit('menuClick', $event)\"\r\n @expand-change=\"(menuKey, expanded) => emit('expandChange', menuKey, expanded)\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n"],"names":["props","__props","emit","__emit","router","useRouter","checkPermission","computed","hasMenuPermission","isActive","isFolder","isExpanded","key","isDisabled","indentStyle","handleMenuClick","event","newExpanded","STYLE_PRESETS","preset","ChevronIcon","_createElementBlock","_normalizeClass","_unref","cn","_createElementVNode","_createBlock","JIcon","_openBlock","_hoisted_1","_toDisplayString","_cache","_withModifiers","$event","_createVNode","_hoisted_2","_Fragment","child","index","_component_JDynamicMenuItem","menuKey","expanded"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"JDynamicMenuItem.vue.js","sources":["../../../../../src/components/organisms/JSidebarSimple/JDynamicMenuItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useRouter } from 'vue-router'\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\nimport JIcon from '@/components/atoms/JIcon.vue'\nimport { cn, hasMenuPermission } from '@/lib/utils'\n\n/**\n * JDynamicMenuItem - 재귀적 메뉴 아이템 컴포넌트\n * Recursive Menu Item Component\n * \n * @description\n * 다단계 메뉴 구조를 재귀적으로 렌더링하는 컴포넌트입니다.\n * 폴더 타입 메뉴는 확장/축소가 가능하고, 링크 타입 메뉴는 클릭 시 라우팅합니다.\n */\n\ntype StyleType = 'default' | 'minimal'\n\nconst props = withDefaults(\n defineProps<{\n /** 메뉴 아이템 */\n item: SidebarMenuItem\n /** 메뉴 레벨 (들여쓰기용, 0부터 시작) */\n level?: number\n /** 권한 목록 */\n permissions?: MenuPermission[]\n /** 활성화된 메뉴 경로 */\n activePath?: string\n /** 확장된 메뉴 키 목록 */\n expandedKeys?: Set<number | string>\n /** 즐겨찾기 메뉴 키 목록 */\n favorites?: (number | string)[]\n /** 즐겨찾기 변경 핸들러 */\n onFavoriteToggle?: (menuKey: number | string | undefined) => void\n /** 즐겨찾기 확인 함수 */\n isFavorite?: (menuKey: number | string | undefined) => boolean\n /** 스타일 타입 */\n styletype?: StyleType\n /** 추가 CSS 클래스 */\n className?: string\n /** 최대 깊이 제한 (무한 루프 방지, 기본값: 10) */\n maxDepth?: number\n /** 네비게이션 비활성화 (true일 때 router.push 건너뛰고 emit만 수행) */\n disableNavigation?: boolean\n /** 활성화된 메뉴 키 (menuKey 기반 활성화, activePath보다 우선) */\n activeKey?: number | string | null\n }>(),\n {\n level: 0,\n permissions: () => [],\n expandedKeys: () => new Set(),\n favorites: () => [],\n styletype: 'default',\n maxDepth: 10,\n disableNavigation: false,\n activeKey: null,\n },\n)\n\nconst emit = defineEmits<{\n /** 메뉴 클릭 이벤트 */\n menuClick: [event: MenuClickEvent]\n /** 확장 상태 변경 이벤트 */\n expandChange: [menuKey: number | string | undefined, expanded: boolean]\n}>()\n\nconst router = useRouter()\n\n/**\n * 권한 체크 함수\n * Permission check function\n * hasMenuPermission 유틸리티 함수를 사용하여 일관성 유지\n */\nconst checkPermission = computed(() => {\n return hasMenuPermission(props.item.menuKey, props.permissions)\n})\n\n/**\n * 메뉴가 활성화되어 있는지 여부\n * activeKey가 제공되면 menuKey 매칭, 아니면 경로 매칭\n */\nconst isActive = computed(() => {\n // activeKey가 제공되면 menuKey 기반 매칭 (우선순위 높음)\n if (props.activeKey !== undefined && props.activeKey !== null) {\n return props.item.menuKey === props.activeKey\n }\n // 경로 기반 매칭 (기본 동작)\n if (!props.item.path || !props.activePath) return false\n return props.activePath === props.item.path\n})\n\n/**\n * 메뉴 타입이 폴더인지 여부\n * 순환 참조 방지: children이 유효한 배열인지 확인\n */\nconst isFolder = computed(() => {\n return props.item.menuType === 'F' || (Array.isArray(props.item.children) && props.item.children.length > 0)\n})\n\n/**\n * 메뉴가 확장되어 있는지 여부\n */\nconst isExpanded = computed(() => {\n if (!isFolder.value) return false\n const key = props.item.menuKey || props.item.label\n return props.expandedKeys?.has(key) ?? false\n})\n\n/**\n * 메뉴가 비활성화되어 있는지 여부\n */\nconst isDisabled = computed(() => {\n return props.item.disabled || !checkPermission.value\n})\n\n/**\n * 레벨별 들여쓰기 스타일\n * 모든 레벨에서 동일한 padding 사용 (들여쓰기는 컨테이너의 ml로 조절)\n */\nconst indentStyle = computed(() => {\n return { paddingLeft: '8px', paddingRight: '8px' }\n})\n\n\n\n/**\n * 메뉴 클릭 핸들러\n */\nconst handleMenuClick = (event: MouseEvent) => {\n if (isDisabled.value) {\n event.preventDefault()\n return\n }\n\n if (isFolder.value) {\n // 폴더 타입: 확장/축소 토글\n const key = props.item.menuKey || props.item.label\n const newExpanded = !isExpanded.value\n emit('expandChange', key, newExpanded)\n // 폴더도 메뉴 클릭 이벤트 발생\n emit('menuClick', {\n menuItem: props.item,\n path: [props.item],\n event,\n })\n } else {\n // 링크 타입: 라우팅 (disableNavigation이 false일 때만)\n if (!props.disableNavigation && props.item.path) {\n router.push(props.item.path)\n }\n \n // 메뉴 클릭 이벤트 발생\n emit('menuClick', {\n menuItem: props.item,\n path: [props.item], // 단순화된 경로 (필요시 부모 경로 포함하도록 확장 가능)\n event,\n })\n }\n}\n\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n itemClass: string\n labelClass: string\n iconSize: 'sm' | 'md'\n}> = {\n default: {\n itemClass: 'flex items-center gap-1.5 py-1 rounded-md cursor-pointer transition-colors group',\n labelClass: 'flex-1 truncate text-xs',\n iconSize: 'sm',\n },\n minimal: {\n itemClass: 'flex items-center gap-1 py-1 rounded-md cursor-pointer transition-colors group',\n labelClass: 'flex-1 truncate text-xs',\n iconSize: 'sm', // JIcon은 'xs'를 지원하지 않으므로 'sm' 사용\n },\n}\n\nconst preset = computed(() => {\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\n})\n\n/**\n * Chevron 아이콘 컴포넌트\n */\nconst ChevronIcon = computed(() => {\n return isExpanded.value ? 'chevronDown' : 'chevronRight'\n})\n\n/**\n * 하위 메뉴 갯수 계산 (재귀적으로 모든 하위 메뉴 포함)\n * 폴더 타입인 경우에만 표시\n */\nconst childrenCount = computed(() => {\n if (!isFolder.value || !Array.isArray(props.item.children)) {\n return 0\n }\n \n const countChildren = (items: SidebarMenuItem[]): number => {\n let count = 0\n for (const item of items) {\n count++ // 현재 아이템 카운트\n if (Array.isArray(item.children) && item.children.length > 0) {\n count += countChildren(item.children) // 재귀적으로 하위 메뉴 카운트\n }\n }\n return count\n }\n \n return countChildren(props.item.children)\n})\n</script>\n\n<template>\n <div :class=\"cn('w-full', className)\">\n <!-- 메뉴 아이템 -->\n <div\n :class=\"cn(\n preset.itemClass,\n {\n 'bg-primary/5 text-primary border-l-2 border-primary shadow-sm': isActive,\n 'hover:bg-accent/50': !isDisabled && !isActive,\n 'opacity-50 cursor-not-allowed': isDisabled,\n 'font-medium': isActive,\n 'font-semibold': isFolder, // 폴더인 경우 볼드체\n }\n )\"\n :style=\"indentStyle\"\n @click=\"handleMenuClick\"\n >\n <!-- Chevron 아이콘 (폴더 타입만, 덜 굵게) -->\n <JIcon\n v-if=\"isFolder\"\n :name=\"ChevronIcon\"\n :size=\"preset.iconSize\"\n class=\"flex-shrink-0 opacity-60\"\n style=\"stroke-width: 1.5;\"\n />\n <span v-else class=\"w-4 flex-shrink-0\" /> <!-- 폴더가 아닐 때 공간 확보 -->\n\n <!-- 메뉴 아이콘 (폴더가 아닌 경우만 표시) -->\n <JIcon\n v-if=\"item.icon && !isFolder\"\n :name=\"item.icon\"\n :size=\"preset.iconSize\"\n class=\"flex-shrink-0\"\n />\n\n <!-- 메뉴 라벨 -->\n <span :class=\"preset.labelClass\">{{ item.label }}</span>\n \n <!-- 하위 메뉴 갯수 (폴더인 경우만) -->\n <span\n v-if=\"isFolder && childrenCount > 0\"\n :class=\"cn(\n 'text-muted-foreground ml-1 flex-shrink-0',\n props.styletype === 'minimal' ? 'text-[10px]' : 'text-xs'\n )\"\n >\n ({{ childrenCount }})\n </span>\n \n <!-- 즐겨찾기 버튼 (menuType이 L인 경우만) -->\n <button\n v-if=\"item.menuKey && item.menuType === 'L' && onFavoriteToggle\"\n :class=\"cn(\n 'opacity-0 group-hover:opacity-100 transition-opacity hover:bg-accent rounded flex-shrink-0',\n props.styletype === 'minimal' ? 'p-0.5' : 'p-1',\n isFavorite && isFavorite(item.menuKey) && 'opacity-100'\n )\"\n @click.stop=\"onFavoriteToggle(item.menuKey)\"\n >\n <JIcon\n :name=\"isFavorite && isFavorite(item.menuKey) ? 'star' : 'star'\"\n :size=\"preset.iconSize\"\n :class=\"isFavorite && isFavorite(item.menuKey) ? 'text-yellow-500 fill-yellow-500' : 'text-muted-foreground'\"\n />\n </button>\n </div>\n\n <!-- 하위 메뉴 (폴더 타입이고 확장된 경우) -->\n <!-- 깊이 제한 체크: maxDepth를 초과하지 않는 경우에만 렌더링 -->\n <div\n v-if=\"isFolder && isExpanded && item.children && Array.isArray(item.children) && item.children.length > 0 && (level + 1) < maxDepth\"\n class=\"border-l border-border/60 ml-[14px] pl-[6px]\"\n >\n <JDynamicMenuItem\n v-for=\"(child, index) in item.children\"\n :key=\"child.menuKey || child.label || index\"\n :item=\"child\"\n :level=\"level + 1\"\n :max-depth=\"maxDepth\"\n :permissions=\"permissions\"\n :active-path=\"activePath\"\n :expanded-keys=\"expandedKeys\"\n :favorites=\"favorites\"\n :on-favorite-toggle=\"onFavoriteToggle\"\n :is-favorite=\"isFavorite\"\n :styletype=\"styletype\"\n :disable-navigation=\"disableNavigation\"\n :active-key=\"activeKey\"\n @menu-click=\"emit('menuClick', $event)\"\n @expand-change=\"(menuKey, expanded) => emit('expandChange', menuKey, expanded)\"\n />\n </div>\n </div>\n</template>\n"],"names":["props","__props","emit","__emit","router","useRouter","checkPermission","computed","hasMenuPermission","isActive","isFolder","isExpanded","key","isDisabled","indentStyle","handleMenuClick","event","newExpanded","STYLE_PRESETS","preset","ChevronIcon","childrenCount","countChildren","items","count","item","_createElementBlock","_normalizeClass","_unref","cn","_createElementVNode","_createBlock","JIcon","_openBlock","_hoisted_1","_toDisplayString","_cache","_withModifiers","$event","_createVNode","_hoisted_2","_Fragment","child","index","_component_JDynamicMenuItem","menuKey","expanded"],"mappings":"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"}
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
for (const [t_key, t_val] of t_opts)
|
|
4
4
|
t_merged[t_key] = t_val;
|
|
5
5
|
return t_merged;
|
|
6
|
-
};,u=t(e.default,[["__scopeId","data-v-
|
|
6
|
+
};,u=t(e.default,[["__scopeId","data-v-cf0579e4"]]);exports.default=u;
|
|
7
7
|
//# sourceMappingURL=JSidebarSimple.vue.cjs.map
|
|
@@ -6,8 +6,8 @@ const r = (r_comp, r_opts) => {
|
|
|
6
6
|
r_merged[r_key] = r_val;
|
|
7
7
|
return r_merged;
|
|
8
8
|
};
|
|
9
|
-
const
|
|
9
|
+
const p = /* @__PURE__ */ r(o, [["__scopeId", "data-v-cf0579e4"]]);
|
|
10
10
|
export {
|
|
11
|
-
|
|
11
|
+
p as default
|
|
12
12
|
};
|
|
13
13
|
//# sourceMappingURL=JSidebarSimple.vue.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),b=require("vue-router"),g=require("./JSidebarSimple/JDynamicMenuItem.vue.cjs"),c=require("../../lib/utils.cjs"),d=require("../../lib/menu-utils.cjs"),E=e.defineComponent({__name:"JSidebarSimple",props:{menuItems:{},permissions:{default:()=>[]},searchQuery:{default:""},styletype:{default:"default"},class:{},width:{default:"250px"},isVisible:{type:Boolean,default:!0}},emits:["menuClick"],setup(n,{emit:m}){const s=n,p=m,y=b.useRoute(),f=e.computed(()=>y.path),r=e.ref(new Set),u=e.computed(()=>d.filterMenuItems(s.menuItems,s.searchQuery||""));e.watch(()=>u.value,t=>{if(!s.searchQuery||s.searchQuery.trim()==="")return;d.getExpandedKeysForSearch(t).forEach(a=>{r.value.add(a)})},{immediate:!1});const v=(t,l)=>{t&&(l?r.value.add(t):r.value.delete(t))},h=t=>{p("menuClick",t)},o={default:{containerClass:"h-full bg-background border-r border-border overflow-y-auto",menuPaddingClass:"p-
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),b=require("vue-router"),g=require("./JSidebarSimple/JDynamicMenuItem.vue.cjs"),c=require("../../lib/utils.cjs"),d=require("../../lib/menu-utils.cjs"),E=e.defineComponent({__name:"JSidebarSimple",props:{menuItems:{},permissions:{default:()=>[]},searchQuery:{default:""},styletype:{default:"default"},class:{},width:{default:"250px"},isVisible:{type:Boolean,default:!0}},emits:["menuClick"],setup(n,{emit:m}){const s=n,p=m,y=b.useRoute(),f=e.computed(()=>y.path),r=e.ref(new Set),u=e.computed(()=>d.filterMenuItems(s.menuItems,s.searchQuery||""));e.watch(()=>u.value,t=>{if(!s.searchQuery||s.searchQuery.trim()==="")return;d.getExpandedKeysForSearch(t).forEach(a=>{r.value.add(a)})},{immediate:!1});const v=(t,l)=>{t&&(l?r.value.add(t):r.value.delete(t))},h=t=>{p("menuClick",t)},o={default:{containerClass:"h-full bg-background border-r border-border overflow-y-auto",menuPaddingClass:"p-1.5"},minimal:{containerClass:"h-full bg-background border-r border-border overflow-y-auto",menuPaddingClass:"p-1"}},i=e.computed(()=>o[s.styletype]??o.default),k=e.computed(()=>c.cn(i.value.containerClass,s.class));return(t,l)=>(e.openBlock(),e.createBlock(e.Transition,{name:"slide"},{default:e.withCtx(()=>[e.withDirectives(e.createElementVNode("aside",{class:e.normalizeClass(k.value),style:e.normalizeStyle({width:n.width})},[e.createElementVNode("div",{class:e.normalizeClass(e.unref(c.cn)(i.value.menuPaddingClass,"space-y-0.5"))},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(u.value,(a,C)=>(e.openBlock(),e.createBlock(g.default,{key:a.menuKey||a.label||C,item:a,level:0,permissions:n.permissions,"active-path":f.value,"expanded-keys":r.value,styletype:n.styletype,onMenuClick:h,onExpandChange:v},null,8,["item","permissions","active-path","expanded-keys","styletype"]))),128))],2)],6),[[e.vShow,s.isVisible]])]),_:1}))}});exports.default=E;
|
|
2
2
|
//# sourceMappingURL=JSidebarSimple.vue2.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSidebarSimple.vue2.cjs","sources":["../../../../src/components/organisms/JSidebarSimple.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\nimport { useRoute } from 'vue-router'\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\nimport { cn } from '@/lib/utils'\nimport { filterMenuItems, getExpandedKeysForSearch } from '@/lib/menu-utils'\n\r\n/**\r\n * JSidebarSimple - 간단한 사이드바 컴포넌트\r\n * Simple Sidebar Component\r\n * \r\n * @description\r\n * 다단계 메뉴 구조를 지원하는 기본 사이드바 컴포넌트입니다.\r\n * 권한 체크, 메뉴 검색 등의 기능을 제공합니다.\r\n * \r\n * @example\r\n * ```vue\r\n * <JSidebarSimple\r\n * :menu-items=\"menuItems\"\r\n * :permissions=\"userPermissions\"\r\n * @menu-click=\"handleMenuClick\"\r\n * />\r\n * ```\r\n * \r\n * @example JSON 메뉴 데이터 예시\r\n * ```json\r\n * [\r\n * {\r\n * \"label\": \"대시보드\",\r\n * \"icon\": \"house\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 1,\r\n * \"path\": \"/dashboard\"\r\n * },\r\n * {\r\n * \"label\": \"재고 관리\",\r\n * \"icon\": \"package\",\r\n * \"menuType\": \"F\",\r\n * \"menuKey\": 2,\r\n * \"children\": [\r\n * {\r\n * \"label\": \"재고 현황\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 21,\r\n * \"path\": \"/inventory/status\"\r\n * },\r\n * {\r\n * \"label\": \"입고 관리\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 22,\r\n * \"path\": \"/inventory/receiving\"\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * ```\r\n */\r\n\r\ntype StyleType = 'default' | 'minimal'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 메뉴 아이템 목록 */\r\n menuItems: SidebarMenuItem[]\r\n /** 권한 목록 */\r\n permissions?: MenuPermission[]\r\n /** 검색어 */\r\n searchQuery?: string\r\n /** 스타일 타입 */\r\n styletype?: StyleType\r\n /** 추가 CSS 클래스 */\r\n class?: string\r\n /** 너비 */\r\n width?: string\r\n /** 표시 여부 */\r\n isVisible?: boolean\r\n }>(),\r\n {\r\n permissions: () => [],\r\n searchQuery: '',\r\n styletype: 'default',\r\n width: '250px',\r\n isVisible: true,\r\n },\r\n)\r\n\r\nconst emit = defineEmits<{\r\n /** 메뉴 클릭 이벤트 */\r\n menuClick: [event: MenuClickEvent]\r\n}>()\r\n\r\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\r\nconst route = useRoute()\r\n\r\n/**\r\n * 현재 활성화된 경로\r\n */\r\nconst activePath = computed(() => route.path)\r\n\r\n/**\r\n * 확장된 메뉴 키 목록 (Set)\r\n */\r\nconst expandedKeys = ref<Set<number | string>>(new Set())\r\n\r\n/**\n * 검색어로 필터링된 메뉴 아이템\n * 재귀적으로 children까지 검색\n */\nconst filteredMenuItems = computed(() => {\n return filterMenuItems(props.menuItems, props.searchQuery || '')\n})\n\r\n/**\n * 검색 결과에 따라 부모 메뉴 자동 확장\n * computed 외부에서 watch를 통해 처리\n */\nwatch(\n () => filteredMenuItems.value,\n (filtered) => {\n if (!props.searchQuery || props.searchQuery.trim() === '') {\n return\n }\n\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\n const keysToExpand = getExpandedKeysForSearch(filtered)\n keysToExpand.forEach(key => {\n expandedKeys.value.add(key)\n })\n },\n { immediate: false }\n)\n\r\n/**\r\n * 확장 상태 변경 핸들러\r\n */\r\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\r\n if (!menuKey) return\r\n\r\n if (expanded) {\r\n expandedKeys.value.add(menuKey)\r\n } else {\r\n expandedKeys.value.delete(menuKey)\r\n }\r\n}\r\n\r\n/**\r\n * 메뉴 클릭 핸들러\r\n */\r\nconst handleMenuClick = (event: MenuClickEvent) => {\r\n emit('menuClick', event)\r\n}\r\n\r\n/**\
|
|
1
|
+
{"version":3,"file":"JSidebarSimple.vue2.cjs","sources":["../../../../src/components/organisms/JSidebarSimple.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\nimport { useRoute } from 'vue-router'\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\nimport { cn } from '@/lib/utils'\nimport { filterMenuItems, getExpandedKeysForSearch } from '@/lib/menu-utils'\n\r\n/**\r\n * JSidebarSimple - 간단한 사이드바 컴포넌트\r\n * Simple Sidebar Component\r\n * \r\n * @description\r\n * 다단계 메뉴 구조를 지원하는 기본 사이드바 컴포넌트입니다.\r\n * 권한 체크, 메뉴 검색 등의 기능을 제공합니다.\r\n * \r\n * @example\r\n * ```vue\r\n * <JSidebarSimple\r\n * :menu-items=\"menuItems\"\r\n * :permissions=\"userPermissions\"\r\n * @menu-click=\"handleMenuClick\"\r\n * />\r\n * ```\r\n * \r\n * @example JSON 메뉴 데이터 예시\r\n * ```json\r\n * [\r\n * {\r\n * \"label\": \"대시보드\",\r\n * \"icon\": \"house\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 1,\r\n * \"path\": \"/dashboard\"\r\n * },\r\n * {\r\n * \"label\": \"재고 관리\",\r\n * \"icon\": \"package\",\r\n * \"menuType\": \"F\",\r\n * \"menuKey\": 2,\r\n * \"children\": [\r\n * {\r\n * \"label\": \"재고 현황\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 21,\r\n * \"path\": \"/inventory/status\"\r\n * },\r\n * {\r\n * \"label\": \"입고 관리\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 22,\r\n * \"path\": \"/inventory/receiving\"\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * ```\r\n */\r\n\r\ntype StyleType = 'default' | 'minimal'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 메뉴 아이템 목록 */\r\n menuItems: SidebarMenuItem[]\r\n /** 권한 목록 */\r\n permissions?: MenuPermission[]\r\n /** 검색어 */\r\n searchQuery?: string\r\n /** 스타일 타입 */\r\n styletype?: StyleType\r\n /** 추가 CSS 클래스 */\r\n class?: string\r\n /** 너비 */\r\n width?: string\r\n /** 표시 여부 */\r\n isVisible?: boolean\r\n }>(),\r\n {\r\n permissions: () => [],\r\n searchQuery: '',\r\n styletype: 'default',\r\n width: '250px',\r\n isVisible: true,\r\n },\r\n)\r\n\r\nconst emit = defineEmits<{\r\n /** 메뉴 클릭 이벤트 */\r\n menuClick: [event: MenuClickEvent]\r\n}>()\r\n\r\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\r\nconst route = useRoute()\r\n\r\n/**\r\n * 현재 활성화된 경로\r\n */\r\nconst activePath = computed(() => route.path)\r\n\r\n/**\r\n * 확장된 메뉴 키 목록 (Set)\r\n */\r\nconst expandedKeys = ref<Set<number | string>>(new Set())\r\n\r\n/**\n * 검색어로 필터링된 메뉴 아이템\n * 재귀적으로 children까지 검색\n */\nconst filteredMenuItems = computed(() => {\n return filterMenuItems(props.menuItems, props.searchQuery || '')\n})\n\r\n/**\n * 검색 결과에 따라 부모 메뉴 자동 확장\n * computed 외부에서 watch를 통해 처리\n */\nwatch(\n () => filteredMenuItems.value,\n (filtered) => {\n if (!props.searchQuery || props.searchQuery.trim() === '') {\n return\n }\n\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\n const keysToExpand = getExpandedKeysForSearch(filtered)\n keysToExpand.forEach(key => {\n expandedKeys.value.add(key)\n })\n },\n { immediate: false }\n)\n\r\n/**\r\n * 확장 상태 변경 핸들러\r\n */\r\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\r\n if (!menuKey) return\r\n\r\n if (expanded) {\r\n expandedKeys.value.add(menuKey)\r\n } else {\r\n expandedKeys.value.delete(menuKey)\r\n }\r\n}\r\n\r\n/**\r\n * 메뉴 클릭 핸들러\r\n */\r\nconst handleMenuClick = (event: MenuClickEvent) => {\r\n emit('menuClick', event)\r\n}\r\n\r\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n menuPaddingClass: string\n}> = {\n default: {\n containerClass: 'h-full bg-background border-r border-border overflow-y-auto',\n menuPaddingClass: 'p-1.5',\n },\n minimal: {\n containerClass: 'h-full bg-background border-r border-border overflow-y-auto',\n menuPaddingClass: 'p-1',\n },\n}\n\r\nconst preset = computed(() => {\r\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\r\n})\r\n\r\n/**\r\n * 루트 클래스\r\n */\r\nconst rootClasses = computed(() => {\r\n return cn(\r\n preset.value.containerClass,\r\n props.class\r\n )\r\n})\r\n</script>\r\n\r\n<template>\r\n <Transition name=\"slide\">\r\n <aside v-show=\"props.isVisible\" :class=\"rootClasses\" :style=\"{ width }\">\r\n <div :class=\"cn(preset.menuPaddingClass, 'space-y-0.5')\">\n <JDynamicMenuItem\r\n v-for=\"(item, index) in filteredMenuItems\"\r\n :key=\"item.menuKey || item.label || index\"\r\n :item=\"item\"\r\n :level=\"0\"\r\n :permissions=\"permissions\"\r\n :active-path=\"activePath\"\r\n :expanded-keys=\"expandedKeys\"\r\n :styletype=\"styletype\"\r\n @menu-click=\"handleMenuClick\"\r\n @expand-change=\"handleExpandChange\"\r\n />\r\n </div>\r\n </aside>\r\n </Transition>\r\n</template>\r\n\r\n<style scoped>\r\n.slide-enter-active,\r\n.slide-leave-active {\r\n transition: transform 0.3s ease, opacity 0.3s ease;\r\n}\r\n\r\n.slide-enter-from,\r\n.slide-leave-to {\r\n transform: translateX(-100%);\r\n opacity: 0;\r\n}\r\n</style>\r\n"],"names":["props","__props","emit","__emit","route","useRoute","activePath","computed","expandedKeys","ref","filteredMenuItems","filterMenuItems","watch","filtered","getExpandedKeysForSearch","key","handleExpandChange","menuKey","expanded","handleMenuClick","event","STYLE_PRESETS","preset","rootClasses","cn","_createBlock","_Transition","_createElementVNode","_normalizeClass","_unref","_openBlock","_createElementBlock","_Fragment","_renderList","item","index","JDynamicMenuItem","_vShow"],"mappings":"0hBA6DA,MAAMA,EAAQC,EA0BRC,EAAOC,EAMPC,EAAQC,EAAAA,SAAA,EAKRC,EAAaC,EAAAA,SAAS,IAAMH,EAAM,IAAI,EAKtCI,EAAeC,EAAAA,IAA0B,IAAI,GAAK,EAMlDC,EAAoBH,EAAAA,SAAS,IAC1BI,EAAAA,gBAAgBX,EAAM,UAAWA,EAAM,aAAe,EAAE,CAChE,EAMDY,EAAAA,MACE,IAAMF,EAAkB,MACvBG,GAAa,CACZ,GAAI,CAACb,EAAM,aAAeA,EAAM,YAAY,KAAA,IAAW,GACrD,OAImBc,EAAAA,yBAAyBD,CAAQ,EACzC,QAAQE,GAAO,CAC1BP,EAAa,MAAM,IAAIO,CAAG,CAC5B,CAAC,CACH,EACA,CAAE,UAAW,EAAA,CAAM,EAMrB,MAAMC,EAAqB,CAACC,EAAsCC,IAAsB,CACjFD,IAEDC,EACFV,EAAa,MAAM,IAAIS,CAAO,EAE9BT,EAAa,MAAM,OAAOS,CAAO,EAErC,EAKME,EAAmBC,GAA0B,CACjDlB,EAAK,YAAakB,CAAK,CACzB,EAKMC,EAGD,CACH,QAAS,CACP,eAAgB,8DAChB,iBAAkB,OAAA,EAEpB,QAAS,CACP,eAAgB,8DAChB,iBAAkB,KAAA,CACpB,EAGIC,EAASf,EAAAA,SAAS,IACfc,EAAcrB,EAAM,SAAS,GAAKqB,EAAc,OACxD,EAKKE,EAAchB,EAAAA,SAAS,IACpBiB,EAAAA,GACLF,EAAO,MAAM,eACbtB,EAAM,KAAA,CAET,8BAICyB,EAAAA,YAiBaC,EAAAA,WAAA,CAjBD,KAAK,SAAO,mBACtB,IAeQ,kBAfRC,EAAAA,mBAeQ,QAAA,CAfyB,uBAAOJ,EAAA,KAAW,EAAG,8BAAStB,EAAA,MAAK,CAAA,GAClE0B,EAAAA,mBAaM,MAAA,CAbA,MAAKC,EAAAA,eAAEC,EAAAA,MAAAL,EAAAA,EAAA,EAAGF,EAAA,MAAO,iBAAgB,aAAA,CAAA,CAAA,IACrCQ,EAAAA,UAAA,EAAA,EAAAC,EAAAA,mBAWEC,WAAA,KAAAC,EAAAA,WAVwBvB,EAAA,MAAiB,CAAjCwB,EAAMC,mBADhBV,EAAAA,YAWEW,UAAA,CATC,IAAKF,EAAK,SAAWA,EAAK,OAASC,EACnC,KAAAD,EACA,MAAO,EACP,YAAajC,EAAA,YACb,cAAaK,EAAA,MACb,gBAAeE,EAAA,MACf,UAAWP,EAAA,UACX,YAAYkB,EACZ,eAAeH,CAAA,4FAZP,CAAAqB,EAAAA,MAAArC,EAAM,SAAS,CAAA"}
|
|
@@ -35,7 +35,7 @@ const j = /* @__PURE__ */ E({
|
|
|
35
35
|
}, u = {
|
|
36
36
|
default: {
|
|
37
37
|
containerClass: "h-full bg-background border-r border-border overflow-y-auto",
|
|
38
|
-
menuPaddingClass: "p-
|
|
38
|
+
menuPaddingClass: "p-1.5"
|
|
39
39
|
},
|
|
40
40
|
minimal: {
|
|
41
41
|
containerClass: "h-full bg-background border-r border-border overflow-y-auto",
|
|
@@ -52,7 +52,7 @@ const j = /* @__PURE__ */ E({
|
|
|
52
52
|
style: I({ width: s.width })
|
|
53
53
|
}, [
|
|
54
54
|
m("div", {
|
|
55
|
-
class: p(M(f)(d.value.menuPaddingClass, "space-y-
|
|
55
|
+
class: p(M(f)(d.value.menuPaddingClass, "space-y-0.5"))
|
|
56
56
|
}, [
|
|
57
57
|
(o(!0), Q(_, null, V(i.value, (a, g) => (o(), c(L, {
|
|
58
58
|
key: a.menuKey || a.label || g,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSidebarSimple.vue2.js","sources":["../../../../src/components/organisms/JSidebarSimple.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\nimport { useRoute } from 'vue-router'\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\nimport { cn } from '@/lib/utils'\nimport { filterMenuItems, getExpandedKeysForSearch } from '@/lib/menu-utils'\n\r\n/**\r\n * JSidebarSimple - 간단한 사이드바 컴포넌트\r\n * Simple Sidebar Component\r\n * \r\n * @description\r\n * 다단계 메뉴 구조를 지원하는 기본 사이드바 컴포넌트입니다.\r\n * 권한 체크, 메뉴 검색 등의 기능을 제공합니다.\r\n * \r\n * @example\r\n * ```vue\r\n * <JSidebarSimple\r\n * :menu-items=\"menuItems\"\r\n * :permissions=\"userPermissions\"\r\n * @menu-click=\"handleMenuClick\"\r\n * />\r\n * ```\r\n * \r\n * @example JSON 메뉴 데이터 예시\r\n * ```json\r\n * [\r\n * {\r\n * \"label\": \"대시보드\",\r\n * \"icon\": \"house\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 1,\r\n * \"path\": \"/dashboard\"\r\n * },\r\n * {\r\n * \"label\": \"재고 관리\",\r\n * \"icon\": \"package\",\r\n * \"menuType\": \"F\",\r\n * \"menuKey\": 2,\r\n * \"children\": [\r\n * {\r\n * \"label\": \"재고 현황\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 21,\r\n * \"path\": \"/inventory/status\"\r\n * },\r\n * {\r\n * \"label\": \"입고 관리\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 22,\r\n * \"path\": \"/inventory/receiving\"\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * ```\r\n */\r\n\r\ntype StyleType = 'default' | 'minimal'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 메뉴 아이템 목록 */\r\n menuItems: SidebarMenuItem[]\r\n /** 권한 목록 */\r\n permissions?: MenuPermission[]\r\n /** 검색어 */\r\n searchQuery?: string\r\n /** 스타일 타입 */\r\n styletype?: StyleType\r\n /** 추가 CSS 클래스 */\r\n class?: string\r\n /** 너비 */\r\n width?: string\r\n /** 표시 여부 */\r\n isVisible?: boolean\r\n }>(),\r\n {\r\n permissions: () => [],\r\n searchQuery: '',\r\n styletype: 'default',\r\n width: '250px',\r\n isVisible: true,\r\n },\r\n)\r\n\r\nconst emit = defineEmits<{\r\n /** 메뉴 클릭 이벤트 */\r\n menuClick: [event: MenuClickEvent]\r\n}>()\r\n\r\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\r\nconst route = useRoute()\r\n\r\n/**\r\n * 현재 활성화된 경로\r\n */\r\nconst activePath = computed(() => route.path)\r\n\r\n/**\r\n * 확장된 메뉴 키 목록 (Set)\r\n */\r\nconst expandedKeys = ref<Set<number | string>>(new Set())\r\n\r\n/**\n * 검색어로 필터링된 메뉴 아이템\n * 재귀적으로 children까지 검색\n */\nconst filteredMenuItems = computed(() => {\n return filterMenuItems(props.menuItems, props.searchQuery || '')\n})\n\r\n/**\n * 검색 결과에 따라 부모 메뉴 자동 확장\n * computed 외부에서 watch를 통해 처리\n */\nwatch(\n () => filteredMenuItems.value,\n (filtered) => {\n if (!props.searchQuery || props.searchQuery.trim() === '') {\n return\n }\n\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\n const keysToExpand = getExpandedKeysForSearch(filtered)\n keysToExpand.forEach(key => {\n expandedKeys.value.add(key)\n })\n },\n { immediate: false }\n)\n\r\n/**\r\n * 확장 상태 변경 핸들러\r\n */\r\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\r\n if (!menuKey) return\r\n\r\n if (expanded) {\r\n expandedKeys.value.add(menuKey)\r\n } else {\r\n expandedKeys.value.delete(menuKey)\r\n }\r\n}\r\n\r\n/**\r\n * 메뉴 클릭 핸들러\r\n */\r\nconst handleMenuClick = (event: MenuClickEvent) => {\r\n emit('menuClick', event)\r\n}\r\n\r\n/**\
|
|
1
|
+
{"version":3,"file":"JSidebarSimple.vue2.js","sources":["../../../../src/components/organisms/JSidebarSimple.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\nimport { useRoute } from 'vue-router'\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\nimport { cn } from '@/lib/utils'\nimport { filterMenuItems, getExpandedKeysForSearch } from '@/lib/menu-utils'\n\r\n/**\r\n * JSidebarSimple - 간단한 사이드바 컴포넌트\r\n * Simple Sidebar Component\r\n * \r\n * @description\r\n * 다단계 메뉴 구조를 지원하는 기본 사이드바 컴포넌트입니다.\r\n * 권한 체크, 메뉴 검색 등의 기능을 제공합니다.\r\n * \r\n * @example\r\n * ```vue\r\n * <JSidebarSimple\r\n * :menu-items=\"menuItems\"\r\n * :permissions=\"userPermissions\"\r\n * @menu-click=\"handleMenuClick\"\r\n * />\r\n * ```\r\n * \r\n * @example JSON 메뉴 데이터 예시\r\n * ```json\r\n * [\r\n * {\r\n * \"label\": \"대시보드\",\r\n * \"icon\": \"house\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 1,\r\n * \"path\": \"/dashboard\"\r\n * },\r\n * {\r\n * \"label\": \"재고 관리\",\r\n * \"icon\": \"package\",\r\n * \"menuType\": \"F\",\r\n * \"menuKey\": 2,\r\n * \"children\": [\r\n * {\r\n * \"label\": \"재고 현황\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 21,\r\n * \"path\": \"/inventory/status\"\r\n * },\r\n * {\r\n * \"label\": \"입고 관리\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 22,\r\n * \"path\": \"/inventory/receiving\"\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * ```\r\n */\r\n\r\ntype StyleType = 'default' | 'minimal'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 메뉴 아이템 목록 */\r\n menuItems: SidebarMenuItem[]\r\n /** 권한 목록 */\r\n permissions?: MenuPermission[]\r\n /** 검색어 */\r\n searchQuery?: string\r\n /** 스타일 타입 */\r\n styletype?: StyleType\r\n /** 추가 CSS 클래스 */\r\n class?: string\r\n /** 너비 */\r\n width?: string\r\n /** 표시 여부 */\r\n isVisible?: boolean\r\n }>(),\r\n {\r\n permissions: () => [],\r\n searchQuery: '',\r\n styletype: 'default',\r\n width: '250px',\r\n isVisible: true,\r\n },\r\n)\r\n\r\nconst emit = defineEmits<{\r\n /** 메뉴 클릭 이벤트 */\r\n menuClick: [event: MenuClickEvent]\r\n}>()\r\n\r\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\r\nconst route = useRoute()\r\n\r\n/**\r\n * 현재 활성화된 경로\r\n */\r\nconst activePath = computed(() => route.path)\r\n\r\n/**\r\n * 확장된 메뉴 키 목록 (Set)\r\n */\r\nconst expandedKeys = ref<Set<number | string>>(new Set())\r\n\r\n/**\n * 검색어로 필터링된 메뉴 아이템\n * 재귀적으로 children까지 검색\n */\nconst filteredMenuItems = computed(() => {\n return filterMenuItems(props.menuItems, props.searchQuery || '')\n})\n\r\n/**\n * 검색 결과에 따라 부모 메뉴 자동 확장\n * computed 외부에서 watch를 통해 처리\n */\nwatch(\n () => filteredMenuItems.value,\n (filtered) => {\n if (!props.searchQuery || props.searchQuery.trim() === '') {\n return\n }\n\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\n const keysToExpand = getExpandedKeysForSearch(filtered)\n keysToExpand.forEach(key => {\n expandedKeys.value.add(key)\n })\n },\n { immediate: false }\n)\n\r\n/**\r\n * 확장 상태 변경 핸들러\r\n */\r\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\r\n if (!menuKey) return\r\n\r\n if (expanded) {\r\n expandedKeys.value.add(menuKey)\r\n } else {\r\n expandedKeys.value.delete(menuKey)\r\n }\r\n}\r\n\r\n/**\r\n * 메뉴 클릭 핸들러\r\n */\r\nconst handleMenuClick = (event: MenuClickEvent) => {\r\n emit('menuClick', event)\r\n}\r\n\r\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n menuPaddingClass: string\n}> = {\n default: {\n containerClass: 'h-full bg-background border-r border-border overflow-y-auto',\n menuPaddingClass: 'p-1.5',\n },\n minimal: {\n containerClass: 'h-full bg-background border-r border-border overflow-y-auto',\n menuPaddingClass: 'p-1',\n },\n}\n\r\nconst preset = computed(() => {\r\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\r\n})\r\n\r\n/**\r\n * 루트 클래스\r\n */\r\nconst rootClasses = computed(() => {\r\n return cn(\r\n preset.value.containerClass,\r\n props.class\r\n )\r\n})\r\n</script>\r\n\r\n<template>\r\n <Transition name=\"slide\">\r\n <aside v-show=\"props.isVisible\" :class=\"rootClasses\" :style=\"{ width }\">\r\n <div :class=\"cn(preset.menuPaddingClass, 'space-y-0.5')\">\n <JDynamicMenuItem\r\n v-for=\"(item, index) in filteredMenuItems\"\r\n :key=\"item.menuKey || item.label || index\"\r\n :item=\"item\"\r\n :level=\"0\"\r\n :permissions=\"permissions\"\r\n :active-path=\"activePath\"\r\n :expanded-keys=\"expandedKeys\"\r\n :styletype=\"styletype\"\r\n @menu-click=\"handleMenuClick\"\r\n @expand-change=\"handleExpandChange\"\r\n />\r\n </div>\r\n </aside>\r\n </Transition>\r\n</template>\r\n\r\n<style scoped>\r\n.slide-enter-active,\r\n.slide-leave-active {\r\n transition: transform 0.3s ease, opacity 0.3s ease;\r\n}\r\n\r\n.slide-enter-from,\r\n.slide-leave-to {\r\n transform: translateX(-100%);\r\n opacity: 0;\r\n}\r\n</style>\r\n"],"names":["props","__props","emit","__emit","route","useRoute","activePath","computed","expandedKeys","ref","filteredMenuItems","filterMenuItems","watch","filtered","getExpandedKeysForSearch","key","handleExpandChange","menuKey","expanded","handleMenuClick","event","STYLE_PRESETS","preset","rootClasses","cn","_createBlock","_Transition","_createElementVNode","_normalizeClass","_unref","_openBlock","_createElementBlock","_Fragment","_renderList","item","index","JDynamicMenuItem","_vShow"],"mappings":";;;;;;;;;;;;;;;;;;AA6DA,UAAMA,IAAQC,GA0BRC,IAAOC,GAMPC,IAAQC,EAAA,GAKRC,IAAaC,EAAS,MAAMH,EAAM,IAAI,GAKtCI,IAAeC,EAA0B,oBAAI,KAAK,GAMlDC,IAAoBH,EAAS,MAC1BI,EAAgBX,EAAM,WAAWA,EAAM,eAAe,EAAE,CAChE;AAMD,IAAAY;AAAA,MACE,MAAMF,EAAkB;AAAA,MACxB,CAACG,MAAa;AACZ,YAAI,CAACb,EAAM,eAAeA,EAAM,YAAY,KAAA,MAAW;AACrD;AAKF,QADqBc,EAAyBD,CAAQ,EACzC,QAAQ,CAAAE,MAAO;AAC1B,UAAAP,EAAa,MAAM,IAAIO,CAAG;AAAA,QAC5B,CAAC;AAAA,MACH;AAAA,MACA,EAAE,WAAW,GAAA;AAAA,IAAM;AAMrB,UAAMC,IAAqB,CAACC,GAAsCC,MAAsB;AACtF,MAAKD,MAEDC,IACFV,EAAa,MAAM,IAAIS,CAAO,IAE9BT,EAAa,MAAM,OAAOS,CAAO;AAAA,IAErC,GAKME,IAAkB,CAACC,MAA0B;AACjD,MAAAlB,EAAK,aAAakB,CAAK;AAAA,IACzB,GAKMC,IAGD;AAAA,MACH,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,kBAAkB;AAAA,MAAA;AAAA,MAEpB,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,kBAAkB;AAAA,MAAA;AAAA,IACpB,GAGIC,IAASf,EAAS,MACfc,EAAcrB,EAAM,SAAS,KAAKqB,EAAc,OACxD,GAKKE,IAAchB,EAAS,MACpBiB;AAAA,MACLF,EAAO,MAAM;AAAA,MACbtB,EAAM;AAAA,IAAA,CAET;2BAICyB,EAiBaC,GAAA,EAjBD,MAAK,WAAO;AAAA,iBACtB,MAeQ;AAAA,UAfRC,EAeQ,SAAA;AAAA,UAfyB,SAAOJ,EAAA,KAAW;AAAA,UAAG,kBAAStB,EAAA,OAAK;AAAA,QAAA;UAClE0B,EAaM,OAAA;AAAA,YAbA,OAAKC,EAAEC,EAAAL,CAAA,EAAGF,EAAA,MAAO,kBAAgB,aAAA,CAAA;AAAA,UAAA;aACrCQ,EAAA,EAAA,GAAAC,EAWEC,GAAA,MAAAC,EAVwBvB,EAAA,OAAiB,CAAjCwB,GAAMC,YADhBV,EAWEW,GAAA;AAAA,cATC,KAAKF,EAAK,WAAWA,EAAK,SAASC;AAAA,cACnC,MAAAD;AAAA,cACA,OAAO;AAAA,cACP,aAAajC,EAAA;AAAA,cACb,eAAaK,EAAA;AAAA,cACb,iBAAeE,EAAA;AAAA,cACf,WAAWP,EAAA;AAAA,cACX,aAAYkB;AAAA,cACZ,gBAAeH;AAAA,YAAA;;;UAZP,CAAAqB,GAAArC,EAAM,SAAS;AAAA,QAAA;;;;;;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),a=require("@vueuse/core"),c=require("lucide-vue-next"),o=require("reka-ui"),i=require("../../lib/utils.cjs"),l=e.defineComponent({__name:"AccordionTrigger",props:{asChild:{type:Boolean},as:{},class:{}},setup(s){const r=s,n=a.reactiveOmit(r,"class");return(t,u)=>(e.openBlock(),e.createBlock(e.unref(o.AccordionHeader),{class:"flex"},{default:e.withCtx(()=>[e.createVNode(e.unref(o.AccordionTrigger),e.mergeProps(e.unref(n),{class:e.unref(i.cn)("flex flex-1 items-center justify-between py-
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),a=require("@vueuse/core"),c=require("lucide-vue-next"),o=require("reka-ui"),i=require("../../lib/utils.cjs"),l=e.defineComponent({__name:"AccordionTrigger",props:{asChild:{type:Boolean},as:{},class:{}},setup(s){const r=s,n=a.reactiveOmit(r,"class");return(t,u)=>(e.openBlock(),e.createBlock(e.unref(o.AccordionHeader),{class:"flex"},{default:e.withCtx(()=>[e.createVNode(e.unref(o.AccordionTrigger),e.mergeProps(e.unref(n),{class:e.unref(i.cn)("flex flex-1 items-center justify-between py-2 text-xs font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",r.class)}),{default:e.withCtx(()=>[e.renderSlot(t.$slots,"default"),e.renderSlot(t.$slots,"icon",{},()=>[e.createVNode(e.unref(c.ChevronDown),{class:"h-3.5 w-3.5 shrink-0 transition-transform duration-200"})])]),_:3},16,["class"])]),_:3}))}});exports.default=l;
|
|
2
2
|
//# sourceMappingURL=AccordionTrigger.vue.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccordionTrigger.vue.cjs","sources":["../../../../src/components/shadcn/AccordionTrigger.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { AccordionTriggerProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ChevronDown } from \"lucide-vue-next\"\r\nimport {\r\n AccordionHeader,\r\n AccordionTrigger,\r\n\r\n} from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n</script>\r\n\r\n<template>\r\n <AccordionHeader class=\"flex\">\
|
|
1
|
+
{"version":3,"file":"AccordionTrigger.vue.cjs","sources":["../../../../src/components/shadcn/AccordionTrigger.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { AccordionTriggerProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ChevronDown } from \"lucide-vue-next\"\r\nimport {\r\n AccordionHeader,\r\n AccordionTrigger,\r\n\r\n} from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n</script>\r\n\r\n<template>\r\n <AccordionHeader class=\"flex\">\n <AccordionTrigger\n v-bind=\"delegatedProps\"\n :class=\"\n cn(\n 'flex flex-1 items-center justify-between py-2 text-xs font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',\n props.class,\n )\n \"\n >\n <slot />\n <slot name=\"icon\">\n <ChevronDown\n class=\"h-3.5 w-3.5 shrink-0 transition-transform duration-200\"\n />\n </slot>\n </AccordionTrigger>\n </AccordionHeader>\n</template>\r\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","AccordionHeader","_createVNode","AccordionTrigger","_mergeProps","cn","_renderSlot","_ctx","ChevronDown"],"mappings":"sVAYA,MAAMA,EAAQC,EAERC,EAAiBC,EAAAA,aAAaH,EAAO,OAAO,8BAIhDI,EAAAA,YAiBkBC,EAAAA,MAAAC,EAAAA,eAAA,EAAA,CAjBD,MAAM,QAAM,mBAC3B,IAemB,CAfnBC,EAAAA,YAemBF,EAAAA,MAAAG,EAAAA,gBAAA,EAfnBC,EAAAA,WAemBJ,EAAAA,MAAAH,CAAA,EAdK,CACrB,MAAgBG,EAAAA,MAAAK,IAAA,yIAAgKV,EAAM,KAAA,uBAOvL,IAAQ,CAARW,aAAQC,EAAA,OAAA,SAAA,EACRD,EAAAA,WAIOC,mBAJP,IAIO,CAHLL,EAAAA,YAEEF,EAAAA,MAAAQ,EAAAA,WAAA,EAAA,CADA,MAAM,yDAAwD,CAAA"}
|
|
@@ -12,18 +12,18 @@ const y = /* @__PURE__ */ c({
|
|
|
12
12
|
},
|
|
13
13
|
setup(a) {
|
|
14
14
|
const o = a, i = f(o, "class");
|
|
15
|
-
return (r,
|
|
15
|
+
return (r, x) => (m(), l(e(u), { class: "flex" }, {
|
|
16
16
|
default: t(() => [
|
|
17
17
|
s(e(g), d(e(i), {
|
|
18
18
|
class: e(h)(
|
|
19
|
-
"flex flex-1 items-center justify-between py-
|
|
19
|
+
"flex flex-1 items-center justify-between py-2 text-xs font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
|
|
20
20
|
o.class
|
|
21
21
|
)
|
|
22
22
|
}), {
|
|
23
23
|
default: t(() => [
|
|
24
24
|
n(r.$slots, "default"),
|
|
25
25
|
n(r.$slots, "icon", {}, () => [
|
|
26
|
-
s(e(p), { class: "h-
|
|
26
|
+
s(e(p), { class: "h-3.5 w-3.5 shrink-0 transition-transform duration-200" })
|
|
27
27
|
])
|
|
28
28
|
]),
|
|
29
29
|
_: 3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccordionTrigger.vue.js","sources":["../../../../src/components/shadcn/AccordionTrigger.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { AccordionTriggerProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ChevronDown } from \"lucide-vue-next\"\r\nimport {\r\n AccordionHeader,\r\n AccordionTrigger,\r\n\r\n} from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n</script>\r\n\r\n<template>\r\n <AccordionHeader class=\"flex\">\
|
|
1
|
+
{"version":3,"file":"AccordionTrigger.vue.js","sources":["../../../../src/components/shadcn/AccordionTrigger.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { AccordionTriggerProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ChevronDown } from \"lucide-vue-next\"\r\nimport {\r\n AccordionHeader,\r\n AccordionTrigger,\r\n\r\n} from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n</script>\r\n\r\n<template>\r\n <AccordionHeader class=\"flex\">\n <AccordionTrigger\n v-bind=\"delegatedProps\"\n :class=\"\n cn(\n 'flex flex-1 items-center justify-between py-2 text-xs font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',\n props.class,\n )\n \"\n >\n <slot />\n <slot name=\"icon\">\n <ChevronDown\n class=\"h-3.5 w-3.5 shrink-0 transition-transform duration-200\"\n />\n </slot>\n </AccordionTrigger>\n </AccordionHeader>\n</template>\r\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","AccordionHeader","_createVNode","AccordionTrigger","_mergeProps","cn","_renderSlot","_ctx","ChevronDown"],"mappings":";;;;;;;;;;;;;AAYA,UAAMA,IAAQC,GAERC,IAAiBC,EAAaH,GAAO,OAAO;2BAIhDI,EAiBkBC,EAAAC,CAAA,GAAA,EAjBD,OAAM,UAAM;AAAA,iBAC3B,MAemB;AAAA,QAfnBC,EAemBF,EAAAG,CAAA,GAfnBC,EAemBJ,EAAAH,CAAA,GAdK;AAAA,UACrB,OAAgBG,EAAAK,CAAA;AAAA;YAAgKV,EAAM;AAAA,UAAA;AAAA;qBAOvL,MAAQ;AAAA,YAARW,EAAQC,EAAA,QAAA,SAAA;AAAA,YACRD,EAIOC,sBAJP,MAIO;AAAA,cAHLL,EAEEF,EAAAQ,CAAA,GAAA,EADA,OAAM,0DAAwD;AAAA,YAAA;;;;;;;;;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),t=require("../../lib/utils.cjs"),n=e.defineComponent({__name:"Card",props:{class:{}},setup(r){const s=r;return(o,
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),t=require("../../lib/utils.cjs"),n=e.defineComponent({__name:"Card",props:{class:{}},setup(r){const s=r;return(o,a)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(e.unref(t.cn)("rounded-sm border bg-card text-card-foreground shadow-sm",s.class))},[e.renderSlot(o.$slots,"default")],2))}});exports.default=n;
|
|
2
2
|
//# sourceMappingURL=Card.vue.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card.vue.cjs","sources":["../../../../src/components/shadcn/Card.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<{\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div\
|
|
1
|
+
{"version":3,"file":"Card.vue.cjs","sources":["../../../../src/components/shadcn/Card.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<{\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div\n :class=\"\n cn(\n 'rounded-sm border bg-card text-card-foreground shadow-sm',\n props.class,\n )\n \"\n >\n <slot />\r\n </div>\r\n</template>\r\n"],"names":["props","__props","_createElementBlock","_normalizeClass","_unref","cn","_renderSlot","_ctx"],"mappings":"iOAIA,MAAMA,EAAQC,8BAMZC,EAAAA,mBASM,MAAA,CARH,MAAKC,EAAAA,eAASC,EAAAA,MAAAC,EAAAA,EAAA,6DAAgFL,EAAM,KAAA,KAOrGM,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card.vue.js","sources":["../../../../src/components/shadcn/Card.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<{\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div\
|
|
1
|
+
{"version":3,"file":"Card.vue.js","sources":["../../../../src/components/shadcn/Card.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<{\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div\n :class=\"\n cn(\n 'rounded-sm border bg-card text-card-foreground shadow-sm',\n props.class,\n )\n \"\n >\n <slot />\r\n </div>\r\n</template>\r\n"],"names":["props","__props","_createElementBlock","_normalizeClass","_unref","cn","_renderSlot","_ctx"],"mappings":";;;;;;;;AAIA,UAAMA,IAAQC;2BAMZC,EASM,OAAA;AAAA,MARH,OAAKC;AAAAA,QAASC,EAAAC,CAAA;AAAA;UAAgFL,EAAM;AAAA,QAAA;AAAA;;MAOrGM,EAAQC,EAAA,QAAA,SAAA;AAAA,IAAA;;;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),r=require("../../lib/utils.cjs"),o=e.defineComponent({__name:"CardContent",props:{class:{}},setup(t){const s=t;return(n,l)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(e.unref(r.cn)("p-
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),r=require("../../lib/utils.cjs"),o=e.defineComponent({__name:"CardContent",props:{class:{}},setup(t){const s=t;return(n,l)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(e.unref(r.cn)("p-3 pt-2 pb-2",s.class))},[e.renderSlot(n.$slots,"default")],2))}});exports.default=o;
|
|
2
2
|
//# sourceMappingURL=CardContent.vue.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardContent.vue.cjs","sources":["../../../../src/components/shadcn/CardContent.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<{\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div :class=\"cn('p-
|
|
1
|
+
{"version":3,"file":"CardContent.vue.cjs","sources":["../../../../src/components/shadcn/CardContent.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<{\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div :class=\"cn('p-3 pt-2 pb-2', props.class)\">\r\n <slot />\r\n </div>\r\n</template>\r\n"],"names":["props","__props","_createElementBlock","_normalizeClass","_unref","cn","_renderSlot","_ctx"],"mappings":"wOAIA,MAAMA,EAAQC,8BAMZC,EAAAA,mBAEM,MAAA,CAFA,MAAKC,EAAAA,eAAEC,QAAAC,EAAAA,EAAA,EAAE,gBAAkBL,EAAM,KAAK,CAAA,CAAA,GAC1CM,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { defineComponent as n, createElementBlock as r, openBlock as s, normalizeClass as a, unref as
|
|
2
|
-
import { cn as
|
|
1
|
+
import { defineComponent as n, createElementBlock as r, openBlock as s, normalizeClass as a, unref as p, renderSlot as c } from "vue";
|
|
2
|
+
import { cn as l } from "../../lib/utils.js";
|
|
3
3
|
const i = /* @__PURE__ */ n({
|
|
4
4
|
__name: "CardContent",
|
|
5
5
|
props: {
|
|
@@ -8,9 +8,9 @@ const i = /* @__PURE__ */ n({
|
|
|
8
8
|
setup(e) {
|
|
9
9
|
const o = e;
|
|
10
10
|
return (t, m) => (s(), r("div", {
|
|
11
|
-
class: a(
|
|
11
|
+
class: a(p(l)("p-3 pt-2 pb-2", o.class))
|
|
12
12
|
}, [
|
|
13
|
-
|
|
13
|
+
c(t.$slots, "default")
|
|
14
14
|
], 2));
|
|
15
15
|
}
|
|
16
16
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardContent.vue.js","sources":["../../../../src/components/shadcn/CardContent.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<{\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div :class=\"cn('p-
|
|
1
|
+
{"version":3,"file":"CardContent.vue.js","sources":["../../../../src/components/shadcn/CardContent.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<{\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div :class=\"cn('p-3 pt-2 pb-2', props.class)\">\r\n <slot />\r\n </div>\r\n</template>\r\n"],"names":["props","__props","_createElementBlock","_normalizeClass","_unref","cn","_renderSlot","_ctx"],"mappings":";;;;;;;;AAIA,UAAMA,IAAQC;2BAMZC,EAEM,OAAA;AAAA,MAFA,OAAKC,EAAEC,EAAAC,CAAA,EAAE,iBAAkBL,EAAM,KAAK,CAAA;AAAA,IAAA;MAC1CM,EAAQC,EAAA,QAAA,SAAA;AAAA,IAAA;;;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),o=require("../../lib/utils.cjs"),n=e.defineComponent({__name:"CardDescription",props:{class:{}},setup(t){const s=t;return(r,l)=>(e.openBlock(),e.createElementBlock("p",{class:e.normalizeClass(e.unref(o.cn)("text-
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),o=require("../../lib/utils.cjs"),n=e.defineComponent({__name:"CardDescription",props:{class:{}},setup(t){const s=t;return(r,l)=>(e.openBlock(),e.createElementBlock("p",{class:e.normalizeClass(e.unref(o.cn)("text-xs text-muted-foreground",s.class))},[e.renderSlot(r.$slots,"default")],2))}});exports.default=n;
|
|
2
2
|
//# sourceMappingURL=CardDescription.vue.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardDescription.vue.cjs","sources":["../../../../src/components/shadcn/CardDescription.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<{\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n</script>\r\n\r\n<template>\
|
|
1
|
+
{"version":3,"file":"CardDescription.vue.cjs","sources":["../../../../src/components/shadcn/CardDescription.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<{\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n</script>\r\n\r\n<template>\n <p :class=\"cn('text-xs text-muted-foreground', props.class)\">\n <slot />\n </p>\n</template>\n"],"names":["props","__props","_createElementBlock","_normalizeClass","_unref","cn","_renderSlot","_ctx"],"mappings":"4OAIA,MAAMA,EAAQC,8BAMZC,EAAAA,mBAEI,IAAA,CAFA,MAAKC,EAAAA,eAAEC,QAAAC,EAAAA,EAAA,EAAE,gCAAkCL,EAAM,KAAK,CAAA,CAAA,GACxDM,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|