Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Moved the majority of `assets/css/animations.css`'s structural (non-motion) CSS into `theme.json`/`styles/**` JSON block-style partials across buttons, cards, footer, header, mega menu, mobile menu, details/accordion, and links — leaving only real motion (transitions, transforms, `@keyframes`) and a small set of confirmed WordPress/JSON limitations (no `:hover`/`:focus` generation for arbitrary style variations, `@media`/`@supports` stripped from the `styles/**.json` `css` field, content referencing Sass variables) in Sass. `assets/css/animations.css` dropped from 2,003 to 1,444 lines (LS-2340).
- Eliminated 3 of 5 files under `src/scss/abstracts/mixins/` (`_mq.scss`, `_breakpoints-theme.scss`, `_glass.scss`) by inlining every remaining call-site as literal CSS; `_motion.scss` and `_surface.scss` remain only because the dead `gsap/_card-spotlight.scss` (tracked for removal on LS-2341) still references them. Removed the now-unneeded `sync:breakpoints` npm script and its `theme-utils.mjs` implementation.
- Consolidated 3 groups of byte-identical (or near-identical) hover/motion rules that had been duplicated once per consuming file — a shared circular icon-button hover contract (header search button, mobile-menu close button, footer proof-card, footer social-icon), a shared mega-menu-item row hover contract, and a shared frosted-glass `@supports` blur block — into one new partial, `src/scss/animations/_shared-hover.scss`.
- Fixed a render-order bug in `inc/portfolio-card-colors.php`: the WooCommerce card-colour swap now runs on `render_block_data` (before WordPress decides which block-style variation to generate CSS for) instead of `render_block` (which only edited the rendered HTML string after that decision was already made), so WooCommerce-tagged Portfolio cards no longer silently lose their intended styling.
- Renamed section-level patterns to lead with `section-` (`section-cta`, `section-cta-consultation-band`/`inline`/`reassurance`/`strip`, `section-card-feature`/`services`/`solutions`, `section-stats-grid`) to distinguish freely-insertable section patterns from full-page template patterns and page-scoped content patterns (LS-1226).
- Refactored `src/scss/animations.scss` and `src/scss/gsap-animations.scss` into loader entrypoints backed by smaller contextual partials, normalised live preset JSON onto WordPress shorthand for non-colour tokens, and removed the dead `settings.custom.button-padding` branch.
- Made `theme.json` custom layout breakpoints the build-time source for the Sass `mq()` map, and tightened the CSS build to compile only explicit Sass entry files so tracked source-directory CSS artefacts can no longer override live assets.
Expand Down
1,299 changes: 370 additions & 929 deletions assets/css/animations.css

Large diffs are not rendered by default.

78 changes: 11 additions & 67 deletions assets/css/gsap-animations.css
Original file line number Diff line number Diff line change
Expand Up @@ -69,73 +69,17 @@
transition: none;
}
}
/********** Home Hero Section **********/
/* Home Hero Section: background-only Group block style. */
.is-style-home-hero-section {
--ls-home-hero-surface: var(--wp--custom--color--surface--canvas);
--ls-home-hero-brand: var(--wp--custom--color--effect--hero--brand);
--ls-home-hero-cta: var(--wp--custom--color--effect--hero--cta);
--ls-home-hero-accent: var(--wp--custom--color--effect--hero--accent);
position: relative;
overflow: hidden;
isolation: isolate;
background: radial-gradient(circle at 16% 14%, color-mix(in srgb, var(--ls-home-hero-brand) 12%, transparent) 0%, transparent 34%), radial-gradient(circle at 84% 18%, color-mix(in srgb, var(--ls-home-hero-cta) 14%, transparent) 0%, transparent 28%), radial-gradient(circle at 50% 100%, color-mix(in srgb, var(--ls-home-hero-accent) 7%, transparent) 0%, transparent 36%), linear-gradient(180deg, color-mix(in srgb, var(--ls-home-hero-surface) 98%, var(--wp--custom--color--surface--highlight) 2%) 0%, var(--ls-home-hero-surface) 100%);
}
.is-style-home-hero-section > :not(.ls-home-hero-section__background) {
position: relative;
z-index: var(--wp--custom--z-index--content);
}

.ls-home-hero-section__background,
.ls-home-hero-section__network {
position: absolute;
inset: 0;
pointer-events: none;
overflow: hidden;
}

.ls-home-hero-section__background {
z-index: var(--wp--custom--z-index--base);
}

.ls-home-hero-section__network {
z-index: var(--wp--custom--z-index--content);
opacity: 0.92;
}

.ls-home-hero-section__orb {
position: absolute;
border-radius: 999px;
filter: blur(80px);
opacity: 0.8;
transform: translate3d(0, 0, 0);
will-change: transform;
z-index: var(--wp--custom--z-index--base);
}

.ls-home-hero-section__orb--brand {
top: 8%;
left: -8rem;
width: 24rem;
height: 24rem;
background: color-mix(in srgb, var(--ls-home-hero-brand) 24%, transparent);
}

.ls-home-hero-section__orb--cta {
right: -6rem;
bottom: 10%;
width: 20rem;
height: 20rem;
background: color-mix(in srgb, var(--ls-home-hero-cta) 22%, transparent);
}

.ls-home-hero-section__canvas {
display: block;
inline-size: 100%;
block-size: 100%;
}

