From 18f1449bd2ac40970c9ed517562665ab4160dc37 Mon Sep 17 00:00:00 2001 From: Kiro Agent <244629292+kiro-agent@users.noreply.github.com> Date: Sat, 23 May 2026 13:39:18 +0000 Subject: [PATCH 1/5] feat: add SLASHED Bricks Builder integration plugin Create a WordPress plugin at integrations/bricks/ that integrates the SLASHED CSS framework with Bricks Builder, providing: - CSS enqueue on frontend and editor iframe (class-enqueue.php) - CSS variable registration for builder pickers (class-variables.php) - Layout and state class autocomplete (class-classes.php) - Color palette synchronization with CSS var references (class-colors.php) - Filter hooks for all registration arrays - Editor panel styling and documentation Co-authored-by: Jack Granatowski --- integrations/bricks/README.md | 139 ++++++++ integrations/bricks/assets/editor.css | 18 + .../bricks/includes/class-classes.php | 309 ++++++++++++++++++ integrations/bricks/includes/class-colors.php | 160 +++++++++ .../bricks/includes/class-enqueue.php | 71 ++++ .../bricks/includes/class-variables.php | 300 +++++++++++++++++ integrations/bricks/slashed-bricks.php | 96 ++++++ 7 files changed, 1093 insertions(+) create mode 100644 integrations/bricks/README.md create mode 100644 integrations/bricks/assets/editor.css create mode 100644 integrations/bricks/includes/class-classes.php create mode 100644 integrations/bricks/includes/class-colors.php create mode 100644 integrations/bricks/includes/class-enqueue.php create mode 100644 integrations/bricks/includes/class-variables.php create mode 100644 integrations/bricks/slashed-bricks.php diff --git a/integrations/bricks/README.md b/integrations/bricks/README.md new file mode 100644 index 00000000..3be5aad2 --- /dev/null +++ b/integrations/bricks/README.md @@ -0,0 +1,139 @@ +# SLASHED for Bricks + +A WordPress plugin that integrates the [SLASHED](https://github.com/codeslash-dev/SLASHED) cascade-layer CSS framework with [Bricks Builder](https://bricksbuilder.io/). + +## Features + +- **CSS Loading** - Automatically enqueues the SLASHED CSS bundle on the frontend and within the Bricks editor iframe +- **Variable Pickers** - Registers all 587+ SLASHED CSS custom properties for use in Bricks variable pickers and the code editor autocomplete +- **Class Autocomplete** - All `.sf-*` layout classes and `.is-*` state classes appear in the Bricks class input with organized categories +- **Color Palette** - Synchronizes SLASHED color tokens (brand scales, status, and semantic colors) with the Bricks global color palette + +## Requirements + +- WordPress 6.0+ +- PHP 7.4+ +- Bricks Builder 1.9.2+ +- SLASHED CSS framework (included via the `dist/slashed.optimal.css` bundle) + +## Installation + +### Option A: Copy to plugins directory + +Copy the `integrations/bricks/` folder to your WordPress plugins directory: + +```bash +cp -r integrations/bricks /path/to/wp-content/plugins/slashed-bricks +``` + +### Option B: Symlink (for development) + +```bash +ln -s /path/to/SLASHED/integrations/bricks /path/to/wp-content/plugins/slashed-bricks +``` + +Then activate the plugin in **WordPress Admin > Plugins**. + +## Configuration + +The plugin works out of the box with sensible defaults. All behavior can be customized via WordPress filter hooks. + +### Filter Hooks + +#### `slashed_bricks/css_bundle_url` + +Override which CSS bundle URL to load. + +```php +add_filter( 'slashed_bricks/css_bundle_url', function( $url ) { + // Load from a CDN instead. + return 'https://cdn.example.com/slashed/slashed.optimal.css'; +} ); +``` + +#### `slashed_bricks/registered_classes` + +Filter the array of classes before registration with Bricks. + +```php +add_filter( 'slashed_bricks/registered_classes', function( $classes ) { + // Remove state classes. + return array_filter( $classes, function( $class ) { + return $class['category'] !== 'SLASHED State'; + } ); +} ); +``` + +#### `slashed_bricks/registered_colors` + +Filter the colors array before registration with Bricks. + +```php +add_filter( 'slashed_bricks/registered_colors', function( $colors ) { + // Only keep brand colors, remove semantic. + return array_filter( $colors, function( $color ) { + return strpos( $color['category'], 'Semantic' ) === false; + } ); +} ); +``` + +#### `slashed_bricks/registered_variables` + +Filter the CSS variables array before registration with Bricks. + +```php +add_filter( 'slashed_bricks/registered_variables', function( $variables ) { + // Remove z-index variables. + unset( $variables['Z-Index'] ); + return $variables; +} ); +``` + +#### `slashed_bricks/color_categories` + +Filter which color categories to include in the palette. + +```php +add_filter( 'slashed_bricks/color_categories', function( $categories ) { + // Only include primary and secondary brand palettes. + return array_intersect_key( $categories, array_flip( [ + 'SLASHED Primary', + 'SLASHED Secondary', + ] ) ); +} ); +``` + +## Architecture + +``` +integrations/bricks/ + slashed-bricks.php Main plugin bootstrap (guards, constants, loader) + includes/class-enqueue.php CSS enqueue for frontend + editor iframe + includes/class-variables.php Variable registration for builder pickers + includes/class-classes.php Class registration for autocomplete + includes/class-colors.php Color palette synchronization + assets/editor.css Minimal editor panel styling + README.md This file +``` + +### How It Works + +1. **Bootstrap** (`slashed-bricks.php`) - Checks that Bricks is active, defines constants, and loads class files. + +2. **Enqueue** (`class-enqueue.php`) - Hooks into `wp_enqueue_scripts` to load the SLASHED CSS bundle. Since Bricks fires `wp_enqueue_scripts` in its editor iframe context, this single hook covers both frontend and builder preview. + +3. **Variables** (`class-variables.php`) - Registers organized variable groups via `bricks/builder/i18n` and provides code editor autocomplete data via `bricks/code/get_code_signatures`. + +4. **Classes** (`class-classes.php`) - Registers all layout and state classes as locked global classes via `bricks/setup/control_options`, making them available in the class picker with categorized organization. + +5. **Colors** (`class-colors.php`) - Injects color entries into the Bricks global color palette via `bricks/setup/control_options`. Colors reference CSS variables (`var(--sf-color-*)`) rather than hardcoded values, so they adapt to theme customization and dark mode. + +## CSS Bundle + +By default, the plugin loads `dist/slashed.optimal.css` from the SLASHED framework directory (resolved relative to the plugin location). This is the recommended bundle that includes core tokens, layout primitives, states, and optional palette tokens. + +To load a different bundle (e.g., the minimal `dist/slashed.essential.css` or the full `dist/slashed.full.css`), use the `slashed_bricks/css_bundle_url` filter. + +## License + +MIT - Same as the SLASHED framework. diff --git a/integrations/bricks/assets/editor.css b/integrations/bricks/assets/editor.css new file mode 100644 index 00000000..bd630018 --- /dev/null +++ b/integrations/bricks/assets/editor.css @@ -0,0 +1,18 @@ +/** + * SLASHED for Bricks - Editor Panel Styles + * + * Minimal styling for SLASHED entries in the Bricks Builder panel. + * Loaded only in the admin editor context, not on the frontend. + */ + +/* Style SLASHED variable group headers in the panel */ +[data-slashed-group] { + font-weight: 600; + color: #1e293b; +} + +/* Improve readability of SLASHED class entries */ +.brx-body .slashed-class-item { + font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace; + font-size: 0.85em; +} diff --git a/integrations/bricks/includes/class-classes.php b/integrations/bricks/includes/class-classes.php new file mode 100644 index 00000000..aa3fe5c5 --- /dev/null +++ b/integrations/bricks/includes/class-classes.php @@ -0,0 +1,309 @@ +get_classes(); + + if ( ! isset( $control_options['globalClassesLocked'] ) ) { + $control_options['globalClassesLocked'] = array(); + } + + foreach ( $classes as $class_entry ) { + $control_options['globalClassesLocked'][] = $class_entry; + } + + return $control_options; + } + + /** + * Get all SLASHED classes formatted for Bricks. + * + * @return array Array of class entries. + */ + public function get_classes() { + $classes = array(); + + // Layout classes. + $layout = $this->get_layout_classes(); + foreach ( $layout as $class_name ) { + $classes[] = array( + 'id' => $class_name, + 'name' => $class_name, + 'settings' => array( 'locked' => true ), + 'category' => 'SLASHED Layout', + ); + } + + // State classes. + $states = $this->get_state_classes(); + foreach ( $states as $class_name ) { + $classes[] = array( + 'id' => $class_name, + 'name' => $class_name, + 'settings' => array( 'locked' => true ), + 'category' => 'SLASHED State', + ); + } + + /** + * Filter the registered classes before passing to Bricks. + * + * @param array $classes Array of class entry arrays. + */ + return apply_filters( 'slashed_bricks/registered_classes', $classes ); + } + + /** + * Get all SLASHED layout classes. + * + * @return array + */ + private function get_layout_classes() { + return array( + // Section. + 'sf-section', + 'sf-section--s', + 'sf-section--m', + 'sf-section--l', + 'sf-section--xl', + 'sf-section-group', + + // Divider. + 'sf-divider', + 'sf-divider--vertical', + + // Container. + 'sf-container', + 'sf-container--narrow', + 'sf-container--prose', + 'sf-container--wide', + 'sf-container--full', + + // Stack. + 'sf-stack', + 'sf-stack--2xs', + 'sf-stack--xs', + 'sf-stack--s', + 'sf-stack--m', + 'sf-stack--l', + 'sf-stack--xl', + 'sf-stack--2xl', + 'sf-stack--3xl', + 'sf-stack--center', + 'sf-stack--end', + 'sf-stack--stretch', + + // Box. + 'sf-box', + + // Center. + 'sf-center', + 'sf-center--intrinsic', + + // Cluster. + 'sf-cluster', + 'sf-cluster--2xs', + 'sf-cluster--xs', + 'sf-cluster--s', + 'sf-cluster--m', + 'sf-cluster--l', + 'sf-cluster--xl', + 'sf-cluster--no-wrap', + 'sf-cluster--center', + 'sf-cluster--end', + 'sf-cluster--between', + + // Sidebar. + 'sf-sidebar', + 'sf-sidebar--right', + 'sf-sidebar--narrow', + 'sf-sidebar--wide', + + // Switcher. + 'sf-switcher', + 'sf-switcher--no-wrap', + 'sf-switcher--vertical', + + // Grid. + 'sf-grid', + 'sf-grid--fit', + 'sf-grid--xs', + 'sf-grid--s', + 'sf-grid--m', + 'sf-grid--l', + 'sf-grid--xl', + 'sf-grid--dense', + 'sf-grid-1', + 'sf-grid-2', + 'sf-grid-3', + 'sf-grid-4', + 'sf-grid-6', + 'sf-grid-1-2', + 'sf-grid-2-1', + 'sf-grid-1-3', + 'sf-grid-3-1', + + // Icon. + 'sf-icon', + 'sf-icon--xs', + 'sf-icon--s', + 'sf-icon--m', + 'sf-icon--l', + 'sf-icon--xl', + + // Cover. + 'sf-cover', + 'sf-cover__center', + 'sf-cover--min', + 'sf-cover--max', + 'sf-cover--padding-s', + 'sf-cover--padding-l', + + // Frame. + 'sf-frame', + 'sf-frame--square', + 'sf-frame--video', + 'sf-frame--cinema', + 'sf-frame--portrait', + 'sf-frame--4-3', + 'sf-frame--3-2', + 'sf-frame--golden', + + // Reel. + 'sf-reel', + + // Imposter. + 'sf-imposter', + 'sf-imposter--fixed', + 'sf-imposter--contain', + + // Alternate. + 'sf-alternate', + + // Pancake. + 'sf-pancake', + + // Bento. + 'sf-bento', + 'sf-bento--2', + 'sf-bento--4', + 'sf-bento--compact', + 'sf-bento--tall', + + // Subgrid. + 'sf-subgrid', + 'sf-subgrid-rows', + + // Prose. + 'sf-prose', + 'sf-not-prose', + + // Content Grid. + 'sf-content-grid', + 'sf-breakout', + 'sf-full-bleed', + ); + } + + /** + * Get all SLASHED state classes. + * + * @return array + */ + private function get_state_classes() { + return array( + // Visibility. + 'is-hidden', + 'is-invisible', + 'is-visible', + + // Interactivity. + 'is-disabled', + 'is-readonly', + + // Loading. + 'is-loading', + 'is-busy', + 'is-pending', + 'is-skeleton', + + // Active. + 'is-active', + 'is-selected', + 'is-current', + 'is-highlighted', + 'is-pressed', + + // Disclosure. + 'is-open', + 'is-collapsed', + 'is-expanded', + + // Validation. + 'is-valid', + 'is-invalid', + 'is-warning', + 'is-success', + 'is-error', + 'is-info', + 'is-danger', + + // Position. + 'is-sticky', + 'is-pinned', + 'is-fixed', + 'is-fullscreen', + 'is-resizable', + + // Overflow. + 'is-clipped', + 'is-scrollable', + 'is-truncated', + + // Drag. + 'is-dragging', + 'is-drop-target', + 'is-draggable', + + // Overlay. + 'is-overlay', + + // Focus. + 'is-clickable', + 'is-unselectable', + 'is-focused', + + // Empty. + 'is-empty', + ); + } +} diff --git a/integrations/bricks/includes/class-colors.php b/integrations/bricks/includes/class-colors.php new file mode 100644 index 00000000..5c133b84 --- /dev/null +++ b/integrations/bricks/includes/class-colors.php @@ -0,0 +1,160 @@ +get_colors(); + + if ( ! isset( $control_options['globalColors'] ) ) { + $control_options['globalColors'] = array(); + } + + foreach ( $colors as $color_entry ) { + $control_options['globalColors'][] = $color_entry; + } + + return $control_options; + } + + /** + * Get all SLASHED colors formatted for Bricks. + * + * @return array Array of color entries. + */ + public function get_colors() { + $colors = array(); + $categories = $this->get_color_categories(); + + /** + * Filter which color categories to include. + * + * @param array $categories Associative array of category => color definitions. + */ + $categories = apply_filters( 'slashed_bricks/color_categories', $categories ); + + foreach ( $categories as $category => $category_colors ) { + foreach ( $category_colors as $color ) { + $color['category'] = $category; + $colors[] = $color; + } + } + + /** + * Filter the registered colors before passing to Bricks. + * + * @param array $colors Array of color entry arrays. + */ + return apply_filters( 'slashed_bricks/registered_colors', $colors ); + } + + /** + * Get color categories with their color definitions. + * + * @return array + */ + private function get_color_categories() { + $categories = array(); + + // Brand colors with palette scales. + $brands = array( 'primary', 'secondary', 'tertiary', 'action', 'neutral', 'base' ); + $scale = array( '50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950' ); + + foreach ( $brands as $brand ) { + $category_name = 'SLASHED ' . ucfirst( $brand ); + $brand_colors = array(); + + // Base color. + $brand_colors[] = array( + 'id' => 'sf-' . $brand, + 'name' => 'SF ' . ucfirst( $brand ), + 'color' => array( 'hex' => 'var(--sf-color-' . $brand . ')' ), + ); + + // Scale colors. + foreach ( $scale as $step ) { + $brand_colors[] = array( + 'id' => 'sf-' . $brand . '-' . $step, + 'name' => 'SF ' . ucfirst( $brand ) . ' ' . $step, + 'color' => array( 'hex' => 'var(--sf-color-' . $brand . '-' . $step . ')' ), + ); + } + + $categories[ $category_name ] = $brand_colors; + } + + // Status colors. + $status_colors = array(); + $statuses = array( 'success', 'warning', 'error', 'info', 'danger' ); + + foreach ( $statuses as $status ) { + $status_colors[] = array( + 'id' => 'sf-' . $status, + 'name' => 'SF ' . ucfirst( $status ), + 'color' => array( 'hex' => 'var(--sf-color-' . $status . ')' ), + ); + } + + $categories['SLASHED Status'] = $status_colors; + + // Semantic colors. + $semantic_colors = array(); + $semantic_map = array( + 'text' => 'Text', + 'text--secondary' => 'Text Secondary', + 'text--muted' => 'Text Muted', + 'heading' => 'Heading', + 'bg' => 'Background', + 'surface' => 'Surface', + 'well' => 'Well', + 'raised' => 'Raised', + 'overlay' => 'Overlay', + 'inverse' => 'Inverse', + 'border' => 'Border', + 'border--subtle' => 'Border Subtle', + 'border--strong' => 'Border Strong', + 'link' => 'Link', + 'link--hover' => 'Link Hover', + 'link--active' => 'Link Active', + 'link--visited' => 'Link Visited', + ); + + foreach ( $semantic_map as $token => $label ) { + $semantic_colors[] = array( + 'id' => 'sf-' . str_replace( '--', '-', $token ), + 'name' => 'SF ' . $label, + 'color' => array( 'hex' => 'var(--sf-color-' . $token . ')' ), + ); + } + + $categories['SLASHED Semantic'] = $semantic_colors; + + return $categories; + } +} diff --git a/integrations/bricks/includes/class-enqueue.php b/integrations/bricks/includes/class-enqueue.php new file mode 100644 index 00000000..97269de6 --- /dev/null +++ b/integrations/bricks/includes/class-enqueue.php @@ -0,0 +1,71 @@ + variables. + */ + public function get_variables() { + $variables = array( + 'Colors' => $this->get_color_variables(), + 'Spacing' => $this->get_spacing_variables(), + 'Typography' => $this->get_typography_variables(), + 'Layout' => $this->get_layout_variables(), + 'Radius' => $this->get_radius_variables(), + 'Shadows' => $this->get_shadow_variables(), + 'Motion' => $this->get_motion_variables(), + 'Z-Index' => $this->get_z_index_variables(), + ); + + /** + * Filter the registered CSS variables. + * + * @param array $variables Associative array of category => variable names. + */ + return apply_filters( 'slashed_bricks/registered_variables', $variables ); + } + + /** + * Register variable group labels with Bricks i18n. + * + * @param array $i18n Existing i18n strings. + * @return array Modified i18n strings. + */ + public function register_variable_groups( $i18n ) { + $variables = $this->get_variables(); + + foreach ( $variables as $category => $vars ) { + $i18n[ 'slashed_' . sanitize_key( $category ) ] = 'SLASHED ' . $category; + } + + return $i18n; + } + + /** + * Register variables for code editor autocomplete. + * + * @param array $signatures Existing code signatures. + * @return array Modified code signatures. + */ + public function register_code_signatures( $signatures ) { + $variables = $this->get_variables(); + + $css_vars = array(); + foreach ( $variables as $category => $vars ) { + foreach ( $vars as $var ) { + $css_vars[] = array( + 'label' => $var, + 'detail' => 'SLASHED ' . $category, + 'type' => 'variable', + ); + } + } + + if ( ! isset( $signatures['css'] ) ) { + $signatures['css'] = array(); + } + + $signatures['css']['slashed_variables'] = $css_vars; + + return $signatures; + } + + /** + * Get color-related CSS variables. + * + * @return array + */ + private function get_color_variables() { + $colors = array(); + $brands = array( 'primary', 'secondary', 'tertiary', 'action', 'neutral', 'base' ); + $status = array( 'success', 'warning', 'error', 'info', 'danger' ); + + // Brand colors - base + scale. + foreach ( $brands as $brand ) { + $colors[] = '--sf-color-' . $brand; + foreach ( array( '50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950' ) as $step ) { + $colors[] = '--sf-color-' . $brand . '-' . $step; + } + } + + // Status colors. + foreach ( $status as $s ) { + $colors[] = '--sf-color-' . $s; + $colors[] = '--sf-color-' . $s . '-subtle'; + $colors[] = '--sf-color-' . $s . '-strong'; + $colors[] = '--sf-color-' . $s . '-muted'; + } + + // Semantic colors. + $semantic = array( + 'text', 'text--secondary', 'text--muted', 'heading', + 'bg', 'surface', 'well', 'raised', 'overlay', 'inverse', + 'border', 'border--subtle', 'border--strong', + 'link', 'link--hover', 'link--active', 'link--visited', + ); + foreach ( $semantic as $s ) { + $colors[] = '--sf-color-' . $s; + } + + return $colors; + } + + /** + * Get spacing-related CSS variables. + * + * @return array + */ + private function get_spacing_variables() { + $sizes = array( '3xs', '2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl' ); + $vars = array(); + + foreach ( $sizes as $size ) { + $vars[] = '--sf-space-' . $size; + } + + $vars[] = '--sf-gap'; + $vars[] = '--sf-content-gap'; + $vars[] = '--sf-component-pad'; + $vars[] = '--sf-space-gutter'; + $vars[] = '--sf-section-pad'; + + return $vars; + } + + /** + * Get typography-related CSS variables. + * + * @return array + */ + private function get_typography_variables() { + $sizes = array( '2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl', '4xl', '5xl' ); + $vars = array(); + + foreach ( $sizes as $size ) { + $vars[] = '--sf-text-' . $size; + } + + $vars[] = '--sf-font-sans'; + $vars[] = '--sf-font-serif'; + $vars[] = '--sf-font-mono'; + $vars[] = '--sf-font-weight-normal'; + $vars[] = '--sf-font-weight-medium'; + $vars[] = '--sf-font-weight-semibold'; + $vars[] = '--sf-font-weight-bold'; + $vars[] = '--sf-leading-tight'; + $vars[] = '--sf-leading-snug'; + $vars[] = '--sf-leading-normal'; + $vars[] = '--sf-leading-relaxed'; + $vars[] = '--sf-leading-loose'; + $vars[] = '--sf-tracking-tight'; + $vars[] = '--sf-tracking-normal'; + $vars[] = '--sf-tracking-wide'; + + return $vars; + } + + /** + * Get layout-related CSS variables. + * + * @return array + */ + private function get_layout_variables() { + return array( + '--sf-container-narrow', + '--sf-container-default', + '--sf-container-wide', + '--sf-container-full', + '--sf-stack-gap', + '--sf-cluster-gap', + '--sf-cluster-align', + '--sf-cluster-justify', + '--sf-sidebar-gap', + '--sf-sidebar-min-width', + '--sf-sidebar-width-default', + '--sf-switcher-threshold', + '--sf-switcher-gap', + '--sf-grid-min', + '--sf-grid-gap', + '--sf-cover-min-height', + '--sf-cover-padding', + '--sf-frame-ratio', + '--sf-reel-item-width', + '--sf-reel-gap', + '--sf-reel-height', + '--sf-imposter-margin', + '--sf-bento-gap', + '--sf-breakout-width', + '--sf-content-width', + '--sf-prose-paragraph', + '--sf-box-padding', + '--sf-box-border-width', + '--sf-box-border-color', + '--sf-center-max', + '--sf-center-gutter', + ); + } + + /** + * Get radius-related CSS variables. + * + * @return array + */ + private function get_radius_variables() { + return array( + '--sf-radius-xs', + '--sf-radius-s', + '--sf-radius-m', + '--sf-radius-l', + '--sf-radius-xl', + '--sf-radius-full', + ); + } + + /** + * Get shadow-related CSS variables. + * + * @return array + */ + private function get_shadow_variables() { + return array( + '--sf-shadow-xs', + '--sf-shadow-s', + '--sf-shadow-m', + '--sf-shadow-l', + '--sf-shadow-xl', + ); + } + + /** + * Get motion/transition-related CSS variables. + * + * @return array + */ + private function get_motion_variables() { + return array( + '--sf-duration-fast', + '--sf-duration-normal', + '--sf-duration-slow', + '--sf-ease-in', + '--sf-ease-out', + '--sf-ease-in-out', + '--sf-transition-fast', + '--sf-transition-normal', + '--sf-transition-slow', + ); + } + + /** + * Get z-index CSS variables. + * + * @return array + */ + private function get_z_index_variables() { + return array( + '--sf-z-base', + '--sf-z-dropdown', + '--sf-z-sticky', + '--sf-z-fixed', + '--sf-z-modal', + '--sf-z-popover', + '--sf-z-tooltip', + '--sf-z-toast', + ); + } +} diff --git a/integrations/bricks/slashed-bricks.php b/integrations/bricks/slashed-bricks.php new file mode 100644 index 00000000..d1f7da5c --- /dev/null +++ b/integrations/bricks/slashed-bricks.php @@ -0,0 +1,96 @@ +get( 'Name' ) ) || 'bricks' === strtolower( $theme->get_template() ) ) { + return true; + } + + if ( defined( 'BRICKS_VERSION' ) ) { + return true; + } + + return false; +} + +/** + * Initialize the plugin. + */ +function slashed_bricks_init() { + if ( ! slashed_bricks_is_bricks_active() ) { + add_action( 'admin_notices', 'slashed_bricks_missing_bricks_notice' ); + return; + } + + require_once SLASHED_BRICKS_PATH . 'includes/class-enqueue.php'; + require_once SLASHED_BRICKS_PATH . 'includes/class-variables.php'; + require_once SLASHED_BRICKS_PATH . 'includes/class-classes.php'; + require_once SLASHED_BRICKS_PATH . 'includes/class-colors.php'; + + new Slashed_Bricks_Enqueue(); + new Slashed_Bricks_Variables(); + new Slashed_Bricks_Classes(); + new Slashed_Bricks_Colors(); +} +add_action( 'after_setup_theme', 'slashed_bricks_init' ); + +/** + * Display admin notice when Bricks Builder is not active. + */ +function slashed_bricks_missing_bricks_notice() { + ?> +
+

