244 lines
6.1 KiB
JavaScript
Executable File
244 lines
6.1 KiB
JavaScript
Executable File
import { __ } from "@wordpress/i18n";
|
|
import {
|
|
useBlockProps,
|
|
InspectorControls,
|
|
MediaUpload,
|
|
MediaUploadCheck,
|
|
} from "@wordpress/block-editor";
|
|
import {
|
|
PanelBody,
|
|
Button,
|
|
FocalPointPicker,
|
|
RangeControl,
|
|
ToolbarGroup,
|
|
ToolbarButton,
|
|
} from "@wordpress/components";
|
|
import { BlockControls } from "@wordpress/block-editor";
|
|
import { useState } from "@wordpress/element";
|
|
|
|
import "./editor.scss";
|
|
|
|
export default function Edit({ attributes, setAttributes }) {
|
|
const { images, height } = attributes;
|
|
const [selectedImageIndex, setSelectedImageIndex] = useState(null);
|
|
|
|
const blockProps = useBlockProps();
|
|
|
|
const onSelectImages = (media) => {
|
|
const newImages = media.map((img) => ({
|
|
id: img.id,
|
|
url: img.url,
|
|
alt: img.alt || "",
|
|
focalPoint: { x: 0.5, y: 0.5 },
|
|
scale: 0.8,
|
|
rotation: 0,
|
|
}));
|
|
setAttributes({ images: [...images, ...newImages] });
|
|
};
|
|
|
|
const updateImageFocalPoint = (index, focalPoint) => {
|
|
const newImages = [...images];
|
|
newImages[index] = { ...newImages[index], focalPoint };
|
|
setAttributes({ images: newImages });
|
|
};
|
|
|
|
const updateImageScale = (index, scale) => {
|
|
const newImages = [...images];
|
|
newImages[index] = { ...newImages[index], scale };
|
|
setAttributes({ images: newImages });
|
|
};
|
|
|
|
const updateImageRotation = (index, rotation) => {
|
|
const newImages = [...images];
|
|
newImages[index] = { ...newImages[index], rotation };
|
|
setAttributes({ images: newImages });
|
|
};
|
|
|
|
const removeImage = (index) => {
|
|
const newImages = images.filter((_, i) => i !== index);
|
|
setAttributes({ images: newImages });
|
|
if (selectedImageIndex === index) {
|
|
setSelectedImageIndex(null);
|
|
}
|
|
};
|
|
|
|
const moveImage = (index, direction) => {
|
|
const newImages = [...images];
|
|
const newIndex = index + direction;
|
|
if (newIndex >= 0 && newIndex < images.length) {
|
|
[newImages[index], newImages[newIndex]] = [
|
|
newImages[newIndex],
|
|
newImages[index],
|
|
];
|
|
setAttributes({ images: newImages });
|
|
setSelectedImageIndex(newIndex);
|
|
}
|
|
};
|
|
|
|
const getImageStyle = (image) => {
|
|
const focalPoint = image.focalPoint || { x: 0.5, y: 0.5 };
|
|
const scale = image.scale || 0.8;
|
|
const rotation = image.rotation || 0;
|
|
return {
|
|
left: `${focalPoint.x * 100}%`,
|
|
top: `${focalPoint.y * 100}%`,
|
|
transform: ` rotate(${rotation}deg) scale(${scale})`,
|
|
};
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<BlockControls>
|
|
<ToolbarGroup>
|
|
<MediaUploadCheck>
|
|
<MediaUpload
|
|
onSelect={onSelectImages}
|
|
allowedTypes={["image"]}
|
|
multiple
|
|
gallery
|
|
value={images.map((img) => img.id)}
|
|
render={({ open }) => (
|
|
<ToolbarButton onClick={open}>
|
|
{__("Add Images", "image-stack")}
|
|
</ToolbarButton>
|
|
)}
|
|
/>
|
|
</MediaUploadCheck>
|
|
</ToolbarGroup>
|
|
</BlockControls>
|
|
|
|
<InspectorControls>
|
|
<PanelBody title={__("Container Settings", "image-stack")}>
|
|
<RangeControl
|
|
label={__("Container Height", "image-stack")}
|
|
value={height}
|
|
onChange={(value) => setAttributes({ height: value })}
|
|
min={200}
|
|
max={800}
|
|
step={10}
|
|
/>
|
|
</PanelBody>
|
|
|
|
{images.length > 0 && (
|
|
<PanelBody title={__("Images", "image-stack")} initialOpen={true}>
|
|
{images.map((image, index) => (
|
|
<PanelBody
|
|
key={image.id}
|
|
title={`${__("Image", "image-stack")} ${index + 1}`}
|
|
initialOpen={selectedImageIndex === index}
|
|
onToggle={() =>
|
|
setSelectedImageIndex(
|
|
selectedImageIndex === index ? null : index
|
|
)
|
|
}
|
|
>
|
|
<div className="image-stack-image-preview">
|
|
<img src={image.url} alt={image.alt} />
|
|
</div>
|
|
|
|
<FocalPointPicker
|
|
label={__("Focal Point", "image-stack")}
|
|
url={image.url}
|
|
value={image.focalPoint || { x: 0.5, y: 0.5 }}
|
|
onChange={(focalPoint) =>
|
|
updateImageFocalPoint(index, focalPoint)
|
|
}
|
|
/>
|
|
|
|
<RangeControl
|
|
label={__("Scale", "image-stack")}
|
|
value={image.scale || 0.8}
|
|
onChange={(scale) => updateImageScale(index, scale)}
|
|
min={0.1}
|
|
max={3}
|
|
step={0.05}
|
|
/>
|
|
|
|
<RangeControl
|
|
label={__("Rotation (deg)", "image-stack")}
|
|
value={image.rotation || 0}
|
|
onChange={(rotation) => updateImageRotation(index, rotation)}
|
|
min={-180}
|
|
max={180}
|
|
step={1}
|
|
/>
|
|
|
|
<div className="image-stack-image-controls">
|
|
<Button
|
|
isSecondary
|
|
isSmall
|
|
disabled={index === 0}
|
|
onClick={() => moveImage(index, -1)}
|
|
>
|
|
{__("↑ Move Up", "image-stack")}
|
|
</Button>
|
|
<Button
|
|
isSecondary
|
|
isSmall
|
|
disabled={index === images.length - 1}
|
|
onClick={() => moveImage(index, 1)}
|
|
>
|
|
{__("↓ Move Down", "image-stack")}
|
|
</Button>
|
|
<Button
|
|
isDestructive
|
|
isSmall
|
|
onClick={() => removeImage(index)}
|
|
>
|
|
{__("Remove", "image-stack")}
|
|
</Button>
|
|
</div>
|
|
</PanelBody>
|
|
))}
|
|
</PanelBody>
|
|
)}
|
|
</InspectorControls>
|
|
|
|
<div {...blockProps}>
|
|
<div
|
|
className="image-stack-container"
|
|
style={{ height: `${height}px` }}
|
|
>
|
|
{images.length === 0 && (
|
|
<div className="image-stack-placeholder">
|
|
<MediaUploadCheck>
|
|
<MediaUpload
|
|
onSelect={onSelectImages}
|
|
allowedTypes={["image"]}
|
|
multiple
|
|
gallery
|
|
render={({ open }) => (
|
|
<Button variant="primary" onClick={open}>
|
|
{__("Ajouter une Image", "image-stack")}
|
|
</Button>
|
|
)}
|
|
/>
|
|
</MediaUploadCheck>
|
|
</div>
|
|
)}
|
|
|
|
{images.map((image, index) => (
|
|
<div
|
|
key={image.id}
|
|
className={`image-stack-item ${
|
|
selectedImageIndex === index ? "is-selected" : ""
|
|
}`}
|
|
onClick={() => setSelectedImageIndex(index)}
|
|
role="button"
|
|
tabIndex={0}
|
|
onKeyDown={(e) => {
|
|
if (e.key === "Enter" || e.key === " ") {
|
|
setSelectedImageIndex(index);
|
|
}
|
|
}}
|
|
style={getImageStyle(image)}
|
|
>
|
|
<img src={image.url} alt={image.alt} />
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|