@imksh/create 1.0.28 → 1.0.31
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/package.json +1 -1
- package/src/utils/askTemplate.js +2 -1
- package/templates/layers/electron/base/electron/main.js +262 -0
- package/templates/layers/electron/base/electron/preload.js +37 -0
- package/templates/layers/electron/base/electron-builder.json5 +68 -0
- package/templates/layers/electron/javascript/_gitignore +38 -0
- package/templates/layers/electron/javascript/package.json +49 -0
- package/templates/layers/electron/javascript/src/components/layout/SidebarLayout.jsx +43 -0
- package/templates/layers/electron/javascript/src/components/ui/TitleBar.jsx +130 -0
- package/templates/layers/electron/javascript/src/config/appConfig.js +51 -0
- package/templates/layers/electron/javascript/src/hooks/useElectron.js +68 -0
- package/templates/layers/electron/javascript/src/main.jsx +17 -0
- package/templates/layers/electron/javascript/src/store/useUiStore.js +59 -0
- package/templates/layers/electron/javascript/vite.config.js +29 -0
- package/templates/layers/electron/typescript/_gitignore +38 -0
- package/templates/layers/electron/typescript/electron/main.ts +213 -0
- package/templates/layers/electron/typescript/electron/preload.ts +52 -0
- package/templates/layers/electron/typescript/package.json +52 -0
- package/templates/layers/electron/typescript/src/components/layout/SidebarLayout.tsx +42 -0
- package/templates/layers/electron/typescript/src/components/ui/TitleBar.tsx +120 -0
- package/templates/layers/electron/typescript/src/config/appConfig.ts +52 -0
- package/templates/layers/electron/typescript/src/hooks/useElectron.ts +68 -0
- package/templates/layers/electron/typescript/src/main.tsx +17 -0
- package/templates/layers/electron/typescript/src/store/useUiStore.ts +97 -0
- package/templates/layers/electron/typescript/src/vite-env.d.ts +13 -0
- package/templates/layers/electron/typescript/tsconfig.json +25 -0
- package/templates/layers/electron/typescript/tsconfig.node.json +11 -0
- package/templates/layers/electron/typescript/vite.config.ts +29 -0
- package/templates/layers/next/javascript/src/components/common/Breadcrumbs.jsx +44 -6
- package/templates/layers/next/javascript/src/components/common/Loading.jsx +1 -0
- package/templates/layers/next/javascript/src/components/common/LottieIcon.jsx +1 -0
- package/templates/layers/next/javascript/src/components/common/Pagination.jsx +170 -0
- package/templates/layers/next/javascript/src/components/common/SidebarModal.jsx +180 -0
- package/templates/layers/next/javascript/src/components/common/StatsCard.jsx +168 -0
- package/templates/layers/next/javascript/src/components/common/Table.jsx +191 -41
- package/templates/layers/next/javascript/src/components/common/Tabs.jsx +187 -0
- package/templates/layers/next/javascript/src/components/common/ToggleSwitch.jsx +4 -3
- package/templates/layers/next/javascript/src/components/layout/ProtectedRoute.jsx +2 -1
- package/templates/layers/next/javascript/src/components/layout/PublicLayout.jsx +3 -6
- package/templates/layers/next/javascript/src/components/layout/SidebarLayout.jsx +4 -17
- package/templates/layers/next/javascript/src/components/modals/ConfirmModal.jsx +4 -12
- package/templates/layers/next/javascript/src/components/modals/Modal.jsx +50 -19
- package/templates/layers/next/javascript/src/components/ui/Input.jsx +50 -0
- package/templates/layers/next/{typescript/src/components/ui/sidebar.tsx → javascript/src/components/ui/Sidebar.jsx} +65 -53
- package/templates/layers/next/javascript/src/components/ui/SidebarHeader.jsx +11 -6
- package/templates/layers/next/javascript/src/config/appConfig.js +4 -4
- package/templates/layers/next/javascript/src/hooks/useWindowSize.js +2 -3
- package/templates/layers/next/javascript/src/store/useUiStore.js +9 -4
- package/templates/layers/next/typescript/src/components/common/Breadcrumbs.tsx +57 -8
- package/templates/layers/next/typescript/src/components/common/Loading.tsx +1 -0
- package/templates/layers/next/typescript/src/components/common/Pagination.tsx +186 -0
- package/templates/layers/next/typescript/src/components/common/SidebarModal.tsx +200 -0
- package/templates/layers/next/typescript/src/components/common/StatsCard.tsx +232 -0
- package/templates/layers/next/typescript/src/components/common/Table.tsx +201 -35
- package/templates/layers/next/typescript/src/components/common/Tabs.tsx +190 -0
- package/templates/layers/next/typescript/src/components/common/ToggleSwitch.tsx +12 -8
- package/templates/layers/next/typescript/src/components/layout/PublicLayout.tsx +8 -6
- package/templates/layers/next/typescript/src/components/layout/SidebarLayout.tsx +8 -17
- package/templates/layers/next/typescript/src/components/modals/ConfirmModal.tsx +1 -0
- package/templates/layers/next/typescript/src/components/modals/Modal.tsx +67 -21
- package/templates/layers/next/typescript/src/components/ui/Button.tsx +1 -0
- package/templates/layers/next/typescript/src/components/ui/Input.tsx +40 -60
- package/templates/layers/next/{javascript/src/components/ui/sidebar.jsx → typescript/src/components/ui/Sidebar.tsx} +77 -44
- package/templates/layers/next/typescript/src/components/ui/SidebarHeader.tsx +16 -10
- package/templates/layers/next/typescript/src/config/appConfig.ts +4 -4
- package/templates/layers/next/typescript/src/hooks/useWindowSize.ts +2 -3
- package/templates/layers/next/typescript/src/store/useUiStore.ts +14 -4
- package/templates/layers/node/javascript/package.json +2 -1
- package/templates/layers/node/javascript/src/controllers/push.controller.js +35 -14
- package/templates/layers/node/javascript/src/models/pushSubscription.model.js +5 -0
- package/templates/layers/node/javascript/src/utils/pushHelper.js +59 -12
- package/templates/layers/node/typescript/package-lock.json +3795 -0
- package/templates/layers/node/typescript/package.json +3 -2
- package/templates/layers/node/typescript/src/controllers/push.controller.ts +35 -14
- package/templates/layers/node/typescript/src/models/pushSubscription.model.ts +6 -0
- package/templates/layers/node/typescript/src/services/auth.service.ts +3 -3
- package/templates/layers/node/typescript/src/utils/pushHelper.ts +66 -12
- package/templates/layers/node-prisma/javascript/package.json +6 -3
- package/templates/layers/node-prisma/javascript/prisma/schema.prisma +20 -9
- package/templates/layers/node-prisma/javascript/prisma.config.js +12 -0
- package/templates/layers/node-prisma/javascript/src/config/{db.js → prisma.js} +9 -1
- package/templates/layers/node-prisma/javascript/src/controllers/push.controller.js +58 -19
- package/templates/layers/node-prisma/javascript/src/utils/pushHelper.js +62 -14
- package/templates/layers/node-prisma/typescript/package-lock.json +4808 -0
- package/templates/layers/node-prisma/typescript/package.json +8 -4
- package/templates/layers/node-prisma/typescript/prisma/schema.prisma +20 -9
- package/templates/layers/node-prisma/typescript/prisma.config.ts +12 -0
- package/templates/layers/node-prisma/typescript/src/config/{db.ts → prisma.ts} +9 -1
- package/templates/layers/node-prisma/typescript/src/controllers/push.controller.ts +67 -22
- package/templates/layers/node-prisma/typescript/src/index.ts +1 -1
- package/templates/layers/node-prisma/typescript/src/middleware/auth.middleware.ts +15 -5
- package/templates/layers/node-prisma/typescript/src/services/auth.service.ts +134 -128
- package/templates/layers/node-prisma/typescript/src/utils/pushHelper.ts +69 -14
- package/templates/layers/prisma/typescript/prisma/schema.prisma +35 -10
- package/templates/layers/react/javascript/src/components/common/Breadcrumbs.jsx +62 -58
- package/templates/layers/react/javascript/src/components/common/Pagination.jsx +164 -76
- package/templates/layers/react/javascript/src/components/common/SidebarModal.jsx +179 -0
- package/templates/layers/react/javascript/src/components/common/StatsCard.jsx +167 -0
- package/templates/layers/react/javascript/src/components/common/Table.jsx +248 -132
- package/templates/layers/react/javascript/src/components/common/Tabs.jsx +164 -112
- package/templates/layers/react/javascript/src/components/common/ToggleSwitch.jsx +3 -3
- package/templates/layers/react/javascript/src/components/layout/SidebarLayout.jsx +4 -12
- package/templates/layers/react/javascript/src/components/modals/Modal.jsx +53 -18
- package/templates/layers/react/javascript/src/components/ui/Input.jsx +49 -0
- package/templates/layers/react/javascript/src/components/ui/Sidebar.jsx +215 -0
- package/templates/layers/react/javascript/src/components/ui/SidebarHeader.jsx +25 -30
- package/templates/layers/react/javascript/src/config/appConfig.js +3 -3
- package/templates/layers/react/javascript/src/hooks/useWindowSize.js +2 -2
- package/templates/layers/react/typescript/src/components/common/Breadcrumbs.tsx +32 -6
- package/templates/layers/react/typescript/src/components/common/Pagination.tsx +151 -57
- package/templates/layers/react/typescript/src/components/common/SidebarModal.tsx +199 -0
- package/templates/layers/react/typescript/src/components/common/StatsCard.tsx +231 -0
- package/templates/layers/react/typescript/src/components/common/Table.tsx +197 -34
- package/templates/layers/react/typescript/src/components/common/Tabs.tsx +56 -12
- package/templates/layers/react/typescript/src/components/common/ToggleSwitch.tsx +15 -3
- package/templates/layers/react/typescript/src/components/layout/SidebarLayout.tsx +3 -6
- package/templates/layers/react/typescript/src/components/modals/Modal.tsx +151 -0
- package/templates/layers/react/typescript/src/components/ui/Input.tsx +58 -0
- package/templates/layers/react/typescript/src/components/ui/Sidebar.tsx +116 -53
- package/templates/layers/react/typescript/src/components/ui/SidebarHeader.tsx +5 -4
- package/templates/layers/react/typescript/src/config/appConfig.ts +3 -3
- package/templates/layers/react/typescript/src/hooks/useWindowSize.ts +2 -3
- package/templates/layers/react-native/base/src/components/ui/BiometricLock.tsx +2 -1
- package/templates/layers/react-native/base/src/config/appConfig.ts +44 -0
- package/templates/presets/electron/preset.json +9 -0
- package/templates/presets/electron-ts/preset.json +9 -0
- package/templates/layers/react/javascript/src/components/ui/sidebar.jsx +0 -169
|
@@ -1,134 +1,186 @@
|
|
|
1
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
1
|
import React from "react";
|
|
3
2
|
import { ChevronDown } from "lucide-react";
|
|
4
3
|
import { motion } from "framer-motion";
|
|
5
|
-
|
|
4
|
+
|
|
5
|
+
export const Tabs = ({
|
|
6
6
|
tabs,
|
|
7
7
|
activeTab,
|
|
8
8
|
onChange,
|
|
9
|
-
variant = "
|
|
10
|
-
className = "",
|
|
9
|
+
variant = "box",
|
|
10
|
+
className = "bg-base-200 w-fit",
|
|
11
11
|
dropdown = false,
|
|
12
|
+
disabled = false,
|
|
13
|
+
size = "base",
|
|
12
14
|
}) => {
|
|
13
15
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
16
|
+
|
|
17
|
+
const getTabSizeClass = () => {
|
|
18
|
+
switch (size) {
|
|
19
|
+
case "xs":
|
|
20
|
+
return "text-xs px-2.5 h-7 min-h-7";
|
|
21
|
+
case "sm":
|
|
22
|
+
return "text-sm px-3 h-8 min-h-8";
|
|
23
|
+
case "base":
|
|
24
|
+
return "text-base px-4 h-10 min-h-10";
|
|
25
|
+
case "lg":
|
|
26
|
+
return "text-lg px-6 h-12 min-h-12";
|
|
27
|
+
case "xl":
|
|
28
|
+
return "text-xl px-6 h-14 min-h-14";
|
|
29
|
+
case "2xl":
|
|
30
|
+
return "text-2xl px-8 h-16 min-h-16";
|
|
31
|
+
default:
|
|
32
|
+
return "text-base px-4 h-10 min-h-10";
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const getBtnSizeClass = () => {
|
|
37
|
+
switch (size) {
|
|
38
|
+
case "xs":
|
|
39
|
+
return "btn-xs text-xs";
|
|
40
|
+
case "sm":
|
|
41
|
+
return "btn-sm text-sm";
|
|
42
|
+
case "base":
|
|
43
|
+
return "text-base";
|
|
44
|
+
case "lg":
|
|
45
|
+
return "btn-lg text-lg";
|
|
46
|
+
case "xl":
|
|
47
|
+
return "btn-lg text-xl";
|
|
48
|
+
case "2xl":
|
|
49
|
+
return "btn-lg text-2xl";
|
|
50
|
+
default:
|
|
51
|
+
return "text-base";
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const tabSizeClass = getTabSizeClass();
|
|
56
|
+
const btnSizeClass = getBtnSizeClass();
|
|
57
|
+
|
|
58
|
+
// Close dropdown if user clicks outside
|
|
14
59
|
React.useEffect(() => {
|
|
15
60
|
if (!dropdown || !isOpen) return;
|
|
16
61
|
const closeMenu = () => setIsOpen(false);
|
|
17
62
|
document.addEventListener("click", closeMenu);
|
|
18
63
|
return () => document.removeEventListener("click", closeMenu);
|
|
19
64
|
}, [dropdown, isOpen]);
|
|
65
|
+
|
|
20
66
|
const renderDropdown = () => {
|
|
21
67
|
if (!dropdown) return null;
|
|
22
68
|
const activeItem = tabs.find((t) => t.id === activeTab);
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
tab.
|
|
64
|
-
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
return (
|
|
70
|
+
<div
|
|
71
|
+
className="relative md:hidden w-full max-w-xs z-[50]"
|
|
72
|
+
onClick={(e) => e.stopPropagation()}
|
|
73
|
+
>
|
|
74
|
+
{/* Trigger Button */}
|
|
75
|
+
<button
|
|
76
|
+
type="button"
|
|
77
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
78
|
+
disabled={disabled}
|
|
79
|
+
className={`btn ${btnSizeClass} bg-base-200 border-base-300 border flex w-full items-center justify-between px-3 text-base-content ${disabled ? "opacity-50 cursor-not-allowed" : ""}`}
|
|
80
|
+
>
|
|
81
|
+
<div className="flex items-center gap-1.5">
|
|
82
|
+
{activeItem?.icon}
|
|
83
|
+
<span className="font-semibold">{activeItem?.label}</span>
|
|
84
|
+
</div>
|
|
85
|
+
<ChevronDown
|
|
86
|
+
size={14}
|
|
87
|
+
className={`opacity-50 transition-transform ${isOpen ? "rotate-180" : ""}`}
|
|
88
|
+
/>
|
|
89
|
+
</button>
|
|
90
|
+
|
|
91
|
+
{/* Dropdown Menu */}
|
|
92
|
+
{isOpen && (
|
|
93
|
+
<div className="absolute top-full left-0 right-0 mt-1 bg-base-100 border border-base-200 shadow rounded-lg py-1 animate-in fade-in slide-in-from-top-2">
|
|
94
|
+
{tabs.map((tab) => (
|
|
95
|
+
<button
|
|
96
|
+
key={tab.id}
|
|
97
|
+
onClick={() => {
|
|
98
|
+
onChange(tab.id);
|
|
99
|
+
setIsOpen(false);
|
|
100
|
+
}}
|
|
101
|
+
type="button"
|
|
102
|
+
className={`w-full flex items-center gap-2 px-3 py-2 transition-colors ${size === "base" ? "text-sm" : `text-${size}`} ${
|
|
103
|
+
activeTab === tab.id
|
|
104
|
+
? "bg-primary/10 text-primary font-semibold"
|
|
105
|
+
: "hover:bg-base-200 text-base-content/80"
|
|
106
|
+
}`}
|
|
107
|
+
>
|
|
108
|
+
{tab.icon}
|
|
109
|
+
{tab.label}
|
|
110
|
+
</button>
|
|
111
|
+
))}
|
|
112
|
+
</div>
|
|
113
|
+
)}
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
69
116
|
};
|
|
117
|
+
|
|
70
118
|
if (variant === "box") {
|
|
71
|
-
return
|
|
72
|
-
|
|
73
|
-
renderDropdown()
|
|
74
|
-
|
|
75
|
-
className
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
119
|
+
return (
|
|
120
|
+
<>
|
|
121
|
+
{renderDropdown()}
|
|
122
|
+
<div
|
|
123
|
+
className={`tabs tabs-boxed p-1 flex-nowrap overflow-x-auto hide-scrollbar shrink-0 rounded-lg ${dropdown ? "hidden md:flex" : "flex"} ${className}`}
|
|
124
|
+
>
|
|
125
|
+
{tabs.map((tab) => (
|
|
126
|
+
<button
|
|
127
|
+
type="button"
|
|
128
|
+
key={tab.id}
|
|
129
|
+
onClick={() => onChange(tab.id)}
|
|
130
|
+
disabled={disabled}
|
|
131
|
+
className={`tab ${tabSizeClass} whitespace-nowrap flex items-center rounded-lg gap-2 relative z-0 ${
|
|
132
|
+
activeTab === tab.id
|
|
133
|
+
? "text-primary-content"
|
|
134
|
+
: "text-base-content/70 hover:text-base-content "
|
|
135
|
+
} ${disabled ? "opacity-50 cursor-not-allowed" : ""}`}
|
|
136
|
+
>
|
|
137
|
+
{activeTab === tab.id && (
|
|
138
|
+
<motion.div
|
|
139
|
+
layoutId="activeTabBox"
|
|
140
|
+
className="absolute inset-0 bg-primary rounded-lg -z-10"
|
|
141
|
+
transition={{ type: "spring", duration: 0, bounce: 0.2 }}
|
|
142
|
+
/>
|
|
143
|
+
)}
|
|
144
|
+
{tab.icon}
|
|
145
|
+
{tab.label}
|
|
146
|
+
</button>
|
|
147
|
+
))}
|
|
148
|
+
</div>
|
|
149
|
+
</>
|
|
150
|
+
);
|
|
99
151
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
tab.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
152
|
+
|
|
153
|
+
// default: underline
|
|
154
|
+
return (
|
|
155
|
+
<>
|
|
156
|
+
{renderDropdown()}
|
|
157
|
+
<div
|
|
158
|
+
className={`tabs tabs-bordered ${dropdown ? "hidden md:flex" : "flex"} ${className}`}
|
|
159
|
+
>
|
|
160
|
+
{tabs.map((tab) => (
|
|
161
|
+
<button
|
|
162
|
+
type="button"
|
|
163
|
+
key={tab.id}
|
|
164
|
+
onClick={() => onChange(tab.id)}
|
|
165
|
+
disabled={disabled}
|
|
166
|
+
className={`tab ${tabSizeClass} whitespace-nowrap relative !border-transparent ${
|
|
167
|
+
activeTab === tab.id
|
|
168
|
+
? "font-semibold text-primary"
|
|
169
|
+
: "text-base-content/70 hover:text-base-content"
|
|
170
|
+
} ${disabled ? "opacity-50 cursor-not-allowed" : ""}`}
|
|
171
|
+
>
|
|
172
|
+
{activeTab === tab.id && (
|
|
173
|
+
<motion.div
|
|
174
|
+
layoutId="activeTabUnderline"
|
|
175
|
+
className="absolute bottom-0 left-0 right-0 h-0.5 bg-primary"
|
|
176
|
+
transition={{ type: "spring", duration: 0.5, bounce: 0.2 }}
|
|
177
|
+
/>
|
|
178
|
+
)}
|
|
179
|
+
{tab.icon && <span className="mr-2">{tab.icon}</span>}
|
|
180
|
+
{tab.label}
|
|
181
|
+
</button>
|
|
182
|
+
))}
|
|
183
|
+
</div>
|
|
184
|
+
</>
|
|
185
|
+
);
|
|
133
186
|
};
|
|
134
|
-
export { Tabs };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { motion } from "motion/react";
|
|
3
3
|
|
|
4
|
-
const ToggleSwitch = ({ checked, onChange, label }) => {
|
|
4
|
+
const ToggleSwitch = ({ checked, onChange, label, className }) => {
|
|
5
5
|
return (
|
|
6
6
|
<div
|
|
7
|
-
className=
|
|
7
|
+
className={`flex items-center gap-3 cursor-pointer select-none w-fit group ${className}`}
|
|
8
8
|
onClick={() => onChange(!checked)}
|
|
9
9
|
>
|
|
10
10
|
<span className="text-sm font-bold">{label}</span>
|
|
@@ -16,7 +16,7 @@ const ToggleSwitch = ({ checked, onChange, label }) => {
|
|
|
16
16
|
}`}
|
|
17
17
|
>
|
|
18
18
|
<motion.div
|
|
19
|
-
className={`w-4 h-4 rounded-full shadow
|
|
19
|
+
className={`w-4 h-4 rounded-full shadow ${
|
|
20
20
|
checked ? "bg-white" : "bg-base-content/40"
|
|
21
21
|
}`}
|
|
22
22
|
layout
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
1
|
import { Outlet, useLocation } from "react-router-dom";
|
|
3
2
|
import SidebarHeader from "../ui/SidebarHeader";
|
|
4
|
-
import Sidebar from "../ui/
|
|
3
|
+
import Sidebar from "../ui/Sidebar";
|
|
5
4
|
import { useUiStore } from "../../store/useUiStore";
|
|
6
|
-
import appConfig from "../../config/appConfig";
|
|
7
5
|
|
|
8
6
|
const SidebarLayout = () => {
|
|
9
7
|
const { headerTitle, headerActions, setHeaderTitle, setHeaderActions } =
|
|
10
8
|
useUiStore();
|
|
11
9
|
const { pathname } = useLocation();
|
|
12
10
|
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
setHeaderTitle(appConfig.app.name);
|
|
16
|
-
setHeaderActions(null);
|
|
17
|
-
}, [pathname, setHeaderTitle, setHeaderActions]);
|
|
11
|
+
// Layout no longer resets title on every route change.
|
|
12
|
+
// Individual pages are responsible for setting their own title via useUiStore.
|
|
18
13
|
|
|
19
14
|
return (
|
|
20
15
|
<div className="flex h-screen overflow-hidden">
|
|
@@ -23,10 +18,7 @@ const SidebarLayout = () => {
|
|
|
23
18
|
<div className="flex flex-1 flex-col overflow-hidden">
|
|
24
19
|
<SidebarHeader title={headerTitle} actions={headerActions} />
|
|
25
20
|
|
|
26
|
-
<main
|
|
27
|
-
className="flex-1 h-full overflow-y-auto px-2 py-6 md:p-6 max-w-7xl"
|
|
28
|
-
data-lenis-prevent
|
|
29
|
-
>
|
|
21
|
+
<main className="flex-1 h-full overflow-y-auto " data-lenis-prevent>
|
|
30
22
|
<Outlet />
|
|
31
23
|
</main>
|
|
32
24
|
</div>
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
2
|
import { createPortal } from "react-dom";
|
|
3
3
|
import { IoClose } from "react-icons/io5";
|
|
4
|
+
import { useUiStore } from "../../store/useUiStore";
|
|
4
5
|
|
|
5
6
|
const sizes = {
|
|
6
7
|
sm: "max-w-sm",
|
|
7
8
|
md: "max-w-md",
|
|
8
9
|
lg: "max-w-lg",
|
|
9
|
-
xl: "max-w-
|
|
10
|
-
"2xl": "max-w-
|
|
10
|
+
xl: "max-w-xl",
|
|
11
|
+
"2xl": "max-w-2xl",
|
|
12
|
+
"3xl": "max-w-3xl",
|
|
13
|
+
"4xl": "max-w-4xl",
|
|
14
|
+
"5xl": "max-w-5xl",
|
|
15
|
+
"6xl": "max-w-6xl",
|
|
16
|
+
"7xl": "max-w-7xl",
|
|
11
17
|
full: "max-w-7xl",
|
|
12
18
|
};
|
|
13
19
|
|
|
@@ -16,12 +22,27 @@ const Modal = ({
|
|
|
16
22
|
onClose,
|
|
17
23
|
title,
|
|
18
24
|
children,
|
|
19
|
-
size = "
|
|
25
|
+
size = "4xl",
|
|
20
26
|
closeOnBackdrop = true,
|
|
21
27
|
closeOnEsc = true,
|
|
22
28
|
showCloseButton = true,
|
|
29
|
+
hideHeader = false,
|
|
30
|
+
className = "",
|
|
31
|
+
bodyClass = "p-2 sm:p-4",
|
|
23
32
|
footer,
|
|
33
|
+
height,
|
|
24
34
|
}) => {
|
|
35
|
+
const setModalOpen = useUiStore((state) => state.setModalOpen);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (open) {
|
|
39
|
+
setModalOpen(true);
|
|
40
|
+
return () => {
|
|
41
|
+
setModalOpen(false);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}, [open, setModalOpen]);
|
|
45
|
+
|
|
25
46
|
useEffect(() => {
|
|
26
47
|
if (!open || !closeOnEsc) return;
|
|
27
48
|
|
|
@@ -33,7 +54,9 @@ const Modal = ({
|
|
|
33
54
|
|
|
34
55
|
document.addEventListener("keydown", handleKeyDown);
|
|
35
56
|
|
|
36
|
-
return () =>
|
|
57
|
+
return () => {
|
|
58
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
59
|
+
};
|
|
37
60
|
}, [open, closeOnEsc, onClose]);
|
|
38
61
|
|
|
39
62
|
if (!open) return null;
|
|
@@ -50,35 +73,47 @@ const Modal = ({
|
|
|
50
73
|
<div
|
|
51
74
|
className={`
|
|
52
75
|
relative
|
|
76
|
+
flex flex-col overflow-hidden max-h-[90vh]
|
|
53
77
|
w-full
|
|
54
78
|
${sizes[size]}
|
|
55
79
|
rounded-2xl
|
|
56
80
|
bg-base-100
|
|
57
|
-
shadow-
|
|
81
|
+
shadow-md
|
|
58
82
|
border border-base-300
|
|
59
83
|
animate-in zoom-in-95 fade-in duration-200
|
|
84
|
+
${className}
|
|
60
85
|
`}
|
|
86
|
+
style={height ? { height } : undefined}
|
|
61
87
|
>
|
|
62
88
|
{/* Header */}
|
|
63
|
-
|
|
64
|
-
<
|
|
89
|
+
{!hideHeader && (title || showCloseButton) && (
|
|
90
|
+
<div className="flex items-center justify-between border-b border-base-300 px-6 py-4 shrink-0">
|
|
91
|
+
{title && <h2 className="text-lg font-bold">{title}</h2>}
|
|
65
92
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
93
|
+
{showCloseButton && (
|
|
94
|
+
<button
|
|
95
|
+
className="btn btn-circle btn-sm btn-error btn-soft text-error/70 hover:text-error hover:bg-error/20 hover:shadow-sm hover:rotate-180 transition-transform duration-200"
|
|
96
|
+
onClick={onClose}
|
|
97
|
+
>
|
|
98
|
+
<IoClose size={20} className="" />
|
|
99
|
+
</button>
|
|
100
|
+
)}
|
|
101
|
+
</div>
|
|
102
|
+
)}
|
|
75
103
|
|
|
76
104
|
{/* Body */}
|
|
77
|
-
<div
|
|
105
|
+
<div
|
|
106
|
+
className={`flex-1 min-h-0 overflow-y-auto ${bodyClass}`}
|
|
107
|
+
data-lenis-prevent="true"
|
|
108
|
+
>
|
|
109
|
+
{children}
|
|
110
|
+
</div>
|
|
78
111
|
|
|
79
112
|
{/* Footer */}
|
|
80
113
|
{footer && (
|
|
81
|
-
<div className="border-t border-base-300 px-6 py-4">
|
|
114
|
+
<div className="border-t border-base-300 px-6 py-4 shrink-0">
|
|
115
|
+
{footer}
|
|
116
|
+
</div>
|
|
82
117
|
)}
|
|
83
118
|
</div>
|
|
84
119
|
</div>,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { X } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
export const Input = React.forwardRef(
|
|
5
|
+
(
|
|
6
|
+
{
|
|
7
|
+
icon,
|
|
8
|
+
wrapperClassName = "",
|
|
9
|
+
onClear,
|
|
10
|
+
className = "",
|
|
11
|
+
value,
|
|
12
|
+
size,
|
|
13
|
+
...props
|
|
14
|
+
},
|
|
15
|
+
ref,
|
|
16
|
+
) => {
|
|
17
|
+
const sizeClass = size ? `input-${size}` : "";
|
|
18
|
+
return (
|
|
19
|
+
<div className={`relative ${wrapperClassName}`}>
|
|
20
|
+
{icon && (
|
|
21
|
+
<div className="absolute left-3 top-1/2 -translate-y-1/2 text-base-content/50 pointer-events-none flex items-center justify-center z-10">
|
|
22
|
+
{icon}
|
|
23
|
+
</div>
|
|
24
|
+
)}
|
|
25
|
+
<input
|
|
26
|
+
ref={ref}
|
|
27
|
+
value={value}
|
|
28
|
+
className={`input input-bordered w-full ${sizeClass} ${icon ? "pl-10" : ""} ${
|
|
29
|
+
onClear && value ? "pr-10" : ""
|
|
30
|
+
} ${className}`}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
|
|
34
|
+
{onClear && value && (
|
|
35
|
+
<button
|
|
36
|
+
type="button"
|
|
37
|
+
onClick={onClear}
|
|
38
|
+
className="absolute right-3 top-1/2 -translate-y-1/2 text-base-content/40 hover:text-base-content transition-colors flex items-center justify-center"
|
|
39
|
+
aria-label="Clear input"
|
|
40
|
+
>
|
|
41
|
+
<X size={16} />
|
|
42
|
+
</button>
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
Input.displayName = "Input";
|