-
Notifications
You must be signed in to change notification settings - Fork 96
feature: sidebar gutenberg block #251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
feature: sidebar gutenberg block #251
Conversation
WalkthroughAdds a new Sidebar Gutenberg block (editor, view script, PHP render, styles) and introduces a DocsGrid block build output. Updates build assets (dependencies and versions), adds comprehensive CSS (LTR/RTL, print, frontend), introduces shared editor controls, registers data store, and updates tooling/config (webpack, scripts), and plugin registration. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 29
🧹 Nitpick comments (26)
src/blocks/Sidebar/components/CountBadge.js (1)
14-16: Consider handling negative count values.While checking for
count === 0is appropriate, consider also handling negative values (e.g.,count <= 0) to guard against unexpected data.Apply this diff:
- if (count === 0) { + if (count <= 0) { return null; }src/components/Blocks/AlignmentControls.js (1)
205-215: Consider usingundefinedinstead ofnullfor consistency.The Reset All button sets alignment values to
null, whereasColorsControls.js(line 338-341) usesundefinedfor the same purpose. For consistency across control components, consider usingundefinedas it's the conventional way to indicate "no value set" for optional attributes.Apply this diff for consistency:
onClick={() => { setAttributes({ alignmentControls: { ...alignmentControls, [device]: { ...currentAlignment, - textAlign: null, - alignItems: null, - justifyContent: null, - direction: null, + textAlign: undefined, + alignItems: undefined, + justifyContent: undefined, + direction: undefined, }, }, }); }}src/components/Blocks/DimensionsControls.js (1)
239-256: Consider usingundefinedinstead ofnullfor consistency.The Reset All button uses
nullto clear dimension values, whileColorsControls.jsusesundefined. For consistency across control components, consider usingundefined.src/components/Blocks/DisplayControls.js (2)
50-57: Add defensive check for displayControls.The function assumes
attributes.displayControlsexists and is an object. If it's undefined or null, this will throw an error.Apply this diff to add a safe default:
const toggleDeviceVisibility = (deviceKey) => { setAttributes({ displayControls: { - ...attributes.displayControls, + ...(attributes.displayControls || {}), [deviceKey]: !attributes.displayControls[deviceKey], }, }); };
60-61: Add defensive check for device key access.Line 61 accesses
attributes.displayControls[key]without checking if displayControls exists.Apply this diff:
const renderDeviceCard = ({ key, icon, label }) => { - const isHidden = attributes.displayControls[key]; + const isHidden = attributes.displayControls?.[key] || false;src/components/Blocks/BackgroundImageControls.js (1)
33-60: Consider extracting focal point configuration.The logic for setting focal points based on size is somewhat complex and could benefit from extraction into a configuration object for better maintainability.
Consider refactoring like this:
const FOCAL_POINT_PRESETS = { cover: { focalPoint: null, repeat: null }, contain: { focalPoint: { x: 0.5, y: 0.5 }, repeat: false }, tile: { focalPoint: { x: 0.5, y: 0 }, repeat: true } }; const handleBackgroundImageSizeChange = (value) => { const preset = FOCAL_POINT_PRESETS[value] || {}; setAttributes({ backgroundImageControls: { ...backgroundImageControls, [device]: { ...currentBackgroundImage, bgSize: value, bgFocalPoint: preset.focalPoint, bgRepeat: preset.repeat, }, }, }); };src/components/Blocks/TypographyControls.js (2)
34-37: Add defensive checks for font families structure.The code assumes
fontFamilies[0]exists and hasthemeandcustomproperties. This could fail if the structure is different.Apply this diff:
// Combine both theme and custom fonts - const themeFonts = fontFamilies[0]?.theme || []; - const customFonts = fontFamilies[0]?.custom || []; + const themeFonts = fontFamilies?.[0]?.theme || []; + const customFonts = fontFamilies?.[0]?.custom || []; const validFontFamilies = [...themeFonts, ...customFonts];
77-77: Remove or clarify empty onChange handler.The disabled SelectControl has an empty
onChange={() => {}}handler. Since the control is disabled, this handler will never be called. Consider removing it or adding a comment explaining why it's present.value={'default'} - onChange={() => {}} disabledsrc/blocks/Sidebar/index.js (1)
7-17: Consider adding block icon for better UX.The block registration doesn't include an icon, which means it will use a default placeholder icon in the block inserter. Consider adding an icon to improve the user experience.
Example:
+import { folder } from '@wordpress/icons'; + registerBlockType(metadata.name, { /** * @see ./edit.js */ edit: Edit, + icon: folder, /** * @see ./save.js */ save: Save, });src/blocks/Sidebar/view.js (3)
10-44: Refactor to use class toggles instead of inline styles.The current implementation directly manipulates
style.displaywhich prevents CSS transitions and makes styling harder to maintain. Consider toggling a CSS class instead.if (isExpanded) { // Collapse - children.style.display = 'none'; + children.classList.add('is-collapsed'); this.setAttribute('aria-expanded', 'false'); if (toggleButton) { // Change to down arrow - toggleButton.innerHTML = ` - <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" style="width: 16px; height: 16px;"> - <path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" /> - </svg> - `; + toggleButton.classList.add('is-collapsed'); } } else { // Expand - children.style.display = 'block'; + children.classList.remove('is-collapsed'); this.setAttribute('aria-expanded', 'true'); if (toggleButton) { // Change to up arrow - toggleButton.innerHTML = ` - <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" style="width: 16px; height: 16px;"> - <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 15.75 7.5-7.5 7.5 7.5" /> - </svg> - `; + toggleButton.classList.remove('is-collapsed'); } }Then add CSS:
.wedocs-section-children.is-collapsed { display: none; } .wedocs-expand-toggle.is-collapsed svg:first-child { display: none; } .wedocs-expand-toggle:not(.is-collapsed) svg:last-child { display: none; }
56-116: Consider event delegation for better performance.The current implementation attaches individual event listeners to every section, title, and article link. For large documentation trees, this could create hundreds of listeners. Event delegation would be more efficient.
- // Handle hover effects for sections - const sections = document.querySelectorAll('.wedocs-section'); - - sections.forEach(section => { - section.addEventListener('mouseenter', function() { - const hoverBg = getComputedStyle(this).getPropertyValue('--section-bg-hover'); - if (hoverBg && hoverBg.trim() !== '') { - this.style.backgroundColor = hoverBg; - } - }); - - section.addEventListener('mouseleave', function() { - const normalBg = getComputedStyle(this).getPropertyValue('--section-bg'); - this.style.backgroundColor = normalBg || ''; - }); - }); + // Handle hover effects using event delegation + document.addEventListener('mouseenter', function(e) { + const section = e.target.closest('.wedocs-section'); + if (section) { + const hoverBg = getComputedStyle(section).getPropertyValue('--section-bg-hover'); + if (hoverBg && hoverBg.trim() !== '') { + section.style.backgroundColor = hoverBg; + } + } + + const articleLink = e.target.closest('.wedocs-article a'); + if (articleLink) { + const article = articleLink.closest('.wedocs-article'); + const hoverColor = getComputedStyle(article).getPropertyValue('--doc-list-text-color-hover'); + if (hoverColor) { + articleLink.style.color = hoverColor; + } + } + }, true); + + document.addEventListener('mouseleave', function(e) { + const section = e.target.closest('.wedocs-section'); + if (section) { + const normalBg = getComputedStyle(section).getPropertyValue('--section-bg'); + section.style.backgroundColor = normalBg || ''; + } + + const articleLink = e.target.closest('.wedocs-article a'); + if (articleLink) { + const article = articleLink.closest('.wedocs-article'); + const textColor = getComputedStyle(article).getPropertyValue('--doc-list-text-color'); + if (textColor) { + articleLink.style.color = textColor; + } + } + }, true);
48-53: Extract toggle logic to avoid indirect click triggering.Calling
this.click()in the keyboard handler is indirect and can cause issues if the click handler changes. Extract the toggle logic into a function.+ function toggleSection(header) { + const section = header.closest('.wedocs-section'); + const children = section.querySelector('.wedocs-section-children'); + const toggleButton = header.querySelector('.wedocs-expand-toggle'); + const isExpanded = header.getAttribute('aria-expanded') === 'true'; + + if (!children) return; + + if (isExpanded) { + children.classList.add('is-collapsed'); + header.setAttribute('aria-expanded', 'false'); + if (toggleButton) { + toggleButton.classList.add('is-collapsed'); + } + } else { + children.classList.remove('is-collapsed'); + header.setAttribute('aria-expanded', 'true'); + if (toggleButton) { + toggleButton.classList.remove('is-collapsed'); + } + } + } + sectionHeaders.forEach(header => { header.addEventListener('click', function(e) { e.preventDefault(); - - const section = this.closest('.wedocs-section'); - const children = section.querySelector('.wedocs-section-children'); - // ... rest of toggle logic + toggleSection(this); }); header.addEventListener('keydown', function(e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); - this.click(); + toggleSection(this); } }); });assets/build/blocks/DocsGrid/style-index.css (1)
13-46: Reduce duplication in pagination styles and relocate RTL-specific rule.
.wedocs-docs-paginationis defined twice; consider consolidating the shared rules and scoping differences (buttons vs.page-numbers) to avoid drift.- The
[dir=rtl]arrow rule in the LTR stylesheet is redundant given the separate RTL file; keep RTL-only rules in the RTL stylesheet for clarity.Also applies to: 217-299, 213-215
src/components/Blocks/BorderAndShadowControls.js (1)
70-81: Unify i18n text domain with the plugin.Use
wedocsas the text domain for consistent translation loading.Apply this diff (repeat for all labels):
- label={__('Border', 'block-responsive')} + label={__('Border', 'wedocs')} - name: __('Theme', 'block-responsive'), + name: __('Theme', 'wedocs'), - label={__('Border Radius', 'block-responsive')} + label={__('Border Radius', 'wedocs')} - <Text>{__('Drop Shadow', 'block-responsive')}</Text> + <Text>{__('Drop Shadow', 'wedocs')}</Text> - label={__('Outset', 'block-responsive')} + label={__('Outset', 'wedocs')} - label={__('Inset', 'block-responsive')} + label={__('Inset', 'wedocs')} - label={__('X Position', 'block-responsive')} + label={__('X Position', 'wedocs')} - label={__('Y Position', 'block-responsive')} + label={__('Y Position', 'wedocs')} - label={__('Blur', 'block-responsive')} + label={__('Blur', 'wedocs')} - label={__('Spread', 'block-responsive')} + label={__('Spread', 'wedocs')} - text={__('Reset All', 'block-responsive')} + text={__('Reset All', 'wedocs')}Also applies to: 95-99, 131-135, 159-166, 177-181, 185-191, 193-201, 203-209, 219-219
src/blocks/Sidebar/components/ArticleItem.js (1)
10-24: Reduce duplication; prefer CSS hovers over JS events
- decodeHtmlEntities and getColorValue duplicate SectionItem.js helpers; extract to a small shared util.
- Replace inline onMouseEnter/onMouseLeave color changes with CSS :hover using CSS variables for consistency.
Also applies to: 36-45, 58-66
src/blocks/Sidebar/edit.js (1)
121-124: Prefer importing apiFetch over using wp.apiFetchImporting ensures bundling and typings:
import apiFetch from '@wordpress/api-fetch'then useapiFetch({ path }).src/blocks/Sidebar/components/SectionItem.js (1)
1-4: Remove unused importCountBadge is imported but not used.
-import CountBadge from './CountBadge';assets/build/blocks/Sidebar/render.php (1)
19-29: Remove or use unused variables$section_title_tag, $article_title_tag, $count_badge_styles, $doc_list_styles, and $content/$parent are unused. Clean up or wire them into output (see parity comment).
src/blocks/Sidebar/render.php (5)
324-324: Remove unused $count_badge_styles param (and argument) or implement badge renderingParameter is unused; keep code lean or render the badge.
Apply:
- function wedocs_render_section_with_articles( $section, $articles_by_section, $enable_nested_articles, $section_title_tag, $article_title_tag, $section_styles, $title_styles, $doc_list_styles, $tree_styles, $count_badge_styles, $level = 0 ) { + function wedocs_render_section_with_articles( $section, $articles_by_section, $enable_nested_articles, $section_title_tag, $article_title_tag, $section_styles, $title_styles, $doc_list_styles, $tree_styles, $level = 0 ) {And adjust call:
- $children .= wedocs_render_section_with_articles( - $section, $articles_by_section, $enable_nested_articles, $section_title_tag, $article_title_tag, - $section_styles, $title_styles, $doc_list_styles, $tree_styles, $count_badge_styles - ); + $children .= wedocs_render_section_with_articles( + $section, $articles_by_section, $enable_nested_articles, $section_title_tag, $article_title_tag, + $section_styles, $title_styles, $doc_list_styles, $tree_styles + );Also applies to: 204-207
340-413: Localize ARIA labels for accessibilityHardcoded English strings for aria-labels should be translated.
Example:
- ) . '; background: none; border: none; cursor: pointer; padding: 2px; border-radius: 2px; display: flex; align-items: center; justify-content: center; width: 24px; height: 24px;" aria-expanded="true" aria-label="Toggle ' . esc_attr( - $section->post_title - ) . ' section"> + ) . '; background: none; border: none; cursor: pointer; padding: 2px; border-radius: 2px; display: flex; align-items: center; justify-content: center; width: 24px; height: 24px;" aria-expanded="true" aria-label="' . esc_attr( sprintf( __( 'Toggle %s section', 'wedocs' ), $section->post_title ) ) . '">Apply similar change where aria-label is set on headers/buttons.
Also applies to: 474-493, 575-590
142-153: Normalize boolean enableNestedArticles from attributesThe empty-string coerce is brittle; normalize robustly.
Consider:
- if ($enable_nested_articles === '') { - $enable_nested_articles = true; - } + $enable_nested_articles = filter_var( $enable_nested_articles, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE ); + if ( null === $enable_nested_articles ) { + $enable_nested_articles = true; + }
294-319: Sorting: normalize $order input and use spaceship operatorGuard against 'ASC' casing and improve readability.
Example:
- function wedocs_sort_docs( $docs, $orderby, $order ) { + function wedocs_sort_docs( $docs, $orderby, $order ) { + $order = strtolower( (string) $order ) === 'desc' ? 'desc' : 'asc'; if ( empty( $docs ) ) { return $docs; } usort( $docs, function( $a, $b ) use ( $orderby, $order ) { switch ( $orderby ) { case 'name': - $result = strcmp( $a->post_title, $b->post_title ); + $result = strcmp( $a->post_title, $b->post_title ); break; case 'slug': - $result = strcmp( $a->post_name, $b->post_name ); + $result = strcmp( $a->post_name, $b->post_name ); break; case 'id': - $result = $a->ID - $b->ID; + $result = $a->ID <=> $b->ID; break; default: - $result = $a->menu_order - $b->menu_order; + $result = $a->menu_order <=> $b->menu_order; } - return $order === 'desc' ? - $result : $result; + return $order === 'desc' ? -$result : $result; } ); return $docs; }
570-589: Avoid emoji as icon; prefer SVG for consistency and a11yThe 📄 emoji may render inconsistently. Consider an inline SVG like other icons.
assets/build/blocks/Sidebar/index.js (3)
1207-1223: Ignore lints on bundled artifacts; errors are from webpack runtimeBiome flags (use-before-declare, redeclare) are in webpack bootstrap code. Exclude built assets (assets/build/) from linting and code review. Source changes should be made under src/.
670-672: Import and declare dependency for apiFetch in sourceUsing wp.apiFetch assumes the global is enqueued. Prefer importing from @wordpress/api-fetch in src and adding it to the block’s asset dependencies to avoid runtime undefined globals.
158-174: Remove dead code (CountBadge) or wire it upCountBadge is built and exported but not used anywhere. Either render it (e.g., for children counts) or drop it to reduce bundle size.
Also applies to: 206-207, 510-514
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (14)
assets/build/block.js.mapis excluded by!**/*.mapassets/build/blocks/DocsGrid/index.js.mapis excluded by!**/*.mapassets/build/blocks/DocsGrid/style-index.css.mapis excluded by!**/*.mapassets/build/blocks/Sidebar/index.js.mapis excluded by!**/*.mapassets/build/blocks/Sidebar/style-index.css.mapis excluded by!**/*.mapassets/build/frontend.css.mapis excluded by!**/*.mapassets/build/frontend.js.mapis excluded by!**/*.mapassets/build/index.css.mapis excluded by!**/*.mapassets/build/index.js.mapis excluded by!**/*.mapassets/build/print.css.mapis excluded by!**/*.mapassets/build/print.js.mapis excluded by!**/*.mapassets/build/store.js.mapis excluded by!**/*.mapassets/build/style-block.css.mapis excluded by!**/*.mappackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (45)
assets/build/block.asset.php(1 hunks)assets/build/blocks/DocsGrid/index.asset.php(1 hunks)assets/build/blocks/DocsGrid/index.js(1 hunks)assets/build/blocks/DocsGrid/style-index-rtl.css(1 hunks)assets/build/blocks/DocsGrid/style-index.css(1 hunks)assets/build/blocks/Sidebar/block.json(1 hunks)assets/build/blocks/Sidebar/index.asset.php(1 hunks)assets/build/blocks/Sidebar/index.js(1 hunks)assets/build/blocks/Sidebar/render.php(1 hunks)assets/build/frontend-rtl.css(1 hunks)assets/build/frontend.asset.php(1 hunks)assets/build/frontend.css(2 hunks)assets/build/frontend.js(1 hunks)assets/build/index.asset.php(1 hunks)assets/build/print-rtl.css(1 hunks)assets/build/print.asset.php(1 hunks)assets/build/print.css(2 hunks)assets/build/print.js(1 hunks)assets/build/store.asset.php(1 hunks)assets/build/store.js(1 hunks)assets/build/style-block-rtl.css(1 hunks)assets/build/style-block.css(1 hunks)package.json(1 hunks)src/blocks/Sidebar/block.json(1 hunks)src/blocks/Sidebar/components/ArticleItem.js(1 hunks)src/blocks/Sidebar/components/CountBadge.js(1 hunks)src/blocks/Sidebar/components/SectionItem.js(1 hunks)src/blocks/Sidebar/components/SidebarContainer.js(1 hunks)src/blocks/Sidebar/components/index.js(1 hunks)src/blocks/Sidebar/edit.js(1 hunks)src/blocks/Sidebar/index.js(1 hunks)src/blocks/Sidebar/render.php(1 hunks)src/blocks/Sidebar/save.js(1 hunks)src/blocks/Sidebar/style.css(1 hunks)src/blocks/Sidebar/view.js(1 hunks)src/blocks/index.js(1 hunks)src/components/Blocks/AlignmentControls.js(1 hunks)src/components/Blocks/BackgroundImageControls.js(1 hunks)src/components/Blocks/BorderAndShadowControls.js(1 hunks)src/components/Blocks/ColorsControls.js(1 hunks)src/components/Blocks/DimensionsControls.js(1 hunks)src/components/Blocks/DisplayControls.js(1 hunks)src/components/Blocks/TypographyControls.js(1 hunks)webpack.config.js(1 hunks)wedocs.php(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (17)
src/blocks/Sidebar/components/CountBadge.js (3)
src/blocks/Sidebar/edit.js (1)
attributes(9-23)src/blocks/Sidebar/components/ArticleItem.js (2)
attributes(3-8)getColorValue(22-24)src/blocks/Sidebar/components/SectionItem.js (2)
attributes(8-13)getColorValue(24-26)
src/blocks/Sidebar/components/ArticleItem.js (4)
src/blocks/Sidebar/edit.js (1)
attributes(9-23)src/blocks/Sidebar/components/SectionItem.js (7)
attributes(8-13)decodeHtmlEntities(16-21)indentation(29-29)getColorValue(24-26)iconStyle(59-63)TitleTag(69-69)children(70-70)src/blocks/Sidebar/components/CountBadge.js (2)
attributes(2-2)getColorValue(5-7)src/blocks/Sidebar/view.js (1)
hoverColor(104-104)
src/blocks/Sidebar/components/SidebarContainer.js (3)
src/blocks/Sidebar/edit.js (2)
sections(82-82)attributes(9-23)src/blocks/Sidebar/components/SectionItem.js (2)
SectionItem(5-236)attributes(8-13)src/blocks/Sidebar/components/ArticleItem.js (1)
attributes(3-8)
src/blocks/Sidebar/components/SectionItem.js (2)
src/blocks/Sidebar/edit.js (1)
attributes(9-23)src/blocks/Sidebar/components/ArticleItem.js (8)
attributes(3-8)decodeHtmlEntities(11-16)getColorValue(22-24)indentation(19-19)iconStyle(36-40)TitleTag(47-47)children(48-48)ArticleItem(1-144)
src/components/Blocks/DimensionsControls.js (5)
src/components/Blocks/AlignmentControls.js (1)
attributes(27-27)src/components/Blocks/BackgroundImageControls.js (1)
attributes(15-15)src/components/Blocks/BorderAndShadowControls.js (1)
attributes(22-22)src/components/Blocks/ColorsControls.js (1)
attributes(18-18)src/components/Blocks/TypographyControls.js (1)
attributes(29-29)
src/blocks/Sidebar/edit.js (3)
src/blocks/Sidebar/components/ArticleItem.js (1)
attributes(3-8)src/blocks/Sidebar/components/SectionItem.js (1)
attributes(8-13)src/blocks/Sidebar/components/SidebarContainer.js (1)
SidebarContainer(4-26)
src/blocks/Sidebar/index.js (2)
src/blocks/Sidebar/edit.js (1)
Edit(8-467)src/blocks/Sidebar/save.js (1)
Save(1-5)
src/components/Blocks/BorderAndShadowControls.js (5)
src/components/Blocks/AlignmentControls.js (1)
attributes(27-27)src/components/Blocks/BackgroundImageControls.js (1)
attributes(15-15)src/components/Blocks/ColorsControls.js (1)
attributes(18-18)src/components/Blocks/DimensionsControls.js (1)
attributes(12-12)src/components/Blocks/TypographyControls.js (1)
attributes(29-29)
assets/build/store.js (10)
src/components/Documentations/index.js (3)
docs(19-22)loading(29-32)parentDocs(24-27)src/components/DocListing/index.js (3)
docs(27-29)loading(37-40)sections(103-103)src/components/SelectBox.js (1)
pages(16-16)src/blocks/DocsGrid/edit.js (2)
loading(18-18)wp(16-16)src/components/DocListing/ListingHeader.js (1)
loading(13-16)src/blocks/Sidebar/edit.js (1)
sections(82-82)src/components/Documentations/ParentDocs.js (2)
sections(36-40)articles(42-46)src/components/AddArticleModal.js (1)
articles(35-39)src/components/DocListing/QuickEditModal.js (1)
articles(34-38)src/components/DocListing/DocSections.js (2)
articles(70-70)settings(86-89)
src/components/Blocks/AlignmentControls.js (5)
src/components/Blocks/BackgroundImageControls.js (1)
attributes(15-15)src/components/Blocks/BorderAndShadowControls.js (1)
attributes(22-22)src/components/Blocks/ColorsControls.js (1)
attributes(18-18)src/components/Blocks/DimensionsControls.js (1)
attributes(12-12)src/components/Blocks/TypographyControls.js (1)
attributes(29-29)
assets/build/blocks/DocsGrid/index.js (1)
src/blocks/Sidebar/edit.js (3)
attributes(9-23)processDocsData(142-238)sections(82-82)
src/components/Blocks/BackgroundImageControls.js (1)
src/blocks/CustomControls/UnitControl.js (1)
UnitControl(4-27)
src/components/Blocks/TypographyControls.js (9)
src/blocks/Sidebar/edit.js (1)
attributes(9-23)src/blocks/Sidebar/components/ArticleItem.js (1)
attributes(3-8)src/blocks/Sidebar/components/SectionItem.js (1)
attributes(8-13)src/blocks/Sidebar/components/CountBadge.js (1)
attributes(2-2)src/components/Blocks/AlignmentControls.js (1)
attributes(27-27)src/components/Blocks/BackgroundImageControls.js (1)
attributes(15-15)src/components/Blocks/BorderAndShadowControls.js (1)
attributes(22-22)src/components/Blocks/ColorsControls.js (1)
attributes(18-18)src/components/Blocks/DimensionsControls.js (1)
attributes(12-12)
src/components/Blocks/ColorsControls.js (1)
src/blocks/Sidebar/edit.js (1)
useSelect(30-36)
src/blocks/Sidebar/render.php (1)
assets/build/blocks/Sidebar/render.php (3)
render_wedocs_sidebar(11-153)wedocs_sort_docs(158-192)wedocs_render_section_with_articles(197-226)
assets/build/blocks/Sidebar/render.php (2)
src/blocks/Sidebar/render.php (3)
render_wedocs_sidebar(142-289)wedocs_sort_docs(294-319)wedocs_render_section_with_articles(324-521)includes/Walker.php (2)
Walker(10-22)start_el(15-21)
src/components/Blocks/DisplayControls.js (6)
src/components/Blocks/AlignmentControls.js (1)
attributes(27-27)src/components/Blocks/BackgroundImageControls.js (1)
attributes(15-15)src/components/Blocks/BorderAndShadowControls.js (1)
attributes(22-22)src/components/Blocks/ColorsControls.js (1)
attributes(18-18)src/components/Blocks/DimensionsControls.js (1)
attributes(12-12)src/components/Blocks/TypographyControls.js (1)
attributes(29-29)
🪛 Biome (2.1.2)
src/blocks/Sidebar/style.css
[error] 74-74: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
padding is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
assets/build/print-rtl.css
[error] 40-40: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
white-space is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
[error] 65-65: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
font-size is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
assets/build/store.js
[error] 321-324: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 325-325: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 375-375: Unsafe usage of optional chaining.
If it short-circuits with 'undefined' the evaluation will throw TypeError here:
(lint/correctness/noUnsafeOptionalChaining)
[error] 376-376: Unsafe usage of optional chaining.
If it short-circuits with 'undefined' the evaluation will throw TypeError here:
(lint/correctness/noUnsafeOptionalChaining)
assets/build/blocks/DocsGrid/index.js
[error] 1040-1040: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1047-1047: Shouldn't redeclare 'i'. Consider to delete it or rename it.
'i' is defined here:
(lint/suspicious/noRedeclare)
[error] 1048-1048: Shouldn't redeclare 'chunkIds'. Consider to delete it or rename it.
'chunkIds' is defined here:
(lint/suspicious/noRedeclare)
[error] 1048-1048: Shouldn't redeclare 'fn'. Consider to delete it or rename it.
'fn' is defined here:
(lint/suspicious/noRedeclare)
[error] 1048-1048: Shouldn't redeclare 'priority'. Consider to delete it or rename it.
'priority' is defined here:
(lint/suspicious/noRedeclare)
assets/build/style-block.css
[error] 54-54: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
width is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
assets/build/frontend-rtl.css
[error] 326-326: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
display is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
[error] 493-493: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
white-space is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
[error] 518-518: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
font-size is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
assets/build/style-block-rtl.css
[error] 54-54: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
width is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
assets/build/blocks/Sidebar/index.js
[error] 1210-1210: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1217-1217: Shouldn't redeclare 'i'. Consider to delete it or rename it.
'i' is defined here:
(lint/suspicious/noRedeclare)
[error] 1218-1218: Shouldn't redeclare 'chunkIds'. Consider to delete it or rename it.
'chunkIds' is defined here:
(lint/suspicious/noRedeclare)
[error] 1218-1218: Shouldn't redeclare 'fn'. Consider to delete it or rename it.
'fn' is defined here:
(lint/suspicious/noRedeclare)
[error] 1218-1218: Shouldn't redeclare 'priority'. Consider to delete it or rename it.
'priority' is defined here:
(lint/suspicious/noRedeclare)
🪛 PHPMD (2.15.0)
src/blocks/Sidebar/render.php
142-142: Avoid unused parameters such as '$content'. (undefined)
(UnusedFormalParameter)
157-157: Avoid unused local variables such as '$container_styles'. (undefined)
(UnusedLocalVariable)
324-324: Avoid unused parameters such as '$count_badge_styles'. (undefined)
(UnusedFormalParameter)
assets/build/blocks/Sidebar/render.php
11-11: Avoid unused parameters such as '$content'. (undefined)
(UnusedFormalParameter)
19-19: Avoid unused local variables such as '$section_title_tag'. (undefined)
(UnusedLocalVariable)
20-20: Avoid unused local variables such as '$article_title_tag'. (undefined)
(UnusedLocalVariable)
26-26: Avoid unused local variables such as '$count_badge_styles'. (undefined)
(UnusedLocalVariable)
27-27: Avoid unused local variables such as '$doc_list_styles'. (undefined)
(UnusedLocalVariable)
32-32: Avoid unused local variables such as '$parent'. (undefined)
(UnusedLocalVariable)
🔇 Additional comments (29)
assets/build/print.css (1)
1-186: LGTM!Build artifact with updated pipeline metadata and source map reference. No functional CSS changes detected.
assets/build/print.asset.php (1)
1-1: LGTM!Standard asset manifest version bump for cache invalidation.
assets/build/frontend.js (1)
1-28: LGTM!Standard webpack bootstrap runtime for ES module interop. No concerns.
assets/build/print.js (1)
1-28: LGTM!Standard webpack bootstrap runtime, consistent with other build outputs.
src/blocks/Sidebar/components/CountBadge.js (1)
18-26: LGTM!The badge rendering logic is clean with proper accessibility support via
aria-label.assets/build/style-block-rtl.css (2)
53-54: Vendor prefix pattern is intentional.The duplicate
widthproperties flagged by static analysis are intentional vendor prefixing. The-moz-fit-contentprefix ensures compatibility with older Firefox versions, whilefit-contentprovides the standard fallback. This is a common progressive enhancement pattern in CSS.
1-137: LGTM!RTL styling for the Wedocs search block is comprehensive and properly structured. The CSS variables, layout rules, and accessibility considerations are well-implemented.
webpack.config.js (1)
9-9: Verify @wordpress/scripts defaultConfig.entry API. Unable to locate the upstream webpack config locally; please confirm that in @wordpress/scripts v^30.25.0+,defaultConfig.entryis indeed a function and that using...defaultConfig.entry()aligns with the official API.package.json (1)
33-33: Select format for breaking changes overview. Would you prefer a short summary of the breaking changes across @wordpress/scripts v25→30 or a detailed changelog with links for each version?assets/build/block.asset.php (1)
1-1: LGTM!The dependency update from
reacttoreact-jsx-runtimealigns with the modern JSX transform introduced in React 17+. The addition ofwp-datasuggests proper integration with WordPress data stores.src/components/Blocks/ColorsControls.js (1)
17-351: LGTM!The color controls component follows WordPress block editor patterns correctly:
- Proper use of
useSelectto fetch theme colors and gradients- Consistent per-device attribute management with proper spread operators
- Appropriate use of experimental components with ESLint disable comment
- Reset functionality correctly clears values while preserving other device settings
src/components/Blocks/AlignmentControls.js (1)
26-222: LGTM!The alignment controls component follows the established patterns:
- Consistent per-device attribute management
- Proper use of WordPress icon components
- Clear separation of concerns with individual handlers
src/blocks/Sidebar/block.json (1)
1-118: LGTM!The block manifest is well-structured:
- Uses latest schema and API version 3
- Comprehensive attribute definitions with appropriate types and defaults
- Proper asset file references for editor and frontend
- Support configuration appropriately enables spacing and background customization
src/components/Blocks/DimensionsControls.js (1)
11-261: LGTM!The dimension controls component is well-implemented:
- Proper use of WordPress experimental components
- Consistent per-device attribute management
- Comprehensive coverage of dimension properties (padding, margin, width, height)
- Clear UI organization with appropriate labels
assets/build/store.asset.php (1)
1-1: LGTM!The asset version bump aligns with the build changes introduced in this PR.
src/blocks/index.js (1)
3-3: LGTM!The Sidebar block import follows the same pattern as the existing blocks and properly integrates into the block registration system.
assets/build/frontend.asset.php (1)
1-1: LGTM!The asset version bump reflects the build changes in this PR.
assets/build/frontend.css (1)
1-3: LGTM!The addition of build metadata comments and sourcemap reference is standard for build artifacts. No functional changes to CSS.
Also applies to: 1223-1224
src/blocks/Sidebar/index.js (1)
5-5: Retain style import. This import is required for the bundler to generate thestyle-index.cssfile declared inblock.json.assets/build/blocks/Sidebar/index.asset.php (1)
1-1: LGTM! Standard WordPress block asset manifest.The dependencies and version hash are correctly formatted for a server-rendered Gutenberg block.
src/blocks/Sidebar/save.js (1)
1-7: LGTM! Correct pattern for server-rendered blocks.Returning
nullfrom the save function is the standard approach for dynamic blocks that render server-side via PHP. The comment clearly documents this behavior.wedocs.php (2)
50-50: LGTM! Sidebar render file inclusion.The
require_oncestatement properly includes the Sidebar block's render callback, following the same pattern as the DocsGrid block.
187-193: LGTM! Sidebar block registration.The block registration follows WordPress best practices and maintains consistency with the existing DocsGrid block registration pattern. The render callback is properly configured.
assets/build/index.asset.php (1)
1-1: LGTM! Updated for modern JSX transform.The addition of
react-jsx-runtimealigns with the new JSX transform introduced in React 17+, which is now the standard for WordPress block development.src/blocks/Sidebar/components/index.js (1)
1-4: LGTM! Clean barrel export pattern.The barrel export provides a clean public API for the Sidebar components, allowing consumers to import from a single entry point.
src/blocks/Sidebar/components/SidebarContainer.js (1)
20-20: Tailwind CSS is configured
Confirmed tailwind.config.js, tailwindcss dependency, and wide use of utility classes—no changes needed.assets/build/store.js (1)
1-20: No async dependency detected
package.json and lockfiles contain no async entries. Confirm whether [email protected] is required or if issue #162 can be closed.assets/build/blocks/DocsGrid/index.js (1)
1036-1055: Ignore lints on webpack runtime in built artifactsBiome warnings about redeclarations/use-before-declaration are from webpack runtime scaffolding. Safe to ignore in built files; don’t patch compiled output.
Also applies to: 1047-1048
assets/build/blocks/Sidebar/index.js (1)
11-11: Block attribute parity: ensure server supports all editor optionsThe editor exposes “Count” ordering (block.json). Confirm render.php supports it (currently missing before fix) and that style attributes (e.g., container background) match frontend output.
| @@ -0,0 +1 @@ | |||
| <?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => 'c2ad1e7060a95f9ac780'); | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Inconsistent with AI-generated summary.
The AI summary states that wp-data is included in the dependencies array, but the actual code does not include it. The Sidebar block includes wp-data but DocsGrid does not, while DocsGrid includes wp-primitives that Sidebar lacks.
Verify whether the DocsGrid block requires wp-data for its functionality. If the block uses WordPress data stores or selectors, the dependency should be included.
🏁 Script executed:
#!/bin/bash
# Description: Check if DocsGrid source files use wp-data APIs
# Search for wp-data usage in DocsGrid source files
rg -n --type=js -C3 -g '!**/build/**' -g '**/DocsGrid/**' '@wordpress/data|useSelect|useDispatch|select|dispatch'Length of output: 81305
Include wp-data in DocsGrid block dependencies
DocsGrid edit.js invokes wp.data.useSelect → enqueue 'wp-data'.
In assets/build/blocks/DocsGrid/index.asset.php, add 'wp-data' to the dependencies array:
<?php return array(
- 'dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-primitives'),
+ 'dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-primitives', 'wp-data'),
'version' => 'c2ad1e7060a95f9ac780'
);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => 'c2ad1e7060a95f9ac780'); | |
| <?php return array( | |
| 'dependencies' => array( | |
| 'react-jsx-runtime', | |
| 'wp-block-editor', | |
| 'wp-blocks', | |
| 'wp-components', | |
| 'wp-element', | |
| 'wp-i18n', | |
| 'wp-primitives', | |
| 'wp-data', | |
| ), | |
| 'version' => 'c2ad1e7060a95f9ac780', | |
| ); |
🤖 Prompt for AI Agents
In assets/build/blocks/DocsGrid/index.asset.php around line 1, the block
dependencies array is missing 'wp-data' even though DocsGrid edit.js calls
wp.data.useSelect; update the dependencies array to include 'wp-data' (add
'wp-data' as an element in the returned 'dependencies' array) so the built block
enqueues the data module at runtime.
| className: `wedocs-docs-grid ${getGridClass()}`, | ||
| children: loading ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(Spinner, {}) : displayDocs.map(doc => renderGridItem(doc, applyStyles())) | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spinner is undefined in bundle — import and reference it from components
The compiled bundle renders but there’s no import or qualified reference. This will throw at runtime.
Fix in source (src/blocks/DocsGrid/edit.js):
- import { __ } from '@wordpress/i18n';
+ import { __ } from '@wordpress/i18n';
+ import { Spinner } from '@wordpress/components';And ensure usage is <Spinner /> (named import) so the bundle emits _wordpress_components__.Spinner.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| className: `wedocs-docs-grid ${getGridClass()}`, | |
| children: loading ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(Spinner, {}) : displayDocs.map(doc => renderGridItem(doc, applyStyles())) | |
| }) | |
| import { __ } from '@wordpress/i18n'; | |
| import { Spinner } from '@wordpress/components'; |
🤖 Prompt for AI Agents
In assets/build/blocks/DocsGrid/index.js around lines 884-886 the compiled
bundle renders <Spinner /> but Spinner is not imported, causing a runtime error;
update the source file src/blocks/DocsGrid/edit.js to add a named import for
Spinner from @wordpress/components (e.g. import { Spinner } from
'@wordpress/components') and ensure the component usage is the named <Spinner />
so the bundle emits the correct _wordpress_components_.Spinner reference.
| .wedocs-docs-grid__articles li ::marker { | ||
| content: "•"; | ||
| color: var(--wedocs-doc-children-active-color, #0073aa); | ||
| margin-left: 0.5rem; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect ::marker selector spacing (won’t apply).
Use li::marker (no space). The current li ::marker will not style list markers in RTL either.
Apply this diff:
-.wedocs-docs-grid__articles li ::marker {
+.wedocs-docs-grid__articles li::marker {
content: "•";
color: var(--wedocs-doc-children-active-color, #0073aa);
- margin-left: 0.5rem;
+ margin-left: 0.5rem;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .wedocs-docs-grid__articles li ::marker { | |
| content: "•"; | |
| color: var(--wedocs-doc-children-active-color, #0073aa); | |
| margin-left: 0.5rem; | |
| } | |
| .wedocs-docs-grid__articles li::marker { | |
| content: "•"; | |
| color: var(--wedocs-doc-children-active-color, #0073aa); | |
| margin-left: 0.5rem; | |
| } |
🤖 Prompt for AI Agents
In assets/build/blocks/DocsGrid/style-index-rtl.css around lines 182–186 the
selector "li ::marker" is incorrect (the space prevents the ::marker
pseudo-element from applying); change it to "li::marker" (no space) and keep the
same declarations (content, color, margin-left) so list markers are properly
styled in RTL.
| .wedocs-docs-grid__articles li ::marker { | ||
| content: "•"; | ||
| color: var(--wedocs-doc-children-active-color, #0073aa); | ||
| margin-right: 0.5rem; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect ::marker selector spacing (won’t apply).
Use li::marker (no space). The current li ::marker targets a descendant’s marker and won’t affect the list item bullet.
Apply this diff:
-.wedocs-docs-grid__articles li ::marker {
+.wedocs-docs-grid__articles li::marker {
content: "•";
color: var(--wedocs-doc-children-active-color, #0073aa);
margin-right: 0.5rem;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .wedocs-docs-grid__articles li ::marker { | |
| content: "•"; | |
| color: var(--wedocs-doc-children-active-color, #0073aa); | |
| margin-right: 0.5rem; | |
| } | |
| .wedocs-docs-grid__articles li::marker { | |
| content: "•"; | |
| color: var(--wedocs-doc-children-active-color, #0073aa); | |
| margin-right: 0.5rem; | |
| } |
🤖 Prompt for AI Agents
In assets/build/blocks/DocsGrid/style-index.css around lines 182 to 186, the
selector uses "li ::marker" (a space) which targets a descendant's marker and
won't style the list item's bullet; change it to "li::marker" (no space) so the
rule applies to the list item marker, keeping the same declarations (content,
color, margin-right).
| "supports": { | ||
| "html": true, | ||
| "spacing": { | ||
| "padding": true | ||
| }, | ||
| "color": { | ||
| "background": true, | ||
| "text": false | ||
| } | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disable HTML editing for this dynamic block; add textdomain.
- For server-rendered blocks, set
"html": falseto prevent editing raw HTML that won’t persist through render. - Consider adding
"textdomain": "wedocs"for consistent translations.
Apply this diff:
"supports": {
- "html": true,
+ "html": false,
"spacing": {
"padding": true
},
"color": {
"background": true,
"text": false
}
},
+ "textdomain": "wedocs",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "supports": { | |
| "html": true, | |
| "spacing": { | |
| "padding": true | |
| }, | |
| "color": { | |
| "background": true, | |
| "text": false | |
| } | |
| }, | |
| "supports": { | |
| "html": false, | |
| "spacing": { | |
| "padding": true | |
| }, | |
| "color": { | |
| "background": true, | |
| "text": false | |
| } | |
| }, | |
| "textdomain": "wedocs", |
🤖 Prompt for AI Agents
In assets/build/blocks/Sidebar/block.json around lines 10 to 19, the block
currently allows raw HTML editing and lacks a textdomain; update the "supports"
object to set "html" to false and add "textdomain": "wedocs" at the same level
(ensuring valid JSON structure and commas), so server-rendered content can't be
edited as raw HTML and translations use the wedocs textdomain.
| padding: 8px 12px; | ||
| background-color: var(--tree-header-bg, transparent); | ||
| color: var(--tree-header-text, inherit); | ||
| padding: var(--tree-header-padding, 8px 12px); | ||
| border-radius: var(--tree-header-border-radius, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicate padding declaration.
The padding property is declared twice (lines 71 and 74). The second declaration with a CSS variable overrides the first fixed value.
Apply this diff to remove the duplicate:
align-items: center;
justify-content: space-between;
cursor: pointer;
- padding: 8px 12px;
background-color: var(--tree-header-bg, transparent);
color: var(--tree-header-text, inherit);
padding: var(--tree-header-padding, 8px 12px);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| padding: 8px 12px; | |
| background-color: var(--tree-header-bg, transparent); | |
| color: var(--tree-header-text, inherit); | |
| padding: var(--tree-header-padding, 8px 12px); | |
| border-radius: var(--tree-header-border-radius, 0); | |
| align-items: center; | |
| justify-content: space-between; | |
| cursor: pointer; | |
| background-color: var(--tree-header-bg, transparent); | |
| color: var(--tree-header-text, inherit); | |
| padding: var(--tree-header-padding, 8px 12px); | |
| border-radius: var(--tree-header-border-radius, 0); |
🧰 Tools
🪛 Biome (2.1.2)
[error] 74-74: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
padding is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
🤖 Prompt for AI Agents
In src/blocks/Sidebar/style.css around lines 71 to 75, remove the duplicate
padding declaration so only the CSS variable-based padding remains (delete the
fixed `padding: 8px 12px;` line); ensure the remaining `padding:
var(--tree-header-padding, 8px 12px);` provides the default value and no other
padding declarations in this block conflict.
| import { MediaUpload, MediaUploadCheck } from '@wordpress/block-editor'; | ||
| import { | ||
| Button, | ||
| FocalPointPicker, | ||
| ToggleControl, | ||
| __experimentalUnitControl as UnitControl, | ||
| Flex, | ||
| FlexItem, | ||
| __experimentalToggleGroupControl as ToggleGroupControl, | ||
| __experimentalToggleGroupControlOption as ToggleGroupControlOption, | ||
| } from '@wordpress/components'; | ||
| import { __ } from '@wordpress/i18n'; | ||
|
|
||
| const BackgroundImageControls = ({ attributes, setAttributes, device }) => { | ||
| const { backgroundImageControls } = attributes; | ||
| const currentBackgroundImage = backgroundImageControls[device] || {}; | ||
|
|
||
| const ALLOWED_MEDIA_TYPES = ['image']; | ||
|
|
||
| // Handle focal point change | ||
| const handleFocalPointChange = (newFocalPoint) => { | ||
| setAttributes({ | ||
| backgroundImageControls: { | ||
| ...backgroundImageControls, | ||
| [device]: { | ||
| ...currentBackgroundImage, | ||
| bgFocalPoint: newFocalPoint, | ||
| }, | ||
| }, | ||
| }); | ||
| }; | ||
|
|
||
| const handleBackgroundImageSizeChange = (value) => { | ||
| let newFocalPoint = currentBackgroundImage.bgFocalPoint || {}; | ||
| let newBgRepeat = currentBackgroundImage.bgRepeat || false; | ||
|
|
||
| // Set focal point and repeat based on size | ||
| if (value === 'cover') { | ||
| newFocalPoint = null; | ||
| newBgRepeat = null; | ||
| } else if (value === 'contain') { | ||
| newFocalPoint = { x: 0.5, y: 0.5 }; // 50% 50% | ||
| newBgRepeat = false; | ||
| } else if (value === 'tile') { | ||
| newFocalPoint = { x: 0.5, y: 0 }; // 50% 0px | ||
| newBgRepeat = true; | ||
| } | ||
|
|
||
| setAttributes({ | ||
| backgroundImageControls: { | ||
| ...backgroundImageControls, | ||
| [device]: { | ||
| ...currentBackgroundImage, | ||
| bgSize: value, | ||
| bgFocalPoint: newFocalPoint, | ||
| bgRepeat: newBgRepeat, | ||
| }, | ||
| }, | ||
| }); | ||
| }; | ||
|
|
||
| return ( | ||
| <div | ||
| className="block-responsive-background-image-controls" | ||
| style={{ | ||
| display: 'flex', | ||
| flexDirection: 'column', | ||
| gap: '16px', | ||
| }} | ||
| > | ||
| <MediaUploadCheck> | ||
| <MediaUpload | ||
| onSelect={(media) => { | ||
| setAttributes({ | ||
| backgroundImageControls: { | ||
| ...backgroundImageControls, | ||
| [device]: { | ||
| ...currentBackgroundImage, | ||
| bgUrl: media.url, | ||
| bgId: media.id, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| allowedTypes={ALLOWED_MEDIA_TYPES} | ||
| value={currentBackgroundImage.bgId} | ||
| render={({ open }) => ( | ||
| <Button | ||
| __next40pxDefaultSize | ||
| onClick={open} | ||
| style={{ | ||
| width: '100%', | ||
| justifyContent: 'center', | ||
| border: '1px solid #ddd', | ||
| }} | ||
| > | ||
| {currentBackgroundImage.bgUrl | ||
| ? __( | ||
| 'Change Background Image', | ||
| 'block-responsive' | ||
| ) | ||
| : __( | ||
| 'Add Background Image', | ||
| 'block-responsive' | ||
| )} | ||
| </Button> | ||
| )} | ||
| /> | ||
| </MediaUploadCheck> | ||
| {currentBackgroundImage.bgUrl && ( | ||
| <> | ||
| <FocalPointPicker | ||
| __nextHasNoMarginBottom | ||
| url={currentBackgroundImage.bgUrl || ''} | ||
| value={currentBackgroundImage.bgFocalPoint || {}} | ||
| onDragStart={handleFocalPointChange} | ||
| onDrag={handleFocalPointChange} | ||
| onChange={handleFocalPointChange} | ||
| /> | ||
| <ToggleControl | ||
| __nextHasNoMarginBottom | ||
| label={__('Fixed background', 'block-responsive')} | ||
| checked={currentBackgroundImage.bgFixed || false} | ||
| onChange={(value) => { | ||
| setAttributes({ | ||
| backgroundImageControls: { | ||
| ...backgroundImageControls, | ||
| [device]: { | ||
| ...currentBackgroundImage, | ||
| bgFixed: value, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| /> | ||
| <ToggleGroupControl | ||
| label={__('Size', 'block-responsive')} | ||
| value={currentBackgroundImage.bgSize || 'cover'} | ||
| onChange={handleBackgroundImageSizeChange} | ||
| isBlock | ||
| __nextHasNoMarginBottom | ||
| __next40pxDefaultSize | ||
| > | ||
| <ToggleGroupControlOption | ||
| value="cover" | ||
| label={__('Cover', 'block-responsive')} | ||
| /> | ||
| <ToggleGroupControlOption | ||
| value="contain" | ||
| label={__('Contain', 'block-responsive')} | ||
| /> | ||
| <ToggleGroupControlOption | ||
| value="tile" | ||
| label={__('Tile', 'block-responsive')} | ||
| /> | ||
| </ToggleGroupControl> | ||
| <Flex | ||
| style={{ | ||
| gap: '8px', | ||
| justifyContent: 'flex-start', | ||
| }} | ||
| > | ||
| <FlexItem style={{ maxWidth: '100px' }}> | ||
| <UnitControl | ||
| __next40pxDefaultSize | ||
| value={currentBackgroundImage.bgWidth || 'auto'} | ||
| disabled={ | ||
| currentBackgroundImage.bgSize !== 'tile' | ||
| } | ||
| onChange={(value) => { | ||
| setAttributes({ | ||
| backgroundImageControls: { | ||
| ...backgroundImageControls, | ||
| [device]: { | ||
| ...currentBackgroundImage, | ||
| bgWidth: value, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| placeholder={__('Auto', 'block-responsive')} | ||
| /> | ||
| </FlexItem> | ||
| <FlexItem> | ||
| <ToggleControl | ||
| __nextHasNoMarginBottom | ||
| label={__('Repeat', 'block-responsive')} | ||
| disabled={ | ||
| !( | ||
| currentBackgroundImage.bgSize === | ||
| 'contain' || | ||
| currentBackgroundImage.bgSize === 'tile' | ||
| ) | ||
| } | ||
| checked={ | ||
| currentBackgroundImage.bgRepeat || false | ||
| } | ||
| onChange={(value) => { | ||
| setAttributes({ | ||
| backgroundImageControls: { | ||
| ...backgroundImageControls, | ||
| [device]: { | ||
| ...currentBackgroundImage, | ||
| bgRepeat: value, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| /> | ||
| </FlexItem> | ||
| </Flex> | ||
|
|
||
| <Button | ||
| __next40pxDefaultSize | ||
| variant="secondary" | ||
| isDestructive | ||
| text={__('Reset All', 'block-responsive')} | ||
| style={{ | ||
| width: '100%', | ||
| justifyContent: 'center', | ||
| }} | ||
| onClick={() => { | ||
| setAttributes({ | ||
| backgroundImageControls: { | ||
| ...backgroundImageControls, | ||
| [device]: { | ||
| ...currentBackgroundImage, | ||
| bgUrl: null, | ||
| bgId: null, | ||
| bgFocalPoint: null, | ||
| bgFixed: null, | ||
| bgSize: null, | ||
| bgWidth: null, | ||
| bgRepeat: null, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| /> | ||
| </> | ||
| )} | ||
| </div> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent text domain throughout the file.
The component uses 'block-responsive' as the text domain across all localized strings (lines 100, 104, 122, 137, 146, 150, 154, 181, 187, 217), but should use 'wedocs' to match the plugin's text domain.
Example fix for line 100:
- 'Change Background Image',
- 'block-responsive'
+ 'Change Background Image',
+ 'wedocs'Apply similar changes to all other __() calls in this file.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { MediaUpload, MediaUploadCheck } from '@wordpress/block-editor'; | |
| import { | |
| Button, | |
| FocalPointPicker, | |
| ToggleControl, | |
| __experimentalUnitControl as UnitControl, | |
| Flex, | |
| FlexItem, | |
| __experimentalToggleGroupControl as ToggleGroupControl, | |
| __experimentalToggleGroupControlOption as ToggleGroupControlOption, | |
| } from '@wordpress/components'; | |
| import { __ } from '@wordpress/i18n'; | |
| const BackgroundImageControls = ({ attributes, setAttributes, device }) => { | |
| const { backgroundImageControls } = attributes; | |
| const currentBackgroundImage = backgroundImageControls[device] || {}; | |
| const ALLOWED_MEDIA_TYPES = ['image']; | |
| // Handle focal point change | |
| const handleFocalPointChange = (newFocalPoint) => { | |
| setAttributes({ | |
| backgroundImageControls: { | |
| ...backgroundImageControls, | |
| [device]: { | |
| ...currentBackgroundImage, | |
| bgFocalPoint: newFocalPoint, | |
| }, | |
| }, | |
| }); | |
| }; | |
| const handleBackgroundImageSizeChange = (value) => { | |
| let newFocalPoint = currentBackgroundImage.bgFocalPoint || {}; | |
| let newBgRepeat = currentBackgroundImage.bgRepeat || false; | |
| // Set focal point and repeat based on size | |
| if (value === 'cover') { | |
| newFocalPoint = null; | |
| newBgRepeat = null; | |
| } else if (value === 'contain') { | |
| newFocalPoint = { x: 0.5, y: 0.5 }; // 50% 50% | |
| newBgRepeat = false; | |
| } else if (value === 'tile') { | |
| newFocalPoint = { x: 0.5, y: 0 }; // 50% 0px | |
| newBgRepeat = true; | |
| } | |
| setAttributes({ | |
| backgroundImageControls: { | |
| ...backgroundImageControls, | |
| [device]: { | |
| ...currentBackgroundImage, | |
| bgSize: value, | |
| bgFocalPoint: newFocalPoint, | |
| bgRepeat: newBgRepeat, | |
| }, | |
| }, | |
| }); | |
| }; | |
| return ( | |
| <div | |
| className="block-responsive-background-image-controls" | |
| style={{ | |
| display: 'flex', | |
| flexDirection: 'column', | |
| gap: '16px', | |
| }} | |
| > | |
| <MediaUploadCheck> | |
| <MediaUpload | |
| onSelect={(media) => { | |
| setAttributes({ | |
| backgroundImageControls: { | |
| ...backgroundImageControls, | |
| [device]: { | |
| ...currentBackgroundImage, | |
| bgUrl: media.url, | |
| bgId: media.id, | |
| }, | |
| }, | |
| }); | |
| }} | |
| allowedTypes={ALLOWED_MEDIA_TYPES} | |
| value={currentBackgroundImage.bgId} | |
| render={({ open }) => ( | |
| <Button | |
| __next40pxDefaultSize | |
| onClick={open} | |
| style={{ | |
| width: '100%', | |
| justifyContent: 'center', | |
| border: '1px solid #ddd', | |
| }} | |
| > | |
| {currentBackgroundImage.bgUrl | |
| ? __( | |
| 'Change Background Image', | |
| 'block-responsive' | |
| ) | |
| : __( | |
| 'Add Background Image', | |
| 'block-responsive' | |
| )} | |
| </Button> | |
| )} | |
| /> | |
| </MediaUploadCheck> | |
| {currentBackgroundImage.bgUrl && ( | |
| <> | |
| <FocalPointPicker | |
| __nextHasNoMarginBottom | |
| url={currentBackgroundImage.bgUrl || ''} | |
| value={currentBackgroundImage.bgFocalPoint || {}} | |
| onDragStart={handleFocalPointChange} | |
| onDrag={handleFocalPointChange} | |
| onChange={handleFocalPointChange} | |
| /> | |
| <ToggleControl | |
| __nextHasNoMarginBottom | |
| label={__('Fixed background', 'block-responsive')} | |
| checked={currentBackgroundImage.bgFixed || false} | |
| onChange={(value) => { | |
| setAttributes({ | |
| backgroundImageControls: { | |
| ...backgroundImageControls, | |
| [device]: { | |
| ...currentBackgroundImage, | |
| bgFixed: value, | |
| }, | |
| }, | |
| }); | |
| }} | |
| /> | |
| <ToggleGroupControl | |
| label={__('Size', 'block-responsive')} | |
| value={currentBackgroundImage.bgSize || 'cover'} | |
| onChange={handleBackgroundImageSizeChange} | |
| isBlock | |
| __nextHasNoMarginBottom | |
| __next40pxDefaultSize | |
| > | |
| <ToggleGroupControlOption | |
| value="cover" | |
| label={__('Cover', 'block-responsive')} | |
| /> | |
| <ToggleGroupControlOption | |
| value="contain" | |
| label={__('Contain', 'block-responsive')} | |
| /> | |
| <ToggleGroupControlOption | |
| value="tile" | |
| label={__('Tile', 'block-responsive')} | |
| /> | |
| </ToggleGroupControl> | |
| <Flex | |
| style={{ | |
| gap: '8px', | |
| justifyContent: 'flex-start', | |
| }} | |
| > | |
| <FlexItem style={{ maxWidth: '100px' }}> | |
| <UnitControl | |
| __next40pxDefaultSize | |
| value={currentBackgroundImage.bgWidth || 'auto'} | |
| disabled={ | |
| currentBackgroundImage.bgSize !== 'tile' | |
| } | |
| onChange={(value) => { | |
| setAttributes({ | |
| backgroundImageControls: { | |
| ...backgroundImageControls, | |
| [device]: { | |
| ...currentBackgroundImage, | |
| bgWidth: value, | |
| }, | |
| }, | |
| }); | |
| }} | |
| placeholder={__('Auto', 'block-responsive')} | |
| /> | |
| </FlexItem> | |
| <FlexItem> | |
| <ToggleControl | |
| __nextHasNoMarginBottom | |
| label={__('Repeat', 'block-responsive')} | |
| disabled={ | |
| !( | |
| currentBackgroundImage.bgSize === | |
| 'contain' || | |
| currentBackgroundImage.bgSize === 'tile' | |
| ) | |
| } | |
| checked={ | |
| currentBackgroundImage.bgRepeat || false | |
| } | |
| onChange={(value) => { | |
| setAttributes({ | |
| backgroundImageControls: { | |
| ...backgroundImageControls, | |
| [device]: { | |
| ...currentBackgroundImage, | |
| bgRepeat: value, | |
| }, | |
| }, | |
| }); | |
| }} | |
| /> | |
| </FlexItem> | |
| </Flex> | |
| <Button | |
| __next40pxDefaultSize | |
| variant="secondary" | |
| isDestructive | |
| text={__('Reset All', 'block-responsive')} | |
| style={{ | |
| width: '100%', | |
| justifyContent: 'center', | |
| }} | |
| onClick={() => { | |
| setAttributes({ | |
| backgroundImageControls: { | |
| ...backgroundImageControls, | |
| [device]: { | |
| ...currentBackgroundImage, | |
| bgUrl: null, | |
| bgId: null, | |
| bgFocalPoint: null, | |
| bgFixed: null, | |
| bgSize: null, | |
| bgWidth: null, | |
| bgRepeat: null, | |
| }, | |
| }, | |
| }); | |
| }} | |
| /> | |
| </> | |
| )} | |
| </div> | |
| ); | |
| }; | |
| <MediaUpload | |
| onSelect={(media) => { | |
| setAttributes({ | |
| backgroundImageControls: { | |
| ...backgroundImageControls, | |
| [device]: { | |
| ...currentBackgroundImage, | |
| bgUrl: media.url, | |
| bgId: media.id, | |
| }, | |
| }, | |
| }); | |
| }} | |
| allowedTypes={ALLOWED_MEDIA_TYPES} | |
| value={currentBackgroundImage.bgId} | |
| render={({ open }) => ( | |
| <Button | |
| __next40pxDefaultSize | |
| onClick={open} | |
| style={{ | |
| width: '100%', | |
| justifyContent: 'center', | |
| border: '1px solid #ddd', | |
| }} | |
| > | |
| {currentBackgroundImage.bgUrl | |
| ? __( | |
| 'Change Background Image', | |
| 'wedocs' | |
| ) | |
| : __( | |
| 'Add Background Image', | |
| 'wedocs' | |
| )} | |
| </Button> | |
| )} | |
| /> |
🤖 Prompt for AI Agents
In src/components/Blocks/BackgroundImageControls.js lines ~100–217, all
localization calls use the wrong text domain 'block-responsive'; replace every
instance of __('...','block-responsive') with __('...','wedocs') (i.e., update
all __() calls in the file to use 'wedocs' as the second argument) and run a
quick grep to ensure no remaining occurrences of 'block-responsive' in this
file.
| const BorderAndShadowControls = ({ attributes, setAttributes, device }) => { | ||
| const { borderAndShadowControls } = attributes; | ||
| const currentBorderAndShadow = borderAndShadowControls[device] || {}; | ||
| const themeColors = useSetting('color.palette'); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard against undefined attributes to prevent runtime crash.
borderAndShadowControls[device] will throw if borderAndShadowControls is undefined. Default it safely.
Apply this diff:
-const { borderAndShadowControls } = attributes;
-const currentBorderAndShadow = borderAndShadowControls[device] || {};
+const { borderAndShadowControls = {} } = attributes;
+const currentBorderAndShadow = borderAndShadowControls?.[device] || {};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const BorderAndShadowControls = ({ attributes, setAttributes, device }) => { | |
| const { borderAndShadowControls } = attributes; | |
| const currentBorderAndShadow = borderAndShadowControls[device] || {}; | |
| const themeColors = useSetting('color.palette'); | |
| const BorderAndShadowControls = ({ attributes, setAttributes, device }) => { | |
| const { borderAndShadowControls = {} } = attributes; | |
| const currentBorderAndShadow = borderAndShadowControls?.[device] || {}; | |
| const themeColors = useSetting('color.palette'); | |
| // … |
🤖 Prompt for AI Agents
In src/components/Blocks/BorderAndShadowControls.js around lines 21 to 25, guard
against attributes or attributes.borderAndShadowControls being undefined before
indexing by device; replace the direct access with a safe default (for example
destructure from attributes || {}, and compute currentBorderAndShadow as
(borderAndShadowControls && borderAndShadowControls[device]) || {} or use
optional chaining with a fallback) so the code never attempts to read properties
of undefined.
| { | ||
| key: 'mobile', | ||
| icon: mobile, | ||
| label: __('Hide on mobile', 'block-responsive'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent text domain.
The component uses 'block-responsive' as the text domain, but based on the PR context (weDocs plugin) and other files in the codebase, it should use 'wedocs' for consistency.
Apply this diff to fix the text domain:
- label: __('Hide on mobile', 'block-responsive'),
+ label: __('Hide on mobile', 'wedocs'),- label: __('Hide on tablet', 'block-responsive'),
+ label: __('Hide on tablet', 'wedocs'),- label: __('Hide on desktop', 'block-responsive'),
+ label: __('Hide on desktop', 'wedocs'),- {__('Display Options', 'block-responsive')}
+ {__('Display Options', 'wedocs')}Also applies to: 16-16, 21-21, 90-90
🤖 Prompt for AI Agents
In src/components/Blocks/DisplayControls.js around lines 11, 16, 21 and 90, the
i18n text domain is incorrectly set to 'block-responsive'; update each
__('...','block-responsive') and _x(...,'block-responsive') occurrences on those
lines to use the correct text domain 'wedocs' so all translation calls match the
project convention.
| import { __ } from '@wordpress/i18n'; | ||
| import { | ||
| __experimentalFontFamilyControl as FontFamilyControl, | ||
| LineHeightControl, | ||
| useSetting, | ||
| useSettings, | ||
| FontSizePicker, | ||
| __experimentalFontAppearanceControl as FontAppearanceControl, | ||
| } from '@wordpress/block-editor'; | ||
| import { | ||
| Flex, | ||
| FlexItem, | ||
| Button, | ||
| __experimentalUnitControl as UnitControl, | ||
| __experimentalToggleGroupControl as ToggleGroupControl, | ||
| __experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon, | ||
| SelectControl, | ||
| } from '@wordpress/components'; | ||
| import { | ||
| lineSolid, | ||
| formatUnderline, | ||
| formatStrikethrough, | ||
| formatUppercase, | ||
| formatLowercase, | ||
| formatCapitalize, | ||
| } from '@wordpress/icons'; | ||
|
|
||
| const TypographyControls = ({ attributes, setAttributes, device }) => { | ||
| const { typographyControls } = attributes; | ||
| const currentTypography = typographyControls[device] || {}; | ||
| const fontSizes = useSetting('typography.fontSizes'); | ||
| const fontFamilies = useSettings('typography.fontFamilies'); | ||
|
|
||
| // Combine both theme and custom fonts | ||
| const themeFonts = fontFamilies[0]?.theme || []; | ||
| const customFonts = fontFamilies[0]?.custom || []; | ||
| const validFontFamilies = [...themeFonts, ...customFonts]; | ||
|
|
||
| return ( | ||
| <> | ||
| <div | ||
| style={{ | ||
| display: 'flex', | ||
| flexDirection: 'column', | ||
| gap: '16px', | ||
| }} | ||
| > | ||
| {validFontFamilies.length > 0 ? ( | ||
| <FontFamilyControl | ||
| __next40pxDefaultSize | ||
| __nextHasNoMarginBottom | ||
| fontFamilies={validFontFamilies} | ||
| onChange={(value) => { | ||
| setAttributes({ | ||
| typographyControls: { | ||
| ...typographyControls, | ||
| [device]: { | ||
| ...typographyControls[device], | ||
| fontFamily: value, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| value={currentTypography.fontFamily || ''} | ||
| /> | ||
| ) : ( | ||
| <div className="block-responsive-font-control-disabled"> | ||
| <SelectControl | ||
| __next40pxDefaultSize | ||
| __nextHasNoMarginBottom | ||
| label={__('Font', 'block-responsive')} | ||
| help={__( | ||
| 'Not supported in classic themes.', | ||
| 'block-responsive' | ||
| )} | ||
| value={'default'} | ||
| onChange={() => {}} | ||
| disabled | ||
| options={[ | ||
| { | ||
| disabled: true, | ||
| label: __('Default', 'block-responsive'), | ||
| value: 'default', | ||
| }, | ||
| ]} | ||
| /> | ||
| </div> | ||
| )} | ||
|
|
||
| <FontSizePicker | ||
| __next40pxDefaultSize | ||
| fontSizes={fontSizes} | ||
| onChange={(value) => { | ||
| setAttributes({ | ||
| typographyControls: { | ||
| ...typographyControls, | ||
| [device]: { | ||
| ...typographyControls[device], | ||
| fontSize: value, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| value={currentTypography.fontSize || ''} | ||
| withSlider | ||
| withReset={false} | ||
| /> | ||
|
|
||
| <Flex style={{ gap: '16px' }}> | ||
| <FlexItem isBlock> | ||
| <FontAppearanceControl | ||
| __next40pxDefaultSize | ||
| onChange={(value) => { | ||
| setAttributes({ | ||
| typographyControls: { | ||
| ...typographyControls, | ||
| [device]: { | ||
| ...typographyControls[device], | ||
| fontAppearance: value, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| value={currentTypography.fontAppearance || ''} | ||
| /> | ||
| </FlexItem> | ||
| <FlexItem isBlock> | ||
| <LineHeightControl | ||
| __next40pxDefaultSize | ||
| __unstableInputWidth="auto" | ||
| onChange={(value) => { | ||
| setAttributes({ | ||
| typographyControls: { | ||
| ...typographyControls, | ||
| [device]: { | ||
| ...typographyControls[device], | ||
| lineHeight: value, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| value={currentTypography.lineHeight || ''} | ||
| /> | ||
| </FlexItem> | ||
| </Flex> | ||
|
|
||
| <Flex style={{ gap: '16px' }}> | ||
| <FlexItem isBlock> | ||
| <UnitControl | ||
| label={__('Letter spacing', 'block-responsive')} | ||
| __next40pxDefaultSize | ||
| onChange={(value) => { | ||
| setAttributes({ | ||
| typographyControls: { | ||
| ...typographyControls, | ||
| [device]: { | ||
| ...typographyControls[device], | ||
| letterSpacing: value, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| value={currentTypography.letterSpacing || ''} | ||
| /> | ||
| </FlexItem> | ||
| <FlexItem isBlock> | ||
| <ToggleGroupControl | ||
| isDeselectable | ||
| label={__('Decoration', 'block-responsive')} | ||
| value={currentTypography.textDecoration || ''} | ||
| onChange={(value) => { | ||
| setAttributes({ | ||
| typographyControls: { | ||
| ...typographyControls, | ||
| [device]: { | ||
| ...typographyControls[device], | ||
| textDecoration: value, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| __next40pxDefaultSize | ||
| __nextHasNoMarginBottom | ||
| > | ||
| <ToggleGroupControlOptionIcon | ||
| value="none" | ||
| label={__('None', 'block-responsive')} | ||
| icon={lineSolid} | ||
| /> | ||
| <ToggleGroupControlOptionIcon | ||
| value="underline" | ||
| label={__('Underline', 'block-responsive')} | ||
| icon={formatUnderline} | ||
| /> | ||
| <ToggleGroupControlOptionIcon | ||
| value="line-through" | ||
| label={__('Strikethrough', 'block-responsive')} | ||
| icon={formatStrikethrough} | ||
| /> | ||
| </ToggleGroupControl> | ||
| </FlexItem> | ||
| </Flex> | ||
|
|
||
| <ToggleGroupControl | ||
| isDeselectable | ||
| label={__('Letter case', 'block-responsive')} | ||
| value={currentTypography.textTransform || ''} | ||
| onChange={(value) => { | ||
| setAttributes({ | ||
| typographyControls: { | ||
| ...typographyControls, | ||
| [device]: { | ||
| ...typographyControls[device], | ||
| textTransform: value, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| __next40pxDefaultSize | ||
| __nextHasNoMarginBottom | ||
| > | ||
| <ToggleGroupControlOptionIcon | ||
| value="none" | ||
| label={__('None', 'block-responsive')} | ||
| icon={lineSolid} | ||
| /> | ||
| <ToggleGroupControlOptionIcon | ||
| value="uppercase" | ||
| label={__('Uppercase', 'block-responsive')} | ||
| icon={formatUppercase} | ||
| /> | ||
| <ToggleGroupControlOptionIcon | ||
| value="lowercase" | ||
| label={__('Lowercase', 'block-responsive')} | ||
| icon={formatLowercase} | ||
| /> | ||
| <ToggleGroupControlOptionIcon | ||
| value="capitalize" | ||
| label={__('Capitalize', 'block-responsive')} | ||
| icon={formatCapitalize} | ||
| /> | ||
| </ToggleGroupControl> | ||
| </div> | ||
| <Button | ||
| __next40pxDefaultSize | ||
| variant="secondary" | ||
| isDestructive | ||
| text={__('Reset All', 'block-responsive')} | ||
| style={{ | ||
| width: '100%', | ||
| justifyContent: 'center', | ||
| marginTop: '16px', | ||
| }} | ||
| onClick={() => { | ||
| setAttributes({ | ||
| typographyControls: { | ||
| ...typographyControls, | ||
| [device]: { | ||
| ...currentTypography, | ||
| fontFamily: null, | ||
| fontSize: null, | ||
| fontAppearance: null, | ||
| lineHeight: null, | ||
| letterSpacing: null, | ||
| textDecoration: null, | ||
| textTransform: null, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| /> | ||
| </> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent text domain throughout the file.
The component uses 'block-responsive' as the text domain across all localized strings, but should use 'wedocs' to match the plugin's text domain.
Lines affected: 71, 73, 82, 150, 169, 187-188, 192-193, 197-198, 206, 224-225, 229-230, 234-235, 239-240, 248.
Apply this pattern to all __() calls:
- label={__('Font', 'block-responsive')}
+ label={__('Font', 'wedocs')}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { __ } from '@wordpress/i18n'; | |
| import { | |
| __experimentalFontFamilyControl as FontFamilyControl, | |
| LineHeightControl, | |
| useSetting, | |
| useSettings, | |
| FontSizePicker, | |
| __experimentalFontAppearanceControl as FontAppearanceControl, | |
| } from '@wordpress/block-editor'; | |
| import { | |
| Flex, | |
| FlexItem, | |
| Button, | |
| __experimentalUnitControl as UnitControl, | |
| __experimentalToggleGroupControl as ToggleGroupControl, | |
| __experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon, | |
| SelectControl, | |
| } from '@wordpress/components'; | |
| import { | |
| lineSolid, | |
| formatUnderline, | |
| formatStrikethrough, | |
| formatUppercase, | |
| formatLowercase, | |
| formatCapitalize, | |
| } from '@wordpress/icons'; | |
| const TypographyControls = ({ attributes, setAttributes, device }) => { | |
| const { typographyControls } = attributes; | |
| const currentTypography = typographyControls[device] || {}; | |
| const fontSizes = useSetting('typography.fontSizes'); | |
| const fontFamilies = useSettings('typography.fontFamilies'); | |
| // Combine both theme and custom fonts | |
| const themeFonts = fontFamilies[0]?.theme || []; | |
| const customFonts = fontFamilies[0]?.custom || []; | |
| const validFontFamilies = [...themeFonts, ...customFonts]; | |
| return ( | |
| <> | |
| <div | |
| style={{ | |
| display: 'flex', | |
| flexDirection: 'column', | |
| gap: '16px', | |
| }} | |
| > | |
| {validFontFamilies.length > 0 ? ( | |
| <FontFamilyControl | |
| __next40pxDefaultSize | |
| __nextHasNoMarginBottom | |
| fontFamilies={validFontFamilies} | |
| onChange={(value) => { | |
| setAttributes({ | |
| typographyControls: { | |
| ...typographyControls, | |
| [device]: { | |
| ...typographyControls[device], | |
| fontFamily: value, | |
| }, | |
| }, | |
| }); | |
| }} | |
| value={currentTypography.fontFamily || ''} | |
| /> | |
| ) : ( | |
| <div className="block-responsive-font-control-disabled"> | |
| <SelectControl | |
| __next40pxDefaultSize | |
| __nextHasNoMarginBottom | |
| label={__('Font', 'block-responsive')} | |
| help={__( | |
| 'Not supported in classic themes.', | |
| 'block-responsive' | |
| )} | |
| value={'default'} | |
| onChange={() => {}} | |
| disabled | |
| options={[ | |
| { | |
| disabled: true, | |
| label: __('Default', 'block-responsive'), | |
| value: 'default', | |
| }, | |
| ]} | |
| /> | |
| </div> | |
| )} | |
| <FontSizePicker | |
| __next40pxDefaultSize | |
| fontSizes={fontSizes} | |
| onChange={(value) => { | |
| setAttributes({ | |
| typographyControls: { | |
| ...typographyControls, | |
| [device]: { | |
| ...typographyControls[device], | |
| fontSize: value, | |
| }, | |
| }, | |
| }); | |
| }} | |
| value={currentTypography.fontSize || ''} | |
| withSlider | |
| withReset={false} | |
| /> | |
| <Flex style={{ gap: '16px' }}> | |
| <FlexItem isBlock> | |
| <FontAppearanceControl | |
| __next40pxDefaultSize | |
| onChange={(value) => { | |
| setAttributes({ | |
| typographyControls: { | |
| ...typographyControls, | |
| [device]: { | |
| ...typographyControls[device], | |
| fontAppearance: value, | |
| }, | |
| }, | |
| }); | |
| }} | |
| value={currentTypography.fontAppearance || ''} | |
| /> | |
| </FlexItem> | |
| <FlexItem isBlock> | |
| <LineHeightControl | |
| __next40pxDefaultSize | |
| __unstableInputWidth="auto" | |
| onChange={(value) => { | |
| setAttributes({ | |
| typographyControls: { | |
| ...typographyControls, | |
| [device]: { | |
| ...typographyControls[device], | |
| lineHeight: value, | |
| }, | |
| }, | |
| }); | |
| }} | |
| value={currentTypography.lineHeight || ''} | |
| /> | |
| </FlexItem> | |
| </Flex> | |
| <Flex style={{ gap: '16px' }}> | |
| <FlexItem isBlock> | |
| <UnitControl | |
| label={__('Letter spacing', 'block-responsive')} | |
| __next40pxDefaultSize | |
| onChange={(value) => { | |
| setAttributes({ | |
| typographyControls: { | |
| ...typographyControls, | |
| [device]: { | |
| ...typographyControls[device], | |
| letterSpacing: value, | |
| }, | |
| }, | |
| }); | |
| }} | |
| value={currentTypography.letterSpacing || ''} | |
| /> | |
| </FlexItem> | |
| <FlexItem isBlock> | |
| <ToggleGroupControl | |
| isDeselectable | |
| label={__('Decoration', 'block-responsive')} | |
| value={currentTypography.textDecoration || ''} | |
| onChange={(value) => { | |
| setAttributes({ | |
| typographyControls: { | |
| ...typographyControls, | |
| [device]: { | |
| ...typographyControls[device], | |
| textDecoration: value, | |
| }, | |
| }, | |
| }); | |
| }} | |
| __next40pxDefaultSize | |
| __nextHasNoMarginBottom | |
| > | |
| <ToggleGroupControlOptionIcon | |
| value="none" | |
| label={__('None', 'block-responsive')} | |
| icon={lineSolid} | |
| /> | |
| <ToggleGroupControlOptionIcon | |
| value="underline" | |
| label={__('Underline', 'block-responsive')} | |
| icon={formatUnderline} | |
| /> | |
| <ToggleGroupControlOptionIcon | |
| value="line-through" | |
| label={__('Strikethrough', 'block-responsive')} | |
| icon={formatStrikethrough} | |
| /> | |
| </ToggleGroupControl> | |
| </FlexItem> | |
| </Flex> | |
| <ToggleGroupControl | |
| isDeselectable | |
| label={__('Letter case', 'block-responsive')} | |
| value={currentTypography.textTransform || ''} | |
| onChange={(value) => { | |
| setAttributes({ | |
| typographyControls: { | |
| ...typographyControls, | |
| [device]: { | |
| ...typographyControls[device], | |
| textTransform: value, | |
| }, | |
| }, | |
| }); | |
| }} | |
| __next40pxDefaultSize | |
| __nextHasNoMarginBottom | |
| > | |
| <ToggleGroupControlOptionIcon | |
| value="none" | |
| label={__('None', 'block-responsive')} | |
| icon={lineSolid} | |
| /> | |
| <ToggleGroupControlOptionIcon | |
| value="uppercase" | |
| label={__('Uppercase', 'block-responsive')} | |
| icon={formatUppercase} | |
| /> | |
| <ToggleGroupControlOptionIcon | |
| value="lowercase" | |
| label={__('Lowercase', 'block-responsive')} | |
| icon={formatLowercase} | |
| /> | |
| <ToggleGroupControlOptionIcon | |
| value="capitalize" | |
| label={__('Capitalize', 'block-responsive')} | |
| icon={formatCapitalize} | |
| /> | |
| </ToggleGroupControl> | |
| </div> | |
| <Button | |
| __next40pxDefaultSize | |
| variant="secondary" | |
| isDestructive | |
| text={__('Reset All', 'block-responsive')} | |
| style={{ | |
| width: '100%', | |
| justifyContent: 'center', | |
| marginTop: '16px', | |
| }} | |
| onClick={() => { | |
| setAttributes({ | |
| typographyControls: { | |
| ...typographyControls, | |
| [device]: { | |
| ...currentTypography, | |
| fontFamily: null, | |
| fontSize: null, | |
| fontAppearance: null, | |
| lineHeight: null, | |
| letterSpacing: null, | |
| textDecoration: null, | |
| textTransform: null, | |
| }, | |
| }, | |
| }); | |
| }} | |
| /> | |
| </> | |
| ); | |
| }; | |
| <div className="block-responsive-font-control-disabled"> | |
| <SelectControl | |
| __next40pxDefaultSize | |
| __nextHasNoMarginBottom | |
| label={__( 'Font', 'wedocs' )} | |
| help={__( | |
| 'Not supported in classic themes.', | |
| 'block-responsive' | |
| )} | |
| value={'default'} | |
| onChange={() => {}} | |
| disabled | |
| options={[ | |
| { | |
| disabled: true, | |
| label={__( 'Default', 'wedocs' )} | |
| value: 'default', | |
| }, | |
| ]} | |
| /> | |
| </div> |
fixes #162
User Story
As a site admin, I want to add a Sidebar block to my documentation pages so that I can display selected docs, sections, and docs with customizable order and layout, making navigation easier for users.
Description
Introduce a "Sidebar" Gutenberg block in weDocs. The block should allow selecting ocsd, including/excluding categories, defining order, and customizing layout.
Developers can follow the default Gutenberg block handbook for implementation standards and coding best practices.
Summary by CodeRabbit