@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
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { defineComponent as M, ref as m, computed as C, createElementBlock as u, openBlock as c, normalizeClass as z, unref as o, createElementVNode as t, createCommentVNode as L, toDisplayString as f, createVNode as i, withCtx as g, Fragment as _, createTextVNode as w } from "vue";
|
|
2
|
+
import V from "../atoms/JButton.vue.js";
|
|
3
|
+
import T from "../atoms/JInput.vue.js";
|
|
4
|
+
import "../shadcn/index.js";
|
|
5
|
+
import "lucide-vue-next";
|
|
6
|
+
import { cn as J } from "../../lib/utils.js";
|
|
7
|
+
import "@internationalized/date";
|
|
8
|
+
import "md-editor-v3";
|
|
9
|
+
/* empty css */
|
|
10
|
+
/* empty css */
|
|
11
|
+
import "../shadcn/badge-variants.js";
|
|
12
|
+
import "@vueuse/core";
|
|
13
|
+
import "reka-ui";
|
|
14
|
+
/* empty css */
|
|
15
|
+
import "../shadcn/avatar-variants.js";
|
|
16
|
+
import j from "../atoms/JIcon.vue.js";
|
|
17
|
+
import "dompurify";
|
|
18
|
+
/* empty css */
|
|
19
|
+
import S from "../atoms/JGrid.vue.js";
|
|
20
|
+
/* empty css */
|
|
21
|
+
/* empty css */
|
|
22
|
+
import "vue-sonner";
|
|
23
|
+
const E = { class: "j-shuttle-container" }, O = { class: "j-shuttle-panel" }, $ = { class: "j-shuttle-panel-card" }, F = { class: "j-shuttle-panel-header" }, q = { class: "j-shuttle-panel-title" }, A = { class: "j-shuttle-panel-count" }, H = {
|
|
24
|
+
key: 0,
|
|
25
|
+
class: "j-shuttle-search"
|
|
26
|
+
}, I = { class: "j-shuttle-grid-wrapper" }, K = { class: "j-shuttle-panel-footer" }, P = { class: "text-xs text-muted-foreground" }, Q = { class: "j-shuttle-actions" }, W = { class: "j-shuttle-actions-buttons" }, X = { class: "j-shuttle-panel" }, Y = { class: "j-shuttle-panel-card" }, Z = { class: "j-shuttle-panel-header j-shuttle-panel-header--primary" }, ee = { class: "j-shuttle-panel-title" }, te = { class: "j-shuttle-panel-count j-shuttle-panel-count--primary" }, se = {
|
|
27
|
+
key: 0,
|
|
28
|
+
class: "j-shuttle-search"
|
|
29
|
+
}, le = { class: "j-shuttle-grid-wrapper" }, ae = { class: "j-shuttle-panel-footer" }, oe = { class: "text-xs text-muted-foreground" }, Le = /* @__PURE__ */ M({
|
|
30
|
+
__name: "JShuttle",
|
|
31
|
+
props: {
|
|
32
|
+
leftTitle: { default: "Unmapped" },
|
|
33
|
+
rightTitle: { default: "Mapped" },
|
|
34
|
+
leftData: {},
|
|
35
|
+
rightData: {},
|
|
36
|
+
columnDefs: {},
|
|
37
|
+
searchable: { type: Boolean, default: !1 },
|
|
38
|
+
class: {}
|
|
39
|
+
},
|
|
40
|
+
emits: ["update:leftData", "update:rightData", "move"],
|
|
41
|
+
setup(d, { expose: N, emit: U }) {
|
|
42
|
+
const a = d, h = U, n = m([]), r = m([]), p = m(""), v = m(""), b = m(), y = m(), k = C(() => {
|
|
43
|
+
if (!a.searchable || !p.value)
|
|
44
|
+
return a.leftData;
|
|
45
|
+
const l = p.value.toLowerCase();
|
|
46
|
+
return a.leftData.filter((e) => Object.values(e).some(
|
|
47
|
+
(s) => String(s).toLowerCase().includes(l)
|
|
48
|
+
));
|
|
49
|
+
}), R = C(() => {
|
|
50
|
+
if (!a.searchable || !v.value)
|
|
51
|
+
return a.rightData;
|
|
52
|
+
const l = v.value.toLowerCase();
|
|
53
|
+
return a.rightData.filter((e) => Object.values(e).some(
|
|
54
|
+
(s) => String(s).toLowerCase().includes(l)
|
|
55
|
+
));
|
|
56
|
+
});
|
|
57
|
+
function G() {
|
|
58
|
+
if (n.value.length === 0) return;
|
|
59
|
+
const l = [...n.value], e = a.leftData.filter(
|
|
60
|
+
(D) => !l.some((x) => x.id === D.id)
|
|
61
|
+
), s = [...a.rightData, ...l];
|
|
62
|
+
h("update:leftData", e), h("update:rightData", s), h("move", { items: l, direction: "toRight" }), n.value = [];
|
|
63
|
+
}
|
|
64
|
+
function B() {
|
|
65
|
+
if (r.value.length === 0) return;
|
|
66
|
+
const l = [...r.value], e = a.rightData.filter(
|
|
67
|
+
(D) => !l.some((x) => x.id === D.id)
|
|
68
|
+
), s = [...a.leftData, ...l];
|
|
69
|
+
h("update:leftData", s), h("update:rightData", e), h("move", { items: l, direction: "toLeft" }), r.value = [];
|
|
70
|
+
}
|
|
71
|
+
return N({
|
|
72
|
+
leftGridRef: b,
|
|
73
|
+
rightGridRef: y
|
|
74
|
+
}), (l, e) => (c(), u("div", {
|
|
75
|
+
class: z(o(J)("j-shuttle", a.class))
|
|
76
|
+
}, [
|
|
77
|
+
t("div", E, [
|
|
78
|
+
t("div", O, [
|
|
79
|
+
t("div", $, [
|
|
80
|
+
t("div", F, [
|
|
81
|
+
t("h4", q, f(d.leftTitle || "Unmapped"), 1),
|
|
82
|
+
t("span", A, f(k.value.length) + " items ", 1)
|
|
83
|
+
]),
|
|
84
|
+
d.searchable ? (c(), u("div", H, [
|
|
85
|
+
i(o(T), {
|
|
86
|
+
modelValue: p.value,
|
|
87
|
+
"onUpdate:modelValue": e[0] || (e[0] = (s) => p.value = s),
|
|
88
|
+
placeholder: "검색..."
|
|
89
|
+
}, {
|
|
90
|
+
prefix: g(() => [
|
|
91
|
+
i(o(j), {
|
|
92
|
+
name: "search",
|
|
93
|
+
class: "w-4 h-4 text-muted-foreground"
|
|
94
|
+
})
|
|
95
|
+
]),
|
|
96
|
+
_: 1
|
|
97
|
+
}, 8, ["modelValue"])
|
|
98
|
+
])) : L("", !0),
|
|
99
|
+
t("div", I, [
|
|
100
|
+
i(o(S), {
|
|
101
|
+
ref_key: "leftGridRef",
|
|
102
|
+
ref: b,
|
|
103
|
+
"row-data": k.value,
|
|
104
|
+
"column-defs": d.columnDefs,
|
|
105
|
+
checkbox: !0,
|
|
106
|
+
"row-numbers": !1,
|
|
107
|
+
pagination: !1,
|
|
108
|
+
"selected-rows": n.value,
|
|
109
|
+
"onUpdate:selectedRows": e[1] || (e[1] = (s) => n.value = s),
|
|
110
|
+
class: "h-full"
|
|
111
|
+
}, null, 8, ["row-data", "column-defs", "selected-rows"])
|
|
112
|
+
]),
|
|
113
|
+
t("div", K, [
|
|
114
|
+
t("span", P, [
|
|
115
|
+
n.value.length > 0 ? (c(), u(_, { key: 0 }, [
|
|
116
|
+
t("strong", null, f(n.value.length), 1),
|
|
117
|
+
e[4] || (e[4] = w(" selected ", -1))
|
|
118
|
+
], 64)) : (c(), u(_, { key: 1 }, [
|
|
119
|
+
w(" No items selected ")
|
|
120
|
+
], 64))
|
|
121
|
+
])
|
|
122
|
+
])
|
|
123
|
+
])
|
|
124
|
+
]),
|
|
125
|
+
t("div", Q, [
|
|
126
|
+
e[5] || (e[5] = t("div", { class: "j-shuttle-actions-divider" }, null, -1)),
|
|
127
|
+
t("div", W, [
|
|
128
|
+
i(o(V), {
|
|
129
|
+
styletype: "primary",
|
|
130
|
+
size: "xs",
|
|
131
|
+
disabled: n.value.length === 0,
|
|
132
|
+
onClick: G,
|
|
133
|
+
class: "j-shuttle-action-btn",
|
|
134
|
+
title: "선택한 항목을 오른쪽으로 이동"
|
|
135
|
+
}, {
|
|
136
|
+
default: g(() => [
|
|
137
|
+
i(o(j), {
|
|
138
|
+
name: "chevronRight",
|
|
139
|
+
class: "w-3.5 h-3.5"
|
|
140
|
+
})
|
|
141
|
+
]),
|
|
142
|
+
_: 1
|
|
143
|
+
}, 8, ["disabled"]),
|
|
144
|
+
i(o(V), {
|
|
145
|
+
variant: "outline",
|
|
146
|
+
size: "xs",
|
|
147
|
+
disabled: r.value.length === 0,
|
|
148
|
+
onClick: B,
|
|
149
|
+
class: "j-shuttle-action-btn",
|
|
150
|
+
title: "선택한 항목을 왼쪽으로 이동"
|
|
151
|
+
}, {
|
|
152
|
+
default: g(() => [
|
|
153
|
+
i(o(j), {
|
|
154
|
+
name: "chevronLeft",
|
|
155
|
+
class: "w-3.5 h-3.5"
|
|
156
|
+
})
|
|
157
|
+
]),
|
|
158
|
+
_: 1
|
|
159
|
+
}, 8, ["disabled"])
|
|
160
|
+
])
|
|
161
|
+
]),
|
|
162
|
+
t("div", X, [
|
|
163
|
+
t("div", Y, [
|
|
164
|
+
t("div", Z, [
|
|
165
|
+
t("h4", ee, f(d.rightTitle || "Mapped"), 1),
|
|
166
|
+
t("span", te, f(R.value.length) + " items ", 1)
|
|
167
|
+
]),
|
|
168
|
+
d.searchable ? (c(), u("div", se, [
|
|
169
|
+
i(o(T), {
|
|
170
|
+
modelValue: v.value,
|
|
171
|
+
"onUpdate:modelValue": e[2] || (e[2] = (s) => v.value = s),
|
|
172
|
+
placeholder: "검색..."
|
|
173
|
+
}, {
|
|
174
|
+
prefix: g(() => [
|
|
175
|
+
i(o(j), {
|
|
176
|
+
name: "search",
|
|
177
|
+
class: "w-4 h-4 text-muted-foreground"
|
|
178
|
+
})
|
|
179
|
+
]),
|
|
180
|
+
_: 1
|
|
181
|
+
}, 8, ["modelValue"])
|
|
182
|
+
])) : L("", !0),
|
|
183
|
+
t("div", le, [
|
|
184
|
+
i(o(S), {
|
|
185
|
+
ref_key: "rightGridRef",
|
|
186
|
+
ref: y,
|
|
187
|
+
"row-data": R.value,
|
|
188
|
+
"column-defs": d.columnDefs,
|
|
189
|
+
checkbox: !0,
|
|
190
|
+
"row-numbers": !1,
|
|
191
|
+
pagination: !1,
|
|
192
|
+
"selected-rows": r.value,
|
|
193
|
+
"onUpdate:selectedRows": e[3] || (e[3] = (s) => r.value = s),
|
|
194
|
+
class: "h-full"
|
|
195
|
+
}, null, 8, ["row-data", "column-defs", "selected-rows"])
|
|
196
|
+
]),
|
|
197
|
+
t("div", ae, [
|
|
198
|
+
t("span", oe, [
|
|
199
|
+
r.value.length > 0 ? (c(), u(_, { key: 0 }, [
|
|
200
|
+
t("strong", null, f(r.value.length), 1),
|
|
201
|
+
e[6] || (e[6] = w(" selected ", -1))
|
|
202
|
+
], 64)) : (c(), u(_, { key: 1 }, [
|
|
203
|
+
w(" No items selected ")
|
|
204
|
+
], 64))
|
|
205
|
+
])
|
|
206
|
+
])
|
|
207
|
+
])
|
|
208
|
+
])
|
|
209
|
+
])
|
|
210
|
+
], 2));
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
export {
|
|
214
|
+
Le as default
|
|
215
|
+
};
|
|
216
|
+
//# sourceMappingURL=JShuttle.vue2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JShuttle.vue2.js","sources":["../../../../src/components/organisms/JShuttle.vue"],"sourcesContent":["<template>\n <div :class=\"cn('j-shuttle', props.class)\">\n <div class=\"j-shuttle-container\">\n <!-- 왼쪽 패널 -->\n <div class=\"j-shuttle-panel\">\n <div class=\"j-shuttle-panel-card\">\n <!-- 헤더 -->\n <div class=\"j-shuttle-panel-header\">\n <h4 class=\"j-shuttle-panel-title\">\n {{ leftTitle || 'Unmapped' }}\n </h4>\n <span class=\"j-shuttle-panel-count\">\n {{ filteredLeftData.length }} items\n </span>\n </div>\n\n <!-- 검색 -->\n <div v-if=\"searchable\" class=\"j-shuttle-search\">\n <JInput\n v-model=\"leftSearch\"\n placeholder=\"검색...\"\n >\n <template #prefix>\n <JIcon name=\"search\" class=\"w-4 h-4 text-muted-foreground\" />\n </template>\n </JInput>\n </div>\n\n <!-- 그리드 -->\n <div class=\"j-shuttle-grid-wrapper\">\n <JGrid\n ref=\"leftGridRef\"\n :row-data=\"filteredLeftData\"\n :column-defs=\"columnDefs\"\n :checkbox=\"true\"\n :row-numbers=\"false\"\n :pagination=\"false\"\n v-model:selected-rows=\"leftSelectedRows\"\n class=\"h-full\"\n />\n </div>\n\n <!-- 푸터 (선택 개수) -->\n <div class=\"j-shuttle-panel-footer\">\n <span class=\"text-xs text-muted-foreground\">\n <template v-if=\"leftSelectedRows.length > 0\">\n <strong>{{ leftSelectedRows.length }}</strong> selected\n </template>\n <template v-else>\n No items selected\n </template>\n </span>\n </div>\n </div>\n </div>\n\n <!-- 중앙 버튼 영역 -->\n <div class=\"j-shuttle-actions\">\n <div class=\"j-shuttle-actions-divider\" />\n <div class=\"j-shuttle-actions-buttons\">\n <JButton\n styletype=\"primary\"\n size=\"xs\"\n :disabled=\"leftSelectedRows.length === 0\"\n @click=\"moveToRight\"\n class=\"j-shuttle-action-btn\"\n title=\"선택한 항목을 오른쪽으로 이동\"\n >\n <JIcon name=\"chevronRight\" class=\"w-3.5 h-3.5\" />\n </JButton>\n <JButton\n variant=\"outline\"\n size=\"xs\"\n :disabled=\"rightSelectedRows.length === 0\"\n @click=\"moveToLeft\"\n class=\"j-shuttle-action-btn\"\n title=\"선택한 항목을 왼쪽으로 이동\"\n >\n <JIcon name=\"chevronLeft\" class=\"w-3.5 h-3.5\" />\n </JButton>\n </div>\n </div>\n\n <!-- 오른쪽 패널 -->\n <div class=\"j-shuttle-panel\">\n <div class=\"j-shuttle-panel-card\">\n <!-- 헤더 -->\n <div class=\"j-shuttle-panel-header j-shuttle-panel-header--primary\">\n <h4 class=\"j-shuttle-panel-title\">\n {{ rightTitle || 'Mapped' }}\n </h4>\n <span class=\"j-shuttle-panel-count j-shuttle-panel-count--primary\">\n {{ filteredRightData.length }} items\n </span>\n </div>\n\n <!-- 검색 -->\n <div v-if=\"searchable\" class=\"j-shuttle-search\">\n <JInput\n v-model=\"rightSearch\"\n placeholder=\"검색...\"\n >\n <template #prefix>\n <JIcon name=\"search\" class=\"w-4 h-4 text-muted-foreground\" />\n </template>\n </JInput>\n </div>\n\n <!-- 그리드 -->\n <div class=\"j-shuttle-grid-wrapper\">\n <JGrid\n ref=\"rightGridRef\"\n :row-data=\"filteredRightData\"\n :column-defs=\"columnDefs\"\n :checkbox=\"true\"\n :row-numbers=\"false\"\n :pagination=\"false\"\n v-model:selected-rows=\"rightSelectedRows\"\n class=\"h-full\"\n />\n </div>\n\n <!-- 푸터 (선택 개수) -->\n <div class=\"j-shuttle-panel-footer\">\n <span class=\"text-xs text-muted-foreground\">\n <template v-if=\"rightSelectedRows.length > 0\">\n <strong>{{ rightSelectedRows.length }}</strong> selected\n </template>\n <template v-else>\n No items selected\n </template>\n </span>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed } from 'vue'\nimport { JGrid, JButton, JIcon, JInput } from '@/components/atoms'\nimport { cn } from '@/lib/utils'\nimport type { JShuttleProps, JShuttleEmits, ShuttleItem } from '@/types/shuttle.types'\n\nconst props = withDefaults(defineProps<JShuttleProps>(), {\n searchable: false,\n leftTitle: 'Unmapped',\n rightTitle: 'Mapped',\n})\n\nconst emit = defineEmits<JShuttleEmits>()\n\n// 선택된 행\nconst leftSelectedRows = ref<ShuttleItem[]>([])\nconst rightSelectedRows = ref<ShuttleItem[]>([])\n\n// 검색어\nconst leftSearch = ref('')\nconst rightSearch = ref('')\n\n// 그리드 참조\nconst leftGridRef = ref()\nconst rightGridRef = ref()\n\n// 검색 필터링된 데이터\nconst filteredLeftData = computed(() => {\n if (!props.searchable || !leftSearch.value) {\n return props.leftData\n }\n const search = leftSearch.value.toLowerCase()\n return props.leftData.filter((item) => {\n return Object.values(item).some((val) =>\n String(val).toLowerCase().includes(search)\n )\n })\n})\n\nconst filteredRightData = computed(() => {\n if (!props.searchable || !rightSearch.value) {\n return props.rightData\n }\n const search = rightSearch.value.toLowerCase()\n return props.rightData.filter((item) => {\n return Object.values(item).some((val) =>\n String(val).toLowerCase().includes(search)\n )\n })\n})\n\n// 왼쪽 → 오른쪽 이동\nfunction moveToRight() {\n if (leftSelectedRows.value.length === 0) return\n\n const itemsToMove = [...leftSelectedRows.value]\n const newLeftData = props.leftData.filter(\n (item) => !itemsToMove.some((selected) => selected.id === item.id)\n )\n const newRightData = [...props.rightData, ...itemsToMove]\n\n emit('update:leftData', newLeftData)\n emit('update:rightData', newRightData)\n emit('move', { items: itemsToMove, direction: 'toRight' })\n\n leftSelectedRows.value = []\n}\n\n// 오른쪽 → 왼쪽 이동\nfunction moveToLeft() {\n if (rightSelectedRows.value.length === 0) return\n\n const itemsToMove = [...rightSelectedRows.value]\n const newRightData = props.rightData.filter(\n (item) => !itemsToMove.some((selected) => selected.id === item.id)\n )\n const newLeftData = [...props.leftData, ...itemsToMove]\n\n emit('update:leftData', newLeftData)\n emit('update:rightData', newRightData)\n emit('move', { items: itemsToMove, direction: 'toLeft' })\n\n rightSelectedRows.value = []\n}\n\ndefineExpose({\n leftGridRef,\n rightGridRef,\n})\n</script>\n\n<style scoped>\n.j-shuttle {\n width: 100%;\n height: 100%;\n min-height: 500px;\n}\n\n.j-shuttle-container {\n display: flex;\n gap: 0.5rem;\n height: 100%;\n padding: 0;\n border-radius: 0;\n background: transparent;\n}\n\n.j-shuttle-panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n}\n\n.j-shuttle-panel-card {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: hsl(var(--card));\n border: 1px solid hsl(var(--border));\n border-radius: 0.125rem; /* rounded-sm */\n box-shadow: none;\n overflow: hidden;\n}\n\n.j-shuttle-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.4rem 1rem;\n border-bottom: 1px solid hsl(var(--border));\n background: hsl(var(--muted) / 0.3);\n transition: background-color 0.2s ease;\n}\n\n.j-shuttle-panel-header--primary {\n background: linear-gradient(135deg,\n hsl(var(--primary) / 0.08) 0%,\n hsl(var(--primary) / 0.02) 100%);\n}\n\n.j-shuttle-panel-title {\n font-size: 0.8125rem;\n font-weight: 600;\n color: hsl(var(--foreground));\n letter-spacing: -0.01em;\n}\n\n.j-shuttle-panel-count {\n font-size: 0.75rem;\n font-weight: 500;\n color: hsl(var(--muted-foreground));\n padding: 0.25rem 0.625rem;\n border-radius: 0.125rem; /* rounded-sm */\n background: hsl(var(--muted));\n border: 1px solid hsl(var(--border) / 0.5);\n}\n\n.j-shuttle-panel-count--primary {\n color: hsl(var(--primary));\n background: hsl(var(--primary) / 0.1);\n border-color: hsl(var(--primary) / 0.2);\n}\n\n.j-shuttle-search {\n padding: 0.75rem 1rem;\n border-bottom: 1px solid hsl(var(--border) / 0.5);\n background: hsl(var(--card));\n}\n\n.j-shuttle-grid-wrapper {\n flex: 1;\n overflow: hidden;\n padding: 0;\n background: hsl(var(--background));\n}\n\n.j-shuttle-panel-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n padding: 0.625rem 1rem;\n border-top: 1px solid hsl(var(--border) / 0.5);\n background: hsl(var(--muted) / 0.2);\n min-height: 2.5rem;\n}\n\n.j-shuttle-actions {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 0;\n min-width: 2.5rem;\n}\n\n.j-shuttle-actions-divider {\n position: absolute;\n width: 1px;\n height: 100%;\n background: linear-gradient(to bottom,\n transparent 0%,\n hsl(var(--border)) 10%,\n hsl(var(--border)) 90%,\n transparent 100%);\n}\n\n.j-shuttle-actions-buttons {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 0.375rem;\n padding: 0.375rem;\n background: transparent;\n border: none;\n box-shadow: none;\n}\n\n.j-shuttle-action-btn {\n min-width: 2rem;\n min-height: 2rem;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.j-shuttle-action-btn:not(:disabled):hover {\n transform: scale(1.08);\n box-shadow: 0 2px 6px 0 rgb(0 0 0 / 0.12);\n}\n\n.j-shuttle-action-btn:not(:disabled):active {\n transform: scale(1.02);\n}\n\n.j-shuttle-action-btn:disabled {\n opacity: 1;\n background: hsl(var(--muted));\n color: hsl(var(--muted-foreground) / 0.4);\n border-color: hsl(var(--border));\n cursor: not-allowed;\n transform: scale(1);\n}\n\n/* 다크모드 조정 */\n.dark .j-shuttle-container {\n background: linear-gradient(135deg, \n hsl(var(--muted) / 0.2) 0%, \n hsl(var(--muted) / 0.05) 100%);\n}\n\n.dark .j-shuttle-panel-card {\n box-shadow: 0 2px 4px 0 rgb(0 0 0 / 0.2);\n}\n\n.dark .j-shuttle-panel-card:hover {\n box-shadow: 0 4px 6px 0 rgb(0 0 0 / 0.3);\n}\n</style>\n"],"names":["props","__props","emit","__emit","leftSelectedRows","ref","rightSelectedRows","leftSearch","rightSearch","leftGridRef","rightGridRef","filteredLeftData","computed","search","item","val","filteredRightData","moveToRight","itemsToMove","newLeftData","selected","newRightData","moveToLeft","__expose","_createElementBlock","_normalizeClass","_unref","cn","_createElementVNode","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_toDisplayString","_hoisted_6","_openBlock","_hoisted_7","_createVNode","JInput","$event","JIcon","_hoisted_8","JGrid","_hoisted_9","_hoisted_10","_Fragment","_hoisted_11","_hoisted_12","JButton","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21"],"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-63f4ba27"]]);exports.default=u;
|
|
7
7
|
//# sourceMappingURL=JSidebarAdvanced.vue.cjs.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import o from "./JSidebarAdvanced.vue2.js";
|
|
2
2
|
/* empty css */
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
for (const [
|
|
6
|
-
|
|
7
|
-
return
|
|
3
|
+
const a = (a_comp, a_opts) => {
|
|
4
|
+
const a_merged = a_comp.__vccOpts || a_comp;
|
|
5
|
+
for (const [a_key, a_val] of a_opts)
|
|
6
|
+
a_merged[a_key] = a_val;
|
|
7
|
+
return a_merged;
|
|
8
8
|
};
|
|
9
|
-
const e = /* @__PURE__ */ o
|
|
9
|
+
const e = /* @__PURE__ */ a(o, [["__scopeId", "data-v-63f4ba27"]]);
|
|
10
10
|
export {
|
|
11
11
|
e as default
|
|
12
12
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),T=require("vue-router"),I=require("./JSidebarSimple/JDynamicMenuItem.vue.cjs"),L=require("../atoms/JInput.vue.cjs"),S=require("../atoms/JIcon.vue.cjs"),
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),T=require("vue-router"),I=require("./JSidebarSimple/JDynamicMenuItem.vue.cjs"),L=require("../atoms/JInput.vue.cjs"),S=require("../atoms/JIcon.vue.cjs"),p=require("../../lib/utils.cjs"),z={class:"relative"},q={key:1,class:"text-center py-8 text-muted-foreground"},P={key:1,class:"text-center py-8 text-muted-foreground"},J=e.defineComponent({__name:"JSidebarAdvanced",props:{menuItems:{},permissions:{default:()=>[]},favorites:{default:()=>[]},styletype:{default:"minimal"},class:{},width:{default:"280px"},isVisible:{type:Boolean,default:!0}},emits:["menuClick","favoriteChange"],setup(u,{emit:V}){const s=u,b=V,w=T.useRoute(),m=e.ref("menu"),o=e.ref(""),C=e.computed(()=>w.path),f=e.ref(new Set),y=e.computed(()=>{if(!Array.isArray(s.favorites)||s.favorites.length===0)return[];if(!Array.isArray(s.menuItems)||s.menuItems.length===0)return[];const t=r=>{const n=[];if(!Array.isArray(r))return n;for(const a of r){const l=a.menuKey||a.label;if(Array.isArray(s.favorites)&&s.favorites.includes(l)&&a.menuType==="L"&&n.push({...a,children:void 0}),a.children&&Array.isArray(a.children)&&a.children.length>0){const i=t(a.children);n.push(...i)}}return n};return t(s.menuItems)}),h=e.computed(()=>{if(!Array.isArray(s.menuItems)||s.menuItems.length===0)return[];if(!o.value||o.value.trim()==="")return s.menuItems;const t=o.value.toLowerCase().trim(),r=n=>{const a=[];if(!Array.isArray(n))return a;for(const l of n){const v=l.label?.toLowerCase().includes(t)??!1;let i;l.children&&Array.isArray(l.children)&&l.children.length>0&&(i=r(l.children)),(v||Array.isArray(i)&&i.length>0)&&a.push({...l,children:i})}return a};return r(s.menuItems)});e.watch(()=>h.value,t=>{if(!o.value||o.value.trim()==="")return;(a=>{const l=new Set,v=i=>{if(Array.isArray(i)){for(const d of i)if(d.children&&Array.isArray(d.children)&&d.children.length>0){const N=d.menuKey||d.label;l.add(N),v(d.children)}}};return v(a),l})(t).forEach(a=>{f.value.add(a)})},{immediate:!1});const x=e.computed(()=>{if(!Array.isArray(y.value)||y.value.length===0)return[];if(!o.value||o.value.trim()==="")return y.value;const t=o.value.toLowerCase().trim();return y.value.filter(r=>r.label?.toLowerCase().includes(t)??!1)}),k=t=>{m.value!==t&&(m.value=t,o.value="")},g=(t,r)=>{t&&(r?f.value.add(t):f.value.delete(t))},E=t=>{b("menuClick",t)},_=t=>{if(!t)return;const r=s.favorites?.includes(t)??!1;b("favoriteChange",t,!r)},A=(t,r)=>{for(const n of t){if((n.menuKey||n.label)===r)return n;if(n.children&&n.children.length>0){const l=A(n.children,r);if(l)return l}}return null},F=t=>!t||!s.favorites?.includes(t)?!1:A(s.menuItems,t)?.menuType==="L",B={default:{containerClass:"h-full bg-background border-r border-border flex flex-col",tabContainerClass:"flex border-b border-border",tabButtonClass:"flex-1 px-3 py-1.5 text-xs font-medium transition-colors border-b-2 hover:bg-accent/50",searchContainerClass:"p-1.5 border-b border-border",menuContainerClass:"flex-1 overflow-y-auto p-1.5 space-y-0.5"},minimal:{containerClass:"h-full bg-background border-r border-border flex flex-col",tabContainerClass:"flex border-b border-border",tabButtonClass:"flex-1 px-2 py-1 text-xs font-medium transition-colors border-b-2",searchContainerClass:"p-1 border-b border-border",menuContainerClass:"flex-1 overflow-y-auto p-1 space-y-0.5"}},c=e.computed(()=>B[s.styletype]??B.default),M=e.computed(()=>p.cn(c.value.containerClass,s.class));return(t,r)=>(e.openBlock(),e.createBlock(e.Transition,{name:"slide"},{default:e.withCtx(()=>[e.withDirectives(e.createElementVNode("aside",{class:e.normalizeClass(M.value),style:e.normalizeStyle({width:u.width})},[e.createElementVNode("div",{class:e.normalizeClass(c.value.tabContainerClass)},[e.createElementVNode("button",{class:e.normalizeClass(e.unref(p.cn)(c.value.tabButtonClass,m.value==="menu"?"border-primary text-primary":"border-transparent text-muted-foreground hover:text-foreground")),onClick:r[0]||(r[0]=n=>k("menu"))}," 기본메뉴 ",2),e.createElementVNode("button",{class:e.normalizeClass(e.unref(p.cn)(c.value.tabButtonClass,m.value==="favorites"?"border-primary text-primary":"border-transparent text-muted-foreground hover:text-foreground")),onClick:r[1]||(r[1]=n=>k("favorites"))}," 즐겨찾기 ",2)],2),e.createElementVNode("div",{class:e.normalizeClass(c.value.searchContainerClass)},[e.createElementVNode("div",z,[e.createVNode(S.default,{name:"search",size:"sm",class:"absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground"}),e.createVNode(L.default,{modelValue:o.value,"onUpdate:modelValue":r[2]||(r[2]=n=>o.value=n),placeholder:"메뉴 검색...",class:e.normalizeClass(e.unref(p.cn)("pl-8",s.styletype==="minimal"&&"h-8 text-xs"))},null,8,["modelValue","class"])])],2),e.createElementVNode("div",{class:e.normalizeClass(c.value.menuContainerClass)},[m.value==="menu"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[h.value.length>0?(e.openBlock(!0),e.createElementBlock(e.Fragment,{key:0},e.renderList(h.value,(n,a)=>(e.openBlock(),e.createElementBlock("div",{key:n.menuKey||n.label||a,class:"flex items-center group"},[e.createVNode(I.default,{item:n,level:0,permissions:u.permissions,"active-path":C.value,"expanded-keys":f.value,favorites:u.favorites,"on-favorite-toggle":_,"is-favorite":F,styletype:u.styletype,class:"flex-1",onMenuClick:E,onExpandChange:g},null,8,["item","permissions","active-path","expanded-keys","favorites","styletype"])]))),128)):(e.openBlock(),e.createElementBlock("div",q,[...r[3]||(r[3]=[e.createElementVNode("p",{class:"text-xs"},"검색 결과가 없습니다.",-1)])]))],64)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[x.value.length>0?(e.openBlock(!0),e.createElementBlock(e.Fragment,{key:0},e.renderList(x.value,(n,a)=>(e.openBlock(),e.createBlock(I.default,{key:n.menuKey||n.label||a,item:n,level:0,permissions:u.permissions,"active-path":C.value,"expanded-keys":f.value,styletype:u.styletype,onMenuClick:E,onExpandChange:g},null,8,["item","permissions","active-path","expanded-keys","styletype"]))),128)):(e.openBlock(),e.createElementBlock("div",P,[...r[4]||(r[4]=[e.createElementVNode("p",{class:"text-xs"},"즐겨찾기가 없습니다.",-1)])]))],64))],2)],6),[[e.vShow,s.isVisible]])]),_:1}))}});exports.default=J;
|
|
2
2
|
//# sourceMappingURL=JSidebarAdvanced.vue2.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSidebarAdvanced.vue2.cjs","sources":["../../../../src/components/organisms/JSidebarAdvanced.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useRoute } from 'vue-router'\r\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\r\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\r\nimport JInput from '@/components/atoms/JInput.vue'\r\nimport JIcon from '@/components/atoms/JIcon.vue'\r\nimport { cn } from '@/lib/utils'\r\n\r\n/**\r\n * JSidebarAdvanced - 고급 사이드바 컴포넌트\r\n * Advanced Sidebar Component\r\n * \r\n * @description\r\n * 검색, 즐겨찾기, 다단계 메뉴를 지원하는 고급 사이드바 컴포넌트입니다.\r\n * 기본 메뉴와 즐겨찾기 탭을 제공합니다.\r\n * \r\n * @example\r\n * ```vue\r\n * <JSidebarAdvanced\r\n * :menu-items=\"menuItems\"\r\n * :permissions=\"userPermissions\"\r\n * :favorites=\"favoriteMenuKeys\"\r\n * @menu-click=\"handleMenuClick\"\r\n * @favorite-change=\"handleFavoriteChange\"\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\": \"F\",\r\n * \"menuKey\": 22,\r\n * \"children\": [\r\n * {\r\n * \"label\": \"입고 등록\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 221,\r\n * \"path\": \"/inventory/receiving/register\"\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * ```\r\n */\r\n\r\ntype TabType = 'menu' | 'favorites'\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 favorites?: (number | 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 favorites: () => [],\r\n styletype: 'minimal',\r\n width: '280px',\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 favoriteChange: [menuKey: number | string | undefined, isFavorite: boolean]\r\n}>()\r\n\r\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\r\nconst route = useRoute()\r\n\r\n/**\r\n * 현재 활성 탭\r\n */\r\nconst activeTab = ref<TabType>('menu')\r\n\r\n/**\r\n * 검색어\r\n */\r\nconst searchQuery = ref('')\r\n\r\n/**\r\n * 현재 활성화된 경로\r\n */\r\nconst activePath = computed(() => route.path)\r\n\r\n/**\r\n * 확장된 메뉴 키 목록\r\n */\r\nconst expandedKeys = ref<Set<number | string>>(new Set())\r\n\r\n/**\r\n * 즐겨찾기 메뉴 아이템 목록\r\n * 즐겨찾기는 dept 없이 1단계로만 평탄화하여 표시\r\n */\r\nconst favoriteMenuItems = computed(() => {\r\n if (!Array.isArray(props.favorites) || props.favorites.length === 0) {\r\n return []\r\n }\r\n\r\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\r\n return []\r\n }\r\n\r\n /**\r\n * 메뉴 아이템을 재귀적으로 순회하며 즐겨찾기만 추출\r\n * 즐겨찾기에서는 dept 없이 1단계로만 평탄화\r\n * menuType L(Link)만 포함하고 F(Folder)는 제외\r\n */\r\n const flattenFavorites = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\r\n const result: SidebarMenuItem[] = []\r\n\r\n if (!Array.isArray(items)) {\r\n return result\r\n }\r\n\r\n for (const item of items) {\r\n const key = item.menuKey || item.label\r\n const isFavorite = Array.isArray(props.favorites) && props.favorites.includes(key)\r\n\r\n // 즐겨찾기이고 menuType이 L(Link)인 경우만 추가 (F는 제외)\r\n if (isFavorite && item.menuType === 'L') {\r\n result.push({\r\n ...item,\r\n children: undefined, // children 제거하여 1단계로만 표시\r\n })\r\n }\r\n\r\n // 하위 메뉴도 재귀적으로 탐색\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n const childFavorites = flattenFavorites(item.children)\r\n result.push(...childFavorites)\r\n }\r\n }\r\n\r\n return result\r\n }\r\n\r\n return flattenFavorites(props.menuItems)\r\n})\r\n\r\n/**\r\n * 검색어로 필터링된 메뉴 아이템\r\n * 재귀적으로 children까지 검색\r\n */\r\nconst filteredMenuItems = computed(() => {\r\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\r\n return []\r\n }\r\n\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return props.menuItems\r\n }\r\n\r\n const query = searchQuery.value.toLowerCase().trim()\r\n\r\n /**\r\n * 메뉴 아이템을 재귀적으로 검색\r\n */\r\n const searchInMenu = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\r\n const result: SidebarMenuItem[] = []\r\n\r\n if (!Array.isArray(items)) {\r\n return result\r\n }\r\n\r\n for (const item of items) {\r\n const matchesLabel = item.label?.toLowerCase().includes(query) ?? false\r\n\r\n // 하위 메뉴 검색\r\n let filteredChildren: SidebarMenuItem[] | undefined = undefined\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n filteredChildren = searchInMenu(item.children)\r\n }\r\n\r\n // 현재 메뉴나 하위 메뉴 중 하나라도 매칭되면 포함\r\n if (matchesLabel || (Array.isArray(filteredChildren) && filteredChildren.length > 0)) {\r\n result.push({\r\n ...item,\r\n children: filteredChildren,\r\n })\r\n }\r\n }\r\n\r\n return result\r\n }\r\n\r\n return searchInMenu(props.menuItems)\r\n})\r\n\r\n/**\r\n * 검색 결과에 따라 부모 메뉴 자동 확장\r\n * computed 외부에서 watch를 통해 처리\r\n */\r\nwatch(\r\n () => filteredMenuItems.value,\r\n (filtered) => {\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return\r\n }\r\n\r\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\r\n const findParentsWithMatches = (items: SidebarMenuItem[]): Set<number | string> => {\r\n const keysToExpand = new Set<number | string>()\r\n\r\n const traverse = (menuItems: SidebarMenuItem[]): void => {\r\n if (!Array.isArray(menuItems)) {\r\n return\r\n }\r\n\r\n for (const item of menuItems) {\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n const key = item.menuKey || item.label\r\n keysToExpand.add(key)\r\n traverse(item.children)\r\n }\r\n }\r\n }\r\n\r\n traverse(items)\r\n return keysToExpand\r\n }\r\n\r\n const keysToExpand = findParentsWithMatches(filtered)\r\n keysToExpand.forEach(key => {\r\n expandedKeys.value.add(key)\r\n })\r\n },\r\n { immediate: false }\r\n)\r\n\r\n/**\r\n * 검색어로 필터링된 즐겨찾기 메뉴 아이템\r\n * 즐겨찾기는 이미 평탄화되어 있으므로 단순 필터링만 수행\r\n */\r\nconst filteredFavoriteItems = computed(() => {\r\n if (!Array.isArray(favoriteMenuItems.value) || favoriteMenuItems.value.length === 0) {\r\n return []\r\n }\r\n\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return favoriteMenuItems.value\r\n }\r\n\r\n const query = searchQuery.value.toLowerCase().trim()\r\n\r\n // 즐겨찾기는 이미 평탄화되어 1단계이므로 단순 필터링만 수행\r\n return favoriteMenuItems.value.filter((item) =>\r\n item.label?.toLowerCase().includes(query) ?? false\r\n )\r\n})\r\n\r\n\r\n/**\r\n * 탭 변경 핸들러\r\n * 탭 전환 시 검색 쿼리를 초기화하여 각 탭의 독립적인 검색 상태 유지\r\n */\r\nconst handleTabChange = (tab: TabType) => {\r\n if (activeTab.value !== tab) {\r\n activeTab.value = tab\r\n // 탭 전환 시 검색 쿼리 초기화 (선택적 - UX 고려)\r\n // 검색 쿼리를 유지하려면 아래 라인을 제거하세요\r\n searchQuery.value = ''\r\n }\r\n}\r\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/**\r\n * 즐겨찾기 토글 핸들러\r\n */\r\nconst handleFavoriteToggle = (menuKey: number | string | undefined) => {\r\n if (!menuKey) return\r\n\r\n const isFavorite = props.favorites?.includes(menuKey) ?? false\r\n emit('favoriteChange', menuKey, !isFavorite)\r\n}\r\n\r\n/**\r\n * 메뉴 아이템에서 특정 menuKey를 찾는 헬퍼 함수\r\n */\r\nconst findMenuItemByKey = (items: SidebarMenuItem[], targetKey: number | string): SidebarMenuItem | null => {\r\n for (const item of items) {\r\n const key = item.menuKey || item.label\r\n if (key === targetKey) {\r\n return item\r\n }\r\n if (item.children && item.children.length > 0) {\r\n const found = findMenuItemByKey(item.children, targetKey)\r\n if (found) return found\r\n }\r\n }\r\n return null\r\n}\r\n\r\n/**\r\n * 메뉴가 즐겨찾기인지 확인 (L 타입만 즐겨찾기 가능)\r\n */\r\nconst isFavorite = (menuKey: number | string | undefined): boolean => {\r\n if (!menuKey) return false\r\n if (!props.favorites?.includes(menuKey)) return false\r\n \r\n // menuType이 L인 경우만 즐겨찾기로 인정\r\n const menuItem = findMenuItemByKey(props.menuItems, menuKey)\r\n return menuItem?.menuType === 'L'\r\n}\r\n\r\n/**\r\n * 스타일 프리셋\r\n */\r\nconst STYLE_PRESETS: Record<StyleType, {\r\n containerClass: string\r\n tabContainerClass: string\r\n tabButtonClass: string\r\n searchContainerClass: string\r\n menuContainerClass: string\r\n}> = {\r\n default: {\r\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\r\n tabContainerClass: 'flex border-b border-border',\r\n tabButtonClass: 'flex-1 px-4 py-2 text-sm font-medium transition-colors border-b-2 hover:bg-accent/50',\r\n searchContainerClass: 'p-2 border-b border-border',\r\n menuContainerClass: 'flex-1 overflow-y-auto p-2 space-y-1',\r\n },\r\n minimal: {\r\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\r\n tabContainerClass: 'flex border-b border-border pt-[8px]',\r\n tabButtonClass: 'flex-1 px-2 py-[6.5px] text-xs font-medium transition-colors border-b-2',\r\n searchContainerClass: 'p-1 border-b border-border',\r\n menuContainerClass: 'flex-1 overflow-y-auto p-1 space-y-1',\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 * 루트 클래스\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 <!-- 탭 헤더 -->\r\n <div :class=\"preset.tabContainerClass\">\r\n <button\r\n :class=\"cn(\r\n preset.tabButtonClass,\r\n activeTab === 'menu'\r\n ? 'border-primary text-primary'\r\n : 'border-transparent text-muted-foreground hover:text-foreground'\r\n )\"\r\n @click=\"handleTabChange('menu')\"\r\n >\r\n 기본메뉴\r\n </button>\r\n <button\r\n :class=\"cn(\r\n preset.tabButtonClass,\r\n activeTab === 'favorites'\r\n ? 'border-primary text-primary'\r\n : 'border-transparent text-muted-foreground hover:text-foreground'\r\n )\"\r\n @click=\"handleTabChange('favorites')\"\r\n >\r\n 즐겨찾기\r\n </button>\r\n </div>\r\n\r\n <!-- 검색 영역 -->\r\n <div :class=\"preset.searchContainerClass\">\r\n <div class=\"relative\">\r\n <JIcon\r\n name=\"search\"\r\n size=\"sm\"\r\n class=\"absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground\"\r\n />\r\n <JInput\r\n v-model=\"searchQuery\"\r\n placeholder=\"메뉴 검색...\"\r\n :class=\"cn(\r\n 'pl-8',\r\n props.styletype === 'minimal' && 'h-8 text-xs'\r\n )\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 메뉴 목록 -->\r\n <div :class=\"preset.menuContainerClass\">\r\n <template v-if=\"activeTab === 'menu'\">\r\n <template v-if=\"filteredMenuItems.length > 0\">\r\n <div\r\n v-for=\"(item, index) in filteredMenuItems\"\r\n :key=\"item.menuKey || item.label || index\"\r\n class=\"flex items-center group\"\r\n >\r\n <JDynamicMenuItem\r\n :item=\"item\"\r\n :level=\"0\"\r\n :permissions=\"permissions\"\r\n :active-path=\"activePath\"\r\n :expanded-keys=\"expandedKeys\"\r\n :favorites=\"favorites\"\r\n :on-favorite-toggle=\"handleFavoriteToggle\"\r\n :is-favorite=\"isFavorite\"\r\n :styletype=\"styletype\"\r\n class=\"flex-1\"\r\n @menu-click=\"handleMenuClick\"\r\n @expand-change=\"handleExpandChange\"\r\n />\r\n </div>\r\n </template>\r\n <div v-else class=\"text-center py-8 text-muted-foreground\">\r\n <p>검색 결과가 없습니다.</p>\r\n </div>\r\n </template>\r\n\r\n <template v-else>\r\n <template v-if=\"filteredFavoriteItems.length > 0\">\r\n <JDynamicMenuItem\r\n v-for=\"(item, index) in filteredFavoriteItems\"\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 </template>\r\n <div v-else class=\"text-center py-8 text-muted-foreground\">\r\n <p>즐겨찾기가 없습니다.</p>\r\n </div>\r\n </template>\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","activeTab","ref","searchQuery","activePath","computed","expandedKeys","favoriteMenuItems","flattenFavorites","items","result","item","key","childFavorites","filteredMenuItems","query","searchInMenu","matchesLabel","filteredChildren","watch","filtered","keysToExpand","traverse","menuItems","filteredFavoriteItems","handleTabChange","tab","handleExpandChange","menuKey","expanded","handleMenuClick","event","handleFavoriteToggle","isFavorite","findMenuItemByKey","targetKey","found","STYLE_PRESETS","preset","rootClasses","cn","_createBlock","_Transition","_createElementVNode","_normalizeClass","_unref","_hoisted_1","_createVNode","JIcon","JInput","$event","_createElementBlock","_Fragment","_openBlock","_renderList","index","JDynamicMenuItem","_hoisted_2","_cache","_hoisted_3","_vShow"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"JSidebarAdvanced.vue2.cjs","sources":["../../../../src/components/organisms/JSidebarAdvanced.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useRoute } from 'vue-router'\r\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\r\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\r\nimport JInput from '@/components/atoms/JInput.vue'\r\nimport JIcon from '@/components/atoms/JIcon.vue'\r\nimport { cn } from '@/lib/utils'\r\n\r\n/**\r\n * JSidebarAdvanced - 고급 사이드바 컴포넌트\r\n * Advanced Sidebar Component\r\n * \r\n * @description\r\n * 검색, 즐겨찾기, 다단계 메뉴를 지원하는 고급 사이드바 컴포넌트입니다.\r\n * 기본 메뉴와 즐겨찾기 탭을 제공합니다.\r\n * \r\n * @example\r\n * ```vue\r\n * <JSidebarAdvanced\r\n * :menu-items=\"menuItems\"\r\n * :permissions=\"userPermissions\"\r\n * :favorites=\"favoriteMenuKeys\"\r\n * @menu-click=\"handleMenuClick\"\r\n * @favorite-change=\"handleFavoriteChange\"\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\": \"F\",\r\n * \"menuKey\": 22,\r\n * \"children\": [\r\n * {\r\n * \"label\": \"입고 등록\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 221,\r\n * \"path\": \"/inventory/receiving/register\"\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * ```\r\n */\r\n\r\ntype TabType = 'menu' | 'favorites'\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 favorites?: (number | 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 favorites: () => [],\r\n styletype: 'minimal',\r\n width: '280px',\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 favoriteChange: [menuKey: number | string | undefined, isFavorite: boolean]\r\n}>()\r\n\r\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\r\nconst route = useRoute()\r\n\r\n/**\r\n * 현재 활성 탭\r\n */\r\nconst activeTab = ref<TabType>('menu')\r\n\r\n/**\r\n * 검색어\r\n */\r\nconst searchQuery = ref('')\r\n\r\n/**\r\n * 현재 활성화된 경로\r\n */\r\nconst activePath = computed(() => route.path)\r\n\r\n/**\r\n * 확장된 메뉴 키 목록\r\n */\r\nconst expandedKeys = ref<Set<number | string>>(new Set())\r\n\r\n/**\r\n * 즐겨찾기 메뉴 아이템 목록\r\n * 즐겨찾기는 dept 없이 1단계로만 평탄화하여 표시\r\n */\r\nconst favoriteMenuItems = computed(() => {\r\n if (!Array.isArray(props.favorites) || props.favorites.length === 0) {\r\n return []\r\n }\r\n\r\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\r\n return []\r\n }\r\n\r\n /**\r\n * 메뉴 아이템을 재귀적으로 순회하며 즐겨찾기만 추출\r\n * 즐겨찾기에서는 dept 없이 1단계로만 평탄화\r\n * menuType L(Link)만 포함하고 F(Folder)는 제외\r\n */\r\n const flattenFavorites = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\r\n const result: SidebarMenuItem[] = []\r\n\r\n if (!Array.isArray(items)) {\r\n return result\r\n }\r\n\r\n for (const item of items) {\r\n const key = item.menuKey || item.label\r\n const isFavorite = Array.isArray(props.favorites) && props.favorites.includes(key)\r\n\r\n // 즐겨찾기이고 menuType이 L(Link)인 경우만 추가 (F는 제외)\r\n if (isFavorite && item.menuType === 'L') {\r\n result.push({\r\n ...item,\r\n children: undefined, // children 제거하여 1단계로만 표시\r\n })\r\n }\r\n\r\n // 하위 메뉴도 재귀적으로 탐색\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n const childFavorites = flattenFavorites(item.children)\r\n result.push(...childFavorites)\r\n }\r\n }\r\n\r\n return result\r\n }\r\n\r\n return flattenFavorites(props.menuItems)\r\n})\r\n\r\n/**\r\n * 검색어로 필터링된 메뉴 아이템\r\n * 재귀적으로 children까지 검색\r\n */\r\nconst filteredMenuItems = computed(() => {\r\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\r\n return []\r\n }\r\n\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return props.menuItems\r\n }\r\n\r\n const query = searchQuery.value.toLowerCase().trim()\r\n\r\n /**\r\n * 메뉴 아이템을 재귀적으로 검색\r\n */\r\n const searchInMenu = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\r\n const result: SidebarMenuItem[] = []\r\n\r\n if (!Array.isArray(items)) {\r\n return result\r\n }\r\n\r\n for (const item of items) {\r\n const matchesLabel = item.label?.toLowerCase().includes(query) ?? false\r\n\r\n // 하위 메뉴 검색\r\n let filteredChildren: SidebarMenuItem[] | undefined = undefined\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n filteredChildren = searchInMenu(item.children)\r\n }\r\n\r\n // 현재 메뉴나 하위 메뉴 중 하나라도 매칭되면 포함\r\n if (matchesLabel || (Array.isArray(filteredChildren) && filteredChildren.length > 0)) {\r\n result.push({\r\n ...item,\r\n children: filteredChildren,\r\n })\r\n }\r\n }\r\n\r\n return result\r\n }\r\n\r\n return searchInMenu(props.menuItems)\r\n})\r\n\r\n/**\r\n * 검색 결과에 따라 부모 메뉴 자동 확장\r\n * computed 외부에서 watch를 통해 처리\r\n */\r\nwatch(\r\n () => filteredMenuItems.value,\r\n (filtered) => {\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return\r\n }\r\n\r\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\r\n const findParentsWithMatches = (items: SidebarMenuItem[]): Set<number | string> => {\r\n const keysToExpand = new Set<number | string>()\r\n\r\n const traverse = (menuItems: SidebarMenuItem[]): void => {\r\n if (!Array.isArray(menuItems)) {\r\n return\r\n }\r\n\r\n for (const item of menuItems) {\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n const key = item.menuKey || item.label\r\n keysToExpand.add(key)\r\n traverse(item.children)\r\n }\r\n }\r\n }\r\n\r\n traverse(items)\r\n return keysToExpand\r\n }\r\n\r\n const keysToExpand = findParentsWithMatches(filtered)\r\n keysToExpand.forEach(key => {\r\n expandedKeys.value.add(key)\r\n })\r\n },\r\n { immediate: false }\r\n)\r\n\r\n/**\r\n * 검색어로 필터링된 즐겨찾기 메뉴 아이템\r\n * 즐겨찾기는 이미 평탄화되어 있으므로 단순 필터링만 수행\r\n */\r\nconst filteredFavoriteItems = computed(() => {\r\n if (!Array.isArray(favoriteMenuItems.value) || favoriteMenuItems.value.length === 0) {\r\n return []\r\n }\r\n\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return favoriteMenuItems.value\r\n }\r\n\r\n const query = searchQuery.value.toLowerCase().trim()\r\n\r\n // 즐겨찾기는 이미 평탄화되어 1단계이므로 단순 필터링만 수행\r\n return favoriteMenuItems.value.filter((item) =>\r\n item.label?.toLowerCase().includes(query) ?? false\r\n )\r\n})\r\n\r\n\r\n/**\r\n * 탭 변경 핸들러\r\n * 탭 전환 시 검색 쿼리를 초기화하여 각 탭의 독립적인 검색 상태 유지\r\n */\r\nconst handleTabChange = (tab: TabType) => {\r\n if (activeTab.value !== tab) {\r\n activeTab.value = tab\r\n // 탭 전환 시 검색 쿼리 초기화 (선택적 - UX 고려)\r\n // 검색 쿼리를 유지하려면 아래 라인을 제거하세요\r\n searchQuery.value = ''\r\n }\r\n}\r\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/**\r\n * 즐겨찾기 토글 핸들러\r\n */\r\nconst handleFavoriteToggle = (menuKey: number | string | undefined) => {\r\n if (!menuKey) return\r\n\r\n const isFavorite = props.favorites?.includes(menuKey) ?? false\r\n emit('favoriteChange', menuKey, !isFavorite)\r\n}\r\n\r\n/**\r\n * 메뉴 아이템에서 특정 menuKey를 찾는 헬퍼 함수\r\n */\r\nconst findMenuItemByKey = (items: SidebarMenuItem[], targetKey: number | string): SidebarMenuItem | null => {\r\n for (const item of items) {\r\n const key = item.menuKey || item.label\r\n if (key === targetKey) {\r\n return item\r\n }\r\n if (item.children && item.children.length > 0) {\r\n const found = findMenuItemByKey(item.children, targetKey)\r\n if (found) return found\r\n }\r\n }\r\n return null\r\n}\r\n\r\n/**\r\n * 메뉴가 즐겨찾기인지 확인 (L 타입만 즐겨찾기 가능)\r\n */\r\nconst isFavorite = (menuKey: number | string | undefined): boolean => {\r\n if (!menuKey) return false\r\n if (!props.favorites?.includes(menuKey)) return false\r\n \r\n // menuType이 L인 경우만 즐겨찾기로 인정\r\n const menuItem = findMenuItemByKey(props.menuItems, menuKey)\r\n return menuItem?.menuType === 'L'\r\n}\r\n\r\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n tabContainerClass: string\n tabButtonClass: string\n searchContainerClass: string\n menuContainerClass: string\n}> = {\n default: {\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\n tabContainerClass: 'flex border-b border-border',\n tabButtonClass: 'flex-1 px-3 py-1.5 text-xs font-medium transition-colors border-b-2 hover:bg-accent/50',\n searchContainerClass: 'p-1.5 border-b border-border',\n menuContainerClass: 'flex-1 overflow-y-auto p-1.5 space-y-0.5',\n },\n minimal: {\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\n tabContainerClass: 'flex border-b border-border',\n tabButtonClass: 'flex-1 px-2 py-1 text-xs font-medium transition-colors border-b-2',\n searchContainerClass: 'p-1 border-b border-border',\n menuContainerClass: 'flex-1 overflow-y-auto p-1 space-y-0.5',\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 <!-- 탭 헤더 -->\r\n <div :class=\"preset.tabContainerClass\">\r\n <button\r\n :class=\"cn(\r\n preset.tabButtonClass,\r\n activeTab === 'menu'\r\n ? 'border-primary text-primary'\r\n : 'border-transparent text-muted-foreground hover:text-foreground'\r\n )\"\r\n @click=\"handleTabChange('menu')\"\r\n >\r\n 기본메뉴\r\n </button>\r\n <button\r\n :class=\"cn(\r\n preset.tabButtonClass,\r\n activeTab === 'favorites'\r\n ? 'border-primary text-primary'\r\n : 'border-transparent text-muted-foreground hover:text-foreground'\r\n )\"\r\n @click=\"handleTabChange('favorites')\"\r\n >\r\n 즐겨찾기\r\n </button>\r\n </div>\r\n\r\n <!-- 검색 영역 -->\r\n <div :class=\"preset.searchContainerClass\">\r\n <div class=\"relative\">\r\n <JIcon\r\n name=\"search\"\r\n size=\"sm\"\r\n class=\"absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground\"\r\n />\r\n <JInput\r\n v-model=\"searchQuery\"\r\n placeholder=\"메뉴 검색...\"\r\n :class=\"cn(\r\n 'pl-8',\r\n props.styletype === 'minimal' && 'h-8 text-xs'\r\n )\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 메뉴 목록 -->\r\n <div :class=\"preset.menuContainerClass\">\r\n <template v-if=\"activeTab === 'menu'\">\r\n <template v-if=\"filteredMenuItems.length > 0\">\r\n <div\r\n v-for=\"(item, index) in filteredMenuItems\"\r\n :key=\"item.menuKey || item.label || index\"\r\n class=\"flex items-center group\"\r\n >\r\n <JDynamicMenuItem\r\n :item=\"item\"\r\n :level=\"0\"\r\n :permissions=\"permissions\"\r\n :active-path=\"activePath\"\r\n :expanded-keys=\"expandedKeys\"\r\n :favorites=\"favorites\"\r\n :on-favorite-toggle=\"handleFavoriteToggle\"\r\n :is-favorite=\"isFavorite\"\r\n :styletype=\"styletype\"\r\n class=\"flex-1\"\r\n @menu-click=\"handleMenuClick\"\r\n @expand-change=\"handleExpandChange\"\r\n />\r\n </div>\r\n </template>\n <div v-else class=\"text-center py-8 text-muted-foreground\">\n <p class=\"text-xs\">검색 결과가 없습니다.</p>\n </div>\n </template>\n\n <template v-else>\n <template v-if=\"filteredFavoriteItems.length > 0\">\n <JDynamicMenuItem\n v-for=\"(item, index) in filteredFavoriteItems\"\n :key=\"item.menuKey || item.label || index\"\n :item=\"item\"\n :level=\"0\"\n :permissions=\"permissions\"\n :active-path=\"activePath\"\n :expanded-keys=\"expandedKeys\"\n :styletype=\"styletype\"\n @menu-click=\"handleMenuClick\"\n @expand-change=\"handleExpandChange\"\n />\n </template>\n <div v-else class=\"text-center py-8 text-muted-foreground\">\n <p class=\"text-xs\">즐겨찾기가 없습니다.</p>\n </div>\n </template>\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","activeTab","ref","searchQuery","activePath","computed","expandedKeys","favoriteMenuItems","flattenFavorites","items","result","item","key","childFavorites","filteredMenuItems","query","searchInMenu","matchesLabel","filteredChildren","watch","filtered","keysToExpand","traverse","menuItems","filteredFavoriteItems","handleTabChange","tab","handleExpandChange","menuKey","expanded","handleMenuClick","event","handleFavoriteToggle","isFavorite","findMenuItemByKey","targetKey","found","STYLE_PRESETS","preset","rootClasses","cn","_createBlock","_Transition","_createElementVNode","_normalizeClass","_unref","_hoisted_1","_createVNode","JIcon","JInput","$event","_createElementBlock","_Fragment","_openBlock","_renderList","index","JDynamicMenuItem","_hoisted_2","_cache","_hoisted_3","_vShow"],"mappings":"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"}
|