Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Full-API admin panel expansion with Cheatsheet

The admin SPA (Svelte 5) gains five new tab components: VariablesTab, ClassesTab, BundleTab, HooksTab, and CheatsheetTab. Together they expose the entire SLASHED public API — every `--sf-*` variable, `.sf-*`/`.is-*` class, plugin setting, and filter hook — as read-only reference pages, plus one writable setting (html_font_size) in BundleTab. The PHP side adds the new tab slugs and pipes inventory data into the hydration payload.

**Watch for:** The CheatsheetTab "no results" empty-state has a logic gap that causes it to never appear when a single view mode is selected (confirmed). Hard-coded counts in CheatsheetTab (607/143/40) will silently drift from the actual inventory (confirmed). The `bundle` tab is not in the `readOnlyTabs` list yet it has its own independent save, meaning the global SaveBar also renders on that tab — potentially confusing when only a single-setting save button is relevant (confirmed).

---

## High-level view

Five read-only reference tabs materialize what was previously scattered across docs and PHP source. VariablesTab and ClassesTab pull live inventory from the PHP hydration payload; CheatsheetTab and HooksTab ship their own static data modules. The design splits "live from server" (inventory-based) from "static documentation" (cheatsheet-data.js, hook definitions), avoiding an extra REST round-trip for content that changes only on plugin release.

BundleTab is the only new tab with write capability. It calls `POST /settings` with `html_font_size` through the same `call()` helper the existing token endpoints use, but the tab sits outside the `readOnlyTabs` gate, so the global SaveBar is simultaneously visible — two independent save affordances on one screen with unrelated persistence paths.

The CheatsheetTab introduces a 282-line static data module (`cheatsheet-data.js`) with hand-curated descriptions for every token and class. The search UX filters by name or description, but the empty-state condition has an operator-precedence bug that silences the "no results" message in single-view modes.

---

<details>
<summary>Issues (5)</summary>

1. **Empty-state logic in CheatsheetTab** — The `{#if showVariables && ... && showClasses && ...}` condition requires *both* view flags to be true, so the "No results" message never appears when `viewMode` is `'variables'` or `'classes'`. Split into per-mode empty checks or restructure the condition.
2. **Hard-coded counts drift** — `totalVarCount`, `totalSfClassCount`, `totalIsClassCount` in CheatsheetTab are constants (607/143/40) while the actual data comes from `cheatsheet-data.js` and `meta.inventory`. Derive from data or document that they're intentional approximations.
3. **Dual save affordances on BundleTab** — BundleTab has its own "Save Settings" button but is not in `readOnlyTabs`, so the global SaveBar also renders. Either add `'bundle'` to `readOnlyTabs` or hide the global bar contextually for that tab.
4. **Stale cheatsheet data** — `cheatsheet-data.js` is hand-maintained static content that will diverge from the framework CSS over time. Consider a build-time generation step, or add a comment pointing to the authoritative sources.
5. **Inventory absence is silent** — If PHP's `Slashed_Bricks_Inventory::get()` returns an empty or malformed structure, VariablesTab and ClassesTab show "0 items" with no diagnostic. A small notice ("inventory unavailable — check bundle path") would aid debugging.

</details>

<details>
<summary>Details</summary>

## Empty-state logic bug in CheatsheetTab

Line 138 of CheatsheetTab.svelte:

```svelte
{#if showVariables && filteredVariableGroups.length === 0 && filteredMiscTokens.length === 0 && showClasses && filteredClassGroups.length === 0}
```

When `viewMode` is `'variables'`, `showClasses` is `false`, so the entire condition short-circuits to `false` regardless of whether the variable results are empty. The user types a non-matching query and sees a blank screen with no feedback. The fix is straightforward — compute a single `noResults` derived that accounts for the active view:

```js
let noResults = $derived(
search.trim() && (
(!showVariables || (filteredVariableGroups.length === 0 && filteredMiscTokens.length === 0)) &&
(!showClasses || filteredClassGroups.length === 0)
)
);
```

## Hard-coded counts vs. live data

CheatsheetTab declares:

```js
const totalVarCount = 607;
const totalSfClassCount = 143;
const totalIsClassCount = 40;
```

