@nextsparkjs/core 0.1.0-beta.149 → 0.1.0-beta.150

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 (83) hide show
  1. package/dist/components/dashboard/block-editor/block-picker.d.ts +6 -1
  2. package/dist/components/dashboard/block-editor/block-picker.d.ts.map +1 -1
  3. package/dist/components/dashboard/block-editor/block-picker.js +34 -12
  4. package/dist/components/dashboard/block-editor/block-preview-canvas.d.ts +2 -1
  5. package/dist/components/dashboard/block-editor/block-preview-canvas.d.ts.map +1 -1
  6. package/dist/components/dashboard/block-editor/block-preview-canvas.js +5 -0
  7. package/dist/components/dashboard/block-editor/builder-editor-view.d.ts.map +1 -1
  8. package/dist/components/dashboard/block-editor/builder-editor-view.js +41 -13
  9. package/dist/components/dashboard/block-editor/floating-block-toolbar.d.ts +2 -1
  10. package/dist/components/dashboard/block-editor/floating-block-toolbar.d.ts.map +1 -1
  11. package/dist/components/dashboard/block-editor/floating-block-toolbar.js +17 -1
  12. package/dist/components/dashboard/block-editor/tree-view-node.d.ts +4 -1
  13. package/dist/components/dashboard/block-editor/tree-view-node.d.ts.map +1 -1
  14. package/dist/components/dashboard/block-editor/tree-view-node.js +52 -1
  15. package/dist/components/dashboard/block-editor/tree-view.d.ts +4 -1
  16. package/dist/components/dashboard/block-editor/tree-view.d.ts.map +1 -1
  17. package/dist/components/dashboard/block-editor/tree-view.js +6 -0
  18. package/dist/components/entities/EntityTable.d.ts +1 -1
  19. package/dist/components/entities/EntityTable.d.ts.map +1 -1
  20. package/dist/components/entities/EntityTable.js +14 -1
  21. package/dist/components/entities/entity-table.types.d.ts +2 -0
  22. package/dist/components/entities/entity-table.types.d.ts.map +1 -1
  23. package/dist/components/entities/wrappers/EntityListWrapper.d.ts.map +1 -1
  24. package/dist/components/entities/wrappers/EntityListWrapper.js +19 -1
  25. package/dist/emails/otp-verification.d.ts +9 -0
  26. package/dist/emails/otp-verification.d.ts.map +1 -0
  27. package/dist/emails/otp-verification.js +72 -0
  28. package/dist/emails/reset-password.d.ts +9 -0
  29. package/dist/emails/reset-password.d.ts.map +1 -0
  30. package/dist/emails/reset-password.js +95 -0
  31. package/dist/emails/team-invitation.d.ts +9 -0
  32. package/dist/emails/team-invitation.d.ts.map +1 -0
  33. package/dist/emails/team-invitation.js +93 -0
  34. package/dist/emails/verify-email.d.ts +13 -0
  35. package/dist/emails/verify-email.d.ts.map +1 -0
  36. package/dist/emails/verify-email.js +84 -0
  37. package/dist/lib/api/entities.d.ts +6 -1
  38. package/dist/lib/api/entities.d.ts.map +1 -1
  39. package/dist/lib/api/entities.js +23 -2
  40. package/dist/lib/auth.d.ts.map +1 -1
  41. package/dist/lib/auth.js +12 -7
  42. package/dist/lib/blocks/clipboard.d.ts +11 -0
  43. package/dist/lib/blocks/clipboard.d.ts.map +1 -0
  44. package/dist/lib/blocks/clipboard.js +30 -0
  45. package/dist/lib/email/index.d.ts +1 -0
  46. package/dist/lib/email/index.d.ts.map +1 -1
  47. package/dist/lib/email/index.js +12 -0
  48. package/dist/lib/email/send.d.ts +15 -0
  49. package/dist/lib/email/send.d.ts.map +1 -0
  50. package/dist/lib/email/send.js +11 -0
  51. package/dist/lib/email/templates.d.ts +42 -29
  52. package/dist/lib/email/templates.d.ts.map +1 -1
  53. package/dist/lib/email/templates.js +8 -303
  54. package/dist/lib/email/types.d.ts +32 -0
  55. package/dist/lib/email/types.d.ts.map +1 -1
  56. package/dist/lib/services/subscription.service.d.ts +2 -2
  57. package/dist/lib/services/subscription.service.d.ts.map +1 -1
  58. package/dist/lib/services/subscription.service.js +6 -6
  59. package/dist/messages/de/email.json +58 -0
  60. package/dist/messages/en/admin.json +6 -2
  61. package/dist/messages/en/email.json +58 -0
  62. package/dist/messages/en/index.d.ts +4 -0
  63. package/dist/messages/en/index.d.ts.map +1 -1
  64. package/dist/messages/es/admin.json +6 -2
  65. package/dist/messages/es/email.json +58 -0
  66. package/dist/messages/es/index.d.ts +4 -0
  67. package/dist/messages/es/index.d.ts.map +1 -1
  68. package/dist/messages/fr/email.json +58 -0
  69. package/dist/messages/it/email.json +58 -0
  70. package/dist/messages/pt/email.json +58 -0
  71. package/dist/styles/classes.json +3 -2
  72. package/dist/templates/app/api/v1/teams/[teamId]/members/route.ts +9 -7
  73. package/dist/templates/contents/themes/starter/emails/_README.md +69 -0
  74. package/dist/templates/contents/themes/starter/emails/verify-email.ts +34 -0
  75. package/package.json +6 -2
  76. package/scripts/build/registry/discovery/emails.mjs +146 -0
  77. package/scripts/build/registry/generators/email-registry.mjs +94 -0
  78. package/scripts/build/registry.mjs +8 -4
  79. package/templates/app/api/v1/teams/[teamId]/members/route.ts +9 -7
  80. package/templates/contents/themes/starter/emails/_README.md +69 -0
  81. package/templates/contents/themes/starter/emails/verify-email.ts +34 -0
  82. package/tests/jest/__mocks__/@nextsparkjs/registries/email-registry.ts +41 -0
  83. package/tests/jest/__mocks__/next-intl-server.js +55 -0
