Skip to content

v0.6.25: Add .sf-bg layer, overflow-fade variants, button/card components - #94

Merged
jackgranatowski merged 11 commits into
mainfrom
claude/frontend-panel-layout-settings-hsjg3r
Jun 29, 2026
Merged

v0.6.25: Add .sf-bg layer, overflow-fade variants, button/card components#94
jackgranatowski merged 11 commits into
mainfrom
claude/frontend-panel-layout-settings-hsjg3r

Conversation

@jackgranatowski

@jackgranatowski jackgranatowski commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

This release adds three major component systems to the SLASHED framework:

  1. Background layer (.sf-bg): A new absolutely-positioned cover media component that sits behind parent content. Supports bare <img> or wrapper with nested <img>/<video>/<picture>. Auto-promotes parent to positioned, isolated stacking context via :has(), composing natively under .sf-scrim.

  2. Overflow fade variants: Extends .sf-overflow-fade with directional modifiers (--left, --right, --top, --bottom, --block, --inline) using mask gradients. Replaces hardcoded --sf-scroll-shadow-size references with --sf-mask-scrim-start and --sf-mask-scrim-end tokens for consistency.

  3. Button and card components: Staged (commented) component definitions for .sf-btn (with style/semantic/width variants and loading state) and .sf-card (with media, avatar, title subcomponents). Includes form layout helpers (.sf-field, .sf-form-row, .sf-form-col, .sf-form-inline) and table component tokens.

Admin app improvements:

  • Enhanced SliderRow component with raw CSS expression mode for modular-scale source tokens
  • Modular-scale derived-token computation in TypeScript mirrors CSS framework formula for accurate live preview
  • PHP CSS generator skips legacy hardcoded clamp declarations when source tokens are present
  • Mobile-responsive overlay panel (full overlay on mobile, push-left on desktop)
  • Updated radius scale defaults in BordersPanel to match framework v0.6.25

Framework version: Updated to v0.6.25

Type

  • feat
  • fix
  • docs
  • chore / tooling

Checklist

  • Conventional Commit messages
  • npm test passes
  • npm run lint passes
  • npm run verify passes
  • Generated artifacts not hand-edited
  • CHANGELOG.md updated
  • Built SPA assets committed

Notes

All component definitions are staged (commented out) pending v0.8 release. The .sf-bg layer and overflow-fade variants are production-ready. Raw CSS expression mode in the admin app enables power users to reference framework tokens directly (e.g., var(--sf-container-default)) in the live preview.

https://claude.ai/code/session_01R5nboHaQC81NxMpVfaktdf

Summary by CodeRabbit

  • New Features

    • Added support for editing raw CSS values in multiple style controls, alongside the existing slider inputs.
    • Improved the live preview with computed modular-scale text and spacing values.
    • Added new background-layer styling options for media placed behind content.
  • Bug Fixes

    • Better preserves ignored files during sync operations.
    • Improved overlay behavior on desktop and mobile, including more reliable panel positioning.
    • Made style overrides more resilient when values use CSS expressions.

claude added 2 commits June 29, 2026 10:01
Panel layout (desktop/mobile):
- Inject sf-panel-push stylesheet into document.head on mount; use
  html.sf-panel-active { padding-right: 420px; box-sizing: border-box }
  so the page shrinks beside the panel even when themes set overflow-x:hidden
- Toggle sf-panel-active class via $effect (add on desktop+open, remove otherwise)
- Detect mobile (≤768px) via MediaQueryList; on mobile the panel is a
  full-width overlay instead of pushing content
- Position panel/trigger relative to --wp-admin--admin-bar--height CSS var

Modular scale live preview (JS + PHP):
- persistence.ts: computeScaleTokens() pre-computes all derived text/space
  clamp tokens using the same pow() formula as the CSS framework; derived
  tokens are injected as unlayered CSS so they beat @layer slashed.overrides
  hardcoded values from legacy WP settings
- class-css-generator.php: flat_has_any() detects when scale source tokens
  are saved as flat overrides; generate_typography_declarations() and
  generate_spacing_declarations() skip emitting per-size hardcoded clamp
  values in that case, letting the framework's CSS compute them instead

Sync script fix:
- sync-core.mjs local mode now preserves syncignored files before wiping
  src/ (mirrors GitHub API mode behaviour); previously App.svelte,
  AppOverlay.svelte, persistence.ts etc. were deleted on every build

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R5nboHaQC81NxMpVfaktdf
Update vendored slashed.full.css bundle and sync panel component
changes for SliderRow, BordersPanel, LayoutPanel, and SpacingPanel
that were present on this branch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R5nboHaQC81NxMpVfaktdf
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jackgranatowski, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 054e814a-f761-4164-86bd-dbdc4759ae8d

📥 Commits

