-
This commit is contained in:
@@ -21,11 +21,8 @@ import {
|
|||||||
Menu,
|
Menu,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Collapse,
|
Collapse,
|
||||||
TextField,
|
|
||||||
Badge,
|
Badge,
|
||||||
Avatar,
|
Avatar,
|
||||||
ToggleButton,
|
|
||||||
ToggleButtonGroup,
|
|
||||||
Stack,
|
Stack,
|
||||||
alpha,
|
alpha,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
@@ -63,25 +60,13 @@ import {
|
|||||||
ExpandMore as ExpandMoreIcon,
|
ExpandMore as ExpandMoreIcon,
|
||||||
ExpandLess as ExpandLessIcon,
|
ExpandLess as ExpandLessIcon,
|
||||||
Search as SearchIcon,
|
Search as SearchIcon,
|
||||||
FormatBold as BoldIcon,
|
|
||||||
FormatItalic as ItalicIcon,
|
|
||||||
FormatUnderlined as UnderlineIcon,
|
|
||||||
FormatAlignLeft as AlignLeftIcon,
|
|
||||||
FormatAlignCenter as AlignCenterIcon,
|
|
||||||
FormatAlignRight as AlignRightIcon,
|
|
||||||
FormatColorFill as FillColorIcon,
|
|
||||||
FormatColorText as TextColorIcon,
|
|
||||||
BorderColor as StrokeColorIcon,
|
|
||||||
CloudDone as SavedIcon,
|
CloudDone as SavedIcon,
|
||||||
CloudOff as UnsavedIcon,
|
CloudOff as UnsavedIcon,
|
||||||
AspectRatio as AspectRatioIcon,
|
|
||||||
Check as CheckIcon,
|
|
||||||
ArrowDropDown as DropdownIcon,
|
ArrowDropDown as DropdownIcon,
|
||||||
History as HistoryIcon,
|
History as HistoryIcon,
|
||||||
DataObject as DataBindIcon,
|
|
||||||
AutoMode as AutoSaveIcon,
|
AutoMode as AutoSaveIcon,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import type { ElementType, AprtElement } from "../../types/report";
|
import type { ElementType } from "../../types/report";
|
||||||
|
|
||||||
// Snap options type
|
// Snap options type
|
||||||
export interface SnapOptions {
|
export interface SnapOptions {
|
||||||
@@ -118,10 +103,6 @@ interface EditorToolbarProps {
|
|||||||
currentPageName: string;
|
currentPageName: string;
|
||||||
onPrevPage: () => void;
|
onPrevPage: () => void;
|
||||||
onNextPage: () => void;
|
onNextPage: () => void;
|
||||||
// Optional: selected element for contextual toolbar
|
|
||||||
selectedElement?: AprtElement | null;
|
|
||||||
// Optional: callback for element updates from toolbar
|
|
||||||
onUpdateSelectedElement?: (updates: Partial<AprtElement>) => void;
|
|
||||||
// Optional: save status
|
// Optional: save status
|
||||||
hasUnsavedChanges?: boolean;
|
hasUnsavedChanges?: boolean;
|
||||||
lastSavedAt?: Date | null;
|
lastSavedAt?: Date | null;
|
||||||
@@ -222,30 +203,6 @@ const SNAP_OPTIONS_CONFIG = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Color presets for quick selection
|
|
||||||
const COLOR_PRESETS = [
|
|
||||||
"#000000",
|
|
||||||
"#424242",
|
|
||||||
"#757575",
|
|
||||||
"#ffffff",
|
|
||||||
"#f44336",
|
|
||||||
"#e91e63",
|
|
||||||
"#9c27b0",
|
|
||||||
"#673ab7",
|
|
||||||
"#3f51b5",
|
|
||||||
"#2196f3",
|
|
||||||
"#03a9f4",
|
|
||||||
"#00bcd4",
|
|
||||||
"#009688",
|
|
||||||
"#4caf50",
|
|
||||||
"#8bc34a",
|
|
||||||
"#cddc39",
|
|
||||||
"#ffeb3b",
|
|
||||||
"#ffc107",
|
|
||||||
"#ff9800",
|
|
||||||
"#ff5722",
|
|
||||||
];
|
|
||||||
|
|
||||||
// Format time ago
|
// Format time ago
|
||||||
function formatTimeAgo(date: Date | null | undefined): string {
|
function formatTimeAgo(date: Date | null | undefined): string {
|
||||||
if (!date) return "";
|
if (!date) return "";
|
||||||
@@ -364,109 +321,6 @@ function StyledIconButton({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compact color picker button
|
|
||||||
function ColorPickerButton({
|
|
||||||
color,
|
|
||||||
onChange,
|
|
||||||
label,
|
|
||||||
icon: Icon,
|
|
||||||
}: {
|
|
||||||
color: string;
|
|
||||||
onChange: (color: string) => void;
|
|
||||||
label: string;
|
|
||||||
icon: React.ElementType;
|
|
||||||
}) {
|
|
||||||
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Tooltip title={label} arrow>
|
|
||||||
<IconButton
|
|
||||||
size="small"
|
|
||||||
onClick={(e) => setAnchorEl(e.currentTarget)}
|
|
||||||
sx={{
|
|
||||||
borderRadius: 1.5,
|
|
||||||
position: "relative",
|
|
||||||
"&:hover": { bgcolor: "action.hover" },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon fontSize="small" />
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
position: "absolute",
|
|
||||||
bottom: 2,
|
|
||||||
left: "50%",
|
|
||||||
transform: "translateX(-50%)",
|
|
||||||
width: 14,
|
|
||||||
height: 3,
|
|
||||||
bgcolor: color,
|
|
||||||
borderRadius: 0.5,
|
|
||||||
border: "1px solid",
|
|
||||||
borderColor: "divider",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
<Popover
|
|
||||||
open={Boolean(anchorEl)}
|
|
||||||
anchorEl={anchorEl}
|
|
||||||
onClose={() => setAnchorEl(null)}
|
|
||||||
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
|
|
||||||
>
|
|
||||||
<Box sx={{ p: 1.5 }}>
|
|
||||||
<Typography
|
|
||||||
variant="caption"
|
|
||||||
color="text.secondary"
|
|
||||||
sx={{ mb: 1, display: "block" }}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</Typography>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "grid",
|
|
||||||
gridTemplateColumns: "repeat(5, 1fr)",
|
|
||||||
gap: 0.5,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{COLOR_PRESETS.map((presetColor) => (
|
|
||||||
<IconButton
|
|
||||||
key={presetColor}
|
|
||||||
size="small"
|
|
||||||
onClick={() => {
|
|
||||||
onChange(presetColor);
|
|
||||||
setAnchorEl(null);
|
|
||||||
}}
|
|
||||||
sx={{
|
|
||||||
width: 28,
|
|
||||||
height: 28,
|
|
||||||
p: 0,
|
|
||||||
bgcolor: presetColor,
|
|
||||||
border: "2px solid",
|
|
||||||
borderColor:
|
|
||||||
color === presetColor ? "primary.main" : "divider",
|
|
||||||
"&:hover": {
|
|
||||||
transform: "scale(1.15)",
|
|
||||||
borderColor: "primary.main",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{color === presetColor && (
|
|
||||||
<CheckIcon
|
|
||||||
sx={{
|
|
||||||
fontSize: 14,
|
|
||||||
color: presetColor === "#ffffff" ? "#000" : "#fff",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</IconButton>
|
|
||||||
))}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Popover>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function EditorToolbar({
|
export default function EditorToolbar({
|
||||||
onAddElement,
|
onAddElement,
|
||||||
onDeleteElement,
|
onDeleteElement,
|
||||||
@@ -492,8 +346,6 @@ export default function EditorToolbar({
|
|||||||
currentPageName,
|
currentPageName,
|
||||||
onPrevPage,
|
onPrevPage,
|
||||||
onNextPage,
|
onNextPage,
|
||||||
selectedElement,
|
|
||||||
onUpdateSelectedElement,
|
|
||||||
hasUnsavedChanges = false,
|
hasUnsavedChanges = false,
|
||||||
lastSavedAt,
|
lastSavedAt,
|
||||||
onOpenCommandPalette,
|
onOpenCommandPalette,
|
||||||
@@ -551,275 +403,6 @@ export default function EditorToolbar({
|
|||||||
setAddMenuAnchor(null);
|
setAddMenuAnchor(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle text formatting
|
|
||||||
const handleTextFormat = (format: "bold" | "italic" | "underline") => {
|
|
||||||
if (
|
|
||||||
!selectedElement ||
|
|
||||||
selectedElement.type !== "text" ||
|
|
||||||
!onUpdateSelectedElement
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
const currentStyle = selectedElement.style || {};
|
|
||||||
let updates: Partial<AprtElement> = {};
|
|
||||||
|
|
||||||
switch (format) {
|
|
||||||
case "bold":
|
|
||||||
updates = {
|
|
||||||
style: {
|
|
||||||
...currentStyle,
|
|
||||||
fontWeight: currentStyle.fontWeight === "bold" ? "normal" : "bold",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case "italic":
|
|
||||||
updates = {
|
|
||||||
style: {
|
|
||||||
...currentStyle,
|
|
||||||
fontStyle:
|
|
||||||
currentStyle.fontStyle === "italic" ? "normal" : "italic",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case "underline":
|
|
||||||
updates = {
|
|
||||||
style: {
|
|
||||||
...currentStyle,
|
|
||||||
textDecoration:
|
|
||||||
currentStyle.textDecoration === "underline"
|
|
||||||
? "none"
|
|
||||||
: "underline",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
onUpdateSelectedElement(updates);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle text alignment
|
|
||||||
const handleTextAlign = (align: "left" | "center" | "right") => {
|
|
||||||
if (
|
|
||||||
!selectedElement ||
|
|
||||||
selectedElement.type !== "text" ||
|
|
||||||
!onUpdateSelectedElement
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
onUpdateSelectedElement({
|
|
||||||
style: {
|
|
||||||
...selectedElement.style,
|
|
||||||
textAlign: align,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Contextual toolbar based on selection
|
|
||||||
const renderContextualToolbar = () => {
|
|
||||||
if (!selectedElement || !onUpdateSelectedElement) return null;
|
|
||||||
|
|
||||||
const currentStyle = selectedElement.style || {};
|
|
||||||
|
|
||||||
// Text-specific toolbar
|
|
||||||
if (selectedElement.type === "text") {
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 0.5,
|
|
||||||
px: 1.5,
|
|
||||||
py: 0.5,
|
|
||||||
bgcolor: alpha(theme.palette.primary.main, 0.04),
|
|
||||||
borderRadius: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Text formatting */}
|
|
||||||
<ToggleButtonGroup
|
|
||||||
size="small"
|
|
||||||
sx={{ "& .MuiToggleButton-root": { border: 0, borderRadius: 1 } }}
|
|
||||||
>
|
|
||||||
<ToggleButton
|
|
||||||
value="bold"
|
|
||||||
selected={currentStyle.fontWeight === "bold"}
|
|
||||||
onClick={() => handleTextFormat("bold")}
|
|
||||||
>
|
|
||||||
<BoldIcon fontSize="small" />
|
|
||||||
</ToggleButton>
|
|
||||||
<ToggleButton
|
|
||||||
value="italic"
|
|
||||||
selected={currentStyle.fontStyle === "italic"}
|
|
||||||
onClick={() => handleTextFormat("italic")}
|
|
||||||
>
|
|
||||||
<ItalicIcon fontSize="small" />
|
|
||||||
</ToggleButton>
|
|
||||||
<ToggleButton
|
|
||||||
value="underline"
|
|
||||||
selected={currentStyle.textDecoration === "underline"}
|
|
||||||
onClick={() => handleTextFormat("underline")}
|
|
||||||
>
|
|
||||||
<UnderlineIcon fontSize="small" />
|
|
||||||
</ToggleButton>
|
|
||||||
</ToggleButtonGroup>
|
|
||||||
|
|
||||||
<Divider orientation="vertical" flexItem sx={{ mx: 0.5 }} />
|
|
||||||
|
|
||||||
{/* Text alignment */}
|
|
||||||
<ToggleButtonGroup
|
|
||||||
size="small"
|
|
||||||
exclusive
|
|
||||||
value={currentStyle.textAlign || "left"}
|
|
||||||
onChange={(_, value) => value && handleTextAlign(value)}
|
|
||||||
sx={{ "& .MuiToggleButton-root": { border: 0, borderRadius: 1 } }}
|
|
||||||
>
|
|
||||||
<ToggleButton value="left">
|
|
||||||
<AlignLeftIcon fontSize="small" />
|
|
||||||
</ToggleButton>
|
|
||||||
<ToggleButton value="center">
|
|
||||||
<AlignCenterIcon fontSize="small" />
|
|
||||||
</ToggleButton>
|
|
||||||
<ToggleButton value="right">
|
|
||||||
<AlignRightIcon fontSize="small" />
|
|
||||||
</ToggleButton>
|
|
||||||
</ToggleButtonGroup>
|
|
||||||
|
|
||||||
<Divider orientation="vertical" flexItem sx={{ mx: 0.5 }} />
|
|
||||||
|
|
||||||
{/* Colors */}
|
|
||||||
<ColorPickerButton
|
|
||||||
color={currentStyle.color || "#000000"}
|
|
||||||
onChange={(color) =>
|
|
||||||
onUpdateSelectedElement({ style: { ...currentStyle, color } })
|
|
||||||
}
|
|
||||||
label="Colore testo"
|
|
||||||
icon={TextColorIcon}
|
|
||||||
/>
|
|
||||||
<ColorPickerButton
|
|
||||||
color={currentStyle.backgroundColor || "transparent"}
|
|
||||||
onChange={(color) =>
|
|
||||||
onUpdateSelectedElement({
|
|
||||||
style: { ...currentStyle, backgroundColor: color },
|
|
||||||
})
|
|
||||||
}
|
|
||||||
label="Sfondo"
|
|
||||||
icon={FillColorIcon}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Divider orientation="vertical" flexItem sx={{ mx: 0.5 }} />
|
|
||||||
|
|
||||||
{/* Data binding indicator */}
|
|
||||||
{selectedElement.content?.type === "binding" && (
|
|
||||||
<Chip
|
|
||||||
icon={<DataBindIcon sx={{ fontSize: 14 }} />}
|
|
||||||
label="Data Bound"
|
|
||||||
size="small"
|
|
||||||
color="info"
|
|
||||||
variant="outlined"
|
|
||||||
sx={{ height: 24 }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shape/Line toolbar
|
|
||||||
if (selectedElement.type === "shape" || selectedElement.type === "line") {
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 0.5,
|
|
||||||
px: 1.5,
|
|
||||||
py: 0.5,
|
|
||||||
bgcolor: alpha(theme.palette.warning.main, 0.04),
|
|
||||||
borderRadius: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ColorPickerButton
|
|
||||||
color={currentStyle.backgroundColor || "#ffffff"}
|
|
||||||
onChange={(color) =>
|
|
||||||
onUpdateSelectedElement({
|
|
||||||
style: { ...currentStyle, backgroundColor: color },
|
|
||||||
})
|
|
||||||
}
|
|
||||||
label="Riempimento"
|
|
||||||
icon={FillColorIcon}
|
|
||||||
/>
|
|
||||||
<ColorPickerButton
|
|
||||||
color={currentStyle.borderColor || "#000000"}
|
|
||||||
onChange={(color) =>
|
|
||||||
onUpdateSelectedElement({
|
|
||||||
style: { ...currentStyle, borderColor: color },
|
|
||||||
})
|
|
||||||
}
|
|
||||||
label="Bordo"
|
|
||||||
icon={StrokeColorIcon}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Divider orientation="vertical" flexItem sx={{ mx: 0.5 }} />
|
|
||||||
|
|
||||||
{/* Border width */}
|
|
||||||
<Tooltip title="Spessore bordo">
|
|
||||||
<Box sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
|
|
||||||
<Typography variant="caption" color="text.secondary">
|
|
||||||
Bordo:
|
|
||||||
</Typography>
|
|
||||||
<TextField
|
|
||||||
type="number"
|
|
||||||
size="small"
|
|
||||||
value={currentStyle.borderWidth || 1}
|
|
||||||
onChange={(e) =>
|
|
||||||
onUpdateSelectedElement({
|
|
||||||
style: {
|
|
||||||
...currentStyle,
|
|
||||||
borderWidth: Number(e.target.value),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
inputProps={{ min: 0, max: 20, step: 0.5 }}
|
|
||||||
sx={{ width: 60, "& input": { py: 0.5, fontSize: "0.75rem" } }}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</Tooltip>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Image toolbar
|
|
||||||
if (selectedElement.type === "image") {
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 0.5,
|
|
||||||
px: 1.5,
|
|
||||||
py: 0.5,
|
|
||||||
bgcolor: alpha(theme.palette.secondary.main, 0.04),
|
|
||||||
borderRadius: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Chip
|
|
||||||
icon={<ImageIcon sx={{ fontSize: 14 }} />}
|
|
||||||
label={selectedElement.name || "Immagine"}
|
|
||||||
size="small"
|
|
||||||
variant="outlined"
|
|
||||||
sx={{ height: 24, maxWidth: 150 }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Divider orientation="vertical" flexItem sx={{ mx: 0.5 }} />
|
|
||||||
|
|
||||||
<StyledIconButton
|
|
||||||
tooltip="Mantieni proporzioni"
|
|
||||||
active={selectedElement.imageSettings?.maintainAspectRatio}
|
|
||||||
>
|
|
||||||
<AspectRatioIcon fontSize="small" />
|
|
||||||
</StyledIconButton>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Save status indicator
|
// Save status indicator
|
||||||
const renderSaveStatus = () => {
|
const renderSaveStatus = () => {
|
||||||
return (
|
return (
|
||||||
@@ -1490,13 +1073,6 @@ export default function EditorToolbar({
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Contextual toolbar for text/shape */}
|
|
||||||
{selectedElement && onUpdateSelectedElement && (
|
|
||||||
<Box sx={{ borderTop: 1, borderColor: "divider", px: 1.5, py: 0.5 }}>
|
|
||||||
{renderContextualToolbar()}
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Shared Popovers */}
|
{/* Shared Popovers */}
|
||||||
<Menu
|
<Menu
|
||||||
anchorEl={addMenuAnchor}
|
anchorEl={addMenuAnchor}
|
||||||
@@ -2374,79 +1950,6 @@ export default function EditorToolbar({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Contextual Toolbar Row - appears when element is selected */}
|
|
||||||
{selectedElement && onUpdateSelectedElement && (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 1,
|
|
||||||
px: 2,
|
|
||||||
py: 0.75,
|
|
||||||
borderTop: 1,
|
|
||||||
borderColor: "divider",
|
|
||||||
bgcolor: alpha(theme.palette.grey[100], 0.5),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Element type indicator */}
|
|
||||||
<Chip
|
|
||||||
icon={
|
|
||||||
ELEMENT_TYPES.find((e) => e.type === selectedElement.type)?.icon
|
|
||||||
? (() => {
|
|
||||||
const Icon = ELEMENT_TYPES.find(
|
|
||||||
(e) => e.type === selectedElement.type,
|
|
||||||
)!.icon;
|
|
||||||
return <Icon sx={{ fontSize: 16 }} />;
|
|
||||||
})()
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
label={
|
|
||||||
ELEMENT_TYPES.find((e) => e.type === selectedElement.type)
|
|
||||||
?.label || selectedElement.type
|
|
||||||
}
|
|
||||||
size="small"
|
|
||||||
variant="outlined"
|
|
||||||
sx={{
|
|
||||||
borderColor: ELEMENT_TYPES.find(
|
|
||||||
(e) => e.type === selectedElement.type,
|
|
||||||
)?.color,
|
|
||||||
color: ELEMENT_TYPES.find((e) => e.type === selectedElement.type)
|
|
||||||
?.color,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Divider orientation="vertical" flexItem sx={{ mx: 0.5 }} />
|
|
||||||
|
|
||||||
{/* Contextual formatting options */}
|
|
||||||
{renderContextualToolbar()}
|
|
||||||
|
|
||||||
<Box flex={1} />
|
|
||||||
|
|
||||||
{/* Element name */}
|
|
||||||
{selectedElement.name && (
|
|
||||||
<Typography
|
|
||||||
variant="caption"
|
|
||||||
color="text.secondary"
|
|
||||||
sx={{ fontFamily: "monospace" }}
|
|
||||||
>
|
|
||||||
{selectedElement.name}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Position info */}
|
|
||||||
<Typography
|
|
||||||
variant="caption"
|
|
||||||
color="text.disabled"
|
|
||||||
sx={{ fontFamily: "monospace" }}
|
|
||||||
>
|
|
||||||
{Math.round(selectedElement.position.x)}×
|
|
||||||
{Math.round(selectedElement.position.y)} |{" "}
|
|
||||||
{Math.round(selectedElement.position.width)}×
|
|
||||||
{Math.round(selectedElement.position.height)}mm
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1713,9 +1713,6 @@ export default function ReportEditorPage() {
|
|||||||
setSelectedElementIds([]);
|
setSelectedElementIds([]);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
// New props for enhanced toolbar
|
|
||||||
selectedElement={selectedElement}
|
|
||||||
onUpdateSelectedElement={handleUpdateSelectedElement}
|
|
||||||
hasUnsavedChanges={hasUnsavedChanges}
|
hasUnsavedChanges={hasUnsavedChanges}
|
||||||
// Auto-save props
|
// Auto-save props
|
||||||
autoSaveEnabled={autoSaveEnabled}
|
autoSaveEnabled={autoSaveEnabled}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user