From d928a0e8fd2f70593706ac184491038978ce9f21 Mon Sep 17 00:00:00 2001 From: Jeremy Rangel Date: Wed, 1 Jan 2025 18:09:33 -0800 Subject: [PATCH] Added theme archvier and changes to blocks --- functions.php | 14 ++ .../build/index.asset.php | 2 +- .../lcp-header-container/build/index.js | 2 +- .../lcp-header-container/build/view.asset.php | 2 +- .../blocks/lcp-header-container/build/view.js | 2 +- .../lcp-header-container.php | 30 +++ .../blocks/lcp-header-container/src/edit.js | 172 +++++------------- .../blocks/lcp-header-container/src/view.js | 21 ++- includes/blocks/lcp-viewport/build/block.json | 4 + .../blocks/lcp-viewport/build/index.asset.php | 2 +- includes/blocks/lcp-viewport/build/index.js | 2 +- .../blocks/lcp-viewport/build/view.asset.php | 2 +- includes/blocks/lcp-viewport/build/view.js | 1 - includes/blocks/lcp-viewport/src/block.json | 4 + includes/blocks/lcp-viewport/src/edit.js | 111 +++++++++-- includes/blocks/lcp-viewport/src/save.js | 16 +- includes/blocks/lcp-viewport/src/view.js | 1 - package.json | 10 + script.js | 9 +- style.css | 4 + zip-theme.js | 89 +++++++++ 21 files changed, 342 insertions(+), 158 deletions(-) create mode 100644 package.json create mode 100644 zip-theme.js diff --git a/functions.php b/functions.php index 6d480ef..39ce1a6 100644 --- a/functions.php +++ b/functions.php @@ -401,3 +401,17 @@ function mytheme_uninstall_icon_set() { } add_action('wp_ajax_uninstall_icon_set', 'mytheme_uninstall_icon_set'); + + +/* Add Styles */ +function lcp_header_height_style() { + // Fetch the lcp_header_height value from wp_options. + $header_height = get_option('lcp_header_height', 0); // Default to 0 if not found + + // Ensure we have a valid value + if ($header_height) { + // Output the inline style tag with the CSS variable for header height + echo ""; + } +} +add_action('wp_head', 'lcp_header_height_style'); diff --git a/includes/blocks/lcp-header-container/build/index.asset.php b/includes/blocks/lcp-header-container/build/index.asset.php index 350d393..4a48edb 100644 --- a/includes/blocks/lcp-header-container/build/index.asset.php +++ b/includes/blocks/lcp-header-container/build/index.asset.php @@ -1 +1 @@ - array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n'), 'version' => '92128317eaa465727f6e'); + array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n'), 'version' => '5d694dedd074dafba412'); diff --git a/includes/blocks/lcp-header-container/build/index.js b/includes/blocks/lcp-header-container/build/index.js index 4e3a704..dbe721f 100644 --- a/includes/blocks/lcp-header-container/build/index.js +++ b/includes/blocks/lcp-header-container/build/index.js @@ -1 +1 @@ -(()=>{"use strict";var e,t={717:()=>{const e=window.wp.blocks,t=window.wp.i18n,l=window.wp.blockEditor,n=window.wp.components,r=window.React,o=window.ReactJSXRuntime,s=JSON.parse('{"UU":"lcp/header-container"}');(0,e.registerBlockType)(s.UU,{edit:function({attributes:e,setAttributes:s}){const[i,a]=(0,r.useState)(!1),[d,p]=(0,r.useState)("10px"),[c,h]=(0,r.useState)("10px"),[x,g]=(0,r.useState)("10px"),[u,v]=(0,r.useState)("10px"),{sticky:f}=e,m=(0,l.useBlockProps)();return(0,o.jsxs)("div",{...m,children:[(0,o.jsxs)(l.InspectorControls,{children:[(0,o.jsx)(n.SelectControl,{label:(0,t.__)("Sticky Behavior","lcp"),value:f,options:[{label:(0,t.__)("Never","lcp"),value:"never"},{label:(0,t.__)("On Scroll","lcp"),value:"onScroll"},{label:(0,t.__)("Always","lcp"),value:"always"}],onChange:e=>{s({sticky:e})}}),(0,o.jsxs)(n.BaseControl,{label:"Padding - Desktop",children:[(0,o.jsxs)("div",{style:{display:"flex",flexDirection:"row"},children:[(0,o.jsx)("span",{style:{marginRight:"10px"},children:"Padding"}),(0,o.jsx)(n.ToggleControl,{label:"Use Independent Padding",checked:i,onChange:()=>{a(!i)}})]}),i?(0,o.jsxs)("div",{style:{display:"grid",padding:"10px",gridTemplateColumns:"1fr 1fr",gap:"10px",justifyItems:"center"},children:[(0,o.jsxs)("fieldset",{style:{gridColumn:"span 2",width:"116px"},children:[(0,o.jsx)("legend",{children:"Top"}),(0,o.jsx)(n.__experimentalUnitControl,{value:d,onChange:e=>{p(e),s({paddingTop:e})}})]}),(0,o.jsxs)("fieldset",{children:[(0,o.jsx)("legend",{children:"Left"}),(0,o.jsx)(n.__experimentalUnitControl,{value:u,onChange:e=>{v(e),s({paddingLeft:e})}})]}),(0,o.jsxs)("fieldset",{children:[(0,o.jsx)("legend",{children:"Right"}),(0,o.jsx)(n.__experimentalUnitControl,{value:c,onChange:e=>{h(e),s({paddingRight:e})}})]}),(0,o.jsxs)("fieldset",{style:{gridColumn:"span 2",width:"116px"},children:[(0,o.jsx)("legend",{children:"Bottom"}),(0,o.jsx)(n.__experimentalUnitControl,{value:x,onChange:e=>{g(e),s({paddingBottom:e})}})]})]}):(0,o.jsx)(n.__experimentalUnitControl,{label:"Padding Value",value:999,onChange:e=>{s({padding:{extraLarge:{top:e,right:e,bottom:e,left:e},large:{top:e,right:e,bottom:e,left:e},medium:{top:e,right:e,bottom:e,left:e},small:{top:e,right:e,bottom:e,left:e}}})}})]})]}),(0,o.jsx)(l.InnerBlocks,{template:[["core/template-part",{slug:"header"}]]})]})},save:function({attributes:e}){const{sticky:t}=e,n=l.useBlockProps.save();let r="";"onScroll"===t?r="lcp-sticky-on-scroll":"always"===t&&(r="lcp-sticky");const s=`${n.className} ${r}`;return(0,o.jsx)("div",{...n,className:s,id:"lcp-header-container",children:(0,o.jsx)(l.InnerBlocks.Content,{})})}})}},l={};function n(e){var r=l[e];if(void 0!==r)return r.exports;var o=l[e]={exports:{}};return t[e](o,o.exports,n),o.exports}n.m=t,e=[],n.O=(t,l,r,o)=>{if(!l){var s=1/0;for(p=0;p=o)&&Object.keys(n.O).every((e=>n.O[e](l[a])))?l.splice(a--,1):(i=!1,o0&&e[p-1][2]>o;p--)e[p]=e[p-1];e[p]=[l,r,o]},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={57:0,350:0};n.O.j=t=>0===e[t];var t=(t,l)=>{var r,o,s=l[0],i=l[1],a=l[2],d=0;if(s.some((t=>0!==e[t]))){for(r in i)n.o(i,r)&&(n.m[r]=i[r]);if(a)var p=a(n)}for(t&&t(l);dn(717)));r=n.O(r)})(); \ No newline at end of file +(()=>{"use strict";var e,n={717:()=>{const e=window.wp.blocks,n=window.React,t=window.wp.i18n,r=window.wp.blockEditor,o=window.wp.components,s=window.ReactJSXRuntime,c=JSON.parse('{"UU":"lcp/header-container"}');(0,e.registerBlockType)(c.UU,{edit:function({attributes:e,setAttributes:c}){const[l,i]=(0,n.useState)(!1),{sticky:a}=e,p=(0,n.useRef)(null),h=(0,r.useBlockProps)({ref:p});return(0,n.useEffect)((()=>{const e=p.current;if(!e)return;const n=new ResizeObserver((()=>{const n=e.getBoundingClientRect().height;fetch("/wp-json/lcp/v1/set-header-height",{method:"POST",headers:{"Content-Type":"application/json","X-WP-Nonce":wpApiSettings.nonce},body:JSON.stringify({height:n})}).then((e=>e.json())).then((e=>{console.log("Height saved:",e)})).catch((e=>{console.error("Error saving height:",e)}))}));return n.observe(e),()=>n.disconnect()}),[]),(0,s.jsxs)("div",{...h,children:[(0,s.jsx)(r.InspectorControls,{children:(0,s.jsx)(o.SelectControl,{label:(0,t.__)("Sticky Behavior","lcp"),value:a,options:[{label:(0,t.__)("Never","lcp"),value:"never"},{label:(0,t.__)("On Scroll","lcp"),value:"onScroll"},{label:(0,t.__)("Always","lcp"),value:"always"}],onChange:e=>c({sticky:e})})}),(0,s.jsx)("div",{id:"lcp-header-container",children:(0,s.jsx)(r.InnerBlocks,{})})]})},save:function({attributes:e}){const{sticky:n}=e,t=r.useBlockProps.save();let o="";"onScroll"===n?o="lcp-sticky-on-scroll":"always"===n&&(o="lcp-sticky");const c=`${t.className} ${o}`;return(0,s.jsx)("div",{...t,className:c,id:"lcp-header-container",children:(0,s.jsx)(r.InnerBlocks.Content,{})})}})}},t={};function r(e){var o=t[e];if(void 0!==o)return o.exports;var s=t[e]={exports:{}};return n[e](s,s.exports,r),s.exports}r.m=n,e=[],r.O=(n,t,o,s)=>{if(!t){var c=1/0;for(p=0;p=s)&&Object.keys(r.O).every((e=>r.O[e](t[i])))?t.splice(i--,1):(l=!1,s0&&e[p-1][2]>s;p--)e[p]=e[p-1];e[p]=[t,o,s]},r.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),(()=>{var e={57:0,350:0};r.O.j=n=>0===e[n];var n=(n,t)=>{var o,s,c=t[0],l=t[1],i=t[2],a=0;if(c.some((n=>0!==e[n]))){for(o in l)r.o(l,o)&&(r.m[o]=l[o]);if(i)var p=i(r)}for(n&&n(t);ar(717)));o=r.O(o)})(); \ No newline at end of file diff --git a/includes/blocks/lcp-header-container/build/view.asset.php b/includes/blocks/lcp-header-container/build/view.asset.php index 3cee5e3..e9fa76d 100644 --- a/includes/blocks/lcp-header-container/build/view.asset.php +++ b/includes/blocks/lcp-header-container/build/view.asset.php @@ -1 +1 @@ - array(), 'version' => 'd4e4a494008d04e1eb42'); + array(), 'version' => '187056d57d17d681fe72'); diff --git a/includes/blocks/lcp-header-container/build/view.js b/includes/blocks/lcp-header-container/build/view.js index f0b02e4..8f648d2 100644 --- a/includes/blocks/lcp-header-container/build/view.js +++ b/includes/blocks/lcp-header-container/build/view.js @@ -1 +1 @@ -console.log("Hello World! (from create-block-lcp-viewport block)"); \ No newline at end of file +document.addEventListener("DOMContentLoaded",(function(){var e=document.getElementById("lcp-header-container");if(e){var t=e.offsetHeight;getComputedStyle(document.documentElement).getPropertyValue("--lcp--header--height").trim()!==t+"px"&&document.documentElement.style.setProperty("--lcp--header--height",t+"px")}})); \ No newline at end of file diff --git a/includes/blocks/lcp-header-container/lcp-header-container.php b/includes/blocks/lcp-header-container/lcp-header-container.php index e7a2356..7bc6723 100644 --- a/includes/blocks/lcp-header-container/lcp-header-container.php +++ b/includes/blocks/lcp-header-container/lcp-header-container.php @@ -31,3 +31,33 @@ function lcp_header_container_block_init() { ); } add_action( 'init', 'lcp_header_container_block_init' ); + + +/* REST API TO UPDATE OPTIONS */ +// Register custom REST API endpoint +function lcp_register_rest_route() { + register_rest_route('lcp/v1', '/set-header-height', array( + 'methods' => 'POST', + 'callback' => 'lcp_set_header_height', + 'permission_callback' => function () { + return current_user_can('manage_options'); // Ensure the user has permission + }, + )); +} + +add_action('rest_api_init', 'lcp_register_rest_route'); + +// Callback to save the height to wp_options +function lcp_set_header_height(WP_REST_Request $request) { + $height = $request->get_param('height'); + + if (is_numeric($height)) { + update_option('lcp_header_height', $height); + return new WP_REST_Response(array('message' => 'Height saved successfully'), 200); + } + + return new WP_REST_Response(array('message' => 'Invalid height value'), 400); +} + + + diff --git a/includes/blocks/lcp-header-container/src/edit.js b/includes/blocks/lcp-header-container/src/edit.js index f11d6f7..b57316a 100644 --- a/includes/blocks/lcp-header-container/src/edit.js +++ b/includes/blocks/lcp-header-container/src/edit.js @@ -1,73 +1,61 @@ -/** - * Retrieves the translation of text. - * - * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-i18n/ - */ +import { useEffect, useRef, useState } from 'react'; import { __ } from '@wordpress/i18n'; - -/** - * React hook that is used to mark the block wrapper element. - * It provides all the necessary props like the class name. - * - * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops - */ import { useBlockProps, InnerBlocks, InspectorControls } from '@wordpress/block-editor'; -import { SelectControl, BaseControl, ToggleControl,__experimentalUnitControl as UnitControl } from '@wordpress/components'; -import { useState, useEffect } from 'react'; -/** - * Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files. - * Those files can contain any CSS code that gets applied to the editor. - * - * @see https://www.npmjs.com/package/@wordpress/scripts#using-css - */ +import { SelectControl, BaseControl, ToggleControl, __experimentalUnitControl as UnitControl } from '@wordpress/components'; import './editor.scss'; -/** - * The edit function describes the structure of your block in the context of the - * editor. This represents what the editor will render when the block is used. - * - * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit - * - * @return {Element} Element to render. - */ export default function Edit({ attributes, setAttributes }) { - const [isIndependentLarge, setIsIndependentLarge] = useState(false); - - const [paddingTop, setPaddingTop] = useState('10px'); - const [paddingRight, setPaddingRight] = useState('10px'); - const [paddingBottom, setPaddingBottom] = useState('10px'); - const [paddingLeft, setPaddingLeft] = useState('10px'); - const { sticky } = attributes; + const blockRef = useRef(null); // Ref to the block container element + // Block props for the outer block - const blockProps = useBlockProps(); + const blockProps = useBlockProps({ + ref: blockRef, + }); - // Handle the change of the sticky attribute - const handleStickyChange = (value) => { - setAttributes({ sticky: value }); - }; - const handleToggleChange = () => { - setIsIndependentLarge(!isIndependentLarge); - }; + // Use ResizeObserver to monitor height changes + useEffect(() => { + const blockElement = blockRef.current; + if (!blockElement) return; - const updatePaddingForAllSizes = (newValue) => { - const newPadding = { - extraLarge: { top: newValue, right: newValue, bottom: newValue, left: newValue }, - large: { top: newValue, right: newValue, bottom: newValue, left: newValue }, - medium: { top: newValue, right: newValue, bottom: newValue, left: newValue }, - small: { top: newValue, right: newValue, bottom: newValue, left: newValue } - }; + // ResizeObserver to monitor changes in the block's size + const resizeObserver = new ResizeObserver(() => { + // Get the height using getBoundingClientRect (this avoids issues with offsets) + const rect = blockElement.getBoundingClientRect(); + const height = rect.height; // Use the height property from getBoundingClientRect() - // Update the padding attribute with the new padding object - setAttributes({ padding: newPadding }); - }; + // Send the height to a custom REST API endpoint + fetch('/wp-json/lcp/v1/set-header-height', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-WP-Nonce': wpApiSettings.nonce, // Ensure you have the nonce for security + }, + body: JSON.stringify({ + height, + }), + }) + .then((response) => response.json()) + .then((data) => { + console.log('Height saved:', data); + }) + .catch((error) => { + console.error('Error saving height:', error); + }); + }); + // Observe the block element for resize changes + resizeObserver.observe(blockElement); + + // Cleanup the observer when the component unmounts + return () => resizeObserver.disconnect(); + }, []); return (
- {/* Inspector Controls: Add a SelectControl to change the sticky attribute */} + {/* Inspector Controls */} setAttributes({ sticky: value })} /> - -
- Padding - -
- - {/* Padding controls */} - {isIndependentLarge ? ( -
- {/* Padding controls for top, left, right, bottom */} -
- Top - { - setPaddingTop(newValue); - setAttributes({ paddingTop: newValue }); - }} - /> -
-
- Left - { - setPaddingLeft(newValue); - setAttributes({ paddingLeft: newValue }); - }} - /> -
-
- Right - { - setPaddingRight(newValue); - setAttributes({ paddingRight: newValue }); - }} - /> -
-
- Bottom - { - setPaddingBottom(newValue); - setAttributes({ paddingBottom: newValue }); - }} - /> -
-
- ) : ( - - )} -
+ {/* Other controls */}
- - - +
+ +
); } diff --git a/includes/blocks/lcp-header-container/src/view.js b/includes/blocks/lcp-header-container/src/view.js index e2a7ec6..b989abb 100644 --- a/includes/blocks/lcp-header-container/src/view.js +++ b/includes/blocks/lcp-header-container/src/view.js @@ -21,5 +21,22 @@ */ /* eslint-disable no-console */ -console.log( 'Hello World! (from create-block-lcp-viewport block)' ); -/* eslint-enable no-console */ +document.addEventListener('DOMContentLoaded', function() { + // Get the element with the id "lcp-header-container" + var headerContainer = document.getElementById('lcp-header-container'); + + // Check if the element exists + if (headerContainer) { + // Get the height of the header container + var headerHeight = headerContainer.offsetHeight; + + // Get the current value of the --lcp--header--height custom property + var currentHeaderHeight = getComputedStyle(document.documentElement).getPropertyValue('--lcp--header--height').trim(); + + // Compare if the current value is different from the new headerHeight (in px) + if (currentHeaderHeight !== headerHeight + 'px') { + // If they are different, update the --lcp--header--height custom property + document.documentElement.style.setProperty('--lcp--header--height', headerHeight + 'px'); + } + } +}); diff --git a/includes/blocks/lcp-viewport/build/block.json b/includes/blocks/lcp-viewport/build/block.json index a2693ad..aeda567 100644 --- a/includes/blocks/lcp-viewport/build/block.json +++ b/includes/blocks/lcp-viewport/build/block.json @@ -19,6 +19,10 @@ "hasSidecontent": { "type": "boolean", "default": false + }, + "hasStickyHeader": { + "type": "boolean", + "default": false } }, "textdomain": "lcp-viewport", diff --git a/includes/blocks/lcp-viewport/build/index.asset.php b/includes/blocks/lcp-viewport/build/index.asset.php index fe80c80..531a1e9 100644 --- a/includes/blocks/lcp-viewport/build/index.asset.php +++ b/includes/blocks/lcp-viewport/build/index.asset.php @@ -1 +1 @@ - array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '6fbadff15d92199f61a3'); + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => 'a54c989d69efb5b39b31'); diff --git a/includes/blocks/lcp-viewport/build/index.js b/includes/blocks/lcp-viewport/build/index.js index 17ef466..8fab74f 100644 --- a/includes/blocks/lcp-viewport/build/index.js +++ b/includes/blocks/lcp-viewport/build/index.js @@ -1 +1 @@ -(()=>{"use strict";var e,t={771:()=>{const e=window.wp.blocks,t=window.wp.i18n,n=window.wp.blockEditor,o=window.wp.components,r=window.wp.element,c=window.ReactJSXRuntime,i=JSON.parse('{"UU":"lcp/viewport"}');(0,e.registerBlockType)(i.UU,{edit:function({attributes:i,setAttributes:s,clientId:l}){const{hasSidecontent:p}=i,d=(0,n.useBlockProps)({className:p?"has-sidecontent":""}),a=[p?["lcp/sidecontent"]:null,["lcp/header-container"],,["lcp/main-area"],["lcp/footer-container"]].filter(Boolean);return(0,r.useEffect)((()=>{if(p){const t=(0,e.createBlock)("lcp/sidecontent",{});wp.data.select("core/block-editor").getBlocks(l),wp.data.dispatch("core/block-editor").insertBlocks(t,1,l)}}),[p,l]),(0,c.jsxs)("div",{...d,children:[(0,c.jsx)(n.InspectorControls,{children:(0,c.jsx)(o.ToggleControl,{label:(0,t.__)("Include Side Content","lcp-viewport"),checked:p,onChange:e=>s({hasSidecontent:e})})}),(0,c.jsx)("div",{id:"lcp-viewport-outer",children:(0,c.jsx)("div",{id:"lcp-viewport-inner",children:(0,c.jsx)(n.InnerBlocks,{renderAppender:()=>(0,c.jsx)(n.InnerBlocks.ButtonBlockAppender,{}),template:a})})})]})},save:function({attributes:e}){const{hasSidecontent:t}=e,o=(n.useBlockProps.save(),t?"lcp-has-sidecontent":"");return(0,c.jsx)("div",{class:o,id:"lcp-viewport-outer",children:(0,c.jsx)("div",{id:"lcp-viewport-inner",class:o,children:(0,c.jsx)(n.InnerBlocks.Content,{})})})}})}},n={};function o(e){var r=n[e];if(void 0!==r)return r.exports;var c=n[e]={exports:{}};return t[e](c,c.exports,o),c.exports}o.m=t,e=[],o.O=(t,n,r,c)=>{if(!n){var i=1/0;for(d=0;d=c)&&Object.keys(o.O).every((e=>o.O[e](n[l])))?n.splice(l--,1):(s=!1,c0&&e[d-1][2]>c;d--)e[d]=e[d-1];e[d]=[n,r,c]},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={57:0,350:0};o.O.j=t=>0===e[t];var t=(t,n)=>{var r,c,i=n[0],s=n[1],l=n[2],p=0;if(i.some((t=>0!==e[t]))){for(r in s)o.o(s,r)&&(o.m[r]=s[r]);if(l)var d=l(o)}for(t&&t(n);po(771)));r=o.O(r)})(); \ No newline at end of file +(()=>{"use strict";var e,t={199:()=>{const e=window.wp.blocks,t=window.wp.i18n,o=window.wp.blockEditor,c=window.wp.components,n=window.wp.element,r=window.wp.data,i=window.ReactJSXRuntime,s=JSON.parse('{"UU":"lcp/viewport"}');(0,e.registerBlockType)(s.UU,{edit:function({attributes:s,setAttributes:l,clientId:a}){const{hasSidecontent:d,hasStickyHeader:p}=s,[u,w]=(0,n.useState)(!1),[k,h]=(0,n.useState)(!1),[v,f]=(0,n.useState)(!1),[b,B]=(0,n.useState)(null),x=(0,o.useBlockProps)({className:d?"has-sidecontent":""}),j=[d?["lcp/sidecontent"]:null,["lcp/header-container"],["lcp/main-area"],["lcp/footer-container"]].filter(Boolean);(0,n.useEffect)((()=>{if(d){const t=(0,e.createBlock)("lcp/sidecontent",{});wp.data.dispatch("core/block-editor").insertBlocks(t,1,a)}}),[d,a]),(0,n.useEffect)((()=>{const e=(0,r.subscribe)((()=>{const e=wp.data.select("core/block-editor").getBlocks();if(k||v)return;const t=e.find((e=>e.clientId!==a&&!wp.data.select("core/block-editor").getBlockParents(e.clientId).includes(a)));t&&(B(t),w(!0),f(!0))}));return()=>{e()}}),[a,k,v]);const m=()=>{if(b){const e=wp.data.select("core/block-editor").getBlocks(a).find((e=>"lcp/main-area"===e.name));e&&(console.log(e),wp.data.dispatch("core/block-editor").insertBlocks(b,e.clientId,0))}w(!1)};return(0,n.useEffect)((()=>{v&&h(!1)}),[v]),(0,r.useSelect)((e=>e("core/block-editor").getBlocks(x.clientId)),[x.clientId]),(0,i.jsxs)("div",{...x,children:[(0,i.jsx)(o.InspectorControls,{children:(0,i.jsx)(c.ToggleControl,{label:(0,t.__)("Include Side Content","lcp-viewport"),checked:d,onChange:e=>l({hasSidecontent:e})})}),(0,i.jsx)("div",{id:"lcp-viewport-outer",children:(0,i.jsx)("div",{id:"lcp-viewport-inner",children:(0,i.jsx)(o.InnerBlocks,{renderAppender:()=>(0,i.jsx)(o.InnerBlocks.ButtonBlockAppender,{}),template:j})})}),u&&!k&&(0,i.jsxs)(c.Modal,{title:(0,t.__)("Block Outside Viewport","lcp-viewport"),onRequestClose:m,className:"block-outside-popup",children:[(0,i.jsx)("p",{children:(0,t.__)("You added a block outside of the lcp/viewport container. Please make sure the block is inside the appropriate area.","lcp-viewport")}),(0,i.jsx)(c.Button,{isPrimary:!0,onClick:m,children:(0,t.__)("Close","lcp-viewport")}),(0,i.jsx)(c.Button,{isSecondary:!0,onClick:()=>{h(!0),w(!1)},children:(0,t.__)("Ignore","lcp-viewport")})]})]})},save:function({attributes:e}){const{hasSidecontent:t,hasStickyHeader:c}=e;o.useBlockProps.save();let n="";return t&&(n+="lcp-has-sidecontent "),c&&(n+="lcp-has-sticky-header"),(0,i.jsx)("div",{className:n,id:"lcp-viewport-outer",children:(0,i.jsx)("div",{id:"lcp-viewport-inner",className:n,children:(0,i.jsx)(o.InnerBlocks.Content,{})})})}})}},o={};function c(e){var n=o[e];if(void 0!==n)return n.exports;var r=o[e]={exports:{}};return t[e](r,r.exports,c),r.exports}c.m=t,e=[],c.O=(t,o,n,r)=>{if(!o){var i=1/0;for(d=0;d=r)&&Object.keys(c.O).every((e=>c.O[e](o[l])))?o.splice(l--,1):(s=!1,r0&&e[d-1][2]>r;d--)e[d]=e[d-1];e[d]=[o,n,r]},c.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={57:0,350:0};c.O.j=t=>0===e[t];var t=(t,o)=>{var n,r,i=o[0],s=o[1],l=o[2],a=0;if(i.some((t=>0!==e[t]))){for(n in s)c.o(s,n)&&(c.m[n]=s[n]);if(l)var d=l(c)}for(t&&t(o);ac(199)));n=c.O(n)})(); \ No newline at end of file diff --git a/includes/blocks/lcp-viewport/build/view.asset.php b/includes/blocks/lcp-viewport/build/view.asset.php index 3cee5e3..f534533 100644 --- a/includes/blocks/lcp-viewport/build/view.asset.php +++ b/includes/blocks/lcp-viewport/build/view.asset.php @@ -1 +1 @@ - array(), 'version' => 'd4e4a494008d04e1eb42'); + array(), 'version' => '31d6cfe0d16ae931b73c'); diff --git a/includes/blocks/lcp-viewport/build/view.js b/includes/blocks/lcp-viewport/build/view.js index f0b02e4..e69de29 100644 --- a/includes/blocks/lcp-viewport/build/view.js +++ b/includes/blocks/lcp-viewport/build/view.js @@ -1 +0,0 @@ -console.log("Hello World! (from create-block-lcp-viewport block)"); \ No newline at end of file diff --git a/includes/blocks/lcp-viewport/src/block.json b/includes/blocks/lcp-viewport/src/block.json index 46d796c..bac1b06 100644 --- a/includes/blocks/lcp-viewport/src/block.json +++ b/includes/blocks/lcp-viewport/src/block.json @@ -19,6 +19,10 @@ "hasSidecontent":{ "type":"boolean", "default":false + }, + "hasStickyHeader":{ + "type":"boolean", + "default":false } }, "textdomain": "lcp-viewport", diff --git a/includes/blocks/lcp-viewport/src/edit.js b/includes/blocks/lcp-viewport/src/edit.js index 3422544..6f6048a 100644 --- a/includes/blocks/lcp-viewport/src/edit.js +++ b/includes/blocks/lcp-viewport/src/edit.js @@ -1,13 +1,20 @@ import { __ } from '@wordpress/i18n'; import { useBlockProps, InnerBlocks, InspectorControls } from '@wordpress/block-editor'; import { ToggleControl } from '@wordpress/components'; -import { useEffect } from '@wordpress/element'; +import { useEffect, useState } from '@wordpress/element'; import { createBlock } from '@wordpress/blocks'; // Used for creating new blocks - +import { useSelect, subscribe } from '@wordpress/data'; // Import subscribe +import { Modal, Button } from '@wordpress/components'; // Import Modal for popup import './editor.scss'; export default function Edit({ attributes, setAttributes, clientId }) { - const { hasSidecontent } = attributes; + const { hasSidecontent, hasStickyHeader } = attributes; + + // Popup visibility state + const [isPopupVisible, setIsPopupVisible] = useState(false); + const [hasIgnoredPopup, setHasIgnoredPopup] = useState(false); // Track if user has ignored the popup + const [blockAdded, setBlockAdded] = useState(false); // Track whether a block has been added + const [addedBlock, setAddedBlock] = useState(null); // Track the block that was added outside of viewport // Block props with custom className management const blockProps = useBlockProps({ @@ -18,7 +25,6 @@ export default function Edit({ attributes, setAttributes, clientId }) { const template = [ hasSidecontent ? ['lcp/sidecontent'] : null, // Only include 'lcp/sidecontent' if `hasSidecontent` is true ['lcp/header-container'], // Add initial content to header-container - , // Always include 'lcp/header-container' and add a paragraph block inside it ['lcp/main-area'], // Always include 'lcp/main-area' ['lcp/footer-container'] // Always include 'lcp/footer-container' ].filter(Boolean); // Remove any null or undefined values from the array @@ -32,18 +38,84 @@ export default function Edit({ attributes, setAttributes, clientId }) { useEffect(() => { if (hasSidecontent) { // Create a new block and insert it in the block's inner blocks - const blockToAdd = createBlock('lcp/sidecontent', { - - }); - - // Insert the block programmatically into the block - const innerBlocks = wp.data.select('core/block-editor').getBlocks(clientId); - - wp.data.dispatch('core/block-editor').insertBlocks(blockToAdd, 1, clientId); // Insert at position 0 - + const blockToAdd = createBlock('lcp/sidecontent', {}); + wp.data.dispatch('core/block-editor').insertBlocks(blockToAdd, 1, clientId); // Insert at position 0 } }, [hasSidecontent, clientId]); // Only runs when `hasSidecontent` or `clientId` changes + // Track block additions and show popup if block is outside the lcp/viewport + useEffect(() => { + const unsubscribe = subscribe(() => { + const blocks = wp.data.select('core/block-editor').getBlocks(); // Get all blocks + + // If the popup is ignored, don't check for outside blocks + if (hasIgnoredPopup || blockAdded) return; + + // Check if any block added is outside the lcp/viewport (excluding lcp/viewport itself) + const addedBlockOutside = blocks.find((block) => { + if (block.clientId === clientId) { + // Skip the current block (lcp/viewport) + return false; + } + const parent = wp.data.select('core/block-editor').getBlockParents(block.clientId); + // If the block is not inside lcp/viewport or its children, show popup + return !parent.includes(clientId); + }); + + if (addedBlockOutside) { + setAddedBlock(addedBlockOutside); // Store the added block + setIsPopupVisible(true); // Show the popup if block is outside + setBlockAdded(true); // Mark that a block has been added + } + }); + + // Cleanup the subscription on component unmount + return () => { + unsubscribe(); + }; + }, [clientId, hasIgnoredPopup, blockAdded]); // Reset check when block is added or state changes + + // Handle the popup close + const closePopup = () => { + // Check if an added block exists + if (addedBlock) { + // Retrieve the parent block (main area) + const mainAreaBlock = wp.data.select('core/block-editor').getBlocks(clientId) + .find(block => block.name === 'lcp/main-area'); // Find the 'lcp/main-area' block + + if (mainAreaBlock) { + console.log(mainAreaBlock) + // Insert the block into the 'lcp/main-area' + wp.data.dispatch('core/block-editor').insertBlocks( + addedBlock, // The block to insert + mainAreaBlock.clientId, // Specify the clientId of the main-area block + 0 // Insert at the start (index 0) of the main-area block's InnerBlocks + ); + } + } + // Close the popup after moving the block + setIsPopupVisible(false); + }; + + // Handle the "Ignore" button click to dismiss popup and not show again until next block addition + const ignorePopup = () => { + setHasIgnoredPopup(true); // Set the state to indicate the user has ignored the popup + setIsPopupVisible(false); // Close the popup + }; + + // Reset the "Ignore" state when a new block is added (for the next block addition) + useEffect(() => { + if (blockAdded) { + // Reset ignore state after a new block has been added + setHasIgnoredPopup(false); + } + }, [blockAdded]); // Trigger when blockAdded state changes + + // Use useSelect to subscribe to the state of inner blocks + const innerBlocks = useSelect((select) => { + return select('core/block-editor').getBlocks(blockProps.clientId); + }, [blockProps.clientId]); + return (
{/* Inspector Controls: Add a toggle for the `hasSidecontent` attribute */} @@ -64,6 +136,19 @@ export default function Edit({ attributes, setAttributes, clientId }) { />
+ + {/* Modal for Popup */} + {isPopupVisible && !hasIgnoredPopup && ( + +

{__('You added a block outside of the lcp/viewport container. Please make sure the block is inside the appropriate area.', 'lcp-viewport')}

+ + +
+ )} ); } diff --git a/includes/blocks/lcp-viewport/src/save.js b/includes/blocks/lcp-viewport/src/save.js index d41cf8f..04f04ca 100644 --- a/includes/blocks/lcp-viewport/src/save.js +++ b/includes/blocks/lcp-viewport/src/save.js @@ -10,15 +10,21 @@ import { useBlockProps, InnerBlocks } from '@wordpress/block-editor'; * @return {Element} Element to render. */ export default function Save({ attributes }) { - const { hasSidecontent } = attributes; // Retrieve the hasSidecontent attribute + const { hasSidecontent, hasStickyHeader } = attributes; // Retrieve the hasSidecontent and hasStickyHeader attributes const blockProps = useBlockProps.save(); - // Conditionally add the 'has-sidecontent' class if hasSidecontent is true - const className = hasSidecontent ? 'lcp-has-sidecontent' : ''; + // Conditionally add the 'has-sidecontent' and 'lcp-has-sticky-header' classes + let classNames = ''; + if (hasSidecontent) { + classNames += 'lcp-has-sidecontent '; + } + if (hasStickyHeader) { + classNames += 'lcp-has-sticky-header'; + } return ( -
-
+
+
diff --git a/includes/blocks/lcp-viewport/src/view.js b/includes/blocks/lcp-viewport/src/view.js index e2a7ec6..04bbf1d 100644 --- a/includes/blocks/lcp-viewport/src/view.js +++ b/includes/blocks/lcp-viewport/src/view.js @@ -21,5 +21,4 @@ */ /* eslint-disable no-console */ -console.log( 'Hello World! (from create-block-lcp-viewport block)' ); /* eslint-enable no-console */ diff --git a/package.json b/package.json new file mode 100644 index 0000000..4f20e7d --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "name": "localcontentpro", + "version": "0.0.1", + "scripts": { + "zip-theme": "node zip-theme.js" + }, + "devDependencies": { + "archiver": "^5.3.2" + } +} diff --git a/script.js b/script.js index 7e20078..20872e4 100644 --- a/script.js +++ b/script.js @@ -29,6 +29,7 @@ document.addEventListener('DOMContentLoaded', function () { // Function to handle the scroll event function handleScroll() { + document.documentElement.style.setProperty('--lcp--full-header--height', fullHeaderHeight + "px"); const scrolled = window.scrollY || document.documentElement.scrollTop; @@ -36,7 +37,7 @@ document.addEventListener('DOMContentLoaded', function () { if (scrolled >= headerHeight) { // Add the 'lcp-fixed' class and set 'top' to 0 for side content sideContent.classList.add('lcp-fixed'); - sideContent.style.top = fullHeaderHeight + 'px'; + // sideContent.style.top = fullHeaderHeight + 'px'; // If the header has 'lcp-sticky-on-scroll', adjust height of side content to be 100vh - fullHeaderHeight if (headerIsStickyOnScroll) { @@ -44,7 +45,7 @@ document.addEventListener('DOMContentLoaded', function () { // Add 'lcp-fixed' to the header header.classList.add('lcp-fixed'); // Set the 'top' of the sideContent to the height of the header - sideContent.style.top = `${fullHeaderHeight}px`; + // sideContent.style.top = `${fullHeaderHeight}px`; } else if (headerIsSticky) { // If the header is sticky but not 'sticky-on-scroll', keep the side content height adjusted sideContent.style.height = `calc(100vh - ${fullHeaderHeight}px)`; @@ -52,13 +53,13 @@ document.addEventListener('DOMContentLoaded', function () { // Set side content height to 100vh when not sticky sideContent.style.height = 'calc(100vh - 32px)'; - sideContent.style.top = '32px'; + // sideContent.style.top = '32px'; } } else { // Remove the 'lcp-fixed' class from side content and header if scrolled back above the header sideContent.classList.remove('lcp-fixed'); - sideContent.style.top = ''; // Reset the 'top' style + // sideContent.style.top = ''; // Reset the 'top' style // Reset height to 100vh when not fixed sideContent.style.height = `calc(100vh - ${fullHeaderHeight}px)` ; diff --git a/style.css b/style.css index 002699c..38f53f5 100644 --- a/style.css +++ b/style.css @@ -88,6 +88,10 @@ Version: 1.0 z-index: 3; width: 100% } +#lcp-sidecontent {top:var(--lcp---header--height)} +.admin-bar #lcp-sidecontent { + top: calc(var(--lcp--header--height) + 32px); +} #lcp-header-container.lcp-sticky { position: fixed; diff --git a/zip-theme.js b/zip-theme.js new file mode 100644 index 0000000..b37fd9f --- /dev/null +++ b/zip-theme.js @@ -0,0 +1,89 @@ +const fs = require('fs'); +const path = require('path'); +const archiver = require('archiver'); + +// Path to the theme's style.css +const styleCssPath = path.join(__dirname, 'style.css'); + +// Directories to exclude +const excludedDirs = [ + 'node_modules', + 'src', + '.gitignore', + 'package.json', + 'package-lock.json', + 'theme.zip', + '.git' +]; + +// Helper function to check if a file or directory should be excluded +const shouldExclude = (filePath) => { + return excludedDirs.some(exclude => filePath.includes(exclude)); +}; + +// Read the style.css file and extract the theme name +fs.readFile(styleCssPath, 'utf8', (err, data) => { + if (err) { + console.error('Error reading style.css:', err); + return; + } + + // Regex to match the theme name in the header + const themeNameMatch = data.match(/\/\*[\s\S]*?Theme Name:\s*(.*?)\s*\*\//); + + // Fallback to 'theme' if no theme name is found + const themeName = themeNameMatch && themeNameMatch[1] ? themeNameMatch[1].trim() : 'theme'; + + // Sanitize the theme name (remove spaces and convert to lowercase) + const sanitizedThemeName = themeName.replace(/\s+/g, '').toLowerCase(); + + // Define the output zip file path using the sanitized theme name + const output = fs.createWriteStream(path.join(__dirname, `${sanitizedThemeName}.zip`)); + + // Create an archiver instance + const archive = archiver('zip', { + zlib: { level: 9 } // Compression level + }); + + // Pipe the archive to the output file + archive.pipe(output); + + // Recursively append all files in the theme directory except excluded ones + const addFilesRecursively = (directory) => { + const files = fs.readdirSync(directory); + + files.forEach((file) => { + const filePath = path.join(directory, file); + + // Exclude the file or directory if it matches the exclusion criteria + if (shouldExclude(filePath)) { + console.log(`Excluding: ${filePath}`); + return; // Skip this file/directory + } + + const stat = fs.statSync(filePath); + + if (stat.isDirectory()) { + // If it's a directory, recurse into it + addFilesRecursively(filePath); + } else { + // If it's a file, add it to the archive + archive.file(filePath, { name: path.relative(__dirname, filePath) }); + } + }); + }; + + // Start adding files from the theme directory + addFilesRecursively(__dirname); + + // Finalize the archive + archive.finalize(); + + output.on('close', () => { + console.log(`Theme has been zipped into ${sanitizedThemeName}.zip`); + }); + + output.on('error', (err) => { + console.error('Error creating zip file:', err); + }); +});