Reviewing files that changed from the base of the PR and between cd3166d and 2b21ae7.

📒 Files selected for processing (5)
  • SLASHED-for-WP/admin-app/framework-css/badges/slashed.full.css
  • SLASHED-for-WP/admin-app/scripts/sync-core.mjs
  • SLASHED-for-WP/admin-app/src/AppOverlay.svelte
  • SLASHED-for-WP/admin-app/src/components/panels/BordersPanel.svelte
  • SLASHED-for-WP/includes/class-css-generator.php
📝 Walkthrough

Walkthrough

Adds raw CSS expression editing to SliderRow and wires it across BordersPanel, LayoutPanel, and SpacingPanel. Introduces client-side modular-scale token derivation in persistence.ts and suppresses legacy PHP clamp generation when source tokens are active. Updates AppOverlay with mobile detection and CSS-class-based panel push. Hardens sync-core.mjs file preservation across src/ wipes. Bundles SLASHED CSS v0.6.25 with .sf-bg and refreshed overflow-fade tokens.

Changes

Raw CSS Token Editing, Modular-Scale Derivation, and PHP Clamp Suppression

Layer / File(s) Summary
SliderRow raw-edit props and UI
admin-app/src/components/inputs/SliderRow.svelte
label made optional; rawDefault, currentRaw, onRawSet props added. Internal state tracks draft text and editing flag; an auto-raw regex detects CSS expressions. UI conditionally renders a text input in raw mode or the existing RangeWithNumber slider with a "default: …" hint.
Panel wiring of raw CSS props
admin-app/src/components/panels/BordersPanel.svelte, LayoutPanel.svelte, SpacingPanel.svelte
BordersPanel updates BASE_RADII/RADIUS_FINE/COMPONENT_TOKENS constants, adds CSS-expression guards in getRadiusValue/getComponentVal, and passes rawDefault/currentRaw/onRawSet to divider, radius, and component sliders. LayoutPanel and SpacingPanel wire the same three props to their SliderRow instances for all affected tokens.
Client-side modular-scale token computation
admin-app/src/lib/persistence.ts
Adds computeScaleTokens with fluidClamp math to derive --sf-text-* and --sf-space-* from source overrides. injectLivePreview merges derived tokens before encoding the :root preview. wpSave constructs the endpoint via new URL(...) and enforces a same-origin check.
PHP: suppress legacy clamp output when source tokens present
includes/class-css-generator.php
New flat_has_any() helper detects modular-scale source keys. get_override_css() computes $skip_text_sizes/$skip_space_sizes and passes them into generate_typography_declarations() and generate_spacing_declarations(), which conditionally omit per-size clamp emissions.

AppOverlay Mobile-Responsive Behavior

Layer / File(s) Summary
Mobile detection, class toggle, injected stylesheet, and positioning
admin-app/src/AppOverlay.svelte
isMobile state from matchMedia; effect replaces document.body.style.marginRight with sf-panel-active class toggle on document.documentElement. onMount injects an sf-panel-push stylesheet and registers a media listener; cleanup removes both. Trigger and panel top/width/height use --wp-admin--admin-bar--height and isMobile.

sync-core Preservation, Header Relocation, and Framework CSS

Layer / File(s) Summary
sync-core: preserve syncignored files during src/ wipe
admin-app/scripts/sync-core.mjs
fs import extended with openSync, fstatSync, closeSync. Both local and GitHub remote branches now resolve ignored paths under SRC_ROOT, validate as files via fstatSync, read and buffer content, wipe SRC, recreate directories, then restore files.
StudioHeader: relocate Save button in toolbar
admin-app/src/components/shell/StudioHeader.svelte
Save button block (with saving/saved icon states) moved to an earlier position in the header control row; the prior end-of-row placement is removed.
Bundled SLASHED CSS v0.6.25
admin-app/framework-css/badges/slashed.full.css
Version bump to v0.6.25; adds --sf-bg-* tokens and .sf-bg background-layer implementation with :where(:has(> .sf-bg)) parent rule; refreshes .sf-overflow-fade mask-image gradients to use --sf-mask-scrim-start/--sf-mask-scrim-end; expands commented component token docs (--sf-btn-*, smart-card, form layout, table).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • Components: second batch SLASHED#384: The PR renames button token documentation from --sf-button-* to --sf-btn-* in the CSS bundle and updates COMPONENT_TOKENS in BordersPanel.svelte to use --sf-btn-* token names, directly touching the component-token surface described in this issue.

Possibly related PRs

  • codeslash-dev/SLASHED-Plugins#27: Both PRs modify admin-app/scripts/sync-core.mjs to preserve .syncignore-listed files during src/ wipes.
  • codeslash-dev/SLASHED-Plugins#86: Both PRs modify admin-app/src/AppOverlay.svelte—the prior PR introduces the overlay; this PR adds mobile detection and CSS-class-based panel push.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main framework update: v0.6.25 with the new .sf-bg layer, overflow-fade variants, and staged button/card components.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/frontend-panel-layout-settings-hsjg3r

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…PCS array formatting

