Jake Vanderwerf
5 days ago a9b3b28d001941921aa70d37fdc87c758a163a44
src/video/edit.js
New file
@@ -0,0 +1,276 @@
//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>
      </>
   );
}