dn-react-router-toolkit 0.9.8 → 0.9.9

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.
Files changed (37) hide show
  1. package/dist/api/index.js +1 -1
  2. package/dist/api/index.mjs +1 -1
  3. package/dist/api/patch_resource_handler.js +1 -1
  4. package/dist/api/patch_resource_handler.mjs +1 -1
  5. package/dist/api/put_resource_handler.js +1 -1
  6. package/dist/api/put_resource_handler.mjs +1 -1
  7. package/dist/api/resource_handler.js +1 -1
  8. package/dist/api/resource_handler.mjs +1 -1
  9. package/dist/client/editor.d.mts +1 -1
  10. package/dist/client/editor.d.ts +1 -1
  11. package/dist/client/index.d.mts +1 -1
  12. package/dist/client/index.d.ts +1 -1
  13. package/dist/client/index.js +2 -2
  14. package/dist/client/index.mjs +1 -1
  15. package/dist/client/store_text_editor.d.mts +1 -1
  16. package/dist/client/store_text_editor.d.ts +1 -1
  17. package/dist/client/store_text_editor.js +2 -2
  18. package/dist/client/store_text_editor.mjs +1 -1
  19. package/dist/crud/crud_form.js +2 -2
  20. package/dist/crud/crud_form.mjs +1 -1
  21. package/dist/crud/index.js +1 -1
  22. package/dist/crud/index.mjs +1 -1
  23. package/dist/post/index.d.mts +1 -4
  24. package/dist/post/index.d.ts +1 -4
  25. package/dist/post/index.js +2 -475
  26. package/dist/post/index.mjs +1 -484
  27. package/dist/post/thumbnail_picker.d.mts +1 -1
  28. package/dist/post/thumbnail_picker.d.ts +1 -1
  29. package/package.json +2 -2
  30. package/dist/post/editor_toolbar.d.mts +0 -10
  31. package/dist/post/editor_toolbar.d.ts +0 -10
  32. package/dist/post/editor_toolbar.js +0 -203
  33. package/dist/post/editor_toolbar.mjs +0 -177
  34. package/dist/post/post_form_page.d.mts +0 -33
  35. package/dist/post/post_form_page.d.ts +0 -33
  36. package/dist/post/post_form_page.js +0 -583
  37. package/dist/post/post_form_page.mjs +0 -560