These are displayed in the header and never recalculated. If someone adds a token to `cheatsheet-data.js` the count won't update. These should be derived:

```js
const totalVarCount = variableGroups.reduce((n, g) => n + g.tokens.length, 0) + miscTokens.length;
```

If 607/143/40 intentionally represent the *framework* totals (not the listed representative tokens), a comment would prevent confusion.

## Dual save controls on BundleTab

`readOnlyTabs` in App.svelte: `['cheatsheet', 'hooks', 'variables', 'classes']`. BundleTab is absent, so the global `SaveBar` renders alongside BundleTab's own "Save Settings" button. The global bar's "Save changes" calls `saveSection()` for token data; BundleTab's button calls `saveSettings()`. A user clicking the global save on BundleTab persists nothing meaningful (or worse, persists an empty section object). Adding `'bundle'` to `readOnlyTabs` is the simplest fix since BundleTab already owns its save flow.

## Categorization drift risk in VariablesTab

The `CATEGORY_MAP` in VariablesTab is a JS snapshot of `class-inventory.php`'s `category_map()`. If PHP adds a new prefix mapping, the SPA won't pick it up — tokens fall through to "Misc" silently. A cleaner long-term approach: have PHP send pre-categorized groups in the hydration payload rather than duplicating the mapping logic client-side.

## Cheatsheet data maintenance

`cheatsheet-data.js` is a hand-curated module separate from `meta.inventory`. It documents the *framework* exhaustively with descriptions, while inventory reflects what's *installed*. The trade-off is maintenance: when the framework ships new tokens, both `cheatsheet-data.js` and the CSS source need updates. A build script that extracts token names from the CSS and merges with a description sidecar would prevent drift.

</details>

<details>
<summary>File map</summary>

| File | Change |
|------|--------|
| `admin-app/src/components/VariablesTab.svelte` | New — read-only grouped variable list with JS categorization |
| `admin-app/src/components/ClassesTab.svelte` | New — collapsible sf-class / is-class sections |
| `admin-app/src/components/BundleTab.svelte` | New — bundle info + html_font_size save |
| `admin-app/src/components/HooksTab.svelte` | New — static hook reference with PHP code examples |
| `admin-app/src/components/CheatsheetTab.svelte` | New — searchable token/class index with view toggle |
| `admin-app/src/lib/cheatsheet-data.js` | New — 282-line static data module for cheatsheet |
| `admin-app/src/lib/api.js` | Added `saveSettings()` export |
| `admin-app/src/lib/stores.svelte.js` | Exposed `inventory` and `pluginSettings` from bootstrap |
| `admin-app/src/App.svelte` | Import + render new tabs; hide SaveBar on read-only tabs |
| `admin-app/index.html` | Dev harness: mock inventory, pluginSettings, new tab slugs |
| `includes/class-admin-page.php` | Added 5 tab slugs to `$this->tabs` |
| `includes/class-admin-page-svelte.php` | Passes `inventory` in `wp_localize_script` payload |

Full diff: `git diff 7b05039..HEAD`

