@arronqzy/react-view 1.0.11 → 1.0.13
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 +4 -4
- package/package.json +6 -6
- package/src/panel/ReactViewOnlinePreview.tsx +41 -18
- package/src/panel/ReactViewPanel.tsx +52 -2
- package/src/panel/ai/AssistantChatPanel.tsx +15 -41
- package/src/panel/components/PanelConfigSidebar.tsx +442 -352
- package/src/panel/components/WorkspaceConfigSidebar.tsx +8 -0
- package/src/panel/utils/chartOptionBuilder.ts +48 -3
- package/src/panel/utils/outputScale.ts +69 -0
- package/src/panel/utils/panelElementDefaults.ts +0 -1
|
@@ -104,8 +104,8 @@ export function PanelConfigSidebar({
|
|
|
104
104
|
"scrollbar-thin [&::-webkit-scrollbar]:h-2 [&::-webkit-scrollbar]:w-2 [&::-webkit-scrollbar-track]:bg-muted/40 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-border/80 [&::-webkit-scrollbar-thumb]:hover:bg-border";
|
|
105
105
|
const [expandedSections, setExpandedSections] = useState<Record<string, boolean>>({
|
|
106
106
|
nodeInfo: true,
|
|
107
|
-
styleBackground:
|
|
108
|
-
styleBorder:
|
|
107
|
+
styleBackground: false,
|
|
108
|
+
styleBorder: false,
|
|
109
109
|
chartBasic: true,
|
|
110
110
|
chartAdvanced: false,
|
|
111
111
|
chartAdvancedHighFreq: true,
|
|
@@ -421,9 +421,21 @@ export function PanelConfigSidebar({
|
|
|
421
421
|
|
|
422
422
|
useEffect(() => {
|
|
423
423
|
return subscribeRevealPanelConfig((detail) => {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
424
|
+
setExpandedSections((prev) => {
|
|
425
|
+
const next = { ...prev };
|
|
426
|
+
for (const section of detail.sections) next[section] = true;
|
|
427
|
+
next.nodeMore = true;
|
|
428
|
+
next.styleBgLayout = true;
|
|
429
|
+
next.chartDisplayMore = true;
|
|
430
|
+
next.chartTooltip = true;
|
|
431
|
+
next.chartAxes = true;
|
|
432
|
+
next.textInputAbility = true;
|
|
433
|
+
next.audioDisplayStyle = true;
|
|
434
|
+
next.geometryCanvasScript = true;
|
|
435
|
+
next.geometrySketch = true;
|
|
436
|
+
next.referenceCopyStrategy = true;
|
|
437
|
+
return next;
|
|
438
|
+
});
|
|
427
439
|
window.requestAnimationFrame(() => {
|
|
428
440
|
const field = detail.fields[0];
|
|
429
441
|
if (field) highlightConfigField(field);
|
|
@@ -475,16 +487,48 @@ export function PanelConfigSidebar({
|
|
|
475
487
|
const renderFieldGroup = (
|
|
476
488
|
title: string,
|
|
477
489
|
children: React.ReactNode,
|
|
478
|
-
hint?: React.ReactNode
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
490
|
+
hint?: React.ReactNode,
|
|
491
|
+
options?: { groupKey?: string; defaultOpen?: boolean }
|
|
492
|
+
) => {
|
|
493
|
+
const groupKey = options?.groupKey;
|
|
494
|
+
const defaultOpen = options?.defaultOpen ?? true;
|
|
495
|
+
const header = (
|
|
496
|
+
<>
|
|
482
497
|
<div className="text-[11px] font-semibold text-muted-foreground">{title}</div>
|
|
483
498
|
{hint ? <ConfigHintIcon label={title}>{hint}</ConfigHintIcon> : null}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
499
|
+
</>
|
|
500
|
+
);
|
|
501
|
+
if (!groupKey) {
|
|
502
|
+
return (
|
|
503
|
+
<div className="space-y-2.5 rounded-lg border border-border/55 bg-background/80 p-2.5">
|
|
504
|
+
<div className="flex items-center gap-1">{header}</div>
|
|
505
|
+
{children}
|
|
506
|
+
</div>
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
const open = hasSearch ? true : isSectionExpanded(groupKey, defaultOpen);
|
|
510
|
+
return (
|
|
511
|
+
<Collapsible
|
|
512
|
+
open={open}
|
|
513
|
+
onOpenChange={(next) => setSectionExpanded(groupKey, next)}
|
|
514
|
+
className="space-y-2.5 rounded-lg border border-border/55 bg-background/80 p-2.5"
|
|
515
|
+
>
|
|
516
|
+
<div className="flex items-center gap-1.5">
|
|
517
|
+
<CollapsibleTrigger asChild>
|
|
518
|
+
<button
|
|
519
|
+
type="button"
|
|
520
|
+
className="flex h-5 w-5 items-center justify-center rounded text-[11px] hover:bg-accent"
|
|
521
|
+
aria-label={open ? t("panel.config.collapseGroup", { title }) : t("panel.config.expandGroup", { title })}
|
|
522
|
+
>
|
|
523
|
+
{open ? "▾" : "▸"}
|
|
524
|
+
</button>
|
|
525
|
+
</CollapsibleTrigger>
|
|
526
|
+
{header}
|
|
527
|
+
</div>
|
|
528
|
+
<CollapsibleContent className="space-y-2.5">{children}</CollapsibleContent>
|
|
529
|
+
</Collapsible>
|
|
530
|
+
);
|
|
531
|
+
};
|
|
488
532
|
const isNodeCardExpanded = useCallback(
|
|
489
533
|
(id: string) => expandedNodeCards[id] ?? true,
|
|
490
534
|
[expandedNodeCards]
|
|
@@ -1369,15 +1413,19 @@ export function PanelConfigSidebar({
|
|
|
1369
1413
|
className="h-7"
|
|
1370
1414
|
type="number"
|
|
1371
1415
|
min={1}
|
|
1372
|
-
|
|
1373
|
-
|
|
1416
|
+
placeholder={t("panel.config.barWidthAuto")}
|
|
1417
|
+
value={el.chart?.barWidth ?? ""}
|
|
1418
|
+
onChange={(e) => {
|
|
1419
|
+
const raw = e.target.value.trim();
|
|
1374
1420
|
updateElement(el.id, {
|
|
1375
1421
|
chart: {
|
|
1376
1422
|
...(el.chart ?? {}),
|
|
1377
|
-
barWidth:
|
|
1423
|
+
barWidth: raw
|
|
1424
|
+
? Math.max(1, Number(raw) || 1)
|
|
1425
|
+
: undefined,
|
|
1378
1426
|
},
|
|
1379
|
-
})
|
|
1380
|
-
}
|
|
1427
|
+
});
|
|
1428
|
+
}}
|
|
1381
1429
|
/>
|
|
1382
1430
|
</label>
|
|
1383
1431
|
) : null}
|
|
@@ -1879,21 +1927,6 @@ export function PanelConfigSidebar({
|
|
|
1879
1927
|
{readonlyReason}
|
|
1880
1928
|
</div>
|
|
1881
1929
|
) : null}
|
|
1882
|
-
<div className="rounded-lg border border-border/60 bg-card/80 px-2.5 py-2 text-xs">
|
|
1883
|
-
<label className="flex items-center gap-2">
|
|
1884
|
-
<Checkbox
|
|
1885
|
-
checked={selectedElement.locked === true}
|
|
1886
|
-
disabled={!canToggleNodeLock}
|
|
1887
|
-
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"
|
|
1888
|
-
onCheckedChange={(checked) =>
|
|
1889
|
-
updateElement(selectedElement.id, {
|
|
1890
|
-
locked: checked === true,
|
|
1891
|
-
})
|
|
1892
|
-
}
|
|
1893
|
-
/>
|
|
1894
|
-
<span>{t("panel.config.lockNode")}</span>
|
|
1895
|
-
</label>
|
|
1896
|
-
</div>
|
|
1897
1930
|
<fieldset disabled={!isNodeEditable} className={!isNodeEditable ? "opacity-60" : ""}>
|
|
1898
1931
|
<div className="space-y-3.5 text-xs">
|
|
1899
1932
|
{renderSection(
|
|
@@ -1913,7 +1946,7 @@ export function PanelConfigSidebar({
|
|
|
1913
1946
|
className="h-7"
|
|
1914
1947
|
/>
|
|
1915
1948
|
</label>
|
|
1916
|
-
<div className="grid grid-cols-
|
|
1949
|
+
<div className="grid grid-cols-2 gap-2">
|
|
1917
1950
|
<label className="block space-y-1" data-config-field="x">
|
|
1918
1951
|
<div>X</div>
|
|
1919
1952
|
<Input
|
|
@@ -1941,20 +1974,7 @@ export function PanelConfigSidebar({
|
|
|
1941
1974
|
/>
|
|
1942
1975
|
</label>
|
|
1943
1976
|
</div>
|
|
1944
|
-
<div className="grid grid-cols-
|
|
1945
|
-
<label className="block space-y-1" data-config-field="rotate">
|
|
1946
|
-
<div>{t("panel.config.rotate")}</div>
|
|
1947
|
-
<Input
|
|
1948
|
-
type="number"
|
|
1949
|
-
value={selectedElement.rotate ?? 0}
|
|
1950
|
-
onChange={(e) =>
|
|
1951
|
-
updateElement(selectedElement.id, {
|
|
1952
|
-
rotate: Number(e.target.value) || 0,
|
|
1953
|
-
})
|
|
1954
|
-
}
|
|
1955
|
-
className="h-7"
|
|
1956
|
-
/>
|
|
1957
|
-
</label>
|
|
1977
|
+
<div className="grid grid-cols-2 gap-2">
|
|
1958
1978
|
<label className="block space-y-1" data-config-field="width">
|
|
1959
1979
|
<div>{t("panel.config.width")}</div>
|
|
1960
1980
|
<Input
|
|
@@ -1985,6 +2005,24 @@ export function PanelConfigSidebar({
|
|
|
1985
2005
|
/>
|
|
1986
2006
|
</label>
|
|
1987
2007
|
</div>
|
|
2008
|
+
{renderFieldGroup(
|
|
2009
|
+
t("panel.config.groupNodeMore"),
|
|
2010
|
+
<>
|
|
2011
|
+
<div className="grid grid-cols-2 gap-2">
|
|
2012
|
+
<label className="block space-y-1" data-config-field="rotate">
|
|
2013
|
+
<div>{t("panel.config.rotate")}</div>
|
|
2014
|
+
<Input
|
|
2015
|
+
type="number"
|
|
2016
|
+
value={selectedElement.rotate ?? 0}
|
|
2017
|
+
onChange={(e) =>
|
|
2018
|
+
updateElement(selectedElement.id, {
|
|
2019
|
+
rotate: Number(e.target.value) || 0,
|
|
2020
|
+
})
|
|
2021
|
+
}
|
|
2022
|
+
className="h-7"
|
|
2023
|
+
/>
|
|
2024
|
+
</label>
|
|
2025
|
+
</div>
|
|
1988
2026
|
<div className="space-y-1.5">
|
|
1989
2027
|
<div className="text-[11px] text-muted-foreground">{t("panel.config.nodeZOrder")}</div>
|
|
1990
2028
|
<div className="text-[11px] text-muted-foreground/90">
|
|
@@ -2023,205 +2061,177 @@ export function PanelConfigSidebar({
|
|
|
2023
2061
|
</div>
|
|
2024
2062
|
<div className="truncate text-muted-foreground">ID: {selectedElement.id}</div>
|
|
2025
2063
|
<div className="text-muted-foreground">{t("panel.config.type")}: {selectedElement.materialType ?? selectedElement.id}</div>
|
|
2064
|
+
</>,
|
|
2065
|
+
undefined,
|
|
2066
|
+
{ groupKey: "nodeMore", defaultOpen: false }
|
|
2067
|
+
)}
|
|
2026
2068
|
</>,
|
|
2027
2069
|
true,
|
|
2028
|
-
[t("panel.config.name"), "id", t("panel.config.type"), t("panel.layers.lockShort"), "locked", "name"]
|
|
2070
|
+
[t("panel.config.name"), "id", t("panel.config.type"), t("panel.config.rotate"), t("panel.config.nodeZOrder"), t("panel.layers.lockShort"), "locked", "name"]
|
|
2029
2071
|
)}
|
|
2072
|
+
</div>
|
|
2073
|
+
</fieldset>
|
|
2074
|
+
<div className="rounded-lg border border-border/60 bg-card/80 px-2.5 py-2 text-xs">
|
|
2075
|
+
<label className="flex items-center gap-2">
|
|
2076
|
+
<Checkbox
|
|
2077
|
+
checked={selectedElement.locked === true}
|
|
2078
|
+
disabled={!canToggleNodeLock}
|
|
2079
|
+
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"
|
|
2080
|
+
onCheckedChange={(checked) =>
|
|
2081
|
+
updateElement(selectedElement.id, {
|
|
2082
|
+
locked: checked === true,
|
|
2083
|
+
})
|
|
2084
|
+
}
|
|
2085
|
+
/>
|
|
2086
|
+
<span>{t("panel.config.lockNode")}</span>
|
|
2087
|
+
</label>
|
|
2088
|
+
</div>
|
|
2089
|
+
<fieldset disabled={!isNodeEditable} className={!isNodeEditable ? "opacity-60" : ""}>
|
|
2090
|
+
<div className="space-y-3.5 text-xs">
|
|
2030
2091
|
|
|
2031
|
-
{
|
|
2032
|
-
"styleBackground",
|
|
2033
|
-
t("panel.config.sectionStyleBackground"),
|
|
2092
|
+
{isChartElement ? (
|
|
2034
2093
|
<>
|
|
2035
|
-
{
|
|
2036
|
-
|
|
2094
|
+
{renderSection(
|
|
2095
|
+
"chartBasic",
|
|
2096
|
+
t("panel.config.sectionChartBasic"),
|
|
2037
2097
|
<>
|
|
2038
|
-
{
|
|
2039
|
-
t("panel.config.
|
|
2040
|
-
|
|
2041
|
-
|
|
2098
|
+
{renderFieldGroup(
|
|
2099
|
+
t("panel.config.groupBasicDisplay"),
|
|
2100
|
+
<>
|
|
2101
|
+
<label className="block space-y-1.5" data-config-field="chart.title">
|
|
2102
|
+
<div>{t("panel.config.title")}</div>
|
|
2103
|
+
<Input
|
|
2104
|
+
value={selectedElement.chart?.title ?? ""}
|
|
2105
|
+
onChange={(e) => updateSelectedChart({ title: e.target.value })}
|
|
2106
|
+
className="h-7"
|
|
2107
|
+
/>
|
|
2108
|
+
</label>
|
|
2109
|
+
|
|
2110
|
+
{renderColorField(
|
|
2111
|
+
t("panel.config.primaryColor"),
|
|
2112
|
+
selectedElement.chart?.color ?? "#3b82f6",
|
|
2113
|
+
(next) => updateSelectedChart({ color: next || "#3b82f6" })
|
|
2114
|
+
)}
|
|
2115
|
+
</>
|
|
2042
2116
|
)}
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
className="hidden"
|
|
2059
|
-
onChange={async (e) => {
|
|
2060
|
-
const file = e.target.files?.[0];
|
|
2061
|
-
e.currentTarget.value = "";
|
|
2062
|
-
if (!file) return;
|
|
2063
|
-
await handleUploadBackgroundImage(file);
|
|
2064
|
-
}}
|
|
2065
|
-
/>
|
|
2066
|
-
</label>
|
|
2067
|
-
{uploadStatus ? (
|
|
2068
|
-
<span className="text-[11px] text-muted-foreground">{uploadStatus}</span>
|
|
2069
|
-
) : null}
|
|
2070
|
-
</div>
|
|
2071
|
-
</>
|
|
2072
|
-
)}
|
|
2073
|
-
{renderFieldGroup(
|
|
2074
|
-
t("panel.config.groupBgLayout"),
|
|
2075
|
-
<div className="grid grid-cols-2 gap-2">
|
|
2076
|
-
<label className="block space-y-1">
|
|
2077
|
-
<div>{t("panel.config.backgroundSize")}</div>
|
|
2078
|
-
<Select
|
|
2079
|
-
value={selectedElement.style?.backgroundSize ?? "__none__"}
|
|
2080
|
-
onValueChange={(value) =>
|
|
2081
|
-
updateSelectedStyle({
|
|
2082
|
-
backgroundSize: value === "__none__" ? undefined : value,
|
|
2083
|
-
})
|
|
2084
|
-
}
|
|
2085
|
-
>
|
|
2086
|
-
<SelectTrigger className="h-7">
|
|
2087
|
-
<SelectValue placeholder={t("panel.config.selectBackgroundSize")} />
|
|
2088
|
-
</SelectTrigger>
|
|
2089
|
-
<SelectContent>
|
|
2090
|
-
<SelectItem value="__none__">{t("common.default")}</SelectItem>
|
|
2091
|
-
<SelectItem value="cover">cover</SelectItem>
|
|
2092
|
-
<SelectItem value="contain">contain</SelectItem>
|
|
2093
|
-
<SelectItem value="100% 100%">100% 100%</SelectItem>
|
|
2094
|
-
<SelectItem value="auto">auto</SelectItem>
|
|
2095
|
-
</SelectContent>
|
|
2096
|
-
</Select>
|
|
2097
|
-
</label>
|
|
2098
|
-
<label className="block space-y-1">
|
|
2099
|
-
<div>{t("panel.config.backgroundPosition")}</div>
|
|
2100
|
-
<Select
|
|
2101
|
-
value={selectedElement.style?.backgroundPosition ?? "__none__"}
|
|
2102
|
-
onValueChange={(value) =>
|
|
2103
|
-
updateSelectedStyle({
|
|
2104
|
-
backgroundPosition: value === "__none__" ? undefined : value,
|
|
2105
|
-
})
|
|
2106
|
-
}
|
|
2107
|
-
>
|
|
2108
|
-
<SelectTrigger className="h-7">
|
|
2109
|
-
<SelectValue placeholder={t("panel.config.selectBackgroundPosition")} />
|
|
2110
|
-
</SelectTrigger>
|
|
2111
|
-
<SelectContent>
|
|
2112
|
-
<SelectItem value="__none__">{t("common.default")}</SelectItem>
|
|
2113
|
-
<SelectItem value="center">center</SelectItem>
|
|
2114
|
-
<SelectItem value="top">top</SelectItem>
|
|
2115
|
-
<SelectItem value="bottom">bottom</SelectItem>
|
|
2116
|
-
<SelectItem value="left">left</SelectItem>
|
|
2117
|
-
<SelectItem value="right">right</SelectItem>
|
|
2118
|
-
<SelectItem value="top left">top left</SelectItem>
|
|
2119
|
-
<SelectItem value="top right">top right</SelectItem>
|
|
2120
|
-
<SelectItem value="bottom left">bottom left</SelectItem>
|
|
2121
|
-
<SelectItem value="bottom right">bottom right</SelectItem>
|
|
2122
|
-
</SelectContent>
|
|
2123
|
-
</Select>
|
|
2124
|
-
</label>
|
|
2125
|
-
</div>
|
|
2126
|
-
)}
|
|
2127
|
-
</>,
|
|
2128
|
-
true,
|
|
2129
|
-
[t("panel.config.backgroundColor"), t("panel.config.backgroundImage"), "background", "backgroundSize", "backgroundPosition", t("panel.config.searchKwLayout")]
|
|
2130
|
-
)}
|
|
2117
|
+
{renderFieldGroup(
|
|
2118
|
+
t("panel.config.groupData"),
|
|
2119
|
+
<>
|
|
2120
|
+
<label className="block space-y-1">
|
|
2121
|
+
<div>{t("panel.config.labelsCsv")}</div>
|
|
2122
|
+
<Input
|
|
2123
|
+
value={getChartLabelsDisplayText(selectedElement.chart)}
|
|
2124
|
+
onChange={(e) =>
|
|
2125
|
+
updateSelectedChart({
|
|
2126
|
+
labelsText: e.target.value,
|
|
2127
|
+
})
|
|
2128
|
+
}
|
|
2129
|
+
className="h-7"
|
|
2130
|
+
/>
|
|
2131
|
+
</label>
|
|
2131
2132
|
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
t("panel.config.sectionStyleBorder"),
|
|
2135
|
-
<>
|
|
2136
|
-
{renderFieldGroup(
|
|
2137
|
-
t("panel.config.groupBorderGeometry"),
|
|
2138
|
-
<div className="grid grid-cols-2 gap-2">
|
|
2139
|
-
<label className="block space-y-1">
|
|
2140
|
-
<div>{t("panel.config.borderWidth")}</div>
|
|
2141
|
-
<Input
|
|
2142
|
-
type="number"
|
|
2143
|
-
min={0}
|
|
2144
|
-
value={selectedElement.style?.borderWidth ?? 0}
|
|
2145
|
-
onChange={(e) =>
|
|
2146
|
-
updateSelectedStyle({ borderWidth: Math.max(0, Number(e.target.value) || 0) })
|
|
2147
|
-
}
|
|
2148
|
-
className="h-7"
|
|
2149
|
-
/>
|
|
2150
|
-
</label>
|
|
2151
|
-
<label className="block space-y-1">
|
|
2152
|
-
<div>{t("panel.config.borderRadius")}</div>
|
|
2153
|
-
<Input
|
|
2154
|
-
type="number"
|
|
2155
|
-
min={0}
|
|
2156
|
-
value={selectedElement.style?.borderRadius ?? 0}
|
|
2157
|
-
onChange={(e) =>
|
|
2158
|
-
updateSelectedStyle({ borderRadius: Math.max(0, Number(e.target.value) || 0) })
|
|
2159
|
-
}
|
|
2160
|
-
className="h-7"
|
|
2161
|
-
/>
|
|
2162
|
-
</label>
|
|
2163
|
-
</div>
|
|
2164
|
-
)}
|
|
2165
|
-
{renderFieldGroup(
|
|
2166
|
-
t("panel.config.groupBorderVisual"),
|
|
2167
|
-
<div className="grid grid-cols-2 gap-2">
|
|
2168
|
-
<label className="block space-y-1">
|
|
2169
|
-
<div>{t("panel.config.borderStyle")}</div>
|
|
2170
|
-
<Select
|
|
2171
|
-
value={selectedElement.style?.borderStyle ?? "solid"}
|
|
2172
|
-
onValueChange={(value) =>
|
|
2173
|
-
updateSelectedStyle({
|
|
2174
|
-
borderStyle: value as NonNullable<PanelElementStyle["borderStyle"]>,
|
|
2175
|
-
})
|
|
2176
|
-
}
|
|
2177
|
-
>
|
|
2178
|
-
<SelectTrigger className="h-7">
|
|
2179
|
-
<SelectValue placeholder={t("panel.config.selectBorderStyle")} />
|
|
2180
|
-
</SelectTrigger>
|
|
2181
|
-
<SelectContent>
|
|
2182
|
-
<SelectItem value="none">none</SelectItem>
|
|
2183
|
-
<SelectItem value="solid">solid</SelectItem>
|
|
2184
|
-
<SelectItem value="dashed">dashed</SelectItem>
|
|
2185
|
-
<SelectItem value="dotted">dotted</SelectItem>
|
|
2186
|
-
<SelectItem value="double">double</SelectItem>
|
|
2187
|
-
</SelectContent>
|
|
2188
|
-
</Select>
|
|
2189
|
-
</label>
|
|
2190
|
-
{renderColorField(
|
|
2191
|
-
t("panel.config.borderColor"),
|
|
2192
|
-
selectedElement.style?.borderColor ?? "",
|
|
2193
|
-
(next) => updateSelectedStyle({ borderColor: next || undefined })
|
|
2194
|
-
)}
|
|
2195
|
-
</div>
|
|
2196
|
-
)}
|
|
2197
|
-
</>,
|
|
2198
|
-
true,
|
|
2199
|
-
[t("panel.config.searchKwBorder"), "border", t("panel.config.searchKwWidth"), t("panel.config.searchKwRadius"), t("panel.config.color"), t("panel.config.searchKwStyle")]
|
|
2200
|
-
)}
|
|
2201
|
-
|
|
2202
|
-
{isChartElement ? (
|
|
2203
|
-
<>
|
|
2204
|
-
{renderSection(
|
|
2205
|
-
"chartBasic",
|
|
2206
|
-
t("panel.config.sectionChartBasic"),
|
|
2207
|
-
<>
|
|
2208
|
-
{renderFieldGroup(
|
|
2209
|
-
t("panel.config.groupBasicDisplay"),
|
|
2210
|
-
<>
|
|
2211
|
-
<label className="block space-y-1.5" data-config-field="chart.title">
|
|
2212
|
-
<div>{t("panel.config.title")}</div>
|
|
2133
|
+
<label className="block space-y-1">
|
|
2134
|
+
<div>{t("panel.config.valuesCsv")}</div>
|
|
2213
2135
|
<Input
|
|
2214
|
-
value={selectedElement.chart
|
|
2215
|
-
onChange={(e) =>
|
|
2136
|
+
value={getChartValuesDisplayText(selectedElement.chart)}
|
|
2137
|
+
onChange={(e) =>
|
|
2138
|
+
updateSelectedChart({
|
|
2139
|
+
valuesText: e.target.value,
|
|
2140
|
+
})
|
|
2141
|
+
}
|
|
2216
2142
|
className="h-7"
|
|
2217
2143
|
/>
|
|
2218
2144
|
</label>
|
|
2145
|
+
</>
|
|
2146
|
+
)}
|
|
2219
2147
|
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2148
|
+
{selectedChartType === "bar" ||
|
|
2149
|
+
selectedChartType === "line" ||
|
|
2150
|
+
selectedChartType === "area" ||
|
|
2151
|
+
selectedChartType === "pie" ? (
|
|
2152
|
+
renderFieldGroup(
|
|
2153
|
+
t("panel.config.groupSeries"),
|
|
2154
|
+
<>
|
|
2155
|
+
{selectedChartType === "bar" ? (
|
|
2156
|
+
<label className="block space-y-1">
|
|
2157
|
+
<div>{t("panel.config.barWidthPx")}</div>
|
|
2158
|
+
<Input
|
|
2159
|
+
type="number"
|
|
2160
|
+
min={1}
|
|
2161
|
+
placeholder={t("panel.config.barWidthAuto")}
|
|
2162
|
+
value={selectedElement.chart?.barWidth ?? ""}
|
|
2163
|
+
onChange={(e) => {
|
|
2164
|
+
const raw = e.target.value.trim();
|
|
2165
|
+
updateSelectedChart({
|
|
2166
|
+
barWidth: raw
|
|
2167
|
+
? Math.max(1, Number(raw) || 1)
|
|
2168
|
+
: undefined,
|
|
2169
|
+
});
|
|
2170
|
+
}}
|
|
2171
|
+
className="h-7"
|
|
2172
|
+
/>
|
|
2173
|
+
</label>
|
|
2174
|
+
) : null}
|
|
2175
|
+
|
|
2176
|
+
{selectedChartType === "line" || selectedChartType === "area" ? (
|
|
2177
|
+
<label className="flex items-center gap-2">
|
|
2178
|
+
<Checkbox
|
|
2179
|
+
checked={selectedElement.chart?.smooth ?? true}
|
|
2180
|
+
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"
|
|
2181
|
+
onCheckedChange={(checked) =>
|
|
2182
|
+
updateSelectedChart({ smooth: checked === true })
|
|
2183
|
+
}
|
|
2184
|
+
/>
|
|
2185
|
+
<span>{t("panel.config.smooth")}</span>
|
|
2186
|
+
</label>
|
|
2187
|
+
) : null}
|
|
2188
|
+
|
|
2189
|
+
{selectedChartType === "pie" ? (
|
|
2190
|
+
<div className="grid grid-cols-2 gap-2">
|
|
2191
|
+
<label className="block space-y-1">
|
|
2192
|
+
<div>{t("panel.config.pieInnerRadiusPct")}</div>
|
|
2193
|
+
<Input
|
|
2194
|
+
type="number"
|
|
2195
|
+
min={0}
|
|
2196
|
+
max={99}
|
|
2197
|
+
value={selectedElement.chart?.pieInnerRadius ?? 30}
|
|
2198
|
+
onChange={(e) =>
|
|
2199
|
+
updateSelectedChart({
|
|
2200
|
+
pieInnerRadius: Math.max(
|
|
2201
|
+
0,
|
|
2202
|
+
Math.min(99, Number(e.target.value) || 0)
|
|
2203
|
+
),
|
|
2204
|
+
})
|
|
2205
|
+
}
|
|
2206
|
+
className="h-7"
|
|
2207
|
+
/>
|
|
2208
|
+
</label>
|
|
2209
|
+
<label className="block space-y-1">
|
|
2210
|
+
<div>{t("panel.config.pieOuterRadiusPct")}</div>
|
|
2211
|
+
<Input
|
|
2212
|
+
type="number"
|
|
2213
|
+
min={1}
|
|
2214
|
+
max={100}
|
|
2215
|
+
value={selectedElement.chart?.pieOuterRadius ?? 65}
|
|
2216
|
+
onChange={(e) =>
|
|
2217
|
+
updateSelectedChart({
|
|
2218
|
+
pieOuterRadius: Math.max(
|
|
2219
|
+
1,
|
|
2220
|
+
Math.min(100, Number(e.target.value) || 1)
|
|
2221
|
+
),
|
|
2222
|
+
})
|
|
2223
|
+
}
|
|
2224
|
+
className="h-7"
|
|
2225
|
+
/>
|
|
2226
|
+
</label>
|
|
2227
|
+
</div>
|
|
2228
|
+
) : null}
|
|
2229
|
+
</>
|
|
2230
|
+
)
|
|
2231
|
+
) : null}
|
|
2232
|
+
{renderFieldGroup(
|
|
2233
|
+
t("panel.config.groupChartDisplayMore"),
|
|
2234
|
+
<>
|
|
2225
2235
|
<label className="flex items-center gap-2">
|
|
2226
2236
|
<Checkbox
|
|
2227
2237
|
checked={selectedElement.chart?.colorMode === "gradient"}
|
|
@@ -2304,7 +2314,9 @@ export function PanelConfigSidebar({
|
|
|
2304
2314
|
</SelectContent>
|
|
2305
2315
|
</Select>
|
|
2306
2316
|
</label>
|
|
2307
|
-
|
|
2317
|
+
</>,
|
|
2318
|
+
undefined,
|
|
2319
|
+
{ groupKey: "chartDisplayMore", defaultOpen: false }
|
|
2308
2320
|
)}
|
|
2309
2321
|
{renderFieldGroup(
|
|
2310
2322
|
t("panel.config.groupTooltip"),
|
|
@@ -2361,39 +2373,10 @@ export function PanelConfigSidebar({
|
|
|
2361
2373
|
className="h-7"
|
|
2362
2374
|
/>
|
|
2363
2375
|
</label>
|
|
2364
|
-
|
|
2376
|
+
</>,
|
|
2377
|
+
undefined,
|
|
2378
|
+
{ groupKey: "chartTooltip", defaultOpen: false }
|
|
2365
2379
|
)}
|
|
2366
|
-
{renderFieldGroup(
|
|
2367
|
-
t("panel.config.groupData"),
|
|
2368
|
-
<>
|
|
2369
|
-
<label className="block space-y-1">
|
|
2370
|
-
<div>{t("panel.config.labelsCsv")}</div>
|
|
2371
|
-
<Input
|
|
2372
|
-
value={getChartLabelsDisplayText(selectedElement.chart)}
|
|
2373
|
-
onChange={(e) =>
|
|
2374
|
-
updateSelectedChart({
|
|
2375
|
-
labelsText: e.target.value,
|
|
2376
|
-
})
|
|
2377
|
-
}
|
|
2378
|
-
className="h-7"
|
|
2379
|
-
/>
|
|
2380
|
-
</label>
|
|
2381
|
-
|
|
2382
|
-
<label className="block space-y-1">
|
|
2383
|
-
<div>{t("panel.config.valuesCsv")}</div>
|
|
2384
|
-
<Input
|
|
2385
|
-
value={getChartValuesDisplayText(selectedElement.chart)}
|
|
2386
|
-
onChange={(e) =>
|
|
2387
|
-
updateSelectedChart({
|
|
2388
|
-
valuesText: e.target.value,
|
|
2389
|
-
})
|
|
2390
|
-
}
|
|
2391
|
-
className="h-7"
|
|
2392
|
-
/>
|
|
2393
|
-
</label>
|
|
2394
|
-
</>
|
|
2395
|
-
)}
|
|
2396
|
-
|
|
2397
2380
|
{selectedChartType === "bar" ||
|
|
2398
2381
|
selectedChartType === "line" ||
|
|
2399
2382
|
selectedChartType === "area" ||
|
|
@@ -2555,88 +2538,12 @@ export function PanelConfigSidebar({
|
|
|
2555
2538
|
<span>{t("panel.config.yAxisLabelAutoEllipsis")}</span>
|
|
2556
2539
|
</label>
|
|
2557
2540
|
</div>
|
|
2558
|
-
|
|
2541
|
+
</>,
|
|
2542
|
+
undefined,
|
|
2543
|
+
{ groupKey: "chartAxes", defaultOpen: false }
|
|
2559
2544
|
)
|
|
2560
2545
|
) : null}
|
|
2561
2546
|
|
|
2562
|
-
{selectedChartType === "bar" ||
|
|
2563
|
-
selectedChartType === "line" ||
|
|
2564
|
-
selectedChartType === "area" ||
|
|
2565
|
-
selectedChartType === "pie" ? (
|
|
2566
|
-
renderFieldGroup(
|
|
2567
|
-
t("panel.config.groupSeries"),
|
|
2568
|
-
<>
|
|
2569
|
-
{selectedChartType === "bar" ? (
|
|
2570
|
-
<label className="block space-y-1">
|
|
2571
|
-
<div>{t("panel.config.barWidthPx")}</div>
|
|
2572
|
-
<Input
|
|
2573
|
-
type="number"
|
|
2574
|
-
min={1}
|
|
2575
|
-
value={selectedElement.chart?.barWidth ?? 24}
|
|
2576
|
-
onChange={(e) =>
|
|
2577
|
-
updateSelectedChart({ barWidth: Math.max(1, Number(e.target.value) || 1) })
|
|
2578
|
-
}
|
|
2579
|
-
className="h-7"
|
|
2580
|
-
/>
|
|
2581
|
-
</label>
|
|
2582
|
-
) : null}
|
|
2583
|
-
|
|
2584
|
-
{selectedChartType === "line" || selectedChartType === "area" ? (
|
|
2585
|
-
<label className="flex items-center gap-2">
|
|
2586
|
-
<Checkbox
|
|
2587
|
-
checked={selectedElement.chart?.smooth ?? true}
|
|
2588
|
-
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"
|
|
2589
|
-
onCheckedChange={(checked) =>
|
|
2590
|
-
updateSelectedChart({ smooth: checked === true })
|
|
2591
|
-
}
|
|
2592
|
-
/>
|
|
2593
|
-
<span>{t("panel.config.smooth")}</span>
|
|
2594
|
-
</label>
|
|
2595
|
-
) : null}
|
|
2596
|
-
|
|
2597
|
-
{selectedChartType === "pie" ? (
|
|
2598
|
-
<div className="grid grid-cols-2 gap-2">
|
|
2599
|
-
<label className="block space-y-1">
|
|
2600
|
-
<div>{t("panel.config.pieInnerRadiusPct")}</div>
|
|
2601
|
-
<Input
|
|
2602
|
-
type="number"
|
|
2603
|
-
min={0}
|
|
2604
|
-
max={99}
|
|
2605
|
-
value={selectedElement.chart?.pieInnerRadius ?? 30}
|
|
2606
|
-
onChange={(e) =>
|
|
2607
|
-
updateSelectedChart({
|
|
2608
|
-
pieInnerRadius: Math.max(
|
|
2609
|
-
0,
|
|
2610
|
-
Math.min(99, Number(e.target.value) || 0)
|
|
2611
|
-
),
|
|
2612
|
-
})
|
|
2613
|
-
}
|
|
2614
|
-
className="h-7"
|
|
2615
|
-
/>
|
|
2616
|
-
</label>
|
|
2617
|
-
<label className="block space-y-1">
|
|
2618
|
-
<div>{t("panel.config.pieOuterRadiusPct")}</div>
|
|
2619
|
-
<Input
|
|
2620
|
-
type="number"
|
|
2621
|
-
min={1}
|
|
2622
|
-
max={100}
|
|
2623
|
-
value={selectedElement.chart?.pieOuterRadius ?? 65}
|
|
2624
|
-
onChange={(e) =>
|
|
2625
|
-
updateSelectedChart({
|
|
2626
|
-
pieOuterRadius: Math.max(
|
|
2627
|
-
1,
|
|
2628
|
-
Math.min(100, Number(e.target.value) || 1)
|
|
2629
|
-
),
|
|
2630
|
-
})
|
|
2631
|
-
}
|
|
2632
|
-
className="h-7"
|
|
2633
|
-
/>
|
|
2634
|
-
</label>
|
|
2635
|
-
</div>
|
|
2636
|
-
) : null}
|
|
2637
|
-
</>
|
|
2638
|
-
)
|
|
2639
|
-
) : null}
|
|
2640
2547
|
</>,
|
|
2641
2548
|
true,
|
|
2642
2549
|
[
|
|
@@ -3086,7 +2993,9 @@ export function PanelConfigSidebar({
|
|
|
3086
2993
|
}
|
|
3087
2994
|
/>
|
|
3088
2995
|
<span>{t("panel.config.allowCanvasInput")}</span>
|
|
3089
|
-
</label
|
|
2996
|
+
</label>,
|
|
2997
|
+
undefined,
|
|
2998
|
+
{ groupKey: "textInputAbility", defaultOpen: false }
|
|
3090
2999
|
)}
|
|
3091
3000
|
</>,
|
|
3092
3001
|
true,
|
|
@@ -3269,7 +3178,9 @@ export function PanelConfigSidebar({
|
|
|
3269
3178
|
{t("panel.config.audioPosterHint")}
|
|
3270
3179
|
</ConfigHintIcon>
|
|
3271
3180
|
</div>
|
|
3272
|
-
|
|
3181
|
+
</>,
|
|
3182
|
+
undefined,
|
|
3183
|
+
{ groupKey: "audioDisplayStyle", defaultOpen: false }
|
|
3273
3184
|
)}
|
|
3274
3185
|
</>,
|
|
3275
3186
|
true,
|
|
@@ -3442,7 +3353,8 @@ export function PanelConfigSidebar({
|
|
|
3442
3353
|
</>,
|
|
3443
3354
|
<>
|
|
3444
3355
|
{t("panel.config.canvasScriptHint")}
|
|
3445
|
-
|
|
3356
|
+
</>,
|
|
3357
|
+
{ groupKey: "geometryCanvasScript", defaultOpen: false }
|
|
3446
3358
|
)}
|
|
3447
3359
|
{renderFieldGroup(
|
|
3448
3360
|
t("panel.config.groupSketchOverlay"),
|
|
@@ -3539,7 +3451,9 @@ export function PanelConfigSidebar({
|
|
|
3539
3451
|
{t("panel.config.clearSketch")}
|
|
3540
3452
|
</button>
|
|
3541
3453
|
</div>
|
|
3542
|
-
|
|
3454
|
+
</>,
|
|
3455
|
+
undefined,
|
|
3456
|
+
{ groupKey: "geometrySketch", defaultOpen: false }
|
|
3543
3457
|
)}
|
|
3544
3458
|
</>,
|
|
3545
3459
|
true,
|
|
@@ -3699,17 +3613,193 @@ export function PanelConfigSidebar({
|
|
|
3699
3613
|
</>,
|
|
3700
3614
|
<>
|
|
3701
3615
|
{t("panel.config.copyStrategyHint")}
|
|
3702
|
-
|
|
3616
|
+
</>,
|
|
3617
|
+
{ groupKey: "referenceCopyStrategy", defaultOpen: false }
|
|
3703
3618
|
)}
|
|
3704
3619
|
</>,
|
|
3705
3620
|
true,
|
|
3706
3621
|
[t("panel.config.searchKwRef"), "ref", t("panel.config.layer"), t("panel.material.shallowCopy"), t("panel.material.deepCopy"), "snapshot"]
|
|
3707
3622
|
)
|
|
3708
|
-
) : (
|
|
3623
|
+
) : selectedElement.materialType === "image" ? null : (
|
|
3709
3624
|
<div className="text-xs leading-6 text-muted-foreground">
|
|
3710
3625
|
{t("panel.config.notChartType")}
|
|
3711
3626
|
</div>
|
|
3712
3627
|
)}
|
|
3628
|
+
{renderSection(
|
|
3629
|
+
"styleBackground",
|
|
3630
|
+
t("panel.config.sectionStyleBackground"),
|
|
3631
|
+
<>
|
|
3632
|
+
{renderFieldGroup(
|
|
3633
|
+
t("panel.config.groupBgFill"),
|
|
3634
|
+
<>
|
|
3635
|
+
{renderColorField(
|
|
3636
|
+
t("panel.config.backgroundColor"),
|
|
3637
|
+
selectedElement.style?.backgroundColor ?? "",
|
|
3638
|
+
(next) => updateSelectedStyle({ backgroundColor: next || undefined })
|
|
3639
|
+
)}
|
|
3640
|
+
</>
|
|
3641
|
+
)}
|
|
3642
|
+
{renderFieldGroup(
|
|
3643
|
+
t("panel.config.groupBgLayout"),
|
|
3644
|
+
<>
|
|
3645
|
+
<label className="block space-y-1">
|
|
3646
|
+
<div>{t("panel.config.backgroundImage")}</div>
|
|
3647
|
+
<Input
|
|
3648
|
+
value={selectedElement.style?.backgroundImage ?? ""}
|
|
3649
|
+
onChange={(e) => updateSelectedStyle({ backgroundImage: e.target.value || undefined })}
|
|
3650
|
+
placeholder='url("https://...") / linear-gradient(...)'
|
|
3651
|
+
className="h-7"
|
|
3652
|
+
/>
|
|
3653
|
+
</label>
|
|
3654
|
+
<div className="flex items-center gap-2">
|
|
3655
|
+
<label className="inline-flex cursor-pointer items-center rounded border border-border px-2 py-1 text-[11px] hover:bg-accent">
|
|
3656
|
+
{t("panel.config.uploadImage")}
|
|
3657
|
+
<Input
|
|
3658
|
+
type="file"
|
|
3659
|
+
accept="image/*"
|
|
3660
|
+
className="hidden"
|
|
3661
|
+
onChange={async (e) => {
|
|
3662
|
+
const file = e.target.files?.[0];
|
|
3663
|
+
e.currentTarget.value = "";
|
|
3664
|
+
if (!file) return;
|
|
3665
|
+
await handleUploadBackgroundImage(file);
|
|
3666
|
+
}}
|
|
3667
|
+
/>
|
|
3668
|
+
</label>
|
|
3669
|
+
{uploadStatus ? (
|
|
3670
|
+
<span className="text-[11px] text-muted-foreground">{uploadStatus}</span>
|
|
3671
|
+
) : null}
|
|
3672
|
+
</div>
|
|
3673
|
+
<div className="grid grid-cols-2 gap-2">
|
|
3674
|
+
<label className="block space-y-1">
|
|
3675
|
+
<div>{t("panel.config.backgroundSize")}</div>
|
|
3676
|
+
<Select
|
|
3677
|
+
value={selectedElement.style?.backgroundSize ?? "__none__"}
|
|
3678
|
+
onValueChange={(value) =>
|
|
3679
|
+
updateSelectedStyle({
|
|
3680
|
+
backgroundSize: value === "__none__" ? undefined : value,
|
|
3681
|
+
})
|
|
3682
|
+
}
|
|
3683
|
+
>
|
|
3684
|
+
<SelectTrigger className="h-7">
|
|
3685
|
+
<SelectValue placeholder={t("panel.config.selectBackgroundSize")} />
|
|
3686
|
+
</SelectTrigger>
|
|
3687
|
+
<SelectContent>
|
|
3688
|
+
<SelectItem value="__none__">{t("common.default")}</SelectItem>
|
|
3689
|
+
<SelectItem value="cover">cover</SelectItem>
|
|
3690
|
+
<SelectItem value="contain">contain</SelectItem>
|
|
3691
|
+
<SelectItem value="100% 100%">100% 100%</SelectItem>
|
|
3692
|
+
<SelectItem value="auto">auto</SelectItem>
|
|
3693
|
+
</SelectContent>
|
|
3694
|
+
</Select>
|
|
3695
|
+
</label>
|
|
3696
|
+
<label className="block space-y-1">
|
|
3697
|
+
<div>{t("panel.config.backgroundPosition")}</div>
|
|
3698
|
+
<Select
|
|
3699
|
+
value={selectedElement.style?.backgroundPosition ?? "__none__"}
|
|
3700
|
+
onValueChange={(value) =>
|
|
3701
|
+
updateSelectedStyle({
|
|
3702
|
+
backgroundPosition: value === "__none__" ? undefined : value,
|
|
3703
|
+
})
|
|
3704
|
+
}
|
|
3705
|
+
>
|
|
3706
|
+
<SelectTrigger className="h-7">
|
|
3707
|
+
<SelectValue placeholder={t("panel.config.selectBackgroundPosition")} />
|
|
3708
|
+
</SelectTrigger>
|
|
3709
|
+
<SelectContent>
|
|
3710
|
+
<SelectItem value="__none__">{t("common.default")}</SelectItem>
|
|
3711
|
+
<SelectItem value="center">center</SelectItem>
|
|
3712
|
+
<SelectItem value="top">top</SelectItem>
|
|
3713
|
+
<SelectItem value="bottom">bottom</SelectItem>
|
|
3714
|
+
<SelectItem value="left">left</SelectItem>
|
|
3715
|
+
<SelectItem value="right">right</SelectItem>
|
|
3716
|
+
<SelectItem value="top left">top left</SelectItem>
|
|
3717
|
+
<SelectItem value="top right">top right</SelectItem>
|
|
3718
|
+
<SelectItem value="bottom left">bottom left</SelectItem>
|
|
3719
|
+
<SelectItem value="bottom right">bottom right</SelectItem>
|
|
3720
|
+
</SelectContent>
|
|
3721
|
+
</Select>
|
|
3722
|
+
</label>
|
|
3723
|
+
</div>
|
|
3724
|
+
</>,
|
|
3725
|
+
undefined,
|
|
3726
|
+
{ groupKey: "styleBgLayout", defaultOpen: false }
|
|
3727
|
+
)}
|
|
3728
|
+
</>,
|
|
3729
|
+
false,
|
|
3730
|
+
[t("panel.config.backgroundColor"), t("panel.config.backgroundImage"), "background", "backgroundSize", "backgroundPosition", t("panel.config.searchKwLayout")]
|
|
3731
|
+
)}
|
|
3732
|
+
|
|
3733
|
+
{renderSection(
|
|
3734
|
+
"styleBorder",
|
|
3735
|
+
t("panel.config.sectionStyleBorder"),
|
|
3736
|
+
<>
|
|
3737
|
+
{renderFieldGroup(
|
|
3738
|
+
t("panel.config.groupBorderGeometry"),
|
|
3739
|
+
<div className="grid grid-cols-2 gap-2">
|
|
3740
|
+
<label className="block space-y-1">
|
|
3741
|
+
<div>{t("panel.config.borderWidth")}</div>
|
|
3742
|
+
<Input
|
|
3743
|
+
type="number"
|
|
3744
|
+
min={0}
|
|
3745
|
+
value={selectedElement.style?.borderWidth ?? 0}
|
|
3746
|
+
onChange={(e) =>
|
|
3747
|
+
updateSelectedStyle({ borderWidth: Math.max(0, Number(e.target.value) || 0) })
|
|
3748
|
+
}
|
|
3749
|
+
className="h-7"
|
|
3750
|
+
/>
|
|
3751
|
+
</label>
|
|
3752
|
+
<label className="block space-y-1">
|
|
3753
|
+
<div>{t("panel.config.borderRadius")}</div>
|
|
3754
|
+
<Input
|
|
3755
|
+
type="number"
|
|
3756
|
+
min={0}
|
|
3757
|
+
value={selectedElement.style?.borderRadius ?? 0}
|
|
3758
|
+
onChange={(e) =>
|
|
3759
|
+
updateSelectedStyle({ borderRadius: Math.max(0, Number(e.target.value) || 0) })
|
|
3760
|
+
}
|
|
3761
|
+
className="h-7"
|
|
3762
|
+
/>
|
|
3763
|
+
</label>
|
|
3764
|
+
</div>
|
|
3765
|
+
)}
|
|
3766
|
+
{renderFieldGroup(
|
|
3767
|
+
t("panel.config.groupBorderVisual"),
|
|
3768
|
+
<div className="grid grid-cols-2 gap-2">
|
|
3769
|
+
<label className="block space-y-1">
|
|
3770
|
+
<div>{t("panel.config.borderStyle")}</div>
|
|
3771
|
+
<Select
|
|
3772
|
+
value={selectedElement.style?.borderStyle ?? "solid"}
|
|
3773
|
+
onValueChange={(value) =>
|
|
3774
|
+
updateSelectedStyle({
|
|
3775
|
+
borderStyle: value as NonNullable<PanelElementStyle["borderStyle"]>,
|
|
3776
|
+
})
|
|
3777
|
+
}
|
|
3778
|
+
>
|
|
3779
|
+
<SelectTrigger className="h-7">
|
|
3780
|
+
<SelectValue placeholder={t("panel.config.selectBorderStyle")} />
|
|
3781
|
+
</SelectTrigger>
|
|
3782
|
+
<SelectContent>
|
|
3783
|
+
<SelectItem value="none">none</SelectItem>
|
|
3784
|
+
<SelectItem value="solid">solid</SelectItem>
|
|
3785
|
+
<SelectItem value="dashed">dashed</SelectItem>
|
|
3786
|
+
<SelectItem value="dotted">dotted</SelectItem>
|
|
3787
|
+
<SelectItem value="double">double</SelectItem>
|
|
3788
|
+
</SelectContent>
|
|
3789
|
+
</Select>
|
|
3790
|
+
</label>
|
|
3791
|
+
{renderColorField(
|
|
3792
|
+
t("panel.config.borderColor"),
|
|
3793
|
+
selectedElement.style?.borderColor ?? "",
|
|
3794
|
+
(next) => updateSelectedStyle({ borderColor: next || undefined })
|
|
3795
|
+
)}
|
|
3796
|
+
</div>
|
|
3797
|
+
)}
|
|
3798
|
+
</>,
|
|
3799
|
+
false,
|
|
3800
|
+
[t("panel.config.searchKwBorder"), "border", t("panel.config.searchKwWidth"), t("panel.config.searchKwRadius"), t("panel.config.color"), t("panel.config.searchKwStyle")]
|
|
3801
|
+
)}
|
|
3802
|
+
|
|
3713
3803
|
{hasSearch && renderedSectionCount === 0 ? (
|
|
3714
3804
|
<div className="rounded border border-border/60 bg-background px-2 py-1.5 text-[11px] text-muted-foreground">
|
|
3715
3805
|
{t("panel.config.noMatch")}
|