@@ -1,560 +0,0 @@
1
- // src/post/post_form_page.tsx
2
- import { useLoaderData } from "react-router";
3
- import { useStoreComponent as useStoreComponent2 } from "react-store-input";
4
-
5
- // src/post/editor_toolbar.tsx
6
- import {
7
- GoFileMedia,
8
- GoLink,
9
- GoListOrdered,
10
- GoListUnordered
11
- } from "react-icons/go";
12
-
13
- // src/client/env_loader.tsx
14
- import { useRouteLoaderData } from "react-router";
15
- import { jsx } from "react/jsx-runtime";
16
-
17
- // src/client/file_input.tsx
18
- import {
19
- useRef
20
- } from "react";
21
- import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
22
- function FileInput({
23
- buttonRef,
24
- className,
25
- ref,
26
- children,
27
- onClick,
28
- onChange,
29
- ...props
30
- }) {
31
- const inputRef = useRef(null);
32
- return /* @__PURE__ */ jsxs(Fragment, { children: [
33
- /* @__PURE__ */ jsx2(
34
- "button",
35
- {
36
- ref: buttonRef,
37
- className,
38
- type: "button",
39
- onClick: () => {
40
- inputRef.current?.click();
41
- },
42
- children
43
- }
44
- ),
45
- /* @__PURE__ */ jsx2(
46
- "input",
47
- {
48
- ...props,
49
- type: "file",
50
- ref: inputRef,
51
- style: {
52
- display: "none"
53
- },
54
- onChange: async (e) => {
55
- await onChange?.(e);
56
- if (inputRef.current) {
57
- inputRef.current.value = "";
58
- }
59
- }
60
- }
61
- )
62
- ] });
63
- }
64
-
65
- // src/client/use_user_agent.tsx
66
- import { useRouteLoaderData as useRouteLoaderData2 } from "react-router";
67
-
68
- // src/client/store_text_editor.tsx
69
- import {
70
- TextEditor
71
- } from "dn-react-text-editor";
72
- import { useStoreController } from "react-store-input";
73
- import { useImperativeHandle, useRef as useRef2 } from "react";
74
- import { jsx as jsx3 } from "react/jsx-runtime";
75
- function StoreTextEditor({
76
- store,
77
- name,
78
- getter,
79
- setter,
80
- defaultValue,
81
- ref,
82
- ...props
83
- }) {
84
- const controllerRef = useRef2(null);
85
- useImperativeHandle(
86
- ref,
87
- () => controllerRef.current,
88
- []
89
- );
90
- const { dispatch } = useStoreController(store, {
91
- onSubscribe: (state) => {
92
- const controller = controllerRef.current;
93
- if (!controller) {
94
- return;
95
- }
96
- const getResult = () => {
97
- if (getter) {
98
- return getter(state) || "";
99
- }
100
- if (name) {
101
- return state[name] || "";
102
- }
103
- return "";
104
- };
105
- const result = getResult();
106
- if (controller.value !== result) {
107
- controller.value = result;
108
- }
109
- },
110
- onDispatch: (state) => {
111
- const controller = controllerRef.current;
112
- if (!controller) {
113
- return;
114
- }
115
- if (setter) {
116
- setter(state, controller.value);
117
- return;
118
- }
119
- if (name) {
120
- state[name] = controller.value;
121
- }
122
- }
123
- });
124
- const getDefaultValue = () => {
125
- if (getter) {
126
- return getter(store.state);
127
- }
128
- if (name) {
129
- return store.state[name];
130
- }
131
- return void 0;
132
- };
133
- return /* @__PURE__ */ jsx3(
134
- TextEditor,
135
- {
136
- ...props,
137
- ref: controllerRef,
138
- defaultValue: defaultValue ?? getDefaultValue(),
139
- onChange: (e) => {
140
- dispatch();
141
- props.onChange?.(e);
142
- }
143
- }
144
- );
145
- }
146
-
147
- // src/client/editor.tsx
148
- import { generateMetadata } from "gw-file/client";
149
-
150
- // src/utils/cn.ts
151
- function cn(...classes) {
152
- return classes.filter(Boolean).join(" ").trim();
153
- }
154
-
155
- // src/utils/date.ts
156
- import moment from "moment-timezone";
157
-
158
- // src/utils/slug.ts
159
- var toSlug = (str) => {
160
- return str.toLowerCase().replace(/[^a-zA-Z0-9가-힣ㄱ-ㅎㅏ-ㅣ]+/g, "-").replace(/^-|-$/g, "");
161
- };
162
-
163
- // src/post/editor_toolbar.tsx
164
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
165
- function EditorToolbar({
166
- textEditorRef,
167
- className
168
- }) {
169
- return /* @__PURE__ */ jsxs2(
170
- "div",
171
- {
172
- className: cn("w-full h-12 flex items-center gap-0.5 px-1", className),
173
- children: [
174
- /* @__PURE__ */ jsx4(
175
- FileInput,
176
- {
177
- className: "button-icon-base text-[18px]",
178
- onChange: async (e) => {
179
- const files = e.target.files;
180
- if (!files || files.length === 0) {
181
- return;
182
- }
183
- textEditorRef.current?.commands.attachFile(Array.from(files));
184
- },
185
- children: /* @__PURE__ */ jsx4(GoFileMedia, {})
186
- }
187
- ),
188
- /* @__PURE__ */ jsx4(
189
- "button",
190
- {
191
- type: "button",
192
- onClick: () => {
193
- const href = prompt("\uB9C1\uD06C URL\uC744 \uC785\uB825\uD558\uC138\uC694");
194
- if (!href) {
195
- return;
196
- }
197
- textEditorRef.current?.commands.toggleMark("link", { href });
198
- },
199
- className: "button-icon-base text-[20px]",
200
- children: /* @__PURE__ */ jsx4(GoLink, {})
201
- }
202
- ),
203
- /* @__PURE__ */ jsx4(
204
- "button",
205
- {
206
- type: "button",
207
- onClick: () => {
208
- textEditorRef.current?.commands.toggleBlockType("heading", {
209
- level: 2
210
- });
211
- },
212
- className: "button-icon-base text-[18px]",
213
- children: /* @__PURE__ */ jsx4("span", { children: "H2" })
214
- }
215
- ),
216
- /* @__PURE__ */ jsx4(
217
- "button",
218
- {
219
- type: "button",
220
- onClick: () => {
221
- textEditorRef.current?.commands.toggleBlockType("heading", {
222
- level: 3
223
- });
224
- },
225
- className: "button-icon-base text-[18px]",
226
- children: /* @__PURE__ */ jsx4("span", { children: "H3" })
227
- }
228
- ),
229
- /* @__PURE__ */ jsx4(
230
- "button",
231
- {
232
- type: "button",
233
- onClick: () => {
234
- textEditorRef.current?.commands.wrapInList("ordered_list");
235
- },
236
- className: "button-icon-base text-[20px]",
237
- children: /* @__PURE__ */ jsx4(GoListOrdered, {})
238
- }
239
- ),
240
- /* @__PURE__ */ jsx4(
241
- "button",
242
- {
243
- type: "button",
244
- onClick: () => {
245
- textEditorRef.current?.commands.wrapInList("bullet_list");
246
- },
247
- className: "button-icon-base text-[20px]",
248
- children: /* @__PURE__ */ jsx4(GoListUnordered, {})
249
- }
250
- )
251
- ]
252
- }
253
- );
254
- }
255
-
256
- // src/post/post_form_page.tsx
257
- import { useRef as useRef3 } from "react";
258
- import "dn-react-text-editor";
259
-
260
- // src/post/thumbnail_picker.tsx
261
- import { useSelector } from "react-store-input";
262
- import { useEffect, useState } from "react";
263
- import { jsx as jsx5 } from "react/jsx-runtime";
264
- function PostThumbnailPicker({
265
- store,
266
- textEditorRef
267
- }) {
268
- const thumbnail = useSelector(store, (state) => state.thumbnail);
269
- const [thumbnails, setThumbnails] = useState([]);
270
- useEffect(() => {
271
- const update = () => {
272
- const textEditor = textEditorRef.current;
273
- if (!textEditor) {
274
- return;
275
- }
276
- const html = textEditor.value;
277
- if (!html) {
278
- return;
279
- }
280
- const parser = new DOMParser();
281
- const docHtml = parser.parseFromString(html, "text/html");
282
- const images = docHtml.querySelectorAll("img");
283
- const thumbnails2 = Array.from(images).map((img) => img.src);
284
- setThumbnails(thumbnails2);
285
- if (thumbnails2.length > 0 && !store.state.thumbnail) {
286
- store.dispatch((state) => {
287
- state.thumbnail = thumbnails2[0];
288
- });
289
- }
290
- };
291
- const unsubscribe = store.subscribe((tr) => {
292
- update();
293
- });
294
- setTimeout(() => {
295
- update();
296
- }, 0);
297
- return () => {
298
- unsubscribe();
299
- };
300
- }, []);
301
- return /* @__PURE__ */ jsx5("div", { className: "grid grid-cols-6 gap-1", children: thumbnails.map((url, index) => /* @__PURE__ */ jsx5(
302
- "button",
303
- {
304
- type: "button",
305
- className: cn(
306
- "border border-neutral-200 rounded-lg overflow-hidden aspect-4/3",
307
- thumbnail === url && "border-transparent ring-2 ring-primary"
308
- ),
309
- onClick: () => {
310
- store.dispatch((state) => {
311
- state.thumbnail = url;
312
- });
313
- },
314
- children: /* @__PURE__ */ jsx5(
315
- "img",
316
- {
317
- src: url,
318
- alt: `Thumbnail ${index + 1}`,
319
- className: "w-full h-full object-cover"
320
- }
321
- )
322
- },
323
- index
324
- )) });
325
- }
326
-
327
- // src/crud/crud_form_provider.tsx
328
- import { useNavigate } from "react-router";
329
- import { useStore } from "react-store-input";
330
- import {
331
- createContext,
332
- useContext
333
- } from "react";
334
- import { jsx as jsx6 } from "react/jsx-runtime";
335
- var FormContext = createContext({});
336
-
337
- // src/form/create_form_component.tsx
338
- import "react";
339
- import { jsx as jsx7 } from "react/jsx-runtime";
340
- function createComponent(tag, options) {
341
- return function FormComponent({ className, ...props }) {
342
- const Tag = tag;
343
- return /* @__PURE__ */ jsx7(Tag, { ...props, className: cn(options.className, className) });
344
- };
345
- }
346
-
347
- // src/form/form_components.tsx
348
- var FormEntry = createComponent("div", {
349
- className: "flex-1"
350
- });
351
- var FormRow = createComponent("div", {
352
- className: "flex-1 flex gap-4 mb-6"
353
- });
354
- var FormLabel = createComponent("label", {
355
- className: "flex-1 font-semibold mb-2.5 block"
356
- });
357
-
358
- // src/crud/crud_form.tsx
359
- import { useStoreComponent } from "react-store-input";
360
- import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
361
-
362
- // src/post/post_form_page.tsx
363
- import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
364
- var createPostFormPage = ({
365
- header: AdminPageHeader,
366
- textEditorClassName,
367
- attachFile
368
- }) => {
369
- return function PostFormPage({ form }) {
370
- const { boards } = useLoaderData();
371
- const component = useStoreComponent2(form.store);
372
- const textEditorRef = useRef3(null);
373
- return /* @__PURE__ */ jsxs4(Fragment3, { children: [
374
- /* @__PURE__ */ jsx9(
375
- AdminPageHeader,
376
- {
377
- title: `${form.name} \uCD94\uAC00`,
378
- actions: /* @__PURE__ */ jsxs4(Fragment3, { children: [
379
- /* @__PURE__ */ jsx9(
380
- "button",
381
- {
382
- type: "button",
383
- className: "button-outline",
384
- onClick: () => {
385
- form.delete();
386
- },
387
- children: "\uC0AD\uC81C\uD558\uAE30"
388
- }
389
- ),
390
- /* @__PURE__ */ jsx9(
391
- "button",
392
- {
393
- type: "button",
394
- className: "button-primary",
395
- onClick: () => {
396
- form.submit();
397
- },
398
- children: "\uC800\uC7A5\uD558\uAE30"
399
- }
400
- )
401
- ] })
402
- }
403
- ),
404
- /* @__PURE__ */ jsx9("div", { className: "px-4", children: /* @__PURE__ */ jsxs4("div", { className: "max-w-7xl mx-auto w-full", children: [
405
- /* @__PURE__ */ jsxs4(FormRow, { children: [
406
- /* @__PURE__ */ jsxs4(FormEntry, { children: [
407
- /* @__PURE__ */ jsx9(FormLabel, { children: "\uACF5\uAC1C\uC5EC\uBD80" }),
408
- /* @__PURE__ */ jsxs4(
409
- component.select,
410
- {
411
- name: "isPublic",
412
- className: "select-form",
413
- toInputValue: (value) => value ? "true" : "false",
414
- toStateValue: (value) => Boolean(value === "true"),
415
- children: [
416
- /* @__PURE__ */ jsx9("option", { value: "true", children: "\uACF5\uAC1C" }),
417
- /* @__PURE__ */ jsx9("option", { value: "false", children: "\uBE44\uACF5\uAC1C" })
418
- ]
419
- }
420
- )
421
- ] }),
422
- /* @__PURE__ */ jsxs4(FormEntry, { children: [
423
- /* @__PURE__ */ jsx9(FormLabel, { children: "\uC791\uC131\uC77C\uC2DC" }),
424
- /* @__PURE__ */ jsx9(
425
- component.input,
426
- {
427
- name: "createdAt",
428
- className: "input-form",
429
- type: "datetime-local"
430
- }
431
- )
432
- ] })
433
- ] }),
434
- /* @__PURE__ */ jsxs4(FormRow, { children: [
435
- /* @__PURE__ */ jsxs4(FormEntry, { children: [
436
- /* @__PURE__ */ jsx9(FormLabel, { children: "\uAC8C\uC2DC\uD310" }),
437
- /* @__PURE__ */ jsxs4(component.select, { name: "boardId", className: "select-form", children: [
438
- /* @__PURE__ */ jsx9("option", { value: "", children: "\uC120\uD0DD\uD558\uC138\uC694" }),
439
- boards.map((board) => /* @__PURE__ */ jsx9("option", { value: board.id, children: board.title }, board.id))
440
- ] })
441
- ] }),
442
- /* @__PURE__ */ jsxs4(FormEntry, { children: [
443
- /* @__PURE__ */ jsx9(FormLabel, { children: "\uCE74\uD14C\uACE0\uB9AC" }),
444
- /* @__PURE__ */ jsx9(
445
- component.input,
446
- {
447
- name: "category",
448
- className: "input-form",
449
- placeholder: "\uCE74\uD14C\uACE0\uB9AC"
450
- }
451
- )
452
- ] })
453
- ] }),
454
- /* @__PURE__ */ jsxs4(FormRow, { children: [
455
- /* @__PURE__ */ jsxs4(FormEntry, { children: [
456
- /* @__PURE__ */ jsx9(FormLabel, { children: "\uC81C\uBAA9" }),
457
- /* @__PURE__ */ jsx9(
458
- component.input,
459
- {
460
- name: "title",
461
- className: "input-form",
462
- placeholder: "\uC81C\uBAA9\uC744 \uC785\uB825\uD558\uC138\uC694",
463
- onChange: (e) => {
464
- const title = e.target.value;
465
- form.store.dispatch((state) => {
466
- state.slug = toSlug(title);
467
- });
468
- }
469
- }
470
- )
471
- ] }),
472
- /* @__PURE__ */ jsxs4(FormEntry, { children: [
473
- /* @__PURE__ */ jsx9(FormLabel, { children: "\uBD80\uC81C\uBAA9" }),
474
- /* @__PURE__ */ jsx9(
475
- component.input,
476
- {
477
- name: "subtitle",
478
- className: "input-form",
479
- placeholder: "\uBD80\uC81C\uBAA9\uC744 \uC785\uB825\uD558\uC138\uC694"
480
- }
481
- )
482
- ] })
483
- ] }),
484
- /* @__PURE__ */ jsxs4(FormRow, { children: [
485
- /* @__PURE__ */ jsxs4(FormEntry, { children: [
486
- /* @__PURE__ */ jsx9(FormLabel, { children: "\uC2AC\uB7EC\uADF8" }),
487
- /* @__PURE__ */ jsx9(
488
- component.input,
489
- {
490
- name: "slug",
491
- className: "input-form",
492
- placeholder: "\uC81C\uBAA9"
493
- }
494
- )
495
- ] }),
496
- /* @__PURE__ */ jsxs4(FormEntry, { children: [
497
- /* @__PURE__ */ jsx9(FormLabel, { children: "\uD0DC\uADF8" }),
498
- /* @__PURE__ */ jsx9(
499
- component.input,
500
- {
501
- name: "tags",
502
- className: "input-form",
503
- placeholder: "\uD0DC\uADF8 1, \uD0DC\uADF8 2, \uD0DC\uADF8 3"
504
- }
505
- )
506
- ] })
507
- ] }),
508
- /* @__PURE__ */ jsx9(FormRow, { children: /* @__PURE__ */ jsxs4(FormEntry, { children: [
509
- /* @__PURE__ */ jsx9(FormLabel, { children: "\uC124\uBA85" }),
510
- /* @__PURE__ */ jsx9(
511
- StoreTextEditor,
512
- {
513
- store: form.store,
514
- mode: "text",
515
- name: "description",
516
- className: "text-editor min-h-[80px]",
517
- placeholder: "\uC124\uBA85"
518
- }
519
- )
520
- ] }) }),
521
- /* @__PURE__ */ jsx9(FormRow, { children: /* @__PURE__ */ jsxs4(FormEntry, { children: [
522
- /* @__PURE__ */ jsx9(FormLabel, { children: "\uC378\uB124\uC77C" }),
523
- /* @__PURE__ */ jsx9(
524
- PostThumbnailPicker,
525
- {
526
- store: form.store,
527
- textEditorRef
528
- }
529
- )
530
- ] }) })
531
- ] }) }),
532
- /* @__PURE__ */ jsx9("div", { className: "sticky top-[160px] z-998 bg-white px-4", children: /* @__PURE__ */ jsx9(
533
- EditorToolbar,
534
- {
535
- textEditorRef,
536
- className: "max-w-7xl mx-auto"
537
- }
538
- ) }),
539
- /* @__PURE__ */ jsx9("div", { className: "px-4", children: /* @__PURE__ */ jsx9(
540
- StoreTextEditor,
541
- {
542
- ref: textEditorRef,
543
- store: form.store,
544
- name: "html",
545
- placeholder: "\uC5EC\uAE30\uC5D0 \uBCF8\uBB38\uC744 \uC791\uC131\uD558\uC138\uC694...",
546
- updateDelay: 500,
547
- editor: {
548
- attributes: {
549
- class: cn(textEditorClassName, "pb-[50vh]")
550
- }
551
- },
552
- attachFile
553
- }
554
- ) })
555
- ] });
556
- };
557
- };
558
- export {
559
- createPostFormPage
560
- };