@kyro-cms/admin 0.12.3 → 0.12.5

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 (110) hide show
  1. package/dist/index.cjs +64 -26
  2. package/dist/index.d.cts +2 -1
  3. package/dist/index.d.ts +2 -1
  4. package/dist/index.js +64 -26
  5. package/package.json +8 -2
  6. package/src/components/ActionBar.tsx +16 -16
  7. package/src/components/ApiHealth.tsx +522 -0
  8. package/src/components/ApiKeysManager.tsx +6 -4
  9. package/src/components/AuditLogsPage.tsx +4 -2
  10. package/src/components/AutoForm.tsx +10 -7
  11. package/src/components/BrandingHub.tsx +3 -1
  12. package/src/components/Dashboard.tsx +44 -37
  13. package/src/components/DashboardMetrics.tsx +168 -58
  14. package/src/components/DetailView.tsx +125 -50
  15. package/src/components/DeveloperCenter.tsx +5 -3
  16. package/src/components/GraphQLPlayground.tsx +10 -8
  17. package/src/components/ListView.tsx +66 -45
  18. package/src/components/LoginPage.tsx +21 -19
  19. package/src/components/MarketplaceManager.tsx +3 -1
  20. package/src/components/MediaGallery.tsx +12 -9
  21. package/src/components/PluginsManager.tsx +6 -4
  22. package/src/components/RestPlayground.tsx +8 -6
  23. package/src/components/SessionsManager.tsx +3 -1
  24. package/src/components/Sidebar.astro +180 -92
  25. package/src/components/UserManagement.tsx +8 -6
  26. package/src/components/UserMenu.tsx +19 -17
  27. package/src/components/VersionHistoryPanel.tsx +6 -4
  28. package/src/components/WebhookManager.tsx +143 -15
  29. package/src/components/autoform/AutoFormApiView.tsx +3 -1
  30. package/src/components/autoform/AutoFormEditView.tsx +5 -3
  31. package/src/components/autoform/AutoFormHeader.tsx +6 -6
  32. package/src/components/blocks/AccordionBlock.tsx +5 -3
  33. package/src/components/blocks/ArrayBlock.tsx +5 -3
  34. package/src/components/blocks/BlockWrapper.tsx +5 -3
  35. package/src/components/blocks/CodeBlock.tsx +4 -2
  36. package/src/components/blocks/FileBlock.tsx +5 -3
  37. package/src/components/blocks/HeroBlock.tsx +5 -3
  38. package/src/components/blocks/ImageBlock.tsx +6 -4
  39. package/src/components/blocks/ListBlock.tsx +5 -3
  40. package/src/components/blocks/ParagraphBlock.tsx +3 -1
  41. package/src/components/blocks/RelationshipBlock.tsx +5 -3
  42. package/src/components/blocks/RichTextBlock.tsx +5 -3
  43. package/src/components/blocks/VideoBlock.tsx +5 -3
  44. package/src/components/fields/AccordionField.tsx +10 -51
  45. package/src/components/fields/ArrayField.tsx +9 -7
  46. package/src/components/fields/ArrayLayout.tsx +3 -1
  47. package/src/components/fields/BlocksField.tsx +24 -75
  48. package/src/components/fields/ButtonField.tsx +3 -1
  49. package/src/components/fields/CardField.tsx +6 -4
  50. package/src/components/fields/GroupLayout.tsx +2 -49
  51. package/src/components/fields/HeadingField.tsx +3 -1
  52. package/src/components/fields/HeadingSubheadingField.tsx +4 -2
  53. package/src/components/fields/HeroField.tsx +8 -6
  54. package/src/components/fields/JSONField.tsx +9 -10
  55. package/src/components/fields/LinkField.tsx +4 -2
  56. package/src/components/fields/ListField.tsx +3 -1
  57. package/src/components/fields/MarkdownField.tsx +3 -17
  58. package/src/components/fields/RelationshipBlockField.tsx +7 -5
  59. package/src/components/fields/RelationshipField.tsx +3 -1
  60. package/src/components/fields/RichTextField.tsx +19 -16
  61. package/src/components/fields/SecretField.tsx +9 -69
  62. package/src/components/fields/SelectField.tsx +11 -6
  63. package/src/components/fields/TabsLayout.tsx +2 -48
  64. package/src/components/fields/TextField.tsx +9 -7
  65. package/src/components/fields/UploadField.tsx +3 -1
  66. package/src/components/fields/VideoField.tsx +6 -4
  67. package/src/components/ui/BlockDrawer.tsx +3 -1
  68. package/src/components/ui/CommandPalette.tsx +9 -7
  69. package/src/components/ui/CommandPaletteWrapper.tsx +3 -1
  70. package/src/components/ui/IconPickerModal.tsx +4 -2
  71. package/src/components/ui/PageHeader.tsx +48 -20
  72. package/src/components/users/UserDetail.tsx +3 -1
  73. package/src/components/users/UserForm.tsx +5 -3
  74. package/src/fields/examples/sample-field-2.tsx +3 -1
  75. package/src/fields/examples/sample-field.tsx +3 -1
  76. package/src/hooks/useAutoFormState.ts +19 -11
  77. package/src/integration.ts +21 -0
  78. package/src/layouts/AdminLayout.astro +252 -189
  79. package/src/layouts/AuthLayout.astro +52 -31
  80. package/src/lib/api.ts +7 -7
  81. package/src/lib/autoform-store.ts +4 -0
  82. package/src/lib/deep-equal.ts +3 -3
  83. package/src/lib/i18n.ts +44 -0
  84. package/src/lib/vite-shim-plugin.ts +3 -0
  85. package/src/locales/de.json +163 -0
  86. package/src/locales/en.json +163 -0
  87. package/src/locales/es.json +163 -0
  88. package/src/locales/fr.json +163 -0
  89. package/src/locales/pt.json +163 -0
  90. package/src/pages/403.astro +2 -1
  91. package/src/pages/[collection]/[id].astro +23 -10
  92. package/src/pages/[collection]/index.astro +48 -34
  93. package/src/pages/audit/index.astro +2 -1
  94. package/src/pages/graphql-explorer.astro +2 -1
  95. package/src/pages/graphql.astro +2 -1
  96. package/src/pages/health.astro +9 -0
  97. package/src/pages/index.astro +6 -5
  98. package/src/pages/keys.astro +2 -1
  99. package/src/pages/marketplace.astro +2 -1
  100. package/src/pages/media.astro +2 -1
  101. package/src/pages/plugins.astro +2 -1
  102. package/src/pages/rest-playground.astro +2 -1
  103. package/src/pages/roles/index.astro +16 -52
  104. package/src/pages/sessions.astro +2 -1
  105. package/src/pages/settings/[slug].astro +45 -30
  106. package/src/pages/users/[id].astro +1 -0
  107. package/src/pages/users/index.astro +2 -1
  108. package/src/pages/users/new.astro +2 -1
  109. package/src/pages/webhooks.astro +2 -1
  110. package/src/pages/index_ALT.astro +0 -3
