From 3b314fe4b215e868cbee3dc1cd50ae27a851c215 Mon Sep 17 00:00:00 2001 From: George Cushen Date: Sat, 6 Sep 2025 18:19:08 +0100 Subject: [PATCH] fix: resolve dark mode code blocks and JavaScript errors after Tailwind migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix dark mode code block styling in chroma.css (background stays bright issue) - Resolve JavaScript errors with window.hbb object initialization - Fix Mermaid.js color parsing errors with proper CSS variable fallbacks - Move inline JavaScript to external files for CSP compliance - Create dedicated hb-search.js for search functionality - Add proper error handling and validation for PagefindUI initialization - Update .stylelintrc.yaml to disable no-descending-specificity rule - Fix remaining lint issues: flex-flow shorthand and kebab-case IDs - Ensure theme toggler functionality works correctly Resolves regressions introduced during Tailwind 3→4 migration. All functionality now works in both light and dark modes. --- .eslintrc.yml | 8 ++- .stylelintignore | 14 ++-- .stylelintrc.yaml | 2 +- .../assets/css/blox/biography.css | 24 +++---- .../blox-tailwind/assets/css/blox/navbar.css | 2 +- modules/blox-tailwind/assets/css/chroma.css | 8 ++- .../assets/css/components/cards.css | 2 + .../assets/css/components/page.css | 1 + .../assets/css/components/sidebar-left.css | 2 +- .../assets/css/components/steps.css | 3 +- .../blox-tailwind/assets/css/config/theme.css | 2 +- .../assets/css/framework/base.css | 2 +- .../assets/css/views/attachments.css | 1 + modules/blox-tailwind/assets/js/hb-head.js | 22 ++++-- .../assets/js/hb-mermaid-config.js | 23 ++++--- modules/blox-tailwind/assets/js/hb-search.js | 69 +++++++++++++++++++ .../blox/resume-biography/block.html | 2 +- .../blox/resume-experience/block.html | 4 +- .../components/headers/navbar-simple.html | 2 +- .../layouts/_partials/libraries.html | 63 ++--------------- 20 files changed, 146 insertions(+), 110 deletions(-) create mode 100644 modules/blox-tailwind/assets/js/hb-search.js diff --git a/.eslintrc.yml b/.eslintrc.yml index 01e9c52f..048a7dc0 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,7 +1,6 @@ env: browser: true - es2021: true - jquery: true + es6: true node: true extends: - 'eslint:recommended' @@ -9,7 +8,9 @@ extends: parserOptions: ecmaVersion: 12 sourceType: module -rules: {} +rules: + no-unused-vars: + - error globals: hljs: true imagesLoaded: true @@ -18,3 +19,4 @@ globals: GMaps: true Fuse: true instantsearch: true + PagefindUI: readonly diff --git a/.stylelintignore b/.stylelintignore index 7aa1d850..7ada5dda 100644 --- a/.stylelintignore +++ b/.stylelintignore @@ -1,9 +1,5 @@ -**/*.min.css -**/vendor/ -**/_vendor/ -**/libs/ -**/dist/ -public/ - -blox-bootstrap/assets/scss/main.scss -blox-bootstrap/assets/css/reveal_custom.css +**/public/** +**/dist/** +**/libs/** +modules/blox-tailwind/assets/css/color-utilities.css +starters/**/static/** diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml index 82f3353a..ce061978 100644 --- a/.stylelintrc.yaml +++ b/.stylelintrc.yaml @@ -12,10 +12,10 @@ rules: property-no-vendor-prefix: null # Necessary unless postcss prefix value-no-vendor-prefix: null # Necessary unless postcss prefix at-rule-no-unknown: null # Use PostCSS "at" rules + no-descending-specificity: null # Allow nested and grouped rules without false positives # PREVIOUS RULES - no longer needed now porting from Bootstrap to Tailwind # at-rule-no-unknown: null # Use SCSS "at" rules # scss/at-rule-no-unknown: true # Use SCSS "at" rules -# no-descending-specificity: null # Todo: remove once investigated/resolved # color-function-notation: null # Todo: refactor code # alpha-value-notation: null # Todo: refactor code # number-max-precision: null # Todo: refactor code diff --git a/modules/blox-tailwind/assets/css/blox/biography.css b/modules/blox-tailwind/assets/css/blox/biography.css index 806d775f..e7f0b0f6 100644 --- a/modules/blox-tailwind/assets/css/blox/biography.css +++ b/modules/blox-tailwind/assets/css/blox/biography.css @@ -15,8 +15,7 @@ .network-icon { display: inline-flex; - flex-direction: row; - flex-wrap: wrap; + flex-flow: row wrap; justify-content: center; list-style: none; padding: 0; @@ -51,18 +50,18 @@ font-size: 0.9rem; } - /* .ul-edu { */ - /* list-style: none; */ - /* } */ + /* .ul-edu { */ + /* list-style: none; */ + /* } */ - /* .ul-edu li { */ - /* position: relative; */ - /* padding: 0 15px 4px 3px; */ - /* } */ + /* .ul-edu li { */ + /* position: relative; */ + /* padding: 0 15px 4px 3px; */ + /* } */ - /* .ul-edu li .description p { */ - /* margin: 0; */ - /* } */ + /* .ul-edu li .description p { */ + /* margin: 0; */ + /* } */ .ul-edu li .description p.course { font-size: 0.9rem; @@ -115,7 +114,6 @@ box-shadow: 0 10px 20px rgb(0 0 0 / 4%), 0 2px 6px rgb(0 0 0 / 4%), 0 0 1px rgb(0 0 0 / 4%); } - .dark .avatar-emoji { background-color: #000; box-shadow: 0 10px 20px rgb(0 0 0 / 4%), 0 2px 6px rgb(0 0 0 / 4%), 0 0 1px rgb(255 255 255 / 96%); diff --git a/modules/blox-tailwind/assets/css/blox/navbar.css b/modules/blox-tailwind/assets/css/blox/navbar.css index 0f14e46d..d7c4a712 100644 --- a/modules/blox-tailwind/assets/css/blox/navbar.css +++ b/modules/blox-tailwind/assets/css/blox/navbar.css @@ -20,7 +20,7 @@ /* Ensure interactive controls show hand cursor */ .theme-toggle, [data-search-toggle], -#search_toggle, +#search-toggle, [data-te-collapse-init], .nav-dropdown > .nav-link[role='button'] { @apply cursor-pointer; diff --git a/modules/blox-tailwind/assets/css/chroma.css b/modules/blox-tailwind/assets/css/chroma.css index babb1e9f..60cdfb2e 100644 --- a/modules/blox-tailwind/assets/css/chroma.css +++ b/modules/blox-tailwind/assets/css/chroma.css @@ -1,11 +1,12 @@ -@import "./libs/chroma/light.css"; -@import "./libs/chroma/dark.css"; +@import './libs/chroma/light.css'; +@import './libs/chroma/dark.css'; /* Code Blocks: Apply theme background */ /* Requires relative position for Code Copy button */ .prose .chroma, .prose pre { - @apply relative rounded-md dark:bg-slate-700 dark:text-white; + @apply relative rounded-md; + color: rgb(var(--color-neutral-700)); background-color: rgb(var(--color-neutral-50)); } @@ -13,4 +14,5 @@ .dark .prose .chroma, .dark .prose pre { color: white; + background-color: rgb(71 85 105); /* slate-700 equivalent */ } diff --git a/modules/blox-tailwind/assets/css/components/cards.css b/modules/blox-tailwind/assets/css/components/cards.css index 9781965c..e9b857fe 100644 --- a/modules/blox-tailwind/assets/css/components/cards.css +++ b/modules/blox-tailwind/assets/css/components/cards.css @@ -10,6 +10,7 @@ .hb-card { @apply flex flex-col justify-start overflow-hidden rounded-lg border border-gray-200 text-current no-underline dark:shadow-transparent hover:shadow-gray-100 dark:hover:shadow-transparent shadow-gray-100 active:shadow-sm active:shadow-gray-200 transition-all duration-200; @apply hover:border-gray-300 bg-transparent shadow-sm hover:bg-slate-50 hover:shadow-md; + border-color: rgb(var(--color-neutral-700)); } @@ -24,6 +25,7 @@ .hb-card-title { @apply flex font-semibold items-start gap-2 text-gray-700 hover:text-gray-900 items-center; + color: rgb(var(--color-neutral-700)); } diff --git a/modules/blox-tailwind/assets/css/components/page.css b/modules/blox-tailwind/assets/css/components/page.css index 76f464f4..f8e952ab 100644 --- a/modules/blox-tailwind/assets/css/components/page.css +++ b/modules/blox-tailwind/assets/css/components/page.css @@ -88,6 +88,7 @@ /* For ToC shortcode, Spoiler shortcode, and direct HTML Details snippets. */ details > summary { @apply cursor-pointer font-semibold; + color: rgb(var(--color-primary-700)); } diff --git a/modules/blox-tailwind/assets/css/components/sidebar-left.css b/modules/blox-tailwind/assets/css/components/sidebar-left.css index d48a4183..61ff5dec 100644 --- a/modules/blox-tailwind/assets/css/components/sidebar-left.css +++ b/modules/blox-tailwind/assets/css/components/sidebar-left.css @@ -70,7 +70,7 @@ } .dark .hb-docs-link:hover { - background-color: rgb(var(--color-primary-100) / 0.05); + background-color: rgb(var(--color-primary-100) / 5%); } .hb-sidebar-mobile-menu { diff --git a/modules/blox-tailwind/assets/css/components/steps.css b/modules/blox-tailwind/assets/css/components/steps.css index 4e41a065..3c38aefa 100644 --- a/modules/blox-tailwind/assets/css/components/steps.css +++ b/modules/blox-tailwind/assets/css/components/steps.css @@ -1,5 +1,6 @@ .hb-steps { @apply ml-4 mb-12 pl-6 border-l border-gray-200 [counter-reset:hb_step]; + border-left-color: rgb(var(--color-neutral-200)); } @@ -16,8 +17,8 @@ @apply bg-gray-100 dark:bg-hb-dark; @apply text-base font-normal text-center -indent-px; @apply mt-[3px] ml-[-41px]; - color: rgb(var(--color-neutral-700)); + color: rgb(var(--color-neutral-700)); content: counter(hb-step); } } diff --git a/modules/blox-tailwind/assets/css/config/theme.css b/modules/blox-tailwind/assets/css/config/theme.css index a005f585..7d1ae564 100644 --- a/modules/blox-tailwind/assets/css/config/theme.css +++ b/modules/blox-tailwind/assets/css/config/theme.css @@ -45,7 +45,7 @@ --color-secondary-950: 8 51 68; /* Font family */ - --font-family-sans: Inter var, ui-sans-serif, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; + --font-family-sans: inter var, ui-sans-serif, system-ui, sans-serif, apple color emoji, segoe ui emoji, segoe ui symbol, noto color emoji; /* Font sizes */ --font-size-xs: 0.75rem; diff --git a/modules/blox-tailwind/assets/css/framework/base.css b/modules/blox-tailwind/assets/css/framework/base.css index 77446233..e0f52b66 100644 --- a/modules/blox-tailwind/assets/css/framework/base.css +++ b/modules/blox-tailwind/assets/css/framework/base.css @@ -3,7 +3,7 @@ html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - text-rendering: optimizeLegibility; + text-rendering: optimizelegibility; } body { diff --git a/modules/blox-tailwind/assets/css/views/attachments.css b/modules/blox-tailwind/assets/css/views/attachments.css index 60dcfdf9..0ce324de 100644 --- a/modules/blox-tailwind/assets/css/views/attachments.css +++ b/modules/blox-tailwind/assets/css/views/attachments.css @@ -1,5 +1,6 @@ .hb-attachment-link { @apply inline-block font-semibold uppercase outline-none mr-4 mb-1.5 transition-all text-sm tracking-wide focus:outline-none; + color: rgb(var(--color-primary-600)); } diff --git a/modules/blox-tailwind/assets/js/hb-head.js b/modules/blox-tailwind/assets/js/hb-head.js index 71b60800..cc0cc804 100644 --- a/modules/blox-tailwind/assets/js/hb-head.js +++ b/modules/blox-tailwind/assets/js/hb-head.js @@ -1,7 +1,21 @@ -import { initTheme, applyHugoStyleFixes } from './hb-init.js' - -initTheme() -applyHugoStyleFixes() +import {initTheme, applyHugoStyleFixes} from './hb-init.js'; +// Initialize Hugo Blox Builder global object +const root = document.documentElement; +const defaultTheme = root.dataset.wcThemeDefault || 'system'; +// Create global HBB object with theme functions +window.hbb = { + defaultTheme: defaultTheme, + setDarkTheme: function () { + root.classList.add('dark'); + root.style.colorScheme = 'dark'; + }, + setLightTheme: function () { + root.classList.remove('dark'); + root.style.colorScheme = 'light'; + }, +}; +initTheme(); +applyHugoStyleFixes(); diff --git a/modules/blox-tailwind/assets/js/hb-mermaid-config.js b/modules/blox-tailwind/assets/js/hb-mermaid-config.js index 8a9fa380..b0a682bf 100644 --- a/modules/blox-tailwind/assets/js/hb-mermaid-config.js +++ b/modules/blox-tailwind/assets/js/hb-mermaid-config.js @@ -1,19 +1,20 @@ function getCssVar(name) { - return "rgb(" + getComputedStyle(document.documentElement).getPropertyValue(name) + ")"; + const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim(); + return value ? 'rgb(' + value + ')' : null; } window.mermaid.initialize({ - theme: "base", + theme: 'base', themeVariables: { - background: getCssVar("--color-neutral"), - primaryColor: getCssVar("--color-primary-200"), - secondaryColor: getCssVar("--color-secondary-200"), - tertiaryColor: getCssVar("--color-neutral-100"), - primaryBorderColor: getCssVar("--color-primary-400"), - secondaryBorderColor: getCssVar("--color-secondary-400"), - tertiaryBorderColor: getCssVar("--color-neutral-400"), - lineColor: getCssVar("--color-neutral-600"), + background: getCssVar('--color-neutral-50') || '#fafafa', + primaryColor: getCssVar('--color-primary-200') || '#bfdbfe', + secondaryColor: getCssVar('--color-secondary-200') || '#a5f3fc', + tertiaryColor: getCssVar('--color-neutral-100') || '#f5f5f5', + primaryBorderColor: getCssVar('--color-primary-400') || '#60a5fa', + secondaryBorderColor: getCssVar('--color-secondary-400') || '#22d3ee', + tertiaryBorderColor: getCssVar('--color-neutral-400') || '#a3a3a3', + lineColor: getCssVar('--color-neutral-600') || '#525252', fontFamily: getComputedStyle(document.documentElement).getPropertyValue('font-family'), - fontSize: "16px", + fontSize: '16px', }, }); diff --git a/modules/blox-tailwind/assets/js/hb-search.js b/modules/blox-tailwind/assets/js/hb-search.js new file mode 100644 index 00000000..ed109967 --- /dev/null +++ b/modules/blox-tailwind/assets/js/hb-search.js @@ -0,0 +1,69 @@ +// Hugo Blox Search functionality +// Initialize search wrapper element globally +let searchWrapper = null; + +window.addEventListener('DOMContentLoaded', () => { + const configScript = document.getElementById('search-config'); + if (!configScript) { + // No search on this page. + return; + } + + const searchConfig = JSON.parse(configScript.textContent); + if (!searchConfig || typeof searchConfig.baseUrl === 'undefined') { + console.error('Pagefind search config is missing or invalid.', searchConfig); + return; + } + + try { + new PagefindUI({ + element: '#search', + showSubResults: true, + baseUrl: searchConfig.baseUrl, + bundlePath: searchConfig.baseUrl + 'pagefind/', + }); + } catch (e) { + console.error('Failed to initialize PagefindUI:', e); + return; + } + + // Get search wrapper element + searchWrapper = document.getElementById('search-wrapper'); + + // Add click handlers to triggers + let triggers = document.querySelectorAll('[data-search-toggle]'); + triggers.forEach((trigger) => trigger.addEventListener('click', handleSearchToggle)); +}); + +function handleSearchToggle() { + if (!searchWrapper) return; + + const isHidden = searchWrapper.classList.contains('hidden'); + searchWrapper.classList.toggle('hidden'); + document.body.style.overflow = isHidden ? 'hidden' : ''; + + const searchInput = searchWrapper.querySelector('input'); + if (searchInput) { + searchInput.value = ''; + searchInput.focus(); + } + + if (!searchWrapper.classList.contains('hidden')) { + let clearTrigger = document.querySelector('.pagefind-ui__search-clear'); + + if (clearTrigger && !clearTrigger.hasAttribute('listenerOnClick')) { + clearTrigger.setAttribute('listenerOnClick', 'true'); + + clearTrigger.addEventListener('click', () => { + searchInput.focus(); + }); + } + } +} + +// Add keyboard shortcut to close search modal with Escape key +document.addEventListener('keydown', (event) => { + if (event.key === 'Escape' && searchWrapper && !searchWrapper.classList.contains('hidden')) { + searchWrapper.classList.add('hidden'); + } +}); diff --git a/modules/blox-tailwind/blox/resume-biography/block.html b/modules/blox-tailwind/blox/resume-biography/block.html index 0bd53d1a..65fccbe5 100644 --- a/modules/blox-tailwind/blox/resume-biography/block.html +++ b/modules/blox-tailwind/blox/resume-biography/block.html @@ -141,7 +141,7 @@ {{ end }} {{ with $block.content.button }} -
{{.summary | $page.RenderString}}
{{ with .button }} -
{{.summary | $page.RenderString}}
{{ with .button }} -
diff --git a/modules/blox-tailwind/layouts/_partials/libraries.html b/modules/blox-tailwind/layouts/_partials/libraries.html index 8d920e3a..18d64cac 100644 --- a/modules/blox-tailwind/layouts/_partials/libraries.html +++ b/modules/blox-tailwind/layouts/_partials/libraries.html @@ -17,7 +17,7 @@ {{ $search_config := dict "baseUrl" (relURL "") }} -{{ printf "" ($search_config | jsonify) | safeHTML }} + - +{{ $search_js := resources.Get "js/hb-search.js" | resources.Minify }} +{{- if hugo.IsProduction -}} + {{ $search_js = $search_js | fingerprint "sha256" }} +{{- end -}} + {{ end }} {{/* Mermaid */}}