@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.
- package/dist/index.cjs +64 -26
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +64 -26
- package/package.json +8 -2
- package/src/components/ActionBar.tsx +16 -16
- package/src/components/ApiHealth.tsx +522 -0
- package/src/components/ApiKeysManager.tsx +6 -4
- package/src/components/AuditLogsPage.tsx +4 -2
- package/src/components/AutoForm.tsx +10 -7
- package/src/components/BrandingHub.tsx +3 -1
- package/src/components/Dashboard.tsx +44 -37
- package/src/components/DashboardMetrics.tsx +168 -58
- package/src/components/DetailView.tsx +125 -50
- package/src/components/DeveloperCenter.tsx +5 -3
- package/src/components/GraphQLPlayground.tsx +10 -8
- package/src/components/ListView.tsx +66 -45
- package/src/components/LoginPage.tsx +21 -19
- package/src/components/MarketplaceManager.tsx +3 -1
- package/src/components/MediaGallery.tsx +12 -9
- package/src/components/PluginsManager.tsx +6 -4
- package/src/components/RestPlayground.tsx +8 -6
- package/src/components/SessionsManager.tsx +3 -1
- package/src/components/Sidebar.astro +180 -92
- package/src/components/UserManagement.tsx +8 -6
- package/src/components/UserMenu.tsx +19 -17
- package/src/components/VersionHistoryPanel.tsx +6 -4
- package/src/components/WebhookManager.tsx +143 -15
- package/src/components/autoform/AutoFormApiView.tsx +3 -1
- package/src/components/autoform/AutoFormEditView.tsx +5 -3
- package/src/components/autoform/AutoFormHeader.tsx +6 -6
- package/src/components/blocks/AccordionBlock.tsx +5 -3
- package/src/components/blocks/ArrayBlock.tsx +5 -3
- package/src/components/blocks/BlockWrapper.tsx +5 -3
- package/src/components/blocks/CodeBlock.tsx +4 -2
- package/src/components/blocks/FileBlock.tsx +5 -3
- package/src/components/blocks/HeroBlock.tsx +5 -3
- package/src/components/blocks/ImageBlock.tsx +6 -4
- package/src/components/blocks/ListBlock.tsx +5 -3
- package/src/components/blocks/ParagraphBlock.tsx +3 -1
- package/src/components/blocks/RelationshipBlock.tsx +5 -3
- package/src/components/blocks/RichTextBlock.tsx +5 -3
- package/src/components/blocks/VideoBlock.tsx +5 -3
- package/src/components/fields/AccordionField.tsx +10 -51
- package/src/components/fields/ArrayField.tsx +9 -7
- package/src/components/fields/ArrayLayout.tsx +3 -1
- package/src/components/fields/BlocksField.tsx +24 -75
- package/src/components/fields/ButtonField.tsx +3 -1
- package/src/components/fields/CardField.tsx +6 -4
- package/src/components/fields/GroupLayout.tsx +2 -49
- package/src/components/fields/HeadingField.tsx +3 -1
- package/src/components/fields/HeadingSubheadingField.tsx +4 -2
- package/src/components/fields/HeroField.tsx +8 -6
- package/src/components/fields/JSONField.tsx +9 -10
- package/src/components/fields/LinkField.tsx +4 -2
- package/src/components/fields/ListField.tsx +3 -1
- package/src/components/fields/MarkdownField.tsx +3 -17
- package/src/components/fields/RelationshipBlockField.tsx +7 -5
- package/src/components/fields/RelationshipField.tsx +3 -1
- package/src/components/fields/RichTextField.tsx +19 -16
- package/src/components/fields/SecretField.tsx +9 -69
- package/src/components/fields/SelectField.tsx +11 -6
- package/src/components/fields/TabsLayout.tsx +2 -48
- package/src/components/fields/TextField.tsx +9 -7
- package/src/components/fields/UploadField.tsx +3 -1
- package/src/components/fields/VideoField.tsx +6 -4
- package/src/components/ui/BlockDrawer.tsx +3 -1
- package/src/components/ui/CommandPalette.tsx +9 -7
- package/src/components/ui/CommandPaletteWrapper.tsx +3 -1
- package/src/components/ui/IconPickerModal.tsx +4 -2
- package/src/components/ui/PageHeader.tsx +48 -20
- package/src/components/users/UserDetail.tsx +3 -1
- package/src/components/users/UserForm.tsx +5 -3
- package/src/fields/examples/sample-field-2.tsx +3 -1
- package/src/fields/examples/sample-field.tsx +3 -1
- package/src/hooks/useAutoFormState.ts +19 -11
- package/src/integration.ts +21 -0
- package/src/layouts/AdminLayout.astro +252 -189
- package/src/layouts/AuthLayout.astro +52 -31
- package/src/lib/api.ts +7 -7
- package/src/lib/autoform-store.ts +4 -0
- package/src/lib/deep-equal.ts +3 -3
- package/src/lib/i18n.ts +44 -0
- package/src/lib/vite-shim-plugin.ts +3 -0
- package/src/locales/de.json +163 -0
- package/src/locales/en.json +163 -0
- package/src/locales/es.json +163 -0
- package/src/locales/fr.json +163 -0
- package/src/locales/pt.json +163 -0
- package/src/pages/403.astro +2 -1
- package/src/pages/[collection]/[id].astro +23 -10
- package/src/pages/[collection]/index.astro +48 -34
- package/src/pages/audit/index.astro +2 -1
- package/src/pages/graphql-explorer.astro +2 -1
- package/src/pages/graphql.astro +2 -1
- package/src/pages/health.astro +9 -0
- package/src/pages/index.astro +6 -5
- package/src/pages/keys.astro +2 -1
- package/src/pages/marketplace.astro +2 -1
- package/src/pages/media.astro +2 -1
- package/src/pages/plugins.astro +2 -1
- package/src/pages/rest-playground.astro +2 -1
- package/src/pages/roles/index.astro +16 -52
- package/src/pages/sessions.astro +2 -1
- package/src/pages/settings/[slug].astro +45 -30
- package/src/pages/users/[id].astro +1 -0
- package/src/pages/users/index.astro +2 -1
- package/src/pages/users/new.astro +2 -1
- package/src/pages/webhooks.astro +2 -1
- 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
|
|
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" />
|