- StudioHeader.svelte (plugin): reorder toolbar so Save comes first, then
  Undo/Redo, then the secondary actions (Share, Import, Reset) — matches
  the layout in the framework configurator and AppOverlay
- class-css-generator.php: put each array item on its own line to satisfy
  WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine (PHPCS error)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R5nboHaQC81NxMpVfaktdf
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Release v0.6.25: add .sf-bg layer, overflow-fade variants, and admin token UX fixes
✨ Enhancement 🐞 Bug fix ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

Description

• Add .sf-bg cover-media background layer and directional .sf-overflow-fade variants.
• Improve admin overlay UX: desktop push layout, mobile full overlay, admin-bar-safe positioning.
• Add raw CSS override mode and modular-scale derived-token preview; avoid legacy clamp shadowing.
Diagram

graph TD
  U["User"] --> AO["AppOverlay"] --> SR["SliderRow"] --> PTS["persistence.ts"] --> PREV["Live preview CSS"] --> DOC["Document <head>"]
  AO --> PUSH["Panel push CSS"] --> DOC
  PTS --> APPJS["assets/admin-app/app.js"]
  AO --> APPJS
  SR --> APPJS
  APPJS --> APPCSS["assets/admin-app/app.css"]
  PHP["class-css-generator.php"] --> OV["WP override CSS"] --> FW["slashed.full.css"]
  FW --> SITE["Site styling"]
  OV --> SITE
  subgraph Legend
    direction LR
    _ui["UI component"] ~~~ _gen["Generated asset"] ~~~ _srv["Server-side generator"]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Compute modular-scale outputs only in CSS (no JS derived tokens)
  • ➕ Single source of truth for token math
  • ➕ No extra JS injected CSS payload
  • ➖ Cannot reliably beat legacy @layer overrides without changing server output
  • ➖ Live preview remains incorrect when legacy hardcoded clamps are present
2. Store raw CSS overrides separately from numeric overrides
  • ➕ Avoids parsing/guard logic when a token is an expression
  • ➕ Cleaner typing: numeric sliders vs string expressions
  • ➖ Requires schema/versioning changes in persistence + WP storage
  • ➖ More migration complexity for existing overrides
3. Build admin assets in CI instead of committing app.js/app.css
  • ➕ Smaller diffs; easier review
  • ➕ Eliminates risk of stale committed artifacts
  • ➖ May not fit the plugin distribution workflow that expects built assets committed
  • ➖ Requires CI/release pipeline changes

Recommendation: The chosen approach (JS-derived token injection + PHP suppression of legacy clamps) is the most pragmatic way to guarantee correct precedence without breaking existing WP settings output. If review pain from committed build artifacts becomes recurring, consider shifting asset builds to CI/release tooling later.

Files changed (11) +2060 / -164

Enhancement (6) +985 / -56
slashed.full.cssUpdate framework bundle to v0.6.25 with bg layer + overflow fades +817/-23

Update framework bundle to v0.6.25 with bg layer + overflow fades

• Bumps the bundled framework header to v0.6.25 and introduces the new '.sf-bg' background media layer (with tokens and :has() parent promotion). Extends '.sf-overflow-fade' with directional variants and replaces hardcoded scroll-shadow sizing with shared mask scrim tokens. Also stages (commented) '.sf-btn'/'.sf-card' component definitions and adds related token surface (btn token rename, form/table helper tokens).

SLASHED-for-WP/admin-app/framework-css/badges/slashed.full.css

AppOverlay.svelteDesktop push layout + mobile full overlay behavior +27/-5

Desktop push layout + mobile full overlay behavior

• Replaces body margin pushing with an injected '<html>' padding-right stylesheet toggled by an 'sf-panel-active' class for better theme compatibility. Adds responsive behavior via matchMedia: desktop pushes content, mobile uses full-width overlay. Aligns panel/trigger positioning to the WP admin bar height CSS variable and cleans up injected resources on unmount.

SLASHED-for-WP/admin-app/src/AppOverlay.svelte

SliderRow.svelteAdd raw CSS expression entry mode for token overrides +77/-11

Add raw CSS expression entry mode for token overrides

• Extends SliderRow props to support a raw-default placeholder, current raw value, and raw setter callback. Adds UI to toggle raw mode (auto-enabled for expression-like overrides) and maintains a local draft buffer to avoid interrupted typing during reactive updates.

SLASHED-for-WP/admin-app/src/components/inputs/SliderRow.svelte

BordersPanel.svelteAlign radius/button tokens to v0.6.25 and enable raw token entry +31/-17