@@ -14,7 +14,12 @@ interface BlockPickerProps {
14
14
  selectedBlockId: string | null;
15
15
  onSelectBlock: (id: string) => void;
16
16
  onReorderBlocks: (blocks: (BlockInstance | PatternReference)[]) => void;
17
+ onCopyBlock?: (id: string) => void;
18
+ onDuplicateBlock?: (id: string) => void;
19
+ onRemoveBlock?: (id: string) => void;
20
+ onPasteBlock?: () => void;
21
+ hasClipboardBlock?: boolean;
17
22
  }
18
- export declare function BlockPicker({ blocks, onAddBlock, onAddPattern, entityConfig, entityFields, onEntityFieldChange, showFieldsTab, showPatternsTab, pageBlocks, selectedBlockId, onSelectBlock, onReorderBlocks, }: BlockPickerProps): import("react/jsx-runtime").JSX.Element;
23
+ export declare function BlockPicker({ blocks, onAddBlock, onAddPattern, entityConfig, entityFields, onEntityFieldChange, showFieldsTab, showPatternsTab, pageBlocks, selectedBlockId, onSelectBlock, onReorderBlocks, onCopyBlock, onDuplicateBlock, onRemoveBlock, onPasteBlock, hasClipboardBlock, }: BlockPickerProps): import("react/jsx-runtime").JSX.Element;
19
24
  export {};
20
25
  //# sourceMappingURL=block-picker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-picker.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/block-picker.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AAuBxF,UAAU,gBAAgB;IACxB,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,YAAY,EAAE,kBAAkB,CAAA;IAChC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACrC,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAC5D,aAAa,EAAE,OAAO,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB,UAAU,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,CAAA;IAChD,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,eAAe,EAAE,CAAC,MAAM,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,KAAK,IAAI,CAAA;CACxE;AAED,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,eAAuB,EAEvB,UAAU,EACV,eAAe,EACf,aAAa,EACb,eAAe,GAChB,EAAE,gBAAgB,2CA6TlB"}
1
+ {"version":3,"file":"block-picker.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/block-picker.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AAuBxF,UAAU,gBAAgB;IACxB,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,YAAY,EAAE,kBAAkB,CAAA;IAChC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACrC,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAC5D,aAAa,EAAE,OAAO,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB,UAAU,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,CAAA;IAChD,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,eAAe,EAAE,CAAC,MAAM,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,KAAK,IAAI,CAAA;IACvE,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,eAAuB,EAEvB,UAAU,EACV,eAAe,EACf,aAAa,EACb,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,iBAAiB,GAClB,EAAE,gBAAgB,2CA8UlB"}
@@ -3,7 +3,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useState, useMemo } from "react";
4
4
  import { useTranslations } from "next-intl";
5
5
  import { useQuery } from "@tanstack/react-query";
6
- import { Search, Plus, LayoutGrid, LayoutList, Layers } from "lucide-react";
6
+ import { Search, Plus, LayoutGrid, LayoutList, Layers, ClipboardPaste } from "lucide-react";
7
7
  import { Input } from "../../ui/input.js";
8
8
  import { ScrollArea } from "../../ui/scroll-area.js";
9
9
  import { cn } from "../../../lib/utils/index.js";
@@ -38,7 +38,12 @@ function BlockPicker({
38
38
  pageBlocks,
39
39
  selectedBlockId,
40
40
  onSelectBlock,
41
- onReorderBlocks
41
+ onReorderBlocks,
42
+ onCopyBlock,
43
+ onDuplicateBlock,
44
+ onRemoveBlock,
45
+ onPasteBlock,
46
+ hasClipboardBlock
42
47
  }) {
43
48
  const t = useTranslations("admin.builder");
44
49
  const tPatterns = useTranslations("patterns");
@@ -319,16 +324,33 @@ function BlockPicker({
319
324
  ] })
