Plugin Directory

Changeset 3789556


Ignore:
Timestamp:
11/07/2026 12:41:29 PM (less than one hour ago)
Author:
tupacan
Message:

Update to version 1.0.3 from GitHub

Location:
marqueeflow
Files:
14 edited
1 copied

Legend:

Unmodified
Added
Removed
  • marqueeflow/tags/1.0.3/blocks/marqueeflow/editor.css

    r3788849 r3789556  
    123123}
    124124
    125 /* Pro upgrade panel in the Inspector sidebar */
    126 .mf-pro-panel .components-panel__body-toggle {
    127         display: none;
    128 }
    129 
    130 .mf-pro-panel__inner {
    131         padding: 4px 0;
    132 }
    133 
    134 .mf-pro-panel__title {
    135         margin: 0 0 6px;
    136         font-size: 0.8rem;
    137         font-weight: 600;
    138         text-transform: uppercase;
    139         letter-spacing: 0.06em;
    140         color: #1e1e1e;
    141 }
    142 
    143 .mf-pro-panel__features {
    144         margin: 0 0 10px;
    145         font-size: 0.8rem;
    146         color: #757575;
     125/* Compact, optional promotion above the block's settings. */
     126.mf-upgrade-panel p {
     127        margin-top: 0;
     128        font-size: 13px;
    147129        line-height: 1.5;
    148130}
    149131
    150 .mf-pro-panel__code {
    151         display: inline-block;
    152         font-family: monospace;
    153         font-size: 0.62rem;
    154         background: #f0f0f0;
    155         border: 1px solid #ddd;
    156         border-radius: 3px;
    157         padding: 1px 5px;
    158         letter-spacing: 0.04em;
    159         color: #1e1e1e;
     132.mf-upgrade-panel .components-button {
     133        white-space: normal;
     134        height: auto;
     135        min-height: 36px;
    160136}
    161137
    162 .mf-pro-panel__list {
    163         list-style: disc;
    164         margin: 0 0 12px;
    165         padding: 0 0 0 14px;
    166         font-size: 0.8rem;
    167         color: #757575;
    168         line-height: 1.2;
    169 }
    170 
    171 .mf-pro-panel__list li {
    172         margin: 0;
    173         margin-bottom: 6px;
    174 }
    175 
    176 .mf-pro-panel .components-button {
    177         width: 100%;
    178         justify-content: center;
    179         margin: 8px 0;
    180 }
    181 
    182 .mf-pro-panel .components-button:last-child {
    183         margin-bottom: 0;
    184 }
    185 
    186 .mf-pro-panel__disclaimer {
    187         margin: 8px 0 0;
    188         font-size: 0.72rem;
    189         color: #949494;
    190         text-align: center;
     138.mf-upgrade-panel .dashicons-external {
     139        font-size: 16px;
     140        width: 16px;
     141        height: 16px;
     142        margin-left: 6px;
     143        flex-shrink: 0;
    191144}
    192145
  • marqueeflow/tags/1.0.3/build/index.asset.php

    r3788849 r3789556  
    1 <?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '46ea4f9afb782e9b1411');
     1<?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => 'a1a805e7731bf7bed9f7');
  • marqueeflow/tags/1.0.3/build/index.js

    r3788849 r3789556  
    1 (()=>{"use strict";const e=window.wp.hooks,t=window.wp.blocks,l=window.React,a=window.wp.i18n,r=window.wp.blockEditor,o=window.wp.components,n=window.wp.element,i=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"marqueeflow/marqueeflow","title":"MarqueeFlow","description":"A lightweight marquee-style slider for continuously scrolling images","category":"media","icon":"format-gallery","keywords":["marquee","slider","carousel","image","scrolling","banner"],"supports":{"html":false,"align":["wide","full"]},"attributes":{"images":{"type":"array","default":[],"items":{"type":"object","properties":{"id":{"type":"integer"},"url":{"type":"string"},"alt":{"type":"string"},"link":{"type":"string"}}}},"speed":{"type":"string","default":"normal","enum":["slow","normal","fast"]},"imageHeight":{"type":"string","default":"medium","enum":["small","medium","large","custom"]},"gap":{"type":"string","default":"normal","enum":["normal","spacious","custom"]},"pauseOnHover":{"type":"boolean","default":false},"direction":{"type":"string","default":"ltr","enum":["ltr","rtl"]},"customHeight":{"type":"number","default":80},"customGap":{"type":"number","default":64},"borderRadius":{"type":"number","default":0},"opacity":{"type":"number","default":100},"fadeEdges":{"type":"boolean","default":false},"grayscale":{"type":"boolean","default":false},"invertGrayscale":{"type":"boolean","default":false},"maxWidth":{"type":"string","default":"normal","enum":["narrow","normal","medium","wide","none"]}},"example":{"attributes":{"images":[{"id":1,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 1"},{"id":2,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 2"},{"id":3,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 3"},{"id":4,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 4"},{"id":5,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 5"},{"id":6,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 6"}],"speed":"normal","imageHeight":"medium"}},"textdomain":"marqueeflow","editorStyle":"file:./editor.css","style":"marqueeflow-style"}');(0,t.registerBlockType)(i.name,{...i,edit:function(t){const{attributes:i,setAttributes:m}=t,u={...t,apiVersion:1},{images:s,speed:d,imageHeight:g,gap:c,pauseOnHover:f,direction:w,maxWidth:p}=i,[h,_]=(0,n.useState)(!1),[q,y]=(0,n.useState)(""),[v,b]=(0,n.useState)(0),[x,E]=(0,n.useState)("mouse"),C=(0,r.useBlockProps)(),N=(0,n.useRef)({active:!1,index:null}),[S,I]=(0,n.useState)(null),k=(0,n.useRef)(null),A=(0,n.useRef)(null),F=e=>{_(!0);const t=function(e,t){const l=new Set,a=e=>{if("number"!=typeof e.id&&("string"!=typeof e.id||!/^\d+$/.test(e.id)))return null;const t=Number(e.id);return Number.isSafeInteger(t)&&t>0?t:null};return e.map(e=>{const r=a(e),o=t.findIndex((t,o)=>{if(l.has(o)||!t||"object"!=typeof t)return!1;const n=a(t);return null!==r?n===r:null===n&&Boolean(e.url)&&t.url===e.url});return-1!==o&&l.add(o),{...-1===o?{}:t[o],id:e.id,url:e.url,alt:e.alt||""}})}(e,s);m({images:t}),b(0),_(!1)};(0,n.useEffect)(()=>{0!==s.length?v>s.length-1&&b(s.length-1):b(0)},[s.length,v]),(0,n.useEffect)(()=>{if(null===A.current)return;const e=A.current;A.current=null,0!==s.length&&P(e)},[s.length]);const $=(e,t)=>{if(t<0||t>=s.length||e===t)return!1;const l=[...s],[a]=l.splice(e,1);return l.splice(t,0,a),m({images:l}),!0},H=(0,n.useCallback)((e,t)=>{e.target.closest(".marqueeflow-editor__remove, [data-marqueeflow-extension-controls]")||(e.stopPropagation(),E("mouse"),b(t),N.current={active:!0,index:t},I(t),e.currentTarget.setPointerCapture(e.pointerId))},[]),R=(0,n.useCallback)(e=>{if(!N.current.active)return;const t=((e,t)=>{if(!k.current)return null;const l=k.current.querySelectorAll(".marqueeflow-editor__thumb");for(let a=0;a<l.length;a++){const r=l[a].getBoundingClientRect();if(e>=r.left&&e<=r.right&&t>=r.top&&t<=r.bottom)return a}return null})(e.clientX,e.clientY),l=N.current.index;null!==t&&t!==l&&$(l,t)&&(N.current.index=t,I(t))},[s]),M=(0,n.useCallback)(()=>{N.current={active:!1,index:null},I(null)},[]),P=e=>{requestAnimationFrame(()=>{const t=k.current?.querySelector(`[data-thumb-index="${e}"]`);t&&t.focus()})},D=e=>{"Tab"!==e.key||e.shiftKey||(e.preventDefault(),E("keyboard"),P(v))},z=function(e){return{imageHeight:["small","medium","large"].includes(e.imageHeight)?e.imageHeight:"medium",gap:["normal","spacious"].includes(e.gap)?e.gap:"normal"}}(i),B={small:40,medium:60,large:80}[z.imageHeight]||60,L=Number.isFinite(i.borderRadius)?Math.trunc(Math.min(100,Math.max(0,i.borderRadius))):0,O={className:(()=>{const e=["marqueeflow",`marqueeflow--${d}`];return e.push(`marqueeflow--height-${z.imageHeight}`),e.push(`marqueeflow--gap-${z.gap}`),"rtl"===w&&e.push("marqueeflow--rtl"),f&&e.push("marqueeflow--pause-hover"),e.push(`marqueeflow--max-width-${p}`),e.join(" ")})(),style:{"--marqueeflow-total-images":s.length,"--marqueeflow-height":`${B}px`,...L>0?{"--marqueeflow-radius":`${L}px`}:{}}},U=(0,e.applyFilters)("marqueeflow.editor.preview",O,u),j="string"==typeof U?.className?U.className:O.className,T=U?.style&&"object"==typeof U.style&&!Array.isArray(U.style)?U.style:O.style;return(0,l.createElement)(l.Fragment,null,(0,l.createElement)(r.InspectorControls,null,(0,l.createElement)(o.PanelBody,{className:"marqueeflow-inspector-panel",title:(0,a.__)("Images","marqueeflow"),initialOpen:!0},(0,l.createElement)(o.SelectControl,{label:(0,a.__)("Image Height","marqueeflow"),value:g,options:(0,e.applyFilters)("marqueeflow.editor.layoutOptions",[..."custom"===g?[{label:(0,a.__)("Saved setting (using Medium)","marqueeflow"),value:"custom",disabled:!0}]:[],{label:(0,a.__)("Small (40px)","marqueeflow"),value:"small"},{label:(0,a.__)("Medium (60px)","marqueeflow"),value:"medium"},{label:(0,a.__)("Large (80px)","marqueeflow"),value:"large"}],"imageHeight",u),onChange:e=>m({imageHeight:e}),help:(0,a.__)("Images scale proportionally to the set height","marqueeflow")}),(0,e.applyFilters)("marqueeflow.editor.layoutControl",null,"imageHeight",u),(0,l.createElement)(o.SelectControl,{label:(0,a.__)("Max Image Width","marqueeflow"),value:p,options:[{label:(0,a.__)("Narrow (3× height)","marqueeflow"),value:"narrow"},{label:(0,a.__)("Normal (4× height)","marqueeflow"),value:"normal"},{label:(0,a.__)("Medium (5× height)","marqueeflow"),value:"medium"},{label:(0,a.__)("Wide (6× height)","marqueeflow"),value:"wide"},{label:(0,a.__)("None (no limit)","marqueeflow"),value:"none"}],onChange:e=>m({maxWidth:e}),help:(0,a.__)("Limits how wide a single image can grow. Prevents long horizontal images from dominating the strip.","marqueeflow")}),(0,l.createElement)(o.SelectControl,{label:(0,a.__)("Gap Between Images","marqueeflow"),value:c,options:(0,e.applyFilters)("marqueeflow.editor.layoutOptions",[..."custom"===c?[{label:(0,a.__)("Saved setting (using Normal)","marqueeflow"),value:"custom",disabled:!0}]:[],{label:(0,a.__)("Normal","marqueeflow"),value:"normal"},{label:(0,a.__)("Spacious","marqueeflow"),value:"spacious"}],"gap",u),onChange:e=>m({gap:e})}),(0,e.applyFilters)("marqueeflow.editor.layoutControl",null,"gap",u),(0,l.createElement)(o.RangeControl,{label:(0,a.__)("Corner radius (px)","marqueeflow"),value:L,min:0,max:100,onChange:e=>m({borderRadius:null!=e?e:0})}),(0,e.applyFilters)("marqueeflow.editor.appearance",null,u)),(0,l.createElement)(o.PanelBody,{className:"marqueeflow-inspector-panel",title:(0,a.__)("Animation","marqueeflow"),initialOpen:!1},(0,l.createElement)(o.SelectControl,{label:(0,a.__)("Speed","marqueeflow"),value:d,options:[{label:(0,a.__)("Slow","marqueeflow"),value:"slow"},{label:(0,a.__)("Normal","marqueeflow"),value:"normal"},{label:(0,a.__)("Fast","marqueeflow"),value:"fast"}],onChange:e=>m({speed:e})}),(0,l.createElement)(o.SelectControl,{label:(0,a.__)("Direction","marqueeflow"),value:w,options:[{label:(0,a.__)("Left to Right","marqueeflow"),value:"ltr"},{label:(0,a.__)("Right to Left","marqueeflow"),value:"rtl"}],onChange:e=>m({direction:e})}),(0,l.createElement)(o.ToggleControl,{label:(0,a.__)("Pause on Hover","marqueeflow"),checked:f,onChange:e=>m({pauseOnHover:e}),help:(0,a.__)("Stop animation when user hovers over the slider","marqueeflow")}),(0,e.applyFilters)("marqueeflow.editor.animation",null,u)),(0,e.applyFilters)("marqueeflow.editor.inspector",null,u)),(0,l.createElement)("div",{...C},s.length>0&&(0,l.createElement)("div",{className:"marqueeflow-editor__preview"},(0,l.createElement)("span",{className:"marqueeflow-editor__preview-label"},(0,a.__)("Preview","marqueeflow")),(0,l.createElement)("div",{className:j,style:T},["a","b","c"].map((t,a)=>(0,l.createElement)("ul",{key:t,className:"marqueeflow__set","aria-hidden":a>0||void 0,inert:a>0?"":void 0},s.map((r,o)=>(0,l.createElement)("li",{key:`${t}-${o}`,className:"marqueeflow__item"},(0,e.applyFilters)("marqueeflow.editor.image",(0,l.createElement)("img",{src:r.url,alt:r.alt}),r,{...u,index:o,setIndex:a,isDuplicate:a>0}))))))),0===s.length&&(0,l.createElement)(r.MediaUploadCheck,null,(0,l.createElement)(r.MediaUpload,{onSelect:F,allowedTypes:["image"],multiple:!0,value:[],render:({open:e})=>(0,l.createElement)(o.Placeholder,{icon:"format-gallery",label:(0,a.__)("MarqueeFlow","marqueeflow"),instructions:(0,a.__)("Add images to create a continuously scrolling marquee.","marqueeflow")},(0,l.createElement)(o.Button,{variant:"primary",onClick:e},(0,a.__)("Select Images","marqueeflow")))})),s.length>0&&(0,l.createElement)("div",{className:"marqueeflow-editor__management",onKeyDownCapture:()=>E("keyboard"),onPointerDownCapture:()=>E("mouse")},h&&(0,l.createElement)(o.Spinner,null),(0,l.createElement)(r.MediaUploadCheck,null,(0,l.createElement)(r.MediaUpload,{onSelect:F,allowedTypes:["image"],multiple:!0,value:s.map(e=>e.id),render:({open:e})=>(0,l.createElement)(o.Button,{onClick:e,onKeyDown:D,variant:"primary",style:{marginBottom:"12px"}},(0,a.__)("Edit Images","marqueeflow"))})),s.length<6&&(0,l.createElement)("p",{className:"marqueeflow-editor__hint"},(0,a.__)("For a smooth scrolling effect, we recommend at least 6 images.","marqueeflow")),(0,l.createElement)("p",{style:{fontSize:"0.875rem",margin:"0 0 4px"}},(0,a.__)("Selected images:","marqueeflow")," ",(0,l.createElement)("strong",null,s.length),(0,l.createElement)("span",{id:"marqueeflow-editor-keyboard-hint",style:{color:"#757575",marginLeft:"8px",fontSize:"0.8rem"}},"keyboard"===x?(0,a.__)("← → navigate, ↑ ↓ actions, Shift + ← → reorder","marqueeflow"):(0,a.__)("Drag to reorder","marqueeflow"))),(0,l.createElement)("div",{className:"marqueeflow-editor__sr-only",role:"status","aria-live":"polite"},q),(0,l.createElement)("div",{className:"marqueeflow-editor__grid",ref:k,role:"group","aria-label":(0,a.__)("Reorder images","marqueeflow"),onKeyDownCapture:e=>{const{key:t,shiftKey:l}=e;if("ArrowLeft"!==t&&"ArrowUp"!==t&&"ArrowRight"!==t&&"ArrowDown"!==t)return;if(E("keyboard"),e.target.closest('input, textarea, select, [contenteditable="true"], [data-marqueeflow-extension-controls]'))return;const r=e.target.closest(".marqueeflow-editor__thumb");if(!r)return;const o=Number(r.dataset.thumbIndex);if(Number.isNaN(o))return;const n="ArrowLeft"===t||"ArrowRight"===t,i="ArrowUp"===t||"ArrowDown"===t,m=!!e.target.closest(".marqueeflow-editor__remove");if(n){let r=o;if("ArrowLeft"===t?r=o-1:"ArrowRight"===t&&(r=o+1),e.preventDefault(),e.stopPropagation(),l)return void($(o,r)&&(b(r),y((0,a.sprintf)(/* translators: 1: new position, 2: total number of images */ /* translators: 1: new position, 2: total number of images */
    2 (0,a.__)("Image moved to position %1$d of %2$d.","marqueeflow"),r+1,s.length)),P(r)));if(r<0||r>=s.length)return;return b(r),void P(r)}i&&(e.preventDefault(),e.stopPropagation(),b(o),m?P(o):requestAnimationFrame(()=>{const e=k.current?.querySelector(`[data-thumb-index="${o}"] .marqueeflow-editor__remove`);e&&e.focus()}))}},s.map((t,r)=>(0,l.createElement)("div",{key:t.id||r,"data-thumb-index":r,className:"marqueeflow-editor__thumb"+(S===r?" is-dragging":""),tabIndex:r===v?0:-1,"aria-label":(0,a.sprintf)((0,a.__)("Image %1$d of %2$d","marqueeflow"),r+1,s.length),"aria-describedby":"marqueeflow-editor-keyboard-hint",onFocus:()=>b(r),onPointerDown:e=>H(e,r),onPointerMove:R,onPointerUp:M,style:{touchAction:"none"}},(0,l.createElement)("img",{src:t.url,alt:t.alt}),((t,a)=>{const r=(0,e.applyFilters)("marqueeflow.editor.imageControls",null,t,{...u,index:a});return null==r?null:(0,l.createElement)("div",{"data-marqueeflow-extension-controls":!0},r)})(t,r),(0,l.createElement)("button",{className:"marqueeflow-editor__remove",onClick:()=>(e=>{const t=s.filter((t,l)=>l!==e),l=0===t.length?null:Math.min(e,t.length-1);A.current=l,m({images:t}),null===l?(b(0),y((0,a.__)("Image removed.","marqueeflow"))):(b(l),y((0,a.sprintf)(/* translators: 1: new focused position, 2: total number of images */ /* translators: 1: new focused position, 2: total number of images */
    3 (0,a.__)("Image removed. Focus moved to image %1$d of %2$d.","marqueeflow"),l+1,t.length)))})(r),onFocus:()=>b(r),type:"button",tabIndex:-1,"aria-label":(0,a.__)("Remove image","marqueeflow")},"✕")))))))},save:function({attributes:e}){return null}})&&(window.marqueeflowEditorApi=Object.freeze({apiVersion:1,sharedAppearance:!0,sharedLayout:!0,sharedAnimation:!0,blockName:i.name}),(0,e.doAction)("marqueeflow.editor.ready",window.marqueeflowEditorApi))})();
     1(()=>{"use strict";const e=window.wp.hooks,t=window.wp.blocks,a=window.React,l=window.wp.i18n,r=window.wp.blockEditor,o=window.wp.components,n=window.wp.element,i=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"marqueeflow/marqueeflow","title":"MarqueeFlow","description":"A lightweight marquee-style slider for continuously scrolling images","category":"media","icon":"format-gallery","keywords":["marquee","slider","carousel","image","scrolling","banner"],"supports":{"html":false,"align":["wide","full"]},"attributes":{"images":{"type":"array","default":[],"items":{"type":"object","properties":{"id":{"type":"integer"},"url":{"type":"string"},"alt":{"type":"string"},"link":{"type":"string"}}}},"speed":{"type":"string","default":"normal","enum":["slow","normal","fast"]},"imageHeight":{"type":"string","default":"medium","enum":["small","medium","large","custom"]},"gap":{"type":"string","default":"normal","enum":["normal","spacious","custom"]},"pauseOnHover":{"type":"boolean","default":false},"direction":{"type":"string","default":"ltr","enum":["ltr","rtl"]},"customHeight":{"type":"number","default":80},"customGap":{"type":"number","default":64},"borderRadius":{"type":"number","default":0},"opacity":{"type":"number","default":100},"fadeEdges":{"type":"boolean","default":false},"grayscale":{"type":"boolean","default":false},"invertGrayscale":{"type":"boolean","default":false},"maxWidth":{"type":"string","default":"normal","enum":["narrow","normal","medium","wide","none"]}},"example":{"attributes":{"images":[{"id":1,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 1"},{"id":2,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 2"},{"id":3,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 3"},{"id":4,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 4"},{"id":5,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 5"},{"id":6,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 6"}],"speed":"normal","imageHeight":"medium"}},"textdomain":"marqueeflow","editorStyle":"file:./editor.css","style":"marqueeflow-style"}');(0,t.registerBlockType)(i.name,{...i,edit:function(t){const{attributes:i,setAttributes:m}=t,u={...t,apiVersion:1},{images:s,speed:d,imageHeight:g,gap:c,pauseOnHover:f,direction:p,maxWidth:w}=i,[h,_]=(0,n.useState)(!1),[q,y]=(0,n.useState)(""),[v,b]=(0,n.useState)(0),[x,E]=(0,n.useState)("mouse"),C=(0,r.useBlockProps)(),N=(0,n.useRef)({active:!1,index:null}),[S,k]=(0,n.useState)(null),I=(0,n.useRef)(null),A=(0,n.useRef)(null),F=e=>{_(!0);const t=function(e,t){const a=new Set,l=e=>{if("number"!=typeof e.id&&("string"!=typeof e.id||!/^\d+$/.test(e.id)))return null;const t=Number(e.id);return Number.isSafeInteger(t)&&t>0?t:null};return e.map(e=>{const r=l(e),o=t.findIndex((t,o)=>{if(a.has(o)||!t||"object"!=typeof t)return!1;const n=l(t);return null!==r?n===r:null===n&&Boolean(e.url)&&t.url===e.url});return-1!==o&&a.add(o),{...-1===o?{}:t[o],id:e.id,url:e.url,alt:e.alt||""}})}(e,s);m({images:t}),b(0),_(!1)};(0,n.useEffect)(()=>{0!==s.length?v>s.length-1&&b(s.length-1):b(0)},[s.length,v]),(0,n.useEffect)(()=>{if(null===A.current)return;const e=A.current;A.current=null,0!==s.length&&M(e)},[s.length]);const P=(e,t)=>{if(t<0||t>=s.length||e===t)return!1;const a=[...s],[l]=a.splice(e,1);return a.splice(t,0,l),m({images:a}),!0},$=(0,n.useCallback)((e,t)=>{e.target.closest(".marqueeflow-editor__remove, [data-marqueeflow-extension-controls]")||(e.stopPropagation(),E("mouse"),b(t),N.current={active:!0,index:t},k(t),e.currentTarget.setPointerCapture(e.pointerId))},[]),H=(0,n.useCallback)(e=>{if(!N.current.active)return;const t=((e,t)=>{if(!I.current)return null;const a=I.current.querySelectorAll(".marqueeflow-editor__thumb");for(let l=0;l<a.length;l++){const r=a[l].getBoundingClientRect();if(e>=r.left&&e<=r.right&&t>=r.top&&t<=r.bottom)return l}return null})(e.clientX,e.clientY),a=N.current.index;null!==t&&t!==a&&P(a,t)&&(N.current.index=t,k(t))},[s]),R=(0,n.useCallback)(()=>{N.current={active:!1,index:null},k(null)},[]),M=e=>{requestAnimationFrame(()=>{const t=I.current?.querySelector(`[data-thumb-index="${e}"]`);t&&t.focus()})},D=e=>{"Tab"!==e.key||e.shiftKey||(e.preventDefault(),E("keyboard"),M(v))},B=function(e){return{imageHeight:["small","medium","large"].includes(e.imageHeight)?e.imageHeight:"medium",gap:["normal","spacious"].includes(e.gap)?e.gap:"normal"}}(i),z={small:40,medium:60,large:80}[B.imageHeight]||60,O=globalThis?.marqueeflowUpgrade,L=!0===O?.show&&"string"==typeof O.url&&/^https:\/\//.test(O.url),U=Number.isFinite(i.borderRadius)?Math.trunc(Math.min(100,Math.max(0,i.borderRadius))):0,T={className:(()=>{const e=["marqueeflow",`marqueeflow--${d}`];return e.push(`marqueeflow--height-${B.imageHeight}`),e.push(`marqueeflow--gap-${B.gap}`),"rtl"===p&&e.push("marqueeflow--rtl"),f&&e.push("marqueeflow--pause-hover"),e.push(`marqueeflow--max-width-${w}`),e.join(" ")})(),style:{"--marqueeflow-total-images":s.length,"--marqueeflow-height":`${z}px`,...U>0?{"--marqueeflow-radius":`${U}px`}:{}}},j=(0,e.applyFilters)("marqueeflow.editor.preview",T,u),K="string"==typeof j?.className?j.className:T.className,W=j?.style&&"object"==typeof j.style&&!Array.isArray(j.style)?j.style:T.style;return(0,a.createElement)(a.Fragment,null,(0,a.createElement)(r.InspectorControls,null,L&&(0,a.createElement)(o.PanelBody,{className:"mf-upgrade-panel",title:(0,l.__)("MarqueeFlow Pro","marqueeflow"),initialOpen:!0},(0,a.createElement)("p",null,(0,l.__)("Add custom image sizing and spacing, fade edges, opacity and grayscale effects with the Pro add-on.","marqueeflow")),(0,a.createElement)(o.Button,{variant:"primary",href:O.url,target:"_blank",rel:"noopener noreferrer"},(0,l.__)("See Pro plans","marqueeflow"),(0,a.createElement)("span",{className:"dashicons dashicons-external","aria-hidden":"true"}),(0,a.createElement)("span",{className:"marqueeflow-editor__sr-only"},(0,l.__)(" (opens in a new tab)","marqueeflow")))),(0,a.createElement)(o.PanelBody,{className:"marqueeflow-inspector-panel",title:(0,l.__)("Images","marqueeflow"),initialOpen:!0},(0,a.createElement)(o.SelectControl,{label:(0,l.__)("Image Height","marqueeflow"),value:g,options:(0,e.applyFilters)("marqueeflow.editor.layoutOptions",[..."custom"===g?[{label:(0,l.__)("Saved setting (using Medium)","marqueeflow"),value:"custom",disabled:!0}]:[],{label:(0,l.__)("Small (40px)","marqueeflow"),value:"small"},{label:(0,l.__)("Medium (60px)","marqueeflow"),value:"medium"},{label:(0,l.__)("Large (80px)","marqueeflow"),value:"large"}],"imageHeight",u),onChange:e=>m({imageHeight:e}),help:(0,l.__)("Images scale proportionally to the set height","marqueeflow")}),(0,e.applyFilters)("marqueeflow.editor.layoutControl",null,"imageHeight",u),(0,a.createElement)(o.SelectControl,{label:(0,l.__)("Max Image Width","marqueeflow"),value:w,options:[{label:(0,l.__)("Narrow (3× height)","marqueeflow"),value:"narrow"},{label:(0,l.__)("Normal (4× height)","marqueeflow"),value:"normal"},{label:(0,l.__)("Medium (5× height)","marqueeflow"),value:"medium"},{label:(0,l.__)("Wide (6× height)","marqueeflow"),value:"wide"},{label:(0,l.__)("None (no limit)","marqueeflow"),value:"none"}],onChange:e=>m({maxWidth:e}),help:(0,l.__)("Limits how wide a single image can grow. Prevents long horizontal images from dominating the strip.","marqueeflow")}),(0,a.createElement)(o.SelectControl,{label:(0,l.__)("Gap Between Images","marqueeflow"),value:c,options:(0,e.applyFilters)("marqueeflow.editor.layoutOptions",[..."custom"===c?[{label:(0,l.__)("Saved setting (using Normal)","marqueeflow"),value:"custom",disabled:!0}]:[],{label:(0,l.__)("Normal","marqueeflow"),value:"normal"},{label:(0,l.__)("Spacious","marqueeflow"),value:"spacious"}],"gap",u),onChange:e=>m({gap:e})}),(0,e.applyFilters)("marqueeflow.editor.layoutControl",null,"gap",u),(0,a.createElement)(o.RangeControl,{label:(0,l.__)("Corner radius (px)","marqueeflow"),value:U,min:0,max:100,onChange:e=>m({borderRadius:null!=e?e:0})}),(0,e.applyFilters)("marqueeflow.editor.appearance",null,u)),(0,a.createElement)(o.PanelBody,{className:"marqueeflow-inspector-panel",title:(0,l.__)("Animation","marqueeflow"),initialOpen:!1},(0,a.createElement)(o.SelectControl,{label:(0,l.__)("Speed","marqueeflow"),value:d,options:[{label:(0,l.__)("Slow","marqueeflow"),value:"slow"},{label:(0,l.__)("Normal","marqueeflow"),value:"normal"},{label:(0,l.__)("Fast","marqueeflow"),value:"fast"}],onChange:e=>m({speed:e})}),(0,a.createElement)(o.SelectControl,{label:(0,l.__)("Direction","marqueeflow"),value:p,options:[{label:(0,l.__)("Left to Right","marqueeflow"),value:"ltr"},{label:(0,l.__)("Right to Left","marqueeflow"),value:"rtl"}],onChange:e=>m({direction:e})}),(0,a.createElement)(o.ToggleControl,{label:(0,l.__)("Pause on Hover","marqueeflow"),checked:f,onChange:e=>m({pauseOnHover:e}),help:(0,l.__)("Stop animation when user hovers over the slider","marqueeflow")}),(0,e.applyFilters)("marqueeflow.editor.animation",null,u)),(0,e.applyFilters)("marqueeflow.editor.inspector",null,u)),(0,a.createElement)("div",{...C},s.length>0&&(0,a.createElement)("div",{className:"marqueeflow-editor__preview"},(0,a.createElement)("span",{className:"marqueeflow-editor__preview-label"},(0,l.__)("Preview","marqueeflow")),(0,a.createElement)("div",{className:K,style:W},["a","b","c"].map((t,l)=>(0,a.createElement)("ul",{key:t,className:"marqueeflow__set","aria-hidden":l>0||void 0,inert:l>0?"":void 0},s.map((r,o)=>(0,a.createElement)("li",{key:`${t}-${o}`,className:"marqueeflow__item"},(0,e.applyFilters)("marqueeflow.editor.image",(0,a.createElement)("img",{src:r.url,alt:r.alt}),r,{...u,index:o,setIndex:l,isDuplicate:l>0}))))))),0===s.length&&(0,a.createElement)(r.MediaUploadCheck,null,(0,a.createElement)(r.MediaUpload,{onSelect:F,allowedTypes:["image"],multiple:!0,value:[],render:({open:e})=>(0,a.createElement)(o.Placeholder,{icon:"format-gallery",label:(0,l.__)("MarqueeFlow","marqueeflow"),instructions:(0,l.__)("Add images to create a continuously scrolling marquee.","marqueeflow")},(0,a.createElement)(o.Button,{variant:"primary",onClick:e},(0,l.__)("Select Images","marqueeflow")))})),s.length>0&&(0,a.createElement)("div",{className:"marqueeflow-editor__management",onKeyDownCapture:()=>E("keyboard"),onPointerDownCapture:()=>E("mouse")},h&&(0,a.createElement)(o.Spinner,null),(0,a.createElement)(r.MediaUploadCheck,null,(0,a.createElement)(r.MediaUpload,{onSelect:F,allowedTypes:["image"],multiple:!0,value:s.map(e=>e.id),render:({open:e})=>(0,a.createElement)(o.Button,{onClick:e,onKeyDown:D,variant:"primary",style:{marginBottom:"12px"}},(0,l.__)("Edit Images","marqueeflow"))})),s.length<6&&(0,a.createElement)("p",{className:"marqueeflow-editor__hint"},(0,l.__)("For a smooth scrolling effect, we recommend at least 6 images.","marqueeflow")),(0,a.createElement)("p",{style:{fontSize:"0.875rem",margin:"0 0 4px"}},(0,l.__)("Selected images:","marqueeflow")," ",(0,a.createElement)("strong",null,s.length),(0,a.createElement)("span",{id:"marqueeflow-editor-keyboard-hint",style:{color:"#757575",marginLeft:"8px",fontSize:"0.8rem"}},"keyboard"===x?(0,l.__)("← → navigate, ↑ ↓ actions, Shift + ← → reorder","marqueeflow"):(0,l.__)("Drag to reorder","marqueeflow"))),(0,a.createElement)("div",{className:"marqueeflow-editor__sr-only",role:"status","aria-live":"polite"},q),(0,a.createElement)("div",{className:"marqueeflow-editor__grid",ref:I,role:"group","aria-label":(0,l.__)("Reorder images","marqueeflow"),onKeyDownCapture:e=>{const{key:t,shiftKey:a}=e;if("ArrowLeft"!==t&&"ArrowUp"!==t&&"ArrowRight"!==t&&"ArrowDown"!==t)return;if(E("keyboard"),e.target.closest('input, textarea, select, [contenteditable="true"], [data-marqueeflow-extension-controls]'))return;const r=e.target.closest(".marqueeflow-editor__thumb");if(!r)return;const o=Number(r.dataset.thumbIndex);if(Number.isNaN(o))return;const n="ArrowLeft"===t||"ArrowRight"===t,i="ArrowUp"===t||"ArrowDown"===t,m=!!e.target.closest(".marqueeflow-editor__remove");if(n){let r=o;if("ArrowLeft"===t?r=o-1:"ArrowRight"===t&&(r=o+1),e.preventDefault(),e.stopPropagation(),a)return void(P(o,r)&&(b(r),y((0,l.sprintf)(/* translators: 1: new position, 2: total number of images */ /* translators: 1: new position, 2: total number of images */
     2(0,l.__)("Image moved to position %1$d of %2$d.","marqueeflow"),r+1,s.length)),M(r)));if(r<0||r>=s.length)return;return b(r),void M(r)}i&&(e.preventDefault(),e.stopPropagation(),b(o),m?M(o):requestAnimationFrame(()=>{const e=I.current?.querySelector(`[data-thumb-index="${o}"] .marqueeflow-editor__remove`);e&&e.focus()}))}},s.map((t,r)=>(0,a.createElement)("div",{key:t.id||r,"data-thumb-index":r,className:"marqueeflow-editor__thumb"+(S===r?" is-dragging":""),tabIndex:r===v?0:-1,"aria-label":(0,l.sprintf)((0,l.__)("Image %1$d of %2$d","marqueeflow"),r+1,s.length),"aria-describedby":"marqueeflow-editor-keyboard-hint",onFocus:()=>b(r),onPointerDown:e=>$(e,r),onPointerMove:H,onPointerUp:R,style:{touchAction:"none"}},(0,a.createElement)("img",{src:t.url,alt:t.alt}),((t,l)=>{const r=(0,e.applyFilters)("marqueeflow.editor.imageControls",null,t,{...u,index:l});return null==r?null:(0,a.createElement)("div",{"data-marqueeflow-extension-controls":!0},r)})(t,r),(0,a.createElement)("button",{className:"marqueeflow-editor__remove",onClick:()=>(e=>{const t=s.filter((t,a)=>a!==e),a=0===t.length?null:Math.min(e,t.length-1);A.current=a,m({images:t}),null===a?(b(0),y((0,l.__)("Image removed.","marqueeflow"))):(b(a),y((0,l.sprintf)(/* translators: 1: new focused position, 2: total number of images */ /* translators: 1: new focused position, 2: total number of images */
     3(0,l.__)("Image removed. Focus moved to image %1$d of %2$d.","marqueeflow"),a+1,t.length)))})(r),onFocus:()=>b(r),type:"button",tabIndex:-1,"aria-label":(0,l.__)("Remove image","marqueeflow")},"✕")))))))},save:function({attributes:e}){return null}})&&(window.marqueeflowEditorApi=Object.freeze({apiVersion:1,sharedAppearance:!0,sharedLayout:!0,sharedAnimation:!0,blockName:i.name}),(0,e.doAction)("marqueeflow.editor.ready",window.marqueeflowEditorApi))})();
  • marqueeflow/tags/1.0.3/includes/class-mf-block-marqueeflow.php

    r3788849 r3789556  
    5656
    5757                wp_set_script_translations( 'marqueeflow-block-editor', 'marqueeflow' );
     58                wp_add_inline_script(
     59                        'marqueeflow-block-editor',
     60                        'window.marqueeflowUpgrade = ' . wp_json_encode( [
     61                                'show' => ! class_exists( 'MarqueeFlow_Pro_Plugin', false ),
     62                                'url'  => esc_url_raw( MARQUEEFLOW_PRO_URL ),
     63                        ] ) . ';',
     64                        'before'
     65                );
    5866
    5967        }
  • marqueeflow/tags/1.0.3/marqueeflow.php

    r3788849 r3789556  
    44 * Plugin URI:  https://wordpress.org/plugins/marqueeflow/
    55 * Description: A lightweight marquee-style slider for continuously scrolling images.
    6  * Version:     1.0.2
     6 * Version:     1.0.3
    77 * Author:      tupacan
    88 * Author URI:  https://profiles.wordpress.org/tupacan/
    … …  
    110110        private static ?MarqueeFlow_Plugin $instance = null;
    111111
    112         public const VERSION = '1.0.2';
     112        public const VERSION = '1.0.3';
    113113        public const SLUG    = 'marqueeflow';
    114114
    … …  
    129129
    130130                add_action( 'plugins_loaded', [ $this, 'init' ] );
     131                add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), [ $this, 'add_action_links' ] );
    131132        }
    132133
    … …  
    151152        }
    152153
     154        /** Promotion describes the add-on; it never enables paid behavior. */
     155        public function add_action_links( array $links ): array {
     156                if ( class_exists( 'MarqueeFlow_Pro_Plugin', false ) ) {
     157                        return $links;
     158                }
     159                $links[] = '<a href="' . esc_url( MARQUEEFLOW_PRO_URL ) . '" target="_blank" rel="noopener noreferrer">' .
     160                        esc_html__( 'See Pro plans', 'marqueeflow' ) . '</a>';
     161                return $links;
     162        }
     163
    153164        public function init(): void {
    154165                MarqueeFlow_Assets::init();
  • marqueeflow/tags/1.0.3/readme.txt

    r3788849 r3789556  
    44Requires at least: 6.3
    55Tested up to: 7.1
    6 Stable tag: 1.0.2
     6Stable tag: 1.0.3
    77Requires PHP: 8.0
    88License: GPLv2 or later
    … …  
    2323* Max image width control to prevent wide logos from dominating
    2424* Direction control: Left to Right or Right to Left
     25* Image corner radius
    2526* Pause on hover
    2627* Drag-and-drop image reordering in the editor
    … …  
    36373. Adjust speed, height, and style in the sidebar
    37384. Publish
     39
     40= MarqueeFlow Pro add-on =
     41
     42For custom image height and spacing, faded edges, image opacity and grayscale effects, see [MarqueeFlow Pro plans](https://marqueeflow.pages.dev/). Pro is a separate paid add-on and requires this Free plugin to stay installed and active. An eligible activated license is required for paid controls and effects. Free works independently without a license or Freemius SDK.
    3843
    3944== Installation ==
    … …  
    6873== Changelog ==
    6974
     75= 1.0.3 =
     76* Add a compact Pro plans panel in the block sidebar and a plugin-row pricing link.
     77* Hide Free promotion when the separate Pro add-on is active.
     78* Keep all Free controls and frontend behavior unchanged.
     79
    7080= 1.0.2 =
    7181* Reorganized block settings into Images and Animation panels.
  • marqueeflow/tags/1.0.3/src/blocks/marqueeflow/edit.js

    r3788849 r3789556  
    263263        };
    264264
     265        const upgrade = globalThis?.marqueeflowUpgrade;
     266        const showUpgrade = upgrade?.show === true && typeof upgrade.url === 'string' && /^https:\/\//.test( upgrade.url );
     267
    265268        const radius = Number.isFinite( attributes.borderRadius ) ? Math.trunc( Math.min( 100, Math.max( 0, attributes.borderRadius ) ) ) : 0;
    266269        const basePreview = {
    … …  
    280283                <>
    281284                        <InspectorControls>
     285                                { showUpgrade && (
     286                                        <PanelBody className="mf-upgrade-panel" title={ __( 'MarqueeFlow Pro', 'marqueeflow' ) } initialOpen={ true }>
     287                                                <p>{ __( 'Add custom image sizing and spacing, fade edges, opacity and grayscale effects with the Pro add-on.', 'marqueeflow' ) }</p>
     288                                                <Button variant="primary" href={ upgrade.url } target="_blank" rel="noopener noreferrer">
     289                                                        { __( 'See Pro plans', 'marqueeflow' ) }
     290                                                        <span className="dashicons dashicons-external" aria-hidden="true" />
     291                                                        <span className="marqueeflow-editor__sr-only">{ __( ' (opens in a new tab)', 'marqueeflow' ) }</span>
     292                                                </Button>
     293                                        </PanelBody>
     294                                ) }
     295
    282296                                <PanelBody className="marqueeflow-inspector-panel" title={ __( 'Images', 'marqueeflow' ) } initialOpen={ true }>
    283297                                        <SelectControl
  • marqueeflow/trunk/blocks/marqueeflow/editor.css

    r3788849 r3789556  
    123123}
    124124
    125 /* Pro upgrade panel in the Inspector sidebar */
    126 .mf-pro-panel .components-panel__body-toggle {
    127         display: none;
    128 }
    129 
    130 .mf-pro-panel__inner {
    131         padding: 4px 0;
    132 }
    133 
    134 .mf-pro-panel__title {
    135         margin: 0 0 6px;
    136         font-size: 0.8rem;
    137         font-weight: 600;
    138         text-transform: uppercase;
    139         letter-spacing: 0.06em;
    140         color: #1e1e1e;
    141 }
    142 
    143 .mf-pro-panel__features {
    144         margin: 0 0 10px;
    145         font-size: 0.8rem;
    146         color: #757575;
     125/* Compact, optional promotion above the block's settings. */
     126.mf-upgrade-panel p {
     127        margin-top: 0;
     128        font-size: 13px;
    147129        line-height: 1.5;
    148130}
    149131
    150 .mf-pro-panel__code {
    151         display: inline-block;
    152         font-family: monospace;
    153         font-size: 0.62rem;
    154         background: #f0f0f0;
    155         border: 1px solid #ddd;
    156         border-radius: 3px;
    157         padding: 1px 5px;
    158         letter-spacing: 0.04em;
    159         color: #1e1e1e;
     132.mf-upgrade-panel .components-button {
     133        white-space: normal;
     134        height: auto;
     135        min-height: 36px;
    160136}
    161137
    162 .mf-pro-panel__list {
    163         list-style: disc;
    164         margin: 0 0 12px;
    165         padding: 0 0 0 14px;
    166         font-size: 0.8rem;
    167         color: #757575;
    168         line-height: 1.2;
    169 }
    170 
    171 .mf-pro-panel__list li {
    172         margin: 0;
    173         margin-bottom: 6px;
    174 }
    175 
    176 .mf-pro-panel .components-button {
    177         width: 100%;
    178         justify-content: center;
    179         margin: 8px 0;
    180 }
    181 
    182 .mf-pro-panel .components-button:last-child {
    183         margin-bottom: 0;
    184 }
    185 
    186 .mf-pro-panel__disclaimer {
    187         margin: 8px 0 0;
    188         font-size: 0.72rem;
    189         color: #949494;
    190         text-align: center;
     138.mf-upgrade-panel .dashicons-external {
     139        font-size: 16px;
     140        width: 16px;
     141        height: 16px;
     142        margin-left: 6px;
     143        flex-shrink: 0;
    191144}
    192145
  • marqueeflow/trunk/build/index.asset.php

    r3788849 r3789556  
    1 <?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '46ea4f9afb782e9b1411');
     1<?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => 'a1a805e7731bf7bed9f7');
  • marqueeflow/trunk/build/index.js

    r3788849 r3789556  
    1 (()=>{"use strict";const e=window.wp.hooks,t=window.wp.blocks,l=window.React,a=window.wp.i18n,r=window.wp.blockEditor,o=window.wp.components,n=window.wp.element,i=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"marqueeflow/marqueeflow","title":"MarqueeFlow","description":"A lightweight marquee-style slider for continuously scrolling images","category":"media","icon":"format-gallery","keywords":["marquee","slider","carousel","image","scrolling","banner"],"supports":{"html":false,"align":["wide","full"]},"attributes":{"images":{"type":"array","default":[],"items":{"type":"object","properties":{"id":{"type":"integer"},"url":{"type":"string"},"alt":{"type":"string"},"link":{"type":"string"}}}},"speed":{"type":"string","default":"normal","enum":["slow","normal","fast"]},"imageHeight":{"type":"string","default":"medium","enum":["small","medium","large","custom"]},"gap":{"type":"string","default":"normal","enum":["normal","spacious","custom"]},"pauseOnHover":{"type":"boolean","default":false},"direction":{"type":"string","default":"ltr","enum":["ltr","rtl"]},"customHeight":{"type":"number","default":80},"customGap":{"type":"number","default":64},"borderRadius":{"type":"number","default":0},"opacity":{"type":"number","default":100},"fadeEdges":{"type":"boolean","default":false},"grayscale":{"type":"boolean","default":false},"invertGrayscale":{"type":"boolean","default":false},"maxWidth":{"type":"string","default":"normal","enum":["narrow","normal","medium","wide","none"]}},"example":{"attributes":{"images":[{"id":1,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 1"},{"id":2,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 2"},{"id":3,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 3"},{"id":4,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 4"},{"id":5,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 5"},{"id":6,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 6"}],"speed":"normal","imageHeight":"medium"}},"textdomain":"marqueeflow","editorStyle":"file:./editor.css","style":"marqueeflow-style"}');(0,t.registerBlockType)(i.name,{...i,edit:function(t){const{attributes:i,setAttributes:m}=t,u={...t,apiVersion:1},{images:s,speed:d,imageHeight:g,gap:c,pauseOnHover:f,direction:w,maxWidth:p}=i,[h,_]=(0,n.useState)(!1),[q,y]=(0,n.useState)(""),[v,b]=(0,n.useState)(0),[x,E]=(0,n.useState)("mouse"),C=(0,r.useBlockProps)(),N=(0,n.useRef)({active:!1,index:null}),[S,I]=(0,n.useState)(null),k=(0,n.useRef)(null),A=(0,n.useRef)(null),F=e=>{_(!0);const t=function(e,t){const l=new Set,a=e=>{if("number"!=typeof e.id&&("string"!=typeof e.id||!/^\d+$/.test(e.id)))return null;const t=Number(e.id);return Number.isSafeInteger(t)&&t>0?t:null};return e.map(e=>{const r=a(e),o=t.findIndex((t,o)=>{if(l.has(o)||!t||"object"!=typeof t)return!1;const n=a(t);return null!==r?n===r:null===n&&Boolean(e.url)&&t.url===e.url});return-1!==o&&l.add(o),{...-1===o?{}:t[o],id:e.id,url:e.url,alt:e.alt||""}})}(e,s);m({images:t}),b(0),_(!1)};(0,n.useEffect)(()=>{0!==s.length?v>s.length-1&&b(s.length-1):b(0)},[s.length,v]),(0,n.useEffect)(()=>{if(null===A.current)return;const e=A.current;A.current=null,0!==s.length&&P(e)},[s.length]);const $=(e,t)=>{if(t<0||t>=s.length||e===t)return!1;const l=[...s],[a]=l.splice(e,1);return l.splice(t,0,a),m({images:l}),!0},H=(0,n.useCallback)((e,t)=>{e.target.closest(".marqueeflow-editor__remove, [data-marqueeflow-extension-controls]")||(e.stopPropagation(),E("mouse"),b(t),N.current={active:!0,index:t},I(t),e.currentTarget.setPointerCapture(e.pointerId))},[]),R=(0,n.useCallback)(e=>{if(!N.current.active)return;const t=((e,t)=>{if(!k.current)return null;const l=k.current.querySelectorAll(".marqueeflow-editor__thumb");for(let a=0;a<l.length;a++){const r=l[a].getBoundingClientRect();if(e>=r.left&&e<=r.right&&t>=r.top&&t<=r.bottom)return a}return null})(e.clientX,e.clientY),l=N.current.index;null!==t&&t!==l&&$(l,t)&&(N.current.index=t,I(t))},[s]),M=(0,n.useCallback)(()=>{N.current={active:!1,index:null},I(null)},[]),P=e=>{requestAnimationFrame(()=>{const t=k.current?.querySelector(`[data-thumb-index="${e}"]`);t&&t.focus()})},D=e=>{"Tab"!==e.key||e.shiftKey||(e.preventDefault(),E("keyboard"),P(v))},z=function(e){return{imageHeight:["small","medium","large"].includes(e.imageHeight)?e.imageHeight:"medium",gap:["normal","spacious"].includes(e.gap)?e.gap:"normal"}}(i),B={small:40,medium:60,large:80}[z.imageHeight]||60,L=Number.isFinite(i.borderRadius)?Math.trunc(Math.min(100,Math.max(0,i.borderRadius))):0,O={className:(()=>{const e=["marqueeflow",`marqueeflow--${d}`];return e.push(`marqueeflow--height-${z.imageHeight}`),e.push(`marqueeflow--gap-${z.gap}`),"rtl"===w&&e.push("marqueeflow--rtl"),f&&e.push("marqueeflow--pause-hover"),e.push(`marqueeflow--max-width-${p}`),e.join(" ")})(),style:{"--marqueeflow-total-images":s.length,"--marqueeflow-height":`${B}px`,...L>0?{"--marqueeflow-radius":`${L}px`}:{}}},U=(0,e.applyFilters)("marqueeflow.editor.preview",O,u),j="string"==typeof U?.className?U.className:O.className,T=U?.style&&"object"==typeof U.style&&!Array.isArray(U.style)?U.style:O.style;return(0,l.createElement)(l.Fragment,null,(0,l.createElement)(r.InspectorControls,null,(0,l.createElement)(o.PanelBody,{className:"marqueeflow-inspector-panel",title:(0,a.__)("Images","marqueeflow"),initialOpen:!0},(0,l.createElement)(o.SelectControl,{label:(0,a.__)("Image Height","marqueeflow"),value:g,options:(0,e.applyFilters)("marqueeflow.editor.layoutOptions",[..."custom"===g?[{label:(0,a.__)("Saved setting (using Medium)","marqueeflow"),value:"custom",disabled:!0}]:[],{label:(0,a.__)("Small (40px)","marqueeflow"),value:"small"},{label:(0,a.__)("Medium (60px)","marqueeflow"),value:"medium"},{label:(0,a.__)("Large (80px)","marqueeflow"),value:"large"}],"imageHeight",u),onChange:e=>m({imageHeight:e}),help:(0,a.__)("Images scale proportionally to the set height","marqueeflow")}),(0,e.applyFilters)("marqueeflow.editor.layoutControl",null,"imageHeight",u),(0,l.createElement)(o.SelectControl,{label:(0,a.__)("Max Image Width","marqueeflow"),value:p,options:[{label:(0,a.__)("Narrow (3× height)","marqueeflow"),value:"narrow"},{label:(0,a.__)("Normal (4× height)","marqueeflow"),value:"normal"},{label:(0,a.__)("Medium (5× height)","marqueeflow"),value:"medium"},{label:(0,a.__)("Wide (6× height)","marqueeflow"),value:"wide"},{label:(0,a.__)("None (no limit)","marqueeflow"),value:"none"}],onChange:e=>m({maxWidth:e}),help:(0,a.__)("Limits how wide a single image can grow. Prevents long horizontal images from dominating the strip.","marqueeflow")}),(0,l.createElement)(o.SelectControl,{label:(0,a.__)("Gap Between Images","marqueeflow"),value:c,options:(0,e.applyFilters)("marqueeflow.editor.layoutOptions",[..."custom"===c?[{label:(0,a.__)("Saved setting (using Normal)","marqueeflow"),value:"custom",disabled:!0}]:[],{label:(0,a.__)("Normal","marqueeflow"),value:"normal"},{label:(0,a.__)("Spacious","marqueeflow"),value:"spacious"}],"gap",u),onChange:e=>m({gap:e})}),(0,e.applyFilters)("marqueeflow.editor.layoutControl",null,"gap",u),(0,l.createElement)(o.RangeControl,{label:(0,a.__)("Corner radius (px)","marqueeflow"),value:L,min:0,max:100,onChange:e=>m({borderRadius:null!=e?e:0})}),(0,e.applyFilters)("marqueeflow.editor.appearance",null,u)),(0,l.createElement)(o.PanelBody,{className:"marqueeflow-inspector-panel",title:(0,a.__)("Animation","marqueeflow"),initialOpen:!1},(0,l.createElement)(o.SelectControl,{label:(0,a.__)("Speed","marqueeflow"),value:d,options:[{label:(0,a.__)("Slow","marqueeflow"),value:"slow"},{label:(0,a.__)("Normal","marqueeflow"),value:"normal"},{label:(0,a.__)("Fast","marqueeflow"),value:"fast"}],onChange:e=>m({speed:e})}),(0,l.createElement)(o.SelectControl,{label:(0,a.__)("Direction","marqueeflow"),value:w,options:[{label:(0,a.__)("Left to Right","marqueeflow"),value:"ltr"},{label:(0,a.__)("Right to Left","marqueeflow"),value:"rtl"}],onChange:e=>m({direction:e})}),(0,l.createElement)(o.ToggleControl,{label:(0,a.__)("Pause on Hover","marqueeflow"),checked:f,onChange:e=>m({pauseOnHover:e}),help:(0,a.__)("Stop animation when user hovers over the slider","marqueeflow")}),(0,e.applyFilters)("marqueeflow.editor.animation",null,u)),(0,e.applyFilters)("marqueeflow.editor.inspector",null,u)),(0,l.createElement)("div",{...C},s.length>0&&(0,l.createElement)("div",{className:"marqueeflow-editor__preview"},(0,l.createElement)("span",{className:"marqueeflow-editor__preview-label"},(0,a.__)("Preview","marqueeflow")),(0,l.createElement)("div",{className:j,style:T},["a","b","c"].map((t,a)=>(0,l.createElement)("ul",{key:t,className:"marqueeflow__set","aria-hidden":a>0||void 0,inert:a>0?"":void 0},s.map((r,o)=>(0,l.createElement)("li",{key:`${t}-${o}`,className:"marqueeflow__item"},(0,e.applyFilters)("marqueeflow.editor.image",(0,l.createElement)("img",{src:r.url,alt:r.alt}),r,{...u,index:o,setIndex:a,isDuplicate:a>0}))))))),0===s.length&&(0,l.createElement)(r.MediaUploadCheck,null,(0,l.createElement)(r.MediaUpload,{onSelect:F,allowedTypes:["image"],multiple:!0,value:[],render:({open:e})=>(0,l.createElement)(o.Placeholder,{icon:"format-gallery",label:(0,a.__)("MarqueeFlow","marqueeflow"),instructions:(0,a.__)("Add images to create a continuously scrolling marquee.","marqueeflow")},(0,l.createElement)(o.Button,{variant:"primary",onClick:e},(0,a.__)("Select Images","marqueeflow")))})),s.length>0&&(0,l.createElement)("div",{className:"marqueeflow-editor__management",onKeyDownCapture:()=>E("keyboard"),onPointerDownCapture:()=>E("mouse")},h&&(0,l.createElement)(o.Spinner,null),(0,l.createElement)(r.MediaUploadCheck,null,(0,l.createElement)(r.MediaUpload,{onSelect:F,allowedTypes:["image"],multiple:!0,value:s.map(e=>e.id),render:({open:e})=>(0,l.createElement)(o.Button,{onClick:e,onKeyDown:D,variant:"primary",style:{marginBottom:"12px"}},(0,a.__)("Edit Images","marqueeflow"))})),s.length<6&&(0,l.createElement)("p",{className:"marqueeflow-editor__hint"},(0,a.__)("For a smooth scrolling effect, we recommend at least 6 images.","marqueeflow")),(0,l.createElement)("p",{style:{fontSize:"0.875rem",margin:"0 0 4px"}},(0,a.__)("Selected images:","marqueeflow")," ",(0,l.createElement)("strong",null,s.length),(0,l.createElement)("span",{id:"marqueeflow-editor-keyboard-hint",style:{color:"#757575",marginLeft:"8px",fontSize:"0.8rem"}},"keyboard"===x?(0,a.__)("← → navigate, ↑ ↓ actions, Shift + ← → reorder","marqueeflow"):(0,a.__)("Drag to reorder","marqueeflow"))),(0,l.createElement)("div",{className:"marqueeflow-editor__sr-only",role:"status","aria-live":"polite"},q),(0,l.createElement)("div",{className:"marqueeflow-editor__grid",ref:k,role:"group","aria-label":(0,a.__)("Reorder images","marqueeflow"),onKeyDownCapture:e=>{const{key:t,shiftKey:l}=e;if("ArrowLeft"!==t&&"ArrowUp"!==t&&"ArrowRight"!==t&&"ArrowDown"!==t)return;if(E("keyboard"),e.target.closest('input, textarea, select, [contenteditable="true"], [data-marqueeflow-extension-controls]'))return;const r=e.target.closest(".marqueeflow-editor__thumb");if(!r)return;const o=Number(r.dataset.thumbIndex);if(Number.isNaN(o))return;const n="ArrowLeft"===t||"ArrowRight"===t,i="ArrowUp"===t||"ArrowDown"===t,m=!!e.target.closest(".marqueeflow-editor__remove");if(n){let r=o;if("ArrowLeft"===t?r=o-1:"ArrowRight"===t&&(r=o+1),e.preventDefault(),e.stopPropagation(),l)return void($(o,r)&&(b(r),y((0,a.sprintf)(/* translators: 1: new position, 2: total number of images */ /* translators: 1: new position, 2: total number of images */
    2 (0,a.__)("Image moved to position %1$d of %2$d.","marqueeflow"),r+1,s.length)),P(r)));if(r<0||r>=s.length)return;return b(r),void P(r)}i&&(e.preventDefault(),e.stopPropagation(),b(o),m?P(o):requestAnimationFrame(()=>{const e=k.current?.querySelector(`[data-thumb-index="${o}"] .marqueeflow-editor__remove`);e&&e.focus()}))}},s.map((t,r)=>(0,l.createElement)("div",{key:t.id||r,"data-thumb-index":r,className:"marqueeflow-editor__thumb"+(S===r?" is-dragging":""),tabIndex:r===v?0:-1,"aria-label":(0,a.sprintf)((0,a.__)("Image %1$d of %2$d","marqueeflow"),r+1,s.length),"aria-describedby":"marqueeflow-editor-keyboard-hint",onFocus:()=>b(r),onPointerDown:e=>H(e,r),onPointerMove:R,onPointerUp:M,style:{touchAction:"none"}},(0,l.createElement)("img",{src:t.url,alt:t.alt}),((t,a)=>{const r=(0,e.applyFilters)("marqueeflow.editor.imageControls",null,t,{...u,index:a});return null==r?null:(0,l.createElement)("div",{"data-marqueeflow-extension-controls":!0},r)})(t,r),(0,l.createElement)("button",{className:"marqueeflow-editor__remove",onClick:()=>(e=>{const t=s.filter((t,l)=>l!==e),l=0===t.length?null:Math.min(e,t.length-1);A.current=l,m({images:t}),null===l?(b(0),y((0,a.__)("Image removed.","marqueeflow"))):(b(l),y((0,a.sprintf)(/* translators: 1: new focused position, 2: total number of images */ /* translators: 1: new focused position, 2: total number of images */
    3 (0,a.__)("Image removed. Focus moved to image %1$d of %2$d.","marqueeflow"),l+1,t.length)))})(r),onFocus:()=>b(r),type:"button",tabIndex:-1,"aria-label":(0,a.__)("Remove image","marqueeflow")},"✕")))))))},save:function({attributes:e}){return null}})&&(window.marqueeflowEditorApi=Object.freeze({apiVersion:1,sharedAppearance:!0,sharedLayout:!0,sharedAnimation:!0,blockName:i.name}),(0,e.doAction)("marqueeflow.editor.ready",window.marqueeflowEditorApi))})();
     1(()=>{"use strict";const e=window.wp.hooks,t=window.wp.blocks,a=window.React,l=window.wp.i18n,r=window.wp.blockEditor,o=window.wp.components,n=window.wp.element,i=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"marqueeflow/marqueeflow","title":"MarqueeFlow","description":"A lightweight marquee-style slider for continuously scrolling images","category":"media","icon":"format-gallery","keywords":["marquee","slider","carousel","image","scrolling","banner"],"supports":{"html":false,"align":["wide","full"]},"attributes":{"images":{"type":"array","default":[],"items":{"type":"object","properties":{"id":{"type":"integer"},"url":{"type":"string"},"alt":{"type":"string"},"link":{"type":"string"}}}},"speed":{"type":"string","default":"normal","enum":["slow","normal","fast"]},"imageHeight":{"type":"string","default":"medium","enum":["small","medium","large","custom"]},"gap":{"type":"string","default":"normal","enum":["normal","spacious","custom"]},"pauseOnHover":{"type":"boolean","default":false},"direction":{"type":"string","default":"ltr","enum":["ltr","rtl"]},"customHeight":{"type":"number","default":80},"customGap":{"type":"number","default":64},"borderRadius":{"type":"number","default":0},"opacity":{"type":"number","default":100},"fadeEdges":{"type":"boolean","default":false},"grayscale":{"type":"boolean","default":false},"invertGrayscale":{"type":"boolean","default":false},"maxWidth":{"type":"string","default":"normal","enum":["narrow","normal","medium","wide","none"]}},"example":{"attributes":{"images":[{"id":1,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 1"},{"id":2,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 2"},{"id":3,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 3"},{"id":4,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 4"},{"id":5,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 5"},{"id":6,"url":"data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'120\' height=\'80\' fill=\'%23ddd\'%3E%3Crect width=\'120\' height=\'80\' rx=\'4\'/%3E%3Ctext x=\'60\' y=\'44\' text-anchor=\'middle\' font-size=\'12\' fill=\'%23999\'%3EImage%3C/text%3E%3C/svg%3E","alt":"Image 6"}],"speed":"normal","imageHeight":"medium"}},"textdomain":"marqueeflow","editorStyle":"file:./editor.css","style":"marqueeflow-style"}');(0,t.registerBlockType)(i.name,{...i,edit:function(t){const{attributes:i,setAttributes:m}=t,u={...t,apiVersion:1},{images:s,speed:d,imageHeight:g,gap:c,pauseOnHover:f,direction:p,maxWidth:w}=i,[h,_]=(0,n.useState)(!1),[q,y]=(0,n.useState)(""),[v,b]=(0,n.useState)(0),[x,E]=(0,n.useState)("mouse"),C=(0,r.useBlockProps)(),N=(0,n.useRef)({active:!1,index:null}),[S,k]=(0,n.useState)(null),I=(0,n.useRef)(null),A=(0,n.useRef)(null),F=e=>{_(!0);const t=function(e,t){const a=new Set,l=e=>{if("number"!=typeof e.id&&("string"!=typeof e.id||!/^\d+$/.test(e.id)))return null;const t=Number(e.id);return Number.isSafeInteger(t)&&t>0?t:null};return e.map(e=>{const r=l(e),o=t.findIndex((t,o)=>{if(a.has(o)||!t||"object"!=typeof t)return!1;const n=l(t);return null!==r?n===r:null===n&&Boolean(e.url)&&t.url===e.url});return-1!==o&&a.add(o),{...-1===o?{}:t[o],id:e.id,url:e.url,alt:e.alt||""}})}(e,s);m({images:t}),b(0),_(!1)};(0,n.useEffect)(()=>{0!==s.length?v>s.length-1&&b(s.length-1):b(0)},[s.length,v]),(0,n.useEffect)(()=>{if(null===A.current)return;const e=A.current;A.current=null,0!==s.length&&M(e)},[s.length]);const P=(e,t)=>{if(t<0||t>=s.length||e===t)return!1;const a=[...s],[l]=a.splice(e,1);return a.splice(t,0,l),m({images:a}),!0},$=(0,n.useCallback)((e,t)=>{e.target.closest(".marqueeflow-editor__remove, [data-marqueeflow-extension-controls]")||(e.stopPropagation(),E("mouse"),b(t),N.current={active:!0,index:t},k(t),e.currentTarget.setPointerCapture(e.pointerId))},[]),H=(0,n.useCallback)(e=>{if(!N.current.active)return;const t=((e,t)=>{if(!I.current)return null;const a=I.current.querySelectorAll(".marqueeflow-editor__thumb");for(let l=0;l<a.length;l++){const r=a[l].getBoundingClientRect();if(e>=r.left&&e<=r.right&&t>=r.top&&t<=r.bottom)return l}return null})(e.clientX,e.clientY),a=N.current.index;null!==t&&t!==a&&P(a,t)&&(N.current.index=t,k(t))},[s]),R=(0,n.useCallback)(()=>{N.current={active:!1,index:null},k(null)},[]),M=e=>{requestAnimationFrame(()=>{const t=I.current?.querySelector(`[data-thumb-index="${e}"]`);t&&t.focus()})},D=e=>{"Tab"!==e.key||e.shiftKey||(e.preventDefault(),E("keyboard"),M(v))},B=function(e){return{imageHeight:["small","medium","large"].includes(e.imageHeight)?e.imageHeight:"medium",gap:["normal","spacious"].includes(e.gap)?e.gap:"normal"}}(i),z={small:40,medium:60,large:80}[B.imageHeight]||60,O=globalThis?.marqueeflowUpgrade,L=!0===O?.show&&"string"==typeof O.url&&/^https:\/\//.test(O.url),U=Number.isFinite(i.borderRadius)?Math.trunc(Math.min(100,Math.max(0,i.borderRadius))):0,T={className:(()=>{const e=["marqueeflow",`marqueeflow--${d}`];return e.push(`marqueeflow--height-${B.imageHeight}`),e.push(`marqueeflow--gap-${B.gap}`),"rtl"===p&&e.push("marqueeflow--rtl"),f&&e.push("marqueeflow--pause-hover"),e.push(`marqueeflow--max-width-${w}`),e.join(" ")})(),style:{"--marqueeflow-total-images":s.length,"--marqueeflow-height":`${z}px`,...U>0?{"--marqueeflow-radius":`${U}px`}:{}}},j=(0,e.applyFilters)("marqueeflow.editor.preview",T,u),K="string"==typeof j?.className?j.className:T.className,W=j?.style&&"object"==typeof j.style&&!Array.isArray(j.style)?j.style:T.style;return(0,a.createElement)(a.Fragment,null,(0,a.createElement)(r.InspectorControls,null,L&&(0,a.createElement)(o.PanelBody,{className:"mf-upgrade-panel",title:(0,l.__)("MarqueeFlow Pro","marqueeflow"),initialOpen:!0},(0,a.createElement)("p",null,(0,l.__)("Add custom image sizing and spacing, fade edges, opacity and grayscale effects with the Pro add-on.","marqueeflow")),(0,a.createElement)(o.Button,{variant:"primary",href:O.url,target:"_blank",rel:"noopener noreferrer"},(0,l.__)("See Pro plans","marqueeflow"),(0,a.createElement)("span",{className:"dashicons dashicons-external","aria-hidden":"true"}),(0,a.createElement)("span",{className:"marqueeflow-editor__sr-only"},(0,l.__)(" (opens in a new tab)","marqueeflow")))),(0,a.createElement)(o.PanelBody,{className:"marqueeflow-inspector-panel",title:(0,l.__)("Images","marqueeflow"),initialOpen:!0},(0,a.createElement)(o.SelectControl,{label:(0,l.__)("Image Height","marqueeflow"),value:g,options:(0,e.applyFilters)("marqueeflow.editor.layoutOptions",[..."custom"===g?[{label:(0,l.__)("Saved setting (using Medium)","marqueeflow"),value:"custom",disabled:!0}]:[],{label:(0,l.__)("Small (40px)","marqueeflow"),value:"small"},{label:(0,l.__)("Medium (60px)","marqueeflow"),value:"medium"},{label:(0,l.__)("Large (80px)","marqueeflow"),value:"large"}],"imageHeight",u),onChange:e=>m({imageHeight:e}),help:(0,l.__)("Images scale proportionally to the set height","marqueeflow")}),(0,e.applyFilters)("marqueeflow.editor.layoutControl",null,"imageHeight",u),(0,a.createElement)(o.SelectControl,{label:(0,l.__)("Max Image Width","marqueeflow"),value:w,options:[{label:(0,l.__)("Narrow (3× height)","marqueeflow"),value:"narrow"},{label:(0,l.__)("Normal (4× height)","marqueeflow"),value:"normal"},{label:(0,l.__)("Medium (5× height)","marqueeflow"),value:"medium"},{label:(0,l.__)("Wide (6× height)","marqueeflow"),value:"wide"},{label:(0,l.__)("None (no limit)","marqueeflow"),value:"none"}],onChange:e=>m({maxWidth:e}),help:(0,l.__)("Limits how wide a single image can grow. Prevents long horizontal images from dominating the strip.","marqueeflow")}),(0,a.createElement)(o.SelectControl,{label:(0,l.__)("Gap Between Images","marqueeflow"),value:c,options:(0,e.applyFilters)("marqueeflow.editor.layoutOptions",[..."custom"===c?[{label:(0,l.__)("Saved setting (using Normal)","marqueeflow"),value:"custom",disabled:!0}]:[],{label:(0,l.__)("Normal","marqueeflow"),value:"normal"},{label:(0,l.__)("Spacious","marqueeflow"),value:"spacious"}],"gap",u),onChange:e=>m({gap:e})}),(0,e.applyFilters)("marqueeflow.editor.layoutControl",null,"gap",u),(0,a.createElement)(o.RangeControl,{label:(0,l.__)("Corner radius (px)","marqueeflow"),value:U,min:0,max:100,onChange:e=>m({borderRadius:null!=e?e:0})}),(0,e.applyFilters)("marqueeflow.editor.appearance",null,u)),(0,a.createElement)(o.PanelBody,{className:"marqueeflow-inspector-panel",title:(0,l.__)("Animation","marqueeflow"),initialOpen:!1},(0,a.createElement)(o.SelectControl,{label:(0,l.__)("Speed","marqueeflow"),value:d,options:[{label:(0,l.__)("Slow","marqueeflow"),value:"slow"},{label:(0,l.__)("Normal","marqueeflow"),value:"normal"},{label:(0,l.__)("Fast","marqueeflow"),value:"fast"}],onChange:e=>m({speed:e})}),(0,a.createElement)(o.SelectControl,{label:(0,l.__)("Direction","marqueeflow"),value:p,options:[{label:(0,l.__)("Left to Right","marqueeflow"),value:"ltr"},{label:(0,l.__)("Right to Left","marqueeflow"),value:"rtl"}],onChange:e=>m({direction:e})}),(0,a.createElement)(o.ToggleControl,{label:(0,l.__)("Pause on Hover","marqueeflow"),checked:f,onChange:e=>m({pauseOnHover:e}),help:(0,l.__)("Stop animation when user hovers over the slider","marqueeflow")}),(0,e.applyFilters)("marqueeflow.editor.animation",null,u)),(0,e.applyFilters)("marqueeflow.editor.inspector",null,u)),(0,a.createElement)("div",{...C},s.length>0&&(0,a.createElement)("div",{className:"marqueeflow-editor__preview"},(0,a.createElement)("span",{className:"marqueeflow-editor__preview-label"},(0,l.__)("Preview","marqueeflow")),(0,a.createElement)("div",{className:K,style:W},["a","b","c"].map((t,l)=>(0,a.createElement)("ul",{key:t,className:"marqueeflow__set","aria-hidden":l>0||void 0,inert:l>0?"":void 0},s.map((r,o)=>(0,a.createElement)("li",{key:`${t}-${o}`,className:"marqueeflow__item"},(0,e.applyFilters)("marqueeflow.editor.image",(0,a.createElement)("img",{src:r.url,alt:r.alt}),r,{...u,index:o,setIndex:l,isDuplicate:l>0}))))))),0===s.length&&(0,a.createElement)(r.MediaUploadCheck,null,(0,a.createElement)(r.MediaUpload,{onSelect:F,allowedTypes:["image"],multiple:!0,value:[],render:({open:e})=>(0,a.createElement)(o.Placeholder,{icon:"format-gallery",label:(0,l.__)("MarqueeFlow","marqueeflow"),instructions:(0,l.__)("Add images to create a continuously scrolling marquee.","marqueeflow")},(0,a.createElement)(o.Button,{variant:"primary",onClick:e},(0,l.__)("Select Images","marqueeflow")))})),s.length>0&&(0,a.createElement)("div",{className:"marqueeflow-editor__management",onKeyDownCapture:()=>E("keyboard"),onPointerDownCapture:()=>E("mouse")},h&&(0,a.createElement)(o.Spinner,null),(0,a.createElement)(r.MediaUploadCheck,null,(0,a.createElement)(r.MediaUpload,{onSelect:F,allowedTypes:["image"],multiple:!0,value:s.map(e=>e.id),render:({open:e})=>(0,a.createElement)(o.Button,{onClick:e,onKeyDown:D,variant:"primary",style:{marginBottom:"12px"}},(0,l.__)("Edit Images","marqueeflow"))})),s.length<6&&(0,a.createElement)("p",{className:"marqueeflow-editor__hint"},(0,l.__)("For a smooth scrolling effect, we recommend at least 6 images.","marqueeflow")),(0,a.createElement)("p",{style:{fontSize:"0.875rem",margin:"0 0 4px"}},(0,l.__)("Selected images:","marqueeflow")," ",(0,a.createElement)("strong",null,s.length),(0,a.createElement)("span",{id:"marqueeflow-editor-keyboard-hint",style:{color:"#757575",marginLeft:"8px",fontSize:"0.8rem"}},"keyboard"===x?(0,l.__)("← → navigate, ↑ ↓ actions, Shift + ← → reorder","marqueeflow"):(0,l.__)("Drag to reorder","marqueeflow"))),(0,a.createElement)("div",{className:"marqueeflow-editor__sr-only",role:"status","aria-live":"polite"},q),(0,a.createElement)("div",{className:"marqueeflow-editor__grid",ref:I,role:"group","aria-label":(0,l.__)("Reorder images","marqueeflow"),onKeyDownCapture:e=>{const{key:t,shiftKey:a}=e;if("ArrowLeft"!==t&&"ArrowUp"!==t&&"ArrowRight"!==t&&"ArrowDown"!==t)return;if(E("keyboard"),e.target.closest('input, textarea, select, [contenteditable="true"], [data-marqueeflow-extension-controls]'))return;const r=e.target.closest(".marqueeflow-editor__thumb");if(!r)return;const o=Number(r.dataset.thumbIndex);if(Number.isNaN(o))return;const n="ArrowLeft"===t||"ArrowRight"===t,i="ArrowUp"===t||"ArrowDown"===t,m=!!e.target.closest(".marqueeflow-editor__remove");if(n){let r=o;if("ArrowLeft"===t?r=o-1:"ArrowRight"===t&&(r=o+1),e.preventDefault(),e.stopPropagation(),a)return void(P(o,r)&&(b(r),y((0,l.sprintf)(/* translators: 1: new position, 2: total number of images */ /* translators: 1: new position, 2: total number of images */
     2(0,l.__)("Image moved to position %1$d of %2$d.","marqueeflow"),r+1,s.length)),M(r)));if(r<0||r>=s.length)return;return b(r),void M(r)}i&&(e.preventDefault(),e.stopPropagation(),b(o),m?M(o):requestAnimationFrame(()=>{const e=I.current?.querySelector(`[data-thumb-index="${o}"] .marqueeflow-editor__remove`);e&&e.focus()}))}},s.map((t,r)=>(0,a.createElement)("div",{key:t.id||r,"data-thumb-index":r,className:"marqueeflow-editor__thumb"+(S===r?" is-dragging":""),tabIndex:r===v?0:-1,"aria-label":(0,l.sprintf)((0,l.__)("Image %1$d of %2$d","marqueeflow"),r+1,s.length),"aria-describedby":"marqueeflow-editor-keyboard-hint",onFocus:()=>b(r),onPointerDown:e=>$(e,r),onPointerMove:H,onPointerUp:R,style:{touchAction:"none"}},(0,a.createElement)("img",{src:t.url,alt:t.alt}),((t,l)=>{const r=(0,e.applyFilters)("marqueeflow.editor.imageControls",null,t,{...u,index:l});return null==r?null:(0,a.createElement)("div",{"data-marqueeflow-extension-controls":!0},r)})(t,r),(0,a.createElement)("button",{className:"marqueeflow-editor__remove",onClick:()=>(e=>{const t=s.filter((t,a)=>a!==e),a=0===t.length?null:Math.min(e,t.length-1);A.current=a,m({images:t}),null===a?(b(0),y((0,l.__)("Image removed.","marqueeflow"))):(b(a),y((0,l.sprintf)(/* translators: 1: new focused position, 2: total number of images */ /* translators: 1: new focused position, 2: total number of images */
     3(0,l.__)("Image removed. Focus moved to image %1$d of %2$d.","marqueeflow"),a+1,t.length)))})(r),onFocus:()=>b(r),type:"button",tabIndex:-1,"aria-label":(0,l.__)("Remove image","marqueeflow")},"✕")))))))},save:function({attributes:e}){return null}})&&(window.marqueeflowEditorApi=Object.freeze({apiVersion:1,sharedAppearance:!0,sharedLayout:!0,sharedAnimation:!0,blockName:i.name}),(0,e.doAction)("marqueeflow.editor.ready",window.marqueeflowEditorApi))})();
  • marqueeflow/trunk/includes/class-mf-block-marqueeflow.php

    r3788849 r3789556  
    5656
    5757                wp_set_script_translations( 'marqueeflow-block-editor', 'marqueeflow' );
     58                wp_add_inline_script(
     59                        'marqueeflow-block-editor',
     60                        'window.marqueeflowUpgrade = ' . wp_json_encode( [
     61                                'show' => ! class_exists( 'MarqueeFlow_Pro_Plugin', false ),
     62                                'url'  => esc_url_raw( MARQUEEFLOW_PRO_URL ),
     63                        ] ) . ';',
     64                        'before'
     65                );
    5866
    5967        }
  • marqueeflow/trunk/marqueeflow.php

    r3788849 r3789556  
    44 * Plugin URI:  https://wordpress.org/plugins/marqueeflow/
    55 * Description: A lightweight marquee-style slider for continuously scrolling images.
    6  * Version:     1.0.2
     6 * Version:     1.0.3
    77 * Author:      tupacan
    88 * Author URI:  https://profiles.wordpress.org/tupacan/
    … …  
    110110        private static ?MarqueeFlow_Plugin $instance = null;
    111111
    112         public const VERSION = '1.0.2';
     112        public const VERSION = '1.0.3';
    113113        public const SLUG    = 'marqueeflow';
    114114
    … …  
    129129
    130130                add_action( 'plugins_loaded', [ $this, 'init' ] );
     131                add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), [ $this, 'add_action_links' ] );
    131132        }
    132133
    … …  
    151152        }
    152153
     154        /** Promotion describes the add-on; it never enables paid behavior. */
     155        public function add_action_links( array $links ): array {
     156                if ( class_exists( 'MarqueeFlow_Pro_Plugin', false ) ) {
     157                        return $links;
     158                }
     159                $links[] = '<a href="' . esc_url( MARQUEEFLOW_PRO_URL ) . '" target="_blank" rel="noopener noreferrer">' .
     160                        esc_html__( 'See Pro plans', 'marqueeflow' ) . '</a>';
     161                return $links;
     162        }
     163
    153164        public function init(): void {
    154165                MarqueeFlow_Assets::init();
  • marqueeflow/trunk/readme.txt

    r3788849 r3789556  
    44Requires at least: 6.3
    55Tested up to: 7.1
    6 Stable tag: 1.0.2
     6Stable tag: 1.0.3
    77Requires PHP: 8.0
    88License: GPLv2 or later
    … …  
    2323* Max image width control to prevent wide logos from dominating
    2424* Direction control: Left to Right or Right to Left
     25* Image corner radius
    2526* Pause on hover
    2627* Drag-and-drop image reordering in the editor
    … …  
    36373. Adjust speed, height, and style in the sidebar
    37384. Publish
     39
     40= MarqueeFlow Pro add-on =
     41
     42For custom image height and spacing, faded edges, image opacity and grayscale effects, see [MarqueeFlow Pro plans](https://marqueeflow.pages.dev/). Pro is a separate paid add-on and requires this Free plugin to stay installed and active. An eligible activated license is required for paid controls and effects. Free works independently without a license or Freemius SDK.
    3843
    3944== Installation ==
    … …  
    6873== Changelog ==
    6974
     75= 1.0.3 =
     76* Add a compact Pro plans panel in the block sidebar and a plugin-row pricing link.
     77* Hide Free promotion when the separate Pro add-on is active.
     78* Keep all Free controls and frontend behavior unchanged.
     79
    7080= 1.0.2 =
    7181* Reorganized block settings into Images and Animation panels.
  • marqueeflow/trunk/src/blocks/marqueeflow/edit.js

    r3788849 r3789556  
    263263        };
    264264
     265        const upgrade = globalThis?.marqueeflowUpgrade;
     266        const showUpgrade = upgrade?.show === true && typeof upgrade.url === 'string' && /^https:\/\//.test( upgrade.url );
     267
    265268        const radius = Number.isFinite( attributes.borderRadius ) ? Math.trunc( Math.min( 100, Math.max( 0, attributes.borderRadius ) ) ) : 0;
    266269        const basePreview = {
    … …  
    280283                <>
    281284                        <InspectorControls>
     285                                { showUpgrade && (
     286                                        <PanelBody className="mf-upgrade-panel" title={ __( 'MarqueeFlow Pro', 'marqueeflow' ) } initialOpen={ true }>
     287                                                <p>{ __( 'Add custom image sizing and spacing, fade edges, opacity and grayscale effects with the Pro add-on.', 'marqueeflow' ) }</p>
     288                                                <Button variant="primary" href={ upgrade.url } target="_blank" rel="noopener noreferrer">
     289                                                        { __( 'See Pro plans', 'marqueeflow' ) }
     290                                                        <span className="dashicons dashicons-external" aria-hidden="true" />
     291                                                        <span className="marqueeflow-editor__sr-only">{ __( ' (opens in a new tab)', 'marqueeflow' ) }</span>
     292                                                </Button>
     293                                        </PanelBody>
     294                                ) }
     295
    282296                                <PanelBody className="marqueeflow-inspector-panel" title={ __( 'Images', 'marqueeflow' ) } initialOpen={ true }>
    283297                                        <SelectControl
Note: See TracChangeset for help on using the changeset viewer.