优化
This commit is contained in:
@@ -10,14 +10,12 @@ import {
|
||||
} from '../utils';
|
||||
import { VisibilityRuleDialog } from './VisibilityRuleDialog';
|
||||
import { VisibilityRuleSummary } from './VisibilityRuleSummary';
|
||||
import { toggleSide, isSideEnabled } from '../elementBox';
|
||||
import {
|
||||
alignToSelectionBounds,
|
||||
alignSelectionToCanvas,
|
||||
tileSelectedEvenly,
|
||||
type AlignMode,
|
||||
} from '../elementAlign';
|
||||
import type { ElementSide } from '../types';
|
||||
import { CollapsiblePanelSection } from './CollapsiblePanelSection';
|
||||
import { CommitInput } from './CommitInput';
|
||||
import {
|
||||
@@ -779,7 +777,64 @@ export const PropSidebar: React.FC<PropSidebarProps> = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Text Formatting Controls */}
|
||||
{/* Alignment Tools */}
|
||||
<div className="space-y-1.5">
|
||||
<h5 className="ps-section-title">
|
||||
对齐与分布
|
||||
</h5>
|
||||
<div className="grid grid-cols-3 gap-1.5">
|
||||
<AlignToolButton
|
||||
icon={<AlignHorizontalJustifyStart className="w-3.5 h-3.5" />}
|
||||
label="左对齐"
|
||||
title="靠左对齐 (X=0)"
|
||||
onClick={() => handleElemChange({ ...selectedElem, x: 0 })}
|
||||
/>
|
||||
<AlignToolButton
|
||||
icon={<AlignHorizontalJustifyCenter className="w-3.5 h-3.5" />}
|
||||
label="水平居中"
|
||||
title="水平居中对齐"
|
||||
onClick={() => {
|
||||
const newX = Math.round(((template.width - selectedElem.width) / 2) * 10) / 10;
|
||||
handleElemChange({ ...selectedElem, x: Math.max(0, newX) });
|
||||
}}
|
||||
/>
|
||||
<AlignToolButton
|
||||
icon={<AlignHorizontalJustifyEnd className="w-3.5 h-3.5" />}
|
||||
label="右对齐"
|
||||
title="靠右对齐"
|
||||
onClick={() => {
|
||||
const newX = Math.round((template.width - selectedElem.width) * 10) / 10;
|
||||
handleElemChange({ ...selectedElem, x: Math.max(0, newX) });
|
||||
}}
|
||||
/>
|
||||
<AlignToolButton
|
||||
icon={<AlignVerticalJustifyStart className="w-3.5 h-3.5" />}
|
||||
label="顶对齐"
|
||||
title="靠顶对齐 (Y=0)"
|
||||
onClick={() => handleElemChange({ ...selectedElem, y: 0 })}
|
||||
/>
|
||||
<AlignToolButton
|
||||
icon={<AlignVerticalJustifyCenter className="w-3.5 h-3.5" />}
|
||||
label="垂直居中"
|
||||
title="垂直居中对齐"
|
||||
onClick={() => {
|
||||
const newY = Math.round(((template.height - selectedElem.height) / 2) * 10) / 10;
|
||||
handleElemChange({ ...selectedElem, y: Math.max(0, newY) });
|
||||
}}
|
||||
/>
|
||||
<AlignToolButton
|
||||
icon={<AlignVerticalJustifyEnd className="w-3.5 h-3.5" />}
|
||||
label="底对齐"
|
||||
title="靠底对齐"
|
||||
onClick={() => {
|
||||
const newY = Math.round((template.height - selectedElem.height) * 10) / 10;
|
||||
handleElemChange({ ...selectedElem, y: Math.max(0, newY) });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Text Settings */}
|
||||
{selectedElem.type === 'text' && (
|
||||
<div className="space-y-3 ps-section-divider">
|
||||
<h5 className="ps-section-title">
|
||||
@@ -1096,7 +1151,7 @@ export const PropSidebar: React.FC<PropSidebarProps> = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Barcode Formats Options */}
|
||||
{/* Barcode Settings */}
|
||||
{selectedElem.type === 'barcode' && (
|
||||
<div className="space-y-3 ps-section-divider">
|
||||
<h5 className="ps-section-title">
|
||||
@@ -1134,6 +1189,7 @@ export const PropSidebar: React.FC<PropSidebarProps> = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Image Settings */}
|
||||
{selectedElem.type === 'image' && (
|
||||
<div className="space-y-3 ps-section-divider">
|
||||
<h5 className="ps-section-title">
|
||||
@@ -1367,7 +1423,7 @@ export const PropSidebar: React.FC<PropSidebarProps> = ({
|
||||
className="ps-range"
|
||||
/>
|
||||
</div>
|
||||
<div className="border-t border-[#3a3a3a] pt-2.5">
|
||||
<div className="border-t border-[#3a3a3a] pt-2.5 space-y-2">
|
||||
<label className="ps-field-label">内边距 (mm)</label>
|
||||
<PropInput
|
||||
type="number"
|
||||
@@ -1383,6 +1439,41 @@ export const PropSidebar: React.FC<PropSidebarProps> = ({
|
||||
}
|
||||
className="ps-field font-mono"
|
||||
/>
|
||||
<div>
|
||||
<label className="ps-field-label">各边独立内边距 (mm,留空用统一值)</label>
|
||||
<div className="grid grid-cols-2 gap-1.5">
|
||||
{(
|
||||
[
|
||||
['paddingTop', '上'],
|
||||
['paddingRight', '右'],
|
||||
['paddingBottom', '下'],
|
||||
['paddingLeft', '左'],
|
||||
] as const
|
||||
).map(([key, label]) => (
|
||||
<div key={key} className="flex items-center gap-1">
|
||||
<span className="text-[9px] text-[#777] w-6 shrink-0">{label}</span>
|
||||
<PropInput
|
||||
type="number"
|
||||
min="0"
|
||||
max="10"
|
||||
step="0.5"
|
||||
value={selectedElem[key] ?? ''}
|
||||
onCommit={(val) => {
|
||||
const updated = { ...selectedElem };
|
||||
if (val === '' || val === undefined) {
|
||||
delete updated[key];
|
||||
} else {
|
||||
updated[key] = Math.max(0, Math.min(10, Number(val) || 0));
|
||||
}
|
||||
handleElemChange(updated);
|
||||
}}
|
||||
className="ps-field font-mono text-[10px] flex-1 min-w-0"
|
||||
placeholder="—"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1459,39 +1550,85 @@ export const PropSidebar: React.FC<PropSidebarProps> = ({
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="ps-field-label mb-1">边框边(点击切换)</label>
|
||||
<div className="grid grid-cols-4 gap-1">
|
||||
<label className="ps-field-label">各边独立边框宽度 (mm,留空用统一值,0 为不显示)</label>
|
||||
<div className="grid grid-cols-2 gap-1.5">
|
||||
{(
|
||||
[
|
||||
['top', '上'],
|
||||
['right', '右'],
|
||||
['bottom', '下'],
|
||||
['left', '左'],
|
||||
] as [ElementSide, string][]
|
||||
).map(([side, label]) => (
|
||||
<button
|
||||
key={side}
|
||||
type="button"
|
||||
onClick={() =>
|
||||
handleElemChange({
|
||||
...selectedElem,
|
||||
borderSides: toggleSide(selectedElem.borderSides, side),
|
||||
borderWidth:
|
||||
(selectedElem.borderWidth ?? 0) > 0
|
||||
? selectedElem.borderWidth
|
||||
: 0.3,
|
||||
borderColor: selectedElem.borderColor || '#111827',
|
||||
})
|
||||
}
|
||||
className={`ps-btn text-[10px] justify-center ${
|
||||
isSideEnabled(selectedElem.borderSides, side) &&
|
||||
(selectedElem.borderWidth ?? 0) > 0
|
||||
? 'active'
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
['borderWidthTop', '上'],
|
||||
['borderWidthRight', '右'],
|
||||
['borderWidthBottom', '下'],
|
||||
['borderWidthLeft', '左'],
|
||||
] as const
|
||||
).map(([key, label]) => (
|
||||
<div key={key} className="flex items-center gap-1">
|
||||
<span className="text-[9px] text-[#777] w-6 shrink-0">{label}</span>
|
||||
<PropInput
|
||||
type="number"
|
||||
min="0"
|
||||
max="5"
|
||||
step="0.1"
|
||||
value={selectedElem[key] ?? ''}
|
||||
onCommit={(val) => {
|
||||
const updated = { ...selectedElem };
|
||||
if (val === '' || val === undefined) {
|
||||
delete updated[key];
|
||||
} else {
|
||||
updated[key] = Math.max(0, Math.min(5, Number(val) || 0));
|
||||
}
|
||||
handleElemChange(updated);
|
||||
}}
|
||||
className="ps-field font-mono text-[10px] flex-1 min-w-0"
|
||||
placeholder="—"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="ps-field-label">各边独立边框颜色 (留空用统一值)</label>
|
||||
<div className="grid grid-cols-2 gap-1.5">
|
||||
{(
|
||||
[
|
||||
['borderColorTop', '上'],
|
||||
['borderColorRight', '右'],
|
||||
['borderColorBottom', '下'],
|
||||
['borderColorLeft', '左'],
|
||||
] as const
|
||||
).map(([key, label]) => (
|
||||
<div key={key} className="flex items-center gap-1 min-w-0">
|
||||
<span className="text-[9px] text-[#777] w-6 shrink-0">{label}</span>
|
||||
<input
|
||||
type="color"
|
||||
value={
|
||||
selectedElem[key]?.trim() ||
|
||||
selectedElem.borderColor ||
|
||||
'#111827'
|
||||
}
|
||||
onChange={(e) => {
|
||||
const updated = { ...selectedElem };
|
||||
updated[key] = e.target.value;
|
||||
handleElemChange(updated);
|
||||
}}
|
||||
className="color-input shrink-0 scale-90"
|
||||
title={`${label}边边框颜色`}
|
||||
/>
|
||||
<PropInput
|
||||
type="text"
|
||||
value={selectedElem[key] ?? ''}
|
||||
onCommit={(val) => {
|
||||
const updated = { ...selectedElem };
|
||||
if (val === '' || val === undefined) {
|
||||
delete updated[key];
|
||||
} else {
|
||||
updated[key] = val;
|
||||
}
|
||||
handleElemChange(updated);
|
||||
}}
|
||||
className="ps-field font-mono text-[10px] flex-1 min-w-0"
|
||||
placeholder="—"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1533,62 +1670,6 @@ export const PropSidebar: React.FC<PropSidebarProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Alignment Tools */}
|
||||
<div className="space-y-1.5">
|
||||
<h5 className="ps-section-title">
|
||||
对齐与分布
|
||||
</h5>
|
||||
<div className="grid grid-cols-3 gap-1.5">
|
||||
<AlignToolButton
|
||||
icon={<AlignHorizontalJustifyStart className="w-3.5 h-3.5" />}
|
||||
label="左对齐"
|
||||
title="靠左对齐 (X=0)"
|
||||
onClick={() => handleElemChange({ ...selectedElem, x: 0 })}
|
||||
/>
|
||||
<AlignToolButton
|
||||
icon={<AlignHorizontalJustifyCenter className="w-3.5 h-3.5" />}
|
||||
label="水平居中"
|
||||
title="水平居中对齐"
|
||||
onClick={() => {
|
||||
const newX = Math.round(((template.width - selectedElem.width) / 2) * 10) / 10;
|
||||
handleElemChange({ ...selectedElem, x: Math.max(0, newX) });
|
||||
}}
|
||||
/>
|
||||
<AlignToolButton
|
||||
icon={<AlignHorizontalJustifyEnd className="w-3.5 h-3.5" />}
|
||||
label="右对齐"
|
||||
title="靠右对齐"
|
||||
onClick={() => {
|
||||
const newX = Math.round((template.width - selectedElem.width) * 10) / 10;
|
||||
handleElemChange({ ...selectedElem, x: Math.max(0, newX) });
|
||||
}}
|
||||
/>
|
||||
<AlignToolButton
|
||||
icon={<AlignVerticalJustifyStart className="w-3.5 h-3.5" />}
|
||||
label="顶对齐"
|
||||
title="靠顶对齐 (Y=0)"
|
||||
onClick={() => handleElemChange({ ...selectedElem, y: 0 })}
|
||||
/>
|
||||
<AlignToolButton
|
||||
icon={<AlignVerticalJustifyCenter className="w-3.5 h-3.5" />}
|
||||
label="垂直居中"
|
||||
title="垂直居中对齐"
|
||||
onClick={() => {
|
||||
const newY = Math.round(((template.height - selectedElem.height) / 2) * 10) / 10;
|
||||
handleElemChange({ ...selectedElem, y: Math.max(0, newY) });
|
||||
}}
|
||||
/>
|
||||
<AlignToolButton
|
||||
icon={<AlignVerticalJustifyEnd className="w-3.5 h-3.5" />}
|
||||
label="底对齐"
|
||||
title="靠底对齐"
|
||||
onClick={() => {
|
||||
const newY = Math.round((template.height - selectedElem.height) * 10) / 10;
|
||||
handleElemChange({ ...selectedElem, y: Math.max(0, newY) });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user