import { useEffect, useState } from '@wordpress/element'; import { Button } from '@wordpress/components'; import { Modal, ModalClose, ModalContent, ModalFooter, ModalTrigger, ModalHeader, ModalTitle, } from '@components/ui/Modal'; import classNames from 'classnames'; import apiFetch from '@wordpress/api-fetch'; import { ScrollList } from '@components/ui/ScrollList'; import { ToggleSwitch } from '@components/ui/ToggleSwitch'; import { BlockCategory } from './types'; import { Notice } from '@components/ui/Notice'; // @ts-ignore import { nanoid } from 'nanoid'; const calculateAspectRatio = (width: number, height: number): string => { const ratio = width / height; const aspectRatios = [ { name: 'aspect-4/3', ratio: 4 / 3 }, { name: 'aspect-16/9', ratio: 16 / 9 }, { name: 'aspect-21/9', ratio: 21 / 9 }, { name: 'aspect-3/4', ratio: 3 / 4 }, { name: 'aspect-5/4', ratio: 5 / 4 }, { name: 'aspect-16/10', ratio: 16 / 10 }, { name: 'aspect-2/1', ratio: 2 / 1 }, { name: 'aspect-1/1', ratio: 1 / 1 }, ]; let closest = 'aspect-1/1'; // Default aspect ratio let minDiff = Infinity; aspectRatios.forEach(({ name, ratio: refRatio }) => { const diff = Math.abs(ratio - refRatio); if (diff < minDiff) { minDiff = diff; closest = name; } }); return closest; }; const calculateScale = ( width: number, height: number, tileWidth: number, tileHeight: number, colSpan: string ): string => { let scaleFactor = Math.min(tileWidth / width, tileHeight / height); // Increase scale factor by 0.2 if colSpan is 'col-span-2' if (colSpan === 'col-span-2') { scaleFactor = Math.min(scaleFactor + 0.2, 1); // Ensure it doesn't exceed 1 } const scaleValues = [ { factor: 0.1, scale: 'scale-10' }, { factor: 0.2, scale: 'scale-20' }, { factor: 0.3, scale: 'scale-30' }, { factor: 0.4, scale: 'scale-40' }, { factor: 0.5, scale: 'scale-50' }, { factor: 0.6, scale: 'scale-60' }, { factor: 0.7, scale: 'scale-70' }, { factor: 0.8, scale: 'scale-80' }, { factor: 0.9, scale: 'scale-90' }, ]; // Find the closest matching scale factor const closestScale = scaleValues.reduce((prev, curr) => Math.abs(scaleFactor - curr.factor) < Math.abs(scaleFactor - prev.factor) ? curr : prev ); return closestScale.scale; }; const calculateColSpan = (width: number): string => { if (width >= 800) return 'col-span-2'; return ''; }; export const BitesLibrary = () => { const [blocks, setBlocks] = useState([]); const [selectedCategory, setSelectedCategory] = useState(null); const [navigation, setNavigation] = useState([]); const [open, setOpen] = useState(false); const [blockSelection, setBlockSelection] = useState([]); const [componentMode, setComponentMode] = useState(true); useEffect(() => { apiFetch({ path: `${blockbite.api}/bites/library` }).then((result: any) => { if (result.navigation.length === 0) return; setNavigation(result.navigation); setSelectedCategory(result.navigation[0].post_id); }); }, []); const insertBlocks = () => () => { // Helper function to update the bitesId for a block and its inner blocks const updateBitesId = (block: any) => { // Update the bitesId of the current block if (block.attributes) { block.attributes.bitesId = `bit_${nanoid(8)}`; } // If the block has innerBlocks, recursively update their bitesId as well if (block.innerBlocks && block.innerBlocks.length > 0) { block.innerBlocks = block.innerBlocks.map(updateBitesId); } return block; }; // Parse the block data const parseBlocks = []; blockSelection.forEach((id) => { const block = blocks.find((block) => block.id === id); let parsedBlock = wp.blocks.parse( componentMode ? block.component : block.raw ); // Update the bitesId for each parsed block and its inner blocks parsedBlock = parsedBlock.map(updateBitesId); if (parsedBlock.length) { parseBlocks.push(parsedBlock[0]); } }); const insert = wp.data.select('core/block-editor').getBlockInsertionPoint(); if (insert.rootClientId && insert.index !== undefined) { wp.data .dispatch('core/block-editor') .insertBlocks(parseBlocks, insert.index, insert.rootClientId, true); } else { wp.data.dispatch('core/block-editor').insertBlocks(parseBlocks); } }; const addBlockSelection = (blockId: string) => { if (blockSelection.includes(blockId)) { setBlockSelection(blockSelection.filter((id: string) => id !== blockId)); } else { setBlockSelection([...blockSelection, blockId]); } }; const selectAllBlocks = () => { const allBlockIds = blocks.map((block) => block.id); setBlockSelection(allBlockIds); }; useEffect(() => { if (!selectedCategory) return; apiFetch({ path: `${blockbite.api}/bites/blocks/${selectedCategory}`, }).then((result: any) => { const blocks = result.blocks.map((block: any) => { const { width, height } = block; const aspectRatio = calculateAspectRatio(width, height); const colspan = calculateColSpan(width); const scale = calculateScale(width, height, 400, 400, colspan); return { ...block, aspectRatio, scale, colspan, }; }); setBlocks(blocks); }); }, [selectedCategory]); return ( { setOpen(isOpen); }} > Block Library
{navigation.map((category: BlockCategory, index: number) => ( ))}
{componentMode ? `Change block styles fromout your` : 'Changed block styles should be applied to each block'}
{blocks.length === 0 &&

No blocks found in the library.

} {blocks.map((block: any) => (
addBlockSelection(block.id)} >

{block.name}

))}
{selected {blockSelection.length} blocks} {blockSelection.length > 0 && ( )} {blockSelection.length !== blocks.length && ( )} ); }; export default { BitesLibrary };