Compare commits
33 Commits
f356906bb1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| ae31fec647 | |||
| ceb37fc5af | |||
| 63e181109c | |||
| b79a4ece03 | |||
| 3a205a53cf | |||
| 4447e50bcf | |||
| 1ce1a08442 | |||
| 7bba517b48 | |||
| d928a0e8fd | |||
| 21b00e1937 | |||
| 741d39a962 | |||
| 2df16e37a8 | |||
| 4394776735 | |||
| a8b4dc6b70 | |||
| 4b78f9f571 | |||
| b9e2660318 | |||
| 28139d2455 | |||
| 0d59719440 | |||
| 372d5aa2c1 | |||
| d65992a169 | |||
| 462cffdddc | |||
| 93cc7be3bf | |||
| 44c621e0da | |||
| 216d108289 | |||
| 1ccc6f0031 | |||
| f3fbe0fa32 | |||
| cfbb860bf9 | |||
| 94d2c7c8a2 | |||
| d5a5f4e87b | |||
| 961081128a | |||
| f19e779946 | |||
| 4936a3a742 | |||
| 1234341241 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,7 +6,6 @@ wp-includes/
|
||||
.DS_Store
|
||||
node_modules/
|
||||
.env
|
||||
build/
|
||||
dist/
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
0
assets/css/admin-style.css
Normal file
0
assets/css/admin-style.css
Normal file
BIN
assets/fonts/fira-code/FiraCode-VariableFont_wght.woff2
Normal file
BIN
assets/fonts/fira-code/FiraCode-VariableFont_wght.woff2
Normal file
Binary file not shown.
BIN
assets/fonts/manrope/Manrope-VariableFont_wght.woff2
Normal file
BIN
assets/fonts/manrope/Manrope-VariableFont_wght.woff2
Normal file
Binary file not shown.
BIN
assets/fonts/pt-serif/PTSerif-Bold.woff2
Normal file
BIN
assets/fonts/pt-serif/PTSerif-Bold.woff2
Normal file
Binary file not shown.
BIN
assets/fonts/pt-serif/PTSerif-BoldItalic.woff2
Normal file
BIN
assets/fonts/pt-serif/PTSerif-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
assets/fonts/pt-serif/PTSerif-Italic.woff2
Normal file
BIN
assets/fonts/pt-serif/PTSerif-Italic.woff2
Normal file
Binary file not shown.
BIN
assets/fonts/pt-serif/PTSerif-Regular.woff2
Normal file
BIN
assets/fonts/pt-serif/PTSerif-Regular.woff2
Normal file
Binary file not shown.
BIN
assets/fonts/work-sans/WorkSans-Bold.woff2
Normal file
BIN
assets/fonts/work-sans/WorkSans-Bold.woff2
Normal file
Binary file not shown.
BIN
assets/fonts/work-sans/WorkSans-Italic.woff2
Normal file
BIN
assets/fonts/work-sans/WorkSans-Italic.woff2
Normal file
Binary file not shown.
BIN
assets/fonts/work-sans/WorkSans-Regular.woff2
Normal file
BIN
assets/fonts/work-sans/WorkSans-Regular.woff2
Normal file
Binary file not shown.
BIN
assets/fonts/work-sans/WorkSans-SemiBold.woff2
Normal file
BIN
assets/fonts/work-sans/WorkSans-SemiBold.woff2
Normal file
Binary file not shown.
BIN
assets/img/demo-post-thumbnails/demo-post-thumbnail-1.jpg
Normal file
BIN
assets/img/demo-post-thumbnails/demo-post-thumbnail-1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 723 KiB |
BIN
assets/img/demo-post-thumbnails/demo-post-thumbnail-2.jpg
Normal file
BIN
assets/img/demo-post-thumbnails/demo-post-thumbnail-2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 875 KiB |
BIN
assets/img/demo-post-thumbnails/demo-post-thumbnail-3.jpg
Normal file
BIN
assets/img/demo-post-thumbnails/demo-post-thumbnail-3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 698 KiB |
32
assets/js/custom-image-sizes.js
Normal file
32
assets/js/custom-image-sizes.js
Normal file
@ -0,0 +1,32 @@
|
||||
function lcpUpdateImageSizes(imageSizes) {
|
||||
// Validate the input to ensure it's an array
|
||||
if (!Array.isArray(imageSizes)) {
|
||||
console.error('Invalid image sizes data');
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare the form data to send to WordPress to update the theme settings
|
||||
const updateData = new FormData();
|
||||
updateData.append('action', 'update_lcp_theme_settings'); // WordPress action hook
|
||||
updateData.append('image_sizes', JSON.stringify(imageSizes)); // Send image sizes as a JSON string
|
||||
updateData.append('nonce', customImageSizeAjax.nonce); // Send the nonce
|
||||
|
||||
console.log('Sending data to AJAX:', updateData); // Log the data for debugging
|
||||
|
||||
// Send the AJAX request
|
||||
fetch(customImageSizeAjax.ajax_url, {
|
||||
method: 'POST',
|
||||
body: updateData, // Send form data directly
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
console.log('Theme settings updated successfully.');
|
||||
} else {
|
||||
console.error('Failed to update theme settings:', data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error updating theme settings:', error);
|
||||
});
|
||||
}
|
||||
85
assets/js/demo-posts-import.js
Normal file
85
assets/js/demo-posts-import.js
Normal file
@ -0,0 +1,85 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
// Check if the 'Import Demo Posts' button exists
|
||||
const importButton = document.getElementById('import-demo-posts');
|
||||
console.log(importButton); // This will log the button element to the console
|
||||
|
||||
if (importButton) {
|
||||
// Check if the lcp_demo_posts option exists
|
||||
if (lcp_ajax_obj.lcp_demo_posts && lcp_ajax_obj.lcp_demo_posts.post_ids && lcp_ajax_obj.lcp_demo_posts.post_ids.length > 0) {
|
||||
// Disable the 'Import Demo Posts' button if demo posts have already been imported
|
||||
importButton.disabled = true;
|
||||
importButton.textContent = 'Demo Posts Already Imported'; // Optional: Change button text
|
||||
} else {
|
||||
// Add event listener to import demo posts if the button is enabled
|
||||
importButton.addEventListener('click', function () {
|
||||
console.log("Clicked"); // This should be triggered on button click
|
||||
const formData = new FormData();
|
||||
|
||||
// Append action and nonce to the form data
|
||||
formData.append('action', 'lcp_import_demo_posts');
|
||||
formData.append('lcp_import_nonce', lcp_ajax_obj.nonce);
|
||||
|
||||
// Send the AJAX request to import demo posts
|
||||
fetch(lcp_ajax_obj.ajax_url, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert(data.data); // Success message
|
||||
importButton.disabled = true;
|
||||
importButton.textContent = 'Demo Posts Imported'; // Optional: Change button text
|
||||
} else {
|
||||
alert('Error: ' + (data.data || 'Unknown error')); // Error message
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('An error occurred while processing your request.');
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the 'Delete Demo Posts' button exists
|
||||
const deleteButton = document.getElementById('delete-demo-posts');
|
||||
if (deleteButton) {
|
||||
deleteButton.addEventListener('click', function () {
|
||||
const formData = new FormData();
|
||||
|
||||
// Append action and nonce to the form data for deletion
|
||||
formData.append('action', 'lcp_delete_demo_posts'); // Use the correct action here
|
||||
formData.append('lcp_import_nonce', lcp_ajax_obj.nonce); // Pass nonce for security
|
||||
|
||||
// Send the AJAX request to delete demo posts
|
||||
fetch(lcp_ajax_obj.ajax_url, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert(data.data); // Success message
|
||||
deleteButton.disabled = true;
|
||||
deleteButton.textContent = 'Demo Posts Deleted';
|
||||
|
||||
// Re-enable the "Import Demo Posts" button and reset its text
|
||||
const importButton = document.getElementById('import-demo-posts');
|
||||
if (importButton) {
|
||||
importButton.disabled = false;
|
||||
importButton.textContent = 'Import Demo Posts';
|
||||
}
|
||||
} else {
|
||||
alert('Error: ' + (data.data || 'Unknown error'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('An error occurred while processing your request.');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
71
assets/js/highlight-to-share.js
Normal file
71
assets/js/highlight-to-share.js
Normal 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)}"e=${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
77
assets/js/icon-import.js
Normal 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', lcp_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', lcp_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);
|
||||
});
|
||||
});
|
||||
});
|
||||
250
assets/js/lcp-ui.js
Normal file
250
assets/js/lcp-ui.js
Normal file
@ -0,0 +1,250 @@
|
||||
|
||||
/* ACCORDION */
|
||||
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');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
/* TABS */
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const tabs = document.querySelectorAll('.tab-link');
|
||||
const panes = document.querySelectorAll('.tab-pane');
|
||||
const tabContainer = document.querySelector('.lcp-tab-container'); // The parent container
|
||||
|
||||
// Only enable the hash functionality if the container has the class '.lcp-support-hash'
|
||||
if (tabContainer && tabContainer.classList.contains('lcp-support-hash')) {
|
||||
|
||||
// Function to set the active tab based on the hash in the URL
|
||||
function setActiveTabFromHash() {
|
||||
const hash = window.location.hash; // Get the current URL hash
|
||||
if (hash) {
|
||||
const targetTab = document.querySelector(`.tab-link[data-tab="${hash.substring(1)}"]`); // Remove '#' from hash
|
||||
const targetPane = document.getElementById(hash.substring(1));
|
||||
|
||||
// If both tab and pane exist, make them active
|
||||
if (targetTab && targetPane) {
|
||||
tabs.forEach(link => link.classList.remove('active'));
|
||||
panes.forEach(pane => pane.classList.remove('active'));
|
||||
|
||||
targetTab.classList.add('active');
|
||||
targetPane.classList.add('active');
|
||||
} else {
|
||||
console.error(`Tab or pane with ID '${hash}' not found.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the active tab from the hash when the page loads
|
||||
setActiveTabFromHash();
|
||||
}
|
||||
// Handle tab clicks
|
||||
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 and update URL hash
|
||||
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');
|
||||
if (tabContainer && tabContainer.classList.contains('lcp-support-hash')){
|
||||
window.location.hash = targetPaneId; // Update the URL hash
|
||||
}
|
||||
} else {
|
||||
console.error(`Tab pane with ID '${targetPaneId}' not found.`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
/* REPEATER */
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Function to initialize each repeater instance
|
||||
function initRepeater(repeater) {
|
||||
const firstRow = repeater.querySelector('.lcp-repeater-row');
|
||||
|
||||
// Function to check if all required fields are filled
|
||||
function isRequiredFieldsFilled(row) {
|
||||
const requiredFields = row.querySelectorAll('[data-lcp-required="true"], [data-lcp-required-for-new-row="true"]');
|
||||
let valid = true;
|
||||
|
||||
requiredFields.forEach(input => {
|
||||
// Check input type and value for validation
|
||||
if (input.type === 'number' && (input.value === '' || isNaN(input.value))) {
|
||||
valid = false;
|
||||
} else if (input.type === 'checkbox' && !input.checked) {
|
||||
valid = false;
|
||||
}
|
||||
});
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
// Function to create a new row by cloning the first row
|
||||
function addRepeaterRow() {
|
||||
const newRow = firstRow.cloneNode(true); // true means deep cloning (includes children)
|
||||
|
||||
const inputs = newRow.querySelectorAll('input');
|
||||
inputs.forEach(input => input.value = ''); // Reset value for input fields
|
||||
newRow.querySelector('input[type="checkbox"]').checked = false; // Uncheck the checkbox
|
||||
|
||||
repeater.insertBefore(newRow, repeater.querySelector('.lcp-repeater-add-row'));
|
||||
|
||||
toggleAddRowButton();
|
||||
toggleSubmitButton();
|
||||
}
|
||||
|
||||
// Function to toggle the "Add Row" button based on the required field for new rows
|
||||
function toggleAddRowButton() {
|
||||
const addRowButton = repeater.querySelector('.lcp-repeater-add-row');
|
||||
const rows = repeater.querySelectorAll('.lcp-repeater-row');
|
||||
|
||||
let validForNewRow = true;
|
||||
|
||||
rows.forEach(row => {
|
||||
const requiredForNewRowFields = row.querySelectorAll('[data-lcp-required-for-new-row="true"]');
|
||||
requiredForNewRowFields.forEach(input => {
|
||||
if (input.value === '' || (input.type === 'checkbox' && !input.checked)) {
|
||||
validForNewRow = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
addRowButton.disabled = !validForNewRow;
|
||||
}
|
||||
|
||||
// Function to toggle the "Submit" button based on the validation of all rows
|
||||
function toggleSubmitButton() {
|
||||
const submitButton = repeater.querySelector('.lcp-repeater-submit');
|
||||
const rows = repeater.querySelectorAll('.lcp-repeater-row');
|
||||
|
||||
let allValid = true;
|
||||
|
||||
rows.forEach(row => {
|
||||
if (!isRequiredFieldsFilled(row)) {
|
||||
allValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
submitButton.disabled = !allValid;
|
||||
}
|
||||
|
||||
// Function to handle form submission, ensuring all required fields are filled
|
||||
function handleSubmit(event) {
|
||||
const submitButton = event.target;
|
||||
const actionType = submitButton.getAttribute('data-lcp-action'); // This will be used to pass data to the handler
|
||||
const rows = repeater.querySelectorAll('.lcp-repeater-row');
|
||||
let allValid = true;
|
||||
|
||||
rows.forEach(row => {
|
||||
if (!isRequiredFieldsFilled(row)) {
|
||||
allValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (allValid) {
|
||||
const repeaterData = [];
|
||||
|
||||
rows.forEach(function(row) {
|
||||
const rowData = {};
|
||||
const inputs = row.querySelectorAll('input');
|
||||
|
||||
inputs.forEach(function(input) {
|
||||
const key = input.getAttribute('data-lcp-repeater-key');
|
||||
let value;
|
||||
|
||||
if (input.type === 'checkbox') {
|
||||
value = input.checked; // Boolean value for checkbox
|
||||
} else {
|
||||
value = input.value; // Text or number inputs
|
||||
}
|
||||
|
||||
rowData[key] = value; // Add key-value pair to rowData
|
||||
});
|
||||
|
||||
repeaterData.push(rowData); // Add rowData to the repeaterData array
|
||||
});
|
||||
|
||||
// Now just pass the data off to the handler
|
||||
if (typeof window[actionType] === 'function') {
|
||||
window[actionType](repeaterData); // Calls the function (e.g., `lcpUpdateImageSizes`)
|
||||
}
|
||||
} else {
|
||||
alert("Please fill in all required fields.");
|
||||
}
|
||||
}
|
||||
|
||||
// Event listener for adding a new row when a user clicks the "Add Row" button
|
||||
const addRowButtons = repeater.querySelectorAll('.lcp-repeater-add-row');
|
||||
addRowButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
if (isRequiredFieldsFilled(firstRow)) {
|
||||
addRepeaterRow();
|
||||
} else {
|
||||
alert('Please fill in the required fields to add a new row.');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Event listener for submitting the repeater form
|
||||
const submitButton = repeater.querySelector('.lcp-repeater-submit');
|
||||
submitButton.addEventListener('click', handleSubmit);
|
||||
|
||||
// Initial validation for the add row button
|
||||
toggleAddRowButton();
|
||||
|
||||
// Initial validation for the submit button
|
||||
toggleSubmitButton();
|
||||
|
||||
// Added event listeners to handle any changes in input and trigger validation
|
||||
repeater.addEventListener('input', function() {
|
||||
toggleAddRowButton(); // Revalidate Add Row button
|
||||
toggleSubmitButton(); // Revalidate Submit button
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize each repeater on the page
|
||||
const repeaters = document.querySelectorAll('.lcp-repeater');
|
||||
repeaters.forEach(repeater => {
|
||||
initRepeater(repeater);
|
||||
});
|
||||
});
|
||||
|
||||
122
assets/js/lcp.js
Normal file
122
assets/js/lcp.js
Normal 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, 0)); // 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");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
96
assets/js/react/components/DimensionValueControl.js
Normal file
96
assets/js/react/components/DimensionValueControl.js
Normal 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>
|
||||
);
|
||||
}
|
||||
59
assets/js/react/components/IconSelectControl.js
Normal file
59
assets/js/react/components/IconSelectControl.js
Normal 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
|
||||
/>
|
||||
);
|
||||
}
|
||||
103
assets/js/react/components/PaddingControl.js
Normal file
103
assets/js/react/components/PaddingControl.js
Normal 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>
|
||||
);
|
||||
}
|
||||
57
assets/json/demo-posts.json
Normal file
57
assets/json/demo-posts.json
Normal file
@ -0,0 +1,57 @@
|
||||
{
|
||||
"posts": [
|
||||
{
|
||||
"title": "Mysterious Weather Patterns Reported in Faketown",
|
||||
"content": "Faketown, USA — In what can only be described as a strange turn of events, Faketown residents have been experiencing unpredictable weather patterns. Local meteorologists have been baffled as sudden temperature shifts have been occurring at all hours of the day. One moment, the sun is shining brightly, and the next, it's snowing. This bizarre occurrence is leaving many questioning whether this is a sign of something more ominous. 'I’ve lived here my entire life, and I’ve never seen anything like this,' said local resident Jane Doe.",
|
||||
"excerpt": "Faketown residents have been experiencing unpredictable weather patterns, baffling local meteorologists.",
|
||||
"category": "Local News",
|
||||
"tags": ["weather", "Faketown", "mystery"],
|
||||
"date": "2024-01-01",
|
||||
"status": "publish",
|
||||
"thumbnail": "demo-post-thumbnail-1.jpg"
|
||||
},
|
||||
{
|
||||
"title": "Faketown Mayor Announces New Green Initiative",
|
||||
"content": "In a recent press conference, Faketown’s mayor, John Smith, unveiled an ambitious plan to tackle climate change within the city. The initiative aims to reduce carbon emissions by 40% over the next 10 years, primarily by encouraging the use of electric vehicles and expanding the city's public transportation system. 'We are committed to making Faketown a greener place,' said Mayor Smith. 'Our children and grandchildren deserve a sustainable future.' The plan includes installing charging stations for electric cars across the city and offering tax incentives for green energy solutions.",
|
||||
"excerpt": "Faketown’s mayor unveils a new green initiative to reduce carbon emissions by 40%.",
|
||||
"category": "Politics",
|
||||
"tags": ["green", "climate change", "Faketown"],
|
||||
"date": "2024-01-02",
|
||||
"status": "publish",
|
||||
"thumbnail": "demo-post-thumbnail-2.jpg"
|
||||
},
|
||||
{
|
||||
"title": "Local Chef Opens Revolutionary Restaurant in Faketown",
|
||||
"content": "Faketown, USA — In a culinary first for Faketown, renowned chef Sarah Bellamy has opened a new restaurant that combines traditional American cuisine with exotic flavors from around the world. Located in the heart of Faketown, Bellamy’s restaurant has already become the talk of the town. The menu features a variety of dishes, including 'Fusion Fries' and 'Sushi Burger.' 'I wanted to create something completely unique, a blend of cultures,' said Bellamy. The restaurant offers both dine-in and delivery services, with plans to expand its menu soon.",
|
||||
"excerpt": "Faketown's new restaurant is offering a fusion of global flavors with a local twist.",
|
||||
"category": "Food & Drink",
|
||||
"tags": ["restaurant", "food", "Faketown"],
|
||||
"date": "2024-01-03",
|
||||
"status": "publish",
|
||||
"thumbnail": "demo-post-thumbnail-3.jpg"
|
||||
},
|
||||
{
|
||||
"title": "Strange Creatures Spotted in Faketown's Forests",
|
||||
"content": "In the deep forests surrounding Faketown, local hikers have begun reporting sightings of strange creatures. Descriptions vary, but many claim to have seen large, mysterious beings with glowing eyes. Some hikers have even reported hearing unusual sounds that have no obvious explanation. 'I was out for a hike last week when I saw something huge moving through the trees,' said Greg Johnson, a local resident. 'I don’t know what it was, but it wasn’t a bear.' Authorities are urging hikers to stay on well-trodden paths and report any strange occurrences.",
|
||||
"excerpt": "Faketown residents report strange creatures spotted in nearby forests, baffling experts.",
|
||||
"category": "Strange Happenings",
|
||||
"tags": ["mystery", "Faketown", "creatures"],
|
||||
"date": "2024-01-04",
|
||||
"status": "publish",
|
||||
"thumbnail": "demo-post-thumbnail-1.jpg"
|
||||
|
||||
},
|
||||
{
|
||||
"title": "Faketown's Annual Festival Breaks Attendance Records",
|
||||
"content": "This year's annual Faketown Festival was a resounding success, breaking all previous attendance records. Held in the town square, the festival featured local bands, food trucks, and street performances. The highlight of the event was the traditional 'Faketown Parade,' which saw thousands of people lining the streets. 'We’ve never seen this many people come out,' said event coordinator Lisa Thompson. The festival’s success has sparked excitement about next year’s event, with many suggesting that Faketown could become a regional hub for arts and culture.",
|
||||
"excerpt": "Faketown’s annual festival saw record-breaking attendance, with thousands of people participating.",
|
||||
"category": "Community Events",
|
||||
"tags": ["festival", "community", "Faketown"],
|
||||
"date": "2024-01-05",
|
||||
"status": "publish",
|
||||
"thumbnail": "demo-post-thumbnail-2.jpg"
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
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
67
assets/json/icons/icon-definitions.json
Normal file
67
assets/json/icons/icon-definitions.json
Normal 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"
|
||||
|
||||
}
|
||||
]
|
||||
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
4206
assets/json/input.svg
Normal file
File diff suppressed because one or more lines are too long
1166
functions.php
1166
functions.php
File diff suppressed because it is too large
Load Diff
18
includes/blocks/lcp-button/.editorconfig
Normal file
18
includes/blocks/lcp-button/.editorconfig
Normal 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
30
includes/blocks/lcp-button/.gitignore
vendored
Normal 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
|
||||
101
includes/blocks/lcp-button/build/block.json
Normal file
101
includes/blocks/lcp-button/build/block.json
Normal 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"
|
||||
}
|
||||
1
includes/blocks/lcp-button/build/index-rtl.css
Normal file
1
includes/blocks/lcp-button/build/index-rtl.css
Normal 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}
|
||||
1
includes/blocks/lcp-button/build/index.asset.php
Normal file
1
includes/blocks/lcp-button/build/index.asset.php
Normal 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' => 'eca736ee702435b6a2ff');
|
||||
1
includes/blocks/lcp-button/build/index.css
Normal file
1
includes/blocks/lcp-button/build/index.css
Normal 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}
|
||||
1
includes/blocks/lcp-button/build/index.js
Normal file
1
includes/blocks/lcp-button/build/index.js
Normal file
File diff suppressed because one or more lines are too long
1
includes/blocks/lcp-button/build/style-index-rtl.css
Normal file
1
includes/blocks/lcp-button/build/style-index-rtl.css
Normal file
@ -0,0 +1 @@
|
||||
.wp-block-create-block-button{background-color:#21759b;color:#fff;padding:2px}
|
||||
1
includes/blocks/lcp-button/build/style-index.css
Normal file
1
includes/blocks/lcp-button/build/style-index.css
Normal file
@ -0,0 +1 @@
|
||||
.wp-block-create-block-button{background-color:#21759b;color:#fff;padding:2px}
|
||||
1
includes/blocks/lcp-button/build/view.asset.php
Normal file
1
includes/blocks/lcp-button/build/view.asset.php
Normal file
@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => '39bd3d2fc52e7ff1ed91');
|
||||
1
includes/blocks/lcp-button/build/view.js
Normal file
1
includes/blocks/lcp-button/build/view.js
Normal file
@ -0,0 +1 @@
|
||||
console.log("Hello World! (from create-block-button block)");
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
59
includes/blocks/lcp-button/components/IconSelectControl.js
Normal file
59
includes/blocks/lcp-button/components/IconSelectControl.js
Normal 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
|
||||
/>
|
||||
);
|
||||
}
|
||||
103
includes/blocks/lcp-button/components/PaddingControl.js
Normal file
103
includes/blocks/lcp-button/components/PaddingControl.js
Normal 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>
|
||||
);
|
||||
}
|
||||
69
includes/blocks/lcp-button/lcp-button.php
Normal file
69
includes/blocks/lcp-button/lcp-button.php
Normal 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;
|
||||
}
|
||||
|
||||
20
includes/blocks/lcp-button/package.json
Normal file
20
includes/blocks/lcp-button/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
55
includes/blocks/lcp-button/readme.txt
Normal file
55
includes/blocks/lcp-button/readme.txt
Normal 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.
|
||||
101
includes/blocks/lcp-button/src/block.json
Normal file
101
includes/blocks/lcp-button/src/block.json
Normal 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"
|
||||
}
|
||||
145
includes/blocks/lcp-button/src/edit.js
Normal file
145
includes/blocks/lcp-button/src/edit.js
Normal 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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
32
includes/blocks/lcp-button/src/editor.scss
Normal file
32
includes/blocks/lcp-button/src/editor.scss
Normal 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;
|
||||
}
|
||||
39
includes/blocks/lcp-button/src/index.js
Normal file
39
includes/blocks/lcp-button/src/index.js
Normal 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,
|
||||
} );
|
||||
35
includes/blocks/lcp-button/src/save.js
Normal file
35
includes/blocks/lcp-button/src/save.js
Normal 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 (
|
||||
|
||||
<>
|
||||
{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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
13
includes/blocks/lcp-button/src/style.scss
Normal file
13
includes/blocks/lcp-button/src/style.scss
Normal 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;
|
||||
}
|
||||
|
||||
25
includes/blocks/lcp-button/src/view.js
Normal file
25
includes/blocks/lcp-button/src/view.js
Normal 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 */
|
||||
18
includes/blocks/lcp-dynamic-container/.editorconfig
Normal file
18
includes/blocks/lcp-dynamic-container/.editorconfig
Normal 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-dynamic-container/.gitignore
vendored
Normal file
30
includes/blocks/lcp-dynamic-container/.gitignore
vendored
Normal 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
|
||||
141
includes/blocks/lcp-dynamic-container/build/block.json
Normal file
141
includes/blocks/lcp-dynamic-container/build/block.json
Normal 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"
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n'), 'version' => '04e9c02e00cfeee61658');
|
||||
1
includes/blocks/lcp-dynamic-container/build/index.js
Normal file
1
includes/blocks/lcp-dynamic-container/build/index.js
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
||||
.wp-block-create-block-lcp-viewport{background-color:#21759b;color:#fff;padding:2px}.lcp-dynamic-container.lcp-has-background-image{position:relative;width:100%}.lcp-dynamic-container.lcp-has-background-image>.lcp-background-image{height:100%;right:0;-o-object-fit:cover;object-fit:cover;-o-object-position:center center;object-position:center center;position:absolute;top:0;width:100%}
|
||||
@ -0,0 +1 @@
|
||||
.wp-block-create-block-lcp-viewport{background-color:#21759b;color:#fff;padding:2px}.lcp-dynamic-container.lcp-has-background-image{position:relative;width:100%}.lcp-dynamic-container.lcp-has-background-image>.lcp-background-image{height:100%;left:0;-o-object-fit:cover;object-fit:cover;-o-object-position:center center;object-position:center center;position:absolute;top:0;width:100%}
|
||||
@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => 'd4e4a494008d04e1eb42');
|
||||
1
includes/blocks/lcp-dynamic-container/build/view.js
Normal file
1
includes/blocks/lcp-dynamic-container/build/view.js
Normal file
@ -0,0 +1 @@
|
||||
console.log("Hello World! (from create-block-lcp-viewport block)");
|
||||
221
includes/blocks/lcp-dynamic-container/lcp-dynamic-container.php
Normal file
221
includes/blocks/lcp-dynamic-container/lcp-dynamic-container.php
Normal file
@ -0,0 +1,221 @@
|
||||
<?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_dynamic_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 );
|
||||
}
|
||||
// Set the post thumbnail
|
||||
if ( has_post_thumbnail() ) {
|
||||
// Get the post thumbnail URL for different sizes
|
||||
$full_size_url = get_the_post_thumbnail_url( get_the_ID(), 'full' );
|
||||
$medium_size_url = get_the_post_thumbnail_url( get_the_ID(), 'medium' );
|
||||
$large_size_url = get_the_post_thumbnail_url( get_the_ID(), 'large' );
|
||||
|
||||
// Generate the <picture> element with <source> and <img> tags for responsiveness
|
||||
$post_thumb = '<picture class="lcp-background-image">';
|
||||
|
||||
// Add source for large image (for screens >= 1200px)
|
||||
$post_thumb .= '<source media="(min-width: 1200px)" srcset="' . esc_url( $large_size_url ) . '">';
|
||||
|
||||
// Add source for medium image (for screens >= 768px)
|
||||
$post_thumb .= '<source media="(min-width: 768px)" srcset="' . esc_url( $medium_size_url ) . '">';
|
||||
|
||||
// Add fallback image (for smaller screens or if no match for media queries)
|
||||
$post_thumb .= '<img src="' . esc_url( $full_size_url ) . '" alt="Responsive Background Image" class="responsive-background">';
|
||||
|
||||
$post_thumb .= '</picture>';
|
||||
}
|
||||
|
||||
$has_background_image = (2 + 2 == 4) ? 'lcp-has-background-image' : '';
|
||||
|
||||
// Output the content wrapped in the div with the random class and padding styles
|
||||
return $style_tag . sprintf(
|
||||
'<div class="lcp-dynamic-container %s %s">%s%s</div>',
|
||||
esc_attr( $random_class ), // The random class
|
||||
esc_attr( $has_background_image), // Conditionally add 'lcp-has-background-image' class
|
||||
$post_thumb, // Add the $post_thumb (responsive image) here,
|
||||
$content // Keep the original 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' );
|
||||
20
includes/blocks/lcp-dynamic-container/package.json
Normal file
20
includes/blocks/lcp-dynamic-container/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
55
includes/blocks/lcp-dynamic-container/readme.txt
Normal file
55
includes/blocks/lcp-dynamic-container/readme.txt
Normal 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.
|
||||
136
includes/blocks/lcp-dynamic-container/src/block.json
Normal file
136
includes/blocks/lcp-dynamic-container/src/block.json
Normal 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"}
|
||||
211
includes/blocks/lcp-dynamic-container/src/edit.js
Normal file
211
includes/blocks/lcp-dynamic-container/src/edit.js
Normal 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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
9
includes/blocks/lcp-dynamic-container/src/editor.scss
Normal file
9
includes/blocks/lcp-dynamic-container/src/editor.scss
Normal 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;
|
||||
}
|
||||
39
includes/blocks/lcp-dynamic-container/src/index.js
Normal file
39
includes/blocks/lcp-dynamic-container/src/index.js
Normal 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,
|
||||
} );
|
||||
4
includes/blocks/lcp-dynamic-container/src/save.js
Normal file
4
includes/blocks/lcp-dynamic-container/src/save.js
Normal file
@ -0,0 +1,4 @@
|
||||
import { InnerBlocks } from '@wordpress/block-editor';
|
||||
export default function save() {
|
||||
return (<InnerBlocks.Content/>); // No content is saved in the database for dynamic blocks
|
||||
}
|
||||
29
includes/blocks/lcp-dynamic-container/src/style.scss
Normal file
29
includes/blocks/lcp-dynamic-container/src/style.scss
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
.lcp-dynamic-container.lcp-has-background-image {
|
||||
position:relative;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.lcp-dynamic-container.lcp-has-background-image > .lcp-background-image {
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover; /* Cover the container like a background */
|
||||
object-position: center center; /* Center the image */
|
||||
|
||||
}
|
||||
25
includes/blocks/lcp-dynamic-container/src/view.js
Normal file
25
includes/blocks/lcp-dynamic-container/src/view.js
Normal 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 */
|
||||
18
includes/blocks/lcp-footer-container/.editorconfig
Normal file
18
includes/blocks/lcp-footer-container/.editorconfig
Normal 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-footer-container/.gitignore
vendored
Normal file
30
includes/blocks/lcp-footer-container/.gitignore
vendored
Normal 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
|
||||
29
includes/blocks/lcp-footer-container/build/block.json
Normal file
29
includes/blocks/lcp-footer-container/build/block.json
Normal 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"
|
||||
}
|
||||
1
includes/blocks/lcp-footer-container/build/index-rtl.css
Normal file
1
includes/blocks/lcp-footer-container/build/index-rtl.css
Normal file
@ -0,0 +1 @@
|
||||
.wp-block-create-block-lcp-viewport{border:1px dotted red}
|
||||
@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n'), 'version' => 'f3a49fcf497c8df94623');
|
||||
1
includes/blocks/lcp-footer-container/build/index.css
Normal file
1
includes/blocks/lcp-footer-container/build/index.css
Normal file
@ -0,0 +1 @@
|
||||
.wp-block-create-block-lcp-viewport{border:1px dotted red}
|
||||
1
includes/blocks/lcp-footer-container/build/index.js
Normal file
1
includes/blocks/lcp-footer-container/build/index.js
Normal 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)})();
|
||||
@ -0,0 +1 @@
|
||||
.wp-block-create-block-lcp-viewport{background-color:#21759b;color:#fff;padding:2px}
|
||||
@ -0,0 +1 @@
|
||||
.wp-block-create-block-lcp-viewport{background-color:#21759b;color:#fff;padding:2px}
|
||||
@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => 'd4e4a494008d04e1eb42');
|
||||
1
includes/blocks/lcp-footer-container/build/view.js
Normal file
1
includes/blocks/lcp-footer-container/build/view.js
Normal file
@ -0,0 +1 @@
|
||||
console.log("Hello World! (from create-block-lcp-viewport block)");
|
||||
@ -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' );
|
||||
20
includes/blocks/lcp-footer-container/package.json
Normal file
20
includes/blocks/lcp-footer-container/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
55
includes/blocks/lcp-footer-container/readme.txt
Normal file
55
includes/blocks/lcp-footer-container/readme.txt
Normal 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.
|
||||
30
includes/blocks/lcp-footer-container/src/block.json
Normal file
30
includes/blocks/lcp-footer-container/src/block.json
Normal 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"
|
||||
}
|
||||
153
includes/blocks/lcp-footer-container/src/edit.js
Normal file
153
includes/blocks/lcp-footer-container/src/edit.js
Normal 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>
|
||||
);
|
||||
}
|
||||
9
includes/blocks/lcp-footer-container/src/editor.scss
Normal file
9
includes/blocks/lcp-footer-container/src/editor.scss
Normal 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;
|
||||
}
|
||||
39
includes/blocks/lcp-footer-container/src/index.js
Normal file
39
includes/blocks/lcp-footer-container/src/index.js
Normal 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,
|
||||
} );
|
||||
33
includes/blocks/lcp-footer-container/src/save.js
Normal file
33
includes/blocks/lcp-footer-container/src/save.js
Normal 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>
|
||||
);
|
||||
}
|
||||
12
includes/blocks/lcp-footer-container/src/style.scss
Normal file
12
includes/blocks/lcp-footer-container/src/style.scss
Normal 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;
|
||||
}
|
||||
25
includes/blocks/lcp-footer-container/src/view.js
Normal file
25
includes/blocks/lcp-footer-container/src/view.js
Normal 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 */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user