+ SLASHED for Bricks requires Bricks Builder to be installed and active. +

+
+ Date: Sat, 23 May 2026 13:41:29 +0000 Subject: [PATCH 2/5] fix: correct CSS variable names in Bricks integration to match actual SLASHED tokens Co-authored-by: Jack Granatowski --- .../bricks/includes/class-variables.php | 99 ++++++++++++++++--- 1 file changed, 85 insertions(+), 14 deletions(-) diff --git a/integrations/bricks/includes/class-variables.php b/integrations/bricks/includes/class-variables.php index 505183e8..eaa566bc 100644 --- a/integrations/bricks/includes/class-variables.php +++ b/integrations/bricks/includes/class-variables.php @@ -111,6 +111,21 @@ private function get_color_variables() { foreach ( array( '50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950' ) as $step ) { $colors[] = '--sf-color-' . $brand . '-' . $step; } + + // Functional aliases. + $colors[] = '--sf-color-' . $brand . '-hover'; + $colors[] = '--sf-color-' . $brand . '-active'; + $colors[] = '--sf-color-' . $brand . '-subtle'; + $colors[] = '--sf-color-' . $brand . '-muted'; + $colors[] = '--sf-color-' . $brand . '-ghost'; + + // Shade aliases. + $colors[] = '--sf-color-' . $brand . '-superlight'; + $colors[] = '--sf-color-' . $brand . '-xlight'; + $colors[] = '--sf-color-' . $brand . '-lighter'; + $colors[] = '--sf-color-' . $brand . '-darker'; + $colors[] = '--sf-color-' . $brand . '-xdark'; + $colors[] = '--sf-color-' . $brand . '-superdark'; } // Status colors. @@ -124,9 +139,17 @@ private function get_color_variables() { // Semantic colors. $semantic = array( 'text', 'text--secondary', 'text--muted', 'heading', + 'text--placeholder', 'text--disabled', 'text--inverse', + 'text--on-primary', 'text--on-secondary', 'text--on-tertiary', + 'text--on-action', 'text--on-neutral', 'text--on-base', 'bg', 'surface', 'well', 'raised', 'overlay', 'inverse', + 'bg--hover', 'bg--active', 'bg--selected', 'bg--focus', 'bg--disabled', 'border', 'border--subtle', 'border--strong', + 'border--focus', 'border--disabled', 'border--translucent', 'link', 'link--hover', 'link--active', 'link--visited', + 'link--underline', 'link--disabled', + 'code-bg', 'code-text', + 'selection-bg', 'mark-bg', 'dim', ); foreach ( $semantic as $s ) { $colors[] = '--sf-color-' . $s; @@ -141,7 +164,7 @@ private function get_color_variables() { * @return array */ private function get_spacing_variables() { - $sizes = array( '3xs', '2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl' ); + $sizes = array( 'none', 'px', '2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl', '4xl' ); $vars = array(); foreach ( $sizes as $size ) { @@ -163,28 +186,50 @@ private function get_spacing_variables() { * @return array */ private function get_typography_variables() { - $sizes = array( '2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl', '4xl', '5xl' ); + $sizes = array( '2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl', '4xl' ); $vars = array(); foreach ( $sizes as $size ) { $vars[] = '--sf-text-' . $size; } - $vars[] = '--sf-font-sans'; - $vars[] = '--sf-font-serif'; + // Display sizes. + $vars[] = '--sf-text-display-s'; + $vars[] = '--sf-text-display-m'; + $vars[] = '--sf-text-display-l'; + + // Font families. + $vars[] = '--sf-font-body'; + $vars[] = '--sf-font-heading'; $vars[] = '--sf-font-mono'; + $vars[] = '--sf-font-display'; + $vars[] = '--sf-font-humanist'; + $vars[] = '--sf-font-geometric'; + $vars[] = '--sf-font-slab'; + + // Font weights. + $vars[] = '--sf-font-weight-thin'; + $vars[] = '--sf-font-weight-extralight'; + $vars[] = '--sf-font-weight-light'; $vars[] = '--sf-font-weight-normal'; $vars[] = '--sf-font-weight-medium'; $vars[] = '--sf-font-weight-semibold'; $vars[] = '--sf-font-weight-bold'; + $vars[] = '--sf-font-weight-extrabold'; + $vars[] = '--sf-font-weight-black'; + + // Leading. $vars[] = '--sf-leading-tight'; $vars[] = '--sf-leading-snug'; $vars[] = '--sf-leading-normal'; $vars[] = '--sf-leading-relaxed'; - $vars[] = '--sf-leading-loose'; + + // Tracking. $vars[] = '--sf-tracking-tight'; $vars[] = '--sf-tracking-normal'; $vars[] = '--sf-tracking-wide'; + $vars[] = '--sf-tracking-wider'; + $vars[] = '--sf-tracking-widest'; return $vars; } @@ -237,11 +282,15 @@ private function get_layout_variables() { */ private function get_radius_variables() { return array( + '--sf-radius-none', '--sf-radius-xs', '--sf-radius-s', '--sf-radius-m', '--sf-radius-l', '--sf-radius-xl', + '--sf-radius-2xl', + '--sf-radius-3xl', + '--sf-radius-4xl', '--sf-radius-full', ); } @@ -253,11 +302,14 @@ private function get_radius_variables() { */ private function get_shadow_variables() { return array( + '--sf-shadow-none', '--sf-shadow-xs', '--sf-shadow-s', '--sf-shadow-m', '--sf-shadow-l', '--sf-shadow-xl', + '--sf-shadow-2xl', + '--sf-shadow-inner', ); } @@ -268,15 +320,34 @@ private function get_shadow_variables() { */ private function get_motion_variables() { return array( + // Durations. + '--sf-duration-none', + '--sf-duration-instant', '--sf-duration-fast', '--sf-duration-normal', '--sf-duration-slow', - '--sf-ease-in', + '--sf-duration-slower', + + // Easings. + '--sf-ease-linear', '--sf-ease-out', + '--sf-ease-in', '--sf-ease-in-out', + '--sf-ease-spring', + '--sf-ease-elastic', + '--sf-ease-bounce', + '--sf-ease-overshoot', + + // Transitions. + '--sf-transition-all', + '--sf-transition-colors', + '--sf-transition-transform', + '--sf-transition-opacity', + '--sf-transition-shadow', '--sf-transition-fast', - '--sf-transition-normal', '--sf-transition-slow', + '--sf-transition-enter', + '--sf-transition-exit', ); } @@ -287,14 +358,14 @@ private function get_motion_variables() { */ private function get_z_index_variables() { return array( + '--sf-z-below', '--sf-z-base', - '--sf-z-dropdown', - '--sf-z-sticky', - '--sf-z-fixed', - '--sf-z-modal', - '--sf-z-popover', - '--sf-z-tooltip', - '--sf-z-toast', + '--sf-z-raised', + '--sf-z-low', + '--sf-z-mid', + '--sf-z-high', + '--sf-z-top', + '--sf-z-max', ); } } From 56c98b1e57522ea4a36c24910f3c9ca506b38406 Mon Sep 17 00:00:00 2001 From: Kiro Agent <244629292+kiro-agent@users.noreply.github.com> Date: Sat, 23 May 2026 13:47:25 +0000 Subject: [PATCH 3/5] fix: address semantic review issues in Bricks integration - Fix CSS bundle URL to check both symlink and copy-install paths - Use 'raw' instead of 'hex' for color entries with var() references - Replace editor.css non-existent selectors with empty placeholder - Add filemtime-based cache-busting for CSS bundle version - Add docblock explaining variable picker mechanism in class-variables - Update README with copy-install CSS bundle instructions Co-authored-by: Jack Granatowski --- integrations/bricks/README.md | 18 ++++++++++++ integrations/bricks/assets/editor.css | 20 ++++--------- integrations/bricks/includes/class-colors.php | 11 ++++--- .../bricks/includes/class-enqueue.php | 14 ++++++++- .../bricks/includes/class-variables.php | 6 ++++ integrations/bricks/slashed-bricks.php | 29 +++++++++++++++++-- 6 files changed, 76 insertions(+), 22 deletions(-) diff --git a/integrations/bricks/README.md b/integrations/bricks/README.md index 3be5aad2..8b7f3caf 100644 --- a/integrations/bricks/README.md +++ b/integrations/bricks/README.md @@ -26,6 +26,24 @@ Copy the `integrations/bricks/` folder to your WordPress plugins directory: cp -r integrations/bricks /path/to/wp-content/plugins/slashed-bricks ``` +When using this method, the plugin cannot automatically locate the SLASHED CSS bundle. +You have two options: + +1. **Copy the `dist/` folder** into the plugin directory so the bundle is available at + `wp-content/plugins/slashed-bricks/dist/slashed.optimal.css`: + + ```bash + cp -r dist /path/to/wp-content/plugins/slashed-bricks/dist + ``` + +2. **Use the filter** to point to a CDN or another location: + + ```php + add_filter( 'slashed_bricks/css_bundle_url', function() { + return 'https://cdn.example.com/slashed/slashed.optimal.css'; + } ); + ``` + ### Option B: Symlink (for development) ```bash diff --git a/integrations/bricks/assets/editor.css b/integrations/bricks/assets/editor.css index bd630018..5eabab01 100644 --- a/integrations/bricks/assets/editor.css +++ b/integrations/bricks/assets/editor.css @@ -1,18 +1,10 @@ /** * SLASHED for Bricks - Editor Panel Styles * - * Minimal styling for SLASHED entries in the Bricks Builder panel. - * Loaded only in the admin editor context, not on the frontend. + * This stylesheet is loaded in the Bricks admin editor context. + * Add custom styles here to adjust the appearance of SLASHED + * entries in the builder panel (e.g., variable groups, class items). + * + * Currently empty - the plugin relies on Bricks' native styling + * for registered classes, colors, and variables. */ - -/* Style SLASHED variable group headers in the panel */ -[data-slashed-group] { - font-weight: 600; - color: #1e293b; -} - -/* Improve readability of SLASHED class entries */ -.brx-body .slashed-class-item { - font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace; - font-size: 0.85em; -} diff --git a/integrations/bricks/includes/class-colors.php b/integrations/bricks/includes/class-colors.php index 5c133b84..94607b5b 100644 --- a/integrations/bricks/includes/class-colors.php +++ b/integrations/bricks/includes/class-colors.php @@ -13,6 +13,9 @@ * Class Slashed_Bricks_Colors * * Registers SLASHED color tokens with Bricks Builder's global color palette. + * + * Note: The 'raw' color type (used instead of 'hex' for var() references) + * requires Bricks 1.9.2+. Older versions may not render swatches correctly. */ class Slashed_Bricks_Colors { @@ -94,7 +97,7 @@ private function get_color_categories() { $brand_colors[] = array( 'id' => 'sf-' . $brand, 'name' => 'SF ' . ucfirst( $brand ), - 'color' => array( 'hex' => 'var(--sf-color-' . $brand . ')' ), + 'color' => array( 'raw' => 'var(--sf-color-' . $brand . ')' ), ); // Scale colors. @@ -102,7 +105,7 @@ private function get_color_categories() { $brand_colors[] = array( 'id' => 'sf-' . $brand . '-' . $step, 'name' => 'SF ' . ucfirst( $brand ) . ' ' . $step, - 'color' => array( 'hex' => 'var(--sf-color-' . $brand . '-' . $step . ')' ), + 'color' => array( 'raw' => 'var(--sf-color-' . $brand . '-' . $step . ')' ), ); } @@ -117,7 +120,7 @@ private function get_color_categories() { $status_colors[] = array( 'id' => 'sf-' . $status, 'name' => 'SF ' . ucfirst( $status ), - 'color' => array( 'hex' => 'var(--sf-color-' . $status . ')' ), + 'color' => array( 'raw' => 'var(--sf-color-' . $status . ')' ), ); } @@ -149,7 +152,7 @@ private function get_color_categories() { $semantic_colors[] = array( 'id' => 'sf-' . str_replace( '--', '-', $token ), 'name' => 'SF ' . $label, - 'color' => array( 'hex' => 'var(--sf-color-' . $token . ')' ), + 'color' => array( 'raw' => 'var(--sf-color-' . $token . ')' ), ); } diff --git a/integrations/bricks/includes/class-enqueue.php b/integrations/bricks/includes/class-enqueue.php index 97269de6..86074477 100644 --- a/integrations/bricks/includes/class-enqueue.php +++ b/integrations/bricks/includes/class-enqueue.php @@ -37,11 +37,23 @@ public function __construct() { public function enqueue_frontend_styles() { $css_url = slashed_bricks_get_css_url(); + // Use file modification time for cache-busting when the CSS exists locally. + $repo_path = SLASHED_BRICKS_PATH . '../../dist/slashed.optimal.css'; + $local_path = SLASHED_BRICKS_PATH . 'dist/slashed.optimal.css'; + + if ( file_exists( $repo_path ) ) { + $version = (string) filemtime( $repo_path ); + } elseif ( file_exists( $local_path ) ) { + $version = (string) filemtime( $local_path ); + } else { + $version = SLASHED_BRICKS_VERSION; + } + wp_enqueue_style( 'slashed-framework', $css_url, array(), - SLASHED_BRICKS_VERSION + $version ); } diff --git a/integrations/bricks/includes/class-variables.php b/integrations/bricks/includes/class-variables.php index eaa566bc..2abc71e1 100644 --- a/integrations/bricks/includes/class-variables.php +++ b/integrations/bricks/includes/class-variables.php @@ -14,6 +14,12 @@ * * Registers SLASHED CSS custom properties with Bricks Builder * for variable pickers and code editor autocomplete. + * + * Bricks 1.9.2+ automatically detects CSS custom properties from stylesheets + * loaded in the editor iframe. This class provides additional organization + * (category labels via i18n) and code editor autocomplete (via code signatures). + * The primary variable picker population happens through CSS loading in + * class-enqueue.php. */ class Slashed_Bricks_Variables { diff --git a/integrations/bricks/slashed-bricks.php b/integrations/bricks/slashed-bricks.php index d1f7da5c..3550128c 100644 --- a/integrations/bricks/slashed-bricks.php +++ b/integrations/bricks/slashed-bricks.php @@ -26,13 +26,36 @@ /** * Get the URL for the SLASHED CSS bundle. * - * Resolves the path to dist/slashed.optimal.css relative to the plugin, - * or allows override via the 'slashed_bricks/css_bundle_url' filter. + * Resolves the path to dist/slashed.optimal.css by checking: + * 1. Symlink/in-repo mode: ../../dist/slashed.optimal.css relative to the plugin + * 2. Copy-install mode: dist/slashed.optimal.css within the plugin directory + * + * Falls back to an empty string (with a PHP notice) if neither location exists. + * Use the 'slashed_bricks/css_bundle_url' filter to override. * * @return string URL to the CSS bundle. */ function slashed_bricks_get_css_url() { - $default_url = SLASHED_BRICKS_URL . '../../dist/slashed.optimal.css'; + $default_url = ''; + + // Check symlink/in-repo mode first (../../dist/ relative to plugin). + $repo_path = SLASHED_BRICKS_PATH . '../../dist/slashed.optimal.css'; + if ( file_exists( $repo_path ) ) { + $default_url = SLASHED_BRICKS_URL . '../../dist/slashed.optimal.css'; + } + // Check copy-install mode (dist/ within the plugin directory). + elseif ( file_exists( SLASHED_BRICKS_PATH . 'dist/slashed.optimal.css' ) ) { + $default_url = SLASHED_BRICKS_URL . 'dist/slashed.optimal.css'; + } + // Neither location found. + else { + trigger_error( + 'SLASHED for Bricks: Could not locate slashed.optimal.css. ' + . 'Copy the dist/ folder into the plugin directory, or use the ' + . "'slashed_bricks/css_bundle_url' filter to specify the URL.", + E_USER_NOTICE + ); + } /** * Filter the SLASHED CSS bundle URL. From a00858ead3085f7f90cd92bf3b08a2293a64e7a8 Mon Sep 17 00:00:00 2001 From: Kiro Agent <244629292+kiro-agent@users.noreply.github.com> Date: Sat, 23 May 2026 15:01:03 +0000 Subject: [PATCH 4/5] fix: address PR review feedback - early return, version guard, activation hook --- .../bricks/includes/class-enqueue.php | 4 ++++ integrations/bricks/slashed-bricks.php | 20 +++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/integrations/bricks/includes/class-enqueue.php b/integrations/bricks/includes/class-enqueue.php index 86074477..1bdffa0c 100644 --- a/integrations/bricks/includes/class-enqueue.php +++ b/integrations/bricks/includes/class-enqueue.php @@ -37,6 +37,10 @@ public function __construct() { public function enqueue_frontend_styles() { $css_url = slashed_bricks_get_css_url(); + if ( '' === $css_url ) { + return; + } + // Use file modification time for cache-busting when the CSS exists locally. $repo_path = SLASHED_BRICKS_PATH . '../../dist/slashed.optimal.css'; $local_path = SLASHED_BRICKS_PATH . 'dist/slashed.optimal.css'; diff --git a/integrations/bricks/slashed-bricks.php b/integrations/bricks/slashed-bricks.php index 3550128c..635f9796 100644 --- a/integrations/bricks/slashed-bricks.php +++ b/integrations/bricks/slashed-bricks.php @@ -72,13 +72,14 @@ function slashed_bricks_get_css_url() { */ function slashed_bricks_is_bricks_active() { $theme = wp_get_theme(); + $minimum_version = '1.9.2'; if ( 'bricks' === strtolower( $theme->get( 'Name' ) ) || 'bricks' === strtolower( $theme->get_template() ) ) { - return true; + return version_compare( (string) $theme->get( 'Version' ), $minimum_version, '>=' ); } if ( defined( 'BRICKS_VERSION' ) ) { - return true; + return version_compare( BRICKS_VERSION, $minimum_version, '>=' ); } return false; @@ -105,6 +106,21 @@ function slashed_bricks_init() { } add_action( 'after_setup_theme', 'slashed_bricks_init' ); +/** + * Activation check: ensure Bricks Builder 1.9.2+ is available. + */ +function slashed_bricks_activation_check() { + if ( ! slashed_bricks_is_bricks_active() ) { + deactivate_plugins( plugin_basename( __FILE__ ) ); + wp_die( + esc_html__( 'SLASHED for Bricks requires Bricks Builder 1.9.2 or higher to be installed and active.', 'slashed-bricks' ), + 'Plugin Activation Error', + array( 'back_link' => true ) + ); + } +} +register_activation_hook( __FILE__, 'slashed_bricks_activation_check' ); + /** * Display admin notice when Bricks Builder is not active. */ From 7657e0c5db7f0db3b3fd4b14f6347fce02e5292f Mon Sep 17 00:00:00 2001 From: Kiro Agent <244629292+kiro-agent@users.noreply.github.com> Date: Sat, 23 May 2026 15:18:02 +0000 Subject: [PATCH 5/5] fix: handle Bricks child theme version detection correctly --- integrations/bricks/slashed-bricks.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/integrations/bricks/slashed-bricks.php b/integrations/bricks/slashed-bricks.php index 635f9796..4ca465d0 100644 --- a/integrations/bricks/slashed-bricks.php +++ b/integrations/bricks/slashed-bricks.php @@ -74,12 +74,18 @@ function slashed_bricks_is_bricks_active() { $theme = wp_get_theme(); $minimum_version = '1.9.2'; - if ( 'bricks' === strtolower( $theme->get( 'Name' ) ) || 'bricks' === strtolower( $theme->get_template() ) ) { - return version_compare( (string) $theme->get( 'Version' ), $minimum_version, '>=' ); + if ( defined( 'BRICKS_VERSION' ) ) { + return version_compare( (string) BRICKS_VERSION, $minimum_version, '>=' ); } - if ( defined( 'BRICKS_VERSION' ) ) { - return version_compare( BRICKS_VERSION, $minimum_version, '>=' ); + if ( 'bricks' === strtolower( $theme->get_template() ) ) { + $parent = $theme->parent(); + $version = $parent ? (string) $parent->get( 'Version' ) : (string) $theme->get( 'Version' ); + return version_compare( $version, $minimum_version, '>=' ); + } + + if ( 'bricks' === strtolower( $theme->get( 'Name' ) ) ) { + return version_compare( (string) $theme->get( 'Version' ), $minimum_version, '>=' ); } return false;