@arronqzy/react-view 1.0.3 → 1.0.7
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/styles.css +555 -15
- package/package.json +14 -7
- package/readme.md +74 -5
- package/src/core/template.tsx +12 -2
- package/src/panel/ReactViewOnlinePreview.tsx +18 -8
- package/src/panel/ReactViewPanel.tsx +403 -177
- package/src/panel/ai/AssistantChatPanel.tsx +895 -0
- package/src/panel/ai/AssistantMarkdown.tsx +256 -0
- package/src/panel/ai/applyAssistantAction.ts +652 -0
- package/src/panel/ai/revealConfigField.ts +137 -0
- package/src/panel/components/ConfigHintIcon.tsx +50 -0
- package/src/panel/components/ElementsLayer.tsx +39 -22
- package/src/panel/components/MaterialSidebar.tsx +157 -109
- package/src/panel/components/MoveableLayer.tsx +75 -61
- package/src/panel/components/PanelCanvas.tsx +81 -64
- package/src/panel/components/PanelConfigSidebar.tsx +471 -448
- package/src/panel/components/SelectLayer.tsx +1 -0
- package/src/panel/components/ViewElementScopePanel.tsx +13 -12
- package/src/panel/components/WorkspaceConfigSidebar.tsx +5 -2
- package/src/panel/components/WorkspaceProjectNav.tsx +25 -14
- package/src/panel/components/WorkspaceStageSplit.tsx +3 -1
- package/src/panel/components/scope-config/ScopeConfigContext.tsx +9 -0
- package/src/panel/components/scope-config/ScopeTemplatePreviewHost.tsx +242 -0
- package/src/panel/components/scope-config/ScopeTemplateUsageHint.tsx +12 -0
- package/src/panel/components/scope-config/ScopeTemplateWarningsPanel.tsx +6 -3
- package/src/panel/components/table/ConditionEditor.tsx +205 -0
- package/src/panel/components/table/JsonCodeEditor.tsx +115 -0
- package/src/panel/components/table/PanelConfigTableSection.tsx +2192 -0
- package/src/panel/components/table/TableNodeContent.tsx +544 -0
- package/src/panel/constants/messages.ts +76 -34
- package/src/panel/hooks/usePanelElements.ts +64 -52
- package/src/panel/hooks/useRafThrottledScroll.ts +30 -0
- package/src/panel/hooks/useWorkspaceProjects.ts +11 -8
- package/src/panel/types.ts +6 -0
- package/src/panel/utils/chartOptionBuilder.ts +12 -1
- package/src/panel/utils/panelElementDefaults.ts +69 -39
- package/src/panel/utils/scope-field-labels.ts +51 -37
- package/src/panel/utils/scope-template-chart.ts +92 -0
- package/src/panel/utils/scope-template-preview.ts +128 -0
- package/src/panel/utils/scope-template-spread.ts +252 -0
- package/src/panel/utils/scope-template-warnings.ts +131 -11
- package/src/panel/utils/scope-template.ts +105 -3
- package/src/tailwind.css +36 -15
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
2
3
|
import {
|
|
3
4
|
Card,
|
|
4
5
|
CardContent,
|
|
@@ -19,10 +20,6 @@ import {
|
|
|
19
20
|
SelectTrigger,
|
|
20
21
|
SelectValue,
|
|
21
22
|
Textarea,
|
|
22
|
-
Tooltip,
|
|
23
|
-
TooltipContent,
|
|
24
|
-
TooltipProvider,
|
|
25
|
-
TooltipTrigger,
|
|
26
23
|
} from "@arronqzy/ui";
|
|
27
24
|
import type {
|
|
28
25
|
PanelChartConfig,
|
|
@@ -30,14 +27,20 @@ import type {
|
|
|
30
27
|
PanelElementStyle,
|
|
31
28
|
ReferenceCopyMode,
|
|
32
29
|
} from "../types";
|
|
33
|
-
import { buildChartOption, CHART_TYPES, getChartValuesDisplayText } from "../utils/chartOptionBuilder";
|
|
30
|
+
import { buildChartOption, CHART_TYPES, getChartLabelsDisplayText, getChartValuesDisplayText } from "../utils/chartOptionBuilder";
|
|
34
31
|
import type { PanelLayer } from "../types";
|
|
35
|
-
import {
|
|
32
|
+
import { getPanelMessages } from "../constants/messages";
|
|
36
33
|
import { ViewElementScopePanel } from "./ViewElementScopePanel";
|
|
34
|
+
import { ConfigHintIcon } from "./ConfigHintIcon";
|
|
37
35
|
import { hasViewElementScope } from "../scope/view-scope-store";
|
|
38
36
|
import { collectElementScopeWarnings } from "../utils/scope-template-warnings";
|
|
39
37
|
import { ScopeConfigProvider } from "./scope-config/ScopeConfigContext";
|
|
40
38
|
import { ScopeTemplateWarningsPanel } from "./scope-config/ScopeTemplateWarningsPanel";
|
|
39
|
+
import { PanelConfigTableSection } from "./table/PanelConfigTableSection";
|
|
40
|
+
import {
|
|
41
|
+
highlightConfigField,
|
|
42
|
+
subscribeRevealPanelConfig,
|
|
43
|
+
} from "../ai/revealConfigField";
|
|
41
44
|
|
|
42
45
|
type UpdateElement = (
|
|
43
46
|
id: string,
|
|
@@ -59,6 +62,7 @@ export type PanelConfigSidebarProps = {
|
|
|
59
62
|
) => void;
|
|
60
63
|
/** 蓝图视图绑定节点写入的信号 scope,用于展示与模版解析 */
|
|
61
64
|
viewElementScope?: unknown;
|
|
65
|
+
blueprintNodeOptions?: { id: string; label: string }[];
|
|
62
66
|
};
|
|
63
67
|
|
|
64
68
|
export function PanelConfigSidebar({
|
|
@@ -71,7 +75,11 @@ export function PanelConfigSidebar({
|
|
|
71
75
|
onExcludeSelectedNode,
|
|
72
76
|
onAdjustNodeZOrder,
|
|
73
77
|
viewElementScope,
|
|
78
|
+
blueprintNodeOptions = [],
|
|
74
79
|
}: PanelConfigSidebarProps) {
|
|
80
|
+
const { t } = useI18n();
|
|
81
|
+
const messages = React.useMemo(() => getPanelMessages(t), [t]);
|
|
82
|
+
|
|
75
83
|
const [isAdvancedOptionMode, setIsAdvancedOptionMode] = useState(false);
|
|
76
84
|
const [optionJsonText, setOptionJsonText] = useState("{}");
|
|
77
85
|
const [optionJsonError, setOptionJsonError] = useState<string | null>(null);
|
|
@@ -116,9 +124,9 @@ export function PanelConfigSidebar({
|
|
|
116
124
|
const readonlyReason = !selectedElement
|
|
117
125
|
? ""
|
|
118
126
|
: selectedElement.locked
|
|
119
|
-
?
|
|
127
|
+
? messages.nodeConfigLocked
|
|
120
128
|
: selectedLayer?.locked
|
|
121
|
-
?
|
|
129
|
+
? messages.nodeConfigLayerLocked
|
|
122
130
|
: "";
|
|
123
131
|
const selectedChartType = (selectedElement?.materialType ?? "") as
|
|
124
132
|
| "bar"
|
|
@@ -138,7 +146,7 @@ export function PanelConfigSidebar({
|
|
|
138
146
|
hasViewElementScope(selectedElement.id);
|
|
139
147
|
const scopeWarnings = useMemo(() => {
|
|
140
148
|
if (!selectedElement || viewElementScope === undefined) return [];
|
|
141
|
-
return collectElementScopeWarnings(selectedElement, viewElementScope);
|
|
149
|
+
return collectElementScopeWarnings(selectedElement, viewElementScope, t);
|
|
142
150
|
}, [selectedElement, viewElementScope]);
|
|
143
151
|
const effectiveSelectedElements = useMemo(() => {
|
|
144
152
|
if (selectedElements.length > 0) return selectedElements;
|
|
@@ -171,7 +179,8 @@ export function PanelConfigSidebar({
|
|
|
171
179
|
|
|
172
180
|
useEffect(() => {
|
|
173
181
|
if (!selectedElement || selectedElement.materialType !== "text") return;
|
|
174
|
-
const nextHtml =
|
|
182
|
+
const nextHtml =
|
|
183
|
+
selectedElement.textHtml ?? `<p>${t("panel.defaults.doubleClickTextHtml")}</p>`;
|
|
175
184
|
if (textEditorRef.current && textEditorRef.current.innerHTML !== nextHtml) {
|
|
176
185
|
textEditorRef.current.innerHTML = nextHtml;
|
|
177
186
|
}
|
|
@@ -256,13 +265,13 @@ export function PanelConfigSidebar({
|
|
|
256
265
|
const base64 = await new Promise<string>((resolve, reject) => {
|
|
257
266
|
const reader = new FileReader();
|
|
258
267
|
reader.onload = () => resolve(String(reader.result ?? ""));
|
|
259
|
-
reader.onerror = () => reject(new Error(
|
|
268
|
+
reader.onerror = () => reject(new Error(messages.readImageFailed));
|
|
260
269
|
reader.readAsDataURL(file);
|
|
261
270
|
});
|
|
262
271
|
updateSelectedStyle({
|
|
263
272
|
backgroundImage: `url("${base64}")`,
|
|
264
273
|
});
|
|
265
|
-
setUploadStatus("
|
|
274
|
+
setUploadStatus(t("panel.config.uploadWrittenBase64"));
|
|
266
275
|
try {
|
|
267
276
|
const form = new FormData();
|
|
268
277
|
form.append("file", file);
|
|
@@ -271,10 +280,10 @@ export function PanelConfigSidebar({
|
|
|
271
280
|
const data = (await resp.json()) as { url?: string };
|
|
272
281
|
if (data.url) {
|
|
273
282
|
updateSelectedStyle({ backgroundImageRemoteUrl: data.url });
|
|
274
|
-
setUploadStatus("
|
|
283
|
+
setUploadStatus(t("panel.config.uploadServerAndBase64"));
|
|
275
284
|
}
|
|
276
285
|
} catch {
|
|
277
|
-
setUploadStatus("
|
|
286
|
+
setUploadStatus(t("panel.config.uploadServerFailedKeepBase64"));
|
|
278
287
|
}
|
|
279
288
|
},
|
|
280
289
|
[selectedElement, updateSelectedStyle]
|
|
@@ -292,11 +301,11 @@ export function PanelConfigSidebar({
|
|
|
292
301
|
const base64 = await new Promise<string>((resolve, reject) => {
|
|
293
302
|
const reader = new FileReader();
|
|
294
303
|
reader.onload = () => resolve(String(reader.result ?? ""));
|
|
295
|
-
reader.onerror = () => reject(new Error(
|
|
304
|
+
reader.onerror = () => reject(new Error(messages.readAudioFailed));
|
|
296
305
|
reader.readAsDataURL(file);
|
|
297
306
|
});
|
|
298
307
|
updateSelectedAudio({ audioSrc: base64 });
|
|
299
|
-
setAudioStatus(
|
|
308
|
+
setAudioStatus(messages.audioLocalSaved);
|
|
300
309
|
try {
|
|
301
310
|
const form = new FormData();
|
|
302
311
|
form.append("file", file);
|
|
@@ -305,10 +314,10 @@ export function PanelConfigSidebar({
|
|
|
305
314
|
const data = (await resp.json()) as { url?: string };
|
|
306
315
|
if (data.url) {
|
|
307
316
|
updateSelectedAudio({ audioRemoteUrl: data.url });
|
|
308
|
-
setAudioStatus(
|
|
317
|
+
setAudioStatus(messages.audioRemoteUploaded);
|
|
309
318
|
}
|
|
310
319
|
} catch {
|
|
311
|
-
setAudioStatus(
|
|
320
|
+
setAudioStatus(messages.audioServerUploadFailed);
|
|
312
321
|
}
|
|
313
322
|
},
|
|
314
323
|
[selectedElement, updateSelectedAudio]
|
|
@@ -319,11 +328,11 @@ export function PanelConfigSidebar({
|
|
|
319
328
|
const base64 = await new Promise<string>((resolve, reject) => {
|
|
320
329
|
const reader = new FileReader();
|
|
321
330
|
reader.onload = () => resolve(String(reader.result ?? ""));
|
|
322
|
-
reader.onerror = () => reject(new Error(
|
|
331
|
+
reader.onerror = () => reject(new Error(messages.readImageFailed));
|
|
323
332
|
reader.readAsDataURL(file);
|
|
324
333
|
});
|
|
325
334
|
updateSelectedAudio({ audioPosterImage: base64 });
|
|
326
|
-
setAudioStatus(
|
|
335
|
+
setAudioStatus(messages.audioPosterSet);
|
|
327
336
|
},
|
|
328
337
|
[selectedElement, updateSelectedAudio]
|
|
329
338
|
);
|
|
@@ -333,7 +342,7 @@ export function PanelConfigSidebar({
|
|
|
333
342
|
const startRecordingAudio = useCallback(async () => {
|
|
334
343
|
if (!selectedElement || selectedElement.materialType !== "audio") return;
|
|
335
344
|
if (!navigator.mediaDevices?.getUserMedia) {
|
|
336
|
-
setAudioStatus(
|
|
345
|
+
setAudioStatus(messages.audioRecordUnsupported);
|
|
337
346
|
return;
|
|
338
347
|
}
|
|
339
348
|
try {
|
|
@@ -350,11 +359,11 @@ export function PanelConfigSidebar({
|
|
|
350
359
|
const dataUrl = await new Promise<string>((resolve, reject) => {
|
|
351
360
|
const reader = new FileReader();
|
|
352
361
|
reader.onload = () => resolve(String(reader.result ?? ""));
|
|
353
|
-
reader.onerror = () => reject(new Error(
|
|
362
|
+
reader.onerror = () => reject(new Error(messages.readRecordAudioFailed));
|
|
354
363
|
reader.readAsDataURL(blob);
|
|
355
364
|
});
|
|
356
365
|
updateSelectedAudio({ audioSrc: dataUrl });
|
|
357
|
-
setAudioStatus(
|
|
366
|
+
setAudioStatus(messages.audioRecordSaved);
|
|
358
367
|
recordStreamRef.current?.getTracks().forEach((track) => track.stop());
|
|
359
368
|
recordStreamRef.current = null;
|
|
360
369
|
recorderRef.current = null;
|
|
@@ -362,9 +371,9 @@ export function PanelConfigSidebar({
|
|
|
362
371
|
};
|
|
363
372
|
recorder.start();
|
|
364
373
|
setIsRecordingAudio(true);
|
|
365
|
-
setAudioStatus(
|
|
374
|
+
setAudioStatus(messages.audioRecording);
|
|
366
375
|
} catch {
|
|
367
|
-
setAudioStatus(
|
|
376
|
+
setAudioStatus(messages.audioRecordStartFailed);
|
|
368
377
|
setIsRecordingAudio(false);
|
|
369
378
|
}
|
|
370
379
|
}, [selectedElement, updateSelectedAudio]);
|
|
@@ -381,11 +390,11 @@ export function PanelConfigSidebar({
|
|
|
381
390
|
const base64 = await new Promise<string>((resolve, reject) => {
|
|
382
391
|
const reader = new FileReader();
|
|
383
392
|
reader.onload = () => resolve(String(reader.result ?? ""));
|
|
384
|
-
reader.onerror = () => reject(new Error(
|
|
393
|
+
reader.onerror = () => reject(new Error(messages.readVideoFailed));
|
|
385
394
|
reader.readAsDataURL(file);
|
|
386
395
|
});
|
|
387
396
|
updateSelectedVideo({ videoSrc: base64 });
|
|
388
|
-
setVideoStatus(
|
|
397
|
+
setVideoStatus(messages.videoLocalSaved);
|
|
389
398
|
try {
|
|
390
399
|
const form = new FormData();
|
|
391
400
|
form.append("file", file);
|
|
@@ -394,10 +403,10 @@ export function PanelConfigSidebar({
|
|
|
394
403
|
const data = (await resp.json()) as { url?: string };
|
|
395
404
|
if (data.url) {
|
|
396
405
|
updateSelectedVideo({ videoRemoteUrl: data.url });
|
|
397
|
-
setVideoStatus(
|
|
406
|
+
setVideoStatus(messages.videoRemoteUploaded);
|
|
398
407
|
}
|
|
399
408
|
} catch {
|
|
400
|
-
setVideoStatus(
|
|
409
|
+
setVideoStatus(messages.videoServerUploadFailed);
|
|
401
410
|
}
|
|
402
411
|
},
|
|
403
412
|
[selectedElement, updateSelectedVideo]
|
|
@@ -410,12 +419,25 @@ export function PanelConfigSidebar({
|
|
|
410
419
|
setExpandedSections((prev) => ({ ...prev, [key]: next }));
|
|
411
420
|
};
|
|
412
421
|
|
|
422
|
+
useEffect(() => {
|
|
423
|
+
return subscribeRevealPanelConfig((detail) => {
|
|
424
|
+
for (const section of detail.sections) {
|
|
425
|
+
setSectionExpanded(section, true);
|
|
426
|
+
}
|
|
427
|
+
window.requestAnimationFrame(() => {
|
|
428
|
+
const field = detail.fields[0];
|
|
429
|
+
if (field) highlightConfigField(field);
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
}, []);
|
|
433
|
+
|
|
413
434
|
const renderSection = (
|
|
414
435
|
key: string,
|
|
415
436
|
title: string,
|
|
416
437
|
children: React.ReactNode,
|
|
417
438
|
defaultOpen = true,
|
|
418
|
-
searchTerms: string[] = []
|
|
439
|
+
searchTerms: string[] = [],
|
|
440
|
+
hint?: React.ReactNode
|
|
419
441
|
) => {
|
|
420
442
|
const hit =
|
|
421
443
|
!hasSearch ||
|
|
@@ -427,6 +449,7 @@ export function PanelConfigSidebar({
|
|
|
427
449
|
open={hasSearch ? true : isSectionExpanded(key, defaultOpen)}
|
|
428
450
|
onOpenChange={(open) => setSectionExpanded(key, open)}
|
|
429
451
|
className="rounded-xl border border-border/70 bg-card/95 shadow-sm"
|
|
452
|
+
data-config-section={key}
|
|
430
453
|
>
|
|
431
454
|
<div className="flex items-center gap-1.5 px-3 py-2">
|
|
432
455
|
<CollapsibleTrigger asChild>
|
|
@@ -437,7 +460,10 @@ export function PanelConfigSidebar({
|
|
|
437
460
|
{isSectionExpanded(key, defaultOpen) ? "▾" : "▸"}
|
|
438
461
|
</button>
|
|
439
462
|
</CollapsibleTrigger>
|
|
440
|
-
<div className="
|
|
463
|
+
<div className="flex min-w-0 flex-1 items-center gap-1">
|
|
464
|
+
<div className="text-[11px] font-semibold tracking-wide text-muted-foreground">{title}</div>
|
|
465
|
+
{hint ? <ConfigHintIcon label={title}>{hint}</ConfigHintIcon> : null}
|
|
466
|
+
</div>
|
|
441
467
|
</div>
|
|
442
468
|
<CollapsibleContent className="space-y-3 border-t border-border/60 bg-muted/[0.1] px-3 pb-3 pt-2.5">
|
|
443
469
|
{children}
|
|
@@ -446,9 +472,16 @@ export function PanelConfigSidebar({
|
|
|
446
472
|
);
|
|
447
473
|
};
|
|
448
474
|
|
|
449
|
-
const renderFieldGroup = (
|
|
475
|
+
const renderFieldGroup = (
|
|
476
|
+
title: string,
|
|
477
|
+
children: React.ReactNode,
|
|
478
|
+
hint?: React.ReactNode
|
|
479
|
+
) => (
|
|
450
480
|
<div className="space-y-2.5 rounded-lg border border-border/55 bg-background/80 p-2.5">
|
|
451
|
-
<div className="
|
|
481
|
+
<div className="flex items-center gap-1">
|
|
482
|
+
<div className="text-[11px] font-semibold text-muted-foreground">{title}</div>
|
|
483
|
+
{hint ? <ConfigHintIcon label={title}>{hint}</ConfigHintIcon> : null}
|
|
484
|
+
</div>
|
|
452
485
|
{children}
|
|
453
486
|
</div>
|
|
454
487
|
);
|
|
@@ -479,7 +512,7 @@ export function PanelConfigSidebar({
|
|
|
479
512
|
value={/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(value || "") ? value : "#000000"}
|
|
480
513
|
onChange={(e) => onTextChange(e.target.value)}
|
|
481
514
|
className="h-7 w-10 cursor-pointer p-1"
|
|
482
|
-
aria-label={
|
|
515
|
+
aria-label={t("common.colorPickerAria", { label })}
|
|
483
516
|
/>
|
|
484
517
|
</div>
|
|
485
518
|
</label>
|
|
@@ -494,50 +527,24 @@ export function PanelConfigSidebar({
|
|
|
494
527
|
const renderOptionLabel = (label: string, keyPath: string, desc: string) => (
|
|
495
528
|
<div className="flex min-w-0 items-center gap-1">
|
|
496
529
|
<span className={optionLabelTextClass} title={`${label}(${keyPath})`}>{label}</span>
|
|
497
|
-
<
|
|
498
|
-
<
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
type="button"
|
|
502
|
-
className="inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-border text-[10px] text-muted-foreground"
|
|
503
|
-
aria-label={`${label}说明`}
|
|
504
|
-
>
|
|
505
|
-
?
|
|
506
|
-
</button>
|
|
507
|
-
</TooltipTrigger>
|
|
508
|
-
<TooltipContent className="max-w-[260px] text-[11px]">
|
|
509
|
-
<div>Key: {keyPath}</div>
|
|
510
|
-
<div>{desc}</div>
|
|
511
|
-
</TooltipContent>
|
|
512
|
-
</Tooltip>
|
|
513
|
-
</TooltipProvider>
|
|
530
|
+
<ConfigHintIcon label={label}>
|
|
531
|
+
<div>Key: {keyPath}</div>
|
|
532
|
+
<div>{desc}</div>
|
|
533
|
+
</ConfigHintIcon>
|
|
514
534
|
</div>
|
|
515
535
|
);
|
|
516
|
-
const renderFormatterLabel = (label = "
|
|
536
|
+
const renderFormatterLabel = (label = t("panel.config.tooltipFormatter")) => (
|
|
517
537
|
<div className="flex min-w-0 items-center gap-1">
|
|
518
538
|
<span className={optionLabelTextClass} title={label}>{label}</span>
|
|
519
|
-
<
|
|
520
|
-
<
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
</button>
|
|
529
|
-
</TooltipTrigger>
|
|
530
|
-
<TooltipContent className="max-w-[360px] text-[11px] leading-5">
|
|
531
|
-
<div className="font-medium">可用占位符</div>
|
|
532
|
-
<div>{"{a}=系列名, {b}=类目名, {c}=数值, {d}=百分比(饼图)"}</div>
|
|
533
|
-
<div className="mt-1 font-medium">常用模板 + 输出示例</div>
|
|
534
|
-
<div>{"1) {b}: {c} -> 周一: 120"}</div>
|
|
535
|
-
<div>{"2) {a}<br/>{b}: {c} -> 销量<br/>周一: 120"}</div>
|
|
536
|
-
<div>{"3) {b}: {c} ({d}%) -> 访问来源: 335 (42%)"}</div>
|
|
537
|
-
<div>{"4) ¥{c} / {b} -> ¥120 / 周一"}</div>
|
|
538
|
-
</TooltipContent>
|
|
539
|
-
</Tooltip>
|
|
540
|
-
</TooltipProvider>
|
|
539
|
+
<ConfigHintIcon label="Tooltip Formatter" contentClassName="max-w-[360px]">
|
|
540
|
+
<div className="font-medium">{t("panel.config.formatterPlaceholdersTitle")}</div>
|
|
541
|
+
<div>{t("panel.config.formatterPlaceholders")}</div>
|
|
542
|
+
<div className="mt-1 font-medium">{t("panel.config.formatterExamplesTitle")}</div>
|
|
543
|
+
<div>{t("panel.config.formatterExample1")}</div>
|
|
544
|
+
<div>{t("panel.config.formatterExample2")}</div>
|
|
545
|
+
<div>{t("panel.config.formatterExample3")}</div>
|
|
546
|
+
<div>{t("panel.config.formatterExample4")}</div>
|
|
547
|
+
</ConfigHintIcon>
|
|
541
548
|
</div>
|
|
542
549
|
);
|
|
543
550
|
const mergeOptionPatch = useCallback(
|
|
@@ -593,16 +600,17 @@ export function PanelConfigSidebar({
|
|
|
593
600
|
return (
|
|
594
601
|
<ScopeConfigProvider
|
|
595
602
|
scope={showScopePanel ? viewElementScope : undefined}
|
|
603
|
+
element={selectedElement}
|
|
596
604
|
warnings={scopeWarnings}
|
|
597
605
|
scrollContainerRef={sidebarScrollRef}
|
|
598
606
|
>
|
|
599
607
|
<aside
|
|
600
608
|
ref={sidebarScrollRef}
|
|
601
|
-
className={`scope-config-sidebar h-full overflow-auto border-l border-border bg-muted/[0.14] px-3 py-3 text-foreground [&_.scope-field--highlight]:rounded-md [&_.scope-field--highlight]:ring-2 [&_.scope-field--highlight]:ring-amber-400/80 [&_button[role=checkbox]]:border-2 [&_button[role=checkbox]]:border-foreground/80 [&_button[role=checkbox]]:bg-background [&_button[role=checkbox]]:ring-1 [&_button[role=checkbox]]:ring-foreground/40 [&_button[role=checkbox][data-state=checked]]:border-primary [&_button[role=checkbox][data-state=checked]]:ring-primary/40 ${themedScrollbarClass}`}
|
|
609
|
+
className={`scope-config-sidebar h-full overflow-auto border-l border-border bg-muted/[0.14] px-3 py-3 text-foreground [&_.config-field--highlight]:rounded-md [&_.config-field--highlight]:ring-2 [&_.config-field--highlight]:ring-sky-400/80 [&_.scope-field--highlight]:rounded-md [&_.scope-field--highlight]:ring-2 [&_.scope-field--highlight]:ring-amber-400/80 [&_button[role=checkbox]]:border-2 [&_button[role=checkbox]]:border-foreground/80 [&_button[role=checkbox]]:bg-background [&_button[role=checkbox]]:ring-1 [&_button[role=checkbox]]:ring-foreground/40 [&_button[role=checkbox][data-state=checked]]:border-primary [&_button[role=checkbox][data-state=checked]]:ring-primary/40 ${themedScrollbarClass}`}
|
|
602
610
|
>
|
|
603
611
|
<div className="sticky top-0 z-20 mb-3 rounded-lg border border-border/70 bg-card/95 px-2.5 py-2 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-card/80">
|
|
604
612
|
<div className="flex items-center justify-between gap-2">
|
|
605
|
-
<div className="text-xs font-semibold tracking-wide"
|
|
613
|
+
<div className="text-xs font-semibold tracking-wide">{t("panel.config.panelTitle")}</div>
|
|
606
614
|
</div>
|
|
607
615
|
{showScopePanel ? (
|
|
608
616
|
<ViewElementScopePanel scope={viewElementScope} />
|
|
@@ -621,7 +629,7 @@ export function PanelConfigSidebar({
|
|
|
621
629
|
className="rounded border border-border px-1.5 py-0.5 text-[11px] text-muted-foreground hover:bg-accent"
|
|
622
630
|
onClick={() => setIsSearchCollapsed((prev) => !prev)}
|
|
623
631
|
>
|
|
624
|
-
{isSearchCollapsed ? "
|
|
632
|
+
{isSearchCollapsed ? t("panel.config.expandSearch") : t("panel.config.collapseSearch")}
|
|
625
633
|
</button>
|
|
626
634
|
</div>
|
|
627
635
|
{!isSearchCollapsed ? (
|
|
@@ -629,13 +637,13 @@ export function PanelConfigSidebar({
|
|
|
629
637
|
<Input
|
|
630
638
|
value={configSearch}
|
|
631
639
|
onChange={(e) => setConfigSearch(e.target.value)}
|
|
632
|
-
placeholder="
|
|
640
|
+
placeholder={t("panel.config.searchPlaceholder")}
|
|
633
641
|
className="h-7"
|
|
634
642
|
data-scope-autocomplete="off"
|
|
635
643
|
/>
|
|
636
644
|
{hasSearch ? (
|
|
637
645
|
<div className="mt-1 text-[11px] text-muted-foreground">
|
|
638
|
-
|
|
646
|
+
{t("panel.config.searching", { query: configSearch })}
|
|
639
647
|
</div>
|
|
640
648
|
) : null}
|
|
641
649
|
</div>
|
|
@@ -646,7 +654,7 @@ export function PanelConfigSidebar({
|
|
|
646
654
|
<div className="space-y-3">
|
|
647
655
|
<Card>
|
|
648
656
|
<CardHeader className="pb-2">
|
|
649
|
-
<CardTitle className="text-xs"
|
|
657
|
+
<CardTitle className="text-xs">{t("panel.config.batchTitleWithCount", { count: effectiveSelectedElements.length })}</CardTitle>
|
|
650
658
|
</CardHeader>
|
|
651
659
|
<CardContent className="space-y-2 text-xs">
|
|
652
660
|
<div className="grid grid-cols-2 gap-2">
|
|
@@ -655,14 +663,14 @@ export function PanelConfigSidebar({
|
|
|
655
663
|
className="rounded border border-border bg-background px-2 py-1 hover:bg-accent"
|
|
656
664
|
onClick={() => effectiveSelectedElements.forEach((el) => updateElement(el.id, { locked: true }))}
|
|
657
665
|
>
|
|
658
|
-
|
|
666
|
+
{t("panel.config.lockAll")}
|
|
659
667
|
</button>
|
|
660
668
|
<button
|
|
661
669
|
type="button"
|
|
662
670
|
className="rounded border border-border bg-background px-2 py-1 hover:bg-accent"
|
|
663
671
|
onClick={() => effectiveSelectedElements.forEach((el) => updateElement(el.id, { locked: false }))}
|
|
664
672
|
>
|
|
665
|
-
|
|
673
|
+
{t("panel.config.unlockAll")}
|
|
666
674
|
</button>
|
|
667
675
|
<button
|
|
668
676
|
type="button"
|
|
@@ -673,7 +681,7 @@ export function PanelConfigSidebar({
|
|
|
673
681
|
)
|
|
674
682
|
}
|
|
675
683
|
>
|
|
676
|
-
|
|
684
|
+
{t("panel.config.bringAllForward")}
|
|
677
685
|
</button>
|
|
678
686
|
<button
|
|
679
687
|
type="button"
|
|
@@ -684,7 +692,7 @@ export function PanelConfigSidebar({
|
|
|
684
692
|
)
|
|
685
693
|
}
|
|
686
694
|
>
|
|
687
|
-
|
|
695
|
+
{t("panel.config.sendAllBackward")}
|
|
688
696
|
</button>
|
|
689
697
|
<button
|
|
690
698
|
type="button"
|
|
@@ -695,7 +703,7 @@ export function PanelConfigSidebar({
|
|
|
695
703
|
)
|
|
696
704
|
}
|
|
697
705
|
>
|
|
698
|
-
|
|
706
|
+
{t("panel.config.setAllZIndex1")}
|
|
699
707
|
</button>
|
|
700
708
|
<button
|
|
701
709
|
type="button"
|
|
@@ -711,7 +719,7 @@ export function PanelConfigSidebar({
|
|
|
711
719
|
)
|
|
712
720
|
}
|
|
713
721
|
>
|
|
714
|
-
|
|
722
|
+
{t("panel.config.setAllBgBlue")}
|
|
715
723
|
</button>
|
|
716
724
|
</div>
|
|
717
725
|
</CardContent>
|
|
@@ -734,20 +742,20 @@ export function PanelConfigSidebar({
|
|
|
734
742
|
type="button"
|
|
735
743
|
className="inline-flex h-6 w-6 items-center justify-center rounded border border-border text-[11px] hover:bg-accent"
|
|
736
744
|
onClick={() => setNodeCardExpanded(el.id, !isNodeCardExpanded(el.id))}
|
|
737
|
-
aria-label={isNodeCardExpanded(el.id) ? "
|
|
745
|
+
aria-label={isNodeCardExpanded(el.id) ? t("panel.config.collapseNodeConfig") : t("panel.config.expandNodeConfig")}
|
|
738
746
|
>
|
|
739
747
|
{isNodeCardExpanded(el.id) ? "▾" : "▸"}
|
|
740
748
|
</button>
|
|
741
749
|
<CardTitle className="min-w-0 flex-1 text-xs truncate">
|
|
742
|
-
{el.name?.trim() || el.materialType || "
|
|
750
|
+
{el.name?.trim() || el.materialType || t("common.node")} · {el.id}
|
|
743
751
|
</CardTitle>
|
|
744
752
|
<button
|
|
745
753
|
type="button"
|
|
746
754
|
className="inline-flex h-6 items-center justify-center rounded border border-border px-2 text-[11px] text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
747
755
|
onClick={() => onExcludeSelectedNode?.(el.id)}
|
|
748
|
-
title="
|
|
756
|
+
title={t("panel.config.removeFromSelectionTitle")}
|
|
749
757
|
>
|
|
750
|
-
|
|
758
|
+
{t("panel.config.removeFromSelection")}
|
|
751
759
|
</button>
|
|
752
760
|
</div>
|
|
753
761
|
</CardHeader>
|
|
@@ -758,17 +766,17 @@ export function PanelConfigSidebar({
|
|
|
758
766
|
checked={el.locked === true}
|
|
759
767
|
onCheckedChange={(checked) => updateElement(el.id, { locked: checked === true })}
|
|
760
768
|
/>
|
|
761
|
-
<span
|
|
769
|
+
<span>{t("panel.config.lockedNode")}</span>
|
|
762
770
|
</label>
|
|
763
771
|
{el.locked ? (
|
|
764
772
|
<div className="rounded border border-amber-500/40 bg-amber-500/10 px-2 py-1.5 text-[11px] text-amber-700 dark:text-amber-300">
|
|
765
|
-
|
|
773
|
+
{t("panel.config.lockedNodeHint")}
|
|
766
774
|
</div>
|
|
767
775
|
) : null}
|
|
768
776
|
<fieldset disabled={el.locked} className={el.locked ? "opacity-60" : ""}>
|
|
769
777
|
<div className="space-y-2">
|
|
770
778
|
<label className="block space-y-1">
|
|
771
|
-
<div
|
|
779
|
+
<div>{t("panel.config.name")}</div>
|
|
772
780
|
<Input
|
|
773
781
|
className="h-7"
|
|
774
782
|
value={el.name ?? ""}
|
|
@@ -788,13 +796,13 @@ export function PanelConfigSidebar({
|
|
|
788
796
|
/>
|
|
789
797
|
</label>
|
|
790
798
|
<label className="block space-y-1">
|
|
791
|
-
<div
|
|
799
|
+
<div>{t("panel.config.layer")}</div>
|
|
792
800
|
<Select
|
|
793
801
|
value={el.layerId}
|
|
794
802
|
onValueChange={(value) => updateElement(el.id, { layerId: value })}
|
|
795
803
|
>
|
|
796
804
|
<SelectTrigger className="h-7">
|
|
797
|
-
<SelectValue placeholder="
|
|
805
|
+
<SelectValue placeholder={t("panel.config.selectLayer")} />
|
|
798
806
|
</SelectTrigger>
|
|
799
807
|
<SelectContent>
|
|
800
808
|
{layers.map((layer) => (
|
|
@@ -826,7 +834,7 @@ export function PanelConfigSidebar({
|
|
|
826
834
|
/>
|
|
827
835
|
</label>
|
|
828
836
|
<label className="block space-y-1">
|
|
829
|
-
<div
|
|
837
|
+
<div>{t("panel.config.rotate")}</div>
|
|
830
838
|
<Input
|
|
831
839
|
className="h-7"
|
|
832
840
|
type="number"
|
|
@@ -837,7 +845,7 @@ export function PanelConfigSidebar({
|
|
|
837
845
|
/>
|
|
838
846
|
</label>
|
|
839
847
|
<label className="block space-y-1">
|
|
840
|
-
<div
|
|
848
|
+
<div>{t("panel.config.width")}</div>
|
|
841
849
|
<Input
|
|
842
850
|
className="h-7"
|
|
843
851
|
type="number"
|
|
@@ -849,7 +857,7 @@ export function PanelConfigSidebar({
|
|
|
849
857
|
/>
|
|
850
858
|
</label>
|
|
851
859
|
<label className="block space-y-1">
|
|
852
|
-
<div
|
|
860
|
+
<div>{t("panel.config.height")}</div>
|
|
853
861
|
<Input
|
|
854
862
|
className="h-7"
|
|
855
863
|
type="number"
|
|
@@ -863,7 +871,7 @@ export function PanelConfigSidebar({
|
|
|
863
871
|
</div>
|
|
864
872
|
<div className="grid grid-cols-2 gap-2">
|
|
865
873
|
<label className="block space-y-1">
|
|
866
|
-
<div
|
|
874
|
+
<div>{t("panel.config.backgroundColor")}</div>
|
|
867
875
|
<Input
|
|
868
876
|
className="h-7"
|
|
869
877
|
value={el.style?.backgroundColor ?? ""}
|
|
@@ -879,7 +887,7 @@ export function PanelConfigSidebar({
|
|
|
879
887
|
/>
|
|
880
888
|
</label>
|
|
881
889
|
<label className="block space-y-1">
|
|
882
|
-
<div
|
|
890
|
+
<div>{t("panel.config.borderColorShort")}</div>
|
|
883
891
|
<Input
|
|
884
892
|
className="h-7"
|
|
885
893
|
value={el.style?.borderColor ?? ""}
|
|
@@ -898,7 +906,7 @@ export function PanelConfigSidebar({
|
|
|
898
906
|
{CHART_TYPES.has(el.materialType ?? "") ? (
|
|
899
907
|
<div className="grid grid-cols-2 gap-2">
|
|
900
908
|
<label className="block space-y-1 col-span-2">
|
|
901
|
-
<div
|
|
909
|
+
<div>{t("panel.config.chartTitle")}</div>
|
|
902
910
|
<Input
|
|
903
911
|
className="h-7"
|
|
904
912
|
value={el.chart?.title ?? ""}
|
|
@@ -910,7 +918,7 @@ export function PanelConfigSidebar({
|
|
|
910
918
|
/>
|
|
911
919
|
</label>
|
|
912
920
|
<label className="block space-y-1">
|
|
913
|
-
<div
|
|
921
|
+
<div>{t("panel.config.primaryColor")}</div>
|
|
914
922
|
<Input
|
|
915
923
|
className="h-7"
|
|
916
924
|
value={el.chart?.color ?? ""}
|
|
@@ -930,12 +938,12 @@ export function PanelConfigSidebar({
|
|
|
930
938
|
})
|
|
931
939
|
}
|
|
932
940
|
/>
|
|
933
|
-
<span
|
|
941
|
+
<span>{t("panel.config.primaryGradient")}</span>
|
|
934
942
|
</label>
|
|
935
943
|
{el.chart?.colorMode === "gradient" ? (
|
|
936
944
|
<>
|
|
937
945
|
<label className="block space-y-1">
|
|
938
|
-
<div
|
|
946
|
+
<div>{t("panel.config.gradientFrom")}</div>
|
|
939
947
|
<Input
|
|
940
948
|
className="h-7"
|
|
941
949
|
value={el.chart?.gradientFrom ?? el.chart?.color ?? "#3b82f6"}
|
|
@@ -947,7 +955,7 @@ export function PanelConfigSidebar({
|
|
|
947
955
|
/>
|
|
948
956
|
</label>
|
|
949
957
|
<label className="block space-y-1">
|
|
950
|
-
<div
|
|
958
|
+
<div>{t("panel.config.gradientTo")}</div>
|
|
951
959
|
<Input
|
|
952
960
|
className="h-7"
|
|
953
961
|
value={el.chart?.gradientTo ?? "#22d3ee"}
|
|
@@ -959,7 +967,7 @@ export function PanelConfigSidebar({
|
|
|
959
967
|
/>
|
|
960
968
|
</label>
|
|
961
969
|
<label className="block space-y-1 col-span-2">
|
|
962
|
-
<div
|
|
970
|
+
<div>{t("panel.config.gradientDirection")}</div>
|
|
963
971
|
<Select
|
|
964
972
|
value={el.chart?.gradientDirection ?? "to-right"}
|
|
965
973
|
onValueChange={(value) =>
|
|
@@ -977,15 +985,15 @@ export function PanelConfigSidebar({
|
|
|
977
985
|
>
|
|
978
986
|
<SelectTrigger className="h-7"><SelectValue /></SelectTrigger>
|
|
979
987
|
<SelectContent>
|
|
980
|
-
<SelectItem value="to-right"
|
|
981
|
-
<SelectItem value="to-bottom"
|
|
982
|
-
<SelectItem value="to-bottom-right"
|
|
983
|
-
<SelectItem value="to-top-right"
|
|
988
|
+
<SelectItem value="to-right">{t("panel.config.dirToRight")}</SelectItem>
|
|
989
|
+
<SelectItem value="to-bottom">{t("panel.config.dirToBottom")}</SelectItem>
|
|
990
|
+
<SelectItem value="to-bottom-right">{t("panel.config.dirToBottomRight")}</SelectItem>
|
|
991
|
+
<SelectItem value="to-top-right">{t("panel.config.dirToTopRight")}</SelectItem>
|
|
984
992
|
</SelectContent>
|
|
985
993
|
</Select>
|
|
986
994
|
</label>
|
|
987
995
|
<div className="col-span-2 space-y-1">
|
|
988
|
-
<div className="text-[11px] text-muted-foreground"
|
|
996
|
+
<div className="text-[11px] text-muted-foreground">{t("panel.config.gradientPreview")}</div>
|
|
989
997
|
<div
|
|
990
998
|
className="h-6 rounded border border-border/60"
|
|
991
999
|
style={{
|
|
@@ -1004,7 +1012,7 @@ export function PanelConfigSidebar({
|
|
|
1004
1012
|
</>
|
|
1005
1013
|
) : null}
|
|
1006
1014
|
<label className="block space-y-1">
|
|
1007
|
-
<div
|
|
1015
|
+
<div>{t("panel.config.render")}</div>
|
|
1008
1016
|
<Select
|
|
1009
1017
|
value={el.chart?.renderMode ?? "canvas"}
|
|
1010
1018
|
onValueChange={(value) =>
|
|
@@ -1023,7 +1031,7 @@ export function PanelConfigSidebar({
|
|
|
1023
1031
|
</Select>
|
|
1024
1032
|
</label>
|
|
1025
1033
|
<label className="block space-y-1">
|
|
1026
|
-
<div>
|
|
1034
|
+
<div>{t("panel.config.tooltipBg")}</div>
|
|
1027
1035
|
<Input
|
|
1028
1036
|
className="h-7"
|
|
1029
1037
|
value={el.chart?.tooltipBackgroundColor ?? ""}
|
|
@@ -1047,10 +1055,10 @@ export function PanelConfigSidebar({
|
|
|
1047
1055
|
})
|
|
1048
1056
|
}
|
|
1049
1057
|
/>
|
|
1050
|
-
<span
|
|
1058
|
+
<span>{t("panel.config.showTooltip")}</span>
|
|
1051
1059
|
</label>
|
|
1052
1060
|
<label className="block space-y-1">
|
|
1053
|
-
<div>
|
|
1061
|
+
<div>{t("panel.config.tooltipTrigger")}</div>
|
|
1054
1062
|
<Select
|
|
1055
1063
|
value={el.chart?.tooltipTrigger ?? "axis"}
|
|
1056
1064
|
onValueChange={(value) =>
|
|
@@ -1067,7 +1075,7 @@ export function PanelConfigSidebar({
|
|
|
1067
1075
|
</Select>
|
|
1068
1076
|
</label>
|
|
1069
1077
|
<label className="block space-y-1">
|
|
1070
|
-
<div>
|
|
1078
|
+
<div>{t("panel.config.tooltipTextColor")}</div>
|
|
1071
1079
|
<Input
|
|
1072
1080
|
className="h-7"
|
|
1073
1081
|
value={el.chart?.tooltipTextColor ?? ""}
|
|
@@ -1099,25 +1107,22 @@ export function PanelConfigSidebar({
|
|
|
1099
1107
|
/>
|
|
1100
1108
|
</label>
|
|
1101
1109
|
<label className="block space-y-1 col-span-2">
|
|
1102
|
-
<div
|
|
1110
|
+
<div>{t("panel.config.labelsCsv")}</div>
|
|
1103
1111
|
<Input
|
|
1104
1112
|
className="h-7"
|
|
1105
|
-
value={(el.chart
|
|
1113
|
+
value={getChartLabelsDisplayText(el.chart)}
|
|
1106
1114
|
onChange={(e) =>
|
|
1107
1115
|
updateElement(el.id, {
|
|
1108
1116
|
chart: {
|
|
1109
1117
|
...(el.chart ?? {}),
|
|
1110
|
-
|
|
1111
|
-
.split(",")
|
|
1112
|
-
.map((s) => s.trim())
|
|
1113
|
-
.filter(Boolean),
|
|
1118
|
+
labelsText: e.target.value,
|
|
1114
1119
|
},
|
|
1115
1120
|
})
|
|
1116
1121
|
}
|
|
1117
1122
|
/>
|
|
1118
1123
|
</label>
|
|
1119
1124
|
<label className="block space-y-1 col-span-2">
|
|
1120
|
-
<div
|
|
1125
|
+
<div>{t("panel.config.valuesCsv")}</div>
|
|
1121
1126
|
<Input
|
|
1122
1127
|
className="h-7"
|
|
1123
1128
|
value={getChartValuesDisplayText(el.chart)}
|
|
@@ -1134,7 +1139,7 @@ export function PanelConfigSidebar({
|
|
|
1134
1139
|
{["bar", "line", "area", "scatter"].includes(el.materialType ?? "") ? (
|
|
1135
1140
|
<>
|
|
1136
1141
|
<label className="block space-y-1">
|
|
1137
|
-
<div>
|
|
1142
|
+
<div>{t("panel.config.xAxisName")}</div>
|
|
1138
1143
|
<Input
|
|
1139
1144
|
className="h-7"
|
|
1140
1145
|
value={el.chart?.xAxisName ?? ""}
|
|
@@ -1146,7 +1151,7 @@ export function PanelConfigSidebar({
|
|
|
1146
1151
|
/>
|
|
1147
1152
|
</label>
|
|
1148
1153
|
<label className="block space-y-1">
|
|
1149
|
-
<div>
|
|
1154
|
+
<div>{t("panel.config.yAxisName")}</div>
|
|
1150
1155
|
<Input
|
|
1151
1156
|
className="h-7"
|
|
1152
1157
|
value={el.chart?.yAxisName ?? ""}
|
|
@@ -1158,7 +1163,7 @@ export function PanelConfigSidebar({
|
|
|
1158
1163
|
/>
|
|
1159
1164
|
</label>
|
|
1160
1165
|
<label className="block space-y-1">
|
|
1161
|
-
<div>
|
|
1166
|
+
<div>{t("panel.config.xAxisLabelColor")}</div>
|
|
1162
1167
|
<Input
|
|
1163
1168
|
className="h-7"
|
|
1164
1169
|
value={el.chart?.xAxisLabelColor ?? ""}
|
|
@@ -1171,7 +1176,7 @@ export function PanelConfigSidebar({
|
|
|
1171
1176
|
/>
|
|
1172
1177
|
</label>
|
|
1173
1178
|
<label className="block space-y-1">
|
|
1174
|
-
<div>
|
|
1179
|
+
<div>{t("panel.config.yAxisLabelColor")}</div>
|
|
1175
1180
|
<Input
|
|
1176
1181
|
className="h-7"
|
|
1177
1182
|
value={el.chart?.yAxisLabelColor ?? ""}
|
|
@@ -1184,7 +1189,7 @@ export function PanelConfigSidebar({
|
|
|
1184
1189
|
/>
|
|
1185
1190
|
</label>
|
|
1186
1191
|
<label className="block space-y-1">
|
|
1187
|
-
<div>
|
|
1192
|
+
<div>{t("panel.config.xAxisLabelFontSize")}</div>
|
|
1188
1193
|
<Input
|
|
1189
1194
|
className="h-7"
|
|
1190
1195
|
type="number"
|
|
@@ -1202,7 +1207,7 @@ export function PanelConfigSidebar({
|
|
|
1202
1207
|
/>
|
|
1203
1208
|
</label>
|
|
1204
1209
|
<label className="block space-y-1">
|
|
1205
|
-
<div>
|
|
1210
|
+
<div>{t("panel.config.yAxisLabelFontSize")}</div>
|
|
1206
1211
|
<Input
|
|
1207
1212
|
className="h-7"
|
|
1208
1213
|
type="number"
|
|
@@ -1228,7 +1233,7 @@ export function PanelConfigSidebar({
|
|
|
1228
1233
|
})
|
|
1229
1234
|
}
|
|
1230
1235
|
/>
|
|
1231
|
-
<span>
|
|
1236
|
+
<span>{t("panel.config.xAxisLabelAutoEllipsis")}</span>
|
|
1232
1237
|
</label>
|
|
1233
1238
|
<label className="flex items-center gap-2">
|
|
1234
1239
|
<Checkbox
|
|
@@ -1239,7 +1244,7 @@ export function PanelConfigSidebar({
|
|
|
1239
1244
|
})
|
|
1240
1245
|
}
|
|
1241
1246
|
/>
|
|
1242
|
-
<span>
|
|
1247
|
+
<span>{t("panel.config.yAxisLabelAutoEllipsis")}</span>
|
|
1243
1248
|
</label>
|
|
1244
1249
|
<label className="flex items-center gap-2">
|
|
1245
1250
|
<Checkbox
|
|
@@ -1250,7 +1255,7 @@ export function PanelConfigSidebar({
|
|
|
1250
1255
|
})
|
|
1251
1256
|
}
|
|
1252
1257
|
/>
|
|
1253
|
-
<span>
|
|
1258
|
+
<span>{t("panel.config.xAxisTick")}</span>
|
|
1254
1259
|
</label>
|
|
1255
1260
|
<label className="flex items-center gap-2">
|
|
1256
1261
|
<Checkbox
|
|
@@ -1261,10 +1266,10 @@ export function PanelConfigSidebar({
|
|
|
1261
1266
|
})
|
|
1262
1267
|
}
|
|
1263
1268
|
/>
|
|
1264
|
-
<span>
|
|
1269
|
+
<span>{t("panel.config.yAxisTick")}</span>
|
|
1265
1270
|
</label>
|
|
1266
1271
|
<label className="block space-y-1">
|
|
1267
|
-
<div>
|
|
1272
|
+
<div>{t("panel.config.xAxisTickColor")}</div>
|
|
1268
1273
|
<Input
|
|
1269
1274
|
className="h-7"
|
|
1270
1275
|
value={el.chart?.xAxisTickColor ?? ""}
|
|
@@ -1277,7 +1282,7 @@ export function PanelConfigSidebar({
|
|
|
1277
1282
|
/>
|
|
1278
1283
|
</label>
|
|
1279
1284
|
<label className="block space-y-1">
|
|
1280
|
-
<div>
|
|
1285
|
+
<div>{t("panel.config.yAxisTickColor")}</div>
|
|
1281
1286
|
<Input
|
|
1282
1287
|
className="h-7"
|
|
1283
1288
|
value={el.chart?.yAxisTickColor ?? ""}
|
|
@@ -1298,7 +1303,7 @@ export function PanelConfigSidebar({
|
|
|
1298
1303
|
})
|
|
1299
1304
|
}
|
|
1300
1305
|
/>
|
|
1301
|
-
<span>
|
|
1306
|
+
<span>{t("panel.config.xAxisSplitLine")}</span>
|
|
1302
1307
|
</label>
|
|
1303
1308
|
<label className="flex items-center gap-2">
|
|
1304
1309
|
<Checkbox
|
|
@@ -1309,10 +1314,10 @@ export function PanelConfigSidebar({
|
|
|
1309
1314
|
})
|
|
1310
1315
|
}
|
|
1311
1316
|
/>
|
|
1312
|
-
<span>
|
|
1317
|
+
<span>{t("panel.config.yAxisSplitLine")}</span>
|
|
1313
1318
|
</label>
|
|
1314
1319
|
<label className="block space-y-1">
|
|
1315
|
-
<div>
|
|
1320
|
+
<div>{t("panel.config.xAxisSplitLineColor")}</div>
|
|
1316
1321
|
<Input
|
|
1317
1322
|
className="h-7"
|
|
1318
1323
|
value={el.chart?.xAxisSplitLineColor ?? ""}
|
|
@@ -1325,7 +1330,7 @@ export function PanelConfigSidebar({
|
|
|
1325
1330
|
/>
|
|
1326
1331
|
</label>
|
|
1327
1332
|
<label className="block space-y-1">
|
|
1328
|
-
<div>
|
|
1333
|
+
<div>{t("panel.config.yAxisSplitLineColor")}</div>
|
|
1329
1334
|
<Input
|
|
1330
1335
|
className="h-7"
|
|
1331
1336
|
value={el.chart?.yAxisSplitLineColor ?? ""}
|
|
@@ -1341,7 +1346,7 @@ export function PanelConfigSidebar({
|
|
|
1341
1346
|
) : null}
|
|
1342
1347
|
{el.materialType === "gauge" ? (
|
|
1343
1348
|
<label className="block space-y-1">
|
|
1344
|
-
<div
|
|
1349
|
+
<div>{t("panel.config.gaugeValue")}</div>
|
|
1345
1350
|
<Input
|
|
1346
1351
|
className="h-7"
|
|
1347
1352
|
type="number"
|
|
@@ -1359,7 +1364,7 @@ export function PanelConfigSidebar({
|
|
|
1359
1364
|
) : null}
|
|
1360
1365
|
{el.materialType === "bar" ? (
|
|
1361
1366
|
<label className="block space-y-1">
|
|
1362
|
-
<div
|
|
1367
|
+
<div>{t("panel.config.barWidth")}</div>
|
|
1363
1368
|
<Input
|
|
1364
1369
|
className="h-7"
|
|
1365
1370
|
type="number"
|
|
@@ -1386,13 +1391,13 @@ export function PanelConfigSidebar({
|
|
|
1386
1391
|
})
|
|
1387
1392
|
}
|
|
1388
1393
|
/>
|
|
1389
|
-
<span
|
|
1394
|
+
<span>{t("panel.config.smooth")}</span>
|
|
1390
1395
|
</label>
|
|
1391
1396
|
) : null}
|
|
1392
1397
|
{el.materialType === "pie" ? (
|
|
1393
1398
|
<>
|
|
1394
1399
|
<label className="block space-y-1">
|
|
1395
|
-
<div
|
|
1400
|
+
<div>{t("panel.config.pieInnerRadius")}</div>
|
|
1396
1401
|
<Input
|
|
1397
1402
|
className="h-7"
|
|
1398
1403
|
type="number"
|
|
@@ -1410,7 +1415,7 @@ export function PanelConfigSidebar({
|
|
|
1410
1415
|
/>
|
|
1411
1416
|
</label>
|
|
1412
1417
|
<label className="block space-y-1">
|
|
1413
|
-
<div
|
|
1418
|
+
<div>{t("panel.config.pieOuterRadius")}</div>
|
|
1414
1419
|
<Input
|
|
1415
1420
|
className="h-7"
|
|
1416
1421
|
type="number"
|
|
@@ -1430,7 +1435,7 @@ export function PanelConfigSidebar({
|
|
|
1430
1435
|
</>
|
|
1431
1436
|
) : null}
|
|
1432
1437
|
<label className="block space-y-1">
|
|
1433
|
-
{renderOptionLabel("
|
|
1438
|
+
{renderOptionLabel(t("panel.config.gridLeft"), "grid.left", t("panel.config.gridLeftHint"))}
|
|
1434
1439
|
<Input
|
|
1435
1440
|
className="h-7"
|
|
1436
1441
|
type="number"
|
|
@@ -1448,7 +1453,7 @@ export function PanelConfigSidebar({
|
|
|
1448
1453
|
/>
|
|
1449
1454
|
</label>
|
|
1450
1455
|
<label className="block space-y-1">
|
|
1451
|
-
{renderOptionLabel("
|
|
1456
|
+
{renderOptionLabel(t("panel.config.gridRight"), "grid.right", t("panel.config.gridRightHint"))}
|
|
1452
1457
|
<Input
|
|
1453
1458
|
className="h-7"
|
|
1454
1459
|
type="number"
|
|
@@ -1466,7 +1471,7 @@ export function PanelConfigSidebar({
|
|
|
1466
1471
|
/>
|
|
1467
1472
|
</label>
|
|
1468
1473
|
<label className="block space-y-1">
|
|
1469
|
-
{renderOptionLabel("
|
|
1474
|
+
{renderOptionLabel(t("panel.config.gridTop"), "grid.top", t("panel.config.gridTopHint"))}
|
|
1470
1475
|
<Input
|
|
1471
1476
|
className="h-7"
|
|
1472
1477
|
type="number"
|
|
@@ -1484,7 +1489,7 @@ export function PanelConfigSidebar({
|
|
|
1484
1489
|
/>
|
|
1485
1490
|
</label>
|
|
1486
1491
|
<label className="block space-y-1">
|
|
1487
|
-
{renderOptionLabel("
|
|
1492
|
+
{renderOptionLabel(t("panel.config.gridBottom"), "grid.bottom", t("panel.config.gridBottomHint"))}
|
|
1488
1493
|
<Input
|
|
1489
1494
|
className="h-7"
|
|
1490
1495
|
type="number"
|
|
@@ -1502,7 +1507,7 @@ export function PanelConfigSidebar({
|
|
|
1502
1507
|
/>
|
|
1503
1508
|
</label>
|
|
1504
1509
|
<label className="block space-y-1">
|
|
1505
|
-
{renderOptionLabel("
|
|
1510
|
+
{renderOptionLabel(t("panel.config.legendPosition"), "legend.top", t("panel.config.legendPositionHint"))}
|
|
1506
1511
|
<Select
|
|
1507
1512
|
value={String((el.chart?.option as any)?.legend?.top ?? "top")}
|
|
1508
1513
|
onValueChange={(value) =>
|
|
@@ -1526,7 +1531,7 @@ export function PanelConfigSidebar({
|
|
|
1526
1531
|
</Select>
|
|
1527
1532
|
</label>
|
|
1528
1533
|
<label className="block space-y-1">
|
|
1529
|
-
{renderOptionLabel("
|
|
1534
|
+
{renderOptionLabel(t("panel.config.legendOrient"), "legend.orient", t("panel.config.legendOrientHint"))}
|
|
1530
1535
|
<Select
|
|
1531
1536
|
value={String((el.chart?.option as any)?.legend?.orient ?? "horizontal")}
|
|
1532
1537
|
onValueChange={(value) =>
|
|
@@ -1561,7 +1566,7 @@ export function PanelConfigSidebar({
|
|
|
1561
1566
|
})
|
|
1562
1567
|
}
|
|
1563
1568
|
/>
|
|
1564
|
-
<span
|
|
1569
|
+
<span>{t("panel.config.showLegendWithKey")}</span>
|
|
1565
1570
|
</label>
|
|
1566
1571
|
<label className="flex items-center gap-2">
|
|
1567
1572
|
<Checkbox
|
|
@@ -1584,7 +1589,7 @@ export function PanelConfigSidebar({
|
|
|
1584
1589
|
});
|
|
1585
1590
|
}}
|
|
1586
1591
|
/>
|
|
1587
|
-
<span
|
|
1592
|
+
<span>{t("panel.config.zoomInsideWithKey")}</span>
|
|
1588
1593
|
</label>
|
|
1589
1594
|
<label className="flex items-center gap-2">
|
|
1590
1595
|
<Checkbox
|
|
@@ -1607,7 +1612,7 @@ export function PanelConfigSidebar({
|
|
|
1607
1612
|
});
|
|
1608
1613
|
}}
|
|
1609
1614
|
/>
|
|
1610
|
-
<span
|
|
1615
|
+
<span>{t("panel.config.zoomSliderWithKey")}</span>
|
|
1611
1616
|
</label>
|
|
1612
1617
|
<label className="flex items-center gap-2">
|
|
1613
1618
|
<Checkbox
|
|
@@ -1623,10 +1628,10 @@ export function PanelConfigSidebar({
|
|
|
1623
1628
|
})
|
|
1624
1629
|
}
|
|
1625
1630
|
/>
|
|
1626
|
-
<span
|
|
1631
|
+
<span>{t("panel.config.showAxisPointerWithKey")}</span>
|
|
1627
1632
|
</label>
|
|
1628
1633
|
<label className="block space-y-1">
|
|
1629
|
-
<div
|
|
1634
|
+
<div>{t("panel.config.axisPointerTypeWithKey")}</div>
|
|
1630
1635
|
<Select
|
|
1631
1636
|
value={String((el.chart?.option as any)?.axisPointer?.type ?? "line")}
|
|
1632
1637
|
onValueChange={(value) =>
|
|
@@ -1649,11 +1654,11 @@ export function PanelConfigSidebar({
|
|
|
1649
1654
|
</Select>
|
|
1650
1655
|
</label>
|
|
1651
1656
|
<label className="block space-y-1 col-span-2">
|
|
1652
|
-
<div
|
|
1657
|
+
<div>{t("panel.config.advancedOptionJson")}</div>
|
|
1653
1658
|
<Textarea
|
|
1654
1659
|
className="h-28 font-mono text-[11px]"
|
|
1655
1660
|
defaultValue={JSON.stringify(el.chart?.option ?? {}, null, 2)}
|
|
1656
|
-
placeholder=
|
|
1661
|
+
placeholder={t("panel.config.advancedJsonPlaceholder")}
|
|
1657
1662
|
onBlur={(e) => {
|
|
1658
1663
|
const nextText = e.target.value.trim();
|
|
1659
1664
|
if (!nextText) {
|
|
@@ -1674,7 +1679,7 @@ export function PanelConfigSidebar({
|
|
|
1674
1679
|
{el.materialType === "text" ? (
|
|
1675
1680
|
<div className="grid grid-cols-2 gap-2">
|
|
1676
1681
|
<label className="block space-y-1 col-span-2">
|
|
1677
|
-
<div
|
|
1682
|
+
<div>{t("panel.config.textHtml")}</div>
|
|
1678
1683
|
<Textarea
|
|
1679
1684
|
className="h-24"
|
|
1680
1685
|
value={el.textHtml ?? ""}
|
|
@@ -1682,7 +1687,7 @@ export function PanelConfigSidebar({
|
|
|
1682
1687
|
/>
|
|
1683
1688
|
</label>
|
|
1684
1689
|
<label className="block space-y-1">
|
|
1685
|
-
<div
|
|
1690
|
+
<div>{t("panel.config.fontSize")}</div>
|
|
1686
1691
|
<Input
|
|
1687
1692
|
className="h-7"
|
|
1688
1693
|
type="number"
|
|
@@ -1692,7 +1697,7 @@ export function PanelConfigSidebar({
|
|
|
1692
1697
|
/>
|
|
1693
1698
|
</label>
|
|
1694
1699
|
<label className="block space-y-1">
|
|
1695
|
-
<div
|
|
1700
|
+
<div>{t("panel.config.textColor")}</div>
|
|
1696
1701
|
<Input
|
|
1697
1702
|
className="h-7"
|
|
1698
1703
|
value={el.textColor ?? ""}
|
|
@@ -1704,7 +1709,7 @@ export function PanelConfigSidebar({
|
|
|
1704
1709
|
{el.materialType === "audio" ? (
|
|
1705
1710
|
<div className="grid grid-cols-2 gap-2">
|
|
1706
1711
|
<label className="block space-y-1 col-span-2">
|
|
1707
|
-
<div
|
|
1712
|
+
<div>{t("panel.config.audioUrl")}</div>
|
|
1708
1713
|
<Input
|
|
1709
1714
|
className="h-7"
|
|
1710
1715
|
value={el.audioRemoteUrl ?? ""}
|
|
@@ -1712,7 +1717,7 @@ export function PanelConfigSidebar({
|
|
|
1712
1717
|
/>
|
|
1713
1718
|
</label>
|
|
1714
1719
|
<label className="block space-y-1">
|
|
1715
|
-
<div
|
|
1720
|
+
<div>{t("panel.config.effect")}</div>
|
|
1716
1721
|
<Select
|
|
1717
1722
|
value={el.audioVisualEffect ?? "pulse"}
|
|
1718
1723
|
onValueChange={(value) =>
|
|
@@ -1728,7 +1733,7 @@ export function PanelConfigSidebar({
|
|
|
1728
1733
|
</Select>
|
|
1729
1734
|
</label>
|
|
1730
1735
|
<label className="block space-y-1">
|
|
1731
|
-
<div
|
|
1736
|
+
<div>{t("panel.config.speed")}</div>
|
|
1732
1737
|
<Select
|
|
1733
1738
|
value={el.audioVisualSpeed ?? "normal"}
|
|
1734
1739
|
onValueChange={(value) =>
|
|
@@ -1747,7 +1752,7 @@ export function PanelConfigSidebar({
|
|
|
1747
1752
|
) : null}
|
|
1748
1753
|
{el.materialType === "video" ? (
|
|
1749
1754
|
<label className="block space-y-1">
|
|
1750
|
-
<div
|
|
1755
|
+
<div>{t("panel.config.videoUrl")}</div>
|
|
1751
1756
|
<Input
|
|
1752
1757
|
className="h-7"
|
|
1753
1758
|
value={el.videoRemoteUrl ?? ""}
|
|
@@ -1758,11 +1763,11 @@ export function PanelConfigSidebar({
|
|
|
1758
1763
|
{el.materialType === "grid" ? (
|
|
1759
1764
|
<div className="grid grid-cols-2 gap-2 rounded-lg border border-border/60 bg-muted/20 p-3">
|
|
1760
1765
|
<label className="block space-y-1.5">
|
|
1761
|
-
<div
|
|
1766
|
+
<div>{t("panel.config.rows")}</div>
|
|
1762
1767
|
<Input className="h-7" type="number" min={1} value={el.gridRows ?? 2} onChange={(e) => updateElement(el.id, { gridRows: Math.max(1, Number(e.target.value) || 2) })} />
|
|
1763
1768
|
</label>
|
|
1764
1769
|
<label className="block space-y-1.5">
|
|
1765
|
-
<div
|
|
1770
|
+
<div>{t("panel.config.cols")}</div>
|
|
1766
1771
|
<Input className="h-7" type="number" min={1} value={el.gridCols ?? 3} onChange={(e) => updateElement(el.id, { gridCols: Math.max(1, Number(e.target.value) || 3) })} />
|
|
1767
1772
|
</label>
|
|
1768
1773
|
</div>
|
|
@@ -1770,7 +1775,7 @@ export function PanelConfigSidebar({
|
|
|
1770
1775
|
{el.materialType === "geometry" ? (
|
|
1771
1776
|
<div className="grid grid-cols-2 gap-2 rounded-lg border border-border/60 bg-muted/20 p-3">
|
|
1772
1777
|
<label className="block space-y-1.5">
|
|
1773
|
-
<div
|
|
1778
|
+
<div>{t("panel.config.shape")}</div>
|
|
1774
1779
|
<Select
|
|
1775
1780
|
value={el.geometryShape ?? "rect"}
|
|
1776
1781
|
onValueChange={(value) =>
|
|
@@ -1779,18 +1784,18 @@ export function PanelConfigSidebar({
|
|
|
1779
1784
|
>
|
|
1780
1785
|
<SelectTrigger className="h-7"><SelectValue /></SelectTrigger>
|
|
1781
1786
|
<SelectContent>
|
|
1782
|
-
<SelectItem value="rect"
|
|
1783
|
-
<SelectItem value="circle"
|
|
1784
|
-
<SelectItem value="triangle"
|
|
1785
|
-
<SelectItem value="diamond"
|
|
1786
|
-
<SelectItem value="hexagon"
|
|
1787
|
-
<SelectItem value="star"
|
|
1788
|
-
<SelectItem value="heart"
|
|
1787
|
+
<SelectItem value="rect">{t("panel.config.shapeRect")}</SelectItem>
|
|
1788
|
+
<SelectItem value="circle">{t("panel.config.shapeCircle")}</SelectItem>
|
|
1789
|
+
<SelectItem value="triangle">{t("panel.config.shapeTriangle")}</SelectItem>
|
|
1790
|
+
<SelectItem value="diamond">{t("panel.config.shapeDiamond")}</SelectItem>
|
|
1791
|
+
<SelectItem value="hexagon">{t("panel.config.shapeHexagon")}</SelectItem>
|
|
1792
|
+
<SelectItem value="star">{t("panel.config.shapeStar")}</SelectItem>
|
|
1793
|
+
<SelectItem value="heart">{t("panel.config.shapeHeart")}</SelectItem>
|
|
1789
1794
|
</SelectContent>
|
|
1790
1795
|
</Select>
|
|
1791
1796
|
</label>
|
|
1792
1797
|
<label className="block space-y-1.5">
|
|
1793
|
-
<div
|
|
1798
|
+
<div>{t("panel.config.color")}</div>
|
|
1794
1799
|
<Input
|
|
1795
1800
|
className="h-7"
|
|
1796
1801
|
value={el.geometryColor ?? "#3b82f6"}
|
|
@@ -1802,14 +1807,14 @@ export function PanelConfigSidebar({
|
|
|
1802
1807
|
{el.materialType === "reference" ? (
|
|
1803
1808
|
<div className="grid grid-cols-2 gap-2">
|
|
1804
1809
|
<label className="block space-y-1.5">
|
|
1805
|
-
<div
|
|
1810
|
+
<div>{t("panel.config.refLayer")}</div>
|
|
1806
1811
|
<Select
|
|
1807
1812
|
value={el.refLayerId ?? "__none__"}
|
|
1808
1813
|
onValueChange={(value) => updateElement(el.id, { refLayerId: value === "__none__" ? undefined : value })}
|
|
1809
1814
|
>
|
|
1810
1815
|
<SelectTrigger className="h-7"><SelectValue /></SelectTrigger>
|
|
1811
1816
|
<SelectContent>
|
|
1812
|
-
<SelectItem value="__none__"
|
|
1817
|
+
<SelectItem value="__none__">{t("common.none")}</SelectItem>
|
|
1813
1818
|
{layers.filter((l) => l.id !== el.layerId).map((l) => (
|
|
1814
1819
|
<SelectItem key={l.id} value={l.id}>{l.name}</SelectItem>
|
|
1815
1820
|
))}
|
|
@@ -1817,7 +1822,7 @@ export function PanelConfigSidebar({
|
|
|
1817
1822
|
</Select>
|
|
1818
1823
|
</label>
|
|
1819
1824
|
<label className="block space-y-1.5">
|
|
1820
|
-
<div
|
|
1825
|
+
<div>{t("panel.config.copy")}</div>
|
|
1821
1826
|
<Select
|
|
1822
1827
|
value={el.refCopyMode ?? "shallow"}
|
|
1823
1828
|
onValueChange={(value) => setReferenceCopyMode?.(el.id, value as ReferenceCopyMode)}
|
|
@@ -1844,7 +1849,7 @@ export function PanelConfigSidebar({
|
|
|
1844
1849
|
return !text.includes(normalizedSearch);
|
|
1845
1850
|
}) ? (
|
|
1846
1851
|
<div className="rounded border border-border/60 bg-background px-2 py-1.5 text-[11px] text-muted-foreground">
|
|
1847
|
-
|
|
1852
|
+
{t("panel.config.noEditableMatch")}
|
|
1848
1853
|
</div>
|
|
1849
1854
|
) : null}
|
|
1850
1855
|
</div>
|
|
@@ -1864,8 +1869,8 @@ export function PanelConfigSidebar({
|
|
|
1864
1869
|
<path d="M8 9h8M8 12h8M8 15h5" />
|
|
1865
1870
|
</svg>
|
|
1866
1871
|
</EmptyIcon>
|
|
1867
|
-
<EmptyTitle
|
|
1868
|
-
<EmptyDescription
|
|
1872
|
+
<EmptyTitle>{t("panel.config.emptyNoNodeTitle")}</EmptyTitle>
|
|
1873
|
+
<EmptyDescription>{t("panel.config.emptyNoNodeDesc")}</EmptyDescription>
|
|
1869
1874
|
</Empty>
|
|
1870
1875
|
) : !isMultiSelectMode && selectedElement ? (
|
|
1871
1876
|
<div className="space-y-3">
|
|
@@ -1886,17 +1891,17 @@ export function PanelConfigSidebar({
|
|
|
1886
1891
|
})
|
|
1887
1892
|
}
|
|
1888
1893
|
/>
|
|
1889
|
-
<span
|
|
1894
|
+
<span>{t("panel.config.lockNode")}</span>
|
|
1890
1895
|
</label>
|
|
1891
1896
|
</div>
|
|
1892
1897
|
<fieldset disabled={!isNodeEditable} className={!isNodeEditable ? "opacity-60" : ""}>
|
|
1893
1898
|
<div className="space-y-3.5 text-xs">
|
|
1894
1899
|
{renderSection(
|
|
1895
1900
|
"nodeInfo",
|
|
1896
|
-
"
|
|
1901
|
+
t("panel.config.sectionNodeInfo"),
|
|
1897
1902
|
<>
|
|
1898
|
-
<label className="block space-y-1">
|
|
1899
|
-
<div
|
|
1903
|
+
<label className="block space-y-1" data-config-field="name">
|
|
1904
|
+
<div>{t("panel.config.nodeName")}</div>
|
|
1900
1905
|
<Input
|
|
1901
1906
|
value={selectedElement.name ?? ""}
|
|
1902
1907
|
onChange={(e) =>
|
|
@@ -1904,12 +1909,12 @@ export function PanelConfigSidebar({
|
|
|
1904
1909
|
name: e.target.value || undefined,
|
|
1905
1910
|
})
|
|
1906
1911
|
}
|
|
1907
|
-
placeholder="
|
|
1912
|
+
placeholder={t("panel.config.nodeNamePlaceholder")}
|
|
1908
1913
|
className="h-7"
|
|
1909
1914
|
/>
|
|
1910
1915
|
</label>
|
|
1911
1916
|
<div className="grid grid-cols-3 gap-2">
|
|
1912
|
-
<label className="block space-y-1">
|
|
1917
|
+
<label className="block space-y-1" data-config-field="x">
|
|
1913
1918
|
<div>X</div>
|
|
1914
1919
|
<Input
|
|
1915
1920
|
type="number"
|
|
@@ -1922,7 +1927,7 @@ export function PanelConfigSidebar({
|
|
|
1922
1927
|
className="h-7"
|
|
1923
1928
|
/>
|
|
1924
1929
|
</label>
|
|
1925
|
-
<label className="block space-y-1">
|
|
1930
|
+
<label className="block space-y-1" data-config-field="y">
|
|
1926
1931
|
<div>Y</div>
|
|
1927
1932
|
<Input
|
|
1928
1933
|
type="number"
|
|
@@ -1937,8 +1942,8 @@ export function PanelConfigSidebar({
|
|
|
1937
1942
|
</label>
|
|
1938
1943
|
</div>
|
|
1939
1944
|
<div className="grid grid-cols-3 gap-2">
|
|
1940
|
-
<label className="block space-y-1">
|
|
1941
|
-
<div
|
|
1945
|
+
<label className="block space-y-1" data-config-field="rotate">
|
|
1946
|
+
<div>{t("panel.config.rotate")}</div>
|
|
1942
1947
|
<Input
|
|
1943
1948
|
type="number"
|
|
1944
1949
|
value={selectedElement.rotate ?? 0}
|
|
@@ -1950,8 +1955,8 @@ export function PanelConfigSidebar({
|
|
|
1950
1955
|
className="h-7"
|
|
1951
1956
|
/>
|
|
1952
1957
|
</label>
|
|
1953
|
-
<label className="block space-y-1">
|
|
1954
|
-
<div
|
|
1958
|
+
<label className="block space-y-1" data-config-field="width">
|
|
1959
|
+
<div>{t("panel.config.width")}</div>
|
|
1955
1960
|
<Input
|
|
1956
1961
|
type="number"
|
|
1957
1962
|
min={1}
|
|
@@ -1965,8 +1970,8 @@ export function PanelConfigSidebar({
|
|
|
1965
1970
|
className="h-7"
|
|
1966
1971
|
/>
|
|
1967
1972
|
</label>
|
|
1968
|
-
<label className="block space-y-1">
|
|
1969
|
-
<div
|
|
1973
|
+
<label className="block space-y-1" data-config-field="height">
|
|
1974
|
+
<div>{t("panel.config.height")}</div>
|
|
1970
1975
|
<Input
|
|
1971
1976
|
type="number"
|
|
1972
1977
|
min={1}
|
|
@@ -1981,9 +1986,9 @@ export function PanelConfigSidebar({
|
|
|
1981
1986
|
</label>
|
|
1982
1987
|
</div>
|
|
1983
1988
|
<div className="space-y-1.5">
|
|
1984
|
-
<div className="text-[11px] text-muted-foreground"
|
|
1989
|
+
<div className="text-[11px] text-muted-foreground">{t("panel.config.nodeZOrder")}</div>
|
|
1985
1990
|
<div className="text-[11px] text-muted-foreground/90">
|
|
1986
|
-
|
|
1991
|
+
{t("panel.config.currentZIndex", { value: nodeZOrderLabel ?? "-" })}
|
|
1987
1992
|
</div>
|
|
1988
1993
|
<div className="grid grid-cols-2 gap-2">
|
|
1989
1994
|
<button
|
|
@@ -1991,52 +1996,52 @@ export function PanelConfigSidebar({
|
|
|
1991
1996
|
className="rounded border border-border bg-background px-2 py-1 text-[11px] hover:bg-accent"
|
|
1992
1997
|
onClick={() => onAdjustNodeZOrder?.(selectedElement.id, "bringForward")}
|
|
1993
1998
|
>
|
|
1994
|
-
|
|
1999
|
+
{t("panel.menubar.bringForward")}
|
|
1995
2000
|
</button>
|
|
1996
2001
|
<button
|
|
1997
2002
|
type="button"
|
|
1998
2003
|
className="rounded border border-border bg-background px-2 py-1 text-[11px] hover:bg-accent"
|
|
1999
2004
|
onClick={() => onAdjustNodeZOrder?.(selectedElement.id, "sendBackward")}
|
|
2000
2005
|
>
|
|
2001
|
-
|
|
2006
|
+
{t("panel.menubar.sendBackward")}
|
|
2002
2007
|
</button>
|
|
2003
2008
|
<button
|
|
2004
2009
|
type="button"
|
|
2005
2010
|
className="rounded border border-border bg-background px-2 py-1 text-[11px] hover:bg-accent"
|
|
2006
2011
|
onClick={() => onAdjustNodeZOrder?.(selectedElement.id, "bringToFront")}
|
|
2007
2012
|
>
|
|
2008
|
-
|
|
2013
|
+
{t("panel.menubar.bringToFront")}
|
|
2009
2014
|
</button>
|
|
2010
2015
|
<button
|
|
2011
2016
|
type="button"
|
|
2012
2017
|
className="rounded border border-border bg-background px-2 py-1 text-[11px] hover:bg-accent"
|
|
2013
2018
|
onClick={() => onAdjustNodeZOrder?.(selectedElement.id, "sendToBack")}
|
|
2014
2019
|
>
|
|
2015
|
-
|
|
2020
|
+
{t("panel.menubar.sendToBack")}
|
|
2016
2021
|
</button>
|
|
2017
2022
|
</div>
|
|
2018
2023
|
</div>
|
|
2019
2024
|
<div className="truncate text-muted-foreground">ID: {selectedElement.id}</div>
|
|
2020
|
-
<div className="text-muted-foreground"
|
|
2025
|
+
<div className="text-muted-foreground">{t("panel.config.type")}: {selectedElement.materialType ?? selectedElement.id}</div>
|
|
2021
2026
|
</>,
|
|
2022
2027
|
true,
|
|
2023
|
-
["
|
|
2028
|
+
[t("panel.config.name"), "id", t("panel.config.type"), t("panel.layers.lockShort"), "locked", "name"]
|
|
2024
2029
|
)}
|
|
2025
2030
|
|
|
2026
2031
|
{renderSection(
|
|
2027
2032
|
"styleBackground",
|
|
2028
|
-
"
|
|
2033
|
+
t("panel.config.sectionStyleBackground"),
|
|
2029
2034
|
<>
|
|
2030
2035
|
{renderFieldGroup(
|
|
2031
|
-
"
|
|
2036
|
+
t("panel.config.groupBgFill"),
|
|
2032
2037
|
<>
|
|
2033
2038
|
{renderColorField(
|
|
2034
|
-
"
|
|
2039
|
+
t("panel.config.backgroundColor"),
|
|
2035
2040
|
selectedElement.style?.backgroundColor ?? "",
|
|
2036
2041
|
(next) => updateSelectedStyle({ backgroundColor: next || undefined })
|
|
2037
2042
|
)}
|
|
2038
2043
|
<label className="block space-y-1">
|
|
2039
|
-
<div
|
|
2044
|
+
<div>{t("panel.config.backgroundImage")}</div>
|
|
2040
2045
|
<Input
|
|
2041
2046
|
value={selectedElement.style?.backgroundImage ?? ""}
|
|
2042
2047
|
onChange={(e) => updateSelectedStyle({ backgroundImage: e.target.value || undefined })}
|
|
@@ -2046,7 +2051,7 @@ export function PanelConfigSidebar({
|
|
|
2046
2051
|
</label>
|
|
2047
2052
|
<div className="flex items-center gap-2">
|
|
2048
2053
|
<label className="inline-flex cursor-pointer items-center rounded border border-border px-2 py-1 text-[11px] hover:bg-accent">
|
|
2049
|
-
|
|
2054
|
+
{t("panel.config.uploadImage")}
|
|
2050
2055
|
<Input
|
|
2051
2056
|
type="file"
|
|
2052
2057
|
accept="image/*"
|
|
@@ -2066,10 +2071,10 @@ export function PanelConfigSidebar({
|
|
|
2066
2071
|
</>
|
|
2067
2072
|
)}
|
|
2068
2073
|
{renderFieldGroup(
|
|
2069
|
-
"
|
|
2074
|
+
t("panel.config.groupBgLayout"),
|
|
2070
2075
|
<div className="grid grid-cols-2 gap-2">
|
|
2071
2076
|
<label className="block space-y-1">
|
|
2072
|
-
<div
|
|
2077
|
+
<div>{t("panel.config.backgroundSize")}</div>
|
|
2073
2078
|
<Select
|
|
2074
2079
|
value={selectedElement.style?.backgroundSize ?? "__none__"}
|
|
2075
2080
|
onValueChange={(value) =>
|
|
@@ -2079,10 +2084,10 @@ export function PanelConfigSidebar({
|
|
|
2079
2084
|
}
|
|
2080
2085
|
>
|
|
2081
2086
|
<SelectTrigger className="h-7">
|
|
2082
|
-
<SelectValue placeholder="
|
|
2087
|
+
<SelectValue placeholder={t("panel.config.selectBackgroundSize")} />
|
|
2083
2088
|
</SelectTrigger>
|
|
2084
2089
|
<SelectContent>
|
|
2085
|
-
<SelectItem value="__none__"
|
|
2090
|
+
<SelectItem value="__none__">{t("common.default")}</SelectItem>
|
|
2086
2091
|
<SelectItem value="cover">cover</SelectItem>
|
|
2087
2092
|
<SelectItem value="contain">contain</SelectItem>
|
|
2088
2093
|
<SelectItem value="100% 100%">100% 100%</SelectItem>
|
|
@@ -2091,7 +2096,7 @@ export function PanelConfigSidebar({
|
|
|
2091
2096
|
</Select>
|
|
2092
2097
|
</label>
|
|
2093
2098
|
<label className="block space-y-1">
|
|
2094
|
-
<div
|
|
2099
|
+
<div>{t("panel.config.backgroundPosition")}</div>
|
|
2095
2100
|
<Select
|
|
2096
2101
|
value={selectedElement.style?.backgroundPosition ?? "__none__"}
|
|
2097
2102
|
onValueChange={(value) =>
|
|
@@ -2101,10 +2106,10 @@ export function PanelConfigSidebar({
|
|
|
2101
2106
|
}
|
|
2102
2107
|
>
|
|
2103
2108
|
<SelectTrigger className="h-7">
|
|
2104
|
-
<SelectValue placeholder="
|
|
2109
|
+
<SelectValue placeholder={t("panel.config.selectBackgroundPosition")} />
|
|
2105
2110
|
</SelectTrigger>
|
|
2106
2111
|
<SelectContent>
|
|
2107
|
-
<SelectItem value="__none__"
|
|
2112
|
+
<SelectItem value="__none__">{t("common.default")}</SelectItem>
|
|
2108
2113
|
<SelectItem value="center">center</SelectItem>
|
|
2109
2114
|
<SelectItem value="top">top</SelectItem>
|
|
2110
2115
|
<SelectItem value="bottom">bottom</SelectItem>
|
|
@@ -2121,18 +2126,18 @@ export function PanelConfigSidebar({
|
|
|
2121
2126
|
)}
|
|
2122
2127
|
</>,
|
|
2123
2128
|
true,
|
|
2124
|
-
["
|
|
2129
|
+
[t("panel.config.backgroundColor"), t("panel.config.backgroundImage"), "background", "backgroundSize", "backgroundPosition", t("panel.config.searchKwLayout")]
|
|
2125
2130
|
)}
|
|
2126
2131
|
|
|
2127
2132
|
{renderSection(
|
|
2128
2133
|
"styleBorder",
|
|
2129
|
-
"
|
|
2134
|
+
t("panel.config.sectionStyleBorder"),
|
|
2130
2135
|
<>
|
|
2131
2136
|
{renderFieldGroup(
|
|
2132
|
-
"
|
|
2137
|
+
t("panel.config.groupBorderGeometry"),
|
|
2133
2138
|
<div className="grid grid-cols-2 gap-2">
|
|
2134
2139
|
<label className="block space-y-1">
|
|
2135
|
-
<div
|
|
2140
|
+
<div>{t("panel.config.borderWidth")}</div>
|
|
2136
2141
|
<Input
|
|
2137
2142
|
type="number"
|
|
2138
2143
|
min={0}
|
|
@@ -2144,7 +2149,7 @@ export function PanelConfigSidebar({
|
|
|
2144
2149
|
/>
|
|
2145
2150
|
</label>
|
|
2146
2151
|
<label className="block space-y-1">
|
|
2147
|
-
<div
|
|
2152
|
+
<div>{t("panel.config.borderRadius")}</div>
|
|
2148
2153
|
<Input
|
|
2149
2154
|
type="number"
|
|
2150
2155
|
min={0}
|
|
@@ -2158,10 +2163,10 @@ export function PanelConfigSidebar({
|
|
|
2158
2163
|
</div>
|
|
2159
2164
|
)}
|
|
2160
2165
|
{renderFieldGroup(
|
|
2161
|
-
"
|
|
2166
|
+
t("panel.config.groupBorderVisual"),
|
|
2162
2167
|
<div className="grid grid-cols-2 gap-2">
|
|
2163
2168
|
<label className="block space-y-1">
|
|
2164
|
-
<div
|
|
2169
|
+
<div>{t("panel.config.borderStyle")}</div>
|
|
2165
2170
|
<Select
|
|
2166
2171
|
value={selectedElement.style?.borderStyle ?? "solid"}
|
|
2167
2172
|
onValueChange={(value) =>
|
|
@@ -2171,7 +2176,7 @@ export function PanelConfigSidebar({
|
|
|
2171
2176
|
}
|
|
2172
2177
|
>
|
|
2173
2178
|
<SelectTrigger className="h-7">
|
|
2174
|
-
<SelectValue placeholder="
|
|
2179
|
+
<SelectValue placeholder={t("panel.config.selectBorderStyle")} />
|
|
2175
2180
|
</SelectTrigger>
|
|
2176
2181
|
<SelectContent>
|
|
2177
2182
|
<SelectItem value="none">none</SelectItem>
|
|
@@ -2183,7 +2188,7 @@ export function PanelConfigSidebar({
|
|
|
2183
2188
|
</Select>
|
|
2184
2189
|
</label>
|
|
2185
2190
|
{renderColorField(
|
|
2186
|
-
"
|
|
2191
|
+
t("panel.config.borderColor"),
|
|
2187
2192
|
selectedElement.style?.borderColor ?? "",
|
|
2188
2193
|
(next) => updateSelectedStyle({ borderColor: next || undefined })
|
|
2189
2194
|
)}
|
|
@@ -2191,20 +2196,20 @@ export function PanelConfigSidebar({
|
|
|
2191
2196
|
)}
|
|
2192
2197
|
</>,
|
|
2193
2198
|
true,
|
|
2194
|
-
["
|
|
2199
|
+
[t("panel.config.searchKwBorder"), "border", t("panel.config.searchKwWidth"), t("panel.config.searchKwRadius"), t("panel.config.color"), t("panel.config.searchKwStyle")]
|
|
2195
2200
|
)}
|
|
2196
2201
|
|
|
2197
2202
|
{isChartElement ? (
|
|
2198
2203
|
<>
|
|
2199
2204
|
{renderSection(
|
|
2200
2205
|
"chartBasic",
|
|
2201
|
-
"
|
|
2206
|
+
t("panel.config.sectionChartBasic"),
|
|
2202
2207
|
<>
|
|
2203
2208
|
{renderFieldGroup(
|
|
2204
|
-
"
|
|
2209
|
+
t("panel.config.groupBasicDisplay"),
|
|
2205
2210
|
<>
|
|
2206
|
-
<label className="block space-y-1.5">
|
|
2207
|
-
<div
|
|
2211
|
+
<label className="block space-y-1.5" data-config-field="chart.title">
|
|
2212
|
+
<div>{t("panel.config.title")}</div>
|
|
2208
2213
|
<Input
|
|
2209
2214
|
value={selectedElement.chart?.title ?? ""}
|
|
2210
2215
|
onChange={(e) => updateSelectedChart({ title: e.target.value })}
|
|
@@ -2213,7 +2218,7 @@ export function PanelConfigSidebar({
|
|
|
2213
2218
|
</label>
|
|
2214
2219
|
|
|
2215
2220
|
{renderColorField(
|
|
2216
|
-
"
|
|
2221
|
+
t("panel.config.primaryColor"),
|
|
2217
2222
|
selectedElement.chart?.color ?? "#3b82f6",
|
|
2218
2223
|
(next) => updateSelectedChart({ color: next || "#3b82f6" })
|
|
2219
2224
|
)}
|
|
@@ -2224,22 +2229,22 @@ export function PanelConfigSidebar({
|
|
|
2224
2229
|
updateSelectedChart({ colorMode: checked ? "gradient" : "solid" })
|
|
2225
2230
|
}
|
|
2226
2231
|
/>
|
|
2227
|
-
<span
|
|
2232
|
+
<span>{t("panel.config.usePrimaryGradient")}</span>
|
|
2228
2233
|
</label>
|
|
2229
2234
|
{selectedElement.chart?.colorMode === "gradient" ? (
|
|
2230
2235
|
<div className="grid grid-cols-2 gap-2">
|
|
2231
2236
|
{renderColorField(
|
|
2232
|
-
"
|
|
2237
|
+
t("panel.config.gradientFrom"),
|
|
2233
2238
|
selectedElement.chart?.gradientFrom ?? selectedElement.chart?.color ?? "#3b82f6",
|
|
2234
2239
|
(next) => updateSelectedChart({ gradientFrom: next || "#3b82f6" })
|
|
2235
2240
|
)}
|
|
2236
2241
|
{renderColorField(
|
|
2237
|
-
"
|
|
2242
|
+
t("panel.config.gradientTo"),
|
|
2238
2243
|
selectedElement.chart?.gradientTo ?? "#22d3ee",
|
|
2239
2244
|
(next) => updateSelectedChart({ gradientTo: next || "#22d3ee" })
|
|
2240
2245
|
)}
|
|
2241
2246
|
<label className="block space-y-1 col-span-2">
|
|
2242
|
-
<div
|
|
2247
|
+
<div>{t("panel.config.gradientDirection")}</div>
|
|
2243
2248
|
<Select
|
|
2244
2249
|
value={selectedElement.chart?.gradientDirection ?? "to-right"}
|
|
2245
2250
|
onValueChange={(value) =>
|
|
@@ -2253,18 +2258,18 @@ export function PanelConfigSidebar({
|
|
|
2253
2258
|
}
|
|
2254
2259
|
>
|
|
2255
2260
|
<SelectTrigger className="h-7">
|
|
2256
|
-
<SelectValue placeholder="
|
|
2261
|
+
<SelectValue placeholder={t("panel.config.selectGradientDirection")} />
|
|
2257
2262
|
</SelectTrigger>
|
|
2258
2263
|
<SelectContent>
|
|
2259
|
-
<SelectItem value="to-right"
|
|
2260
|
-
<SelectItem value="to-bottom"
|
|
2261
|
-
<SelectItem value="to-bottom-right"
|
|
2262
|
-
<SelectItem value="to-top-right"
|
|
2264
|
+
<SelectItem value="to-right">{t("panel.config.dirToRight")}</SelectItem>
|
|
2265
|
+
<SelectItem value="to-bottom">{t("panel.config.dirToBottom")}</SelectItem>
|
|
2266
|
+
<SelectItem value="to-bottom-right">{t("panel.config.dirToBottomRight")}</SelectItem>
|
|
2267
|
+
<SelectItem value="to-top-right">{t("panel.config.dirToTopRight")}</SelectItem>
|
|
2263
2268
|
</SelectContent>
|
|
2264
2269
|
</Select>
|
|
2265
2270
|
</label>
|
|
2266
2271
|
<div className="col-span-2 space-y-1">
|
|
2267
|
-
<div className="text-[11px] text-muted-foreground"
|
|
2272
|
+
<div className="text-[11px] text-muted-foreground">{t("panel.config.gradientPreview")}</div>
|
|
2268
2273
|
<div
|
|
2269
2274
|
className="h-6 rounded border border-border/60"
|
|
2270
2275
|
style={{
|
|
@@ -2283,7 +2288,7 @@ export function PanelConfigSidebar({
|
|
|
2283
2288
|
</div>
|
|
2284
2289
|
) : null}
|
|
2285
2290
|
<label className="block space-y-1.5">
|
|
2286
|
-
<div
|
|
2291
|
+
<div>{t("panel.config.renderMode")}</div>
|
|
2287
2292
|
<Select
|
|
2288
2293
|
value={selectedElement.chart?.renderMode ?? "canvas"}
|
|
2289
2294
|
onValueChange={(value) =>
|
|
@@ -2291,7 +2296,7 @@ export function PanelConfigSidebar({
|
|
|
2291
2296
|
}
|
|
2292
2297
|
>
|
|
2293
2298
|
<SelectTrigger className="h-7">
|
|
2294
|
-
<SelectValue placeholder="
|
|
2299
|
+
<SelectValue placeholder={t("panel.config.selectRenderMode")} />
|
|
2295
2300
|
</SelectTrigger>
|
|
2296
2301
|
<SelectContent>
|
|
2297
2302
|
<SelectItem value="canvas">Canvas</SelectItem>
|
|
@@ -2302,7 +2307,7 @@ export function PanelConfigSidebar({
|
|
|
2302
2307
|
</>
|
|
2303
2308
|
)}
|
|
2304
2309
|
{renderFieldGroup(
|
|
2305
|
-
"
|
|
2310
|
+
t("panel.config.groupTooltip"),
|
|
2306
2311
|
<>
|
|
2307
2312
|
<div className="grid grid-cols-2 gap-2">
|
|
2308
2313
|
<label className="flex items-center gap-2">
|
|
@@ -2313,10 +2318,10 @@ export function PanelConfigSidebar({
|
|
|
2313
2318
|
updateSelectedChart({ tooltipShow: checked === true })
|
|
2314
2319
|
}
|
|
2315
2320
|
/>
|
|
2316
|
-
<span
|
|
2321
|
+
<span>{t("panel.config.showTooltip")}</span>
|
|
2317
2322
|
</label>
|
|
2318
2323
|
<label className="block space-y-1">
|
|
2319
|
-
<div>
|
|
2324
|
+
<div>{t("panel.config.tooltipTrigger")}</div>
|
|
2320
2325
|
<Select
|
|
2321
2326
|
value={selectedElement.chart?.tooltipTrigger ?? "axis"}
|
|
2322
2327
|
onValueChange={(value) =>
|
|
@@ -2324,7 +2329,7 @@ export function PanelConfigSidebar({
|
|
|
2324
2329
|
}
|
|
2325
2330
|
>
|
|
2326
2331
|
<SelectTrigger className="h-7">
|
|
2327
|
-
<SelectValue placeholder="
|
|
2332
|
+
<SelectValue placeholder={t("panel.config.selectTooltipTrigger")} />
|
|
2328
2333
|
</SelectTrigger>
|
|
2329
2334
|
<SelectContent>
|
|
2330
2335
|
<SelectItem value="axis">axis</SelectItem>
|
|
@@ -2335,42 +2340,39 @@ export function PanelConfigSidebar({
|
|
|
2335
2340
|
</div>
|
|
2336
2341
|
<div className="grid grid-cols-2 gap-2">
|
|
2337
2342
|
{renderColorField(
|
|
2338
|
-
"
|
|
2343
|
+
t("panel.config.tooltipBgColor"),
|
|
2339
2344
|
selectedElement.chart?.tooltipBackgroundColor ?? "#0f172a",
|
|
2340
2345
|
(next) => updateSelectedChart({ tooltipBackgroundColor: next || "#0f172a" })
|
|
2341
2346
|
)}
|
|
2342
2347
|
{renderColorField(
|
|
2343
|
-
"
|
|
2348
|
+
t("panel.config.tooltipTextColor"),
|
|
2344
2349
|
selectedElement.chart?.tooltipTextColor ?? "#f8fafc",
|
|
2345
2350
|
(next) => updateSelectedChart({ tooltipTextColor: next || "#f8fafc" })
|
|
2346
2351
|
)}
|
|
2347
2352
|
</div>
|
|
2348
2353
|
<label className="block space-y-1">
|
|
2349
|
-
{renderFormatterLabel("
|
|
2354
|
+
{renderFormatterLabel(t("panel.config.tooltipFormatter"))}
|
|
2350
2355
|
<Input
|
|
2351
2356
|
value={selectedElement.chart?.tooltipFormatter ?? ""}
|
|
2352
2357
|
onChange={(e) =>
|
|
2353
2358
|
updateSelectedChart({ tooltipFormatter: e.target.value || undefined })
|
|
2354
2359
|
}
|
|
2355
|
-
placeholder="
|
|
2360
|
+
placeholder={t("panel.config.tooltipFormatterPlaceholder")}
|
|
2356
2361
|
className="h-7"
|
|
2357
2362
|
/>
|
|
2358
2363
|
</label>
|
|
2359
2364
|
</>
|
|
2360
2365
|
)}
|
|
2361
2366
|
{renderFieldGroup(
|
|
2362
|
-
"
|
|
2367
|
+
t("panel.config.groupData"),
|
|
2363
2368
|
<>
|
|
2364
2369
|
<label className="block space-y-1">
|
|
2365
|
-
<div
|
|
2370
|
+
<div>{t("panel.config.labelsCsv")}</div>
|
|
2366
2371
|
<Input
|
|
2367
|
-
value={(selectedElement.chart
|
|
2372
|
+
value={getChartLabelsDisplayText(selectedElement.chart)}
|
|
2368
2373
|
onChange={(e) =>
|
|
2369
2374
|
updateSelectedChart({
|
|
2370
|
-
|
|
2371
|
-
.split(",")
|
|
2372
|
-
.map((s) => s.trim())
|
|
2373
|
-
.filter(Boolean),
|
|
2375
|
+
labelsText: e.target.value,
|
|
2374
2376
|
})
|
|
2375
2377
|
}
|
|
2376
2378
|
className="h-7"
|
|
@@ -2378,7 +2380,7 @@ export function PanelConfigSidebar({
|
|
|
2378
2380
|
</label>
|
|
2379
2381
|
|
|
2380
2382
|
<label className="block space-y-1">
|
|
2381
|
-
<div
|
|
2383
|
+
<div>{t("panel.config.valuesCsv")}</div>
|
|
2382
2384
|
<Input
|
|
2383
2385
|
value={getChartValuesDisplayText(selectedElement.chart)}
|
|
2384
2386
|
onChange={(e) =>
|
|
@@ -2397,24 +2399,24 @@ export function PanelConfigSidebar({
|
|
|
2397
2399
|
selectedChartType === "area" ||
|
|
2398
2400
|
selectedChartType === "scatter" ? (
|
|
2399
2401
|
renderFieldGroup(
|
|
2400
|
-
"
|
|
2402
|
+
t("panel.config.groupAxes"),
|
|
2401
2403
|
<>
|
|
2402
2404
|
<div className="grid grid-cols-2 gap-2">
|
|
2403
2405
|
<label className="block">
|
|
2404
|
-
<div className="mb-1">
|
|
2406
|
+
<div className="mb-1">{t("panel.config.xAxisName")}</div>
|
|
2405
2407
|
<Input
|
|
2406
2408
|
value={selectedElement.chart?.xAxisName ?? ""}
|
|
2407
2409
|
onChange={(e) => updateSelectedChart({ xAxisName: e.target.value })}
|
|
2408
|
-
placeholder="
|
|
2410
|
+
placeholder={t("panel.config.xAxisNamePlaceholder")}
|
|
2409
2411
|
className="h-7"
|
|
2410
2412
|
/>
|
|
2411
2413
|
</label>
|
|
2412
2414
|
<label className="block">
|
|
2413
|
-
<div className="mb-1">
|
|
2415
|
+
<div className="mb-1">{t("panel.config.yAxisName")}</div>
|
|
2414
2416
|
<Input
|
|
2415
2417
|
value={selectedElement.chart?.yAxisName ?? ""}
|
|
2416
2418
|
onChange={(e) => updateSelectedChart({ yAxisName: e.target.value })}
|
|
2417
|
-
placeholder="
|
|
2419
|
+
placeholder={t("panel.config.yAxisNamePlaceholder")}
|
|
2418
2420
|
className="h-7"
|
|
2419
2421
|
/>
|
|
2420
2422
|
</label>
|
|
@@ -2428,7 +2430,7 @@ export function PanelConfigSidebar({
|
|
|
2428
2430
|
updateSelectedChart({ xAxisTickShow: checked === true })
|
|
2429
2431
|
}
|
|
2430
2432
|
/>
|
|
2431
|
-
<span>
|
|
2433
|
+
<span>{t("panel.config.xAxisTick")}</span>
|
|
2432
2434
|
</label>
|
|
2433
2435
|
<label className="flex items-center gap-2">
|
|
2434
2436
|
<Checkbox
|
|
@@ -2438,17 +2440,17 @@ export function PanelConfigSidebar({
|
|
|
2438
2440
|
updateSelectedChart({ yAxisTickShow: checked === true })
|
|
2439
2441
|
}
|
|
2440
2442
|
/>
|
|
2441
|
-
<span>
|
|
2443
|
+
<span>{t("panel.config.yAxisTick")}</span>
|
|
2442
2444
|
</label>
|
|
2443
2445
|
</div>
|
|
2444
2446
|
<div className="grid grid-cols-2 gap-2">
|
|
2445
2447
|
{renderColorField(
|
|
2446
|
-
"
|
|
2448
|
+
t("panel.config.xAxisTickColor"),
|
|
2447
2449
|
selectedElement.chart?.xAxisTickColor ?? "#94a3b8",
|
|
2448
2450
|
(next) => updateSelectedChart({ xAxisTickColor: next || "#94a3b8" })
|
|
2449
2451
|
)}
|
|
2450
2452
|
{renderColorField(
|
|
2451
|
-
"
|
|
2453
|
+
t("panel.config.yAxisTickColor"),
|
|
2452
2454
|
selectedElement.chart?.yAxisTickColor ?? "#94a3b8",
|
|
2453
2455
|
(next) => updateSelectedChart({ yAxisTickColor: next || "#94a3b8" })
|
|
2454
2456
|
)}
|
|
@@ -2462,7 +2464,7 @@ export function PanelConfigSidebar({
|
|
|
2462
2464
|
updateSelectedChart({ xAxisSplitLineShow: checked === true })
|
|
2463
2465
|
}
|
|
2464
2466
|
/>
|
|
2465
|
-
<span>
|
|
2467
|
+
<span>{t("panel.config.xAxisSplitLine")}</span>
|
|
2466
2468
|
</label>
|
|
2467
2469
|
<label className="flex items-center gap-2">
|
|
2468
2470
|
<Checkbox
|
|
@@ -2472,36 +2474,36 @@ export function PanelConfigSidebar({
|
|
|
2472
2474
|
updateSelectedChart({ yAxisSplitLineShow: checked === true })
|
|
2473
2475
|
}
|
|
2474
2476
|
/>
|
|
2475
|
-
<span>
|
|
2477
|
+
<span>{t("panel.config.yAxisSplitLine")}</span>
|
|
2476
2478
|
</label>
|
|
2477
2479
|
</div>
|
|
2478
2480
|
<div className="grid grid-cols-2 gap-2">
|
|
2479
2481
|
{renderColorField(
|
|
2480
|
-
"
|
|
2482
|
+
t("panel.config.xAxisSplitLineColor"),
|
|
2481
2483
|
selectedElement.chart?.xAxisSplitLineColor ?? "#e2e8f0",
|
|
2482
2484
|
(next) => updateSelectedChart({ xAxisSplitLineColor: next || "#e2e8f0" })
|
|
2483
2485
|
)}
|
|
2484
2486
|
{renderColorField(
|
|
2485
|
-
"
|
|
2487
|
+
t("panel.config.yAxisSplitLineColor"),
|
|
2486
2488
|
selectedElement.chart?.yAxisSplitLineColor ?? "#e2e8f0",
|
|
2487
2489
|
(next) => updateSelectedChart({ yAxisSplitLineColor: next || "#e2e8f0" })
|
|
2488
2490
|
)}
|
|
2489
2491
|
</div>
|
|
2490
2492
|
<div className="grid grid-cols-2 gap-2">
|
|
2491
2493
|
{renderColorField(
|
|
2492
|
-
"
|
|
2494
|
+
t("panel.config.xAxisLabelColor"),
|
|
2493
2495
|
selectedElement.chart?.xAxisLabelColor ?? "#64748b",
|
|
2494
2496
|
(next) => updateSelectedChart({ xAxisLabelColor: next || "#64748b" })
|
|
2495
2497
|
)}
|
|
2496
2498
|
{renderColorField(
|
|
2497
|
-
"
|
|
2499
|
+
t("panel.config.yAxisLabelColor"),
|
|
2498
2500
|
selectedElement.chart?.yAxisLabelColor ?? "#64748b",
|
|
2499
2501
|
(next) => updateSelectedChart({ yAxisLabelColor: next || "#64748b" })
|
|
2500
2502
|
)}
|
|
2501
2503
|
</div>
|
|
2502
2504
|
<div className="grid grid-cols-2 gap-2">
|
|
2503
2505
|
<label className="block">
|
|
2504
|
-
<div className="mb-1">
|
|
2506
|
+
<div className="mb-1">{t("panel.config.xAxisLabelFontSize")}</div>
|
|
2505
2507
|
<Input
|
|
2506
2508
|
type="number"
|
|
2507
2509
|
min={8}
|
|
@@ -2516,7 +2518,7 @@ export function PanelConfigSidebar({
|
|
|
2516
2518
|
/>
|
|
2517
2519
|
</label>
|
|
2518
2520
|
<label className="block">
|
|
2519
|
-
<div className="mb-1">
|
|
2521
|
+
<div className="mb-1">{t("panel.config.yAxisLabelFontSize")}</div>
|
|
2520
2522
|
<Input
|
|
2521
2523
|
type="number"
|
|
2522
2524
|
min={8}
|
|
@@ -2540,7 +2542,7 @@ export function PanelConfigSidebar({
|
|
|
2540
2542
|
updateSelectedChart({ xAxisLabelAutoEllipsis: checked === true })
|
|
2541
2543
|
}
|
|
2542
2544
|
/>
|
|
2543
|
-
<span>
|
|
2545
|
+
<span>{t("panel.config.xAxisLabelAutoEllipsis")}</span>
|
|
2544
2546
|
</label>
|
|
2545
2547
|
<label className="flex items-center gap-2">
|
|
2546
2548
|
<Checkbox
|
|
@@ -2550,7 +2552,7 @@ export function PanelConfigSidebar({
|
|
|
2550
2552
|
updateSelectedChart({ yAxisLabelAutoEllipsis: checked === true })
|
|
2551
2553
|
}
|
|
2552
2554
|
/>
|
|
2553
|
-
<span>
|
|
2555
|
+
<span>{t("panel.config.yAxisLabelAutoEllipsis")}</span>
|
|
2554
2556
|
</label>
|
|
2555
2557
|
</div>
|
|
2556
2558
|
</>
|
|
@@ -2562,11 +2564,11 @@ export function PanelConfigSidebar({
|
|
|
2562
2564
|
selectedChartType === "area" ||
|
|
2563
2565
|
selectedChartType === "pie" ? (
|
|
2564
2566
|
renderFieldGroup(
|
|
2565
|
-
"
|
|
2567
|
+
t("panel.config.groupSeries"),
|
|
2566
2568
|
<>
|
|
2567
2569
|
{selectedChartType === "bar" ? (
|
|
2568
2570
|
<label className="block space-y-1">
|
|
2569
|
-
<div
|
|
2571
|
+
<div>{t("panel.config.barWidthPx")}</div>
|
|
2570
2572
|
<Input
|
|
2571
2573
|
type="number"
|
|
2572
2574
|
min={1}
|
|
@@ -2588,14 +2590,14 @@ export function PanelConfigSidebar({
|
|
|
2588
2590
|
updateSelectedChart({ smooth: checked === true })
|
|
2589
2591
|
}
|
|
2590
2592
|
/>
|
|
2591
|
-
<span
|
|
2593
|
+
<span>{t("panel.config.smooth")}</span>
|
|
2592
2594
|
</label>
|
|
2593
2595
|
) : null}
|
|
2594
2596
|
|
|
2595
2597
|
{selectedChartType === "pie" ? (
|
|
2596
2598
|
<div className="grid grid-cols-2 gap-2">
|
|
2597
2599
|
<label className="block space-y-1">
|
|
2598
|
-
<div
|
|
2600
|
+
<div>{t("panel.config.pieInnerRadiusPct")}</div>
|
|
2599
2601
|
<Input
|
|
2600
2602
|
type="number"
|
|
2601
2603
|
min={0}
|
|
@@ -2613,7 +2615,7 @@ export function PanelConfigSidebar({
|
|
|
2613
2615
|
/>
|
|
2614
2616
|
</label>
|
|
2615
2617
|
<label className="block space-y-1">
|
|
2616
|
-
<div
|
|
2618
|
+
<div>{t("panel.config.pieOuterRadiusPct")}</div>
|
|
2617
2619
|
<Input
|
|
2618
2620
|
type="number"
|
|
2619
2621
|
min={1}
|
|
@@ -2638,15 +2640,15 @@ export function PanelConfigSidebar({
|
|
|
2638
2640
|
</>,
|
|
2639
2641
|
true,
|
|
2640
2642
|
[
|
|
2641
|
-
"
|
|
2643
|
+
t("panel.config.searchKwChart"),
|
|
2642
2644
|
"title",
|
|
2643
2645
|
"tooltip",
|
|
2644
|
-
"
|
|
2645
|
-
"
|
|
2646
|
+
t("panel.config.searchKwXAxis"),
|
|
2647
|
+
t("panel.config.searchKwYAxis"),
|
|
2646
2648
|
"axis",
|
|
2647
2649
|
"label",
|
|
2648
|
-
"
|
|
2649
|
-
"
|
|
2650
|
+
t("panel.config.searchKwTick"),
|
|
2651
|
+
t("panel.config.searchKwSplit"),
|
|
2650
2652
|
"render",
|
|
2651
2653
|
"svg",
|
|
2652
2654
|
"canvas",
|
|
@@ -2655,10 +2657,10 @@ export function PanelConfigSidebar({
|
|
|
2655
2657
|
|
|
2656
2658
|
{renderSection(
|
|
2657
2659
|
"chartAdvanced",
|
|
2658
|
-
"
|
|
2660
|
+
t("panel.config.sectionChartAdvanced"),
|
|
2659
2661
|
<>
|
|
2660
2662
|
{renderFieldGroup(
|
|
2661
|
-
"
|
|
2663
|
+
t("panel.config.groupCommonForm"),
|
|
2662
2664
|
<div className="grid grid-cols-1 gap-2">
|
|
2663
2665
|
<div className="rounded-lg border border-border/60 bg-background/70 p-3">
|
|
2664
2666
|
<Collapsible
|
|
@@ -2670,75 +2672,75 @@ export function PanelConfigSidebar({
|
|
|
2670
2672
|
<button
|
|
2671
2673
|
type="button"
|
|
2672
2674
|
className="flex h-5 w-5 items-center justify-center rounded text-[11px] hover:bg-accent"
|
|
2673
|
-
aria-label={isSectionExpanded("chartAdvancedLayout", false) ? "
|
|
2675
|
+
aria-label={isSectionExpanded("chartAdvancedLayout", false) ? t("panel.config.collapseLayoutCoord") : t("panel.config.expandLayoutCoord")}
|
|
2674
2676
|
>
|
|
2675
2677
|
{isSectionExpanded("chartAdvancedLayout", false) ? "▾" : "▸"}
|
|
2676
2678
|
</button>
|
|
2677
2679
|
</CollapsibleTrigger>
|
|
2678
|
-
<div className="text-[11px] font-medium text-muted-foreground"
|
|
2680
|
+
<div className="text-[11px] font-medium text-muted-foreground">{t("panel.config.groupLayoutAndCoord")}</div>
|
|
2679
2681
|
</div>
|
|
2680
2682
|
<CollapsibleContent>
|
|
2681
2683
|
<div className="grid grid-cols-2 gap-2">
|
|
2682
2684
|
<label className="block space-y-1.5">
|
|
2683
|
-
<div className={optionLabelTextClass}
|
|
2685
|
+
<div className={optionLabelTextClass}>{t("panel.config.gridLeftForm")}</div>
|
|
2684
2686
|
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.grid?.left ?? 28)} onChange={(e) => updateSelectedOptionForm({ grid: { left: Number(e.target.value) || 0 } })} />
|
|
2685
2687
|
</label>
|
|
2686
2688
|
<label className="block space-y-1.5">
|
|
2687
|
-
<div className={optionLabelTextClass}
|
|
2689
|
+
<div className={optionLabelTextClass}>{t("panel.config.gridRightForm")}</div>
|
|
2688
2690
|
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.grid?.right ?? 10)} onChange={(e) => updateSelectedOptionForm({ grid: { right: Number(e.target.value) || 0 } })} />
|
|
2689
2691
|
</label>
|
|
2690
2692
|
<label className="block space-y-1.5">
|
|
2691
|
-
<div className={optionLabelTextClass}
|
|
2693
|
+
<div className={optionLabelTextClass}>{t("panel.config.gridTopForm")}</div>
|
|
2692
2694
|
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.grid?.top ?? 30)} onChange={(e) => updateSelectedOptionForm({ grid: { top: Number(e.target.value) || 0 } })} />
|
|
2693
2695
|
</label>
|
|
2694
2696
|
<label className="block space-y-1.5">
|
|
2695
|
-
<div className={optionLabelTextClass}
|
|
2697
|
+
<div className={optionLabelTextClass}>{t("panel.config.gridBottomForm")}</div>
|
|
2696
2698
|
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.grid?.bottom ?? 20)} onChange={(e) => updateSelectedOptionForm({ grid: { bottom: Number(e.target.value) || 0 } })} />
|
|
2697
2699
|
</label>
|
|
2698
2700
|
<label className="block space-y-1.5">
|
|
2699
|
-
<div className={optionLabelTextClass}
|
|
2701
|
+
<div className={optionLabelTextClass}>{t("panel.config.legendPositionForm")}</div>
|
|
2700
2702
|
<Select value={String((selectedElement.chart?.option as any)?.legend?.top ?? "top")} onValueChange={(value) => updateSelectedOptionForm({ legend: { top: value } })}>
|
|
2701
|
-
<SelectTrigger className={optionSelectTriggerClass}><SelectValue placeholder="
|
|
2703
|
+
<SelectTrigger className={optionSelectTriggerClass}><SelectValue placeholder={t("panel.config.selectLegendPosition")} /></SelectTrigger>
|
|
2702
2704
|
<SelectContent>
|
|
2703
|
-
<SelectItem value="top"
|
|
2704
|
-
<SelectItem value="bottom"
|
|
2705
|
-
<SelectItem value="left"
|
|
2706
|
-
<SelectItem value="right"
|
|
2705
|
+
<SelectItem value="top">{t("panel.config.legendTop")}</SelectItem>
|
|
2706
|
+
<SelectItem value="bottom">{t("panel.config.legendBottom")}</SelectItem>
|
|
2707
|
+
<SelectItem value="left">{t("panel.config.legendLeft")}</SelectItem>
|
|
2708
|
+
<SelectItem value="right">{t("panel.config.legendRight")}</SelectItem>
|
|
2707
2709
|
</SelectContent>
|
|
2708
2710
|
</Select>
|
|
2709
2711
|
</label>
|
|
2710
2712
|
<label className="block space-y-1.5">
|
|
2711
|
-
<div className={optionLabelTextClass}
|
|
2713
|
+
<div className={optionLabelTextClass}>{t("panel.config.legendOrientForm")}</div>
|
|
2712
2714
|
<Select value={String((selectedElement.chart?.option as any)?.legend?.orient ?? "horizontal")} onValueChange={(value) => updateSelectedOptionForm({ legend: { orient: value } })}>
|
|
2713
|
-
<SelectTrigger className={optionSelectTriggerClass}><SelectValue placeholder="
|
|
2715
|
+
<SelectTrigger className={optionSelectTriggerClass}><SelectValue placeholder={t("panel.config.selectLegendOrient")} /></SelectTrigger>
|
|
2714
2716
|
<SelectContent>
|
|
2715
|
-
<SelectItem value="horizontal"
|
|
2716
|
-
<SelectItem value="vertical"
|
|
2717
|
+
<SelectItem value="horizontal">{t("panel.config.legendHorizontal")}</SelectItem>
|
|
2718
|
+
<SelectItem value="vertical">{t("panel.config.legendVertical")}</SelectItem>
|
|
2717
2719
|
</SelectContent>
|
|
2718
2720
|
</Select>
|
|
2719
2721
|
</label>
|
|
2720
2722
|
<label className="block space-y-1.5">
|
|
2721
|
-
{renderOptionLabel("
|
|
2723
|
+
{renderOptionLabel(t("panel.config.xAxisMin"), "xAxis.min", t("panel.config.xAxisMinHint"))}
|
|
2722
2724
|
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.xAxis?.min ?? 0)} onChange={(e) => updateSelectedOptionForm({ xAxis: { min: Number(e.target.value) || 0 } })} />
|
|
2723
2725
|
</label>
|
|
2724
2726
|
<label className="block space-y-1.5">
|
|
2725
|
-
{renderOptionLabel("
|
|
2727
|
+
{renderOptionLabel(t("panel.config.xAxisMax"), "xAxis.max", t("panel.config.xAxisMaxHint"))}
|
|
2726
2728
|
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.xAxis?.max ?? 100)} onChange={(e) => updateSelectedOptionForm({ xAxis: { max: Number(e.target.value) || 0 } })} />
|
|
2727
2729
|
</label>
|
|
2728
2730
|
<label className="block space-y-1.5">
|
|
2729
|
-
{renderOptionLabel("
|
|
2731
|
+
{renderOptionLabel(t("panel.config.yAxisMin"), "yAxis.min", t("panel.config.yAxisMinHint"))}
|
|
2730
2732
|
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.yAxis?.min ?? 0)} onChange={(e) => updateSelectedOptionForm({ yAxis: { min: Number(e.target.value) || 0 } })} />
|
|
2731
2733
|
</label>
|
|
2732
2734
|
<label className="block space-y-1.5">
|
|
2733
|
-
{renderOptionLabel("
|
|
2735
|
+
{renderOptionLabel(t("panel.config.yAxisMax"), "yAxis.max", t("panel.config.yAxisMaxHint"))}
|
|
2734
2736
|
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.yAxis?.max ?? 100)} onChange={(e) => updateSelectedOptionForm({ yAxis: { max: Number(e.target.value) || 0 } })} />
|
|
2735
2737
|
</label>
|
|
2736
2738
|
<label className="block space-y-1.5">
|
|
2737
|
-
{renderOptionLabel("
|
|
2739
|
+
{renderOptionLabel(t("panel.config.xAxisLabelRotate"), "xAxis.axisLabel.rotate", t("panel.config.rotateUnitHint"))}
|
|
2738
2740
|
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.xAxis?.axisLabel?.rotate ?? 0)} onChange={(e) => updateSelectedOptionForm({ xAxis: { axisLabel: { rotate: Number(e.target.value) || 0 } } })} />
|
|
2739
2741
|
</label>
|
|
2740
2742
|
<label className="block space-y-1.5">
|
|
2741
|
-
{renderOptionLabel("
|
|
2743
|
+
{renderOptionLabel(t("panel.config.yAxisLabelRotate"), "yAxis.axisLabel.rotate", t("panel.config.rotateUnitHint"))}
|
|
2742
2744
|
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.yAxis?.axisLabel?.rotate ?? 0)} onChange={(e) => updateSelectedOptionForm({ yAxis: { axisLabel: { rotate: Number(e.target.value) || 0 } } })} />
|
|
2743
2745
|
</label>
|
|
2744
2746
|
</div>
|
|
@@ -2756,37 +2758,37 @@ export function PanelConfigSidebar({
|
|
|
2756
2758
|
<button
|
|
2757
2759
|
type="button"
|
|
2758
2760
|
className="flex h-5 w-5 items-center justify-center rounded text-[11px] hover:bg-accent"
|
|
2759
|
-
aria-label={isSectionExpanded("chartAdvancedHighFreq", true) ? "
|
|
2761
|
+
aria-label={isSectionExpanded("chartAdvancedHighFreq", true) ? t("panel.config.collapseHighFreq") : t("panel.config.expandHighFreq")}
|
|
2760
2762
|
>
|
|
2761
2763
|
{isSectionExpanded("chartAdvancedHighFreq", true) ? "▾" : "▸"}
|
|
2762
2764
|
</button>
|
|
2763
2765
|
</CollapsibleTrigger>
|
|
2764
|
-
<div className="text-[11px] font-medium text-muted-foreground"
|
|
2766
|
+
<div className="text-[11px] font-medium text-muted-foreground">{t("panel.config.groupHighFreq")}</div>
|
|
2765
2767
|
</div>
|
|
2766
2768
|
<CollapsibleContent>
|
|
2767
2769
|
<div className="grid grid-cols-1 gap-2">
|
|
2768
2770
|
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
2769
2771
|
<Checkbox className={optionCheckboxClass} checked={Boolean((selectedElement.chart?.option as any)?.legend?.show ?? true)} onCheckedChange={(checked) => updateSelectedOptionForm({ legend: { show: checked === true } })} />
|
|
2770
|
-
{renderOptionLabel("
|
|
2772
|
+
{renderOptionLabel(t("panel.config.showLegend"), "legend.show", t("panel.config.showLegendHint"))}
|
|
2771
2773
|
</label>
|
|
2772
2774
|
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
2773
2775
|
<Checkbox className={optionCheckboxClass} checked={Boolean((selectedElement.chart?.option as any)?.grid?.containLabel ?? false)} onCheckedChange={(checked) => updateSelectedOptionForm({ grid: { containLabel: checked === true } })} />
|
|
2774
|
-
{renderOptionLabel("
|
|
2776
|
+
{renderOptionLabel(t("panel.config.gridContainLabel"), "grid.containLabel", t("panel.config.gridContainLabelHint"))}
|
|
2775
2777
|
</label>
|
|
2776
2778
|
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
2777
2779
|
<Checkbox className={optionCheckboxClass} checked={Boolean(Array.isArray((selectedElement.chart?.option as any)?.dataZoom) && (selectedElement.chart?.option as any)?.dataZoom.some((z: any) => z?.type === "inside"))} onCheckedChange={(checked) => { const prev = Array.isArray((selectedElement.chart?.option as any)?.dataZoom) ? [...(selectedElement.chart?.option as any).dataZoom] : []; const next = checked ? [...prev.filter((z: any) => z?.type !== "inside"), { type: "inside" }] : prev.filter((z: any) => z?.type !== "inside"); updateSelectedOptionForm({ dataZoom: next }); }} />
|
|
2778
|
-
{renderOptionLabel("
|
|
2780
|
+
{renderOptionLabel(t("panel.config.zoomInside"), "dataZoom[type=inside]", t("panel.config.zoomInsideHint"))}
|
|
2779
2781
|
</label>
|
|
2780
2782
|
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
2781
2783
|
<Checkbox className={optionCheckboxClass} checked={Boolean(Array.isArray((selectedElement.chart?.option as any)?.dataZoom) && (selectedElement.chart?.option as any)?.dataZoom.some((z: any) => z?.type === "slider"))} onCheckedChange={(checked) => { const prev = Array.isArray((selectedElement.chart?.option as any)?.dataZoom) ? [...(selectedElement.chart?.option as any).dataZoom] : []; const next = checked ? [...prev.filter((z: any) => z?.type !== "slider"), { type: "slider" }] : prev.filter((z: any) => z?.type !== "slider"); updateSelectedOptionForm({ dataZoom: next }); }} />
|
|
2782
|
-
{renderOptionLabel("
|
|
2784
|
+
{renderOptionLabel(t("panel.config.zoomSlider"), "dataZoom[type=slider]", t("panel.config.zoomSliderHint"))}
|
|
2783
2785
|
</label>
|
|
2784
2786
|
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
2785
2787
|
<Checkbox className={optionCheckboxClass} checked={Boolean((selectedElement.chart?.option as any)?.animation ?? false)} onCheckedChange={(checked) => updateSelectedOptionForm({ animation: checked === true })} />
|
|
2786
|
-
{renderOptionLabel("
|
|
2788
|
+
{renderOptionLabel(t("panel.config.enableAnimation"), "animation", t("panel.config.enableAnimationHint"))}
|
|
2787
2789
|
</label>
|
|
2788
2790
|
<label className="block space-y-1.5">
|
|
2789
|
-
{renderOptionLabel("
|
|
2791
|
+
{renderOptionLabel(t("panel.config.animationDuration"), "animationDuration", t("panel.config.animationDurationHint"))}
|
|
2790
2792
|
<Input type="number" min={0} className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.animationDuration ?? 300)} onChange={(e) => updateSelectedOptionForm({ animationDuration: Math.max(0, Number(e.target.value) || 0) })} />
|
|
2791
2793
|
</label>
|
|
2792
2794
|
</div>
|
|
@@ -2801,33 +2803,33 @@ export function PanelConfigSidebar({
|
|
|
2801
2803
|
<button
|
|
2802
2804
|
type="button"
|
|
2803
2805
|
className="flex h-5 w-5 items-center justify-center rounded text-[11px] hover:bg-accent"
|
|
2804
|
-
aria-label={isSectionExpanded("chartAdvancedAxisPointer", false) ? "
|
|
2806
|
+
aria-label={isSectionExpanded("chartAdvancedAxisPointer", false) ? t("panel.config.collapseAxisPointer") : t("panel.config.expandAxisPointer")}
|
|
2805
2807
|
>
|
|
2806
2808
|
{isSectionExpanded("chartAdvancedAxisPointer", false) ? "▾" : "▸"}
|
|
2807
2809
|
</button>
|
|
2808
2810
|
</CollapsibleTrigger>
|
|
2809
|
-
<div className="text-[11px] font-medium text-muted-foreground"
|
|
2811
|
+
<div className="text-[11px] font-medium text-muted-foreground">{t("panel.config.groupAxisPointer")}</div>
|
|
2810
2812
|
</div>
|
|
2811
2813
|
<CollapsibleContent>
|
|
2812
2814
|
<div className="grid grid-cols-1 gap-2">
|
|
2813
2815
|
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
2814
2816
|
<Checkbox className={optionCheckboxClass} checked={Boolean((selectedElement.chart?.option as any)?.axisPointer?.show ?? false)} onCheckedChange={(checked) => updateSelectedOptionForm({ axisPointer: { show: checked === true } })} />
|
|
2815
|
-
{renderOptionLabel("
|
|
2817
|
+
{renderOptionLabel(t("panel.config.showAxisPointer"), "axisPointer.show", t("panel.config.showAxisPointerHint"))}
|
|
2816
2818
|
</label>
|
|
2817
2819
|
<label className="block space-y-1.5 rounded-md bg-muted/30 px-2 py-1.5">
|
|
2818
|
-
{renderOptionLabel("
|
|
2820
|
+
{renderOptionLabel(t("panel.config.axisPointerType"), "axisPointer.type", t("panel.config.axisPointerTypeHint"))}
|
|
2819
2821
|
<Select value={String((selectedElement.chart?.option as any)?.axisPointer?.type ?? "line")} onValueChange={(value) => updateSelectedOptionForm({ axisPointer: { type: value } })}>
|
|
2820
|
-
<SelectTrigger className={optionSelectTriggerClass}><SelectValue placeholder="
|
|
2822
|
+
<SelectTrigger className={optionSelectTriggerClass}><SelectValue placeholder={t("panel.config.selectAxisPointerType")} /></SelectTrigger>
|
|
2821
2823
|
<SelectContent>
|
|
2822
|
-
<SelectItem value="line"
|
|
2823
|
-
<SelectItem value="shadow"
|
|
2824
|
-
<SelectItem value="cross"
|
|
2824
|
+
<SelectItem value="line">{t("panel.config.axisPointerLine")}</SelectItem>
|
|
2825
|
+
<SelectItem value="shadow">{t("panel.config.axisPointerShadow")}</SelectItem>
|
|
2826
|
+
<SelectItem value="cross">{t("panel.config.axisPointerCross")}</SelectItem>
|
|
2825
2827
|
</SelectContent>
|
|
2826
2828
|
</Select>
|
|
2827
2829
|
</label>
|
|
2828
2830
|
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
2829
2831
|
<Checkbox className={optionCheckboxClass} checked={Boolean((selectedElement.chart?.option as any)?.axisPointer?.snap ?? false)} onCheckedChange={(checked) => updateSelectedOptionForm({ axisPointer: { snap: checked === true } })} />
|
|
2830
|
-
{renderOptionLabel("
|
|
2832
|
+
{renderOptionLabel(t("panel.config.axisPointerSnap"), "axisPointer.snap", t("panel.config.axisPointerSnapHint"))}
|
|
2831
2833
|
</label>
|
|
2832
2834
|
</div>
|
|
2833
2835
|
</CollapsibleContent>
|
|
@@ -2837,7 +2839,7 @@ export function PanelConfigSidebar({
|
|
|
2837
2839
|
</div>
|
|
2838
2840
|
)}
|
|
2839
2841
|
{renderFieldGroup(
|
|
2840
|
-
"
|
|
2842
|
+
t("panel.config.groupJsonAdvanced"),
|
|
2841
2843
|
<>
|
|
2842
2844
|
<label className="flex items-center gap-2 rounded-md bg-background/70 px-2 py-1.5">
|
|
2843
2845
|
<Checkbox
|
|
@@ -2845,11 +2847,11 @@ export function PanelConfigSidebar({
|
|
|
2845
2847
|
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
2846
2848
|
onCheckedChange={(checked) => setIsAdvancedOptionMode(checked === true)}
|
|
2847
2849
|
/>
|
|
2848
|
-
<span
|
|
2850
|
+
<span>{t("panel.config.enableAdvancedJson")}</span>
|
|
2851
|
+
<ConfigHintIcon label={t("panel.config.advancedJsonHintLabel")}>
|
|
2852
|
+
{t("panel.config.advancedJsonHint")}
|
|
2853
|
+
</ConfigHintIcon>
|
|
2849
2854
|
</label>
|
|
2850
|
-
<div className="rounded border border-border/60 bg-background px-2 py-1.5 text-[11px] text-muted-foreground">
|
|
2851
|
-
基础配置会先生成图表配置,高级模式会在此基础上覆盖(深度合并)。
|
|
2852
|
-
</div>
|
|
2853
2855
|
{isAdvancedOptionMode ? (
|
|
2854
2856
|
<>
|
|
2855
2857
|
<Textarea
|
|
@@ -2862,7 +2864,7 @@ export function PanelConfigSidebar({
|
|
|
2862
2864
|
updateSelectedChart({ option: parsed });
|
|
2863
2865
|
setOptionJsonError(null);
|
|
2864
2866
|
} catch {
|
|
2865
|
-
setOptionJsonError("
|
|
2867
|
+
setOptionJsonError(t("panel.config.jsonInvalid"));
|
|
2866
2868
|
}
|
|
2867
2869
|
}}
|
|
2868
2870
|
spellCheck={false}
|
|
@@ -2874,7 +2876,7 @@ export function PanelConfigSidebar({
|
|
|
2874
2876
|
</div>
|
|
2875
2877
|
) : (
|
|
2876
2878
|
<div className="rounded border border-emerald-500/30 bg-emerald-500/10 px-2 py-1.5 text-[11px] text-emerald-700 dark:text-emerald-300">
|
|
2877
|
-
|
|
2879
|
+
{t("panel.config.jsonValidApplied")}
|
|
2878
2880
|
</div>
|
|
2879
2881
|
)}
|
|
2880
2882
|
</>
|
|
@@ -2883,16 +2885,35 @@ export function PanelConfigSidebar({
|
|
|
2883
2885
|
)}
|
|
2884
2886
|
</>,
|
|
2885
2887
|
false,
|
|
2886
|
-
["json", "option", "
|
|
2888
|
+
["json", "option", t("panel.config.searchKwAdvanced"), "echarts"]
|
|
2887
2889
|
)}
|
|
2888
2890
|
</>
|
|
2891
|
+
) : selectedElement.materialType === "table" ? (
|
|
2892
|
+
renderSection(
|
|
2893
|
+
"tableConfig",
|
|
2894
|
+
t("panel.config.sectionTable"),
|
|
2895
|
+
<PanelConfigTableSection
|
|
2896
|
+
element={selectedElement}
|
|
2897
|
+
disabled={!isNodeEditable}
|
|
2898
|
+
updateElement={updateElement}
|
|
2899
|
+
blueprintNodeOptions={blueprintNodeOptions}
|
|
2900
|
+
/>,
|
|
2901
|
+
true,
|
|
2902
|
+
[
|
|
2903
|
+
t("panel.material.table"),
|
|
2904
|
+
"table",
|
|
2905
|
+
t("panel.config.tableSource"),
|
|
2906
|
+
t("panel.config.tableColumns"),
|
|
2907
|
+
t("panel.config.tableRowsText"),
|
|
2908
|
+
]
|
|
2909
|
+
)
|
|
2889
2910
|
) : selectedElement.materialType === "text" ? (
|
|
2890
2911
|
renderSection(
|
|
2891
2912
|
"textConfig",
|
|
2892
|
-
"
|
|
2913
|
+
t("panel.config.sectionText"),
|
|
2893
2914
|
<>
|
|
2894
2915
|
{renderFieldGroup(
|
|
2895
|
-
"
|
|
2916
|
+
t("panel.config.groupTextContent"),
|
|
2896
2917
|
<>
|
|
2897
2918
|
<div className="flex items-center gap-1">
|
|
2898
2919
|
<button
|
|
@@ -2919,6 +2940,7 @@ export function PanelConfigSidebar({
|
|
|
2919
2940
|
</div>
|
|
2920
2941
|
<div
|
|
2921
2942
|
ref={textEditorRef}
|
|
2943
|
+
data-config-field="textHtml"
|
|
2922
2944
|
className="min-h-[120px] rounded border border-border bg-background px-2 py-1.5 text-xs leading-6 outline-none"
|
|
2923
2945
|
style={{
|
|
2924
2946
|
fontFamily: selectedElement.textFontFamily || undefined,
|
|
@@ -2944,10 +2966,10 @@ export function PanelConfigSidebar({
|
|
|
2944
2966
|
</>
|
|
2945
2967
|
)}
|
|
2946
2968
|
{renderFieldGroup(
|
|
2947
|
-
"
|
|
2969
|
+
t("panel.config.groupTextStyle"),
|
|
2948
2970
|
<>
|
|
2949
2971
|
<label className="block space-y-1">
|
|
2950
|
-
<div
|
|
2972
|
+
<div>{t("panel.config.fontFamily")}</div>
|
|
2951
2973
|
<Input
|
|
2952
2974
|
value={selectedElement.textFontFamily ?? ""}
|
|
2953
2975
|
onChange={(e) =>
|
|
@@ -2955,13 +2977,13 @@ export function PanelConfigSidebar({
|
|
|
2955
2977
|
textFontFamily: e.target.value || undefined,
|
|
2956
2978
|
})
|
|
2957
2979
|
}
|
|
2958
|
-
placeholder="
|
|
2980
|
+
placeholder={t("panel.config.fontFamilyPlaceholder")}
|
|
2959
2981
|
className="h-7"
|
|
2960
2982
|
/>
|
|
2961
2983
|
</label>
|
|
2962
2984
|
<div className="grid grid-cols-2 gap-2">
|
|
2963
2985
|
<label className="block space-y-1">
|
|
2964
|
-
<div
|
|
2986
|
+
<div>{t("panel.config.fontSizePx")}</div>
|
|
2965
2987
|
<Input
|
|
2966
2988
|
type="number"
|
|
2967
2989
|
min={8}
|
|
@@ -2977,7 +2999,7 @@ export function PanelConfigSidebar({
|
|
|
2977
2999
|
/>
|
|
2978
3000
|
</label>
|
|
2979
3001
|
<label className="block space-y-1">
|
|
2980
|
-
<div
|
|
3002
|
+
<div>{t("panel.config.fontWeight")}</div>
|
|
2981
3003
|
<Select
|
|
2982
3004
|
value={selectedElement.textFontWeight ?? "400"}
|
|
2983
3005
|
onValueChange={(value) =>
|
|
@@ -2987,7 +3009,7 @@ export function PanelConfigSidebar({
|
|
|
2987
3009
|
}
|
|
2988
3010
|
>
|
|
2989
3011
|
<SelectTrigger className="h-7">
|
|
2990
|
-
<SelectValue placeholder="
|
|
3012
|
+
<SelectValue placeholder={t("panel.config.selectFontWeight")} />
|
|
2991
3013
|
</SelectTrigger>
|
|
2992
3014
|
<SelectContent>
|
|
2993
3015
|
<SelectItem value="300">300</SelectItem>
|
|
@@ -3001,7 +3023,7 @@ export function PanelConfigSidebar({
|
|
|
3001
3023
|
</div>
|
|
3002
3024
|
<div className="grid grid-cols-2 gap-2">
|
|
3003
3025
|
<label className="block space-y-1">
|
|
3004
|
-
<div
|
|
3026
|
+
<div>{t("panel.config.textAlign")}</div>
|
|
3005
3027
|
<Select
|
|
3006
3028
|
value={selectedElement.textAlign ?? "left"}
|
|
3007
3029
|
onValueChange={(value) =>
|
|
@@ -3011,18 +3033,18 @@ export function PanelConfigSidebar({
|
|
|
3011
3033
|
}
|
|
3012
3034
|
>
|
|
3013
3035
|
<SelectTrigger className="h-7">
|
|
3014
|
-
<SelectValue placeholder="
|
|
3036
|
+
<SelectValue placeholder={t("panel.config.selectTextAlign")} />
|
|
3015
3037
|
</SelectTrigger>
|
|
3016
3038
|
<SelectContent>
|
|
3017
|
-
<SelectItem value="left"
|
|
3018
|
-
<SelectItem value="center"
|
|
3019
|
-
<SelectItem value="right"
|
|
3020
|
-
<SelectItem value="justify"
|
|
3039
|
+
<SelectItem value="left">{t("panel.config.alignLeft")}</SelectItem>
|
|
3040
|
+
<SelectItem value="center">{t("panel.config.alignCenter")}</SelectItem>
|
|
3041
|
+
<SelectItem value="right">{t("panel.config.alignRight")}</SelectItem>
|
|
3042
|
+
<SelectItem value="justify">{t("panel.config.alignJustify")}</SelectItem>
|
|
3021
3043
|
</SelectContent>
|
|
3022
3044
|
</Select>
|
|
3023
3045
|
</label>
|
|
3024
3046
|
<label className="block space-y-1">
|
|
3025
|
-
<div
|
|
3047
|
+
<div>{t("panel.config.lineHeight")}</div>
|
|
3026
3048
|
<Input
|
|
3027
3049
|
type="number"
|
|
3028
3050
|
min={1}
|
|
@@ -3042,7 +3064,7 @@ export function PanelConfigSidebar({
|
|
|
3042
3064
|
</label>
|
|
3043
3065
|
</div>
|
|
3044
3066
|
{renderColorField(
|
|
3045
|
-
"
|
|
3067
|
+
t("panel.config.textColor"),
|
|
3046
3068
|
selectedElement.textColor ?? "",
|
|
3047
3069
|
(next) =>
|
|
3048
3070
|
updateSelectedText({
|
|
@@ -3052,7 +3074,7 @@ export function PanelConfigSidebar({
|
|
|
3052
3074
|
</>
|
|
3053
3075
|
)}
|
|
3054
3076
|
{renderFieldGroup(
|
|
3055
|
-
"
|
|
3077
|
+
t("panel.config.groupInputAbility"),
|
|
3056
3078
|
<label className="flex items-center gap-2">
|
|
3057
3079
|
<Checkbox
|
|
3058
3080
|
checked={selectedElement.textAllowInput ?? true}
|
|
@@ -3063,23 +3085,23 @@ export function PanelConfigSidebar({
|
|
|
3063
3085
|
})
|
|
3064
3086
|
}
|
|
3065
3087
|
/>
|
|
3066
|
-
<span
|
|
3088
|
+
<span>{t("panel.config.allowCanvasInput")}</span>
|
|
3067
3089
|
</label>
|
|
3068
3090
|
)}
|
|
3069
3091
|
</>,
|
|
3070
3092
|
true,
|
|
3071
|
-
["
|
|
3093
|
+
[t("panel.material.text"), t("panel.config.searchKwRichText"), t("panel.config.fontFamily"), t("panel.config.color"), t("panel.config.textAlign"), t("panel.config.lineHeight"), t("panel.config.searchKwInput")]
|
|
3072
3094
|
)
|
|
3073
3095
|
) : selectedElement.materialType === "audio" ? (
|
|
3074
3096
|
renderSection(
|
|
3075
3097
|
"audioConfig",
|
|
3076
|
-
"
|
|
3098
|
+
t("panel.config.sectionAudio"),
|
|
3077
3099
|
<>
|
|
3078
3100
|
{renderFieldGroup(
|
|
3079
|
-
"
|
|
3101
|
+
t("panel.config.groupAudioSource"),
|
|
3080
3102
|
<>
|
|
3081
3103
|
<label className="block space-y-1">
|
|
3082
|
-
<div
|
|
3104
|
+
<div>{t("panel.config.audioUrl")}</div>
|
|
3083
3105
|
<Input
|
|
3084
3106
|
value={selectedElement.audioRemoteUrl ?? ""}
|
|
3085
3107
|
onChange={(e) =>
|
|
@@ -3094,7 +3116,7 @@ export function PanelConfigSidebar({
|
|
|
3094
3116
|
</label>
|
|
3095
3117
|
<div className="flex items-center gap-2">
|
|
3096
3118
|
<label className="inline-flex cursor-pointer items-center rounded border border-border px-2 py-1 text-[11px] hover:bg-accent">
|
|
3097
|
-
|
|
3119
|
+
{t("panel.config.uploadAudio")}
|
|
3098
3120
|
<Input
|
|
3099
3121
|
type="file"
|
|
3100
3122
|
accept="audio/*"
|
|
@@ -3112,7 +3134,7 @@ export function PanelConfigSidebar({
|
|
|
3112
3134
|
className="rounded border border-border px-2 py-1 text-[11px] hover:bg-accent disabled:opacity-50"
|
|
3113
3135
|
onClick={isRecordingAudio ? stopRecordingAudio : startRecordingAudio}
|
|
3114
3136
|
>
|
|
3115
|
-
{isRecordingAudio ? "
|
|
3137
|
+
{isRecordingAudio ? t("panel.config.stopRecord") : t("panel.config.startRecord")}
|
|
3116
3138
|
</button>
|
|
3117
3139
|
</div>
|
|
3118
3140
|
{audioStatus ? (
|
|
@@ -3128,7 +3150,7 @@ export function PanelConfigSidebar({
|
|
|
3128
3150
|
</>
|
|
3129
3151
|
)}
|
|
3130
3152
|
{renderFieldGroup(
|
|
3131
|
-
"
|
|
3153
|
+
t("panel.config.groupDisplayStyle"),
|
|
3132
3154
|
<>
|
|
3133
3155
|
<label className="flex items-center gap-2">
|
|
3134
3156
|
<Checkbox
|
|
@@ -3140,10 +3162,10 @@ export function PanelConfigSidebar({
|
|
|
3140
3162
|
})
|
|
3141
3163
|
}
|
|
3142
3164
|
/>
|
|
3143
|
-
<span
|
|
3165
|
+
<span>{t("panel.config.autoPauseMedia")}</span>
|
|
3144
3166
|
</label>
|
|
3145
3167
|
<label className="block space-y-1">
|
|
3146
|
-
<div
|
|
3168
|
+
<div>{t("panel.config.audioIconPreset")}</div>
|
|
3147
3169
|
<Select
|
|
3148
3170
|
value={selectedElement.audioIconPreset ?? "__none__"}
|
|
3149
3171
|
onValueChange={(value) =>
|
|
@@ -3156,19 +3178,19 @@ export function PanelConfigSidebar({
|
|
|
3156
3178
|
}
|
|
3157
3179
|
>
|
|
3158
3180
|
<SelectTrigger className="h-7">
|
|
3159
|
-
<SelectValue placeholder="
|
|
3181
|
+
<SelectValue placeholder={t("panel.config.selectIcon")} />
|
|
3160
3182
|
</SelectTrigger>
|
|
3161
3183
|
<SelectContent>
|
|
3162
|
-
<SelectItem value="__none__"
|
|
3163
|
-
<SelectItem value="speaker"
|
|
3164
|
-
<SelectItem value="music"
|
|
3165
|
-
<SelectItem value="headphone"
|
|
3166
|
-
<SelectItem value="wave"
|
|
3184
|
+
<SelectItem value="__none__">{t("panel.config.iconDefaultProgress")}</SelectItem>
|
|
3185
|
+
<SelectItem value="speaker">{t("panel.config.iconSpeaker")}</SelectItem>
|
|
3186
|
+
<SelectItem value="music">{t("panel.config.iconMusic")}</SelectItem>
|
|
3187
|
+
<SelectItem value="headphone">{t("panel.config.iconHeadphone")}</SelectItem>
|
|
3188
|
+
<SelectItem value="wave">{t("panel.config.iconWave")}</SelectItem>
|
|
3167
3189
|
</SelectContent>
|
|
3168
3190
|
</Select>
|
|
3169
3191
|
</label>
|
|
3170
3192
|
<label className="block space-y-1">
|
|
3171
|
-
<div
|
|
3193
|
+
<div>{t("panel.config.visualEffect")}</div>
|
|
3172
3194
|
<Select
|
|
3173
3195
|
value={selectedElement.audioVisualEffect ?? "pulse"}
|
|
3174
3196
|
onValueChange={(value) =>
|
|
@@ -3178,17 +3200,17 @@ export function PanelConfigSidebar({
|
|
|
3178
3200
|
}
|
|
3179
3201
|
>
|
|
3180
3202
|
<SelectTrigger className="h-7">
|
|
3181
|
-
<SelectValue placeholder="
|
|
3203
|
+
<SelectValue placeholder={t("panel.config.selectEffect")} />
|
|
3182
3204
|
</SelectTrigger>
|
|
3183
3205
|
<SelectContent>
|
|
3184
|
-
<SelectItem value="none"
|
|
3185
|
-
<SelectItem value="pulse"
|
|
3186
|
-
<SelectItem value="ripple"
|
|
3206
|
+
<SelectItem value="none">{t("panel.config.effectNone")}</SelectItem>
|
|
3207
|
+
<SelectItem value="pulse">{t("panel.config.effectPulse")}</SelectItem>
|
|
3208
|
+
<SelectItem value="ripple">{t("panel.config.effectRipple")}</SelectItem>
|
|
3187
3209
|
</SelectContent>
|
|
3188
3210
|
</Select>
|
|
3189
3211
|
</label>
|
|
3190
3212
|
<label className="block space-y-1">
|
|
3191
|
-
<div
|
|
3213
|
+
<div>{t("panel.config.effectSpeed")}</div>
|
|
3192
3214
|
<Select
|
|
3193
3215
|
value={selectedElement.audioVisualSpeed ?? "normal"}
|
|
3194
3216
|
onValueChange={(value) =>
|
|
@@ -3198,18 +3220,18 @@ export function PanelConfigSidebar({
|
|
|
3198
3220
|
}
|
|
3199
3221
|
>
|
|
3200
3222
|
<SelectTrigger className="h-7">
|
|
3201
|
-
<SelectValue placeholder="
|
|
3223
|
+
<SelectValue placeholder={t("panel.config.selectSpeed")} />
|
|
3202
3224
|
</SelectTrigger>
|
|
3203
3225
|
<SelectContent>
|
|
3204
|
-
<SelectItem value="slow"
|
|
3205
|
-
<SelectItem value="normal"
|
|
3206
|
-
<SelectItem value="fast"
|
|
3226
|
+
<SelectItem value="slow">{t("panel.config.speedSlow")}</SelectItem>
|
|
3227
|
+
<SelectItem value="normal">{t("panel.config.speedNormal")}</SelectItem>
|
|
3228
|
+
<SelectItem value="fast">{t("panel.config.speedFast")}</SelectItem>
|
|
3207
3229
|
</SelectContent>
|
|
3208
3230
|
</Select>
|
|
3209
3231
|
</label>
|
|
3210
3232
|
<div className="flex items-center gap-2">
|
|
3211
3233
|
<label className="inline-flex cursor-pointer items-center rounded border border-border px-2 py-1 text-[11px] hover:bg-accent">
|
|
3212
|
-
|
|
3234
|
+
{t("panel.config.uploadPoster")}
|
|
3213
3235
|
<Input
|
|
3214
3236
|
type="file"
|
|
3215
3237
|
accept="image/*"
|
|
@@ -3231,35 +3253,38 @@ export function PanelConfigSidebar({
|
|
|
3231
3253
|
})
|
|
3232
3254
|
}
|
|
3233
3255
|
>
|
|
3234
|
-
|
|
3256
|
+
{t("panel.config.clearPoster")}
|
|
3235
3257
|
</button>
|
|
3236
3258
|
</div>
|
|
3237
3259
|
{selectedElement.audioPosterImage ? (
|
|
3238
3260
|
<img
|
|
3239
3261
|
src={selectedElement.audioPosterImage}
|
|
3240
|
-
alt="
|
|
3262
|
+
alt={t("panel.config.audioPosterAlt")}
|
|
3241
3263
|
className="h-20 w-full rounded border border-border/60 object-cover"
|
|
3242
3264
|
/>
|
|
3243
3265
|
) : null}
|
|
3244
|
-
<div className="
|
|
3245
|
-
|
|
3266
|
+
<div className="flex items-center gap-1">
|
|
3267
|
+
<div className="text-[11px] text-muted-foreground">{t("panel.config.audioPoster")}</div>
|
|
3268
|
+
<ConfigHintIcon label={t("panel.config.audioPoster")}>
|
|
3269
|
+
{t("panel.config.audioPosterHint")}
|
|
3270
|
+
</ConfigHintIcon>
|
|
3246
3271
|
</div>
|
|
3247
3272
|
</>
|
|
3248
3273
|
)}
|
|
3249
3274
|
</>,
|
|
3250
3275
|
true,
|
|
3251
|
-
["
|
|
3276
|
+
[t("panel.material.audio"), "url", t("panel.config.searchKwUpload"), t("panel.config.searchKwRecord"), "icon", t("panel.config.searchKwPoster"), t("panel.config.effect"), t("panel.config.searchKwAutoPause"), "media"]
|
|
3252
3277
|
)
|
|
3253
3278
|
) : selectedElement.materialType === "video" ? (
|
|
3254
3279
|
renderSection(
|
|
3255
3280
|
"videoConfig",
|
|
3256
|
-
"
|
|
3281
|
+
t("panel.config.sectionVideo"),
|
|
3257
3282
|
<>
|
|
3258
3283
|
{renderFieldGroup(
|
|
3259
|
-
"
|
|
3284
|
+
t("panel.config.groupVideoSource"),
|
|
3260
3285
|
<>
|
|
3261
3286
|
<label className="block space-y-1">
|
|
3262
|
-
<div
|
|
3287
|
+
<div>{t("panel.config.videoUrl")}</div>
|
|
3263
3288
|
<Input
|
|
3264
3289
|
value={selectedElement.videoRemoteUrl ?? ""}
|
|
3265
3290
|
onChange={(e) =>
|
|
@@ -3274,7 +3299,7 @@ export function PanelConfigSidebar({
|
|
|
3274
3299
|
</label>
|
|
3275
3300
|
<div className="flex items-center gap-2">
|
|
3276
3301
|
<label className="inline-flex cursor-pointer items-center rounded border border-border px-2 py-1 text-[11px] hover:bg-accent">
|
|
3277
|
-
|
|
3302
|
+
{t("panel.config.uploadVideo")}
|
|
3278
3303
|
<Input
|
|
3279
3304
|
type="file"
|
|
3280
3305
|
accept="video/*"
|
|
@@ -3308,26 +3333,26 @@ export function PanelConfigSidebar({
|
|
|
3308
3333
|
})
|
|
3309
3334
|
}
|
|
3310
3335
|
/>
|
|
3311
|
-
<span
|
|
3336
|
+
<span>{t("panel.config.autoPauseMedia")}</span>
|
|
3312
3337
|
</label>
|
|
3313
3338
|
</>
|
|
3314
3339
|
)}
|
|
3315
3340
|
</>,
|
|
3316
3341
|
true,
|
|
3317
|
-
["
|
|
3342
|
+
[t("panel.material.video"), "url", t("panel.config.searchKwUpload"), t("panel.config.searchKwPreview"), t("panel.config.searchKwAutoPause"), "media"]
|
|
3318
3343
|
)
|
|
3319
3344
|
) : null}
|
|
3320
3345
|
{selectedElement
|
|
3321
3346
|
? selectedElement.parentGridId
|
|
3322
3347
|
? renderSection(
|
|
3323
3348
|
"gridChildSpan",
|
|
3324
|
-
"
|
|
3349
|
+
t("panel.config.sectionGridChildSpan"),
|
|
3325
3350
|
<>
|
|
3326
3351
|
{renderFieldGroup(
|
|
3327
|
-
"
|
|
3352
|
+
t("panel.config.groupCrossSlots"),
|
|
3328
3353
|
<div className="grid grid-cols-2 gap-2">
|
|
3329
3354
|
<label className="block space-y-1">
|
|
3330
|
-
<div
|
|
3355
|
+
<div>{t("panel.config.colSpan")}</div>
|
|
3331
3356
|
<Input
|
|
3332
3357
|
type="number"
|
|
3333
3358
|
min={1}
|
|
@@ -3342,7 +3367,7 @@ export function PanelConfigSidebar({
|
|
|
3342
3367
|
/>
|
|
3343
3368
|
</label>
|
|
3344
3369
|
<label className="block space-y-1">
|
|
3345
|
-
<div
|
|
3370
|
+
<div>{t("panel.config.rowSpan")}</div>
|
|
3346
3371
|
<Input
|
|
3347
3372
|
type="number"
|
|
3348
3373
|
min={1}
|
|
@@ -3358,25 +3383,23 @@ export function PanelConfigSidebar({
|
|
|
3358
3383
|
</label>
|
|
3359
3384
|
</div>
|
|
3360
3385
|
)}
|
|
3361
|
-
<div className="rounded border border-border/60 bg-background px-2 py-1.5 text-[11px] text-muted-foreground">
|
|
3362
|
-
网格子节点可跨越多格,占据更大区域,便于复杂布局。
|
|
3363
|
-
</div>
|
|
3364
3386
|
</>,
|
|
3365
3387
|
true,
|
|
3366
|
-
["
|
|
3388
|
+
[t("panel.config.searchKwGrid"), t("panel.config.searchKwCrossCol"), t("panel.config.searchKwCrossRow"), "span", "slot"],
|
|
3389
|
+
<>{t("panel.config.gridChildHint")}</>
|
|
3367
3390
|
)
|
|
3368
3391
|
: null
|
|
3369
3392
|
: null}
|
|
3370
3393
|
{selectedElement.materialType === "geometry" ? (
|
|
3371
3394
|
renderSection(
|
|
3372
3395
|
"geometryConfig",
|
|
3373
|
-
"
|
|
3396
|
+
t("panel.config.sectionGeometry"),
|
|
3374
3397
|
<>
|
|
3375
3398
|
{renderFieldGroup(
|
|
3376
|
-
"
|
|
3399
|
+
t("panel.config.groupBasicShape"),
|
|
3377
3400
|
<>
|
|
3378
3401
|
<label className="block space-y-1">
|
|
3379
|
-
<div
|
|
3402
|
+
<div>{t("panel.config.shape")}</div>
|
|
3380
3403
|
<Select
|
|
3381
3404
|
value={selectedElement.geometryShape ?? "rect"}
|
|
3382
3405
|
onValueChange={(value) =>
|
|
@@ -3386,47 +3409,47 @@ export function PanelConfigSidebar({
|
|
|
3386
3409
|
}
|
|
3387
3410
|
>
|
|
3388
3411
|
<SelectTrigger className="h-7">
|
|
3389
|
-
<SelectValue placeholder="
|
|
3412
|
+
<SelectValue placeholder={t("panel.config.selectShape")} />
|
|
3390
3413
|
</SelectTrigger>
|
|
3391
3414
|
<SelectContent>
|
|
3392
|
-
<SelectItem value="rect"
|
|
3393
|
-
<SelectItem value="circle"
|
|
3394
|
-
<SelectItem value="triangle"
|
|
3395
|
-
<SelectItem value="diamond"
|
|
3396
|
-
<SelectItem value="hexagon"
|
|
3397
|
-
<SelectItem value="star"
|
|
3398
|
-
<SelectItem value="heart"
|
|
3415
|
+
<SelectItem value="rect">{t("panel.config.shapeRect")}</SelectItem>
|
|
3416
|
+
<SelectItem value="circle">{t("panel.config.shapeCircle")}</SelectItem>
|
|
3417
|
+
<SelectItem value="triangle">{t("panel.config.shapeTriangle")}</SelectItem>
|
|
3418
|
+
<SelectItem value="diamond">{t("panel.config.shapeDiamond")}</SelectItem>
|
|
3419
|
+
<SelectItem value="hexagon">{t("panel.config.shapeHexagon")}</SelectItem>
|
|
3420
|
+
<SelectItem value="star">{t("panel.config.shapeStar")}</SelectItem>
|
|
3421
|
+
<SelectItem value="heart">{t("panel.config.shapeHeart")}</SelectItem>
|
|
3399
3422
|
</SelectContent>
|
|
3400
3423
|
</Select>
|
|
3401
3424
|
</label>
|
|
3402
3425
|
{renderColorField(
|
|
3403
|
-
"
|
|
3426
|
+
t("panel.config.geometryColor"),
|
|
3404
3427
|
selectedElement.geometryColor ?? "#3b82f6",
|
|
3405
3428
|
(next) => updateSelectedGeometry({ geometryColor: next || "#3b82f6" })
|
|
3406
3429
|
)}
|
|
3407
3430
|
</>
|
|
3408
3431
|
)}
|
|
3409
3432
|
{renderFieldGroup(
|
|
3410
|
-
"
|
|
3433
|
+
t("panel.config.groupCanvasScript"),
|
|
3411
3434
|
<>
|
|
3412
|
-
<div className="rounded border border-border/60 bg-background px-2 py-1.5 text-[11px] text-muted-foreground">
|
|
3413
|
-
可输入 Canvas 绘制逻辑,变量:ctx、width、height、element。脚本异常会被安全忽略。
|
|
3414
|
-
</div>
|
|
3415
3435
|
<Textarea
|
|
3416
3436
|
value={selectedElement.geometryScript ?? ""}
|
|
3417
3437
|
onChange={(e) => updateSelectedGeometry({ geometryScript: e.target.value || undefined })}
|
|
3418
3438
|
spellCheck={false}
|
|
3419
3439
|
className="h-36 font-mono text-[11px]"
|
|
3420
|
-
placeholder="
|
|
3440
|
+
placeholder={t("panel.config.geometryScriptPlaceholder")}
|
|
3421
3441
|
/>
|
|
3442
|
+
</>,
|
|
3443
|
+
<>
|
|
3444
|
+
{t("panel.config.canvasScriptHint")}
|
|
3422
3445
|
</>
|
|
3423
3446
|
)}
|
|
3424
3447
|
{renderFieldGroup(
|
|
3425
|
-
"
|
|
3448
|
+
t("panel.config.groupSketchOverlay"),
|
|
3426
3449
|
<>
|
|
3427
3450
|
<div className="flex items-center gap-2">
|
|
3428
3451
|
<label className="block space-y-1">
|
|
3429
|
-
<div className="text-[11px]"
|
|
3452
|
+
<div className="text-[11px]">{t("panel.config.penColor")}</div>
|
|
3430
3453
|
<Input
|
|
3431
3454
|
type="color"
|
|
3432
3455
|
value={geometryDrawPenColor}
|
|
@@ -3435,7 +3458,7 @@ export function PanelConfigSidebar({
|
|
|
3435
3458
|
/>
|
|
3436
3459
|
</label>
|
|
3437
3460
|
<label className="block space-y-1">
|
|
3438
|
-
<div className="text-[11px]"
|
|
3461
|
+
<div className="text-[11px]">{t("panel.config.penWidth")}</div>
|
|
3439
3462
|
<Input
|
|
3440
3463
|
type="number"
|
|
3441
3464
|
min={1}
|
|
@@ -3503,7 +3526,7 @@ export function PanelConfigSidebar({
|
|
|
3503
3526
|
updateSelectedGeometry({ geometrySketchDataUrl: canvas.toDataURL("image/png") });
|
|
3504
3527
|
}}
|
|
3505
3528
|
>
|
|
3506
|
-
|
|
3529
|
+
{t("panel.config.applySketch")}
|
|
3507
3530
|
</button>
|
|
3508
3531
|
<button
|
|
3509
3532
|
type="button"
|
|
@@ -3513,25 +3536,25 @@ export function PanelConfigSidebar({
|
|
|
3513
3536
|
redrawGeometryPadFromElement();
|
|
3514
3537
|
}}
|
|
3515
3538
|
>
|
|
3516
|
-
|
|
3539
|
+
{t("panel.config.clearSketch")}
|
|
3517
3540
|
</button>
|
|
3518
3541
|
</div>
|
|
3519
3542
|
</>
|
|
3520
3543
|
)}
|
|
3521
3544
|
</>,
|
|
3522
3545
|
true,
|
|
3523
|
-
["
|
|
3546
|
+
[t("panel.material.geometry"), "geometry", t("panel.config.shape"), "canvas", t("panel.config.searchKwScript"), t("panel.config.searchKwSketch")]
|
|
3524
3547
|
)
|
|
3525
3548
|
) : selectedElement.materialType === "grid" ? (
|
|
3526
3549
|
renderSection(
|
|
3527
3550
|
"gridConfig",
|
|
3528
|
-
"
|
|
3551
|
+
t("panel.config.sectionGrid"),
|
|
3529
3552
|
<>
|
|
3530
3553
|
{renderFieldGroup(
|
|
3531
|
-
"
|
|
3554
|
+
t("panel.config.groupGridParams"),
|
|
3532
3555
|
<div className="grid grid-cols-2 gap-2">
|
|
3533
3556
|
<label className="block space-y-1">
|
|
3534
|
-
<div
|
|
3557
|
+
<div>{t("panel.config.rowCount")}</div>
|
|
3535
3558
|
<Input
|
|
3536
3559
|
type="number"
|
|
3537
3560
|
min={1}
|
|
@@ -3546,7 +3569,7 @@ export function PanelConfigSidebar({
|
|
|
3546
3569
|
/>
|
|
3547
3570
|
</label>
|
|
3548
3571
|
<label className="block space-y-1">
|
|
3549
|
-
<div
|
|
3572
|
+
<div>{t("panel.config.colCount")}</div>
|
|
3550
3573
|
<Input
|
|
3551
3574
|
type="number"
|
|
3552
3575
|
min={1}
|
|
@@ -3561,7 +3584,7 @@ export function PanelConfigSidebar({
|
|
|
3561
3584
|
/>
|
|
3562
3585
|
</label>
|
|
3563
3586
|
<label className="block space-y-1">
|
|
3564
|
-
<div
|
|
3587
|
+
<div>{t("panel.config.gapPx")}</div>
|
|
3565
3588
|
<Input
|
|
3566
3589
|
type="number"
|
|
3567
3590
|
min={0}
|
|
@@ -3576,7 +3599,7 @@ export function PanelConfigSidebar({
|
|
|
3576
3599
|
/>
|
|
3577
3600
|
</label>
|
|
3578
3601
|
<label className="block space-y-1">
|
|
3579
|
-
<div
|
|
3602
|
+
<div>{t("panel.config.paddingPx")}</div>
|
|
3580
3603
|
<Input
|
|
3581
3604
|
type="number"
|
|
3582
3605
|
min={0}
|
|
@@ -3591,7 +3614,7 @@ export function PanelConfigSidebar({
|
|
|
3591
3614
|
/>
|
|
3592
3615
|
</label>
|
|
3593
3616
|
<label className="block space-y-1">
|
|
3594
|
-
<div
|
|
3617
|
+
<div>{t("panel.config.snapThresholdPx")}</div>
|
|
3595
3618
|
<Input
|
|
3596
3619
|
type="number"
|
|
3597
3620
|
min={8}
|
|
@@ -3610,22 +3633,22 @@ export function PanelConfigSidebar({
|
|
|
3610
3633
|
</label>
|
|
3611
3634
|
</div>
|
|
3612
3635
|
)}
|
|
3613
|
-
<div className="rounded border border-border/60 bg-background px-2 py-1.5 text-[11px] text-muted-foreground">
|
|
3614
|
-
其他节点拖拽靠近该网格槽位中心时会自动吸附,并在节点树显示为该网格子节点。
|
|
3615
|
-
</div>
|
|
3616
3636
|
</>,
|
|
3617
3637
|
true,
|
|
3618
|
-
["
|
|
3638
|
+
[t("panel.config.searchKwGrid"), "grid", t("panel.config.rows"), t("panel.config.cols"), t("panel.config.searchKwGap"), t("panel.config.searchKwPadding"), t("panel.config.searchKwSnap"), t("panel.config.searchKwThreshold")],
|
|
3639
|
+
<>
|
|
3640
|
+
{t("panel.config.gridHint")}
|
|
3641
|
+
</>
|
|
3619
3642
|
)
|
|
3620
3643
|
) : selectedElement.materialType === "reference" ? (
|
|
3621
3644
|
renderSection(
|
|
3622
3645
|
"reference",
|
|
3623
|
-
"
|
|
3646
|
+
t("panel.config.sectionReference"),
|
|
3624
3647
|
<>
|
|
3625
3648
|
{renderFieldGroup(
|
|
3626
|
-
"
|
|
3649
|
+
t("panel.config.groupRefSource"),
|
|
3627
3650
|
<label className="block space-y-1">
|
|
3628
|
-
<div
|
|
3651
|
+
<div>{t("panel.config.refLayer")}</div>
|
|
3629
3652
|
<Select
|
|
3630
3653
|
value={selectedElement.refLayerId ?? "__none__"}
|
|
3631
3654
|
onValueChange={(value) =>
|
|
@@ -3635,10 +3658,10 @@ export function PanelConfigSidebar({
|
|
|
3635
3658
|
}
|
|
3636
3659
|
>
|
|
3637
3660
|
<SelectTrigger className="h-7">
|
|
3638
|
-
<SelectValue placeholder="
|
|
3661
|
+
<SelectValue placeholder={t("panel.config.pleaseSelectLayer")} />
|
|
3639
3662
|
</SelectTrigger>
|
|
3640
3663
|
<SelectContent>
|
|
3641
|
-
<SelectItem value="__none__"
|
|
3664
|
+
<SelectItem value="__none__">{t("panel.config.noneNoRef")}</SelectItem>
|
|
3642
3665
|
{layers
|
|
3643
3666
|
.filter((l) => l.id !== selectedElement.layerId)
|
|
3644
3667
|
.map((l) => (
|
|
@@ -3651,10 +3674,10 @@ export function PanelConfigSidebar({
|
|
|
3651
3674
|
</label>
|
|
3652
3675
|
)}
|
|
3653
3676
|
{renderFieldGroup(
|
|
3654
|
-
"
|
|
3677
|
+
t("panel.config.groupCopyStrategy"),
|
|
3655
3678
|
<>
|
|
3656
3679
|
<label className="block space-y-1">
|
|
3657
|
-
<div
|
|
3680
|
+
<div>{t("panel.config.copyMode")}</div>
|
|
3658
3681
|
<Select
|
|
3659
3682
|
value={selectedElement.refCopyMode ?? "shallow"}
|
|
3660
3683
|
onValueChange={(value) =>
|
|
@@ -3665,31 +3688,31 @@ export function PanelConfigSidebar({
|
|
|
3665
3688
|
}
|
|
3666
3689
|
>
|
|
3667
3690
|
<SelectTrigger className="h-7">
|
|
3668
|
-
<SelectValue placeholder="
|
|
3691
|
+
<SelectValue placeholder={t("panel.config.selectCopyMode")} />
|
|
3669
3692
|
</SelectTrigger>
|
|
3670
3693
|
<SelectContent>
|
|
3671
|
-
<SelectItem value="shallow"
|
|
3672
|
-
<SelectItem value="deep"
|
|
3694
|
+
<SelectItem value="shallow">{t("panel.config.shallowFollow")}</SelectItem>
|
|
3695
|
+
<SelectItem value="deep">{t("panel.config.deepFreeze")}</SelectItem>
|
|
3673
3696
|
</SelectContent>
|
|
3674
3697
|
</Select>
|
|
3675
3698
|
</label>
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3699
|
+
</>,
|
|
3700
|
+
<>
|
|
3701
|
+
{t("panel.config.copyStrategyHint")}
|
|
3679
3702
|
</>
|
|
3680
3703
|
)}
|
|
3681
3704
|
</>,
|
|
3682
3705
|
true,
|
|
3683
|
-
["
|
|
3706
|
+
[t("panel.config.searchKwRef"), "ref", t("panel.config.layer"), t("panel.material.shallowCopy"), t("panel.material.deepCopy"), "snapshot"]
|
|
3684
3707
|
)
|
|
3685
3708
|
) : (
|
|
3686
3709
|
<div className="text-xs leading-6 text-muted-foreground">
|
|
3687
|
-
|
|
3710
|
+
{t("panel.config.notChartType")}
|
|
3688
3711
|
</div>
|
|
3689
3712
|
)}
|
|
3690
3713
|
{hasSearch && renderedSectionCount === 0 ? (
|
|
3691
3714
|
<div className="rounded border border-border/60 bg-background px-2 py-1.5 text-[11px] text-muted-foreground">
|
|
3692
|
-
|
|
3715
|
+
{t("panel.config.noMatch")}
|
|
3693
3716
|
</div>
|
|
3694
3717
|
) : null}
|
|
3695
3718
|
</div>
|