//edit.js
|
import { __ } from '@wordpress/i18n';
|
import {
|
useBlockProps,
|
InspectorControls,
|
MediaUpload,
|
MediaUploadCheck,
|
InnerBlocks,
|
useInnerBlocksProps
|
} from '@wordpress/block-editor';
|
import {
|
PanelBody,
|
Button,
|
ToggleControl,
|
BaseControl,
|
RangeControl,
|
SelectControl
|
} from '@wordpress/components';
|
import './editor.scss';
|
|
const ALLOWED_VIDEO_TYPES = ['video'];
|
|
const INNER_BLOCKS_TEMPLATE = [
|
['core/heading', {
|
level: 1,
|
placeholder: 'Add heading...',
|
textAlign: 'center'
|
}],
|
['core/paragraph', {
|
placeholder: 'Add description...',
|
align: 'center'
|
}],
|
['core/buttons', {
|
layout: { type: 'flex', justifyContent: 'center' }
|
}]
|
];
|
|
|
|
export default function Edit({ attributes, setAttributes }) {
|
const {
|
posterId,
|
posterUrl,
|
videoSources,
|
fadeEffect,
|
overlayOpacity,
|
contentAlignment,
|
minHeight
|
} = attributes;
|
|
const blockProps = useBlockProps({
|
className: 'video-cover-editor',
|
style: {
|
minHeight: minHeight ? `${minHeight}px` : undefined
|
}
|
});
|
|
const innerBlocksProps = useInnerBlocksProps(
|
{ className: 'video-cover-content' },
|
{
|
template: INNER_BLOCKS_TEMPLATE,
|
templateLock: false
|
}
|
);
|
|
const onSelectPoster = (media) => {
|
setAttributes({
|
posterId: media.id,
|
posterUrl: media.url
|
});
|
};
|
|
const onSelectVideos = (mediaItems) => {
|
// multiple=true returns an array
|
const items = Array.isArray(mediaItems) ? mediaItems : [mediaItems];
|
const newSources = items
|
.filter(media => !videoSources.some(s => s.id === media.id))
|
.map(media => ({
|
id: media.id,
|
url: media.url,
|
mime: media.mime
|
}));
|
|
if (newSources.length) {
|
setAttributes({
|
videoSources: [...videoSources, ...newSources]
|
});
|
}
|
};
|
|
const removeVideoSource = (index) => {
|
const updated = [...videoSources];
|
updated.splice(index, 1);
|
setAttributes({ videoSources: updated });
|
};
|
|
const renderVideoSourceList = (sources, isMobile = false) => {
|
if (sources.length === 0) return null;
|
|
return (
|
<ul className="video-source-list">
|
{sources.map((source, index) => (
|
<li key={index} className="video-source-item">
|
<span className="video-source-mime">{source.mime}</span>
|
<Button
|
isDestructive
|
isSmall
|
onClick={() => removeVideoSource(index, isMobile)}
|
>
|
{__('Remove', 'jvb')}
|
</Button>
|
</li>
|
))}
|
</ul>
|
);
|
};
|
|
return (
|
<>
|
<InspectorControls>
|
<PanelBody title={__('Video Settings', 'jvb')} initialOpen={true}>
|
<BaseControl
|
label={__('Poster Image', 'jvb')}
|
help={__('Image shown while video loads', 'jvb')}
|
>
|
<MediaUploadCheck>
|
<MediaUpload
|
onSelect={onSelectPoster}
|
allowedTypes={['image']}
|
value={posterId}
|
render={({ open }) => (
|
<>
|
{posterUrl && (
|
<img
|
src={posterUrl}
|
alt={__('Poster preview', 'jvb')}
|
style={{ maxWidth: '100%', marginBottom: '10px' }}
|
/>
|
)}
|
<Button
|
onClick={open}
|
variant={posterUrl ? 'secondary' : 'primary'}
|
>
|
{posterUrl
|
? __('Change Poster', 'jvb')
|
: __('Select Poster', 'jvb')}
|
</Button>
|
{posterUrl && (
|
<Button
|
isDestructive
|
onClick={() => setAttributes({ posterId: 0, posterUrl: '' })}
|
style={{ marginLeft: '10px' }}
|
>
|
{__('Remove', 'jvb')}
|
</Button>
|
)}
|
</>
|
)}
|
/>
|
</MediaUploadCheck>
|
</BaseControl>
|
|
<BaseControl
|
label={__('Video Sources', 'jvb')}
|
help={__('Add multiple formats for better browser support (mp4, webm, etc.)', 'jvb')}
|
>
|
{videoSources.length > 0 && (
|
<ul className="video-source-list">
|
{videoSources.map((source, index) => (
|
<li key={index} className="video-source-item">
|
<span className="video-source-mime">{source.mime}</span>
|
<Button
|
isDestructive
|
isSmall
|
onClick={() => removeVideoSource(index)}
|
>
|
{__('Remove', 'jvb')}
|
</Button>
|
</li>
|
))}
|
</ul>
|
)}
|
<MediaUploadCheck>
|
<MediaUpload
|
multiple={true}
|
onSelect={onSelectVideos}
|
allowedTypes={ALLOWED_VIDEO_TYPES}
|
render={({ open }) => (
|
<Button onClick={open} variant="secondary">
|
{__('Add Video', 'jvb')}
|
</Button>
|
)}
|
/>
|
</MediaUploadCheck>
|
</BaseControl>
|
|
<ToggleControl
|
label={__('Fade Effect', 'jvb')}
|
help={__('Add fade class to video element', 'jvb')}
|
checked={fadeEffect}
|
onChange={(value) => setAttributes({ fadeEffect: value })}
|
/>
|
</PanelBody>
|
|
<PanelBody title={__('Overlay Settings', 'jvb')} initialOpen={true}>
|
<RangeControl
|
label={__('Overlay Opacity', 'jvb')}
|
help={__('Darken video for better text readability', 'jvb')}
|
value={overlayOpacity}
|
onChange={(value) => setAttributes({ overlayOpacity: value })}
|
min={0}
|
max={100}
|
step={5}
|
/>
|
|
<SelectControl
|
label={__('Content Alignment', 'jvb')}
|
value={contentAlignment}
|
options={[
|
{ label: __('Top Left', 'jvb'), value: 'top-left' },
|
{ label: __('Top Center', 'jvb'), value: 'top-center' },
|
{ label: __('Top Right', 'jvb'), value: 'top-right' },
|
{ label: __('Center Left', 'jvb'), value: 'center-left' },
|
{ label: __('Center', 'jvb'), value: 'center' },
|
{ label: __('Center Right', 'jvb'), value: 'center-right' },
|
{ label: __('Bottom Left', 'jvb'), value: 'bottom-left' },
|
{ label: __('Bottom Center', 'jvb'), value: 'bottom-center' },
|
{ label: __('Bottom Right', 'jvb'), value: 'bottom-right' }
|
]}
|
onChange={(value) => setAttributes({ contentAlignment: value })}
|
/>
|
|
<RangeControl
|
label={__('Minimum Height', 'jvb')}
|
help={__('Minimum height in pixels (leave 0 for auto)', 'jvb')}
|
value={minHeight}
|
onChange={(value) => setAttributes({ minHeight: value })}
|
min={0}
|
max={1000}
|
step={50}
|
/>
|
</PanelBody>
|
</InspectorControls>
|
|
<div {...blockProps}>
|
{posterUrl || videoSources.length > 0 ? (
|
<div className="video-cover-preview">
|
{posterUrl && (
|
<>
|
<img src={posterUrl} alt={__('Video poster', 'jvb')} />
|
{overlayOpacity > 0 && (
|
<div
|
className="video-overlay-preview"
|
style={{ opacity: overlayOpacity / 100 }}
|
/>
|
)}
|
</>
|
)}
|
<div className={`video-cover-content-preview align-${contentAlignment}`}>
|
<div {...innerBlocksProps} />
|
</div>
|
<div className="video-info">
|
<p>
|
{videoSources.length} {__('desktop source(s)', 'jvb')}
|
</p>
|
</div>
|
</div>
|
) : (
|
<div className="video-cover-placeholder">
|
<p>{__('Configure video sources in the sidebar →', 'jvb')}</p>
|
</div>
|
)}
|
</div>
|
</>
|
);
|
}
|