@kyro-cms/admin 0.12.4 → 0.12.6
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 +10 -4
- 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 +41 -38
- 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 +11 -10
- package/src/components/autoform/AutoFormApiView.tsx +3 -1
- package/src/components/autoform/AutoFormEditView.tsx +3 -1
- 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 -19
- 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/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
|
@@ -3,12 +3,14 @@ import { Dropdown, DropdownItem, DropdownSeparator } from "./ui/Dropdown";
|
|
|
3
3
|
import { User, Shield, Key, Webhook, Clock, FileText, ExternalLink, HelpCircle, LogOut, Terminal, Zap } from "./ui/icons";
|
|
4
4
|
import { useAuthStore } from "../lib/stores";
|
|
5
5
|
import { apiGet } from "../lib/api";
|
|
6
|
+
import { useTranslation } from "react-i18next";
|
|
6
7
|
|
|
7
8
|
interface UserMenuProps {
|
|
8
9
|
adminPath: string;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export function UserMenu({ adminPath }: UserMenuProps) {
|
|
13
|
+
const { t } = useTranslation();
|
|
12
14
|
const currentUser = useAuthStore((s) => s.user);
|
|
13
15
|
const [avatarUrl, setAvatarUrl] = useState<string | null>(null);
|
|
14
16
|
const [apiAccess, setApiAccess] = useState<{ graphqlEnabled?: boolean } | null>(null);
|
|
@@ -41,7 +43,7 @@ export function UserMenu({ adminPath }: UserMenuProps) {
|
|
|
41
43
|
trigger={
|
|
42
44
|
<div
|
|
43
45
|
className="flex justify-center p-.5 text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)] hover:bg-[var(--kyro-surface)] rounded-xl transition-all shadow-sm active:scale-95"
|
|
44
|
-
title="Account"
|
|
46
|
+
title={t("userMenu.account", { defaultValue: "Account" })}
|
|
45
47
|
>
|
|
46
48
|
{avatarUrl ? (
|
|
47
49
|
<img src={avatarUrl} alt="" className="w-8 h-8 rounded-full object-cover" />
|
|
@@ -53,7 +55,7 @@ export function UserMenu({ adminPath }: UserMenuProps) {
|
|
|
53
55
|
>
|
|
54
56
|
<div className="px-4 py-2 mb-1">
|
|
55
57
|
<p className="text-[10px] font-medium tracking-[0.2em] text-[var(--kyro-text-secondary)] opacity-40">
|
|
56
|
-
Account
|
|
58
|
+
{t("userMenu.account", { defaultValue: "Account" })}
|
|
57
59
|
</p>
|
|
58
60
|
</div>
|
|
59
61
|
|
|
@@ -68,21 +70,21 @@ export function UserMenu({ adminPath }: UserMenuProps) {
|
|
|
68
70
|
}
|
|
69
71
|
}}
|
|
70
72
|
>
|
|
71
|
-
Profile Settings
|
|
73
|
+
{t("userMenu.profileSettings", { defaultValue: "Profile Settings" })}
|
|
72
74
|
</DropdownItem>
|
|
73
75
|
|
|
74
76
|
<DropdownItem
|
|
75
77
|
icon={<Shield className="w-4 h-4" />}
|
|
76
78
|
onClick={() => window.location.href = `${adminPath}/roles`}
|
|
77
79
|
>
|
|
78
|
-
Permissions
|
|
80
|
+
{t("userMenu.permissions", { defaultValue: "Permissions" })}
|
|
79
81
|
</DropdownItem>
|
|
80
82
|
|
|
81
83
|
<DropdownSeparator />
|
|
82
84
|
|
|
83
85
|
<div className="px-4 py-2 mb-1">
|
|
84
86
|
<p className="text-[10px] font-medium tracking-[0.2em] text-[var(--kyro-text-secondary)] opacity-40">
|
|
85
|
-
Developer
|
|
87
|
+
{t("userMenu.developer", { defaultValue: "Developer" })}
|
|
86
88
|
</p>
|
|
87
89
|
</div>
|
|
88
90
|
|
|
@@ -90,33 +92,33 @@ export function UserMenu({ adminPath }: UserMenuProps) {
|
|
|
90
92
|
icon={<Key className="w-4 h-4" />}
|
|
91
93
|
onClick={() => (window.location.href = `${adminPath}/keys`)}
|
|
92
94
|
>
|
|
93
|
-
API Keys
|
|
95
|
+
{t("userMenu.apiKeys", { defaultValue: "API Keys" })}
|
|
94
96
|
</DropdownItem>
|
|
95
97
|
|
|
96
98
|
<DropdownItem
|
|
97
99
|
icon={<Webhook className="w-4 h-4" />}
|
|
98
100
|
onClick={() => (window.location.href = `${adminPath}/webhooks`)}
|
|
99
101
|
>
|
|
100
|
-
Web Hooks
|
|
102
|
+
{t("userMenu.webHooks", { defaultValue: "Web Hooks" })}
|
|
101
103
|
</DropdownItem>
|
|
102
104
|
<DropdownItem
|
|
103
105
|
icon={<Clock className="w-4 h-4" />}
|
|
104
106
|
onClick={() => (window.location.href = `${adminPath}/sessions`)}
|
|
105
107
|
>
|
|
106
|
-
Sessions
|
|
108
|
+
{t("userMenu.sessions", { defaultValue: "Sessions" })}
|
|
107
109
|
</DropdownItem>
|
|
108
110
|
<DropdownItem
|
|
109
111
|
icon={<FileText className="w-4 h-4" />}
|
|
110
112
|
onClick={() => (window.location.href = `${adminPath}/audit`)}
|
|
111
113
|
>
|
|
112
|
-
Audit Logs
|
|
114
|
+
{t("userMenu.auditLogs", { defaultValue: "Audit Logs" })}
|
|
113
115
|
</DropdownItem>
|
|
114
116
|
|
|
115
117
|
<DropdownItem
|
|
116
118
|
icon={<Terminal className="w-4 h-4" />}
|
|
117
119
|
onClick={() => (window.location.href = `${adminPath}/rest-playground`)}
|
|
118
120
|
>
|
|
119
|
-
API Explorer
|
|
121
|
+
{t("userMenu.apiExplorer", { defaultValue: "API Explorer" })}
|
|
120
122
|
</DropdownItem>
|
|
121
123
|
|
|
122
124
|
{(apiAccess === null || apiAccess?.graphqlEnabled) && (
|
|
@@ -124,7 +126,7 @@ export function UserMenu({ adminPath }: UserMenuProps) {
|
|
|
124
126
|
icon={<Zap className="w-4 h-4" />}
|
|
125
127
|
onClick={() => (window.location.href = `${adminPath}/graphql`)}
|
|
126
128
|
>
|
|
127
|
-
GraphQL Playground
|
|
129
|
+
{t("userMenu.graphqlPlayground", { defaultValue: "GraphQL Playground" })}
|
|
128
130
|
</DropdownItem>
|
|
129
131
|
)}
|
|
130
132
|
|
|
@@ -132,22 +134,22 @@ export function UserMenu({ adminPath }: UserMenuProps) {
|
|
|
132
134
|
|
|
133
135
|
<div className="px-4 py-2 mb-1">
|
|
134
136
|
<p className="text-[10px] font-medium tracking-[0.2em] text-[var(--kyro-text-secondary)] opacity-40">
|
|
135
|
-
Resources
|
|
137
|
+
{t("userMenu.resources", { defaultValue: "Resources" })}
|
|
136
138
|
</p>
|
|
137
139
|
</div>
|
|
138
140
|
|
|
139
141
|
<DropdownItem
|
|
140
142
|
icon={<ExternalLink className="w-4 h-4" />}
|
|
141
|
-
onClick={() => window.open("https://
|
|
143
|
+
onClick={() => window.open("https://kyro-cms.com/getting-started.html", "_blank")}
|
|
142
144
|
>
|
|
143
|
-
Documentation
|
|
145
|
+
{t("userMenu.documentation", { defaultValue: "Documentation" })}
|
|
144
146
|
</DropdownItem>
|
|
145
147
|
|
|
146
148
|
<DropdownItem
|
|
147
149
|
icon={<HelpCircle className="w-4 h-4" />}
|
|
148
|
-
onClick={() => window.open("https://github.com/danielDozie/kyro-cms/issues", "_blank")}
|
|
150
|
+
onClick={() => window.open("https://github.com/danielDozie/kyro-cms/issues/new", "_blank")}
|
|
149
151
|
>
|
|
150
|
-
Get Support
|
|
152
|
+
{t("userMenu.getSupport", { defaultValue: "Get Support" })}
|
|
151
153
|
</DropdownItem>
|
|
152
154
|
|
|
153
155
|
<DropdownSeparator />
|
|
@@ -157,7 +159,7 @@ export function UserMenu({ adminPath }: UserMenuProps) {
|
|
|
157
159
|
danger
|
|
158
160
|
onClick={() => document.getElementById("logout-btn")?.click()}
|
|
159
161
|
>
|
|
160
|
-
Sign Out
|
|
162
|
+
{t("actions.signOut", { defaultValue: "Sign Out" })}
|
|
161
163
|
</DropdownItem>
|
|
162
164
|
</Dropdown>
|
|
163
165
|
);
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { SlidePanel } from "./ui/SlidePanel";
|
|
3
3
|
import { Spinner } from "./ui/Spinner";
|
|
4
4
|
import { History, Eye, GitCompare, Undo2, CheckCircle2, Clock, User } from "lucide-react";
|
|
5
|
+
import { useTranslation } from "react-i18next";
|
|
5
6
|
|
|
6
7
|
interface Version {
|
|
7
8
|
id: string;
|
|
@@ -38,6 +39,7 @@ export function VersionHistoryPanel({
|
|
|
38
39
|
onCompare,
|
|
39
40
|
loading = false,
|
|
40
41
|
}: VersionHistoryPanelProps) {
|
|
42
|
+
const { t } = useTranslation();
|
|
41
43
|
const formatDate = (dateValue: any) => {
|
|
42
44
|
if (!dateValue) return "Unknown date";
|
|
43
45
|
const date = new Date(dateValue);
|
|
@@ -82,7 +84,7 @@ export function VersionHistoryPanel({
|
|
|
82
84
|
<SlidePanel
|
|
83
85
|
open={open}
|
|
84
86
|
onClose={onClose}
|
|
85
|
-
title="Version History"
|
|
87
|
+
title={t("tooltips.versionHistory", { defaultValue: "Version History" })}
|
|
86
88
|
width="md"
|
|
87
89
|
>
|
|
88
90
|
{loading ? (
|
|
@@ -159,7 +161,7 @@ export function VersionHistoryPanel({
|
|
|
159
161
|
<button type="button"
|
|
160
162
|
onClick={() => onPreview(version)}
|
|
161
163
|
className="p-2 text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-primary)] hover:bg-[var(--kyro-primary)]/10 rounded-md transition-colors"
|
|
162
|
-
title="Preview this version"
|
|
164
|
+
title={t("tooltips.previewThisVersion", { defaultValue: "Preview this version" })}
|
|
163
165
|
>
|
|
164
166
|
<Eye className="w-4 h-4" />
|
|
165
167
|
</button>
|
|
@@ -172,7 +174,7 @@ export function VersionHistoryPanel({
|
|
|
172
174
|
)
|
|
173
175
|
}
|
|
174
176
|
className="p-2 text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-primary)] hover:bg-[var(--kyro-primary)]/10 rounded-md transition-colors"
|
|
175
|
-
title="Compare with current"
|
|
177
|
+
title={t("tooltips.compareWithCurrent", { defaultValue: "Compare with current" })}
|
|
176
178
|
>
|
|
177
179
|
<GitCompare className="w-4 h-4" />
|
|
178
180
|
</button>
|
|
@@ -181,7 +183,7 @@ export function VersionHistoryPanel({
|
|
|
181
183
|
<button type="button"
|
|
182
184
|
onClick={() => onRestore(version)}
|
|
183
185
|
className="p-2 text-amber-600 hover:bg-amber-500/10 rounded-md transition-colors"
|
|
184
|
-
title="Restore this version"
|
|
186
|
+
title={t("tooltips.restoreThisVersion", { defaultValue: "Restore this version" })}
|
|
185
187
|
>
|
|
186
188
|
<Undo2 className="w-4 h-4" />
|
|
187
189
|
</button>
|
|
@@ -24,7 +24,7 @@ import { useUIStore, toast } from "../lib/stores";
|
|
|
24
24
|
import { Modal, ModalContent, ModalActions } from "./ui/Modal";
|
|
25
25
|
import { Badge } from "./ui/Badge";
|
|
26
26
|
import { PageHeader } from "./ui/PageHeader";
|
|
27
|
-
|
|
27
|
+
import { useTranslation } from "react-i18next";
|
|
28
28
|
|
|
29
29
|
interface WebhookConfigField {
|
|
30
30
|
name: string;
|
|
@@ -76,6 +76,7 @@ const ACTION_ICONS: Record<string, string> = {
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
export function WebhookManager() {
|
|
79
|
+
const { t } = useTranslation();
|
|
79
80
|
const {
|
|
80
81
|
items: webhooks,
|
|
81
82
|
loading,
|
|
@@ -265,7 +266,7 @@ export function WebhookManager() {
|
|
|
265
266
|
return (
|
|
266
267
|
<div className="w-full space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700 pb-32">
|
|
267
268
|
<PageHeader
|
|
268
|
-
title="Webhooks"
|
|
269
|
+
title={t("tooltips.webhooks", { defaultValue: "Webhooks" })}
|
|
269
270
|
description="Get notified when your content changes."
|
|
270
271
|
icon={Webhook}
|
|
271
272
|
actions={[
|
|
@@ -410,7 +411,7 @@ export function WebhookManager() {
|
|
|
410
411
|
type="button"
|
|
411
412
|
onClick={() => handleViewHistory(webhook.id)}
|
|
412
413
|
className="p-2 rounded-lg border border-[var(--kyro-border)] hover:border-[var(--kyro-primary)] transition-colors flex items-center gap-1.5"
|
|
413
|
-
title="View delivery history"
|
|
414
|
+
title={t("tooltips.viewDeliveryHistory", { defaultValue: "View delivery history" })}
|
|
414
415
|
>
|
|
415
416
|
<Activity className="w-3.5 h-3.5" />
|
|
416
417
|
<span className="text-[11px] font-medium hidden sm:inline">History</span>
|
|
@@ -420,7 +421,7 @@ export function WebhookManager() {
|
|
|
420
421
|
type="button"
|
|
421
422
|
onClick={() => handleTest(webhook.id)}
|
|
422
423
|
className="p-2 rounded-lg border border-[var(--kyro-border)] hover:border-[var(--kyro-primary)] transition-colors flex items-center gap-1.5"
|
|
423
|
-
title="Send test request"
|
|
424
|
+
title={t("tooltips.sendTestRequest", { defaultValue: "Send test request" })}
|
|
424
425
|
>
|
|
425
426
|
<Send className="w-3.5 h-3.5" />
|
|
426
427
|
<span className="text-[11px] font-medium">Test</span>
|
|
@@ -439,7 +440,7 @@ export function WebhookManager() {
|
|
|
439
440
|
type="button"
|
|
440
441
|
onClick={() => remove(webhook.id, "Webhook")}
|
|
441
442
|
className="p-2 rounded-lg border border-[var(--kyro-border)] hover:border-red-500/30 hover:bg-red-500/5 transition-colors"
|
|
442
|
-
title="Delete"
|
|
443
|
+
title={t("tooltips.delete", { defaultValue: "Delete" })}
|
|
443
444
|
>
|
|
444
445
|
<Trash2 className="w-3.5 h-3.5 text-red-500/50 hover:text-red-500" />
|
|
445
446
|
</button>
|
|
@@ -455,7 +456,7 @@ export function WebhookManager() {
|
|
|
455
456
|
<Modal
|
|
456
457
|
open={showCreateModal && step === "action"}
|
|
457
458
|
onClose={() => setShowCreateModal(false)}
|
|
458
|
-
title="New webhook"
|
|
459
|
+
title={t("tooltips.newWebhook", { defaultValue: "New webhook" })}
|
|
459
460
|
>
|
|
460
461
|
<ModalContent>
|
|
461
462
|
<div className="space-y-4">
|
|
@@ -552,7 +553,7 @@ export function WebhookManager() {
|
|
|
552
553
|
type="text"
|
|
553
554
|
value={formData.secret}
|
|
554
555
|
onChange={(e) => setFormData({ ...formData, secret: e.target.value })}
|
|
555
|
-
placeholder="Optional"
|
|
556
|
+
placeholder={t("fields.optional", { defaultValue: "Optional" })}
|
|
556
557
|
className="w-full px-3 py-2.5 bg-[var(--kyro-bg)] border border-[var(--kyro-border)] rounded-lg text-sm text-[var(--kyro-text-primary)] focus:outline-none focus:border-[var(--kyro-primary)]"
|
|
557
558
|
/>
|
|
558
559
|
</div>
|
|
@@ -639,7 +640,7 @@ export function WebhookManager() {
|
|
|
639
640
|
<Modal
|
|
640
641
|
open={showTestModal}
|
|
641
642
|
onClose={() => setShowTestModal(false)}
|
|
642
|
-
title="Test webhook"
|
|
643
|
+
title={t("tooltips.testWebhook", { defaultValue: "Test webhook" })}
|
|
643
644
|
>
|
|
644
645
|
<ModalContent>
|
|
645
646
|
<div className="p-6 rounded-xl bg-[var(--kyro-surface)] border border-[var(--kyro-border)] text-center">
|
|
@@ -681,7 +682,7 @@ export function WebhookManager() {
|
|
|
681
682
|
<Modal
|
|
682
683
|
open={showHelpModal}
|
|
683
684
|
onClose={() => setShowHelpModal(false)}
|
|
684
|
-
title="How webhooks work"
|
|
685
|
+
title={t("tooltips.howWebhooksWork", { defaultValue: "How webhooks work" })}
|
|
685
686
|
>
|
|
686
687
|
<ModalContent>
|
|
687
688
|
<div className="space-y-6">
|
|
@@ -737,7 +738,7 @@ export function WebhookManager() {
|
|
|
737
738
|
<Modal
|
|
738
739
|
open={showHistoryModal}
|
|
739
740
|
onClose={() => setShowHistoryModal(false)}
|
|
740
|
-
title="Delivery History"
|
|
741
|
+
title={t("tooltips.deliveryHistory", { defaultValue: "Delivery History" })}
|
|
741
742
|
>
|
|
742
743
|
<ModalContent>
|
|
743
744
|
<div className="space-y-4">
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { useAutoFormStore } from "../../lib/autoform-store";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
3
4
|
|
|
4
5
|
interface AutoFormApiViewProps {
|
|
5
6
|
collectionSlug?: string;
|
|
@@ -10,6 +11,7 @@ export function AutoFormApiView({
|
|
|
10
11
|
collectionSlug,
|
|
11
12
|
globalSlug,
|
|
12
13
|
}: AutoFormApiViewProps) {
|
|
14
|
+
const { t } = useTranslation();
|
|
13
15
|
const { formData } = useAutoFormStore();
|
|
14
16
|
|
|
15
17
|
return (
|
|
@@ -57,7 +59,7 @@ export function AutoFormApiView({
|
|
|
57
59
|
navigator.clipboard.writeText(String(formData.id));
|
|
58
60
|
}}
|
|
59
61
|
className="p-1.5 hover:bg-[var(--kyro-bg-secondary)] rounded-lg transition-colors text-[var(--kyro-text-secondary)] hover:text-[var(--kyro-text-primary)]"
|
|
60
|
-
title="Copy ID"
|
|
62
|
+
title={t("tooltips.copyId", { defaultValue: "Copy ID" })}
|
|
61
63
|
>
|
|
62
64
|
<svg
|
|
63
65
|
width="14"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { CollectionConfig, GlobalConfig, Field } from "@kyro-cms/core/client";
|
|
3
3
|
import { useAutoFormStore } from "../../lib/autoform-store";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
4
5
|
|
|
5
6
|
interface AutoFormEditViewProps {
|
|
6
7
|
config: CollectionConfig | GlobalConfig;
|
|
@@ -15,6 +16,7 @@ export function AutoFormEditView({
|
|
|
15
16
|
collectionSlug,
|
|
16
17
|
renderField,
|
|
17
18
|
}: AutoFormEditViewProps) {
|
|
19
|
+
const { t } = useTranslation();
|
|
18
20
|
const { showPreview, sidebarCollapsed, formData, previewUrl } = useAutoFormStore();
|
|
19
21
|
|
|
20
22
|
if (layout === "single") {
|
|
@@ -67,7 +69,7 @@ export function AutoFormEditView({
|
|
|
67
69
|
<iframe
|
|
68
70
|
src={previewUrl || ""}
|
|
69
71
|
className="w-full h-full border-none"
|
|
70
|
-
title="Live Preview"
|
|
72
|
+
title={t("tooltips.livePreview", { defaultValue: "Live Preview" })}
|
|
71
73
|
/>
|
|
72
74
|
<div className="absolute inset-0 bg-transparent pointer-events-none border-[12px] border-[var(--kyro-surface)] rounded-3xl" />
|
|
73
75
|
</div>
|
|
@@ -5,6 +5,7 @@ import { SplitButton } from "../ui/SplitButton";
|
|
|
5
5
|
import type { SplitButtonStatus } from "../ui/SplitButton";
|
|
6
6
|
import { useAutoFormStore } from "../../lib/autoform-store";
|
|
7
7
|
import { adminPath as ADMIN_BASE } from "../../lib/paths";
|
|
8
|
+
import { useTranslation } from "react-i18next";
|
|
8
9
|
|
|
9
10
|
type View = "edit" | "version" | "api";
|
|
10
11
|
|
|
@@ -41,6 +42,7 @@ export function AutoFormHeader({
|
|
|
41
42
|
handleSchedulePublish,
|
|
42
43
|
handleConflictOverride,
|
|
43
44
|
}: AutoFormHeaderProps) {
|
|
45
|
+
const { t } = useTranslation();
|
|
44
46
|
const [now, setNow] = useState(Date.now());
|
|
45
47
|
const [showSchedulePicker, setShowSchedulePicker] = useState(false);
|
|
46
48
|
const scheduleRef = useRef<HTMLDivElement>(null);
|
|
@@ -194,7 +196,7 @@ export function AutoFormHeader({
|
|
|
194
196
|
<button
|
|
195
197
|
type="button"
|
|
196
198
|
className="kyro-btn p-2 md:p-2.5 rounded-xl border border-[var(--kyro-border)] hover:bg-[var(--kyro-bg-secondary)] transition-all"
|
|
197
|
-
title="More actions"
|
|
199
|
+
title={t("tooltips.moreActions", { defaultValue: "More actions" })}
|
|
198
200
|
>
|
|
199
201
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
|
200
202
|
<circle cx="12" cy="5" r="1.5" />
|
|
@@ -377,8 +379,7 @@ export function AutoFormHeader({
|
|
|
377
379
|
<button
|
|
378
380
|
type="button"
|
|
379
381
|
onClick={() => {
|
|
380
|
-
|
|
381
|
-
markSaved();
|
|
382
|
+
useAutoFormStore.getState().loadDocument(lastSavedData, lastSavedData);
|
|
382
383
|
}}
|
|
383
384
|
className="text-[var(--kyro-primary)] text-[10px] font-medium hover:underline"
|
|
384
385
|
>
|
|
@@ -424,8 +425,7 @@ export function AutoFormHeader({
|
|
|
424
425
|
<button
|
|
425
426
|
type="button"
|
|
426
427
|
onClick={() => {
|
|
427
|
-
|
|
428
|
-
markSaved();
|
|
428
|
+
useAutoFormStore.getState().loadDocument(lastSavedData, lastSavedData);
|
|
429
429
|
}}
|
|
430
430
|
className="text-[var(--kyro-primary)] hover:underline"
|
|
431
431
|
>
|
|
@@ -475,7 +475,7 @@ export function AutoFormHeader({
|
|
|
475
475
|
type="button"
|
|
476
476
|
onClick={() => setShowPreview(!showPreview)}
|
|
477
477
|
className={`kyro-btn p-2.5 rounded-xl transition-all flex items-center gap-2 ${showPreview ? "shadow-lg" : "text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-bg-secondary)]"}`}
|
|
478
|
-
title="Live Preview"
|
|
478
|
+
title={t("tooltips.livePreview", { defaultValue: "Live Preview" })}
|
|
479
479
|
>
|
|
480
480
|
<ExternalLink className="w-4 h-4" />
|
|
481
481
|
{showPreview && (
|
|
@@ -5,11 +5,13 @@ import {
|
|
|
5
5
|
} from "../fields/extensions/blocksStore";
|
|
6
6
|
import { ChevronRight, X } from "../ui/icons";
|
|
7
7
|
import { AccordionField } from "../fields/AccordionField";
|
|
8
|
+
import { useTranslation } from "react-i18next";
|
|
8
9
|
|
|
9
10
|
export const AccordionBlock: 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
|
|
|
@@ -36,7 +38,7 @@ export const AccordionBlock: React.FC<{ block: Record<string, unknown>; index: n
|
|
|
36
38
|
type="button"
|
|
37
39
|
onClick={() => moveBlock(block.id, "up")}
|
|
38
40
|
className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
|
|
39
|
-
title="Move up"
|
|
41
|
+
title={t("tooltips.moveUp", { defaultValue: "Move up" })}
|
|
40
42
|
>
|
|
41
43
|
<ChevronRight className="w-3 h-3 rotate-90" />
|
|
42
44
|
</button>
|
|
@@ -44,7 +46,7 @@ export const AccordionBlock: React.FC<{ block: Record<string, unknown>; index: n
|
|
|
44
46
|
type="button"
|
|
45
47
|
onClick={() => moveBlock(block.id, "down")}
|
|
46
48
|
className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
|
|
47
|
-
title="Move down"
|
|
49
|
+
title={t("tooltips.moveDown", { defaultValue: "Move down" })}
|
|
48
50
|
>
|
|
49
51
|
<ChevronRight className="w-3 h-3" />
|
|
50
52
|
</button>
|
|
@@ -52,7 +54,7 @@ export const AccordionBlock: React.FC<{ block: Record<string, unknown>; index: n
|
|
|
52
54
|
type="button"
|
|
53
55
|
onClick={() => removeBlock(block.id)}
|
|
54
56
|
className="p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]"
|
|
55
|
-
title="Remove"
|
|
57
|
+
title={t("tooltips.remove", { defaultValue: "Remove" })}
|
|
56
58
|
>
|
|
57
59
|
<X className="w-3 h-3" />
|
|
58
60
|
</button>
|
|
@@ -5,11 +5,13 @@ import {
|
|
|
5
5
|
} from "../fields/extensions/blocksStore";
|
|
6
6
|
import { ChevronRight, X } from "../ui/icons";
|
|
7
7
|
import { ChildBlocksTree } from "./ChildBlocksTree";
|
|
8
|
+
import { useTranslation } from "react-i18next";
|
|
8
9
|
|
|
9
10
|
export const ArrayBlock: 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
|
|
|
@@ -32,7 +34,7 @@ export const ArrayBlock: React.FC<{ block: Record<string, unknown>; index: numbe
|
|
|
32
34
|
type="button"
|
|
33
35
|
onClick={() => moveBlock(block.id, "up")}
|
|
34
36
|
className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
|
|
35
|
-
title="Move up"
|
|
37
|
+
title={t("tooltips.moveUp", { defaultValue: "Move up" })}
|
|
36
38
|
>
|
|
37
39
|
<ChevronRight className="w-3 h-3 rotate-90" />
|
|
38
40
|
</button>
|
|
@@ -40,7 +42,7 @@ export const ArrayBlock: React.FC<{ block: Record<string, unknown>; index: numbe
|
|
|
40
42
|
type="button"
|
|
41
43
|
onClick={() => moveBlock(block.id, "down")}
|
|
42
44
|
className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded"
|
|
43
|
-
title="Move down"
|
|
45
|
+
title={t("tooltips.moveDown", { defaultValue: "Move down" })}
|
|
44
46
|
>
|
|
45
47
|
<ChevronRight className="w-3 h-3" />
|
|
46
48
|
</button>
|
|
@@ -48,7 +50,7 @@ export const ArrayBlock: React.FC<{ block: Record<string, unknown>; index: numbe
|
|
|
48
50
|
type="button"
|
|
49
51
|
onClick={() => removeBlock(block.id)}
|
|
50
52
|
className="p-1 hover:bg-[var(--kyro-danger-bg)] rounded text-[var(--kyro-danger)]"
|
|
51
|
-
title="Remove"
|
|
53
|
+
title={t("tooltips.remove", { defaultValue: "Remove" })}
|
|
52
54
|
>
|
|
53
55
|
<X className="w-3 h-3" />
|
|
54
56
|
</button>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { ChevronRight, X } from "../ui/icons";
|
|
3
3
|
import { useBlockActions } from "../fields/extensions/blocksStore";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
4
5
|
|
|
5
6
|
interface BlockWrapperProps {
|
|
6
7
|
id: string;
|
|
@@ -17,6 +18,7 @@ export const BlockWrapper: React.FC<BlockWrapperProps> = ({
|
|
|
17
18
|
children,
|
|
18
19
|
className = "",
|
|
19
20
|
}) => {
|
|
21
|
+
const { t } = useTranslation();
|
|
20
22
|
const { moveBlock, removeBlock } = useBlockActions();
|
|
21
23
|
|
|
22
24
|
return (
|
|
@@ -30,7 +32,7 @@ export const BlockWrapper: React.FC<BlockWrapperProps> = ({
|
|
|
30
32
|
type="button"
|
|
31
33
|
onClick={() => moveBlock(id, "up")}
|
|
32
34
|
className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded text-[var(--kyro-text-muted)] hover:text-[var(--kyro-primary)]"
|
|
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 BlockWrapper: React.FC<BlockWrapperProps> = ({
|
|
|
38
40
|
type="button"
|
|
39
41
|
onClick={() => moveBlock(id, "down")}
|
|
40
42
|
className="p-1 hover:bg-[var(--kyro-surface-accent)] rounded text-[var(--kyro-text-muted)] hover:text-[var(--kyro-primary)]"
|
|
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 BlockWrapper: React.FC<BlockWrapperProps> = ({
|
|
|
46
48
|
type="button"
|
|
47
49
|
onClick={() => removeBlock(id)}
|
|
48
50
|
className="p-1 hover:bg-[var(--kyro-error)]/10 rounded text-[var(--kyro-error)]"
|
|
49
|
-
title="Remove"
|
|
51
|
+
title={t("tooltips.remove", { defaultValue: "Remove" })}
|
|
50
52
|
>
|
|
51
53
|
<X className="w-3 h-3" />
|
|
52
54
|
</button>
|
|
@@ -5,11 +5,13 @@ import {
|
|
|
5
5
|
} from "../fields/extensions/blocksStore";
|
|
6
6
|
import { ChevronRight, X, Code2 } from "../ui/icons";
|
|
7
7
|
import { CodeField } from "../fields/CodeField";
|
|
8
|
+
import { useTranslation } from "react-i18next";
|
|
8
9
|
|
|
9
10
|
export const CodeBlock: 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 ?? {};
|
|
@@ -39,7 +41,7 @@ export const CodeBlock: React.FC<{ block: Record<string, unknown>; index: number
|
|
|
39
41
|
type="button"
|
|
40
42
|
onClick={() => moveBlock(block.id, "up")}
|
|
41
43
|
className="p-1.5 hover:bg-[var(--kyro-surface)] rounded-lg transition-all text-[var(--kyro-text-muted)] hover:text-[var(--kyro-primary)]"
|
|
42
|
-
title="Move up"
|
|
44
|
+
title={t("tooltips.moveUp", { defaultValue: "Move up" })}
|
|
43
45
|
>
|
|
44
46
|
<ChevronRight className="w-4 h-4 rotate-[-90deg]" />
|
|
45
47
|
</button>
|
|
@@ -48,7 +50,7 @@ export const CodeBlock: React.FC<{ block: Record<string, unknown>; index: number
|
|
|
48
50
|
type="button"
|
|
49
51
|
onClick={() => removeBlock(block.id)}
|
|
50
52
|
className="p-1.5 hover:bg-[var(--kyro-danger-bg)] rounded-lg transition-all text-[var(--kyro-text-muted)] hover:text-[var(--kyro-danger)]"
|
|
51
|
-
title="Remove"
|
|
53
|
+
title={t("tooltips.remove", { defaultValue: "Remove" })}
|
|
52
54
|
>
|
|
53
55
|
<X className="w-4 h-4" />
|
|
54
56
|
</button>
|
|
@@ -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 FileBlock: 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 FileBlock: React.FC<{ block: Record<string, unknown>; index: number
|
|
|
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 FileBlock: React.FC<{ block: Record<string, unknown>; index: number
|
|
|
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 FileBlock: React.FC<{ block: Record<string, unknown>; index: number
|
|
|
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>
|
|
@@ -7,11 +7,13 @@ import { ChevronRight, X } from "../ui/icons";
|
|
|
7
7
|
import { HeroField } from "../fields/HeroField";
|
|
8
8
|
import { UploadField } from "../fields/UploadField";
|
|
9
9
|
import { ChildBlocksTree } from "./ChildBlocksTree";
|
|
10
|
+
import { useTranslation } from "react-i18next";
|
|
10
11
|
|
|
11
12
|
export const HeroBlock: React.FC<{ block: Record<string, unknown>; index: number }> = ({
|
|
12
13
|
block,
|
|
13
14
|
index,
|
|
14
15
|
}) => {
|
|
16
|
+
const { t } = useTranslation();
|
|
15
17
|
const blockData = useBlockById(block.id);
|
|
16
18
|
const { updateBlock, removeBlock, moveBlock } = useBlockActions();
|
|
17
19
|
|
|
@@ -35,7 +37,7 @@ export const HeroBlock: React.FC<{ block: Record<string, unknown>; index: number
|
|
|
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 HeroBlock: React.FC<{ block: Record<string, unknown>; index: number
|
|
|
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 HeroBlock: React.FC<{ block: Record<string, unknown>; index: number
|
|
|
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>
|