</details>
38 changes: 38 additions & 0 deletions .agents/tasks/task-admin-panel-full-api-cheatsheet/context.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"project_type": "Svelte 5 SPA (admin-app) embedded in a WordPress plugin (integrations/bricks/)",
"language": "JavaScript (Svelte 5 runes), PHP, CSS",
"build_system": "Vite 6 for the Svelte admin-app. Output goes to integrations/bricks/assets/admin-app/. No build step for the CSS framework itself.",
"test_framework": "No tests for the admin-app. The main SLASHED framework uses Playwright (npm test). The admin-app has no test suite.",
"build_command": "cd integrations/bricks/admin-app && npm install && npm run build",
"test_command": "cd integrations/bricks/admin-app && npm run build (build success = verification since no test suite exists)",
"verification_instructions": "1. npm install in admin-app/. 2. npm run build must succeed without errors. 3. Output files appear in integrations/bricks/assets/admin-app/app.js and app.css.",
"snapshot_or_generated_files": "integrations/bricks/assets/admin-app/app.js and app.css are generated by vite build. They are checked in.",
"setup_instructions": "cd integrations/bricks/admin-app && npm install",
"environment_constraints": "COMMON_DEPENDENCIES network mode - npm install should work. No WordPress runtime available for integration testing. Validation is build-only (vite build).",
"contribution_requirements": "Conventional Commits. CSS custom properties must start with --sf-. The admin-app uses Svelte 5 runes ($state, $derived, $effect, $props). No jQuery in the Svelte app.",
"key_patterns": "1. Svelte 5 runes pattern: module-level reactive state in .svelte.js files using $state(). 2. Tab navigation: meta.tabs drives TabNav.svelte, ui.activeTab selects the active tab body. 3. API calls go through src/lib/api.js using WP REST nonce auth. 4. Hydration data comes from window.slashedBricksApp (populated by PHP wp_localize_script). 5. Each tab is a standalone component rendered conditionally in App.svelte. 6. The inventory (all variables and classes) is available at data/inventory.json. 7. Category mapping logic exists in class-inventory.php (categorize_variable, category_map, category_order).",
"relevant_files": [
"integrations/bricks/admin-app/src/App.svelte",
"integrations/bricks/admin-app/src/lib/stores.svelte.js",
"integrations/bricks/admin-app/src/lib/api.js",
"integrations/bricks/admin-app/src/components/TabNav.svelte",
"integrations/bricks/admin-app/src/components/ColorTab.svelte",
"integrations/bricks/admin-app/src/components/StubTab.svelte",
"integrations/bricks/admin-app/src/components/SaveBar.svelte",
"integrations/bricks/admin-app/src/components/ColorRow.svelte",
"integrations/bricks/admin-app/src/components/LivePreview.svelte",
"integrations/bricks/admin-app/package.json",
"integrations/bricks/admin-app/vite.config.js",
"integrations/bricks/includes/class-admin-page.php",
"integrations/bricks/includes/class-admin-page-svelte.php",
"integrations/bricks/includes/class-rest-controller.php",
"integrations/bricks/includes/class-inventory.php",
"integrations/bricks/data/inventory.json",
"docs/tokens.md",
"docs/layout.md",
"docs/macros.md",
"docs/states.md",
"integrations/bricks/README.md"
],
"directory_structure": "integrations/bricks/admin-app/src/ - Svelte SPA source. integrations/bricks/admin-app/src/components/ - tab and UI components. integrations/bricks/admin-app/src/lib/ - stores and API. integrations/bricks/includes/ - PHP backend classes. integrations/bricks/data/ - inventory.json fallback. docs/ - framework documentation. core/ - CSS source files."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"id": "FEAT-001",
"type": "chore",
"description": "Install dependencies and verify the admin-app builds successfully as-is before making changes.",
"status": "completed",
"steps": [
"Run `npm install` in integrations/bricks/admin-app/",
"Run `npm run build` in integrations/bricks/admin-app/ and confirm it exits 0",
"Verify output files exist at integrations/bricks/assets/admin-app/app.js and app.css"
],
"acceptance_criteria": [
"`npm run build` exits with code 0",
"integrations/bricks/assets/admin-app/app.js exists and is non-empty",
"integrations/bricks/assets/admin-app/app.css exists and is non-empty"
],
"verification": [
"Run `cd integrations/bricks/admin-app && npm run build` and confirm exit code 0"
],
"blocked_reason": null,
"findings": "Build succeeds with exit 0. npm install added 90 packages. Compiled output differs slightly from checked-in version due to minification variable naming, which is expected with Svelte/Vite rebuilds."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"id": "FEAT-002",
"type": "feat",
"description": "Expand the Svelte admin panel to cover the entire public API by replacing stub tabs with real content tabs for Variables, Classes, Bundle/Settings, and Hooks, plus improving the existing ColorTab.",
"status": "completed",
"steps": [
"Step 1 - Create VariablesTab.svelte in src/components/. This tab reads all variables from the inventory (window.slashedBricksApp already provides defaults which contain variable categories from class-inventory.php). For the Svelte SPA, we need to add inventory data to the hydration payload. Since PHP is not available, we will embed a static cheatsheet data module (see FEAT-003). For now, this tab should display all registered variables grouped by their category (Colors, Typography, Spacing, Sizing, Layout, Borders, Radius, Shadows, Effects, Motion, Icons, Z-Index, States, Focus, Scroll, Print, Misc) using the same categorization logic from class-inventory.php. Each category is a collapsible section showing the variable names. This is a read-only view, not an editor.",
"Step 2 - Create ClassesTab.svelte in src/components/. This tab shows all .sf-* layout/utility classes and .is-* state classes in two separate sections. Each class is listed with its name. The data comes from the same static inventory data module.",
"Step 3 - Create BundleTab.svelte in src/components/. This tab shows: (a) Current CSS bundle info (the URL configured, which bundle is active), (b) the html_font_size plugin setting (already exposed via pluginSettings in the hydration payload and the /settings REST endpoint). The font-size select should be functional - on change it calls the existing REST API (POST /slashed-bricks/v1/settings with html_font_size). Show a save button for this section that is independent of the token save flow.",
"Step 4 - Create HooksTab.svelte in src/components/. This is a documentation/reference tab that lists all available filter hooks with their signatures, descriptions, and example PHP code snippets. The content is static/hardcoded since it documents the PHP API. Hooks to document: slashed_bricks/css_bundle_url, slashed_bricks/registered_classes, slashed_bricks/registered_colors, slashed_bricks/registered_variables, slashed_bricks/inventory, slashed_bricks/inventory_local_path, slashed_bricks/color_categories.",
"Step 5 - Update stores.svelte.js to expose inventory data. Add an `inventory` field to the `meta` export that reads from bootstrap.inventory (which we will populate from PHP or from the static fallback). The shape should be { variables: string[], sf_classes: string[], is_classes: string[] }. Also expose pluginSettings from the bootstrap.",
"Step 6 - Update App.svelte to import and render the new tab components. Replace the single StubTab fallback with proper conditional rendering: 'colors' -> ColorTab, 'variables' -> VariablesTab, 'classes' -> ClassesTab, 'bundle' -> BundleTab, 'hooks' -> HooksTab. Any unrecognized tab slug still falls back to StubTab.",
"Step 7 - Update the PHP hydration in class-admin-page-svelte.php to pass inventory data to the SPA. Add 'inventory' key to the wp_localize_script payload containing Slashed_Bricks_Inventory::get() result (variables, sf_classes, is_classes). Also update the 'tabs' to include the new tab slugs.",
"Step 8 - Update class-admin-page.php get_tabs() to add the new tab slugs. Add 'variables' => 'Variables', 'classes' => 'Classes', 'bundle' => 'Bundle', 'hooks' => 'Hooks' to the $this->tabs array. Keep existing tabs (colors, contrast, typography, spacing, radius, shadows, motion, zindex) intact.",
"Step 9 - Update the api.js module to add a saveSettings(settings) function that calls POST /settings with the given payload. This is needed by BundleTab for the font-size setting.",
"Step 10 - Update index.html dev harness to include mock inventory data in window.slashedBricksApp so `vite dev` works for the new tabs. Add inventory with a few sample variables/classes, and the new tab slugs.",
"Step 11 - Build and verify: run `npm run build` in admin-app/ and confirm it succeeds."
],
"acceptance_criteria": [
"App.svelte renders VariablesTab, ClassesTab, BundleTab, HooksTab for their respective tab slugs",
"VariablesTab shows variables grouped by category with collapsible sections",
"ClassesTab shows .sf-* and .is-* classes in separate sections",
"BundleTab shows the font-size setting with a functional select + save button",
"HooksTab shows all 7 filter hooks with descriptions and code examples",
"TabNav shows all tabs including the new ones",
"The app still builds successfully with `npm run build`",
"Existing ColorTab functionality is unchanged"
],
"verification": [
"Run `cd integrations/bricks/admin-app && npm run build` and confirm exit code 0"
],
"blocked_reason": null,
"findings": "All 11 steps implemented successfully. Build passes (vite build exits 0). Created 4 new tab components (VariablesTab, ClassesTab, BundleTab, HooksTab), updated stores to expose inventory and pluginSettings, added saveSettings to api.js, updated App.svelte routing, updated PHP class-admin-page.php and class-admin-page-svelte.php, and enriched the dev harness index.html with mock data for all new tabs. The compiled output grew from ~47KB to ~62KB due to the new components."
}
Loading