@asgerami/zemenay-blog
Version:
Plug-and-play blog system for Next.js - Get a fully functional blog running in minutes with zero configuration
77 lines (76 loc) • 8.58 kB
JavaScript
;
"use client";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ImageEditor = ImageEditor;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
function ImageEditor({ image, publicUrl, onSave, onCancel, className = "", }) {
const [editData, setEditData] = (0, react_1.useState)({
src: publicUrl,
alt: image.alt_text || image.original_name,
alignment: "center",
caption: "",
borderRadius: 0,
shadow: false,
quality: 80,
});
const [previewSize, setPreviewSize] = (0, react_1.useState)({ width: 0, height: 0 });
const imageRef = (0, react_1.useRef)(null);
const handleImageLoad = (0, react_1.useCallback)(() => {
if (imageRef.current) {
const { naturalWidth, naturalHeight } = imageRef.current;
setPreviewSize({ width: naturalWidth, height: naturalHeight });
setEditData((prev) => (Object.assign(Object.assign({}, prev), { width: naturalWidth, height: naturalHeight })));
}
}, []);
const handleSizeChange = (dimension, value) => {
if (!previewSize.width || !previewSize.height)
return;
const aspectRatio = previewSize.width / previewSize.height;
if (dimension === "width") {
setEditData((prev) => (Object.assign(Object.assign({}, prev), { width: value, height: Math.round(value / aspectRatio) })));
}
else {
setEditData((prev) => (Object.assign(Object.assign({}, prev), { height: value, width: Math.round(value * aspectRatio) })));
}
};
const resetToOriginal = () => {
setEditData((prev) => (Object.assign(Object.assign({}, prev), { width: previewSize.width, height: previewSize.height })));
};
const applyPreset = (preset) => {
const maxWidths = {
small: 300,
medium: 500,
large: 800,
full: 1200,
};
const maxWidth = maxWidths[preset];
const aspectRatio = previewSize.width / previewSize.height;
const newWidth = Math.min(maxWidth, previewSize.width);
const newHeight = Math.round(newWidth / aspectRatio);
setEditData((prev) => (Object.assign(Object.assign({}, prev), { width: newWidth, height: newHeight, alignment: preset === "full" ? "full" : prev.alignment })));
};
const getPreviewStyle = () => {
const maxPreviewWidth = 400;
const scale = editData.width
? Math.min(maxPreviewWidth / editData.width, 1)
: 1;
return {
width: editData.width ? editData.width * scale : "auto",
height: editData.height ? editData.height * scale : "auto",
borderRadius: `${editData.borderRadius}px`,
boxShadow: editData.shadow ? "0 4px 12px rgba(0, 0, 0, 0.15)" : "none",
margin: editData.alignment === "center"
? "0 auto"
: editData.alignment === "right"
? "0 0 0 auto"
: "0",
display: "block",
};
};
return ((0, jsx_runtime_1.jsxs)("div", { className: `image-editor ${className}`, children: [(0, jsx_runtime_1.jsxs)("div", { className: "editor-header", children: [(0, jsx_runtime_1.jsx)("h3", { children: "Edit Image" }), (0, jsx_runtime_1.jsxs)("div", { className: "editor-actions", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: onCancel, className: "cancel-btn", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => onSave(editData), className: "save-btn", children: "Insert Image" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "editor-content", children: [(0, jsx_runtime_1.jsxs)("div", { className: "preview-section", children: [(0, jsx_runtime_1.jsx)("h4", { children: "Preview" }), (0, jsx_runtime_1.jsxs)("div", { className: "preview-container", children: [(0, jsx_runtime_1.jsx)("img", { ref: imageRef, src: publicUrl, alt: editData.alt, onLoad: handleImageLoad, style: getPreviewStyle(), className: "preview-image" }), editData.caption && ((0, jsx_runtime_1.jsx)("p", { className: "image-caption", style: {
textAlign: editData.alignment === "full"
? "center"
: editData.alignment,
}, children: editData.caption }))] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "controls-section", children: [(0, jsx_runtime_1.jsxs)("div", { className: "control-group", children: [(0, jsx_runtime_1.jsx)("h4", { children: "Size" }), (0, jsx_runtime_1.jsxs)("div", { className: "size-presets", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => applyPreset("small"), children: "Small" }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => applyPreset("medium"), children: "Medium" }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => applyPreset("large"), children: "Large" }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => applyPreset("full"), children: "Full Width" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "size-inputs", children: [(0, jsx_runtime_1.jsxs)("div", { className: "input-group", children: [(0, jsx_runtime_1.jsx)("label", { children: "Width (px)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", value: editData.width || "", onChange: (e) => handleSizeChange("width", parseInt(e.target.value) || 0), min: "50", max: "1200" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "input-group", children: [(0, jsx_runtime_1.jsx)("label", { children: "Height (px)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", value: editData.height || "", onChange: (e) => handleSizeChange("height", parseInt(e.target.value) || 0), min: "50", max: "1200" })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: resetToOriginal, className: "reset-btn", children: "Reset" })] }), previewSize.width > 0 && ((0, jsx_runtime_1.jsxs)("p", { className: "size-info", children: ["Original: ", previewSize.width, " \u00D7 ", previewSize.height, "px"] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "control-group", children: [(0, jsx_runtime_1.jsx)("h4", { children: "Alignment" }), (0, jsx_runtime_1.jsx)("div", { className: "alignment-options", children: ["left", "center", "right", "full"].map((align) => ((0, jsx_runtime_1.jsx)("button", { type: "button", className: editData.alignment === align ? "active" : "", onClick: () => setEditData((prev) => (Object.assign(Object.assign({}, prev), { alignment: align }))), children: align.charAt(0).toUpperCase() + align.slice(1) }, align))) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "control-group", children: [(0, jsx_runtime_1.jsx)("h4", { children: "Alt Text" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: editData.alt, onChange: (e) => setEditData((prev) => (Object.assign(Object.assign({}, prev), { alt: e.target.value }))), placeholder: "Describe the image for accessibility", className: "alt-input" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "control-group", children: [(0, jsx_runtime_1.jsx)("h4", { children: "Caption (Optional)" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: editData.caption || "", onChange: (e) => setEditData((prev) => (Object.assign(Object.assign({}, prev), { caption: e.target.value }))), placeholder: "Add a caption below the image", className: "caption-input" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "control-group", children: [(0, jsx_runtime_1.jsx)("h4", { children: "Style" }), (0, jsx_runtime_1.jsxs)("div", { className: "style-options", children: [(0, jsx_runtime_1.jsxs)("div", { className: "input-group", children: [(0, jsx_runtime_1.jsx)("label", { children: "Border Radius (px)" }), (0, jsx_runtime_1.jsx)("input", { type: "range", min: "0", max: "20", value: editData.borderRadius || 0, onChange: (e) => setEditData((prev) => (Object.assign(Object.assign({}, prev), { borderRadius: parseInt(e.target.value) }))) }), (0, jsx_runtime_1.jsxs)("span", { children: [editData.borderRadius, "px"] })] }), (0, jsx_runtime_1.jsx)("div", { className: "checkbox-group", children: (0, jsx_runtime_1.jsxs)("label", { children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: editData.shadow || false, onChange: (e) => setEditData((prev) => (Object.assign(Object.assign({}, prev), { shadow: e.target.checked }))) }), "Add shadow"] }) })] })] })] })] })] }));
}