163 lines
4.8 KiB
React
163 lines
4.8 KiB
React
|
|
import useEditorStore from "./useEditorStore";
|
|||
|
|
import { Eye, EyeOff, Trash2 } from "lucide-react";
|
|||
|
|
|
|||
|
|
export default function LayersPanel() {
|
|||
|
|
const elements = useEditorStore((state) => state.elements);
|
|||
|
|
const selectedId = useEditorStore((state) => state.selectedId);
|
|||
|
|
const setSelectedId = useEditorStore((state) => state.setSelectedId);
|
|||
|
|
const deleteElement = useEditorStore((state) => state.deleteElement);
|
|||
|
|
const showLayers = useEditorStore((state) => state.showLayers);
|
|||
|
|
const toggleLayers = useEditorStore((state) => state.toggleLayers);
|
|||
|
|
|
|||
|
|
if (!showLayers) return null;
|
|||
|
|
|
|||
|
|
const getElementIcon = (type) => {
|
|||
|
|
const icons = {
|
|||
|
|
text: "T",
|
|||
|
|
image: "🖼️",
|
|||
|
|
qrcode: "⊡",
|
|||
|
|
line: "─",
|
|||
|
|
rectangle: "▭",
|
|||
|
|
summary: "Σ",
|
|||
|
|
table: "⊞",
|
|||
|
|
};
|
|||
|
|
return icons[type] || "•";
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const getElementLabel = (element) => {
|
|||
|
|
if (element.type === "text") return element.text.substring(0, 20);
|
|||
|
|
if (element.type === "image") return element.src ? "Image" : "Empty Image";
|
|||
|
|
return element.type.charAt(0).toUpperCase() + element.type.slice(1);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div style={styles.panel}>
|
|||
|
|
<div style={styles.header}>
|
|||
|
|
<h4 style={styles.title}>Layers</h4>
|
|||
|
|
<button onClick={toggleLayers} style={styles.closeBtn}>
|
|||
|
|
×
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style={styles.layersList}>
|
|||
|
|
{elements.length === 0 ? (
|
|||
|
|
<div style={styles.emptyState}>No elements</div>
|
|||
|
|
) : (
|
|||
|
|
[...elements].reverse().map((element, index) => (
|
|||
|
|
<div
|
|||
|
|
key={element.id}
|
|||
|
|
style={{
|
|||
|
|
...styles.layerItem,
|
|||
|
|
...(selectedId === element.id ? styles.layerItemSelected : {}),
|
|||
|
|
}}
|
|||
|
|
onClick={() => setSelectedId(element.id)}
|
|||
|
|
>
|
|||
|
|
<div style={styles.layerInfo}>
|
|||
|
|
<span style={styles.layerIcon}>{getElementIcon(element.type)}</span>
|
|||
|
|
<span style={styles.layerLabel}>{getElementLabel(element)}</span>
|
|||
|
|
</div>
|
|||
|
|
<button
|
|||
|
|
onClick={(e) => {
|
|||
|
|
e.stopPropagation();
|
|||
|
|
deleteElement(element.id);
|
|||
|
|
}}
|
|||
|
|
style={styles.deleteBtn}
|
|||
|
|
title="Delete"
|
|||
|
|
>
|
|||
|
|
<Trash2 size={14} />
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
))
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const styles = {
|
|||
|
|
panel: {
|
|||
|
|
width: 220,
|
|||
|
|
background: "#fff",
|
|||
|
|
borderRight: "1px solid #ddd",
|
|||
|
|
display: "flex",
|
|||
|
|
flexDirection: "column",
|
|||
|
|
height: "100%",
|
|||
|
|
},
|
|||
|
|
header: {
|
|||
|
|
padding: "12px 16px",
|
|||
|
|
borderBottom: "1px solid #ddd",
|
|||
|
|
display: "flex",
|
|||
|
|
justifyContent: "space-between",
|
|||
|
|
alignItems: "center",
|
|||
|
|
},
|
|||
|
|
title: {
|
|||
|
|
margin: 0,
|
|||
|
|
fontSize: 14,
|
|||
|
|
fontWeight: 600,
|
|||
|
|
},
|
|||
|
|
closeBtn: {
|
|||
|
|
background: "none",
|
|||
|
|
border: "none",
|
|||
|
|
fontSize: 24,
|
|||
|
|
cursor: "pointer",
|
|||
|
|
padding: 0,
|
|||
|
|
lineHeight: 1,
|
|||
|
|
color: "#666",
|
|||
|
|
},
|
|||
|
|
layersList: {
|
|||
|
|
flex: 1,
|
|||
|
|
overflowY: "auto",
|
|||
|
|
padding: 8,
|
|||
|
|
},
|
|||
|
|
emptyState: {
|
|||
|
|
textAlign: "center",
|
|||
|
|
color: "#999",
|
|||
|
|
fontSize: 13,
|
|||
|
|
marginTop: 20,
|
|||
|
|
},
|
|||
|
|
layerItem: {
|
|||
|
|
padding: "8px 12px",
|
|||
|
|
marginBottom: 4,
|
|||
|
|
borderRadius: 4,
|
|||
|
|
cursor: "pointer",
|
|||
|
|
display: "flex",
|
|||
|
|
justifyContent: "space-between",
|
|||
|
|
alignItems: "center",
|
|||
|
|
transition: "all 0.2s",
|
|||
|
|
border: "1px solid transparent",
|
|||
|
|
},
|
|||
|
|
layerItemSelected: {
|
|||
|
|
background: "#e3f2fd",
|
|||
|
|
border: "1px solid #2196f3",
|
|||
|
|
},
|
|||
|
|
layerInfo: {
|
|||
|
|
display: "flex",
|
|||
|
|
alignItems: "center",
|
|||
|
|
gap: 8,
|
|||
|
|
flex: 1,
|
|||
|
|
overflow: "hidden",
|
|||
|
|
},
|
|||
|
|
layerIcon: {
|
|||
|
|
fontSize: 16,
|
|||
|
|
width: 20,
|
|||
|
|
textAlign: "center",
|
|||
|
|
},
|
|||
|
|
layerLabel: {
|
|||
|
|
fontSize: 13,
|
|||
|
|
overflow: "hidden",
|
|||
|
|
textOverflow: "ellipsis",
|
|||
|
|
whiteSpace: "nowrap",
|
|||
|
|
},
|
|||
|
|
deleteBtn: {
|
|||
|
|
background: "none",
|
|||
|
|
border: "none",
|
|||
|
|
cursor: "pointer",
|
|||
|
|
padding: 4,
|
|||
|
|
display: "flex",
|
|||
|
|
alignItems: "center",
|
|||
|
|
color: "#666",
|
|||
|
|
opacity: 0.6,
|
|||
|
|
transition: "opacity 0.2s",
|
|||
|
|
},
|
|||
|
|
};
|