Align radius/button tokens to v0.6.25 and enable raw token entry

• Updates default radius scale values to match v0.6.25 and renames button tokens to '--sf-btn-*'. Adds per-control 'rawDefault/currentRaw/onRawSet' wiring to enable raw CSS overrides, and guards numeric parsing when overrides are expressions (var/calc/clamp).

SLASHED-for-WP/admin-app/src/components/panels/BordersPanel.svelte

LayoutPanel.svelteEnable raw CSS entry for layout tokens +24/-0

Enable raw CSS entry for layout tokens

• Adds raw-default placeholders (e.g., 'var(--sf-container-default)') and raw setters for layout-related SliderRows. This allows power users to reference framework tokens directly instead of only numeric slider values.

SLASHED-for-WP/admin-app/src/components/panels/LayoutPanel.svelte

SpacingPanel.svelteEnable raw CSS entry for spacing tokens +9/-0

Enable raw CSS entry for spacing tokens

• Adds raw-default token references and raw setters for spacing SliderRows (gap/content-gap/gutter). This enables token-to-token composition (e.g., 'var(--sf-space-m)') in the live preview and saved overrides.

SLASHED-for-WP/admin-app/src/components/panels/SpacingPanel.svelte

Bug fix (3) +195 / -23
sync-core.mjsPreserve syncignored files during local sync wipe +19/-2

Preserve syncignored files during local sync wipe

• When syncing from a local configurator source, preserves 'syncignore'-listed files across the 'src/' directory wipe. This mirrors the GitHub API sync mode and prevents plugin-specific files from being lost.

SLASHED-for-WP/admin-app/scripts/sync-core.mjs

persistence.tsCompute modular-scale derived tokens for accurate live preview +108/-1

Compute modular-scale derived tokens for accurate live preview

• Implements modular-scale derived-token computation in TypeScript (matching the framework’s formula) for text and space steps when source tokens are present. Injects derived tokens as unlayered ':root' CSS alongside overrides so they can win over legacy hardcoded clamps in layered override CSS.

SLASHED-for-WP/admin-app/src/lib/persistence.ts

class-css-generator.phpSkip legacy clamp tokens when modular-scale source tokens are set +68/-20

Skip legacy clamp tokens when modular-scale source tokens are set

• Detects when modular-scale source tokens exist in the flat override map and suppresses emitting legacy per-size/per-step clamp declarations that would shadow framework-computed tokens in layered overrides. Adds a helper 'flat_has_any()' and threads 'skip_sizes' through typography/spacing declaration generation.

SLASHED-for-WP/includes/class-css-generator.php

Other (2) +880 / -85
app.cssUpdate built admin-app CSS artifact +1/-1

Update built admin-app CSS artifact

• Regenerates the built Tailwind/Svelte CSS bundle to reflect the overlay/layout and input UX changes. This is a compiled artifact; source-of-truth remains in 'admin-app/src'.

SLASHED-for-WP/assets/admin-app/app.css

app.jsUpdate built admin-app JS artifact +879/-84

Update built admin-app JS artifact

• Regenerates the built admin-app JavaScript bundle containing the compiled Svelte/TS changes (panel push behavior, raw slider mode, derived-token preview). This is a compiled artifact; source-of-truth remains in 'admin-app/src'.

SLASHED-for-WP/assets/admin-app/app.js

@qodo-code-review

qodo-code-review Bot commented Jun 29, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Preserved path traversal ✓ Resolved 🐞 Bug ⛨ Security
Description
sync-core.mjs now preserves syncignored paths across the src/ wipe, but it never re-validates that
preserved paths stay within SRC (nor that they are files). A malicious or malformed .syncignore
entry can cause arbitrary file read/write outside src/ or throw when readFileSync hits a directory.
Code

SLASHED-for-WP/admin-app/scripts/sync-core.mjs[R261-280]

+    // Fresh tree: drop any stale files from the previous fork before copying,
+    // but preserve syncignored plugin-specific files across the wipe (mirrors
+    // the same logic used in GitHub API mode).
+    const preserved = new Map();
+    if (existsSync(SRC)) {
+      for (const entry of syncIgnore) {
+        const rel = entry.startsWith('src/') ? entry.slice(4) : entry;
+        const p = join(SRC, rel);
+        if (existsSync(p)) {
+          preserved.set(p, readFileSync(p));
+          process.stdout.write(`  keep  src/${rel} (syncignore — saved across wipe)\n`);
+        }
+      }
+      rmSync(SRC, { recursive: true, force: true });
+    }
    mkdirSync(SRC, { recursive: true });
+    for (const [p, content] of preserved) {
+      mkdirSync(dirname(p), { recursive: true });
+      writeFileSync(p, content);
+    }
Relevance

⭐⭐⭐ High

Team previously accepted adding path-traversal guards in sync-core writes (CodeQL) in PR #27.