320
325
  ) : (
321
326
  // Layout Tab - Tree View
322
- /* @__PURE__ */ jsx(
323
- TreeView,
324
- {
325
- blocks: pageBlocks,
326
- selectedBlockId,
327
- onSelectBlock,
328
- onReorder: onReorderBlocks,
329
- emptyMessage: t("layout.empty")
330
- }
331
- )
327
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
328
+ hasClipboardBlock && onPasteBlock && /* @__PURE__ */ jsx("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsxs(
329
+ "button",
330
+ {
331
+ className: "w-full flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-primary/10 text-primary hover:bg-primary/20 transition-colors cursor-pointer",
332
+ onClick: onPasteBlock,
333
+ "data-cy": sel("blockEditor.blockPicker.pasteBlock"),
334
+ children: [
335
+ /* @__PURE__ */ jsx(ClipboardPaste, { className: "h-4 w-4" }),
336
+ t("layout.pasteBlock")
337
+ ]
338
+ }
339
+ ) }),
340
+ /* @__PURE__ */ jsx(
341
+ TreeView,
342
+ {
343
+ blocks: pageBlocks,
344
+ selectedBlockId,
345
+ onSelectBlock,
346
+ onReorder: onReorderBlocks,
347
+ onCopy: onCopyBlock,
348
+ onDuplicate: onDuplicateBlock,
349
+ onRemove: onRemoveBlock,
350
+ emptyMessage: t("layout.empty")
351
+ }
352
+ )
353
+ ] })
332
354
  )
333
355
  ] });
334
356
  }
@@ -5,9 +5,10 @@ interface BlockPreviewCanvasProps {
5
5
  onSelectBlock: (id: string) => void;
6
6
  onMoveUp?: (id: string) => void;
7
7
  onMoveDown?: (id: string) => void;
8
+ onCopy?: (id: string) => void;
8
9
  onDuplicate?: (id: string) => void;
9
10
  onRemove?: (id: string) => void;
10
11
  }
11
- export declare function BlockPreviewCanvas({ blocks, selectedBlockId, onSelectBlock, onMoveUp, onMoveDown, onDuplicate, onRemove, }: BlockPreviewCanvasProps): import("react/jsx-runtime").JSX.Element;
12
+ export declare function BlockPreviewCanvas({ blocks, selectedBlockId, onSelectBlock, onMoveUp, onMoveDown, onCopy, onDuplicate, onRemove, }: BlockPreviewCanvasProps): import("react/jsx-runtime").JSX.Element;
12
13
  export {};
13
14
  //# sourceMappingURL=block-preview-canvas.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-preview-canvas.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/block-preview-canvas.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAkB1D,UAAU,uBAAuB;IAC/B,MAAM,EAAE,aAAa,EAAE,CAAA;IACvB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,eAAe,EACf,aAAa,EACb,QAAQ,EACR,UAAU,EACV,WAAW,EACX,QAAQ,GACT,EAAE,uBAAuB,2CA4CzB"}
