Repository navigation
feat: artisanpack/copyright + marquee + comments-number site-chrome blocks - #571
Conversation
…me blocks
Adds three site-wide chrome blocks under the artisanpack namespace:
- copyright (dynamic) — © + configurable text + current year, with three
display modes (icon-text / icon-only / text-only). Year is read at
render time on every renderer so the line stays accurate without a
rebuild.
- marquee (static) — RichText body wrapped in a sized `<div>`. The
renderers emit an inline `animation: ap-marquee-scroll Ns linear
infinite` declaration that drives the keyframe shipped in the new
`frontend/marquee.css` asset; the editor preview drops the animation
so authors can edit the text without it scrolling under their cursor.
- comments-number (dynamic) — `<count> <singular|plural>` line.
PostResolver stamps `_resolvedCommentCount` (reusing the existing
branch shared with post-comments-count), and the renderers pick the
singular or plural label by count.
Wires the marquee front-end stylesheet through `<x-ve-blocks-styles />`
(new `marqueeStyleHref` + `data-ve-marquee` link tag) so consumers ship
the keyframes alongside the existing accordion / tabs / grid bundles.
Closes #500
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (8)
🚧 Files skipped from review as they are similar to previous changes (5)
📝 WalkthroughWalkthroughAdds three artisanpack site-chrome blocks (copyright, marquee, comments-number) with Gutenberg metadata and editor UI, Blade/React/Vue renderers, marquee CSS and canvas integration, server-side comment-count stamping, and tests across renderer and editor targets. ChangesSite-Chrome Block Fork (CW4)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
resources/js/visual-editor/blocks/__tests__/site-chrome-family.test.ts (1)
70-79: ⚡ Quick winAssert the full
comments-numbercontext contract (postId+postType).This test currently verifies only
postId, so a future removal ofpostTypewould pass unnoticed even though the block schema contract includes both.Suggested patch
it('comments-number declares singular + plural labels and the postId context', () => { const attrs = (commentsNumberMeta as { attributes?: Record<string, { default?: unknown }> }) .attributes; expect(attrs?.singularCommentText?.default).toBe('Comment'); expect(attrs?.pluralCommentText?.default).toBe('Comments'); const usesContext = (commentsNumberMeta as { usesContext?: ReadonlyArray<string> }) .usesContext; expect(usesContext).toContain('postId'); + expect(usesContext).toContain('postType'); });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@resources/js/visual-editor/blocks/__tests__/site-chrome-family.test.ts` around lines 70 - 79, The test only asserts that commentsNumberMeta.usesContext contains 'postId' but should assert the full context contract includes both 'postId' and 'postType'; update the test (referencing commentsNumberMeta and usesContext) to either expect usesContext toContain 'postType' as well or toEqual/contain the exact array of required context keys so removal of 'postType' will fail the test.resources/js/visual-editor/blocks/marquee/edit.tsx (1)
35-47: ⚡ Quick winExtract shared clamping helpers to avoid edit/save drift.
Line 35 and Line 42 duplicate clamping behavior also implemented in
resources/js/visual-editor/blocks/marquee/save.tsx. Centralizing these helpers reduces parity regressions when ranges/defaults change.Proposed refactor
+// resources/js/visual-editor/blocks/marquee/clamp.ts +export function clampPercent(value: number | null | undefined, fallback: number): number { + if (typeof value !== 'number' || !Number.isFinite(value)) { + return fallback; + } + return Math.min(100, Math.max(1, Math.round(value))); +} + +export function clampSpeed(value: number | null | undefined, fallback: number): number { + if (typeof value !== 'number' || !Number.isFinite(value)) { + return fallback; + } + return Math.min(100, Math.max(1, Math.round(value))); +}- function clampPercent(value: number | null | undefined, fallback: number): number { - ... - } - - function clampSpeed(value: number | null | undefined, fallback: number): number { - ... - } +import { clampPercent, clampSpeed } from './clamp';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@resources/js/visual-editor/blocks/marquee/edit.tsx` around lines 35 - 47, The clampPercent and clampSpeed functions in edit.tsx duplicate logic also present in resources/js/visual-editor/blocks/marquee/save.tsx; extract a single shared helper (e.g., export clampNumber or clampPercent/clampSpeed) into a common module (like resources/js/visual-editor/blocks/marquee/utils.ts or a shared utils file), update edit.tsx to import and use the shared clamp helper(s) instead of its local implementations (referencing the existing function names clampPercent and clampSpeed to find the code), and update save.tsx to import the same shared helper so both edit and save use identical clamping logic and defaults.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/visual-editor-renderer-blade/resources/assets/frontend/marquee.css`:
- Around line 20-34: The marquee currently forces continuous motion via
.ap-marquee__text and `@keyframes` ap-marquee-scroll; add a prefers-reduced-motion
override so users who opt out of animations don’t get forced continuous motion —
e.g. add an `@media` (prefers-reduced-motion: reduce) block that targets
.ap-marquee__text (and any element that applies the animation) to disable the
animation (animation: none or animation-play-state: paused) and reset transform
to a static value (e.g., transform: none) so the marquee is not animated for
reduced-motion users.
In `@packages/visual-editor-renderer-react/src/blocks/artisanpack/marquee.tsx`:
- Around line 25-40: The value coming from attrString(attributes.marqueeContent)
is injected raw via dangerouslySetInnerHTML; replace that with a sanitized
version: call the project’s shared HTML sanitizer (or import a lightweight
sanitizer like DOMPurify/sanitizeHtml) immediately after const content =
attrString(attributes.marqueeContent) to produce e.g. sanitizedContent, and pass
sanitizedContent into dangerouslySetInnerHTML instead of content; similarly
ensure the same sanitization is applied at the renderer boundary for the Vue
(innerHTML: content) and Blade ({!! $content !!}) renderers so hostile
markup/event handlers are stripped before rendering.
In `@packages/visual-editor-renderer-react/tests/BlockTree.test.tsx`:
- Around line 696-742: Freeze system time in the failing copyright tests by
using Vitest fake timers: call vi.useFakeTimers() and vi.setSystemTime(...) with
a fixed Date before you compute year and call renderTree (use the same fixed
Date to derive year), then restore timers (vi.useRealTimers()) after the test;
update the three test cases that use new Date().getUTCFullYear() (the tests
invoking renderTree and makeBlock for 'artisanpack/copyright') to set the fake
time, compute year from the pinned date, run assertions, and tear down the fake
timers.
In `@packages/visual-editor-renderer-vue/tests/BlockTree.test.ts`:
- Around line 695-741: These year-dependent specs (the it blocks that call
renderTree/makeBlock and assert on `new Date().getUTCFullYear()`) should freeze
the clock during the test run: in the test suite setup for these specs call your
test runner's fake timer/system time API (e.g. jest.useFakeTimers +
jest.setSystemTime with a fixed UTC Date) before the tests that render via
renderTree, and restore real time after (jest.useRealTimers or
jest.resetAllMocks) so the year assertions are deterministic; add this
setup/teardown in the same describe or beforeAll/afterAll that contains the
renderTree/makeBlock tests.
---
Nitpick comments:
In `@resources/js/visual-editor/blocks/__tests__/site-chrome-family.test.ts`:
- Around line 70-79: The test only asserts that commentsNumberMeta.usesContext
contains 'postId' but should assert the full context contract includes both
'postId' and 'postType'; update the test (referencing commentsNumberMeta and
usesContext) to either expect usesContext toContain 'postType' as well or
toEqual/contain the exact array of required context keys so removal of
'postType' will fail the test.
In `@resources/js/visual-editor/blocks/marquee/edit.tsx`:
- Around line 35-47: The clampPercent and clampSpeed functions in edit.tsx
duplicate logic also present in
resources/js/visual-editor/blocks/marquee/save.tsx; extract a single shared
helper (e.g., export clampNumber or clampPercent/clampSpeed) into a common
module (like resources/js/visual-editor/blocks/marquee/utils.ts or a shared
utils file), update edit.tsx to import and use the shared clamp helper(s)
instead of its local implementations (referencing the existing function names
clampPercent and clampSpeed to find the code), and update save.tsx to import the
same shared helper so both edit and save use identical clamping logic and
defaults.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3b3f54a6-2cbf-4a77-ae3e-047a43149098
📒 Files selected for processing (40)
packages/renderer-parity.jsonpackages/visual-editor-renderer-blade/resources/assets/frontend/marquee.csspackages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/comments-number.blade.phppackages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/copyright.blade.phppackages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/marquee.blade.phppackages/visual-editor-renderer-blade/resources/views/components/blocks-styles.blade.phppackages/visual-editor-renderer-blade/src/View/Components/BlocksStylesComponent.phppackages/visual-editor-renderer-blade/tests/Feature/BlocksStylesComponentTest.phppackages/visual-editor-renderer-blade/tests/Unit/BlockRendererTest.phppackages/visual-editor-renderer-react/src/blocks/artisanpack/commentsNumber.tsxpackages/visual-editor-renderer-react/src/blocks/artisanpack/copyright.tsxpackages/visual-editor-renderer-react/src/blocks/artisanpack/marquee.tsxpackages/visual-editor-renderer-react/src/blocks/registerCoreBlocks.tspackages/visual-editor-renderer-react/tests/BlockTree.test.tsxpackages/visual-editor-renderer-vue/src/blocks/artisanpack/commentsNumber.tspackages/visual-editor-renderer-vue/src/blocks/artisanpack/copyright.tspackages/visual-editor-renderer-vue/src/blocks/artisanpack/marquee.tspackages/visual-editor-renderer-vue/src/blocks/registerCoreBlocks.tspackages/visual-editor-renderer-vue/tests/BlockTree.test.tsresources/js/visual-editor/blocks/__tests__/site-chrome-family.test.tsresources/js/visual-editor/blocks/comments-number/block.jsonresources/js/visual-editor/blocks/comments-number/edit.tsxresources/js/visual-editor/blocks/comments-number/index.tsresources/js/visual-editor/blocks/comments-number/inserter-icon.tsxresources/js/visual-editor/blocks/comments-number/save.tsxresources/js/visual-editor/blocks/copyright/block.jsonresources/js/visual-editor/blocks/copyright/edit.tsxresources/js/visual-editor/blocks/copyright/index.tsresources/js/visual-editor/blocks/copyright/inserter-icon.tsxresources/js/visual-editor/blocks/copyright/save.tsxresources/js/visual-editor/blocks/marquee/block.jsonresources/js/visual-editor/blocks/marquee/edit.tsxresources/js/visual-editor/blocks/marquee/index.tsresources/js/visual-editor/blocks/marquee/inserter-icon.tsxresources/js/visual-editor/blocks/marquee/marquee.cssresources/js/visual-editor/blocks/marquee/save.tsxresources/js/visual-editor/editor/__tests__/canvas-styles.test.tsresources/js/visual-editor/editor/canvas-styles.tssrc/Resources/PostResolver.phptests/Unit/VisualEditor/Resources/PostResolverTest.php
- Honor prefers-reduced-motion on the marquee animation in both the editor preview and the published frontend stylesheet — the keyframe is suppressed and the off-screen transform is reset so opted-out visitors see static text instead of an endless scroll. - Extract the marquee width / speed clamp helpers into a shared `clamp.ts` module so edit.tsx and save.tsx can't drift in their validation ranges or defaults. - Freeze the system clock with `vi.useFakeTimers()` in the React + Vue copyright renderer specs so the year assertions stay deterministic across a Dec 31 → Jan 1 boundary. - Assert both `postId` AND `postType` in the comments-number usesContext contract test so a future removal of `postType` trips the suite.
58227d7
into
feature/495-port-crosswinds-blocks
Description
Adds three site-wide chrome blocks under the
artisanpack/*namespace:artisanpack/copyright(dynamic) —©+ configurable text + current year, with three display modes (icon-text/icon-only/text-only). Year is read at render time on every renderer so the line stays accurate without a rebuild.artisanpack/marquee(static) — RichText body wrapped in a sized<div>. The renderers emit an inlineanimation: ap-marquee-scroll Ns linear infinitedeclaration that drives the keyframe shipped in the newfrontend/marquee.cssasset; the editor preview drops the animation so authors can edit the text without it scrolling under their cursor.artisanpack/comments-number(dynamic) —<count> <singular|plural>line.PostResolverstamps_resolvedCommentCount(reusing the existing branch shared withpost-comments-count), and the renderers pick the singular or plural label by count.Closes: #500
Type of Change
Related Issue
Issue: #500
Motivation and Context
Site-chrome cluster of the umbrella block-port effort (#495). Each block ships under the
artisanpack/*namespace with full Blade + React + Vue renderer parity. None of the three upstream blocks carried transforms, so none are added here.Changes Made
resources/js/visual-editor/blocks/{copyright,marquee,comments-number}/(block.json, edit.tsx, save.tsx, index.ts, inserter-icon.tsx; marquee addsmarquee.css).packages/visual-editor-renderer-blade/resources/views/blocks/artisanpack/.packages/visual-editor-renderer-react/src/blocks/artisanpack/(copyright.tsx,marquee.tsx,commentsNumber.tsx) wired intoregisterCoreBlocks.packages/visual-editor-renderer-vue/src/blocks/artisanpack/wired intoregisterCoreBlocks.PostResolvernow listsartisanpack/comments-numberinSUPPORTED_BLOCKSand routes it throughresolveCommentsCount()alongsidepost-comments-count.frontend/marquee.cssships through<x-ve-blocks-styles />(newmarqueeStyleHref+data-ve-marqueelink tag), so consumers ship the keyframes alongside the existing accordion / tabs / grid bundles.canvas-styles.tsimports the marquee stylesheet into the editor iframe and adds a small.ap-marquee__text { transform: none; white-space: normal }override so the editor renders the text statically.renderer-parity.jsonextended with the three new block names; the parity verifier confirms all 140 blocks register in all three renderers.How Has This Been Tested?
Testing Environment:
feature/500-site-chrome-blocksofffeature/495-port-crosswinds-blocksTests Performed:
npx vitest run— 1972 tests pass (added 9 tosite-chrome-family.test.ts+ 9 React + 9 Vue renderer tests)../vendor/bin/pest— 1062 tests pass (added 8 Blade renderer tests + 2 PostResolver stamping tests + 1 BlocksStyles emission test; 2 unrelated pre-existing FA Icons failures remain on this branch's parent commit).node scripts/verify-renderer-parity.mjs— all 140 blocks registered across blade / react / vue.npm run build— Vite build succeeds.vendor:publish --tag=visual-editor-renderer-blade-assets.Accessibility Tests Run
Details: Marquee is decorative chrome; the inline animation is the only motion concern and the keyframe ships in a separate stylesheet so prefers-reduced-motion can be layered on top later. Comments number and copyright are plain
<p>text.Tests Added
Test details: 9 family-contract tests, 18 renderer tests (9 React + 9 Vue), 8 Blade renderer tests, 2 PostResolver stamping tests, 1 BlocksStyles emission test.
Documentation
Documentation details: Each new file ships a brief docblock describing its role and the contract with the sibling renderers.
Pre-Submission Checklist
🤖 Generated with Claude Code
Summary by CodeRabbit