/* Breakpoint names such as `tablet-portrait` are auto-generated from theme.json via the shared mq mixin setup. */
/********** Home Hero Section — responsive override **********/
/*
* JSON limitation: confirmed empirically (2026-08-11) that the styles/**.json `css` field does
* not support @media — WordPress's style engine strips the @media wrapper and leaks its
* declarations out unconditionally, applying them at every viewport instead of just this one.
* Everything else this component needs lives in styles/sections/home-hero-section.json.
*
* 767.98px mirrors settings.custom.layout.break-points.tablet-portrait (768px) in theme.json,
* offset by 0.02px so it stops just short of the next breakpoint — the same convention the
* retired src/scss/abstracts/mixins/_mq.scss mixin used to generate.
*/
@media (max-width: 767.98px) {
.ls-home-hero-section__network {
opacity: 1;
Expand Down
36 changes: 25 additions & 11 deletions inc/portfolio-card-colors.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,25 @@
* variant when the current post's project-group term is WooCommerce.
* Every other term falls back to the default (WordPress-tinted) variant.
*
* @param string $block_content Rendered block HTML.
* @param array $block Parsed block data.
* @return string
* Hooked on `render_block_data` at priority 9 — one step before core's own
* `wp_render_block_style_variation_support_styles` (priority 10, registered
* in wp-includes/block-supports/block-style-variations.php), which decides
* which is-style-* variation to generate CSS for and stamps a numbered
* instance class (e.g. is-style-card-banner-tint--175) based on whatever
* className is present at that point. Swapping the className here, on the
* parsed block attrs, means core sees the WooCommerce classname before it
* makes that decision. Swapping later via a `render_block` string-replace
* (the previous approach) edits the rendered HTML text only — core had
* already generated CSS for the un-swapped classname's numbered instance,
* so the final class in the HTML no longer matched any compiled rule at
* all, confirmed empirically 2026-08-12.
*
* @param array $block Parsed block data.
* @return array
*/
function ls_theme_portfolio_card_platform_class( $block_content, $block ) {
function ls_theme_portfolio_card_platform_class( $block ) {
if ( 'core/group' !== $block['blockName'] && 'core/post-terms' !== $block['blockName'] ) {
return $block_content;
return $block;
}

$class_name = $block['attrs']['className'] ?? '';
Expand All @@ -35,25 +47,27 @@ function ls_theme_portfolio_card_platform_class( $block_content, $block ) {
$is_badge = false !== strpos( $class_name, 'is-style-badge-brand' );

if ( ! $is_banner && ! $is_badge ) {
return $block_content;
return $block;
}

$post_id = get_the_ID();

if ( ! $post_id ) {
return $block_content;
return $block;
}

$terms = wp_get_post_terms( $post_id, 'project-group', array( 'fields' => 'slugs' ) );

if ( is_wp_error( $terms ) || empty( $terms ) || ! in_array( 'woocommerce', $terms, true ) ) {
return $block_content;
return $block;
}

if ( $is_banner ) {
return str_replace( 'is-style-card-banner-tint', 'is-style-card-banner-tint-woocommerce', $block_content );
$block['attrs']['className'] = str_replace( 'is-style-card-banner-tint', 'is-style-card-banner-tint-woocommerce', $class_name );
} else {
$block['attrs']['className'] = str_replace( 'is-style-badge-brand', 'is-style-badge-woocommerce', $class_name );
}

return str_replace( 'is-style-badge-brand', 'is-style-badge-woocommerce', $block_content );
return $block;
}
add_filter( 'render_block', 'ls_theme_portfolio_card_platform_class', 10, 2 );
add_filter( 'render_block_data', 'ls_theme_portfolio_card_platform_class', 9 );
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
"description": "LightSpeed Theme is a custom WordPress block theme built by LightSpeed for fast, accessible, maintainable websites using the WordPress Site Editor and block editor.",
"type": "module",
"scripts": {
"sync:breakpoints": "node theme-utils.mjs sync-breakpoints",
"build:css": "npm run sync:breakpoints && sass --no-source-map --no-charset --style=expanded src/scss/animations.scss:assets/css/animations.css src/scss/gsap-animations.scss:assets/css/gsap-animations.css",
"build:css": "sass --no-source-map --no-charset --style=expanded src/scss/animations.scss:assets/css/animations.css src/scss/gsap-animations.scss:assets/css/gsap-animations.css",
Comment thread
brandonmarshal marked this conversation as resolved.
"schema:validate": "node theme-utils.mjs validate-schema",
"theme:validate": "node theme-utils.mjs validate-theme",
"patterns:escape": "node theme-utils.mjs escape-patterns",
"security:scan": "node theme-utils.mjs security-scan",
"lint": "npm run lint:json",
"lint:json": "node --input-type=module --eval \"import { readFileSync } from 'fs'; import { glob } from 'glob'; const files = await glob(['theme.json', 'styles/**/*.json']); let ok = true; for (const f of files) { try { JSON.parse(readFileSync(f, 'utf8')); } catch (e) { console.error('Invalid JSON:', f, e.message); ok = false; } } if (ok) console.log('All JSON files are valid.'); else process.exit(1);\"",
"watch:css": "npm run sync:breakpoints && sass --watch --no-source-map --no-charset --style=expanded src/scss/animations.scss:assets/css/animations.css src/scss/gsap-animations.scss:assets/css/gsap-animations.css"
"watch:css": "sass --watch --no-source-map --no-charset --style=expanded src/scss/animations.scss:assets/css/animations.css src/scss/gsap-animations.scss:assets/css/gsap-animations.css"
},
"devDependencies": {
"ajv": "^8.17.1",
Expand Down
Loading
Loading