PR-#27

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PR added a new preserve-and-restore path that bypasses the script’s existing path safety checks
(which are used elsewhere for writes into src/).

SLASHED-for-WP/admin-app/scripts/sync-core.mjs[57-63]
SLASHED-for-WP/admin-app/scripts/sync-core.mjs[133-149]
SLASHED-for-WP/admin-app/scripts/sync-core.mjs[258-307]
PR-#27

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`sync-core.mjs` preserves `.syncignore` entries across a `rmSync(SRC, { recursive: true })` wipe, but the preserved paths are built with `join(SRC, rel)` and then read/written without applying the existing `assertWithinSrc()` guard and without verifying they are files.

This reintroduces a path traversal/arbitrary-write class of bug (and can also crash if an ignored entry is a directory).

### Issue Context
The script already has `assertWithinSrc()` and uses it for other write paths.

### Fix Focus Areas
- SLASHED-for-WP/admin-app/scripts/sync-core.mjs[255-307]

### What to change
- Before `readFileSync(p)` and before `writeFileSync(p, content)`, call `assertWithinSrc(p)`.
- Add a file-type check: `const st = statSync(p); if (!st.isFile()) continue;` (or handle directories explicitly).
- Consider rejecting unsafe `rel` values up front (e.g., if `rel` contains `..` segments or is absolute) even though `assertWithinSrc` is the final guard.
- Apply the same hardening to both the local and GitHub modes (the preservation logic is duplicated).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Skip logic ignores validation ✓ Resolved 🐞 Bug ≡ Correctness
Description
Slashed_CSS_Generator::flat_has_any() suppresses legacy per-size clamp declarations based only on
non-empty stored override values, but those same override values may later be dropped by
generate_flat_override_declarations() via validate_override_value(). This can unexpectedly remove
legacy declarations even when the “source token” override won’t actually be emitted.
Code

SLASHED-for-WP/includes/class-css-generator.php[R200-207]