1
+ {"version":3,"file":"block-preview-canvas.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/block-preview-canvas.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAkB1D,UAAU,uBAAuB;IAC/B,MAAM,EAAE,aAAa,EAAE,CAAA;IACvB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7B,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,eAAe,EACf,aAAa,EACb,QAAQ,EACR,UAAU,EACV,MAAM,EACN,WAAW,EACX,QAAQ,GACT,EAAE,uBAAuB,2CA6CzB"}
@@ -23,6 +23,7 @@ function BlockPreviewCanvas({
23
23
  onSelectBlock,
24
24
  onMoveUp,
25
25
  onMoveDown,
26
+ onCopy,
26
27
  onDuplicate,
27
28
  onRemove
28
29
  }) {
@@ -57,6 +58,7 @@ function BlockPreviewCanvas({
57
58
  isLast: index === blocks.length - 1,
58
59
  onMoveUp,
59
60
  onMoveDown,
61
+ onCopy,
60
62
  onDuplicate,
61
63
  onRemove
62
64
  },
@@ -75,6 +77,7 @@ const SelectableBlockPreview = memo(function SelectableBlockPreview2({
75
77
  isLast = false,
76
78
  onMoveUp,
77
79
  onMoveDown,
80
+ onCopy,
78
81
  onDuplicate,
79
82
  onRemove
80
83
  }) {
@@ -89,6 +92,7 @@ const SelectableBlockPreview = memo(function SelectableBlockPreview2({
89
92
  e.stopPropagation();
90
93
  onMoveDown == null ? void 0 : onMoveDown(blockId);
91
94
  }, [onMoveDown, blockId]);
95
+ const handleCopy = useCallback(() => onCopy == null ? void 0 : onCopy(blockId), [onCopy, blockId]);
92
96
  const handleDuplicate = useCallback(() => onDuplicate == null ? void 0 : onDuplicate(blockId), [onDuplicate, blockId]);
93
97
  const handleRemove = useCallback(() => onRemove == null ? void 0 : onRemove(blockId), [onRemove, blockId]);
94
98
  if (isPatternReference(block)) {
@@ -181,6 +185,7 @@ const SelectableBlockPreview = memo(function SelectableBlockPreview2({
181
185
  blockId: block.id,
182
186
  blockSlug: block.blockSlug,
183
187
  isVisible: isHovered || isSelected,
188
+ onCopy: handleCopy,
184
189
  onDuplicate: handleDuplicate,
185
190
  onRemove: handleRemove
186
191
  }
@@ -1 +1 @@
1
- {"version":3,"file":"builder-editor-view.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/builder-editor-view.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AAwCxF,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;IAChC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAA;IACvB,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC9D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,EAAE,sBAAsB,2CAgsB7I"}
1
+ {"version":3,"file":"builder-editor-view.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/builder-editor-view.tsx"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AAwCxF,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;IAChC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAA;IACvB,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC9D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,EAAE,sBAAsB,2CAiuB7I"}
@@ -5,6 +5,7 @@ import { useRouter } from "next/navigation";
5
5
  import { useTranslations } from "next-intl";
6
6
  import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
7
7
  import { v4 as uuidv4 } from "uuid";
8
+ import { copyBlockToClipboard, getBlockFromClipboard, hasBlockInClipboard } from "../../../lib/blocks/clipboard.js";
8
9
  import { Button } from "../../ui/button.js";
9
10
  import { Input } from "../../ui/input.js";
10
11
  import { Separator } from "../../ui/separator.js";
@@ -268,6 +269,38 @@ function BuilderEditorView({ entitySlug, entityConfig, id, mode, onEntityFieldCh
268
269
  setSelectedBlockId(null);
269
270
  }
270
271
  }, [selectedBlockId]);
272
+ const [clipboardHasBlock, setClipboardHasBlock] = useState(() => hasBlockInClipboard());
273
+ const handleCopyBlock = useCallback((blockId) => {
274
+ const block = blocks.find((b) => b.id === blockId);
275
+ if (block) {
276
+ copyBlockToClipboard(block);
277
+ setClipboardHasBlock(true);
278
+ toast.success(t("messages.blockCopied"));
279
+ }
280
+ }, [blocks, t]);
281
+ const handlePasteBlock = useCallback(() => {
282
+ const clipboardData = getBlockFromClipboard();
283
+ if (!clipboardData) return;
284
+ const newBlock = {
285
+ id: uuidv4(),
286
+ blockSlug: clipboardData.blockSlug,
287
+ props: { ...clipboardData.props }
288
+ };
289
+ if (selectedBlockId) {
290
+ const index = blocks.findIndex((b) => b.id === selectedBlockId);
291
+ if (index !== -1) {
292
+ const newBlocks = [...blocks];
293
+ newBlocks.splice(index + 1, 0, newBlock);
294
+ setBlocks(newBlocks);
295
+ setSelectedBlockId(newBlock.id);
296
+ toast.success(t("messages.blockPasted"));
297
+ return;
298
+ }
299
+ }
300
+ setBlocks((prev) => [...prev, newBlock]);
301
+ setSelectedBlockId(newBlock.id);
302
+ toast.success(t("messages.blockPasted"));
303
+ }, [blocks, selectedBlockId, t]);
271
304
  const handleDuplicateBlock = useCallback((blockId) => {
272
305
  const block = blocks.find((b) => b.id === blockId);
273
306
  if (block) {
@@ -561,17 +594,6 @@ function BuilderEditorView({ entitySlug, entityConfig, id, mode, onEntityFieldCh
561
594
  /* @__PURE__ */ jsx(Save, { className: "h-4 w-4 ml-2" })
562
595
  ]
563
596
  }
564
- ),
565
- /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-8" }),
566
- /* @__PURE__ */ jsx(
567
- Button,
568
- {
569
- variant: "ghost",
570
- size: "icon",
571
- className: "h-9 w-9",
572
- "data-cy": sel("blockEditor.header.settingsButton"),
573
- children: /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" })
574
- }
575
597
  )
576
598
  ] })
577
599
  ] })
@@ -592,7 +614,12 @@ function BuilderEditorView({ entitySlug, entityConfig, id, mode, onEntityFieldCh
592
614
  pageBlocks: blocks,
593
615
  selectedBlockId,
594
616
  onSelectBlock: setSelectedBlockId,
595
- onReorderBlocks: handleReorderBlocks
617
+ onReorderBlocks: handleReorderBlocks,
618
+ onCopyBlock: handleCopyBlock,
619
+ onDuplicateBlock: handleDuplicateBlock,
620
+ onRemoveBlock: handleRemoveBlock,
621
+ onPasteBlock: handlePasteBlock,
622
+ hasClipboardBlock: clipboardHasBlock
596
623
  }
597
624
  ) }),
598
625
  /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-hidden", children: [
@@ -621,6 +648,7 @@ function BuilderEditorView({ entitySlug, entityConfig, id, mode, onEntityFieldCh
621
648
  onSelectBlock: setSelectedBlockId,
622
649
  onMoveUp: handleMoveBlockUp,
623
650
  onMoveDown: handleMoveBlockDown,
651
+ onCopy: handleCopyBlock,
624
652
  onDuplicate: handleDuplicateBlock,
625
653
  onRemove: handleRemoveBlock
626
654
  }
@@ -629,7 +657,7 @@ function BuilderEditorView({ entitySlug, entityConfig, id, mode, onEntityFieldCh
629
657
  )
630
658
  }
631
659
  ),
632
- /* @__PURE__ */ jsx("div", { className: cn(viewMode !== "settings" && "hidden"), children: /* @__PURE__ */ jsx(
660
+ /* @__PURE__ */ jsx("div", { className: cn("h-full", viewMode !== "settings" && "hidden"), children: /* @__PURE__ */ jsx(
633
661
  ConfigPanel,
634
662
  {
635
663
  entityConfig,
@@ -2,6 +2,7 @@ interface FloatingBlockToolbarProps {
2
2
  blockId: string;
3
3
  blockSlug: string;
4
4
  isVisible: boolean;
5
+ onCopy: () => void;
5
6
  onDuplicate: () => void;
6
7
  onRemove: () => void;
7
8
  }
@@ -9,6 +10,6 @@ interface FloatingBlockToolbarProps {
9
10
  * Floating toolbar that appears above blocks in preview mode
10
11
  * Provides quick access to block actions: drag, duplicate, delete
11
12
  */
12
- export declare function FloatingBlockToolbar({ blockId, blockSlug, isVisible, onDuplicate, onRemove, }: FloatingBlockToolbarProps): import("react/jsx-runtime").JSX.Element;
13
+ export declare function FloatingBlockToolbar({ blockId, blockSlug, isVisible, onCopy, onDuplicate, onRemove, }: FloatingBlockToolbarProps): import("react/jsx-runtime").JSX.Element;
13
14
  export {};
14
15
  //# sourceMappingURL=floating-block-toolbar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"floating-block-toolbar.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/floating-block-toolbar.tsx"],"names":[],"mappings":"AASA,UAAU,yBAAyB;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,OAAO,CAAA;IAClB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,SAAS,EACT,SAAS,EACT,WAAW,EACX,QAAQ,GACT,EAAE,yBAAyB,2CA+D3B"}
1
+ {"version":3,"file":"floating-block-toolbar.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/floating-block-toolbar.tsx"],"names":[],"mappings":"AASA,UAAU,yBAAyB;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,SAAS,EACT,SAAS,EACT,MAAM,EACN,WAAW,EACX,QAAQ,GACT,EAAE,yBAAyB,2CA6E3B"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { Copy, Trash2 } from "lucide-react";
3
+ import { Copy, ClipboardCopy, Trash2 } from "lucide-react";
4
4
  import { useTranslations } from "next-intl";
5
5
  import { Button } from "../../ui/button.js";
6
6
  import { cn } from "../../../lib/utils/index.js";
@@ -10,6 +10,7 @@ function FloatingBlockToolbar({
10
10
  blockId,
11
11
  blockSlug,
12
12
  isVisible,
13
+ onCopy,
13
14
  onDuplicate,
14
15
  onRemove
15
16
  }) {
@@ -44,6 +45,21 @@ function FloatingBlockToolbar({
44
45
  "data-cy": sel("blockEditor.previewCanvas.floatingToolbar.divider", { id: blockId })
45
46
  }
46
47
  ),
48
+ /* @__PURE__ */ jsx(
49
+ Button,
50
+ {
51
+ variant: "ghost",
52
+ size: "icon",
53
+ className: "h-5 w-5 hover:bg-primary-foreground/20 text-primary-foreground",
54
+ onClick: (e) => {
55
+ e.stopPropagation();
56
+ onCopy();
57
+ },
58
+ "data-cy": sel("blockEditor.previewCanvas.floatingToolbar.duplicateBtn", { id: blockId }),
59
+ title: t("copy"),
60
+ children: /* @__PURE__ */ jsx(ClipboardCopy, { className: "h-3 w-3" })
61
+ }
62
+ ),
47
63
  /* @__PURE__ */ jsx(
48
64
  Button,
49
65
  {
@@ -4,8 +4,11 @@ interface TreeViewNodeProps {
4
4
  block: BlockInstance | PatternReference;
5
5
  isSelected: boolean;
6
6
  onSelect: () => void;
7
+ onCopy?: () => void;
8
+ onDuplicate?: () => void;
9
+ onRemove?: () => void;
7
10
  isPartOfPattern?: boolean;
8
11
  }
9
- export declare function TreeViewNode({ block, isSelected, onSelect, isPartOfPattern }: TreeViewNodeProps): import("react/jsx-runtime").JSX.Element;
12
+ export declare function TreeViewNode({ block, isSelected, onSelect, onCopy, onDuplicate, onRemove, isPartOfPattern }: TreeViewNodeProps): import("react/jsx-runtime").JSX.Element;
10
13
  export {};
11
14
  //# sourceMappingURL=tree-view-node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tree-view-node.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/tree-view-node.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AAE5F,UAAU,iBAAiB;IACzB,KAAK,EAAE,aAAa,GAAG,gBAAgB,CAAA;IACvC,UAAU,EAAE,OAAO,CAAA;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,UAAU,EACV,QAAQ,EACR,eAAuB,EACxB,EAAE,iBAAiB,2CA6EnB"}
1
+ {"version":3,"file":"tree-view-node.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/tree-view-node.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AAE5F,UAAU,iBAAiB;IACzB,KAAK,EAAE,aAAa,GAAG,gBAAgB,CAAA;IACvC,UAAU,EAAE,OAAO,CAAA;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,UAAU,EACV,QAAQ,EACR,MAAM,EACN,WAAW,EACX,QAAQ,EACR,eAAuB,EACxB,EAAE,iBAAiB,2CA6HnB"}
@@ -2,7 +2,7 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useSortable } from "@dnd-kit/sortable";
4
4
  import { CSS } from "@dnd-kit/utilities";
5
- import { GripVertical } from "lucide-react";
5
+ import { GripVertical, ClipboardCopy, Copy, Trash2 } from "lucide-react";
6
6
  import { cn } from "../../../lib/utils/index.js";
7
7
  import { sel } from "../../../lib/test/index.js";
8
8
  import { BlockService } from "../../../lib/services/block.service.js";
@@ -12,6 +12,9 @@ function TreeViewNode({
12
12
  block,
13
13
  isSelected,
14
14
  onSelect,
15
+ onCopy,
16
+ onDuplicate,
17
+ onRemove,
15
18
  isPartOfPattern = false
16
19
  }) {
17
20
  const {
@@ -81,6 +84,54 @@ function TreeViewNode({
81
84
  ),
82
85
  children: blockName
83
86
  }
87
+ ),
88
+ (onCopy || onDuplicate || onRemove) && /* @__PURE__ */ jsxs(
89
+ "div",
90
+ {
91
+ className: cn(
92
+ "flex items-center gap-0.5 shrink-0 transition-opacity",
93
+ "opacity-0 group-hover:opacity-100",
94
+ isSelected && "opacity-100"
95
+ ),
96
+ children: [
97
+ onCopy && /* @__PURE__ */ jsx(
98
+ "button",
99
+ {
100
+ "data-cy": sel("blockEditor.treeView.nodeCopy", { id: block.id }),
101
+ className: "p-1 rounded hover:bg-muted-foreground/20 text-muted-foreground hover:text-foreground transition-colors cursor-pointer",
102
+ onClick: (e) => {
103
+ e.stopPropagation();
104
+ onCopy();
105
+ },
106
+ children: /* @__PURE__ */ jsx(ClipboardCopy, { className: "h-3.5 w-3.5" })
107
+ }
108
+ ),
109
+ onDuplicate && /* @__PURE__ */ jsx(
110
+ "button",
111
+ {
112
+ "data-cy": sel("blockEditor.treeView.nodeDuplicate", { id: block.id }),
113
+ className: "p-1 rounded hover:bg-muted-foreground/20 text-muted-foreground hover:text-foreground transition-colors cursor-pointer",
114
+ onClick: (e) => {
115
+ e.stopPropagation();
116
+ onDuplicate();
117
+ },
118
+ children: /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" })
119
+ }
120
+ ),
121
+ onRemove && /* @__PURE__ */ jsx(
122
+ "button",
123
+ {
124
+ "data-cy": sel("blockEditor.treeView.nodeRemove", { id: block.id }),
125
+ className: "p-1 rounded hover:bg-destructive/20 text-muted-foreground hover:text-destructive transition-colors cursor-pointer",
126
+ onClick: (e) => {
127
+ e.stopPropagation();
128
+ onRemove();
129
+ },
130
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
131
+ }
132
+ )
133
+ ]
134
+ }
84
135
  )
85
136
  ]
86
137
  }
@@ -5,6 +5,9 @@ interface TreeViewProps {
5
5
  selectedBlockId: string | null;
6
6
  onSelectBlock: (id: string) => void;
7
7
  onReorder: (blocks: (BlockInstance | PatternReference)[]) => void;
8
+ onCopy?: (id: string) => void;
9
+ onDuplicate?: (id: string) => void;
10
+ onRemove?: (id: string) => void;
8
11
  emptyMessage?: string;
9
12
  }
10
13
  /**
@@ -12,6 +15,6 @@ interface TreeViewProps {
12
15
  * Displays a tree structure of all blocks with drag & drop reordering.
13
16
  * Clicking a block selects it and scrolls to it in the preview.
14
17
  */
15
- export declare function TreeView({ blocks, selectedBlockId, onSelectBlock, onReorder, emptyMessage }: TreeViewProps): import("react/jsx-runtime").JSX.Element;
18
+ export declare function TreeView({ blocks, selectedBlockId, onSelectBlock, onReorder, onCopy, onDuplicate, onRemove, emptyMessage }: TreeViewProps): import("react/jsx-runtime").JSX.Element;
16
19
  export {};
17
20
  //# sourceMappingURL=tree-view.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tree-view.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/tree-view.tsx"],"names":[],"mappings":"AAwBA,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AAC5F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAE1D,UAAU,aAAa;IACrB,MAAM,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,CAAA;IAC5C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,KAAK,IAAI,CAAA;IACjE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EACvB,MAAM,EACN,eAAe,EACf,aAAa,EACb,SAAS,EACT,YAAY,EACb,EAAE,aAAa,2CA+Gf"}
1
+ {"version":3,"file":"tree-view.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/tree-view.tsx"],"names":[],"mappings":"AAwBA,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AAC5F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAE1D,UAAU,aAAa;IACrB,MAAM,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,CAAA;IAC5C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,KAAK,IAAI,CAAA;IACjE,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7B,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EACvB,MAAM,EACN,eAAe,EACf,aAAa,EACb,SAAS,EACT,MAAM,EACN,WAAW,EACX,QAAQ,EACR,YAAY,EACb,EAAE,aAAa,2CAkHf"}
@@ -26,6 +26,9 @@ function TreeView({
26
26
  selectedBlockId,
27
27
  onSelectBlock,
28
28
  onReorder,
29
+ onCopy,
30
+ onDuplicate,
31
+ onRemove,
29
32
  emptyMessage
30
33
  }) {
31
34
  const t = useTranslations("admin.builder");
@@ -109,6 +112,9 @@ function TreeView({
109
112
  block: item.block,
110
113
  isSelected: selectedBlockId === item.id,
111
114
  onSelect: () => handleSelectBlock(item.id),
115
+ onCopy: onCopy ? () => onCopy(item.id) : void 0,
116
+ onDuplicate: onDuplicate ? () => onDuplicate(item.id) : void 0,
117
+ onRemove: onRemove ? () => onRemove(item.id) : void 0,
112
118
  isPartOfPattern: false
113
119
  },
114
120
  item.id
@@ -22,5 +22,5 @@ export declare function EntityTable<T extends {
22
22
  id: string;
23
23
  } = {
24
24
  id: string;
25
- }>({ entityConfig, data, columns: customColumns, selectable, selectedIds: controlledSelectedIds, onSelectionChange, onRowClick, basePath, quickActions: customQuickActions, dropdownActions: customDropdownActions, useDefaultActions, pagination, currentSort, onSort, searchQuery, onSearch, enableSearch, getItemName, emptyState, loading, onDelete, getPublicUrl, className, teamId, headerActions, showHeader, }: EntityTableProps<T>): import("react/jsx-runtime").JSX.Element;
25
+ }>({ entityConfig, data, columns: customColumns, selectable, selectedIds: controlledSelectedIds, onSelectionChange, onRowClick, basePath, quickActions: customQuickActions, dropdownActions: customDropdownActions, useDefaultActions, pagination, currentSort, onSort, searchQuery, onSearch, enableSearch, getItemName, emptyState, loading, onDelete, onDuplicate, getPublicUrl, className, teamId, headerActions, showHeader, }: EntityTableProps<T>): import("react/jsx-runtime").JSX.Element;
26
26
  //# sourceMappingURL=EntityTable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EntityTable.d.ts","sourceRoot":"","sources":["../../../src/components/entities/EntityTable.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AA8DH,OAAO,KAAK,EACV,gBAAgB,EAMjB,MAAM,sBAAsB,CAAA;AAE7B;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,EACrE,YAAY,EACZ,IAAI,EACJ,OAAO,EAAE,aAAa,EACtB,UAAkB,EAClB,WAAW,EAAE,qBAAqB,EAClC,iBAAiB,EACjB,UAAU,EACV,QAAQ,EACR,YAAY,EAAE,kBAAkB,EAChC,eAAe,EAAE,qBAAqB,EACtC,iBAAwB,EACxB,UAAU,EACV,WAAW,EACX,MAAM,EACN,WAAgB,EAChB,QAAQ,EACR,YAAmB,EACnB,WAAW,EACX,UAAU,EACV,OAAe,EACf,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,MAAM,EACN,aAAa,EACb,UAAiB,GAClB,EAAE,gBAAgB,CAAC,CAAC,CAAC,2CA2yBrB"}
1
+ {"version":3,"file":"EntityTable.d.ts","sourceRoot":"","sources":["../../../src/components/entities/EntityTable.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AA+DH,OAAO,KAAK,EACV,gBAAgB,EAMjB,MAAM,sBAAsB,CAAA;AAE7B;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,EACrE,YAAY,EACZ,IAAI,EACJ,OAAO,EAAE,aAAa,EACtB,UAAkB,EAClB,WAAW,EAAE,qBAAqB,EAClC,iBAAiB,EACjB,UAAU,EACV,QAAQ,EACR,YAAY,EAAE,kBAAkB,EAChC,eAAe,EAAE,qBAAqB,EACtC,iBAAwB,EACxB,UAAU,EACV,WAAW,EACX,MAAM,EACN,WAAgB,EAChB,QAAQ,EACR,YAAmB,EACnB,WAAW,EACX,UAAU,EACV,OAAe,EACf,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,SAAS,EACT,MAAM,EACN,aAAa,EACb,UAAiB,GAClB,EAAE,gBAAgB,CAAC,CAAC,CAAC,2CAuzBrB"}
@@ -49,6 +49,7 @@ import {
49
49
  Search,
50
50
  Eye,
51
51
  Edit,
52
+ Copy,
52
53
  Trash2,
53
54
  ExternalLink,
54
55
  Loader2
@@ -79,6 +80,7 @@ function EntityTable({
79
80
  emptyState,
80
81
  loading = false,
81
82
  onDelete,
83
+ onDuplicate,
82
84
  getPublicUrl,
83
85
  className,
84
86
  teamId,
@@ -187,6 +189,17 @@ function EntityTable({
187
189
  dataCySuffix: "edit"
188
190
  });
189
191
  }
192
+ if (canUpdate && onDuplicate) {
193
+ actions.push({
194
+ id: "duplicate",
195
+ label: "Duplicate",
196
+ icon: /* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" }),
197
+ onClick: (item) => {
198
+ onDuplicate(item.id);
199
+ },
200
+ dataCySuffix: "duplicate"
201
+ });
202
+ }
190
203
  if (publicBasePath) {
191
204
  actions.push({
192
205
  id: "view-public",
@@ -221,7 +234,7 @@ function EntityTable({
221
234
  });
222
235
  }
223
236
  return actions;
224
- }, [useDefaultActions, canUpdate, canDelete, onDelete, basePath, slug, router, entityConfig.names.singular, getItemName, publicBasePath, getPublicUrlForItem, isPublished]);
237
+ }, [useDefaultActions, canUpdate, canDelete, onDelete, onDuplicate, basePath, slug, router, entityConfig.names.singular, getItemName, publicBasePath, getPublicUrlForItem, isPublished]);
225
238
  const quickActions = useMemo(() => {
226
239
  return [...defaultQuickActions, ...customQuickActions || []];
227
240
  }, [defaultQuickActions, customQuickActions]);
@@ -150,6 +150,8 @@ export interface EntityTableProps<T extends {
150
150
  loading?: boolean;
151
151
  /** Callback when item is deleted */
152
152
  onDelete?: (id: string) => Promise<void>;
153
+ /** Callback when item is duplicated */
154
+ onDuplicate?: (id: string) => Promise<void>;
153
155
  /** Get public URL for item (for builder entities) */
154
156
  getPublicUrl?: (item: T) => string | null;
155
157
  /** Additional className for the table container */
@@ -1 +1 @@
1
- {"version":3,"file":"entity-table.types.d.ts","sourceRoot":"","sources":["../../../src/components/entities/entity-table.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"entity-table.types.d.ts","sourceRoot":"","sources":["../../../src/components/entities/entity-table.types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"EntityListWrapper.d.ts","sourceRoot":"","sources":["../../../../src/components/entities/wrappers/EntityListWrapper.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAA4D,MAAM,OAAO,CAAA;AAmBhF,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAChC;AAED,wBAAgB,iBAAiB,CAAC,EAChC,UAAU,EACV,SAAS,EACT,aAAa,EACd,EAAE,sBAAsB,2CA2WxB"}
1
+ {"version":3,"file":"EntityListWrapper.d.ts","sourceRoot":"","sources":["../../../../src/components/entities/wrappers/EntityListWrapper.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAA4D,MAAM,OAAO,CAAA;AAoBhF,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAChC;AAED,wBAAgB,iBAAiB,CAAC,EAChC,UAAU,EACV,SAAS,EACT,aAAa,EACd,EAAE,sBAAsB,2CA+XxB"}
@@ -2,6 +2,7 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useCallback, useMemo, useRef } from "react";
4
4
  import Link from "next/link";
5
+ import { useRouter } from "next/navigation";
5
6
  import { Plus, Loader2 } from "lucide-react";
6
7
  import { EntityTable } from "../EntityTable.js";
7
8
  import { EntityBulkActions } from "../EntityBulkActions.js";
@@ -12,7 +13,7 @@ import { SearchInput } from "../../shared/SearchInput.js";
12
13
  import { MultiSelectFilter } from "../../shared/MultiSelectFilter.js";
13
14
  import { useEntityConfig } from "../../../hooks/useEntityConfig.js";
14
15
  import { useUrlFilters } from "../../../hooks/useUrlFilters.js";
15
- import { listEntityData, deleteEntityData } from "../../../lib/api/entities.js";
16
+ import { listEntityData, deleteEntityData, duplicateEntityData } from "../../../lib/api/entities.js";
16
17
  import { useTeam } from "../../../hooks/useTeam.js";
17
18
  import { usePermission } from "../../../lib/permissions/hooks.js";
18
19
  import { sel } from "../../../lib/test/index.js";
@@ -23,6 +24,7 @@ function EntityListWrapper({
23
24
  headerActions
24
25
  }) {
25
26
  var _a, _b;
27
+ const router = useRouter();
26
28
  const { config: entityConfig, isLoading, error: configError, isOverride } = useEntityConfig(entityType);
27
29
  const { teamId } = useTeam();
28
30
  const canCreate = usePermission(`${entityType}.create`);
@@ -160,6 +162,21 @@ function EntityListWrapper({
160
162
  throw err;
161
163
  }
162
164
  }, [entityType, entityConfig == null ? void 0 : entityConfig.names.singular, entityConfig == null ? void 0 : entityConfig.names.plural, loadData]);
165
+ const handleDuplicate = useCallback(async (id) => {
166
+ try {
167
+ const created = await duplicateEntityData(entityType, id);
168
+ toast.success(`${(entityConfig == null ? void 0 : entityConfig.names.singular) || "Item"} duplicated successfully`);
169
+ await loadData(false);
170
+ const newId = created == null ? void 0 : created.id;
171
+ if (newId) {
172
+ router.push(`/dashboard/${entityType}/${newId}/edit`);
173
+ }
174
+ } catch (err) {
175
+ console.error(`[EntityListWrapper] Error duplicating ${entityType}:`, err);
176
+ toast.error(`Error duplicating: ${err instanceof Error ? err.message : "Unknown error"}`);
177
+ throw err;
178
+ }
179
+ }, [entityType, entityConfig == null ? void 0 : entityConfig.names.singular, loadData, router]);
163
180
  const handleSelectAll = useCallback(() => {
164
181
  const allIds = new Set(data.map((item) => String(item.id)));
165
182
  setSelectedIds(allIds);
@@ -247,6 +264,7 @@ function EntityListWrapper({
247
264
  searchQuery: searchValue,
248
265
  onSearch: handleSearch,
249
266
  onDelete: handleDelete,
267
+ onDuplicate: entityConfig.builder ? handleDuplicate : void 0,
250
268
  getItemName,
251
269
  className,
252
270
  teamId,
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Core default: OTP Verification template.
3
+ *
4
+ * Themes can override by creating `themes/<theme>/emails/otp-verification.ts`
5
+ * with a default export matching this contract.
6
+ */
7
+ import type { EmailContent, OtpVerificationEmailData } from '../lib/email/types';
8
+ export default function otpVerification(data: OtpVerificationEmailData, locale?: string): Promise<EmailContent>;
9
+ //# sourceMappingURL=otp-verification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otp-verification.d.ts","sourceRoot":"","sources":["../../src/emails/otp-verification.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAKjF,wBAA8B,eAAe,CAC3C,IAAI,EAAE,wBAAwB,EAC9B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CAkEvB"}