@@ -5,11 +5,13 @@ import {
5
5
  } from "../fields/extensions/blocksStore";
6
6
  import { ChevronRight, X } from "../ui/icons";
7
7
  import { UploadField } from "../fields/UploadField";
8
+ import { useTranslation } from "react-i18next";
8
9
 
9
10
  export const ImageBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
10
11
  block,
11
12
  index,
12
13
  }) => {
14
+ const { t } = useTranslation();
13
15
  const blockData = useBlockById(block.id);
14
16
  const { updateBlock, removeBlock, moveBlock } = useBlockActions();
15
17
  const data = blockData?.data || block.data || {};
@@ -28,14 +30,14 @@ export const ImageBlock: React.FC<{ block: Record<string, unknown>; index: numbe
28
30
  <button type="button"
29
31
  onClick={() => moveBlock(block.id, "up")}
30
32
  className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
31
- title="Move up"
33
+ title={t("tooltips.moveUp", { defaultValue: "Move up" })}
32
34
  >
33
35
  <ChevronRight className="w-3 h-3 rotate-90" />
34
36
  </button>
35
37
  <button type="button"
36
38
  onClick={() => removeBlock(block.id)}
37
39
  className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
38
- title="Remove"
40
+ title={t("tooltips.remove", { defaultValue: "Remove" })}
39
41
  >
40
42
  <X className="w-3 h-3" />
41
43
  </button>
@@ -61,7 +63,7 @@ export const ImageBlock: React.FC<{ block: Record<string, unknown>; index: numbe
61
63
  value={data.alt || ""}
62
64
  onChange={(e) => handleChange("alt", e.target.value)}
63
65
  className="w-full px-3 py-2 border border-[var(--kyro-border)] rounded bg-[var(--kyro-surface)] text-[var(--kyro-text-primary)] text-sm"
64
- placeholder="Alternative text..."
66
+ placeholder={t("fields.alternativeText", { defaultValue: "Alternative text..." })}
65
67
  />
66
68
  </div>
67
69
  <div>
@@ -73,7 +75,7 @@ export const ImageBlock: React.FC<{ block: Record<string, unknown>; index: numbe
73
75
  value={data.caption || ""}
74
76
  onChange={(e) => handleChange("caption", e.target.value)}
75
77
  className="w-full px-3 py-2 border border-[var(--kyro-border)] rounded bg-[var(--kyro-surface)] text-[var(--kyro-text-primary)] text-sm"
76
- placeholder="Image caption..."
78
+ placeholder={t("fields.imageCaption", { defaultValue: "Image caption..." })}
77
79
  />
78
80
  </div>
79
81
  </div>
@@ -5,11 +5,13 @@ import {
5
5
  } from "../fields/extensions/blocksStore";
6
6
  import { ChevronRight, X } from "../ui/icons";
7
7
  import { ListField } from "../fields/ListField";
8
+ import { useTranslation } from "react-i18next";
8
9
 
9
10
  export const ListBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
10
11
  block,
11
12
  index,
12
13
  }) => {
14
+ const { t } = useTranslation();
13
15
  const blockData = useBlockById(block.id);
14
16
  const { updateBlock, removeBlock, moveBlock } = useBlockActions();
15
17
 
@@ -31,7 +33,7 @@ export const ListBlock: React.FC<{ block: Record<string, unknown>; index: number
31
33
  type="button"
32
34
  onClick={() => moveBlock(block.id, "up")}
33
35
  className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
34
- title="Move up"
36
+ title={t("tooltips.moveUp", { defaultValue: "Move up" })}
35
37
  >
36
38
  <ChevronRight className="w-3 h-3 rotate-90" />
37
39
  </button>
@@ -39,7 +41,7 @@ export const ListBlock: React.FC<{ block: Record<string, unknown>; index: number
39
41
  type="button"
40
42
  onClick={() => moveBlock(block.id, "down")}
41
43
  className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
42
- title="Move down"
44
+ title={t("tooltips.moveDown", { defaultValue: "Move down" })}
43
45
  >
44
46
  <ChevronRight className="w-3 h-3" />
45
47
  </button>
@@ -47,7 +49,7 @@ export const ListBlock: React.FC<{ block: Record<string, unknown>; index: number
47
49
  type="button"
48
50
  onClick={() => removeBlock(block.id)}
49
51
  className="p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]"
50
- title="Remove"
52
+ title={t("tooltips.remove", { defaultValue: "Remove" })}
51
53
  >
52
54
  <X className="w-3 h-3" />
53
55
  </button>
@@ -4,11 +4,13 @@ import {
4
4
  useBlockActions,
5
5
  } from "../fields/extensions/blocksStore";
6
6
  import { BlockWrapper } from "./BlockWrapper";
7
+ import { useTranslation } from "react-i18next";
7
8
 
8
9
  export const ParagraphBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
9
10
  block,
10
11
  index,
11
12
  }) => {
13
+ const { t } = useTranslation();
12
14
  const blockData = useBlockById(block.id);
13
15
  const { updateBlock } = useBlockActions();
14
16
 
@@ -24,7 +26,7 @@ export const ParagraphBlock: React.FC<{ block: Record<string, unknown>; index: n
24
26
  value={data.text || ""}
25
27
  onChange={(e) => handleChange("text", e.target.value)}
26
28
  className="w-full px-3 py-3 border border-[var(--kyro-border)] rounded bg-[var(--kyro-surface)] text-[var(--kyro-text-primary)] text-sm min-h-[100px] resize-none"
27
- placeholder="Enter paragraph text..."
29
+ placeholder={t("fields.enterParagraphText", { defaultValue: "Enter paragraph text..." })}
28
30
  />
29
31
  </BlockWrapper>
30
32
  );
@@ -5,11 +5,13 @@ import {
5
5
  } from "../fields/extensions/blocksStore";
6
6
  import { ChevronRight, X } from "../ui/icons";
7
7
  import { RelationshipBlockField } from "../fields/RelationshipBlockField";
8
+ import { useTranslation } from "react-i18next";
8
9
 
9
10
  export const RelationshipBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
10
11
  block,
11
12
  index,
12
13
  }) => {
14
+ const { t } = useTranslation();
13
15
  const blockData = useBlockById(block.id);
14
16
  const { updateBlock, removeBlock, moveBlock } = useBlockActions();
15
17
 
@@ -35,7 +37,7 @@ export const RelationshipBlock: React.FC<{ block: Record<string, unknown>; index
35
37
  type="button"
36
38
  onClick={() => moveBlock(block.id, "up")}
37
39
  className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
38
- title="Move up"
40
+ title={t("tooltips.moveUp", { defaultValue: "Move up" })}
39
41
  >
40
42
  <ChevronRight className="w-3 h-3 rotate-90" />
41
43
  </button>
@@ -43,7 +45,7 @@ export const RelationshipBlock: React.FC<{ block: Record<string, unknown>; index
43
45
  type="button"
44
46
  onClick={() => moveBlock(block.id, "down")}
45
47
  className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
46
- title="Move down"
48
+ title={t("tooltips.moveDown", { defaultValue: "Move down" })}
47
49
  >
48
50
  <ChevronRight className="w-3 h-3" />
49
51
  </button>
@@ -51,7 +53,7 @@ export const RelationshipBlock: React.FC<{ block: Record<string, unknown>; index
51
53
  type="button"
52
54
  onClick={() => removeBlock(block.id)}
53
55
  className="p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]"
54
- title="Remove"
56
+ title={t("tooltips.remove", { defaultValue: "Remove" })}
55
57
  >
56
58
  <X className="w-3 h-3" />
57
59
  </button>
@@ -5,11 +5,13 @@ import {
5
5
  } from "../fields/extensions/blocksStore";
6
6
  import { ChevronRight, X, AlignLeft } from "../ui/icons";
7
7
  import { RichTextField } from "../fields";
8
+ import { useTranslation } from "react-i18next";
8
9
 
9
10
  export const RichTextBlock: React.FC<{ block: any; index: number }> = ({
10
11
  block,
11
12
  index,
12
13
  }) => {
14
+ const { t } = useTranslation();
13
15
  const blockData = useBlockById(block.id);
14
16
  const { updateBlock, removeBlock, moveBlock } = useBlockActions();
15
17
 
@@ -33,7 +35,7 @@ export const RichTextBlock: React.FC<{ block: any; index: number }> = ({
33
35
  type="button"
34
36
  onClick={() => moveBlock(block.id, "up")}
35
37
  className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
36
- title="Move up"
38
+ title={t("tooltips.moveUp", { defaultValue: "Move up" })}
37
39
  >
38
40
  <ChevronRight className="w-3 h-3 rotate-90" />
39
41
  </button>
@@ -41,7 +43,7 @@ export const RichTextBlock: React.FC<{ block: any; index: number }> = ({
41
43
  type="button"
42
44
  onClick={() => moveBlock(block.id, "down")}
43
45
  className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
44
- title="Move down"
46
+ title={t("tooltips.moveDown", { defaultValue: "Move down" })}
45
47
  >
46
48
  <ChevronRight className="w-3 h-3" />
47
49
  </button>
@@ -49,7 +51,7 @@ export const RichTextBlock: React.FC<{ block: any; index: number }> = ({
49
51
  type="button"
50
52
  onClick={() => removeBlock(block.id)}
51
53
  className="p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]"
52
- title="Remove"
54
+ title={t("tooltips.remove", { defaultValue: "Remove" })}
53
55
  >
54
56
  <X className="w-3 h-3" />
55
57
  </button>
@@ -5,11 +5,13 @@ import {
5
5
  } from "../fields/extensions/blocksStore";
6
6
  import { ChevronRight, X } from "../ui/icons";
7
7
  import { VideoField } from "../fields/VideoField";
8
+ import { useTranslation } from "react-i18next";
8
9
 
9
10
  export const VideoBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
10
11
  block,
11
12
  index,
12
13
  }) => {
14
+ const { t } = useTranslation();
13
15
  const blockData = useBlockById(block.id);
14
16
  const { updateBlock, removeBlock, moveBlock } = useBlockActions();
15
17
 
@@ -30,7 +32,7 @@ export const VideoBlock: React.FC<{ block: Record<string, unknown>; index: numbe
30
32
  type="button"
31
33
  onClick={() => moveBlock(block.id, "up")}
32
34
  className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
33
- title="Move up"
35
+ title={t("tooltips.moveUp", { defaultValue: "Move up" })}
34
36
  >
35
37
  <ChevronRight className="w-3 h-3 rotate-90" />
36
38
  </button>
@@ -38,7 +40,7 @@ export const VideoBlock: React.FC<{ block: Record<string, unknown>; index: numbe
38
40
  type="button"
39
41
  onClick={() => moveBlock(block.id, "down")}
40
42
  className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
41
- title="Move down"
43
+ title={t("tooltips.moveDown", { defaultValue: "Move down" })}
42
44
  >
43
45
  <ChevronRight className="w-3 h-3" />
44
46
  </button>
@@ -46,7 +48,7 @@ export const VideoBlock: React.FC<{ block: Record<string, unknown>; index: numbe
46
48
  type="button"
47
49
  onClick={() => removeBlock(block.id)}
48
50
  className="p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]"
49
- title="Remove"
51
+ title={t("tooltips.remove", { defaultValue: "Remove" })}
50
52
  >
51
53
  <X className="w-3 h-3" />
52
54
  </button>
@@ -1,5 +1,6 @@
1
1
  import React, { useState, useCallback } from "react";
2
- import { ChevronDown, ChevronUp, Plus, X, Copy, ClipboardPaste, Check } from "../ui/icons";
2
+ import { ChevronDown, ChevronUp, Plus, X } from "../ui/icons";
3
+ import { useTranslation } from "react-i18next";
3
4
 
4
5
  interface AccordionItem {
5
6
  title: string;
@@ -18,53 +19,9 @@ export const AccordionField: React.FC<AccordionFieldProps> = ({
18
19
  compact = false,
19
20
  }) => {
20
21
  const [openIndex, setOpenIndex] = useState<number | null>(0);
21
- const [copied, setCopied] = useState(false);
22
-
23
- const handleCopy = useCallback(async (e: React.MouseEvent) => {
24
- e.preventDefault();
25
- e.stopPropagation();
26
- try {
27
- const payload = JSON.stringify({ __kyro_accordion: true, items });
28
- await navigator.clipboard.writeText(payload);
29
- setCopied(true);
30
- setTimeout(() => setCopied(false), 2000);
31
- } catch (err) {
32
- console.error("Failed to copy", err);
33
- }
34
- }, [items]);
35
-
36
- const handlePaste = useCallback(async (e: React.MouseEvent) => {
37
- e.preventDefault();
38
- e.stopPropagation();
39
- try {
40
- const text = await navigator.clipboard.readText();
41
- const parsed = JSON.parse(text);
42
- if (parsed && parsed.__kyro_accordion && Array.isArray(parsed.items)) {
43
- onChange([...items, ...parsed.items]);
44
- }
45
- } catch (err) {
46
- console.error("Failed to paste", err);
47
- }
48
- }, [items, onChange]);
49
22
 
50
23
  const headerControls = (
51
24
  <div className="flex justify-end gap-1 mb-2">
52
- <button
53
- type="button"
54
- onClick={handleCopy}
55
- className="p-1.5 text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)] transition-colors rounded hover:bg-[var(--kyro-surface)]"
56
- title="Copy Items"
57
- >
58
- {copied ? <Check className="w-3.5 h-3.5 text-green-500" /> : <Copy className="w-3.5 h-3.5" />}
59
- </button>
60
- <button
61
- type="button"
62
- onClick={handlePaste}
63
- className="p-1.5 text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)] transition-colors rounded hover:bg-[var(--kyro-surface)]"
64
- title="Paste Items"
65
- >
66
- <ClipboardPaste className="w-3.5 h-3.5" />
67
- </button>
68
25
  </div>
69
26
  );
70
27
 
@@ -109,6 +66,7 @@ export const AccordionField: React.FC<AccordionFieldProps> = ({
109
66
  ) : (
110
67
  <div className="space-y-1.5">
111
68
  {items.map((item: AccordionItem, index: number) => {
69
+ const { t } = useTranslation();
112
70
  const isOpen = openIndex === index;
113
71
  return (
114
72
  <div
@@ -131,7 +89,7 @@ export const AccordionField: React.FC<AccordionFieldProps> = ({
131
89
  handleRemove(index);
132
90
  }}
133
91
  className="opacity-0 group-hover:opacity-100 p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-error)] transition-opacity"
134
- title="Remove"
92
+ title={t("tooltips.remove", { defaultValue: "Remove" })}
135
93
  >
136
94
  <X className="w-3.5 h-3.5" />
137
95
  </button>
@@ -152,7 +110,7 @@ export const AccordionField: React.FC<AccordionFieldProps> = ({
152
110
  }
153
111
  onClick={(e) => e.stopPropagation()}
154
112
  className={smallInputClass}
155
- placeholder="Item title..."
113
+ placeholder={t("fields.itemTitle", { defaultValue: "Item title..." })}
156
114
  />
157
115
  <textarea
158
116
  value={item.content || ""}
@@ -161,7 +119,7 @@ export const AccordionField: React.FC<AccordionFieldProps> = ({
161
119
  }
162
120
  onClick={(e) => e.stopPropagation()}
163
121
  className={`${smallInputClass} min-h-[60px] resize-none`}
164
- placeholder="Item content..."
122
+ placeholder={t("fields.itemContent", { defaultValue: "Item content..." })}
165
123
  />
166
124
  </div>
167
125
  )}
@@ -192,6 +150,7 @@ export const AccordionField: React.FC<AccordionFieldProps> = ({
192
150
  ) : (
193
151
  <div className="space-y-2">
194
152
  {items.map((item: AccordionItem, index: number) => {
153
+ const { t } = useTranslation();
195
154
  const isOpen = openIndex === index;
196
155
  return (
197
156
  <div
@@ -214,7 +173,7 @@ export const AccordionField: React.FC<AccordionFieldProps> = ({
214
173
  handleRemove(index);
215
174
  }}
216
175
  className="opacity-0 group-hover:opacity-100 p-1.5 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-error)] transition-opacity"
217
- title="Remove"
176
+ title={t("tooltips.remove", { defaultValue: "Remove" })}
218
177
  >
219
178
  <X className="w-4 h-4" />
220
179
  </button>
@@ -232,7 +191,7 @@ export const AccordionField: React.FC<AccordionFieldProps> = ({
232
191
  value={item.title || ""}
233
192
  onChange={(e) => handleTitleChange(index, e.target.value)}
234
193
  className={baseInputClass}
235
- placeholder="Item title..."
194
+ placeholder={t("fields.itemTitle", { defaultValue: "Item title..." })}
236
195
  />
237
196
  <textarea
238
197
  value={item.content || ""}
@@ -240,7 +199,7 @@ export const AccordionField: React.FC<AccordionFieldProps> = ({
240
199
  handleContentChange(index, e.target.value)
241
200
  }
242
201
  className={`${baseInputClass} min-h-[60px] resize-none`}
243
- placeholder="Item content..."
202
+ placeholder={t("fields.itemContent", { defaultValue: "Item content..." })}
244
203
  />
245
204
  </div>
246
205
  )}
@@ -14,6 +14,7 @@ import {
14
14
  verticalListSortingStrategy,
15
15
  } from "@dnd-kit/sortable";
16
16
  import { CSS } from "@dnd-kit/utilities";
17
+ import { useTranslation } from "react-i18next";
17
18
 
18
19
  interface ArrayFieldItem {
19
20
  id?: string;
@@ -54,6 +55,7 @@ function SortableArrayFieldItem({
54
55
  handleRemove,
55
56
  compact,
56
57
  }: SortableArrayFieldItemProps) {
58
+ const { t } = useTranslation();
57
59
  const {
58
60
  attributes,
59
61
  listeners,
@@ -107,7 +109,7 @@ function SortableArrayFieldItem({
107
109
  handleRemove(index);
108
110
  }}
109
111
  className="opacity-0 group-hover:opacity-100 p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-error)] transition-opacity"
110
- title="Remove"
112
+ title={t("tooltips.remove", { defaultValue: "Remove" })}
111
113
  >
112
114
  <X className="w-3.5 h-3.5" />
113
115
  </button>
@@ -149,7 +151,7 @@ function SortableArrayFieldItem({
149
151
  }
150
152
  onClick={(e) => e.stopPropagation()}
151
153
  className={inputClass}
152
- placeholder="Value..."
154
+ placeholder={t("fields.value", { defaultValue: "Value..." })}
153
155
  />
154
156
  )}
155
157
  </div>
@@ -191,7 +193,7 @@ function SortableArrayFieldItem({
191
193
  handleRemove(index);
192
194
  }}
193
195
  className="opacity-0 group-hover:opacity-100 p-1.5 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-error)] transition-opacity"
194
- title="Remove"
196
+ title={t("tooltips.remove", { defaultValue: "Remove" })}
195
197
  >
196
198
  <X className="w-4 h-4" />
197
199
  </button>
@@ -231,7 +233,7 @@ function SortableArrayFieldItem({
231
233
  handleItemChange(index, "value", e.target.value)
232
234
  }
233
235
  className={inputClass}
234
- placeholder="Value..."
236
+ placeholder={t("fields.value", { defaultValue: "Value..." })}
235
237
  />
236
238
  )}
237
239
  </div>
@@ -350,14 +352,14 @@ export const ArrayField: React.FC<ArrayFieldProps> = ({
350
352
  </div>
351
353
  ) : (
352
354
  <SortableContext
353
- items={itemIds}
355
+ items={itemIds as any}
354
356
  strategy={verticalListSortingStrategy}
355
357
  >
356
358
  <div className={compact ? "space-y-1" : "space-y-2"}>
357
359
  {items.map((item, index) => (
358
360
  <SortableArrayFieldItem
359
- key={item.id || item._key || index}
360
- id={item.id || item._key || `idx-${index}`}
361
+ key={(item as any).id || (item as any)._key || index}
362
+ id={(item as any).id || (item as any)._key || `idx-${index}`}
361
363
  index={index}
362
364
  isOpen={openIndex === index}
363
365
  setOpenIndex={setOpenIndex}
@@ -16,6 +16,7 @@ import {
16
16
  verticalListSortingStrategy,
17
17
  } from "@dnd-kit/sortable";
18
18
  import { CSS } from "@dnd-kit/utilities";
19
+ import { useTranslation } from "react-i18next";
19
20
 
20
21
  const SIMPLE_TYPES = new Set(["text", "number", "checkbox", "select", "radio", "color", "email", "password"]);
21
22
 
@@ -67,6 +68,7 @@ function SortableArrayItem({
67
68
  compact,
68
69
  getItemLabel,
69
70
  }: SortableArrayItemProps) {
71
+ const { t } = useTranslation();
70
72
  const {
71
73
  attributes,
72
74
  listeners,
@@ -114,7 +116,7 @@ function SortableArrayItem({
114
116
  disabled={disabled}
115
117
  onClick={onRemove}
116
118
  className="text-[var(--kyro-text-muted)] hover:text-[var(--kyro-error)] transition-colors disabled:opacity-30 p-0.5 mt-1.5 flex-shrink-0"
117
- title="Remove"
119
+ title={t("tooltips.remove", { defaultValue: "Remove" })}
118
120
  >
119
121
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
120
122
  <line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />