163 lines
4.8 KiB
JavaScript
163 lines
4.8 KiB
JavaScript
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",
|
||
},
|
||
};
|