+	private static function flat_has_any( $keys ) {
+		$overrides = Slashed_Token_Store::get_overrides();
+		foreach ( $keys as $key ) {
+			if ( isset( $overrides[ $key ] ) && '' !== (string) $overrides[ $key ] ) {
+				return true;
+			}
+		}
+		return false;
Relevance

⭐⭐⭐ High

Similar mismatch (override detection vs emission filtering/validation) was accepted and fixed in PR
#83.

PR-#83

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The emission path explicitly validates each stored override value and can drop entries; flat_has_any
currently treats any non-empty stored value as present, which can diverge from what is actually
emitted.

SLASHED-for-WP/includes/class-css-generator.php[92-120]
SLASHED-for-WP/includes/class-css-generator.php[176-187]
SLASHED-for-WP/includes/class-css-generator.php[200-207]
PR-#83

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`flat_has_any()` decides whether to skip legacy clamp declarations by checking that certain override keys exist and are non-empty. However, the actual emission path (`generate_flat_override_declarations`) re-validates values and can drop invalid entries.

This creates a mismatch: an invalid/unemittable override can still cause legacy declarations to be skipped, changing output CSS unexpectedly.

### Issue Context
This is the same class of bug as previous generator mismatches: detection/branching should use the same filtering/validation rules as emission.

### Fix Focus Areas
- SLASHED-for-WP/includes/class-css-generator.php[84-120]
- SLASHED-for-WP/includes/class-css-generator.php[176-208]

### What to change
- Update `flat_has_any()` to only return true if the relevant key would actually be emitted:
 - Check key name format (even though keys are hardcoded by callers).
 - Run `validate_override_value($overrides[$key])` and require it to be non-false.
 - Optionally ensure the stored value is scalar before casting.
- Consider centralizing the “clean overrides map” so both `flat_has_any()` and `generate_flat_override_declarations()` operate on the same sanitized representation.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Raw editor flips to slider ✓ Resolved 🐞 Bug ≡ Correctness
Description
SliderRow auto-enables raw mode for CSS expressions, but clearing the raw input triggers onReset
immediately; that clears currentRaw, making isRawOverride false and collapsing showRaw back to the
slider mid-edit. This makes it difficult to edit an existing expression because temporarily emptying
the input exits raw mode.
Code

SLASHED-for-WP/admin-app/src/components/inputs/SliderRow.svelte[R23-87]

+  let userRawMode = $state(false);
+
+  // Auto raw mode when override value is a CSS expression
+  let isRawOverride = $derived(
+    !!currentRaw && /^(var|calc|clamp|min|max|env)\(/.test(currentRaw.trim())
+  );
+
+  let showRaw = $derived(!!(rawDefault && onRawSet && (userRawMode || isRawOverride)));
+
+  // Local draft so typing is never interrupted by re-renders
+  let rawDraft = $state(currentRaw ?? '');
+  let isEditing = $state(false);
+
+  // Sync draft from external currentRaw changes only when user is not actively editing
+  $effect(() => {
+    if (!isEditing) {
+      rawDraft = currentRaw ?? '';
+    }
+  });
</script>

<div class="group">
  <div class="flex items-center justify-between mb-1.5">
-    <span class="text-[11px] font-semibold text-slate-200">{label}</span>
-    {#if overridden}
-      <button
-        onclick={onReset}
-        class="text-[9px] text-slate-500 hover:text-rose-400 cursor-pointer opacity-0 group-hover:opacity-100 transition-colors"
-      >
-        reset
-      </button>
+    {#if label}
+      <span class="text-[11px] font-semibold text-slate-200">{label}</span>
+    {:else}
+      <span></span>
    {/if}
+    <div class="flex items-center gap-1.5">
+      {#if rawDefault && onRawSet}
+        <button
+          onclick={() => { userRawMode = !userRawMode; }}
+          title={showRaw ? "Switch to slider" : "Enter raw CSS value"}
+          class={`text-[9px] font-mono cursor-pointer transition-all px-0.5 ${
+            showRaw
+              ? 'text-indigo-400'
+              : 'opacity-0 group-hover:opacity-100 text-slate-500 hover:text-indigo-400'
+          }`}
+        >&lt;/&gt;</button>
+      {/if}
+      {#if overridden}
+        <button
+          onclick={onReset}
+          class="text-[9px] text-slate-500 hover:text-rose-400 cursor-pointer opacity-0 group-hover:opacity-100 transition-colors"
+        >reset</button>
+      {/if}
+    </div>
  </div>
-  <RangeWithNumber {value} {min} {max} {step} {unit} {onChange} />
+
+  {#if showRaw && rawDefault}
+    <input
+      type="text"
+      value={rawDraft}
+      placeholder={rawDefault}
+      onfocus={() => { isEditing = true; }}
+      onblur={() => { isEditing = false; }}
+      oninput={(e) => {
+        rawDraft = (e.target as HTMLInputElement).value;
+        const v = rawDraft.trim();
+        if (!v) {
+          onReset();
+        } else if (onRawSet) {
+          onRawSet(v);
+        }
+      }}
Relevance

⭐⭐ Medium

No historical evidence found about SliderRow raw-mode UX toggling; file path not present in repo
history.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
showRaw depends on isRawOverride (derived from currentRaw), while the raw input’s oninput calls
onReset when empty, which clears currentRaw and can therefore flip showRaw false while focused.

SLASHED-for-WP/admin-app/src/components/inputs/SliderRow.svelte[23-31]
SLASHED-for-WP/admin-app/src/components/inputs/SliderRow.svelte[72-87]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
In `SliderRow`, raw mode is shown when `userRawMode || isRawOverride`. For an expression override (e.g. `calc(...)`), raw mode is shown via `isRawOverride` even when the user never toggled raw mode.

When the user clears the input to type a new expression, `oninput` calls `onReset()` as soon as the trimmed value becomes empty. That clears `currentRaw`, so `isRawOverride` becomes false, `showRaw` becomes false, and the component swaps back to the slider while the user is still editing.

### Issue Context
This is specifically the auto-raw path (`userRawMode === false`, `isRawOverride === true`).

### Fix Focus Areas
- SLASHED-for-WP/admin-app/src/components/inputs/SliderRow.svelte[23-95]

### What to change
Implement one of these approaches:
- **Defer reset until commit**: don’t call `onReset()` in `oninput`; instead, only reset on `blur` (or on Enter) when the value is empty.
- **Pin raw mode during editing**: include `isEditing` in `showRaw` so the raw input stays mounted while focused, e.g. `userRawMode || isRawOverride || isEditing`.

Also ensure the draft value and override state stay consistent after the chosen commit/reset behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Derived tokens override user ✓ Resolved 🐞 Bug ≡ Correctness
Description
injectLivePreview merges computed modular-scale outputs as { ...ov, ...derived }, so derived
values overwrite any explicit overrides for the same token names (e.g. --sf-text-m). This produces
an incorrect live preview whenever a user overrides an output token while also setting any
modular-scale source token.
Code

SLASHED-for-WP/admin-app/src/lib/persistence.ts[R174-178]

+  // Include pre-computed derived tokens alongside source tokens so they win
+  // as unlayered CSS over any hardcoded clamp values in @layer slashed.overrides.
+  const derived = computeScaleTokens(ov);
+  const preview = Object.keys(derived).length > 0 ? { ...ov, ...derived } : ov;
+  styleEl.textContent = fa(preview, { mode: "root", banner: false });
Relevance

⭐⭐ Medium

No prior accepted/rejected findings found about derived tokens overwriting user overrides via object
spread order.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
computeScaleTokens produces output tokens like --sf-text-m, and injectLivePreview currently
overwrites any same-named keys present in ov due to spread order.

SLASHED-for-WP/admin-app/src/lib/persistence.ts[82-117]
SLASHED-for-WP/admin-app/src/lib/persistence.ts[165-178]
SLASHED-for-WP/admin-app/src/data/token-registry.generated.json[2573-2581]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`injectLivePreview()` computes derived modular-scale tokens and then spreads them after `ov`, meaning computed values override explicit user overrides for the same custom property.

This makes the preview incorrect for cases where users intentionally set `--sf-text-m`/`--sf-space-m` (etc.) while also setting scale source tokens.

### Issue Context
Computed tokens are meant to override *legacy hardcoded* layer declarations, not user-provided overrides in the current overrides map.

### Fix Focus Areas
- SLASHED-for-WP/admin-app/src/lib/persistence.ts[82-121]
- SLASHED-for-WP/admin-app/src/lib/persistence.ts[165-179]

### What to change
- Change merge order so explicit overrides win: `const preview = hasDerived ? { ...derived, ...ov } : ov;`
 - Alternatively, only set `derived[k]` when `ov[k] === undefined`.
- Add a small unit test (if the repo has a test harness) or a runtime assertion in dev builds to ensure `ov` always wins on key collisions.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread SLASHED-for-WP/admin-app/scripts/sync-core.mjs
Add assertWithinSrc() and isFile() checks before reading and writing
preserved syncignore entries in both local and GitHub modes, preventing
a malicious/malformed .syncignore from escaping the src/ directory or
crashing on directory entries.
Comment thread SLASHED-for-WP/admin-app/scripts/sync-core.mjs Fixed
Comment thread SLASHED-for-WP/admin-app/scripts/sync-core.mjs Fixed
claude added 2 commits June 29, 2026 10:26
window.slashedApp.rest.url is PHP-injected but treated as a tainted
DOM source by static analysis. Parsing with URL() and asserting
origin === window.location.origin eliminates the client-side request
forgery vector (CWE-918) before the fetch call.
…tion

Replace assertWithinSrc() helper calls in the syncignore preservation
blocks with inline resolve()+startsWith(SRC_ROOT) checks — the explicit
pattern CodeQL's TaintedPath (CWE-022) sanitizer detection recognises.
Both save and restore phases in local and GitHub modes are covered.
Comment thread SLASHED-for-WP/admin-app/scripts/sync-core.mjs Fixed
Comment thread SLASHED-for-WP/admin-app/scripts/sync-core.mjs Fixed
claude added 2 commits June 29, 2026 10:38
…QL CWE-918

The compiled artifact contained the old wpSave without origin validation.
Patch app.js directly to match the source fix in persistence.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9LLXdjBSrE5BZdPSomqJs
…; exclude compiled assets

sync-core.mjs: replace Map-keyed approach with array of {rel,content} so both
the save and restore phases use resolve(join(SRC,rel)).startsWith(SRC_ROOT)
inline — the canonical CodeQL path-traversal sanitizer pattern on each sink.

codeql.yml: exclude SLASHED-for-WP/assets/** and integrations/bricks/assets/**
(compiled build artifacts) from CodeQL scanning. Source TypeScript is already
analyzed; scanning minified bundles produces false-positive SSRF alerts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9LLXdjBSrE5BZdPSomqJs
Comment thread SLASHED-for-WP/admin-app/scripts/sync-core.mjs Fixed
Comment thread SLASHED-for-WP/admin-app/scripts/sync-core.mjs Fixed
claude added 2 commits June 29, 2026 11:02
… paths-ignore

Replace statSync(path)+readFileSync(path) with openSync→fstatSync(fd)→readFileSync(fd)
in both preservation blocks. All three operations share the same file descriptor so the
file cannot be swapped between the type-check and the read (CWE-367 / js/file-system-race).

Also revert the paths-ignore workaround from codeql.yml added in the previous commit;
real fixes should address the root cause, not suppress the scanner.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9LLXdjBSrE5BZdPSomqJs
…liderRow

- flat_has_any(): call validate_override_value() so detection matches
  emission logic; invalid values no longer suppress legacy clamp rules
- persistence.ts: fix spread order to { ...derived, ...ov } so user
  overrides always win over computed derived tokens in the live preview
- SliderRow.svelte: include isEditing in showRaw so the raw input stays
  visible while focused even on empty; defer onReset() to onblur

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9LLXdjBSrE5BZdPSomqJs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 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 `@SLASHED-for-WP/admin-app/framework-css/badges/slashed.full.css`:
- Around line 2719-2722: The :where(:has(> .sf-bg)) rule is forcing parent
elements to position: relative, which can overwrite intentionally set absolute,
fixed, or sticky positioning. Update the selector in slashed.full.css so the
auto-isolation remains, but positioning is only applied when the parent is known
to be static or via an explicit opt-in class; keep the rule scoped around
.sf-bg-related wrappers rather than globally changing every parent.

In `@SLASHED-for-WP/admin-app/scripts/sync-core.mjs`:
- Around line 269-276: The preserved-file handling in sync-core.mjs still
follows symlinks because srcPath is only checked lexically before openSync, so a
.syncignore entry can escape src/ and preserve outside content. Update the
preserved-file loops around the file-open/read logic to reject symlinks using a
no-follow open or another handle-based check, and keep the inode-safe stat/read
flow in place without reintroducing a pre-open lstatSync race.

In `@SLASHED-for-WP/admin-app/src/AppOverlay.svelte`:
- Around line 209-214: The panel push style in AppOverlay.svelte is mutating the
root box model by setting box-sizing on html, which can affect the entire host
page. Update the pushStyle CSS in the AppOverlay/panel push logic so it only
applies padding/overflow-related changes on html and remove the box-sizing rule
from the sf-panel-active styling.

In `@SLASHED-for-WP/admin-app/src/components/panels/BordersPanel.svelte`:
- Around line 74-82: The radius and component value helpers in
BordersPanel.svelte are treating valid "0" overrides as falsy, so they
incorrectly fall back to defaults. Update getRadius and getComponentVal to
distinguish missing/empty values from numeric zero by checking for
null/undefined/empty string before parsing, and keep returning the parsed value
when it is 0. Preserve the existing var/calc/clamp handling while ensuring
zero-valued overrides remain selected by the slider.

In `@SLASHED-for-WP/includes/class-css-generator.php`:
- Around line 98-117: The CSS source-key detection in class-css-generator.php is
only checking legacy per-size tokens, so scale-only overrides can still be
shadowed by previously saved hardcoded values. Update the skip logic around
flat_has_any in the CSS generator to also recognize the derived scale inputs
used by persistence.ts, specifically the text-scale, text-display-scale, and
space-scale tokens, so frontend output is regenerated consistently with the
client preview. Keep the fix localized to the scale-detection flow in the CSS
generator and ensure the existing text and space branches both honor these
scale-based overrides.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ef7e12fc-6bc4-4a07-a43f-dbc4224f7140

📥 Commits

Reviewing files that changed from the base of the PR and between 2cd3050 and cd3166d.

📒 Files selected for processing (12)
  • SLASHED-for-WP/admin-app/framework-css/badges/slashed.full.css
  • SLASHED-for-WP/admin-app/scripts/sync-core.mjs
  • SLASHED-for-WP/admin-app/src/AppOverlay.svelte
  • SLASHED-for-WP/admin-app/src/components/inputs/SliderRow.svelte
  • SLASHED-for-WP/admin-app/src/components/panels/BordersPanel.svelte
  • SLASHED-for-WP/admin-app/src/components/panels/LayoutPanel.svelte
  • SLASHED-for-WP/admin-app/src/components/panels/SpacingPanel.svelte
  • SLASHED-for-WP/admin-app/src/components/shell/StudioHeader.svelte
  • SLASHED-for-WP/admin-app/src/lib/persistence.ts
  • SLASHED-for-WP/assets/admin-app/app.css
  • SLASHED-for-WP/assets/admin-app/app.js
  • SLASHED-for-WP/includes/class-css-generator.php

Comment thread SLASHED-for-WP/admin-app/framework-css/badges/slashed.full.css
Comment thread SLASHED-for-WP/admin-app/scripts/sync-core.mjs
Comment thread SLASHED-for-WP/admin-app/src/AppOverlay.svelte
Comment thread SLASHED-for-WP/admin-app/src/components/panels/BordersPanel.svelte Outdated
Comment thread SLASHED-for-WP/includes/class-css-generator.php
- sync-core.mjs: use O_NOFOLLOW flag in openSync so symlinked .syncignore
  entries cannot read files outside src/ without a TOCTOU-prone pre-check
- slashed.full.css: remove position:relative from :where(:has(>.sf-bg)) to
  avoid clobbering intentional absolute/fixed/sticky parents; add opt-in
  .sf-bg-parent class for static wrappers that need a containing block
- AppOverlay.svelte: replace box-sizing:border-box on html.sf-panel-active
  with overflow-x:clip to avoid mutating the root box model site-wide
- BordersPanel.svelte: fix getRadiusValue/getComponentVal to use
  isNaN(parsed) instead of ||, so a saved value of 0 is preserved correctly
- class-css-generator.php: add --sf-text-scale, --sf-text-display-scale, and
  --sf-space-scale to the flat_has_any detection keys so scale-only overrides
  correctly suppress legacy hardcoded clamp declarations on the frontend

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9LLXdjBSrE5BZdPSomqJs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants