Compare commits

..

26 Commits

Author SHA1 Message Date
7bba517b48 Changes to blocks and added basic framework for Newsletters 2025-01-02 01:29:51 -08:00
d928a0e8fd Added theme archvier and changes to blocks 2025-01-01 18:09:33 -08:00
21b00e1937 Changes to blocks and styles 2025-01-01 03:08:58 -08:00
741d39a962 Changes to lcp-button 2024-12-31 18:53:46 -08:00
2df16e37a8 Basic integration of tabs UI on theme settings page 2024-12-30 19:41:59 -08:00
4394776735 Add tabs to lcp-ui js and css 2024-12-30 19:23:48 -08:00
a8b4dc6b70 Changed location of react components to .../assets/js/react/components 2024-12-30 18:59:57 -08:00
4b78f9f571 Added lcp-ui.js and changes to blocks 2024-12-30 17:39:30 -08:00
b9e2660318 Added support for all Material Icons 2024-12-30 03:00:46 -08:00
28139d2455 Changes to icon importer 2024-12-30 02:31:16 -08:00
0d59719440 changes to lcp-button and icon uploader 2024-12-29 22:52:17 -08:00
372d5aa2c1 Changes to lcp button and icons 2024-12-29 01:47:56 -08:00
d65992a169 Changes to lcp button and icon selector 2024-12-29 01:47:33 -08:00
462cffdddc changes to blocks and styles 2024-12-27 22:56:39 -08:00
93cc7be3bf Changes to styles 2024-12-23 04:10:45 -08:00
44c621e0da Changes to styles 2024-12-23 03:52:21 -08:00
216d108289 Changes to styles 2024-12-23 03:51:13 -08:00
1ccc6f0031 Changes to script.js and moved backend code to /includes/classes/backend.php 2024-12-23 02:50:12 -08:00
f3fbe0fa32 Changes to blocks 2024-12-22 15:20:12 -08:00
cfbb860bf9 Changes to theme.json and gallery 2024-12-19 01:23:40 -08:00
94d2c7c8a2 Changes to directory structure 2024-12-18 02:27:09 -08:00
d5a5f4e87b Changes to directory structure 2024-12-18 02:20:47 -08:00
961081128a Changes to gallery block and custom code inserter 2024-12-17 17:33:30 -08:00
f19e779946 Minor changes 2024-12-17 01:37:55 -08:00
4936a3a742 Minor changes to filenames 2024-12-16 20:15:22 -08:00
1234341241 New dev branch 2024-12-16 20:12:25 -08:00
293 changed files with 95773 additions and 17 deletions

1
.gitignore vendored
View File

@ -6,7 +6,6 @@ wp-includes/
.DS_Store .DS_Store
node_modules/ node_modules/
.env .env
build/
dist/ dist/
package-lock.json package-lock.json
yarn.lock yarn.lock

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,71 @@
document.addEventListener("DOMContentLoaded", function () {
// Get reference to the popup element
const popup = document.getElementById('popup');
const facebookShareLink = document.getElementById('facebook-share');
const twitterShareLink = document.getElementById('twitter-share');
// Function to check if selection intersects with any <p> tag
function isSelectionInParagraph(selection) {
const range = selection.getRangeAt(0); // Get the selected range
const paragraphs = document.querySelectorAll('p'); // Get all <p> elements
for (let p of paragraphs) {
// Check if the selected range intersects with this <p> tag
const pRect = p.getBoundingClientRect();
const rangeRect = range.getBoundingClientRect();
// Check if the range and the <p> element's bounding boxes overlap
if (rangeRect.top < pRect.bottom && rangeRect.bottom > pRect.top &&
rangeRect.left < pRect.right && rangeRect.right > pRect.left) {
return true; // Selection intersects with this <p> tag
}
}
return false; // No intersection with any <p> tag
}
// Function to show the popup near the selected text
function showPopup(e) {
const selection = window.getSelection();
// Check if any text is selected and if it is inside or intersects with a <p> tag
if (selection.toString().length > 0 && isSelectionInParagraph(selection)) {
// Get the bounding rectangle of the selected text
const range = selection.getRangeAt(0);
const rect = range.getBoundingClientRect();
// Position the popup above the selection (adjust for spacing)
popup.style.left = `${rect.left + window.scrollX}px`;
popup.style.top = `${rect.top + window.scrollY - popup.offsetHeight - 5}px`;
// Show the popup
popup.style.display = 'block';
// Set up share links with the selected text and page URL
const selectedText = selection.toString();
const pageUrl = window.location.href;
// Facebook share link
facebookShareLink.setAttribute('href', `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(pageUrl)}&quote=${encodeURIComponent(selectedText)}`);
// Twitter/X share link
twitterShareLink.setAttribute('href', `https://twitter.com/intent/tweet?text=${encodeURIComponent(selectedText)}&url=${encodeURIComponent(pageUrl)}`);
} else {
// Hide the popup if no text is selected or it's not inside or overlapping a <p> tag
popup.style.display = 'none';
}
}
// Listen for mouse-up event (when selection ends)
document.addEventListener('mouseup', showPopup);
// Optionally, listen for touchend event for mobile devices
document.addEventListener('touchend', showPopup);
// Hide the popup if user clicks anywhere else
document.addEventListener('click', function(event) {
if (!popup.contains(event.target) && !window.getSelection().toString()) {
popup.style.display = 'none';
}
});
});

77
assets/js/icon-import.js Normal file
View File

@ -0,0 +1,77 @@
document.addEventListener('DOMContentLoaded', function () {
console.log('DOMContentLoaded event triggered');
const installButtons = document.querySelectorAll('.install-btn');
const uninstallButtons = document.querySelectorAll('.uninstall-btn');
console.log('Install buttons:', installButtons);
console.log('Uninstall buttons:', uninstallButtons);
// Handle Install button click
installButtons.forEach(function (button) {
console.log('Adding install listener to button', button);
button.addEventListener('click', function (event) {
event.preventDefault(); // Prevent default form submission or page reload
console.log('Install button clicked');
const iconSetId = this.getAttribute('data-icon-set-id');
console.log('Icon Set ID:', iconSetId);
const formData = new FormData();
formData.append('action', 'install_icon_set');
formData.append('icon_set_id', iconSetId);
const xhr = new XMLHttpRequest();
xhr.open('POST', mytheme_ajax.ajax_url, true);
xhr.onload = function () {
if (xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
console.log(response);
if (response.success) {
alert('Icon set installed successfully!');
} else {
alert('Failed to install icon set: ' + response.data.message);
}
} else {
alert('There was an error with the request.');
}
};
xhr.send(formData);
});
});
// Handle Uninstall button click
uninstallButtons.forEach(function (button) {
console.log('Adding uninstall listener to button', button);
button.addEventListener('click', function (event) {
event.preventDefault(); // Prevent default form submission or page reload
console.log('Uninstall button clicked');
const iconSetId = this.getAttribute('data-icon-set-id');
console.log('Icon Set ID for uninstall:', iconSetId);
const formData = new FormData();
formData.append('action', 'uninstall_icon_set');
formData.append('icon_set_id', iconSetId);
const xhr = new XMLHttpRequest();
xhr.open('POST', mytheme_ajax.ajax_url, true);
xhr.onload = function () {
if (xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
console.log(response);
if (response.success) {
alert('Icon set uninstalled successfully!');
} else {
alert('Failed to uninstall icon set: ' + response.data.message);
}
} else {
alert('There was an error with the request.');
}
};
xhr.send(formData);
});
});
});

61
assets/js/lcp-ui.js Normal file
View File

@ -0,0 +1,61 @@
document.addEventListener('DOMContentLoaded', function () {
// Find all elements with the class "lcp-accordion"
var accordions = document.querySelectorAll('.lcp-accordion');
accordions.forEach(function (accordion) {
// Find all tabs within the current accordion
var tabs = accordion.querySelectorAll('.lcp-accordion-tab');
tabs.forEach(function (tab) {
var header = tab.querySelector('h3');
var content = tab.querySelector('.lcp-accordion-content');
// Add click event to each header to toggle the content
header.addEventListener('click', function () {
// Toggle the 'active' class on the tab to show/hide content
tab.classList.toggle('active');
// Optional: Close other open tabs (if only one tab should be open at a time)
tabs.forEach(function (otherTab) {
if (otherTab !== tab) {
otherTab.classList.remove('active');
}
});
});
});
});
});
document.addEventListener('DOMContentLoaded', function () {
const tabs = document.querySelectorAll('.tab-link');
const panes = document.querySelectorAll('.tab-pane');
tabs.forEach(tab => {
tab.addEventListener('click', function (event) {
event.preventDefault();
// Remove active class from all tabs and panes
tabs.forEach(link => link.classList.remove('active'));
panes.forEach(pane => pane.classList.remove('active'));
// Add active class to the clicked tab
tab.classList.add('active');
// Get the target pane
const targetPaneId = tab.dataset.tab;
const targetPane = document.getElementById(targetPaneId);
// Check if targetPane exists before trying to manipulate it
if (targetPane) {
targetPane.classList.add('active');
} else {
console.error(`Tab pane with ID '${targetPaneId}' not found.`);
}
});
});
});

122
assets/js/lcp.js Normal file
View File

@ -0,0 +1,122 @@
document.addEventListener('DOMContentLoaded', function () {
// Get references to the DOM elements
const header = document.getElementById('lcp-header-container');
const sideContent = document.getElementById('lcp-sidecontent');
// Ensure elements exist before proceeding
if (!header || !sideContent) return;
// Check if the header has the 'lcp-sticky' and 'lcp-sticky-on-scroll' class
const headerIsSticky = header.classList.contains('lcp-sticky');
const headerIsStickyOnScroll = header.classList.contains('lcp-sticky-on-scroll');
// Measure the height of the header once the DOM is loaded
const headerHeight = header.offsetHeight;
let fullHeaderHeight;
// If the admin-bar is present, the fullHeaderHeight is the headerHeight + 32px
if (document.body.classList.contains('admin-bar')) {
const adminBarHeight = document.getElementById('wpadminbar').offsetHeight;
fullHeaderHeight = headerHeight + adminBarHeight;
} else {
fullHeaderHeight = headerHeight;
}
// Function to handle the scroll event
function handleScroll() {
document.documentElement.style.setProperty('--lcp--full-header--height', fullHeaderHeight + "px");
if (!headerIsSticky){
const scrolled = window.scrollY || document.documentElement.scrollTop;
// Check if the page has scrolled past the height of the header
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';
// If the header has 'lcp-sticky-on-scroll', adjust height of side content to be 100vh - fullHeaderHeight
if (headerIsStickyOnScroll) {
sideContent.style.height = `calc(100vh - ${fullHeaderHeight}px)`;
// 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`;
} 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)`;
} else {
// Set side content height to 100vh when not sticky
// sideContent.style.height = 'calc(100vh - 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
// Reset height to 100vh when not fixed
// sideContent.style.height = `calc(100vh - ${fullHeaderHeight}px)` ;
// If header has the 'lcp-sticky-on-scroll' class, remove 'lcp-fixed' from the header
if (headerIsStickyOnScroll) {
header.classList.remove('lcp-fixed');
}
}
}
}
// Also trigger the scroll handler once on load in case the page is already scrolled
handleScroll();
function debounce(func, delay) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
func.apply(context, args);
}, delay);
};
}
// Add debounced scroll event listener
window.addEventListener('scroll', debounce(handleScroll, 20)); // 200ms debounce
});
const sidecontent = document.getElementById("lcp-sidecontent");
const innerContent = document.getElementById("lcp-sidecontent-inner");
const scrollTrack = document.getElementById("lcp-scroll-track");
const scrollBar = document.getElementById("lcp-scroll-bar");

View File

@ -0,0 +1,96 @@
import { __ } from '@wordpress/i18n';
import { BaseControl, __experimentalNumberControl as NumberControl, SelectControl, __experimentalHStack as HStack } from '@wordpress/components';
import { useState, useEffect } from 'react';
/**
* Control component with a number input and a select dropdown for units (px, rem, em, % etc.).
* Accepts a default value as a string (e.g., "15px", "10rem", etc.).
* Includes an optional 'auto' unit if includeAuto is true, and handles autoReturnsNull behavior.
*/
export function DimensionValueControl({ value = '10px', onChange, includeAuto = false, autoReturnsNull = false }) {
// Options for select control (CSS units) including 'auto' if enabled
const unitOptions = [
{ label: __('px'), value: 'px' },
{ label: __('%'), value: '%' },
{ label: __('em'), value: 'em' },
{ label: __('rem'), value: 'rem' },
{ label: __('vw'), value: 'vw' },
{ label: __('vh'), value: 'vh' },
...(includeAuto ? [{ label: __('auto'), value: 'auto' }] : []), // Add 'auto' option if includeAuto is true
];
// Parse the value string into a number and unit
const parseValue = (value) => {
const regex = /([0-9]+)([a-zA-Z%]+)?/; // Capture the number and the unit
const match = value.match(regex);
if (match) {
return {
numberValue: parseInt(match[1], 10), // Number part
unitValue: match[2] || 'px' // Unit part (default to 'px' if no unit found)
};
}
return { numberValue: 0, unitValue: 'px' }; // Fallback if invalid format
};
// Use the parsed value to set initial state
const { numberValue: initialNumber, unitValue: initialUnit } = parseValue(value);
const [numberValue, setNumberValue] = useState(initialNumber);
const [unitValue, setUnitValue] = useState(initialUnit);
// Combine the number and unit into a string like "15px"
const dimensionValue = `${numberValue}${unitValue}`;
// Handle number change
const onNumberChange = (newValue) => {
setNumberValue(newValue);
if (onChange && unitValue !== 'auto') {
onChange(`${newValue}${unitValue}`); // Pass updated value back to parent
}
};
// Handle unit change
const onUnitChange = (newUnit) => {
if (newUnit === 'auto') {
setNumberValue(null); // Reset the number value when 'auto' is selected
}
setUnitValue(newUnit);
if (onChange) {
const updatedValue = newUnit === 'auto'
? (autoReturnsNull ? null : 'auto')
: `${numberValue}${newUnit}`; // Pass 'auto' or null or updated value back to parent
onChange(updatedValue);
}
};
// Effect to handle when value prop changes (useful for syncing)
useEffect(() => {
const { numberValue, unitValue } = parseValue(value);
setNumberValue(numberValue);
setUnitValue(unitValue);
}, [value]);
return (
<BaseControl className="lcp-dimension-value-control">
<HStack>
{/* Number input control, disabled when 'auto' is selected */}
<NumberControl
className="lcp-number-control"
value={numberValue || ''}
onChange={onNumberChange}
min={0}
step={0.1}
spinControls={'none'}
disabled={unitValue === 'auto'} // Disable number input if 'auto' is selected
/>
{/* Select dropdown control for units */}
<SelectControl
className="lcp-select-control"
value={unitValue}
options={unitOptions}
onChange={onUnitChange}
/>
</HStack>
</BaseControl>
);
}

View File

@ -0,0 +1,59 @@
import { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { SelectControl } from '@wordpress/components';
export function IconSelectControl(props) {
const { iconSvgId, onIconChange } = props;
const [iconData, setIconData] = useState([]);
useEffect(() => {
const fetchIconData = async () => {
try {
const response = await fetch('/wp-json/lcp/v1/icons');
const data = await response.json();
if (Array.isArray(data) && data.length > 0) {
setIconData(data); // Set the fetched data directly
}
} catch (error) {
console.error('Error fetching icons:', error);
}
};
fetchIconData();
}, []);
const handleIconChange = (selectedIconId) => {
const selectedIcon = iconData.find(icon => icon.iconSvgId === selectedIconId);
if (selectedIcon && onIconChange) {
// Send both icon ID and path (SVG) to the parent component
onIconChange({
iconSvgId: selectedIcon.iconSvgId, // Pass icon ID to parent
iconSvgPath: selectedIcon.iconSvgPaths, // Pass icon paths to parent
viewbox: selectedIcon.selectedIconViewbox // Pass the viewbox to parent
});
console.log("Selected Icon ID:", selectedIcon.iconSvgId); // Debugging output
console.log("Selected Icon Path:", selectedIcon.iconSvgPaths); // Debugging output
console.log("Selected Icon Viewbox:", selectedIcon.selectedIconViewbox); // Debugging output
}
};
if (iconData.length === 0) {
return <p>{__('Loading icons...', 'lcp')}</p>; // Loading state
}
const iconOptions = iconData.map((icon) => ({
value: icon.iconSvgId, // Use icon ID as value for the SelectControl
label: icon.name, // Directly use the icon's name as the label
}));
return (
<SelectControl
label={__('Select Icon', 'lcp')}
value={iconSvgId} // Current selected icon ID
options={iconOptions}
onChange={handleIconChange} // Handle icon change
/>
);
}

View File

@ -0,0 +1,103 @@
import { __ } from '@wordpress/i18n';
import { BaseControl, Button, RangeControl, __experimentalHStack as HStack, __experimentalVStack as VStack } from '@wordpress/components';
import { DimensionValueControl } from './DimensionValueControl';
/**
* Padding Control component to manage padding values for different screen sizes.
*/
export function PaddingControl() {
return (
<BaseControl className="lcp-padding-control">
{/* Padding label and Unlink button */}
<HStack>
<span>{__('Padding')}</span>
<Button
variant="secondary"
aria-label={__('Unlink sides')}
onClick={() => {}}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false">
<path d="M10 17.389H8.444A5.194 5.194 0 1 1 8.444 7H10v1.5H8.444a3.694 3.694 0 0 0 0 7.389H10v1.5ZM14 7h1.556a5.194 5.194 0 0 1 0 10.39H14v-1.5h1.556a3.694 3.694 0 0 0 0-7.39H14V7Zm-4.5 6h5v-1.5h-5V13Z"></path>
</svg>
</Button>
</HStack>
{/* Extra Large Padding Controls */}
{/* Will update all padding values for all screen sizes if updateAllScreenSizes is true */}
{/* Top and Bottom HStack */}
<HStack style={{ flex: 1 }}>
{/* Top and Bottom Icon */}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" className="spacing-sizes-control__icon" aria-hidden="true" focusable="false">
<path d="m7.5 6h9v-1.5h-9zm0 13.5h9v-1.5h-9zm-3-3h1.5v-9h-1.5zm13.5-9v9h1.5v-9z" style={{ opacity: 0.25 }}></path>
<path d="m7.5 6h9v-1.5h-9z"></path>
<path d="m7.5 19.5h9v-1.5h-9z"></path>
</svg>
{/* RangeControl wrapped in HStack with flex: 1 applied to its parent */}
<HStack style={{ flex: 1 }}>
<DimensionValueControl/>
<RangeControl
withInputField={false}
value={10} // Placeholder value
onChange={() => {}}
min={0}
max={50}
/>
</HStack>
{/* Custom Padding Button */}
<Button
style={{padding:0,background:'none',color:'var(--wp-components-color-foreground)'} }
variant="primary"
onClick={() => {}}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false">
<path d="m19 7.5h-7.628c-.3089-.87389-1.1423-1.5-2.122-1.5-.97966 0-1.81309.62611-2.12197 1.5h-2.12803v1.5h2.12803c.30888.87389 1.14231 1.5 2.12197 1.5.9797 0 1.8131-.62611 2.122-1.5h7.628z"></path>
<path d="m19 15h-2.128c-.3089-.8739-1.1423-1.5-2.122-1.5s-1.8131.6261-2.122 1.5h-7.628v1.5h7.628c.3089.8739 1.1423 1.5 2.122 1.5s1.8131-.6261 2.122-1.5h2.128z"></path>
</svg>
</Button>
</HStack>
{/* Left and Right HStack */}
<HStack style={{ flex: 1 }}>
{/* Left and Right Icon */}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" className="spacing-sizes-control__icon" aria-hidden="true" focusable="false">
<path d="m7.5 6h9v-1.5h-9zm0 13.5h9v-1.5h-9zm-3-3h1.5v-9h-1.5zm13.5-9v9h1.5v-9z" style={{ opacity: 0.25 }}></path>
<path d="m7.5 6h9v-1.5h-9z"></path>
<path d="m4.5 7.5v9h1.5v-9z"></path>
<path d="m18 7.5v9h1.5v-9z"></path>
</svg>
{/* RangeControl wrapped in HStack with flex: 1 applied to its parent */}
<RangeControl
withInputField={false}
value={10} // Placeholder value
onChange={() => {}}
min={0}
max={50}
/>
{/* Custom Padding Button */}
<Button
variant="primary"
onClick={() => {}}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false">
<path d="m19 7.5h-7.628c-.3089-.87389-1.1423-1.5-2.122-1.5-.97966 0-1.81309.62611-2.12197 1.5h-2.12803v1.5h2.12803c.30888.87389 1.14231 1.5 2.12197 1.5.9797 0 1.8131-.62611 2.122-1.5h7.628z"></path>
<path d="m19 15h-2.128c-.3089-.8739-1.1423-1.5-2.122-1.5s-1.8131.6261-2.122 1.5h-7.628v1.5h7.628c.3089.8739 1.1423 1.5 2.122 1.5s1.8131-.6261 2.122-1.5h2.128z"></path>
</svg>
</Button>
</HStack>
{/* Additional controls can be added here in a VStack */}
<VStack>
{/* Placeholder for additional components */}
</VStack>
</BaseControl>
);
}

View File

@ -0,0 +1,57 @@
<?php
// Path to your icons.json file
$filePath = 'output.json';
// Read the content of the JSON file
$jsonData = file_get_contents($filePath);
// Decode the JSON data into a PHP array
$iconsData = json_decode($jsonData, true);
// Check if the data is decoded successfully
if (json_last_error() !== JSON_ERROR_NONE) {
die('Error decoding JSON data: ' . json_last_error_msg());
}
// Check if the data contains a 'family' key (indicating it has families with SVGs)
if (isset($iconsData[0]['family'])) {
// Handle the case with families and svgs (structure 1)
foreach ($iconsData as &$family) {
if (isset($family['svgs']) && is_array($family['svgs'])) {
// Sort the 'svgs' array alphabetically by the 'name' field
usort($family['svgs'], function($a, $b) {
return strcmp($a['name'], $b['name']);
});
}
}
// Sort the families by the 'family' field (if needed)
usort($iconsData, function($a, $b) {
return strcmp($a['family'], $b['family']);
});
} else {
// Handle the case without families (structure 2)
// Sort the flat array of icons alphabetically by the 'name' field
usort($iconsData, function($a, $b) {
return strcmp($a['name'], $b['name']);
});
}
// Encode the sorted data back to JSON
$sortedJsonData = json_encode($iconsData, JSON_PRETTY_PRINT);
// Check if encoding was successful
if (json_last_error() !== JSON_ERROR_NONE) {
die('Error encoding JSON data: ' . json_last_error_msg());
}
// Write the sorted JSON data back to the file
if (file_put_contents($filePath, $sortedJsonData)) {
echo "The icons data has been sorted and saved successfully!";
} else {
echo "Error writing the sorted data to the file.";
}
?>

61
assets/json/converter.php Normal file
View File

@ -0,0 +1,61 @@
<?php
// Function to generate a UUID (compliant with MySQL UUID)
function generateUUID() {
return bin2hex(random_bytes(16)); // Generate a random UUID
}
// Function to convert the raw SVG to JSON format
function convertSymbolsToJSON($svgContent) {
// Match all <symbol> elements and extract them
preg_match_all('/<symbol[^>]*>[\s\S]*?<\/symbol>/', $svgContent, $matches);
$jsonData = [];
foreach ($matches[0] as $symbol) {
// Extract 'id', 'viewBox', and 'path' attributes
preg_match('/id="([^"]+)"/', $symbol, $idMatches);
preg_match('/viewBox="([^"]+)"/', $symbol, $viewBoxMatches);
preg_match('/<path[^>]*d="([^"]+)"/', $symbol, $pathMatches);
// If we have a valid symbol, process it
if (isset($idMatches[1]) && isset($viewBoxMatches[1]) && isset($pathMatches[1])) {
// Generate a UUID for the symbol
$uniqueId = generateUUID();
// Capitalize the name by replacing hyphens with spaces and capitalizing each word
$name = ucwords(str_replace('-', ' ', $idMatches[1]));
// Build the symbol JSON object
$symbolJSON = [
"id" => $uniqueId,
"name" => $name,
"viewBox" => $viewBoxMatches[1],
"path" => "<path d='" . $pathMatches[1] . "'/>"
];
// Add the symbol JSON to the data array
$jsonData[] = $symbolJSON;
}
}
return $jsonData;
}
// Read the SVG file (assumes it's in the same directory)
$svgFilePath = 'input.svg'; // The input SVG file
if (file_exists($svgFilePath)) {
$svgContent = file_get_contents($svgFilePath);
// Convert symbols to JSON
$symbolsJson = convertSymbolsToJSON($svgContent);
// Output the JSON data to a file
$outputFilePath = 'output.json';
file_put_contents($outputFilePath, json_encode($symbolsJson, JSON_PRETTY_PRINT));
echo "JSON file has been created successfully: $outputFilePath\n";
} else {
echo "Error: SVG file not found.\n";
}
?>

57
assets/json/fixpaths.php Normal file
View File

@ -0,0 +1,57 @@
<?php
// Path to the input JSON file
$inputFile = 'font-awesome-v6.1.7-solid-svgs.json';
// Step 1: Load the JSON data
$jsonData = file_get_contents($inputFile);
// Check if the file was read successfully
if ($jsonData === false) {
die("Error reading the JSON file.");
}
// Step 2: Decode the JSON data into a PHP array
$data = json_decode($jsonData, true);
// Check if JSON decoding was successful
if ($data === null) {
die("Error decoding the JSON data.");
}
// Step 3: Modify the structure by extracting the 'd' value and formatting the 'paths' tag
foreach ($data as $index => $iconSet) {
if (isset($iconSet['svgs']) && is_array($iconSet['svgs'])) {
foreach ($iconSet['svgs'] as $svgIndex => $svg) {
// Check if 'path' exists
if (isset($svg['path'])) {
// Extract the 'd' attribute value from the nested path string
preg_match('/d=[\'"]([^\'"]+)[\'"]/i', $svg['path'], $matches);
// If we found the 'd' value, format the paths correctly
if (isset($matches[1])) {
$dValue = $matches[1]; // Get the actual 'd' value from the path
// Escape the 'd' value for JSON format (escape double quotes inside the string)
$escapedDValue = str_replace('"', '\\"', $dValue);
// Now, add the proper <path> tag to the 'paths' field
$svg['paths'] = "<path d=\"{$escapedDValue}\"/>";
}
unset($svg['path']); // Optionally remove the original 'path' key
}
// Save the modified svg back to the array
$data[$index]['svgs'][$svgIndex] = $svg;
}
}
}
// Optional: Save the modified JSON to a new file
$outputFile = 'solid-fixed-paths.json';
file_put_contents($outputFile, json_encode($data, JSON_PRETTY_PRINT));
// Output the success message
echo "Successfully modified and saved the JSON file with 'path' converted to 'paths'.\n";
?>

63
assets/json/icons/fix.php Normal file
View File

@ -0,0 +1,63 @@
<?php
// Path to the input JSON file
$inputFile = 'material-icons-twotone.json';
// Path to the output JSON file
$outputFile = 'material-icons-twotone-unescaped-with-ids.json';
// Function to generate a MySQL-style UUID
function generateUUID() {
// Generates a version 4 UUID (random)
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
// Step 1: Load the JSON data
$jsonData = file_get_contents($inputFile);
// Check if the file was read successfully
if ($jsonData === false) {
die("Error reading the JSON file.");
}
// Step 2: Decode the JSON data into a PHP array
$data = json_decode($jsonData, true);
// Check if JSON decoding was successful
if ($data === null) {
die("Error decoding the JSON data.");
}
// Step 3: Iterate through each item and unescape the 'paths' key, and generate a new 'id'
foreach ($data as &$icon) {
// Unescape only HTML entities (without affecting forward slashes)
$icon['paths'] = html_entity_decode($icon['paths'], ENT_QUOTES | ENT_HTML5);
// Generate a new MySQL-style UUID for each 'id'
$icon['id'] = generateUUID();
}
// Step 4: Encode the modified data back into JSON format
$newJsonData = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
// Check if encoding was successful
if ($newJsonData === false) {
die("Error encoding the JSON data.");
}
// Step 5: Save the modified JSON data to the output file
file_put_contents($outputFile, $newJsonData);
// Check if file writing was successful
if (file_put_contents($outputFile, $newJsonData) === false) {
die("Error saving the modified JSON data.");
}
echo "Paths have been unescaped, IDs have been added, and saved to '$outputFile'.\n";
?>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,67 @@
[
{
"id": 1,
"setName": "Font Awesome - Regular",
"setFamily": "Font Awesome",
"version": "6.7.1",
"fileName": "/font-awesome/v6.7.1/font-awesome-v6.7.1-regular-svgs.json",
"default": true
},
{
"id": 2,
"setName": "Font Awesome - Solid",
"setFamily": "Font Awesome",
"version": "6.7.1",
"fileName": "/font-awesome/v6.7.1/font-awesome-v6.7.1-solid-svgs.json"
},
{
"id": 3,
"setName": "Font Awesome - Brands",
"setFamily": "Font Awesome",
"version": "6.7.1",
"fileName": "/font-awesome/v6.7.1/font-awesome-v6.7.1-brands-svgs.json"
},
{
"id": 4,
"setName": "Material Icons - Baseline",
"setFamily": "Material Icons",
"version": "1.0.32",
"fileName": "/material-icons/v1.0.32/material-icons-v1.0.32-baseline-svgs.json"
},
{
"id": 5,
"setName": "Material Icons - Outline",
"setFamily": "Material Icons",
"version": "1.0.32",
"fileName": "/material-icons/v1.0.32/material-icons-v1.0.32-outline-svgs.json"
},
{
"id":6,
"setName": "Material Icons - Twotone",
"setFamily": "Material Icons",
"version": "1.0.32",
"fileName": "/material-icons/v1.0.32/material-icons-v1.0.32-twotone-svgs.json"
},
{
"id": 7,
"setName": "Material Icons - Sharp",
"setFamily": "Material Icons",
"version": "1.0.32",
"fileName": "/material-icons/v1.0.32/material-icons-v1.0.32-sharp-svgs.json"
},
{
"id": 8,
"setName": "Material Icons - Round",
"setFamily": "Material Icons",
"version": "1.0.32",
"fileName": "/material-icons/v1.0.32/material-icons-v1.0.32-round-svgs.json"
}
]

View File

@ -0,0 +1,86 @@
<?php
// Function to capitalize the 'name' field (capitalizes acronyms fully)
function capitalizeName($name) {
// Define a pattern to match acronyms (words in uppercase with no spaces)
$acronymPattern = '/\b[A-Z]{2,}\b/';
// Capitalize each word, and keep acronyms fully uppercase
$name = preg_replace_callback('/\b\w+\b/', function ($matches) use ($acronymPattern) {
$word = $matches[0];
// If it's an acronym (all uppercase), return as is
if (preg_match($acronymPattern, $word)) {
return strtoupper($word);
}
// Otherwise capitalize the first letter of each word and lowercase the rest
return ucfirst(strtolower($word));
}, $name);
return $name;
}
// Function to generate a MySQL UUID format (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
function generateMysqlUuid() {
// Generate a UUID using PHP's random_bytes for a total of 16 random bytes
$data = random_bytes(16);
// Set the version to 4 (random UUID)
$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // Version 4
// Set the variant to RFC4122
$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // RFC4122 variant
// Now unpack the data into 5 parts for formatting as UUID
$hexData = unpack('H8a/H4b/H4c/H4d/H12e', $data);
// Return the UUID in the format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
return $hexData['a'] . '-' . $hexData['b'] . '-' . $hexData['c'] . '-' . $hexData['d'] . '-' . $hexData['e'];
}
// Get the current directory of the script
$currentDir = __DIR__;
// Get all JSON files in the current directory
$jsonFiles = glob($currentDir . '/*.json');
// Iterate over each JSON file
foreach ($jsonFiles as $file) {
// Read the content of the file
$jsonContent = file_get_contents($file);
// Decode JSON to array
$data = json_decode($jsonContent, true);
// Check if the data is valid
if (json_last_error() === JSON_ERROR_NONE) {
// Process each SVG object
foreach ($data as &$set) {
if (isset($set['svgs'])) {
foreach ($set['svgs'] as &$svg) {
// Capitalize the 'name' field
if (isset($svg['name'])) {
$svg['name'] = capitalizeName($svg['name']);
}
// Generate a new MySQL UUID for the 'id' field
if (isset($svg['id'])) {
$svg['id'] = generateMysqlUuid();
}
}
}
}
// Re-encode the modified data to JSON
$newJsonContent = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
// Define the output file name (you can change this as needed)
$outputFile = $currentDir . '/modified_' . basename($file);
// Save the updated content back to a new file
file_put_contents($outputFile, $newJsonContent);
echo "Processed and saved to: " . basename($outputFile) . "\n";
} else {
echo "Invalid JSON in file: " . basename($file) . "\n";
}
}
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4206
assets/json/input.svg Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,465 @@
<?php <?php
function my_block_theme_setup() {
include get_template_directory() . '/includes/classes/wp-hooks.php';
include get_template_directory() . '/includes/classes/lcp-newsletters.php';
//include get_template_directory(). '/includes/blocks/lcp-gallery/lcp-gallery.php';
include get_template_directory() . '/includes/classes/blocks.php';
new Lcp_Blocks();
// Include backend php
include get_template_directory() . '/includes/classes/backend.php';
function lcp_block_theme_setup() {
add_theme_support( 'block-templates' ); add_theme_support( 'block-templates' );
} }
add_action( 'after_setup_theme', 'my_block_theme_setup' ); add_action( 'after_setup_theme', 'lcp_block_theme_setup' );
/* 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 "<style>:root { --lcp--header--height: {$header_height}px; }</style>";
}
}
add_action('wp_enqueue_scripts', 'lcp_header_height_style',1);
function lcp_enqueue() {
// Enqueue the theme's main stylesheet (style.css)
wp_enqueue_style('lcp-style', get_stylesheet_uri());
wp_enqueue_script('lcp-script', get_template_directory_uri() . '/assets/js/lcp.js');
wp_enqueue_script('lcp-ui-script', get_template_directory_uri() . '/assets/js/lcp-ui.js');
}
add_action('wp_enqueue_scripts', 'lcp_enqueue');
function lcp_backend_enqueue() {
// Enqueue the theme's main stylesheet (style.css)
wp_enqueue_style('lcp-style', get_stylesheet_uri());
wp_enqueue_script('lcp-script', get_template_directory_uri() . '/script.js');
}
add_action('admin_enqueue_scripts', 'lcp_enqueue');
/* KEY POINTS */
function add_key_points_meta_box() {
add_meta_box(
'key_points_meta_box', // ID of the meta box
'Key Points', // Title of the meta box
'render_key_points_meta_box', // Callback function to display the meta box
'post', // Post type (you can change it to other post types)
'normal', // Context (normal, side, advanced)
'default' // Priority
);
}
// Add meta box if setting is turned on
$options = get_option('lcp_theme_settings', array());
$enable_key_points_meta = isset($options['enable_key_points_meta']) ? $options['enable_key_points_meta'] : 0;
// Check if 'enable_key_points_meta' is enabled (1), then add the meta box
if ($enable_key_points_meta) {
// Hook into add_meta_boxes to register the custom meta box
add_action('add_meta_boxes', 'add_key_points_meta_box');
}
// Sanitize the SVGs data
function lcp_custom_svgs_sanitize($input) {
// Ensure the input is an array
if (is_array($input)) {
foreach ($input as $key => $svg) {
// Sanitize the name and path for each SVG
if (isset($svg['name'])) {
$input[$key]['name'] = sanitize_text_field($svg['name']);
}
if (isset($svg['path'])) {
$input[$key]['path'] = sanitize_textarea_field($svg['path']);
}
}
}
return $input;
}
// Existing function to render the theme settings page
// Callback function to render the meta box
function render_key_points_meta_box($post) {
// Retrieve the stored key points (serialized data)
$key_points_serialized = get_post_meta($post->ID, '_key_points', true);
$key_points = !empty($key_points_serialized) ? unserialize($key_points_serialized) : [];
?>
<div id="key-points-repeater">
<ul id="key-points-list">
<?php foreach ($key_points as $index => $point) : ?>
<li class="key-point">
<input type="text" name="key_points[<?php echo $index; ?>]" value="<?php echo esc_attr($point); ?>" class="key-point-input" />
<button type="button" class="remove-key-point">Remove</button>
</li>
<?php endforeach; ?>
</ul>
<button type="button" id="add-key-point">Add Key Point</button>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
const addButton = document.getElementById('add-key-point');
const keyPointsList = document.getElementById('key-points-list');
// Function to add a new key point input field
addButton.addEventListener('click', function () {
const index = keyPointsList.children.length;
const newItem = document.createElement('li');
newItem.classList.add('key-point');
newItem.innerHTML = `
<input type="text" name="key_points[${index}]" value="" class="key-point-input" />
<button type="button" class="remove-key-point">Remove</button>
`;
keyPointsList.appendChild(newItem);
});
// Function to remove a key point input field
keyPointsList.addEventListener('click', function (e) {
if (e.target && e.target.classList.contains('remove-key-point')) {
e.target.closest('.key-point').remove();
}
});
});
</script>
<?php
}
// Save the meta box data
function save_key_points_meta_box($post_id) {
// Check if this is an autosave or if the nonce is missing
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return $post_id;
if (!isset($_POST['key_points'])) return $post_id;
// Sanitize and store the key points as a serialized array
$key_points = array_map('sanitize_text_field', $_POST['key_points']);
update_post_meta($post_id, 'key_points', serialize($key_points)); // Use serialize instead of json_encode
}
add_action('save_post', 'save_key_points_meta_box');
// Hook the function to the theme activation process
// Function to drop the lcp_icons table when the theme is deactivated
function drop_lcp_icons_table() {
global $wpdb;
// Table name with WordPress prefix
$table_name = $wpdb->prefix . 'lcp_icons';
// SQL query to drop the table
$sql = "DROP TABLE IF EXISTS $table_name;";
// Execute the query
$wpdb->query($sql);
}
/* BACKEND ICON ADDER */
// Register the dashboard page in the admin menu
function mytheme_register_dashboard_page() {
add_menu_page(
'Icon Management', // Page Title
'Icon Management', // Menu Title
'manage_options', // Capability
'icon-management', // Menu Slug
'mytheme_dashboard_page', // Callback function
'dashicons-images-alt2', // Icon for the menu item
60 // Position
);
}
add_action('admin_menu', 'mytheme_register_dashboard_page');
// Callback function to display the dashboard page content
function mytheme_dashboard_page() {
?>
<div class="wrap">
<h1><?php esc_html_e('Icon Management Dashboard', 'mytheme'); ?></h1>
<div id="icon-dashboard-container">
<?php mytheme_display_icon_sets(); ?>
</div> <!-- This will be populated by PHP -->
</div>
<?php
}
// Function to read and display icon sets from the JSON file
// Function to read and display icon sets from the JSON file
function mytheme_display_icon_sets() {
// Path to the JSON file
$json_path = get_template_directory() . '/assets/json/icons/icon-definitions.json';
// Check if the file exists
if (file_exists($json_path)) {
// Get the contents of the JSON file
$json_data = file_get_contents($json_path);
// Decode JSON data into a PHP array
$icon_sets = json_decode($json_data, true);
// Loop through the icon sets and output HTML
foreach ($icon_sets as $icon_set) {
?>
<div class="icon-set">
<h3><?php echo esc_html($icon_set['setFamily'] . ' - ' . $icon_set['setName']); ?></h3>
<!-- Add data-icon-set-id attribute to the Install and Uninstall buttons -->
<button class="install-btn" data-icon-set-id="<?php echo esc_attr($icon_set['id']); ?>">Install</button>
<button class="uninstall-btn" data-icon-set-id="<?php echo esc_attr($icon_set['id']); ?>">Uninstall</button>
</div>
<?php
}
} else {
echo '<p>' . esc_html__('No icon definitions found.', 'lcp') . '</p>';
}
}
// Enqueue the dashboard styles only on the icon-management page
function mytheme_enqueue_dashboard_styles($hook) {
// Enqueue CSS for the dashboard
wp_enqueue_style(
'mytheme-dashboard-css',
get_template_directory_uri() . '/assets/css/dashboard.css'
);
}
add_action('admin_enqueue_scripts', 'mytheme_enqueue_dashboard_styles');
// Handle the AJAX request for installing icon sets
function lcp_install_icon_set($defaults = false) {
$json_path = get_template_directory() . '/assets/json/icons/icon-definitions.json';
if ($defaults) {
// Import only the default icons
if (file_exists($json_path)) {
$json_data = file_get_contents($json_path);
$icon_sets = json_decode($json_data, true);
// Loop through all icon sets and filter for default icons
foreach ($icon_sets as $icon_set) {
if (isset($icon_set['default']) && $icon_set['default'] === true) {
$file_name = $icon_set['fileName']; // Assuming the JSON structure has 'fileName' key
$icon_file_path = get_template_directory() . '/assets/json/icons/' . $file_name;
if (file_exists($icon_file_path)) {
$icon_data = file_get_contents($icon_file_path);
$icon_json = json_decode($icon_data, true);
// Check if svgs exist and process them
if (isset($icon_json[0]['svgs']) && is_array($icon_json[0]['svgs'])) {
foreach ($icon_json[0]['svgs'] as $svg) {
global $wpdb;
$table_name = $wpdb->prefix . 'lcp_icons';
// Insert the SVG data into the database
$wpdb->insert(
$table_name,
array(
'icon_name' => $svg['name'],
'icon_set_id' => $icon_set['id'],
'icon_family' => $icon_set['setFamily'],
'icon_version' => $icon_set['version'],
'paths' => ($svg['paths']),
'viewbox' => sanitize_text_field($svg['viewBox']),
'icon_id' => sanitize_text_field($svg['id']),
)
);
}
} else {
wp_send_json_error(array('message' => 'SVGs data not found in the JSON file.'));
}
} else {
wp_send_json_error(array('message' => 'SVG file for default set not found.'));
}
}
}
} else {
wp_send_json_error(array('message' => 'Icon definitions file not found.'));
}
} elseif (isset($_POST['icon_set_id'])) {
// Default behavior - check for icon_set_id in $_POST
if (!isset($_POST['icon_set_id'])) {
wp_send_json_error(array('message' => 'Invalid icon set ID.'));
}
$icon_set_id = intval($_POST['icon_set_id']);
// Create the database table if it doesn't exist
mytheme_create_icons_table();
// Read the icon definitions JSON file
if (file_exists($json_path)) {
$json_data = file_get_contents($json_path);
$icon_sets = json_decode($json_data, true);
// Search for the selected icon set by ID
$selected_icon_set = null;
foreach ($icon_sets as $icon_set) {
if ($icon_set['id'] === $icon_set_id) {
$selected_icon_set = $icon_set;
break;
}
}
// If the icon set is found
if ($selected_icon_set) {
$file_name = $selected_icon_set['fileName']; // Assuming the JSON structure has 'fileName' key
$icon_file_path = get_template_directory() . '/assets/json/icons/' . $file_name;
// Now read the corresponding SVG file for the icon set
if (file_exists($icon_file_path)) {
$icon_data = file_get_contents($icon_file_path);
$icon_json = json_decode($icon_data, true);
// Check the structure of the decoded JSON
if (is_array($icon_json)) {
error_log(print_r($icon_json, true)); // Logs to PHP error log for inspection
}
// Loop through svgs if it exists and is an array
if (isset($icon_json[0]['svgs']) && is_array($icon_json[0]['svgs'])) {
foreach ($icon_json[0]['svgs'] as $svg) {
global $wpdb;
$table_name = $wpdb->prefix . 'lcp_icons';
// Insert each SVG data into the database
$wpdb->insert(
$table_name,
array(
'icon_name' => $svg['name'],
'icon_set_id' => $selected_icon_set['id'],
'icon_family' => $selected_icon_set['setFamily'],
'icon_version' => $selected_icon_set['version'],
'paths' => ($svg['paths']),
'viewbox' => sanitize_text_field($svg['viewBox']),
'icon_id' => sanitize_text_field($svg['id']),
)
);
}
wp_send_json_success(array('message' => 'Icon set installed and rows added with actual data.'));
} else {
wp_send_json_error(array('message' => 'SVGs data not found in the JSON file.'));
}
} else {
wp_send_json_error(array('message' => 'SVG file not found.'));
}
} else {
wp_send_json_error(array('message' => 'Icon set not found.'));
}
} else {
wp_send_json_error(array('message' => 'Icon definitions not found.'));
}
}
}
add_action('wp_ajax_install_icon_set', 'lcp_install_icon_set');
// Function to create the icons table in the database if it doesn't exist
function mytheme_create_icons_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'lcp_icons';
$charset_collate = $wpdb->get_charset_collate();
// SQL to create the table if it doesn't exist
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, -- Auto-increment for the ID
icon_name VARCHAR(255),
icon_set_id VARCHAR(255),
icon_family VARCHAR(255),
icon_version VARCHAR(50),
paths TEXT,
viewbox VARCHAR(50),
icon_id VARCHAR(255) UNIQUE, -- Unique identifier for each SVG (based on SVG 'id')
PRIMARY KEY (id)
) $charset_collate;";
// Include the necessary WordPress file to run dbDelta
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
function mytheme_enqueue_dashboard_scripts($hook) {
// Only load the script on the icon-management page
// Enqueue JavaScript for AJAX
wp_enqueue_script(
'icon-import-script',
get_template_directory_uri() . '/assets/js/icon-import.js',
array(), // No dependencies for vanilla JS
null,
true
);
// Pass the AJAX URL to the script
wp_localize_script('icon-import-script', 'mytheme_ajax', array(
'ajax_url' => admin_url('admin-ajax.php')
));
}
add_action('admin_enqueue_scripts', 'mytheme_enqueue_dashboard_scripts');
// Handle the AJAX request for uninstalling icon sets
function mytheme_uninstall_icon_set() {
// Ensure icon set ID is passed in the request
if (!isset($_POST['icon_set_id'])) {
wp_send_json_error(array('message' => 'Invalid icon set ID.'));
}
// Get the icon set ID from the request
$icon_set_id = intval($_POST['icon_set_id']); // Ensure it's an integer
global $wpdb;
// Define the table name
$table_name = $wpdb->prefix . 'lcp_icons';
// Delete all rows where the icon_set_id matches the passed ID
$deleted_rows = $wpdb->delete(
$table_name,
array('icon_set_id' => $icon_set_id), // Condition to match rows by icon_set_id
array('%d') // Sanitize the value as an integer
);
// Check if rows were deleted successfully
if ($deleted_rows) {
wp_send_json_success(array('message' => 'Icon set uninstalled and icons removed from the database.'));
} else {
wp_send_json_error(array('message' => 'No icons found for the specified icon set ID.'));
}
}
add_action('wp_ajax_uninstall_icon_set', 'mytheme_uninstall_icon_set');

View File

@ -0,0 +1,18 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab
[*.{yml,yaml}]
indent_style = space
indent_size = 2

30
includes/blocks/lcp-button/.gitignore vendored Normal file
View File

@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Coverage directory used by tools like istanbul
coverage
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Output of `npm pack`
*.tgz
# Output of `wp-scripts plugin-zip`
*.zip
# dotenv environment variables file
.env

View File

@ -0,0 +1,101 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "lcp/button",
"version": "0.1.0",
"title": "Button",
"category": "widgets",
"icon": "smiley",
"description": "A button for various functions or custom urls",
"example": {},
"supports": {
"html": false
},
"attributes": {
"buttonAction": {
"type": "string",
"default": "customUrl"
},
"customUrl": {
"type": "string",
"default": "#"
},
"buttonText": {
"type": "string",
"default": "Button Text"
},
"displayIcon": {
"type": "boolean",
"default": true
},
"iconSource": {
"type": "string",
"default": "manualSvgPath"
},
"iconSvgPath": {
"type": "string",
"default": ""
},
"iconSvgId": {
"type": "string",
"default": ""
},
"iconSvgViewbox": {
"type": "string",
"default": "0 0 510 510"
},
"popUpId": {
"type": "number"
},
"manualIconSvgPath": {
"type": "string",
"default": ""
},
"buttonHeight": {
"type": "string",
"default": ""
},
"buttonPadding": {
"type": "object",
"default": {
"extraLarge": {
"top": "10px",
"right": "10px",
"bottom": "10px",
"left": "10px"
},
"large": {
"top": "10px",
"right": "10px",
"bottom": "10px",
"left": "10px"
},
"medium": {
"top": "10px",
"right": "10px",
"bottom": "10px",
"left": "10px"
},
"small": {
"top": "10px",
"right": "10px",
"bottom": "10px",
"left": "10px"
}
}
},
"iconHeight": {
"type": "string",
"default": ""
},
"iconWidth": {
"type": "string",
"default": ""
}
},
"textdomain": "lcp",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js"
}

View File

@ -0,0 +1 @@
.wp-block-create-block-button{border:1px dotted red}.lcp-button{background-color:var(--wp--preset--color--accent);border:none;color:#fff;cursor:pointer;display:inline-block;font-size:var(--wp--preset--font-size--small);font-weight:700;margin:auto 5px;padding:10px;text-decoration:none;white-space:nowrap}.lcp-button .lcp-icon{height:1.2em;margin-left:10px;max-height:100%;vertical-align:middle;width:auto;fill:#fff}

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '00e12da1bdf9e61c448a');

View File

@ -0,0 +1 @@
.wp-block-create-block-button{border:1px dotted red}.lcp-button{background-color:var(--wp--preset--color--accent);border:none;color:#fff;cursor:pointer;display:inline-block;font-size:var(--wp--preset--font-size--small);font-weight:700;margin:auto 5px;padding:10px;text-decoration:none;white-space:nowrap}.lcp-button .lcp-icon{height:1.2em;margin-right:10px;max-height:100%;vertical-align:middle;width:auto;fill:#fff}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.wp-block-create-block-button{background-color:#21759b;color:#fff;padding:2px}

View File

@ -0,0 +1 @@
.wp-block-create-block-button{background-color:#21759b;color:#fff;padding:2px}

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array(), 'version' => '39bd3d2fc52e7ff1ed91');

View File

@ -0,0 +1 @@
console.log("Hello World! (from create-block-button block)");

View File

@ -0,0 +1,96 @@
import { __ } from '@wordpress/i18n';
import { BaseControl, __experimentalNumberControl as NumberControl, SelectControl, __experimentalHStack as HStack } from '@wordpress/components';
import { useState, useEffect } from 'react';
/**
* Control component with a number input and a select dropdown for units (px, rem, em, % etc.).
* Accepts a default value as a string (e.g., "15px", "10rem", etc.).
* Includes an optional 'auto' unit if includeAuto is true, and handles autoReturnsNull behavior.
*/
export function DimensionValueControl({ value = '10px', onChange, includeAuto = false, autoReturnsNull = false }) {
// Options for select control (CSS units) including 'auto' if enabled
const unitOptions = [
{ label: __('px'), value: 'px' },
{ label: __('%'), value: '%' },
{ label: __('em'), value: 'em' },
{ label: __('rem'), value: 'rem' },
{ label: __('vw'), value: 'vw' },
{ label: __('vh'), value: 'vh' },
...(includeAuto ? [{ label: __('auto'), value: 'auto' }] : []), // Add 'auto' option if includeAuto is true
];
// Parse the value string into a number and unit
const parseValue = (value) => {
const regex = /([0-9]+)([a-zA-Z%]+)?/; // Capture the number and the unit
const match = value.match(regex);
if (match) {
return {
numberValue: parseInt(match[1], 10), // Number part
unitValue: match[2] || 'px' // Unit part (default to 'px' if no unit found)
};
}
return { numberValue: 0, unitValue: 'px' }; // Fallback if invalid format
};
// Use the parsed value to set initial state
const { numberValue: initialNumber, unitValue: initialUnit } = parseValue(value);
const [numberValue, setNumberValue] = useState(initialNumber);
const [unitValue, setUnitValue] = useState(initialUnit);
// Combine the number and unit into a string like "15px"
const dimensionValue = `${numberValue}${unitValue}`;
// Handle number change
const onNumberChange = (newValue) => {
setNumberValue(newValue);
if (onChange && unitValue !== 'auto') {
onChange(`${newValue}${unitValue}`); // Pass updated value back to parent
}
};
// Handle unit change
const onUnitChange = (newUnit) => {
if (newUnit === 'auto') {
setNumberValue(null); // Reset the number value when 'auto' is selected
}
setUnitValue(newUnit);
if (onChange) {
const updatedValue = newUnit === 'auto'
? (autoReturnsNull ? null : 'auto')
: `${numberValue}${newUnit}`; // Pass 'auto' or null or updated value back to parent
onChange(updatedValue);
}
};
// Effect to handle when value prop changes (useful for syncing)
useEffect(() => {
const { numberValue, unitValue } = parseValue(value);
setNumberValue(numberValue);
setUnitValue(unitValue);
}, [value]);
return (
<BaseControl className="lcp-dimension-value-control">
<HStack>
{/* Number input control, disabled when 'auto' is selected */}
<NumberControl
className="lcp-number-control"
value={numberValue || ''}
onChange={onNumberChange}
min={0}
step={0.1}
spinControls={'none'}
disabled={unitValue === 'auto'} // Disable number input if 'auto' is selected
/>
{/* Select dropdown control for units */}
<SelectControl
className="lcp-select-control"
value={unitValue}
options={unitOptions}
onChange={onUnitChange}
/>
</HStack>
</BaseControl>
);
}

View File

@ -0,0 +1,59 @@
import { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { SelectControl } from '@wordpress/components';
export function IconSelectControl(props) {
const { iconSvgId, onIconChange } = props;
const [iconData, setIconData] = useState([]);
useEffect(() => {
const fetchIconData = async () => {
try {
const response = await fetch('/wp-json/lcp/v1/icons');
const data = await response.json();
if (Array.isArray(data) && data.length > 0) {
setIconData(data); // Set the fetched data directly
}
} catch (error) {
console.error('Error fetching icons:', error);
}
};
fetchIconData();
}, []);
const handleIconChange = (selectedIconId) => {
const selectedIcon = iconData.find(icon => icon.iconSvgId === selectedIconId);
if (selectedIcon && onIconChange) {
// Send both icon ID and path (SVG) to the parent component
onIconChange({
iconSvgId: selectedIcon.iconSvgId, // Pass icon ID to parent
iconSvgPath: selectedIcon.iconSvgPaths, // Pass icon paths to parent
viewbox: selectedIcon.selectedIconViewbox // Pass the viewbox to parent
});
console.log("Selected Icon ID:", selectedIcon.iconSvgId); // Debugging output
console.log("Selected Icon Path:", selectedIcon.iconSvgPaths); // Debugging output
console.log("Selected Icon Viewbox:", selectedIcon.selectedIconViewbox); // Debugging output
}
};
if (iconData.length === 0) {
return <p>{__('Loading icons...', 'lcp')}</p>; // Loading state
}
const iconOptions = iconData.map((icon) => ({
value: icon.iconSvgId, // Use icon ID as value for the SelectControl
label: icon.name, // Directly use the icon's name as the label
}));
return (
<SelectControl
label={__('Select Icon', 'lcp')}
value={iconSvgId} // Current selected icon ID
options={iconOptions}
onChange={handleIconChange} // Handle icon change
/>
);
}

View File

@ -0,0 +1,103 @@
import { __ } from '@wordpress/i18n';
import { BaseControl, Button, RangeControl, __experimentalHStack as HStack, __experimentalVStack as VStack } from '@wordpress/components';
import { DimensionValueControl } from './DimensionValueControl';
/**
* Padding Control component to manage padding values for different screen sizes.
*/
export function PaddingControl() {
return (
<BaseControl className="lcp-padding-control">
{/* Padding label and Unlink button */}
<HStack>
<span>{__('Padding')}</span>
<Button
variant="secondary"
aria-label={__('Unlink sides')}
onClick={() => {}}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false">
<path d="M10 17.389H8.444A5.194 5.194 0 1 1 8.444 7H10v1.5H8.444a3.694 3.694 0 0 0 0 7.389H10v1.5ZM14 7h1.556a5.194 5.194 0 0 1 0 10.39H14v-1.5h1.556a3.694 3.694 0 0 0 0-7.39H14V7Zm-4.5 6h5v-1.5h-5V13Z"></path>
</svg>
</Button>
</HStack>
{/* Extra Large Padding Controls */}
{/* Will update all padding values for all screen sizes if updateAllScreenSizes is true */}
{/* Top and Bottom HStack */}
<HStack style={{ flex: 1 }}>
{/* Top and Bottom Icon */}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" className="spacing-sizes-control__icon" aria-hidden="true" focusable="false">
<path d="m7.5 6h9v-1.5h-9zm0 13.5h9v-1.5h-9zm-3-3h1.5v-9h-1.5zm13.5-9v9h1.5v-9z" style={{ opacity: 0.25 }}></path>
<path d="m7.5 6h9v-1.5h-9z"></path>
<path d="m7.5 19.5h9v-1.5h-9z"></path>
</svg>
{/* RangeControl wrapped in HStack with flex: 1 applied to its parent */}
<HStack style={{ flex: 1 }}>
<DimensionValueControl/>
<RangeControl
withInputField={false}
value={10} // Placeholder value
onChange={() => {}}
min={0}
max={50}
/>
</HStack>
{/* Custom Padding Button */}
<Button
style={{padding:0,background:'none',color:'var(--wp-components-color-foreground)'} }
variant="primary"
onClick={() => {}}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false">
<path d="m19 7.5h-7.628c-.3089-.87389-1.1423-1.5-2.122-1.5-.97966 0-1.81309.62611-2.12197 1.5h-2.12803v1.5h2.12803c.30888.87389 1.14231 1.5 2.12197 1.5.9797 0 1.8131-.62611 2.122-1.5h7.628z"></path>
<path d="m19 15h-2.128c-.3089-.8739-1.1423-1.5-2.122-1.5s-1.8131.6261-2.122 1.5h-7.628v1.5h7.628c.3089.8739 1.1423 1.5 2.122 1.5s1.8131-.6261 2.122-1.5h2.128z"></path>
</svg>
</Button>
</HStack>
{/* Left and Right HStack */}
<HStack style={{ flex: 1 }}>
{/* Left and Right Icon */}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" className="spacing-sizes-control__icon" aria-hidden="true" focusable="false">
<path d="m7.5 6h9v-1.5h-9zm0 13.5h9v-1.5h-9zm-3-3h1.5v-9h-1.5zm13.5-9v9h1.5v-9z" style={{ opacity: 0.25 }}></path>
<path d="m7.5 6h9v-1.5h-9z"></path>
<path d="m4.5 7.5v9h1.5v-9z"></path>
<path d="m18 7.5v9h1.5v-9z"></path>
</svg>
{/* RangeControl wrapped in HStack with flex: 1 applied to its parent */}
<RangeControl
withInputField={false}
value={10} // Placeholder value
onChange={() => {}}
min={0}
max={50}
/>
{/* Custom Padding Button */}
<Button
variant="primary"
onClick={() => {}}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false">
<path d="m19 7.5h-7.628c-.3089-.87389-1.1423-1.5-2.122-1.5-.97966 0-1.81309.62611-2.12197 1.5h-2.12803v1.5h2.12803c.30888.87389 1.14231 1.5 2.12197 1.5.9797 0 1.8131-.62611 2.122-1.5h7.628z"></path>
<path d="m19 15h-2.128c-.3089-.8739-1.1423-1.5-2.122-1.5s-1.8131.6261-2.122 1.5h-7.628v1.5h7.628c.3089.8739 1.1423 1.5 2.122 1.5s1.8131-.6261 2.122-1.5h2.128z"></path>
</svg>
</Button>
</HStack>
{/* Additional controls can be added here in a VStack */}
<VStack>
{/* Placeholder for additional components */}
</VStack>
</BaseControl>
);
}

View File

@ -0,0 +1,69 @@
<?php
/**
* Plugin Name: Button
* Description: Example block scaffolded with Create Block tool.
* Requires at least: 6.6
* Requires PHP: 7.2
* Version: 0.1.0
* Author: The WordPress Contributors
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: button
*
* @package CreateBlock
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Registers the block using the metadata loaded from the `block.json` file.
* Behind the scenes, it registers also all assets so they can be enqueued
* through the block editor in the corresponding context.
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
function create_block_button_block_init() {
register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'create_block_button_block_init' );
/* REST API */
function register_icons_rest_api_endpoint() {
register_rest_route( 'lcp/v1', '/icons', array(
'methods' => 'GET',
'callback' => 'get_icons_data_from_db',
'permission_callback' => '__return_true', // Public access; modify this if real permissions needed
) );
}
add_action( 'rest_api_init', 'register_icons_rest_api_endpoint' );
function get_icons_data_from_db() {
global $wpdb;
// Query the lcp_icons table
$results = $wpdb->get_results(
"SELECT icon_id, icon_name, paths, viewbox FROM {$wpdb->prefix}lcp_icons"
);
// If no icons are found, return an empty array
if ( empty( $results ) ) {
return [];
}
// Format the results for the frontend
$icons = array_map( function( $icon ) {
return [
'iconSvgId' => $icon->icon_id, // Icon ID
'iconSvgPaths' => $icon->paths, // SVG paths (can be multiple)
'selectedIconViewbox' => $icon->viewbox, // ViewBox for the SVG
'name' => $icon->icon_name, // Add name field
];
}, $results );
return $icons;
}

View File

@ -0,0 +1,20 @@
{
"name": "button",
"version": "0.1.0",
"description": "Example block scaffolded with Create Block tool.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
"main": "build/index.js",
"scripts": {
"build": "wp-scripts build",
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"packages-update": "wp-scripts packages-update",
"plugin-zip": "wp-scripts plugin-zip",
"start": "wp-scripts start"
},
"devDependencies": {
"@wordpress/scripts": "^30.6.0"
}
}

View File

@ -0,0 +1,55 @@
=== Button ===
Contributors: The WordPress Contributors
Tags: block
Tested up to: 6.6
Stable tag: 0.1.0
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Example block scaffolded with Create Block tool.
== Description ==
This is the long description. No limit, and you can use Markdown (as well as in the following sections).
For backwards compatibility, if this section is missing, the full length of the short description will be used, and
Markdown parsed.
== Installation ==
This section describes how to install the plugin and get it working.
e.g.
1. Upload the plugin files to the `/wp-content/plugins/button` directory, or install the plugin through the WordPress plugins screen directly.
1. Activate the plugin through the 'Plugins' screen in WordPress
== Frequently Asked Questions ==
= A question that someone might have =
An answer to that question.
= What about foo bar? =
Answer to foo bar dilemma.
== Screenshots ==
1. This screen shot description corresponds to screenshot-1.(png|jpg|jpeg|gif). Note that the screenshot is taken from
the /assets directory or the directory that contains the stable readme.txt (tags or trunk). Screenshots in the /assets
directory take precedence. For example, `/assets/screenshot-1.png` would win over `/tags/4.3/screenshot-1.png`
(or jpg, jpeg, gif).
2. This is the second screen shot
== Changelog ==
= 0.1.0 =
* Release
== Arbitrary section ==
You may provide arbitrary sections, in the same format as the ones above. This may be of use for extremely complicated
plugins where more information needs to be conveyed that doesn't fit into the categories of "description" or
"installation." Arbitrary sections will be shown below the built-in sections outlined above.

View File

@ -0,0 +1,101 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "lcp/button",
"version": "0.1.0",
"title": "Button",
"category": "widgets",
"icon": "smiley",
"description": "A button for various functions or custom urls",
"example": {},
"supports": {
"html": false
},
"attributes": {
"buttonAction": {
"type": "string",
"default": "customUrl"
},
"customUrl": {
"type": "string",
"default": "#"
},
"buttonText": {
"type": "string",
"default": "Button Text"
},
"displayIcon": {
"type": "boolean",
"default": true
},
"iconSource": {
"type": "string",
"default": "manualSvgPath"
},
"iconSvgPath": {
"type": "string",
"default": ""
},
"iconSvgId": {
"type": "string",
"default": ""
},
"iconSvgViewbox": {
"type": "string",
"default": "0 0 510 510"
},
"popUpId": {
"type": "number"
},
"manualIconSvgPath":{
"type": "string",
"default": ""
},
"buttonHeight":{
"type": "string",
"default": ""
},
"buttonPadding":{
"type": "object",
"default": {
"extraLarge": {
"top": "10px",
"right": "10px",
"bottom": "10px",
"left": "10px"
},
"large": {
"top": "10px",
"right": "10px",
"bottom": "10px",
"left": "10px"
},
"medium": {
"top": "10px",
"right": "10px",
"bottom": "10px",
"left": "10px"
},
"small": {
"top": "10px",
"right": "10px",
"bottom": "10px",
"left": "10px"
}
}
},
"iconHeight": {
"type": "string",
"default": ""
},
"iconWidth": {
"type": "string",
"default": ""
}
},
"textdomain": "lcp",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js"
}

View File

@ -0,0 +1,145 @@
import { __ } from '@wordpress/i18n';
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, SelectControl, TextControl, TextareaControl, ToggleControl } from '@wordpress/components';
import { useState, useEffect } from '@wordpress/element';
import './editor.scss';
import { IconSelectControl } from '../components/IconSelectControl';
import { PaddingControl } from '../components/PaddingControl';
import { DimensionValueControl } from '../components/DimensionValueControl';
export default function Edit(props) {
const { attributes, setAttributes } = props;
const { buttonAction, iconHeight, buttonText, iconSvgId, iconSvgPath, iconSvgViewbox, displayIcon, iconSource, customUrl, buttonPadding } = attributes;
// Handle icon selection from dropdown
const handleIconChanges = (selectedIcon) => {
console.log("Icon changed:", selectedIcon);
if (selectedIcon && selectedIcon.iconSvgPath) {
setAttributes({
iconSvgPath: selectedIcon.iconSvgPath,
iconSvgId: selectedIcon.iconSvgId,
iconSvgViewbox: selectedIcon.viewbox
});
}
};
const handleToggleChange = (value) => {
setAttributes({ displayIcon: value });
};
const handleCustomUrlChange = (value) => {
setAttributes({ customUrl: value });
};
const handlePaddingChange = (value) => {
if (typeof value === 'number') {
value = `${value}px`;
}
setAttributes({ buttonPadding: value });
};
// Handle changes to icon height (from the DimensionValueControl)
const handleIconHeightChange = (newHeight) => {
console.log("New icon height:", newHeight); // Debugging line
setAttributes({ iconHeight: newHeight }); // Update the iconHeight attribute
};
const iconSourceOptions = [
{ value: 'manualSvgPath', label: 'SVG Path' },
{ value: 'iconSelector', label: 'Icon Library' },
];
const buttonActionOptions = [
{ value: 'customUrl', label: 'Custom URL' },
{ value: 'showLoginForm', label: 'Show Login Form' },
{ value: 'logOut', label: 'Open Popup' },
{ value: 'shareCurrentPost', label: 'Share Current Post' },
{ value: 'displaySidecontent', label: 'Display Sidecontent' }
];
return (
<>
<InspectorControls>
<PanelBody title={__("Button Settings")}>
<PaddingControl
onChange={handlePaddingChange}
/>
<SelectControl
label={__("Button Action")}
value={buttonAction}
options={buttonActionOptions}
onChange={(value) => setAttributes({ buttonAction: value })}
/>
{buttonAction === 'customUrl' && (
<TextControl
label={__("Custom URL")}
value={customUrl}
onChange={handleCustomUrlChange}
/>
)}
<TextControl
label={__("Button Text")}
value={buttonText}
onChange={(value) => setAttributes({ buttonText: value })}
/>
<ToggleControl
label="Display Icon"
checked={displayIcon}
onChange={handleToggleChange}
/>
<DimensionValueControl
value={iconHeight} // Pass the current iconHeight to the DimensionValueControl
onChange={(newHeight) => setAttributes({ iconHeight: newHeight })} // Update iconHeight when it changes
includeAuto={true}
autoReturnsNull={true}
/>
{displayIcon && (
<>
<SelectControl
label={__("Icon Source")}
value={iconSource}
options={iconSourceOptions}
onChange={(value) => setAttributes({ iconSource: value })}
/>
{iconSource === 'manualSvgPath' && (
<TextareaControl
label="Icon SVG Path"
value={iconSvgPath}
onChange={(value) => setAttributes({ iconSvgPath: value })}
/>
)}
{iconSource === 'iconSelector' && (
<IconSelectControl
iconSvgId={iconSvgId}
onIconChange={handleIconChanges}
/>
)}
</>
)}
</PanelBody>
</InspectorControls>
<div {...useBlockProps()}>
{buttonAction === 'customUrl' ? (
<a href={customUrl} className="lcp-button" style={{ padding: buttonPadding || '10px' }}>
{displayIcon && iconSvgPath && (
<svg style={{ height: iconHeight }} className="lcp-icon" xmlns="http://www.w3.org/2000/svg" viewBox={iconSvgViewbox || "0 0 576 576"} dangerouslySetInnerHTML={{ __html: iconSvgPath }} />
)}
<span className="lcp-button-text">
{buttonText || 'Button'}
</span>
</a>
) : (
<button className="lcp-button" style={{ padding: buttonPadding || '10px' }}>
{displayIcon && iconSvgPath && (
<svg style={{ height: iconHeight }} className="lcp-icon" xmlns="http://www.w3.org/2000/svg" viewBox={iconSvgViewbox || "0 0 576 576"} dangerouslySetInnerHTML={{ __html: iconSvgPath }} />
)}
<span className="lcp-button-text">
{buttonText || 'Button'}
</span>
</button>
)}
</div>
</>
);
}

View File

@ -0,0 +1,32 @@
/**
* The following styles get applied inside the editor only.
*
* Replace them with your own styles or remove the file completely.
*/
.wp-block-create-block-button {
border: 1px dotted #f00;
}
.lcp-button {
display: inline-block;
background-color: var(--wp--preset--color--accent);
border: none;
color: #fff;
text-decoration: none;
padding: 10px;
font-weight: bold;
font-size: var(--wp--preset--font-size--small);
white-space: nowrap;
cursor: pointer;
margin:auto 5px;
}
.lcp-button .lcp-icon {
height: 1.2em;
max-height:100%;
width: auto;
vertical-align: middle; /* Aligns the icon with the text vertically */
margin-right: 10px; /* Space between the icon and the text */
fill:white;
}

View File

@ -0,0 +1,39 @@
/**
* Registers a new block provided a unique name and an object defining its behavior.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
import { registerBlockType } from '@wordpress/blocks';
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* All files containing `style` keyword are bundled together. The code used
* gets applied both to the front of your site and to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './style.scss';
/**
* Internal dependencies
*/
import Edit from './edit';
import save from './save';
import metadata from './block.json';
/**
* Every block starts by registering a new block type definition.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
registerBlockType( metadata.name, {
/**
* @see ./edit.js
*/
edit: Edit,
/**
* @see ./save.js
*/
save,
} );

View File

@ -0,0 +1,35 @@
import { useBlockProps } from '@wordpress/block-editor';
export default function save(props) {
const { attributes } = props;
const {displayIcon, buttonText, buttonPadding,iconHeight,iconSvgPath, iconSvgViewbox, buttonAction, customUrl } = attributes; // Destructure buttonText, iconSvgPath, and iconSvgViewbox
// Get the block props for the button
const blockProps = useBlockProps.save();
// Conditionally render the link or button based on buttonAction
return (
<div {...blockProps}>
{buttonAction === 'customUrl' ? (
<a href={customUrl} className="lcp-button" style={{ padding: buttonPadding || '10px' }}>
{displayIcon && iconSvgPath && (
<svg style={{ height: iconHeight }} className="lcp-icon" xmlns="http://www.w3.org/2000/svg" viewBox={iconSvgViewbox || "0 0 576 576"} dangerouslySetInnerHTML={{ __html: iconSvgPath }} />
)}
<span className="lcp-button-text">
{buttonText || 'Button'}
</span>
</a>
) : (
<button className="lcp-button" style={{ padding: buttonPadding || '10px' }}>
{displayIcon && iconSvgPath && (
<svg style={{ height: iconHeight }} className="lcp-icon" xmlns="http://www.w3.org/2000/svg" viewBox={iconSvgViewbox || "0 0 576 576"} dangerouslySetInnerHTML={{ __html: iconSvgPath }} />
)}
<span className="lcp-button-text">
{buttonText || 'Button'}
</span>
</button>
)}
</div>
);
}

View File

@ -0,0 +1,13 @@
/**
* The following styles get applied both on the front of your site
* and in the editor.
*
* Replace them with your own styles or remove the file completely.
*/
.wp-block-create-block-button {
background-color: #21759b;
color: #fff;
padding: 2px;
}

View File

@ -0,0 +1,25 @@
/**
* Use this file for JavaScript code that you want to run in the front-end
* on posts/pages that contain this block.
*
* When this file is defined as the value of the `viewScript` property
* in `block.json` it will be enqueued on the front end of the site.
*
* Example:
*
* ```js
* {
* "viewScript": "file:./view.js"
* }
* ```
*
* If you're not making any changes to this file because your project doesn't need any
* JavaScript running in the front-end, then you should delete this file and remove
* the `viewScript` property from `block.json`.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#view-script
*/
/* eslint-disable no-console */
console.log( 'Hello World! (from create-block-button block)' );
/* eslint-enable no-console */

View File

@ -0,0 +1,18 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab
[*.{yml,yaml}]
indent_style = space
indent_size = 2

View File

@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Coverage directory used by tools like istanbul
coverage
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Output of `npm pack`
*.tgz
# Output of `wp-scripts plugin-zip`
*.zip
# dotenv environment variables file
.env

View File

@ -0,0 +1,141 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "lcp/dynamic-container",
"version": "0.1.0",
"title": "Dynamic Container",
"category": "widgets",
"icon": "smiley",
"description": "A general purpose container that uses dynamic rendering",
"example": {},
"supports": {
"anchor": true,
"align": [
"left",
"right",
"wide",
"full"
],
"background": {
"backgroundImage": true,
"backgroundSize": true,
"__experimentalDefaultControls": {
"backgroundImage": true
}
},
"color": {
"gradients": true,
"background": true,
"link": true,
"__experimentalDefaultControls": {
"background": true,
"text": true
}
}
},
"attributes": {
"maxWidthExtraLarge": {
"type": "string"
},
"maxWidthLarge": {
"type": "string"
},
"maxWidthMedium": {
"type": "string"
},
"maxWidthSmall": {
"type": "string"
},
"minHeightExtraLarge": {
"type": "string"
},
"minHeightLarge": {
"type": "string"
},
"minHeightMedium": {
"type": "string"
},
"minHeightSmall": {
"type": "string"
},
"isBox": {
"type": "boolean",
"default": false
},
"backgroundColor": {
"type": "string"
},
"entranceAnimation": {
"type": "string"
},
"exitAnimation": {
"type": "string"
},
"overflow": {
"type": "string"
},
"padding": {
"type": "object",
"default": {
"extraLarge": {
"top": "0",
"right": "0",
"bottom": "0",
"left": "0"
},
"large": {
"top": "0",
"right": "0",
"bottom": "0",
"left": "0"
},
"medium": {
"top": "0",
"right": "0",
"bottom": "0",
"left": "0"
},
"small": {
"top": "0",
"right": "0",
"bottom": "0",
"left": "0"
}
}
},
"margin": {
"type": "object",
"default": {
"extraLarge": {
"top": "12px",
"right": "0",
"bottom": "12px",
"left": "0"
},
"large": {
"top": "12px",
"right": "0",
"bottom": "12px",
"left": "0"
},
"medium": {
"top": "12px",
"right": "0",
"bottom": "12px",
"left": "0"
},
"small": {
"top": "12px",
"right": "0",
"bottom": "12px",
"left": "0"
}
}
}
},
"textdomain": "lcp",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js"
}

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n'), 'version' => '40a5279a7e8774abfe4c');

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.wp-block-create-block-lcp-viewport{background-color:#21759b;color:#fff;padding:2px}

View File

@ -0,0 +1 @@
.wp-block-create-block-lcp-viewport{background-color:#21759b;color:#fff;padding:2px}

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array(), 'version' => 'd4e4a494008d04e1eb42');

View File

@ -0,0 +1 @@
console.log("Hello World! (from create-block-lcp-viewport block)");

View File

@ -0,0 +1,195 @@
<?php /**
* Function to generate random class and add dynamic padding styles
*/
if (!function_exists('lcp_random_string')) {
function lcp_random_string($length = 8, $css_compliant = false, $include_character_types = '') {
// Define character sets
$lowercase = 'abcdefghijklmnopqrstuvwxyz';
$uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$numbers = '0123456789';
$special_chars = '!@#$%^&*()_+-=[]{}|;:,.<>?';
$all_chars = $lowercase . $uppercase . $numbers . $special_chars;
// Default to using all characters if no specific types are provided
if (empty($include_character_types)) {
$include_character_types = 'all';
}
// Build the allowed character set
$char_set = '';
if ($include_character_types === 'all') {
// Include everything
$char_set = $all_chars;
} else {
// Add specific types requested
if (strpos($include_character_types, 'lowercase') !== false) {
$char_set .= $lowercase;
}
if (strpos($include_character_types, 'uppercase') !== false) {
$char_set .= $uppercase;
}
if (strpos($include_character_types, 'numbers') !== false) {
$char_set .= $numbers;
}
if (strpos($include_character_types, 'special') !== false) {
$char_set .= $special_chars;
}
}
// Ensure that the string is valid for CSS (starts with a letter and can only include letters, digits, hyphens, or underscores)
$css_char_set = $lowercase . $uppercase . $numbers . '-_';
// Random string generation logic
$random_string = '';
$first_char = '';
// If CSS compliant, start with a letter (either lowercase or uppercase)
if ($css_compliant) {
// Ensure the first character is a letter (CSS compliant start)
$first_char = $lowercase[rand(0, strlen($lowercase) - 1)];
$random_string .= $first_char;
$length--; // Decrease length by 1 as we already added the first char
}
// Fill the rest of the string with random characters from the valid set (CSS compliant)
for ($i = 0; $i < $length; $i++) {
// Use only characters that are CSS compliant (letters, digits, hyphens, or underscores)
$random_string .= $css_char_set[rand(0, strlen($css_char_set) - 1)];
}
// Return the string
return $random_string;
}
}
function render_lcp_container( $attributes, $content ) {
// Debugging: Check the passed attributes
//var_dump($attributes);
// Generate a random class name (optional, could be customized)
$random_class = lcp_random_string(12,true);
// Get the padding and backgroundColor attributes
$padding = isset( $attributes['padding'] ) ? $attributes['padding'] : array();
$background_color = isset( $attributes['backgroundColor'] ) ? $attributes['backgroundColor'] : '#ffffff'; // Default color
// Debugging: Check padding and background color
error_log(print_r($padding, true));
error_log(print_r($background_color, true));
// Check if all padding values are the same across all sizes
$same_padding = true;
$padding_top = $padding['extraLarge']['top'];
$padding_right = $padding['extraLarge']['right'];
$padding_bottom = $padding['extraLarge']['bottom'];
$padding_left = $padding['extraLarge']['left'];
// Compare the padding for all other sizes (large, medium, small)
foreach ( ['large', 'medium', 'small'] as $size ) {
if (
$padding[$size]['top'] !== $padding_top ||
$padding[$size]['right'] !== $padding_right ||
$padding[$size]['bottom'] !== $padding_bottom ||
$padding[$size]['left'] !== $padding_left
) {
$same_padding = false;
break;
}
}
// Prepare the inline style or media queries
$style = '';
// Add background-color to the inline style
$style .= sprintf( 'background-color: %s;', esc_attr( $background_color ) );
if ( $same_padding ) {
// If all padding values are the same, use inline style
$style .= sprintf(
'padding-top: %s; padding-right: %s; padding-bottom: %s; padding-left: %s;',
esc_attr( $padding_top ),
esc_attr( $padding_right ),
esc_attr( $padding_bottom ),
esc_attr( $padding_left )
);
} else {
// If padding is different, generate media queries for different sizes
$style .= sprintf(
'@media (min-width: 1200px) { .%s { padding-top: %s; padding-right: %s; padding-bottom: %s; padding-left: %s; } }',
esc_attr( $random_class ),
esc_attr( $padding['extraLarge']['top'] ),
esc_attr( $padding['extraLarge']['right'] ),
esc_attr( $padding['extraLarge']['bottom'] ),
esc_attr( $padding['extraLarge']['left'] )
);
$style .= sprintf(
'@media (min-width: 1024px) { .%s { padding-top: %s; padding-right: %s; padding-bottom: %s; padding-left: %s; } }',
esc_attr( $random_class ),
esc_attr( $padding['large']['top'] ),
esc_attr( $padding['large']['right'] ),
esc_attr( $padding['large']['bottom'] ),
esc_attr( $padding['large']['left'] )
);
$style .= sprintf(
'@media (min-width: 768px) { .%s { padding-top: %s; padding-right: %s; padding-bottom: %s; padding-left: %s; } }',
esc_attr( $random_class ),
esc_attr( $padding['medium']['top'] ),
esc_attr( $padding['medium']['right'] ),
esc_attr( $padding['medium']['bottom'] ),
esc_attr( $padding['medium']['left'] )
);
$style .= sprintf(
'@media (max-width: 767px) { .%s { padding-top: %s; padding-right: %s; padding-bottom: %s; padding-left: %s; } }',
esc_attr( $random_class ),
esc_attr( $padding['small']['top'] ),
esc_attr( $padding['small']['right'] ),
esc_attr( $padding['small']['bottom'] ),
esc_attr( $padding['small']['left'] )
);
}
// Generate the <style> tag with the final CSS (either inline or media queries)
$style_tag = '';
if ( ! empty( $style ) ) {
$style_tag = sprintf( '<style>.%s { %s }</style>', esc_attr( $random_class ), $style );
}
// Output the content wrapped in the div with the random class and padding styles
return $style_tag . sprintf(
'<div class="lcp-container %s">%s</div>',
esc_attr( $random_class ),
$content
);
}
/**
* Function to return the media query breakpoint based on the size
*/
function get_media_query_breakpoint( $size ) {
// Define breakpoints for each size
$breakpoints = array(
'extraLarge' => '1200px',
'large' => '1024px',
'medium' => '768px',
'small' => '480px',
);
return isset( $breakpoints[$size] ) ? $breakpoints[$size] : '480px';
}
/**
* Function to initialize the block
*/
function lcp_dynamic_container_block_init() {
register_block_type( __DIR__ . '/build', array(
'render_callback' => 'render_lcp_dynamic_container', // Add the render callback here
));
}
add_action( 'init', 'lcp_dynamic_container_block_init' );

View File

@ -0,0 +1,20 @@
{
"name": "lcp-viewport",
"version": "0.1.0",
"description": "Example block scaffolded with Create Block tool.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
"main": "build/index.js",
"scripts": {
"build": "wp-scripts build",
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"packages-update": "wp-scripts packages-update",
"plugin-zip": "wp-scripts plugin-zip",
"start": "wp-scripts start"
},
"devDependencies": {
"@wordpress/scripts": "^30.4.0"
}
}

View File

@ -0,0 +1,55 @@
=== Lcp Viewport ===
Contributors: The WordPress Contributors
Tags: block
Tested up to: 6.6
Stable tag: 0.1.0
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Example block scaffolded with Create Block tool.
== Description ==
This is the long description. No limit, and you can use Markdown (as well as in the following sections).
For backwards compatibility, if this section is missing, the full length of the short description will be used, and
Markdown parsed.
== Installation ==
This section describes how to install the plugin and get it working.
e.g.
1. Upload the plugin files to the `/wp-content/plugins/lcp-viewport` directory, or install the plugin through the WordPress plugins screen directly.
1. Activate the plugin through the 'Plugins' screen in WordPress
== Frequently Asked Questions ==
= A question that someone might have =
An answer to that question.
= What about foo bar? =
Answer to foo bar dilemma.
== Screenshots ==
1. This screen shot description corresponds to screenshot-1.(png|jpg|jpeg|gif). Note that the screenshot is taken from
the /assets directory or the directory that contains the stable readme.txt (tags or trunk). Screenshots in the /assets
directory take precedence. For example, `/assets/screenshot-1.png` would win over `/tags/4.3/screenshot-1.png`
(or jpg, jpeg, gif).
2. This is the second screen shot
== Changelog ==
= 0.1.0 =
* Release
== Arbitrary section ==
You may provide arbitrary sections, in the same format as the ones above. This may be of use for extremely complicated
plugins where more information needs to be conveyed that doesn't fit into the categories of "description" or
"installation." Arbitrary sections will be shown below the built-in sections outlined above.

View File

@ -0,0 +1,136 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "lcp/dynamic-container",
"version": "0.1.0",
"title": "Dynamic Container",
"category": "widgets",
"icon": "smiley",
"description": "A general purpose container that uses dynamic rendering",
"example": {},
"supports": {
"anchor": true,
"align": [ "left", "right", "wide", "full" ],
"background": {
"backgroundImage": true,
"backgroundSize": true,
"__experimentalDefaultControls": {
"backgroundImage": true
}
},
"color": {
"gradients": true,
"background": true,
"link": true,
"__experimentalDefaultControls": {
"background": true,
"text": true
}
}
},
"attributes": {
"maxWidthExtraLarge": {
"type": "string"
},
"maxWidthLarge": {
"type": "string"
},
"maxWidthMedium": {
"type": "string"
},
"maxWidthSmall": {
"type": "string"
},
"minHeightExtraLarge": {
"type": "string"
},
"minHeightLarge": {
"type": "string"
},
"minHeightMedium": {
"type": "string"
},
"minHeightSmall": {
"type": "string"
},
"isBox": {
"type": "boolean",
"default": false
},
"backgroundColor": {
"type": "string"
},
"entranceAnimation": {
"type": "string"
},
"exitAnimation": {
"type": "string"
},
"overflow": {
"type": "string"
},
"padding": {
"type": "object",
"default": {
"extraLarge": {
"top": "0",
"right": "0",
"bottom": "0",
"left": "0"
},
"large": {
"top": "0",
"right": "0",
"bottom": "0",
"left": "0"
},
"medium": {
"top": "0",
"right": "0",
"bottom": "0",
"left": "0"
},
"small": {
"top": "0",
"right": "0",
"bottom": "0",
"left": "0"
}
}
},
"margin": {
"type": "object",
"default": {
"extraLarge": {
"top": "12px",
"right": "0",
"bottom": "12px",
"left": "0"
},
"large": {
"top": "12px",
"right": "0",
"bottom": "12px",
"left": "0"
},
"medium": {
"top": "12px",
"right": "0",
"bottom": "12px",
"left": "0"
},
"small": {
"top": "12px",
"right": "0",
"bottom": "12px",
"left": "0"
}
}
}
},
"textdomain": "lcp",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js"}

View File

@ -0,0 +1,211 @@
import { useBlockProps, InnerBlocks, InspectorControls } from '@wordpress/block-editor';
import { __experimentalToggleGroupControl as ToggleGroupControl,
__experimentalToggleGroupControlOption as ToggleGroupControlOption, __experimentalUnitControl as UnitControl, BaseControl, ToggleControl, ColorPalette, Popover, Button } from '@wordpress/components';
import { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
/**
* 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.
*
* @param {Object} props - The props for the block.
* @return {Element} Element to render.
*/
export default function Edit({ attributes, setAttributes }) {
const blockProps = useBlockProps();
const { padding, maxWidthLarge, maxWidthMedium, maxWidthSmall, minHeightLarge, minHeightMedium, minHeightSmall, backgroundColor } = attributes; // Destructure necessary attributes
// State for independent padding toggle
const [isIndependentLarge, setIsIndependentLarge] = useState(false);
// Toggle to show or hide the color picker popover
const [showColorPopover, setShowColorPopover] = useState(false);
const [selectedColor, setSelectedColor] = useState(backgroundColor || '#ffffff'); // Default color
// Toggle padding for individual sizes
const handleToggleChange = () => {
setIsIndependentLarge(!isIndependentLarge);
};
// Update padding for all sizes
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 }
};
setAttributes({ padding: newPadding });
};
// Handle individual padding changes
const handlePaddingChange = (size, position, newValue) => {
const updatedPadding = { ...padding };
updatedPadding[size][position] = newValue;
setAttributes({ padding: updatedPadding });
};
// Handle color change
const handleColorChange = (color) => {
setSelectedColor(color);
setAttributes({ backgroundColor: color }); // Update background color
};
// Handle maxWidth change for different sizes
const handleMaxWidthChange = (value, size) => {
setAttributes({ [`maxWidth${size}`]: value });
};
// Handle minHeight change for different sizes
const handleMinHeightChange = (value, size) => {
setAttributes({ [`minHeight${size}`]: value });
};
useEffect(() => {
console.log("Updated attributes:", attributes);
}, [attributes]);
return (
<>
<InspectorControls>
<ToggleGroupControl
label="my label"
value="vertical"
isBlock
__nextHasNoMarginBottom
__next40pxDefaultSize
>
<ToggleGroupControlOption value="horizontal" label="Horizontal" />
<ToggleGroupControlOption value="vertical" label="Vertical" />
</ToggleGroupControl>
{/* BaseControl for padding */}
<BaseControl label="Padding - Desktop">
<div style={{ display: 'flex', flexDirection: 'row' }}>
<span style={{ marginRight: '10px' }}>Padding</span>
<ToggleControl
label="Use Independent Padding"
checked={isIndependentLarge}
onChange={handleToggleChange}
/>
</div>
{/* Padding controls */}
{isIndependentLarge ? (
<div style={{ display: 'grid', padding: '10px', gridTemplateColumns: '1fr 1fr', gap: '10px', justifyItems: 'center' }}>
{/* Padding controls for top, left, right, bottom */}
<fieldset style={{ gridColumn: 'span 2', width: '116px' }}>
<legend>Top</legend>
<UnitControl
value={padding.extraLarge?.top || '10px'}
onChange={(newValue) => handlePaddingChange('extraLarge', 'top', newValue)}
/>
</fieldset>
<fieldset>
<legend>Left</legend>
<UnitControl
value={padding.extraLarge?.left || '10px'}
onChange={(newValue) => handlePaddingChange('extraLarge', 'left', newValue)}
/>
</fieldset>
<fieldset>
<legend>Right</legend>
<UnitControl
value={padding.extraLarge?.right || '10px'}
onChange={(newValue) => handlePaddingChange('extraLarge', 'right', newValue)}
/>
</fieldset>
<fieldset style={{ gridColumn: 'span 2', width: '116px' }}>
<legend>Bottom</legend>
<UnitControl
value={padding.extraLarge?.bottom || '10px'}
onChange={(newValue) => handlePaddingChange('extraLarge', 'bottom', newValue)}
/>
</fieldset>
</div>
) : (
<UnitControl
label="Padding Value"
value={999} // You can replace this with an attribute value
onChange={updatePaddingForAllSizes}
/>
)}
</BaseControl>
{/* Max Width Controls */}
<BaseControl label="Max Width">
<div style={{ display: 'flex', flexDirection: 'column' }}>
<UnitControl
label="Large"
value={maxWidthLarge}
onChange={(value) => handleMaxWidthChange(value, 'Large')}
defaultUnit="px"
/>
<UnitControl
label="Medium"
value={maxWidthMedium}
onChange={(value) => handleMaxWidthChange(value, 'Medium')}
defaultUnit="px"
/>
<UnitControl
label="Small"
value={maxWidthSmall}
onChange={(value) => handleMaxWidthChange(value, 'Small')}
defaultUnit="px"
/>
</div>
</BaseControl>
{/* Min Height Controls */}
<BaseControl label="Min Height">
<div style={{ display: 'flex', flexDirection: 'column' }}>
<UnitControl
label="Large"
value={minHeightLarge}
onChange={(value) => handleMinHeightChange(value, 'Large')}
defaultUnit="px"
/>
<UnitControl
label="Medium"
value={minHeightMedium}
onChange={(value) => handleMinHeightChange(value, 'Medium')}
defaultUnit="px"
/>
<UnitControl
label="Small"
value={minHeightSmall}
onChange={(value) => handleMinHeightChange(value, 'Small')}
defaultUnit="px"
/>
</div>
</BaseControl>
{/* Background color picker */}
<BaseControl label={__('Background Color')}>
<div>
<Button onClick={() => setShowColorPopover(!showColorPopover)}>
{__('Choose Background Color')}
</Button>
{showColorPopover && (
<Popover position="bottom center">
<ColorPalette
value={selectedColor}
onChange={handleColorChange}
colors={[{ name: "Primary", slug: "primary", color: "#3E5062" }, { name: "Secondary", slug: "secondary", color: "#2B3843" }, { name: "Light Color - 1", slug: "light-color-1", color: "#ECF0F5" }, { name: "Dark Gray", slug: "dark-gray", color: "#333333" }, { name: "Accent", slug: "accent", color: "#61FFB6" }]}
disableCustomColors={false}
/>
</Popover>
)}
{/* Color indicator */}
<div style={{ backgroundColor: selectedColor, width: '30px', height: '30px', marginTop: '10px', borderRadius: '50%' }}></div>
</div>
</BaseControl>
</InspectorControls>
<div {...blockProps} style={{ maxWidth: maxWidthLarge, minHeight: minHeightLarge }}>
<InnerBlocks />
</div>
</>
);
}

View File

@ -0,0 +1,9 @@
/**
* The following styles get applied inside the editor only.
*
* Replace them with your own styles or remove the file completely.
*/
.wp-block-create-block-lcp-viewport {
border: 1px dotted #f00;
}

View File

@ -0,0 +1,39 @@
/**
* Registers a new block provided a unique name and an object defining its behavior.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
import { registerBlockType } from '@wordpress/blocks';
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* All files containing `style` keyword are bundled together. The code used
* gets applied both to the front of your site and to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './style.scss';
/**
* Internal dependencies
*/
import Edit from './edit';
import save from './save';
import metadata from './block.json';
/**
* Every block starts by registering a new block type definition.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
registerBlockType( metadata.name, {
/**
* @see ./edit.js
*/
edit: Edit,
/**
* @see ./save.js
*/
save,
} );

View File

@ -0,0 +1,12 @@
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
export default function Save() {
// Block props
const blockProps = useBlockProps.save();
return (
<div {...blockProps}>
<InnerBlocks.Content />
</div>
);
}

View File

@ -0,0 +1,12 @@
/**
* The following styles get applied both on the front of your site
* and in the editor.
*
* Replace them with your own styles or remove the file completely.
*/
.wp-block-create-block-lcp-viewport {
background-color: #21759b;
color: #fff;
padding: 2px;
}

View File

@ -0,0 +1,25 @@
/**
* Use this file for JavaScript code that you want to run in the front-end
* on posts/pages that contain this block.
*
* When this file is defined as the value of the `viewScript` property
* in `block.json` it will be enqueued on the front end of the site.
*
* Example:
*
* ```js
* {
* "viewScript": "file:./view.js"
* }
* ```
*
* If you're not making any changes to this file because your project doesn't need any
* JavaScript running in the front-end, then you should delete this file and remove
* the `viewScript` property from `block.json`.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#view-script
*/
/* eslint-disable no-console */
console.log( 'Hello World! (from create-block-lcp-viewport block)' );
/* eslint-enable no-console */

View File

@ -0,0 +1,18 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab
[*.{yml,yaml}]
indent_style = space
indent_size = 2

View File

@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Coverage directory used by tools like istanbul
coverage
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Output of `npm pack`
*.tgz
# Output of `wp-scripts plugin-zip`
*.zip
# dotenv environment variables file
.env

View File

@ -0,0 +1,29 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "lcp/footer-container",
"version": "0.1.0",
"title": "Footer Container",
"category": "widgets",
"icon": "smiley",
"description": "A container for inserting the footer",
"example": {},
"supports": {
"color": {
"background": true,
"text": false,
"link": false
}
},
"attributes": {
"sticky": {
"type": "string",
"default": "never"
}
},
"textdomain": "lcp",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js"
}

View File

@ -0,0 +1 @@
.wp-block-create-block-lcp-viewport{border:1px dotted red}

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n'), 'version' => 'f3a49fcf497c8df94623');

View File

@ -0,0 +1 @@
.wp-block-create-block-lcp-viewport{border:1px dotted red}

View File

@ -0,0 +1 @@
(()=>{"use strict";var e,t={717:()=>{const e=window.wp.blocks,t=window.wp.i18n,n=window.wp.blockEditor,l=window.wp.components,o=window.React,r=window.ReactJSXRuntime,i=JSON.parse('{"UU":"lcp/footer-container"}');(0,e.registerBlockType)(i.UU,{edit:function({attributes:e,setAttributes:i}){const[s,a]=(0,o.useState)(!1),[d,p]=(0,o.useState)("10px"),[c,x]=(0,o.useState)("10px"),[g,h]=(0,o.useState)("10px"),[u,v]=(0,o.useState)("10px"),{sticky:f}=e,j=(0,n.useBlockProps)();return(0,r.jsxs)("div",{...j,children:[(0,r.jsxs)(n.InspectorControls,{children:[(0,r.jsx)(l.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=>{i({sticky:e})}}),(0,r.jsxs)(l.BaseControl,{label:"Padding - Desktop",children:[(0,r.jsxs)("div",{style:{display:"flex",flexDirection:"row"},children:[(0,r.jsx)("span",{style:{marginRight:"10px"},children:"Padding"}),(0,r.jsx)(l.ToggleControl,{label:"Use Independent Padding",checked:s,onChange:()=>{a(!s)}})]}),s?(0,r.jsxs)("div",{style:{display:"grid",padding:"10px",gridTemplateColumns:"1fr 1fr",gap:"10px",justifyItems:"center"},children:[(0,r.jsxs)("fieldset",{style:{gridColumn:"span 2",width:"116px"},children:[(0,r.jsx)("legend",{children:"Top"}),(0,r.jsx)(l.__experimentalUnitControl,{value:d,onChange:e=>{p(e),i({paddingTop:e})}})]}),(0,r.jsxs)("fieldset",{children:[(0,r.jsx)("legend",{children:"Left"}),(0,r.jsx)(l.__experimentalUnitControl,{value:u,onChange:e=>{v(e),i({paddingLeft:e})}})]}),(0,r.jsxs)("fieldset",{children:[(0,r.jsx)("legend",{children:"Right"}),(0,r.jsx)(l.__experimentalUnitControl,{value:c,onChange:e=>{x(e),i({paddingRight:e})}})]}),(0,r.jsxs)("fieldset",{style:{gridColumn:"span 2",width:"116px"},children:[(0,r.jsx)("legend",{children:"Bottom"}),(0,r.jsx)(l.__experimentalUnitControl,{value:g,onChange:e=>{h(e),i({paddingBottom:e})}})]})]}):(0,r.jsx)(l.__experimentalUnitControl,{label:"Padding Value",value:999,onChange:e=>{i({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,r.jsx)(n.InnerBlocks,{template:[["core/template-part",{slug:"footer"}]]})]})},save:function({attributes:e}){const{sticky:t}=e,l=n.useBlockProps.save();return(0,r.jsx)("div",{...l,className:"lcp",id:"lcp-footer-container",children:(0,r.jsx)(n.InnerBlocks.Content,{})})}})}},n={};function l(e){var o=n[e];if(void 0!==o)return o.exports;var r=n[e]={exports:{}};return t[e](r,r.exports,l),r.exports}l.m=t,e=[],l.O=(t,n,o,r)=>{if(!n){var i=1/0;for(p=0;p<e.length;p++){n=e[p][0],o=e[p][1],r=e[p][2];for(var s=!0,a=0;a<n.length;a++)(!1&r||i>=r)&&Object.keys(l.O).every((e=>l.O[e](n[a])))?n.splice(a--,1):(s=!1,r<i&&(i=r));if(s){e.splice(p--,1);var d=o();void 0!==d&&(t=d)}}return t}r=r||0;for(var p=e.length;p>0&&e[p-1][2]>r;p--)e[p]=e[p-1];e[p]=[n,o,r]},l.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={57:0,350:0};l.O.j=t=>0===e[t];var t=(t,n)=>{var o,r,i=n[0],s=n[1],a=n[2],d=0;if(i.some((t=>0!==e[t]))){for(o in s)l.o(s,o)&&(l.m[o]=s[o]);if(a)var p=a(l)}for(t&&t(n);d<i.length;d++)r=i[d],l.o(e,r)&&e[r]&&e[r][0](),e[r]=0;return l.O(p)},n=self.webpackChunklcp_viewport=self.webpackChunklcp_viewport||[];n.forEach(t.bind(null,0)),n.push=t.bind(null,n.push.bind(n))})();var o=l.O(void 0,[350],(()=>l(717)));o=l.O(o)})();

View File

@ -0,0 +1 @@
.wp-block-create-block-lcp-viewport{background-color:#21759b;color:#fff;padding:2px}

View File

@ -0,0 +1 @@
.wp-block-create-block-lcp-viewport{background-color:#21759b;color:#fff;padding:2px}

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array(), 'version' => 'd4e4a494008d04e1eb42');

View File

@ -0,0 +1 @@
console.log("Hello World! (from create-block-lcp-viewport block)");

View File

@ -0,0 +1,20 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Registers the block using the metadata loaded from the `block.json` file.
* Behind the scenes, it registers also all assets so they can be enqueued
* through the block editor in the corresponding context.
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
function lcp_footer_container_block_init() {
register_block_type( __DIR__ . '/build' , array(
'parent' => array( 'lcp/viewport', 'lcp/main-area' ),
)
);
}
add_action( 'init', 'lcp_footer_container_block_init' );

View File

@ -0,0 +1,20 @@
{
"name": "lcp-viewport",
"version": "0.1.0",
"description": "Example block scaffolded with Create Block tool.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
"main": "build/index.js",
"scripts": {
"build": "wp-scripts build",
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"packages-update": "wp-scripts packages-update",
"plugin-zip": "wp-scripts plugin-zip",
"start": "wp-scripts start"
},
"devDependencies": {
"@wordpress/scripts": "^30.4.0"
}
}

View File

@ -0,0 +1,55 @@
=== Lcp Viewport ===
Contributors: The WordPress Contributors
Tags: block
Tested up to: 6.6
Stable tag: 0.1.0
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Example block scaffolded with Create Block tool.
== Description ==
This is the long description. No limit, and you can use Markdown (as well as in the following sections).
For backwards compatibility, if this section is missing, the full length of the short description will be used, and
Markdown parsed.
== Installation ==
This section describes how to install the plugin and get it working.
e.g.
1. Upload the plugin files to the `/wp-content/plugins/lcp-viewport` directory, or install the plugin through the WordPress plugins screen directly.
1. Activate the plugin through the 'Plugins' screen in WordPress
== Frequently Asked Questions ==
= A question that someone might have =
An answer to that question.
= What about foo bar? =
Answer to foo bar dilemma.
== Screenshots ==
1. This screen shot description corresponds to screenshot-1.(png|jpg|jpeg|gif). Note that the screenshot is taken from
the /assets directory or the directory that contains the stable readme.txt (tags or trunk). Screenshots in the /assets
directory take precedence. For example, `/assets/screenshot-1.png` would win over `/tags/4.3/screenshot-1.png`
(or jpg, jpeg, gif).
2. This is the second screen shot
== Changelog ==
= 0.1.0 =
* Release
== Arbitrary section ==
You may provide arbitrary sections, in the same format as the ones above. This may be of use for extremely complicated
plugins where more information needs to be conveyed that doesn't fit into the categories of "description" or
"installation." Arbitrary sections will be shown below the built-in sections outlined above.

View File

@ -0,0 +1,30 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "lcp/footer-container",
"version": "0.1.0",
"title": "Footer Container",
"category": "widgets",
"icon": "smiley",
"description": "A container for inserting the footer",
"example": {},
"supports": {
"color": {
"background": true,
"text": false,
"link": false
}
},
"attributes": {
"sticky": {
"type": "string",
"default": "never"
}
},
"textdomain": "lcp",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js"
}

View File

@ -0,0 +1,153 @@
/**
* Retrieves the translation of text.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-i18n/
*/
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 './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;
// Block props for the outer block
const blockProps = useBlockProps();
// Handle the change of the sticky attribute
const handleStickyChange = (value) => {
setAttributes({ sticky: value });
};
const handleToggleChange = () => {
setIsIndependentLarge(!isIndependentLarge);
};
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 }
};
// Update the padding attribute with the new padding object
setAttributes({ padding: newPadding });
};
return (
<div {...blockProps}>
{/* Inspector Controls: Add a SelectControl to change the sticky attribute */}
<InspectorControls>
<SelectControl
label={__('Sticky Behavior', 'lcp')}
value={sticky}
options={[
{ label: __('Never', 'lcp'), value: 'never' },
{ label: __('On Scroll', 'lcp'), value: 'onScroll' },
{ label: __('Always', 'lcp'), value: 'always' },
]}
onChange={handleStickyChange}
/>
<BaseControl label="Padding - Desktop">
<div style={{ display: 'flex', flexDirection: 'row' }}>
<span style={{ marginRight: '10px' }}>Padding</span>
<ToggleControl
label="Use Independent Padding"
checked={isIndependentLarge}
onChange={handleToggleChange}
/>
</div>
{/* Padding controls */}
{isIndependentLarge ? (
<div style={{ display: 'grid', padding: '10px', gridTemplateColumns: '1fr 1fr', gap: '10px', justifyItems: 'center' }}>
{/* Padding controls for top, left, right, bottom */}
<fieldset style={{ gridColumn: 'span 2', width: '116px' }}>
<legend>Top</legend>
<UnitControl
value={paddingTop}
onChange={(newValue) => {
setPaddingTop(newValue);
setAttributes({ paddingTop: newValue });
}}
/>
</fieldset>
<fieldset>
<legend>Left</legend>
<UnitControl
value={paddingLeft}
onChange={(newValue) => {
setPaddingLeft(newValue);
setAttributes({ paddingLeft: newValue });
}}
/>
</fieldset>
<fieldset>
<legend>Right</legend>
<UnitControl
value={paddingRight}
onChange={(newValue) => {
setPaddingRight(newValue);
setAttributes({ paddingRight: newValue });
}}
/>
</fieldset>
<fieldset style={{ gridColumn: 'span 2', width: '116px' }}>
<legend>Bottom</legend>
<UnitControl
value={paddingBottom}
onChange={(newValue) => {
setPaddingBottom(newValue);
setAttributes({ paddingBottom: newValue });
}}
/>
</fieldset>
</div>
) : (
<UnitControl
label="Padding Value"
value={999}
onChange={updatePaddingForAllSizes}
/>
)}
</BaseControl>
</InspectorControls>
<InnerBlocks
template= {[
["core/template-part", {slug:'footer'}]]
}
/>
</div>
);
}

View File

@ -0,0 +1,9 @@
/**
* The following styles get applied inside the editor only.
*
* Replace them with your own styles or remove the file completely.
*/
.wp-block-create-block-lcp-viewport {
border: 1px dotted #f00;
}

View File

@ -0,0 +1,39 @@
/**
* Registers a new block provided a unique name and an object defining its behavior.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
import { registerBlockType } from '@wordpress/blocks';
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* All files containing `style` keyword are bundled together. The code used
* gets applied both to the front of your site and to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './style.scss';
/**
* Internal dependencies
*/
import Edit from './edit';
import save from './save';
import metadata from './block.json';
/**
* Every block starts by registering a new block type definition.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
registerBlockType( metadata.name, {
/**
* @see ./edit.js
*/
edit: Edit,
/**
* @see ./save.js
*/
save,
} );

View File

@ -0,0 +1,33 @@
/**
* 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 } from '@wordpress/block-editor';
/**
* The save function defines the way in which the different attributes should
* be combined into the final markup, which is then serialized by the block
* editor into `post_content`.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#save
*
* @return {Element} Element to render.
*/
export default function Save({ attributes }) {
// Destructure the 'sticky' attribute from the block attributes
const { sticky } = attributes;
// Block props
const blockProps = useBlockProps.save();
return (
<div {...blockProps} className={"lcp"} id="lcp-footer-container">
<InnerBlocks.Content />
</div>
);
}

View File

@ -0,0 +1,12 @@
/**
* The following styles get applied both on the front of your site
* and in the editor.
*
* Replace them with your own styles or remove the file completely.
*/
.wp-block-create-block-lcp-viewport {
background-color: #21759b;
color: #fff;
padding: 2px;
}

View File

@ -0,0 +1,25 @@
/**
* Use this file for JavaScript code that you want to run in the front-end
* on posts/pages that contain this block.
*
* When this file is defined as the value of the `viewScript` property
* in `block.json` it will be enqueued on the front end of the site.
*
* Example:
*
* ```js
* {
* "viewScript": "file:./view.js"
* }
* ```
*
* If you're not making any changes to this file because your project doesn't need any
* JavaScript running in the front-end, then you should delete this file and remove
* the `viewScript` property from `block.json`.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#view-script
*/
/* eslint-disable no-console */
console.log( 'Hello World! (from create-block-lcp-viewport block)' );
/* eslint-enable no-console */

View File

@ -0,0 +1,18 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab
[*.{yml,yaml}]
indent_style = space
indent_size = 2

Some files were not shown because too many files have changed in this diff Show More