dn-react-router-toolkit 0.8.1 → 0.9.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/dist/crud/index.d.mts +0 -20
- package/dist/crud/index.d.ts +0 -20
- package/dist/crud/index.js +12 -8587
- package/dist/crud/index.mjs +0 -8596
- package/dist/post/index.js +67 -7705
- package/dist/post/index.mjs +54 -7718
- package/dist/post/post_form_page.js +67 -7705
- package/dist/post/post_form_page.mjs +54 -7718
- package/dist/table/index.d.mts +0 -2
- package/dist/table/index.d.ts +0 -2
- package/dist/table/index.js +12 -79
- package/dist/table/index.mjs +12 -77
- package/dist/table/load_table.d.mts +1 -1
- package/dist/table/load_table.d.ts +1 -1
- package/dist/table/load_table.js +2 -2
- package/dist/table/load_table.mjs +2 -2
- package/dist/table/loader.js +2 -2
- package/dist/table/loader.mjs +2 -2
- package/dist/table/table.d.mts +2 -2
- package/dist/table/table.d.ts +2 -2
- package/dist/table/table.js +6 -23
- package/dist/table/table.mjs +6 -23
- package/dist/table/table_form.js +6 -23
- package/dist/table/table_form.mjs +6 -23
- package/package.json +2 -2
- package/dist/crud/crud_loader.d.mts +0 -26
- package/dist/crud/crud_loader.d.ts +0 -26
- package/dist/crud/crud_loader.js +0 -351
- package/dist/crud/crud_loader.mjs +0 -337
- package/dist/crud/crud_page.d.mts +0 -32
- package/dist/crud/crud_page.d.ts +0 -32
- package/dist/crud/crud_page.js +0 -776
- package/dist/crud/crud_page.mjs +0 -758
- package/dist/crud/generate_handlers.d.mts +0 -16
- package/dist/crud/generate_handlers.d.ts +0 -16
- package/dist/crud/generate_handlers.js +0 -39
- package/dist/crud/generate_handlers.mjs +0 -14
- package/dist/crud/generate_pages.d.mts +0 -19
- package/dist/crud/generate_pages.d.ts +0 -19
- package/dist/crud/generate_pages.js +0 -55
- package/dist/crud/generate_pages.mjs +0 -30
- package/dist/crud/generate_routes.d.mts +0 -5
- package/dist/crud/generate_routes.d.ts +0 -5
- package/dist/crud/generate_routes.js +0 -7639
- package/dist/crud/generate_routes.mjs +0 -7627
- package/dist/table/item_loader.d.mts +0 -14
- package/dist/table/item_loader.d.ts +0 -14
- package/dist/table/item_loader.js +0 -43
- package/dist/table/item_loader.mjs +0 -18
- package/dist/table/page.d.mts +0 -16
- package/dist/table/page.d.ts +0 -16
- package/dist/table/page.js +0 -375
- package/dist/table/page.mjs +0 -350
package/dist/crud/crud_page.mjs
DELETED
|
@@ -1,758 +0,0 @@
|
|
|
1
|
-
// src/crud/crud_page.tsx
|
|
2
|
-
import { useLoaderData as useLoaderData2, useLocation as useLocation4 } from "react-router";
|
|
3
|
-
|
|
4
|
-
// src/crud/crud_form_provider.tsx
|
|
5
|
-
import { useNavigate } from "react-router";
|
|
6
|
-
import { useStore } from "react-store-input";
|
|
7
|
-
import {
|
|
8
|
-
createContext,
|
|
9
|
-
useContext
|
|
10
|
-
} from "react";
|
|
11
|
-
|
|
12
|
-
// src/crud/serialize.ts
|
|
13
|
-
function serialize(value) {
|
|
14
|
-
if (value === void 0) {
|
|
15
|
-
return void 0;
|
|
16
|
-
}
|
|
17
|
-
if (value === null) {
|
|
18
|
-
return {
|
|
19
|
-
type: "null",
|
|
20
|
-
value: null
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
if (typeof value === "string") {
|
|
24
|
-
return {
|
|
25
|
-
type: "string",
|
|
26
|
-
value
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
if (typeof value === "number") {
|
|
30
|
-
return {
|
|
31
|
-
type: "number",
|
|
32
|
-
value
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
if (typeof value === "boolean") {
|
|
36
|
-
return {
|
|
37
|
-
type: "boolean",
|
|
38
|
-
value
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
if (value instanceof Date) {
|
|
42
|
-
return {
|
|
43
|
-
type: "date",
|
|
44
|
-
value: value.toISOString()
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
if (Array.isArray(value)) {
|
|
48
|
-
return {
|
|
49
|
-
type: "array",
|
|
50
|
-
value: value.map((item) => serialize(item))
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
if (typeof value === "object") {
|
|
54
|
-
return {
|
|
55
|
-
type: "object",
|
|
56
|
-
value: Object.entries(value).reduce(
|
|
57
|
-
(acc, [key, value2]) => {
|
|
58
|
-
return {
|
|
59
|
-
...acc,
|
|
60
|
-
[key]: serialize(value2)
|
|
61
|
-
};
|
|
62
|
-
},
|
|
63
|
-
{}
|
|
64
|
-
)
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
return void 0;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// src/crud/crud_form_provider.tsx
|
|
71
|
-
import { Korean } from "dn-react-toolkit/utils";
|
|
72
|
-
import { jsx } from "react/jsx-runtime";
|
|
73
|
-
var FormContext = createContext({});
|
|
74
|
-
function useFormContext() {
|
|
75
|
-
return useContext(FormContext);
|
|
76
|
-
}
|
|
77
|
-
function CrudFormProvider({
|
|
78
|
-
primaryKey,
|
|
79
|
-
name,
|
|
80
|
-
prefix,
|
|
81
|
-
item,
|
|
82
|
-
columns = {},
|
|
83
|
-
children
|
|
84
|
-
}) {
|
|
85
|
-
const apiPrefix = `/api${prefix}`;
|
|
86
|
-
const createInitialState = () => {
|
|
87
|
-
return Object.keys(item || columns).reduce((acc, key) => {
|
|
88
|
-
const value2 = item ? item[key] : void 0;
|
|
89
|
-
if (columns[key]?.defaultValue !== void 0) {
|
|
90
|
-
if (typeof value2 === "number") {
|
|
91
|
-
return {
|
|
92
|
-
...acc,
|
|
93
|
-
[key]: value2 ?? columns[key]?.defaultValue
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
return {
|
|
97
|
-
...acc,
|
|
98
|
-
[key]: value2 || columns[key]?.defaultValue
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
return {
|
|
102
|
-
...acc,
|
|
103
|
-
[key]: value2
|
|
104
|
-
};
|
|
105
|
-
}, {});
|
|
106
|
-
};
|
|
107
|
-
const store = useStore(createInitialState());
|
|
108
|
-
const navigate = useNavigate();
|
|
109
|
-
const submit = async () => {
|
|
110
|
-
const res = await fetch(apiPrefix, {
|
|
111
|
-
method: "POST",
|
|
112
|
-
headers: {
|
|
113
|
-
"Content-Type": "application/json"
|
|
114
|
-
},
|
|
115
|
-
body: JSON.stringify(serialize(store.state))
|
|
116
|
-
});
|
|
117
|
-
if (!res.ok) {
|
|
118
|
-
const { message } = await res.json();
|
|
119
|
-
alert(message);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
alert(`${Korean.with(name, ["\uC744", "\uB97C"])} \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4.`);
|
|
123
|
-
const { id } = await res.json();
|
|
124
|
-
navigate(`${prefix}/${id}`);
|
|
125
|
-
};
|
|
126
|
-
const deleteItem = async () => {
|
|
127
|
-
if (!item || !primaryKey) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
const ok = confirm("\uC815\uB9D0\uB85C \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?");
|
|
131
|
-
if (!ok) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
const res = await fetch(`${apiPrefix}/${item[primaryKey]}`, {
|
|
135
|
-
method: "DELETE"
|
|
136
|
-
});
|
|
137
|
-
if (!res.ok) {
|
|
138
|
-
const { message } = await res.json();
|
|
139
|
-
alert(message);
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
alert(`${Korean.with(name, ["\uC744", "\uB97C"])} \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4.`);
|
|
143
|
-
navigate(`${prefix}`);
|
|
144
|
-
};
|
|
145
|
-
const value = {
|
|
146
|
-
name,
|
|
147
|
-
item,
|
|
148
|
-
store,
|
|
149
|
-
submit,
|
|
150
|
-
delete: deleteItem,
|
|
151
|
-
columns
|
|
152
|
-
};
|
|
153
|
-
return /* @__PURE__ */ jsx(FormContext.Provider, { value, children });
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// src/table/page.tsx
|
|
157
|
-
import { Link as Link3, useLocation as useLocation3 } from "react-router";
|
|
158
|
-
|
|
159
|
-
// src/table/table_form.tsx
|
|
160
|
-
import { useLocation as useLocation2, useNavigate as useNavigate2, useSearchParams as useSearchParams3 } from "react-router";
|
|
161
|
-
import { GoSearch } from "react-icons/go";
|
|
162
|
-
|
|
163
|
-
// src/table/table.tsx
|
|
164
|
-
import { cn } from "dn-react-toolkit/utils";
|
|
165
|
-
import { GoArrowDown, GoArrowUp } from "react-icons/go";
|
|
166
|
-
import { Link, useSearchParams } from "react-router";
|
|
167
|
-
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
168
|
-
function Table({
|
|
169
|
-
className = "min-w-full whitespace-nowrap",
|
|
170
|
-
data,
|
|
171
|
-
columns,
|
|
172
|
-
mapper: Mapper,
|
|
173
|
-
getLink,
|
|
174
|
-
limit,
|
|
175
|
-
offset,
|
|
176
|
-
orderBy,
|
|
177
|
-
direction,
|
|
178
|
-
filters
|
|
179
|
-
}) {
|
|
180
|
-
const keys = Object.entries(columns).filter((entry) => entry[1]).map(([key]) => key);
|
|
181
|
-
const sortedArray = [...data];
|
|
182
|
-
const [_, setSearchParams] = useSearchParams();
|
|
183
|
-
return /* @__PURE__ */ jsxs(
|
|
184
|
-
"table",
|
|
185
|
-
{
|
|
186
|
-
className: cn(
|
|
187
|
-
className,
|
|
188
|
-
"text-[15px] border-separate border-spacing-0"
|
|
189
|
-
),
|
|
190
|
-
children: [
|
|
191
|
-
/* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsx2("tr", { children: keys.map((key) => {
|
|
192
|
-
const value = columns[key];
|
|
193
|
-
function getReactNode() {
|
|
194
|
-
if (value && typeof value === "object" && "label" in value) {
|
|
195
|
-
return value.label;
|
|
196
|
-
}
|
|
197
|
-
return value;
|
|
198
|
-
}
|
|
199
|
-
function Head() {
|
|
200
|
-
const reactNode = getReactNode();
|
|
201
|
-
if (typeof reactNode === "string") {
|
|
202
|
-
return /* @__PURE__ */ jsxs(
|
|
203
|
-
"button",
|
|
204
|
-
{
|
|
205
|
-
className: cn(
|
|
206
|
-
orderBy === key ? "text-gray-900 font-medium" : "text-gray-500 font-medium",
|
|
207
|
-
"px-4 flex items-center w-full"
|
|
208
|
-
),
|
|
209
|
-
onClick: () => {
|
|
210
|
-
let newDirection = "asc";
|
|
211
|
-
if (orderBy === key) {
|
|
212
|
-
newDirection = direction === "asc" ? "desc" : "asc";
|
|
213
|
-
}
|
|
214
|
-
setSearchParams({
|
|
215
|
-
orderBy: key,
|
|
216
|
-
direction: newDirection
|
|
217
|
-
});
|
|
218
|
-
},
|
|
219
|
-
children: [
|
|
220
|
-
reactNode,
|
|
221
|
-
orderBy === key && /* @__PURE__ */ jsx2("div", { className: "ml-0.5", children: direction === "asc" ? /* @__PURE__ */ jsx2(GoArrowUp, {}) : /* @__PURE__ */ jsx2(GoArrowDown, {}) })
|
|
222
|
-
]
|
|
223
|
-
}
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
return /* @__PURE__ */ jsx2(Fragment, { children: reactNode });
|
|
227
|
-
}
|
|
228
|
-
const filter = filters[key];
|
|
229
|
-
return /* @__PURE__ */ jsxs(
|
|
230
|
-
"th",
|
|
231
|
-
{
|
|
232
|
-
className: cn(
|
|
233
|
-
"py-4 border-y font-normal align-top"
|
|
234
|
-
),
|
|
235
|
-
children: [
|
|
236
|
-
/* @__PURE__ */ jsx2(Head, {}),
|
|
237
|
-
filter && /* @__PURE__ */ jsx2("div", { className: "px-3 mt-4", children: /* @__PURE__ */ jsxs(
|
|
238
|
-
"select",
|
|
239
|
-
{
|
|
240
|
-
className: "w-full h-10 px-1.5 border rounded-full outline-none",
|
|
241
|
-
onChange: (e) => {
|
|
242
|
-
const value2 = e.target.value;
|
|
243
|
-
setSearchParams((prev) => {
|
|
244
|
-
if (value2) {
|
|
245
|
-
prev.set(
|
|
246
|
-
key,
|
|
247
|
-
encodeURIComponent(
|
|
248
|
-
value2
|
|
249
|
-
)
|
|
250
|
-
);
|
|
251
|
-
} else {
|
|
252
|
-
prev.delete(key);
|
|
253
|
-
}
|
|
254
|
-
return prev;
|
|
255
|
-
});
|
|
256
|
-
},
|
|
257
|
-
children: [
|
|
258
|
-
/* @__PURE__ */ jsx2("option", { value: "", children: "\uC804\uCCB4" }),
|
|
259
|
-
filter.map((option) => /* @__PURE__ */ jsx2(
|
|
260
|
-
"option",
|
|
261
|
-
{
|
|
262
|
-
value: option,
|
|
263
|
-
children: option
|
|
264
|
-
},
|
|
265
|
-
option
|
|
266
|
-
))
|
|
267
|
-
]
|
|
268
|
-
}
|
|
269
|
-
) })
|
|
270
|
-
]
|
|
271
|
-
},
|
|
272
|
-
key
|
|
273
|
-
);
|
|
274
|
-
}) }) }),
|
|
275
|
-
/* @__PURE__ */ jsxs("tbody", { children: [
|
|
276
|
-
sortedArray.length === 0 && /* @__PURE__ */ jsx2("tr", { children: /* @__PURE__ */ jsx2(
|
|
277
|
-
"td",
|
|
278
|
-
{
|
|
279
|
-
colSpan: keys.length,
|
|
280
|
-
className: "px-4 h-20 text-gray-400 text-center",
|
|
281
|
-
children: "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
|
|
282
|
-
}
|
|
283
|
-
) }),
|
|
284
|
-
sortedArray.map((item, i) => /* @__PURE__ */ jsx2("tr", { className: "hover:bg-gray-50 transition-colors", children: keys.map((key, i2) => {
|
|
285
|
-
const value = item[key];
|
|
286
|
-
function Content() {
|
|
287
|
-
if (key in columns) {
|
|
288
|
-
const column = columns[key];
|
|
289
|
-
if (column && typeof column === "object" && "mapper" in column) {
|
|
290
|
-
const mapper = column.mapper;
|
|
291
|
-
if (mapper) {
|
|
292
|
-
return /* @__PURE__ */ jsx2(Fragment, { children: mapper(item) });
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
return /* @__PURE__ */ jsx2(Fragment, { children: String(value) });
|
|
297
|
-
}
|
|
298
|
-
const linkedContent = getLink ? /* @__PURE__ */ jsx2(
|
|
299
|
-
Link,
|
|
300
|
-
{
|
|
301
|
-
to: getLink(item),
|
|
302
|
-
className: "block content-center px-4 w-full h-full",
|
|
303
|
-
children: /* @__PURE__ */ jsx2(Content, {})
|
|
304
|
-
}
|
|
305
|
-
) : /* @__PURE__ */ jsx2(Content, {});
|
|
306
|
-
const cell = Mapper ? /* @__PURE__ */ jsx2(Mapper, { item, index: i2, children: linkedContent }) : linkedContent;
|
|
307
|
-
return /* @__PURE__ */ jsx2("td", { className: "px-0 h-14 border-b", children: cell }, key);
|
|
308
|
-
}) }, i))
|
|
309
|
-
] })
|
|
310
|
-
]
|
|
311
|
-
}
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// src/table/use_table.tsx
|
|
316
|
-
import { useLoaderData } from "react-router";
|
|
317
|
-
function useTable() {
|
|
318
|
-
const { table } = useLoaderData();
|
|
319
|
-
return table;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// src/table/buttons.tsx
|
|
323
|
-
import { cn as cn2 } from "dn-react-toolkit/utils";
|
|
324
|
-
import { Link as Link2, useLocation, useSearchParams as useSearchParams2 } from "react-router";
|
|
325
|
-
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
326
|
-
function TablePageButtons({
|
|
327
|
-
MAX_PAGES_TO_SHOW,
|
|
328
|
-
total,
|
|
329
|
-
limit,
|
|
330
|
-
offset
|
|
331
|
-
}) {
|
|
332
|
-
const pages = Math.ceil(total / limit);
|
|
333
|
-
const { pathname } = useLocation();
|
|
334
|
-
const [searchParams] = useSearchParams2();
|
|
335
|
-
const currentPage = Math.floor(offset / limit) + 1;
|
|
336
|
-
const startButton = (Math.ceil(currentPage / MAX_PAGES_TO_SHOW) - 1) * MAX_PAGES_TO_SHOW;
|
|
337
|
-
const endButton = Math.min(startButton + MAX_PAGES_TO_SHOW - 1, pages);
|
|
338
|
-
return /* @__PURE__ */ jsx3(Fragment2, { children: pages > 1 && /* @__PURE__ */ jsxs2("div", { className: "flex justify-center items-center my-8 gap-4 text-neutral-400", children: [
|
|
339
|
-
startButton > 1 && /* @__PURE__ */ jsx3(
|
|
340
|
-
Link2,
|
|
341
|
-
{
|
|
342
|
-
to: (() => {
|
|
343
|
-
searchParams.set(
|
|
344
|
-
"offset",
|
|
345
|
-
String((startButton - 1) * limit)
|
|
346
|
-
);
|
|
347
|
-
return `${pathname}?${searchParams.toString()}`;
|
|
348
|
-
})(),
|
|
349
|
-
className: "w-10 block text-center transition-colors hover:text-primary",
|
|
350
|
-
children: "\uC774\uC804"
|
|
351
|
-
}
|
|
352
|
-
),
|
|
353
|
-
Array.from({
|
|
354
|
-
length: Math.min(
|
|
355
|
-
MAX_PAGES_TO_SHOW,
|
|
356
|
-
pages - startButton
|
|
357
|
-
)
|
|
358
|
-
}).map((_, index) => {
|
|
359
|
-
return /* @__PURE__ */ jsx3(
|
|
360
|
-
Link2,
|
|
361
|
-
{
|
|
362
|
-
to: (() => {
|
|
363
|
-
searchParams.set(
|
|
364
|
-
"offset",
|
|
365
|
-
String((startButton + index) * limit)
|
|
366
|
-
);
|
|
367
|
-
return `${pathname}?${searchParams.toString()}`;
|
|
368
|
-
})(),
|
|
369
|
-
className: cn2(
|
|
370
|
-
"w-6 block text-center transition-colors",
|
|
371
|
-
currentPage === startButton + index + 1 ? "font-bold text-primary" : "hover:text-primary"
|
|
372
|
-
),
|
|
373
|
-
children: startButton + index + 1
|
|
374
|
-
},
|
|
375
|
-
index
|
|
376
|
-
);
|
|
377
|
-
}),
|
|
378
|
-
endButton < pages && /* @__PURE__ */ jsx3(
|
|
379
|
-
Link2,
|
|
380
|
-
{
|
|
381
|
-
to: (() => {
|
|
382
|
-
searchParams.set(
|
|
383
|
-
"offset",
|
|
384
|
-
String((endButton + 1) * limit)
|
|
385
|
-
);
|
|
386
|
-
return `${pathname}?${searchParams.toString()}`;
|
|
387
|
-
})(),
|
|
388
|
-
className: "w-10 block text-center transition-colors hover:text-primary",
|
|
389
|
-
children: "\uB2E4\uC74C"
|
|
390
|
-
}
|
|
391
|
-
)
|
|
392
|
-
] }) });
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// src/table/table_form.tsx
|
|
396
|
-
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
397
|
-
function TableForm({
|
|
398
|
-
columns,
|
|
399
|
-
primaryKey = "id"
|
|
400
|
-
}) {
|
|
401
|
-
const { pathname } = useLocation2();
|
|
402
|
-
const {
|
|
403
|
-
items,
|
|
404
|
-
total,
|
|
405
|
-
limit,
|
|
406
|
-
offset,
|
|
407
|
-
orderBy,
|
|
408
|
-
direction,
|
|
409
|
-
searchKey,
|
|
410
|
-
filters
|
|
411
|
-
} = useTable();
|
|
412
|
-
const navigate = useNavigate2();
|
|
413
|
-
const search = (query) => {
|
|
414
|
-
const searchParams2 = new URLSearchParams(window.location.search);
|
|
415
|
-
searchParams2.set("query", query);
|
|
416
|
-
searchParams2.set("offset", "0");
|
|
417
|
-
navigate(`${pathname}?${searchParams2.toString()}`);
|
|
418
|
-
};
|
|
419
|
-
const [searchParams] = useSearchParams3();
|
|
420
|
-
return /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
421
|
-
searchKey && /* @__PURE__ */ jsxs3(
|
|
422
|
-
"form",
|
|
423
|
-
{
|
|
424
|
-
className: "h-20 px-4 flex items-center border-t",
|
|
425
|
-
onSubmit: (e) => {
|
|
426
|
-
e.preventDefault();
|
|
427
|
-
const formData = new FormData(e.currentTarget);
|
|
428
|
-
const query = formData.get("query");
|
|
429
|
-
search(query);
|
|
430
|
-
},
|
|
431
|
-
children: [
|
|
432
|
-
/* @__PURE__ */ jsx4(
|
|
433
|
-
"button",
|
|
434
|
-
{
|
|
435
|
-
type: "submit",
|
|
436
|
-
className: "w-10 h-10 flex justify-center items-center",
|
|
437
|
-
children: /* @__PURE__ */ jsx4(GoSearch, { className: "text-xl mr-4" })
|
|
438
|
-
}
|
|
439
|
-
),
|
|
440
|
-
/* @__PURE__ */ jsx4(
|
|
441
|
-
"input",
|
|
442
|
-
{
|
|
443
|
-
className: "outline-none h-full flex-1",
|
|
444
|
-
placeholder: "\uC5EC\uAE30\uC5D0 \uAC80\uC0C9\uD558\uC138\uC694...",
|
|
445
|
-
name: "query",
|
|
446
|
-
defaultValue: searchParams.get("query") ?? ""
|
|
447
|
-
}
|
|
448
|
-
)
|
|
449
|
-
]
|
|
450
|
-
}
|
|
451
|
-
),
|
|
452
|
-
/* @__PURE__ */ jsx4(
|
|
453
|
-
Table,
|
|
454
|
-
{
|
|
455
|
-
data: items,
|
|
456
|
-
columns,
|
|
457
|
-
getLink: primaryKey ? (item) => `${pathname}/${item[primaryKey]}` : void 0,
|
|
458
|
-
limit,
|
|
459
|
-
offset,
|
|
460
|
-
orderBy,
|
|
461
|
-
direction,
|
|
462
|
-
filters
|
|
463
|
-
}
|
|
464
|
-
),
|
|
465
|
-
/* @__PURE__ */ jsx4(
|
|
466
|
-
TablePageButtons,
|
|
467
|
-
{
|
|
468
|
-
total,
|
|
469
|
-
limit,
|
|
470
|
-
offset,
|
|
471
|
-
MAX_PAGES_TO_SHOW: 10
|
|
472
|
-
}
|
|
473
|
-
)
|
|
474
|
-
] });
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// src/table/page.tsx
|
|
478
|
-
import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
479
|
-
function createTablePage({
|
|
480
|
-
name,
|
|
481
|
-
columns,
|
|
482
|
-
primaryKey = "id"
|
|
483
|
-
}) {
|
|
484
|
-
return function TablePage({
|
|
485
|
-
header: Header
|
|
486
|
-
}) {
|
|
487
|
-
const { pathname } = useLocation3();
|
|
488
|
-
return /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
489
|
-
/* @__PURE__ */ jsx5(
|
|
490
|
-
Header,
|
|
491
|
-
{
|
|
492
|
-
title: name,
|
|
493
|
-
actions: /* @__PURE__ */ jsxs4(Link3, { to: `${pathname}/new`, className: "button-primary", children: [
|
|
494
|
-
name,
|
|
495
|
-
" \uCD94\uAC00"
|
|
496
|
-
] })
|
|
497
|
-
}
|
|
498
|
-
),
|
|
499
|
-
/* @__PURE__ */ jsx5("div", { className: "max-w-7xl mx-auto w-full overflow-auto", children: /* @__PURE__ */ jsx5(TableForm, { columns, primaryKey }) })
|
|
500
|
-
] });
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
// src/form/create_form_component.tsx
|
|
505
|
-
import { cn as cn3 } from "dn-react-toolkit/utils";
|
|
506
|
-
import "react";
|
|
507
|
-
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
508
|
-
function createComponent(tag, options) {
|
|
509
|
-
return function FormComponent({ className, ...props }) {
|
|
510
|
-
const Tag = tag;
|
|
511
|
-
return /* @__PURE__ */ jsx6(Tag, { ...props, className: cn3(options.className, className) });
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
// src/form/form_components.tsx
|
|
516
|
-
var FormEntry = createComponent("div", {
|
|
517
|
-
className: "flex-1"
|
|
518
|
-
});
|
|
519
|
-
var FormRow = createComponent("div", {
|
|
520
|
-
className: "flex-1 flex gap-4 mb-6"
|
|
521
|
-
});
|
|
522
|
-
var FormLabel = createComponent("label", {
|
|
523
|
-
className: "flex-1 font-semibold mb-2.5 block"
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
// src/crud/crud_form.tsx
|
|
527
|
-
import { useStoreComponent } from "react-store-input";
|
|
528
|
-
|
|
529
|
-
// src/client/env_loader.tsx
|
|
530
|
-
import { useRouteLoaderData } from "react-router";
|
|
531
|
-
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
532
|
-
|
|
533
|
-
// src/client/file_input.tsx
|
|
534
|
-
import {
|
|
535
|
-
useRef
|
|
536
|
-
} from "react";
|
|
537
|
-
import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
538
|
-
|
|
539
|
-
// src/client/use_user_agent.tsx
|
|
540
|
-
import { useRouteLoaderData as useRouteLoaderData2 } from "react-router";
|
|
541
|
-
|
|
542
|
-
// src/client/store_text_editor.tsx
|
|
543
|
-
import {
|
|
544
|
-
TextEditor
|
|
545
|
-
} from "dn-react-text-editor";
|
|
546
|
-
import { useStoreController } from "react-store-input";
|
|
547
|
-
import { useImperativeHandle, useRef as useRef2 } from "react";
|
|
548
|
-
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
549
|
-
function StoreTextEditor({
|
|
550
|
-
store,
|
|
551
|
-
name,
|
|
552
|
-
getter,
|
|
553
|
-
setter,
|
|
554
|
-
defaultValue,
|
|
555
|
-
ref,
|
|
556
|
-
...props
|
|
557
|
-
}) {
|
|
558
|
-
const controllerRef = useRef2(null);
|
|
559
|
-
useImperativeHandle(
|
|
560
|
-
ref,
|
|
561
|
-
() => controllerRef.current,
|
|
562
|
-
[]
|
|
563
|
-
);
|
|
564
|
-
const { dispatch } = useStoreController(store, {
|
|
565
|
-
onSubscribe: (state) => {
|
|
566
|
-
const controller = controllerRef.current;
|
|
567
|
-
if (!controller) {
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
const getResult = () => {
|
|
571
|
-
if (getter) {
|
|
572
|
-
return getter(state) || "";
|
|
573
|
-
}
|
|
574
|
-
if (name) {
|
|
575
|
-
return state[name] || "";
|
|
576
|
-
}
|
|
577
|
-
return "";
|
|
578
|
-
};
|
|
579
|
-
const result = getResult();
|
|
580
|
-
if (controller.value !== result) {
|
|
581
|
-
controller.value = result;
|
|
582
|
-
}
|
|
583
|
-
},
|
|
584
|
-
onDispatch: (state) => {
|
|
585
|
-
const controller = controllerRef.current;
|
|
586
|
-
if (!controller) {
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
589
|
-
if (setter) {
|
|
590
|
-
setter(state, controller.value);
|
|
591
|
-
return;
|
|
592
|
-
}
|
|
593
|
-
if (name) {
|
|
594
|
-
state[name] = controller.value;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
});
|
|
598
|
-
const getDefaultValue = () => {
|
|
599
|
-
if (getter) {
|
|
600
|
-
return getter(store.state);
|
|
601
|
-
}
|
|
602
|
-
if (name) {
|
|
603
|
-
return store.state[name];
|
|
604
|
-
}
|
|
605
|
-
return void 0;
|
|
606
|
-
};
|
|
607
|
-
return /* @__PURE__ */ jsx9(
|
|
608
|
-
TextEditor,
|
|
609
|
-
{
|
|
610
|
-
...props,
|
|
611
|
-
ref: controllerRef,
|
|
612
|
-
defaultValue: defaultValue ?? getDefaultValue(),
|
|
613
|
-
onChange: (e) => {
|
|
614
|
-
dispatch();
|
|
615
|
-
props.onChange?.(e);
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
// src/client/editor.tsx
|
|
622
|
-
import { generateMetadata } from "dn-react-toolkit/file/client";
|
|
623
|
-
|
|
624
|
-
// src/crud/crud_form.tsx
|
|
625
|
-
import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
626
|
-
function CrudForm({
|
|
627
|
-
AdminHeader
|
|
628
|
-
}) {
|
|
629
|
-
const form = useFormContext();
|
|
630
|
-
const component = useStoreComponent(form.store);
|
|
631
|
-
return /* @__PURE__ */ jsxs6(Fragment6, { children: [
|
|
632
|
-
/* @__PURE__ */ jsx10(
|
|
633
|
-
AdminHeader,
|
|
634
|
-
{
|
|
635
|
-
title: `${form.name} ${form.item ? "\uC218\uC815" : "\uCD94\uAC00"}`,
|
|
636
|
-
actions: /* @__PURE__ */ jsxs6(Fragment6, { children: [
|
|
637
|
-
form.item && /* @__PURE__ */ jsx10(
|
|
638
|
-
"button",
|
|
639
|
-
{
|
|
640
|
-
type: "button",
|
|
641
|
-
className: "button-outline",
|
|
642
|
-
onClick: () => {
|
|
643
|
-
form.delete();
|
|
644
|
-
},
|
|
645
|
-
children: "\uC0AD\uC81C\uD558\uAE30"
|
|
646
|
-
}
|
|
647
|
-
),
|
|
648
|
-
/* @__PURE__ */ jsx10(
|
|
649
|
-
"button",
|
|
650
|
-
{
|
|
651
|
-
type: "button",
|
|
652
|
-
className: "button-primary",
|
|
653
|
-
onClick: form.submit,
|
|
654
|
-
children: "\uC800\uC7A5\uD558\uAE30"
|
|
655
|
-
}
|
|
656
|
-
)
|
|
657
|
-
] })
|
|
658
|
-
}
|
|
659
|
-
),
|
|
660
|
-
/* @__PURE__ */ jsx10("div", { className: "max-w-2xl mx-auto", children: Object.keys(form.columns).length > 0 && /* @__PURE__ */ jsx10(Fragment6, { children: Object.entries(form.columns).map(
|
|
661
|
-
([name, value]) => {
|
|
662
|
-
function InputComponent() {
|
|
663
|
-
if (value.component) {
|
|
664
|
-
const Component = value.component;
|
|
665
|
-
return /* @__PURE__ */ jsx10(Component, { store: form.store, name });
|
|
666
|
-
}
|
|
667
|
-
if (value.type === "textarea") {
|
|
668
|
-
return /* @__PURE__ */ jsx10(
|
|
669
|
-
StoreTextEditor,
|
|
670
|
-
{
|
|
671
|
-
store: form.store,
|
|
672
|
-
name,
|
|
673
|
-
editor: {
|
|
674
|
-
attributes: {
|
|
675
|
-
class: "text-editor-form"
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
);
|
|
680
|
-
}
|
|
681
|
-
if (value.options) {
|
|
682
|
-
const Component = value.options;
|
|
683
|
-
return /* @__PURE__ */ jsx10(component.select, { name, className: "select-form", children: /* @__PURE__ */ jsx10(Component, {}) });
|
|
684
|
-
}
|
|
685
|
-
return /* @__PURE__ */ jsx10(
|
|
686
|
-
component.input,
|
|
687
|
-
{
|
|
688
|
-
name,
|
|
689
|
-
type: value.type,
|
|
690
|
-
className: "input-form"
|
|
691
|
-
}
|
|
692
|
-
);
|
|
693
|
-
}
|
|
694
|
-
const v = form.store.state[name];
|
|
695
|
-
if (typeof v === "boolean") {
|
|
696
|
-
return /* @__PURE__ */ jsxs6("div", { className: "flex", children: [
|
|
697
|
-
value.label,
|
|
698
|
-
/* @__PURE__ */ jsx10("div", { className: "ml-auto", children: /* @__PURE__ */ jsx10(InputComponent, {}) })
|
|
699
|
-
] });
|
|
700
|
-
}
|
|
701
|
-
return /* @__PURE__ */ jsx10(FormRow, { children: /* @__PURE__ */ jsxs6(FormEntry, { children: [
|
|
702
|
-
/* @__PURE__ */ jsx10(FormLabel, { children: value.label }, name),
|
|
703
|
-
/* @__PURE__ */ jsx10(InputComponent, {})
|
|
704
|
-
] }) }, name);
|
|
705
|
-
}
|
|
706
|
-
) }) })
|
|
707
|
-
] });
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
// src/crud/crud_page.tsx
|
|
711
|
-
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
712
|
-
function crudPage({
|
|
713
|
-
name,
|
|
714
|
-
primaryKey,
|
|
715
|
-
tablePageOptions,
|
|
716
|
-
formOptions,
|
|
717
|
-
header
|
|
718
|
-
}) {
|
|
719
|
-
const create = (prefix) => {
|
|
720
|
-
return function Page() {
|
|
721
|
-
const data = useLoaderData2();
|
|
722
|
-
const { pathname } = useLocation4();
|
|
723
|
-
if (pathname === prefix) {
|
|
724
|
-
const Component = createTablePage({
|
|
725
|
-
...tablePageOptions,
|
|
726
|
-
name
|
|
727
|
-
});
|
|
728
|
-
return /* @__PURE__ */ jsx11(Component, { header });
|
|
729
|
-
}
|
|
730
|
-
if (pathname.startsWith(prefix)) {
|
|
731
|
-
return /* @__PURE__ */ jsx11(
|
|
732
|
-
CrudFormProvider,
|
|
733
|
-
{
|
|
734
|
-
item: data?.item,
|
|
735
|
-
prefix,
|
|
736
|
-
name,
|
|
737
|
-
columns: formOptions.columns,
|
|
738
|
-
primaryKey,
|
|
739
|
-
children: formOptions.form ? /* @__PURE__ */ jsx11(FormDelegate, { component: formOptions.form }) : /* @__PURE__ */ jsx11(CrudForm, { AdminHeader: header })
|
|
740
|
-
}
|
|
741
|
-
);
|
|
742
|
-
}
|
|
743
|
-
};
|
|
744
|
-
};
|
|
745
|
-
return {
|
|
746
|
-
name,
|
|
747
|
-
create
|
|
748
|
-
};
|
|
749
|
-
}
|
|
750
|
-
function FormDelegate({
|
|
751
|
-
component: Component
|
|
752
|
-
}) {
|
|
753
|
-
const form = useFormContext();
|
|
754
|
-
return /* @__PURE__ */ jsx11(Component, { form });
|
|
755
|
-
}
|
|
756
|
-
export {
|
|
757
|
-
crudPage
|
|
758
|
-
};
|