03.09.01 — mod_custom hero override, palette starter files, updated descriptions (#84)

* Add mod_custom hero layout override and bump version to 03.09.01

Adds src/html/mod_custom/hero.php — a banner-overlay style template
override for mod_custom, mirroring Cassiopeia's banner layout pattern.
Includes background image support via WebAssetManager and respects the
Module Manager's moduleclass_sfx field.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Ignore and untrack .claude/settings.local.json

Adds .claude/settings.local.json to .gitignore and removes it from
version control to keep local Claude Code permissions out of the repo.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Ship custom palette starters and update template description

- Add src/templates/light.custom.css and dark.custom.css as starter
  palette files that ship with the template, giving users a full
  variable reference to copy and customise
- Register src/templates/ folder in templateDetails.xml <files>
- Update <description> in templateDetails.xml: correct palette source
  paths, add Custom CSS & JavaScript section (user.css / user.js),
  link docs to GitHub repo docs/ directory
- Sync en-GB and en-US tpl_mokocassiopeia.sys.ini with same changes,
  preserving British/American spelling variants; bump version to 03.09.01

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add CSS Variables reference tab to template options

Adds a new 'CSS Variables' tab to the template configuration with eight
documented sections (brand, typography, navigation, header background,
container backgrounds, borders/shadows, forms/focus) so site builders
can reference all available custom properties without leaving Joomla admin.

Also removes external docs links from descriptions in templateDetails.xml
and both language files, replacing them with a pointer to the new tab.
Fixes stale custom palette source paths in en-GB and en-US ini files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Expand CSS Variables tab to full variable reference and add custom-hero class

- Replace 8-field CSS Variables tab with 21 comprehensive sections covering
  all variables from light.standard.css and dark.standard.css
- New sections: Links, Layout & Spacing, Breakpoints, Bootstrap Semantic
  Palette, Bootstrap State Colors, Alert & List Group Colors, Standard
  Colors/Grays/Opacity, Shadows & Shadow Tokens, Buttons, Cards,
  Component & Plugin Colors, VirtueMart, Gable
- Add custom-hero class to hero.php outer div (always present)
- Both en-GB and en-US language files updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add Google Search Console verification and ensure all Google services coexist

- Add googlesitekey param to Google fieldset in templateDetails.xml
- Inject <meta name="google-site-verification"> via setMetaData() in
  index.php, component.php, and offline.php
- GTM, GA, and Search Console verification can now all be active simultaneously
- Add language strings for new field in en-US and en-GB

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add header-aside module position to the right of the logo

- New position renders inside .header-brand-wrap, right-aligned via
  margin-inline-start: auto on .container-header-aside
- CSS: .header-brand-wrap uses flexbox so logo stays left, aside floats right
- Registered in templateDetails.xml positions list
- Language strings added to both en-US and en-GB sys.ini files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add minify build script and generate .min CSS/JS; rename position to brand-aside

Build tooling:
- Add package.json with clean-css and terser dev dependencies
- Add scripts/minify.js: reads joomla.asset.json, auto-detects source/.min
  pairs, and minifies all template-owned CSS and JS files
- Add node_modules/ to .gitignore

Generated .min files (all 6 manifest pairs):
- css/template.min.css      (17.8% saved)
- css/editor.min.css        (49.4% saved)
- css/theme/light.standard.min.css  (13.1% saved)
- css/theme/dark.standard.min.css   (14.4% saved)
- js/template.min.js        (58.2% saved)
- js/gtm.min.js             (62.3% saved)

Rename: header-aside → brand-aside (position, CSS class, language keys)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add hero/banner-overlay CSS variables and wire template.css

- Add HERO / BANNER OVERLAY section to light.standard.css and dark.standard.css:
  --hero-height, --hero-color, --hero-bg-repeat, --hero-bg-attachment,
  --hero-bg-position, --hero-bg-size, --hero-border-bottom,
  --hero-overlay-bg (light: 0.1 alpha / dark: 0.3 alpha),
  --hero-overlay-padding, --hero-overlay-text-align, --hero-overlay-text-color
- Replace all hardcoded values in .container-banner .banner-overlay and
  .overlay with var() references (with fallbacks)
- Fix background-position: comma syntax → correct space-separated single-bg value
- Add css_vars_hero note field to CSS Variables tab in templateDetails.xml
- Add TPL_MOKOCASSIOPEIA_CSS_VARS_HERO_LABEL/DESC to en-US and en-GB
- Regenerate .min files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add smooth theme-switch transitions and restore hero .overlay wrapper

- Add prefers-reduced-motion-scoped CSS transitions (bg, color, border) on
  :root, body, and key layout containers so light/dark theme switches animate
  smoothly instead of snapping
- Restore <div class="overlay"> child in hero.php; slim .custom-hero rule to a
  customisation hook only — visual overlay styles are handled by .overlay child
- Regenerate template.min.css

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update template.css

* Merge duplicate prefers-reduced-motion media queries

Consolidate the two @media (prefers-reduced-motion: no-preference) blocks
into one — scroll-behavior and theme-switch colour transitions share the
same query and are cleaner in a single block.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Promote offcanvas variables to :root theme files and document in CSS Variables tab

- Move --offcanvas-* definitions from component-scoped .offcanvas selector in
  template.css into :root[data-bs-theme] blocks in light.standard.css and
  dark.standard.css so they are overridable via user.css at root level
- Fix two bugs in the old definitions: --offcanvas-bg was incorrectly set to
  var(--body-color) (text colour); corrected to var(--body-bg); and
  --offcanvas-color had a spurious 'color:' prefix
- Dark theme uses a heavier box-shadow (0.3 alpha) for better depth perception
- Add css_vars_offcanvas field to templateDetails.xml CSS Variables tab
- Add en-US and en-GB language strings for the new Offcanvas Panel section
- Rebuild all .min CSS files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Promote Bootstrap component variables from template.css to :root theme files

Move 16 component variable groups from component-scoped selectors in
template.css into :root[data-bs-theme] blocks in light.standard.css and
dark.standard.css:

accordion, breadcrumb, pagination, badge, alert, progress, list-group,
dropdown, toast, modal, tooltip, popover, spinner, nav, nav-tabs, nav-pills

Dark theme values adapted for dark surfaces: semantic var() references,
lighter SVG icon fill colours, heavier shadows, secondary-bg backgrounds.
Component selectors in template.css retain only non-variable rules.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Promote table and backdrop variables to :root theme files

Move --table-* and --backdrop-* base definitions from component selectors
in template.css into :root[data-bs-theme] blocks in light/dark theme files.

Dark table uses white-rgb-based striped/active overlays for proper contrast
on dark surfaces. Deduplicate the double --table-active-* declarations that
existed in template.css. Backdrop values are identical in both themes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add CSS Variables tab documentation for all promoted Bootstrap components

Add LABEL/DESC language strings (en-US + en-GB) for all 17 Bootstrap
component variable groups now living in the :root theme files:

accordion, alert, badge, backdrop, breadcrumb, dropdown, list-group,
modal, nav-tabs, nav-pills, pagination, popover, progress, spinner,
table, toast, tooltip

Each section documents variables with HTML subheadings (Dimensions,
Colours, Typography, Stacking, Animation) and <code> tags for every
variable name. British English spellings used throughout en-GB.

Adds 34 new lines per language file (17 LABEL + 17 DESC pairs, 80
CSS_VARS_* keys total). XML fields were already present from the
prior migration commit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit was merged in pull request #84.
This commit is contained in:
2026-03-24 16:48:07 -05:00
committed by GitHub
parent 1dcbfe1219
commit 97d3133843
23 changed files with 2859 additions and 262 deletions

1
src/media/js/gtm.min.js vendored Normal file
View File

@@ -0,0 +1 @@
(()=>{"use strict";const e=window,t={},n=e=>{const t=(()=>{const e=document.currentScript;return e||(Array.from(document.getElementsByTagName("script")).reverse().find(e=>(e.getAttribute("src")||"").includes("/gtm.js"))||null)})(),n=document.documentElement,o=document.body,a=document.querySelector(`meta[name="moko:gtm-${e}"]`);return t&&t.dataset&&t.dataset[e]||n&&n.dataset&&n.dataset[e]||o&&o.dataset&&o.dataset[e]||a&&a.getAttribute("content")||null},o=(e,t=!1)=>{if(null==e)return t;const n=String(e).trim().toLowerCase();return!!["1","true","yes","y","on"].includes(n)||!["0","false","no","n","off"].includes(n)&&t},a=(...e)=>{if(r.debug)try{console.info("[moko-gtm]",...e)}catch(e){}},r={id:"",dataLayerName:"dataLayer",debug:!1,ignoreDNT:!1,blockOnDev:!0,envAuth:"",envPreview:"",consentDefault:{analytics_storage:"granted",functionality_storage:"granted",security_storage:"granted",ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied"},pageVars:()=>({})},d=(e,t={})=>{const n={...e};for(const e in t){if(!Object.prototype.hasOwnProperty.call(t,e))continue;const o=t[e];o&&"object"==typeof o&&!Array.isArray(o)?n[e]={...n[e]||{},...o}:void 0!==o&&(n[e]=o)}return n},i=()=>{const t=e.MOKO_GTM_OPTIONS&&"object"==typeof e.MOKO_GTM_OPTIONS?e.MOKO_GTM_OPTIONS:{},a=n("id")||e.MOKO_GTM_ID||"",r=n("dataLayer")||"",d=n("debug"),i=n("ignoreDnt"),c=n("blockOnDev"),s=n("envAuth")||"",u=n("envPreview")||"";return{id:a||t.id||"",dataLayerName:r||t.dataLayerName||void 0,debug:o(d,!!t.debug),ignoreDNT:o(i,!!t.ignoreDNT),blockOnDev:o(c,t.blockOnDev??!0),envAuth:s||t.envAuth||"",envPreview:u||t.envPreview||"",consentDefault:t.consentDefault||void 0,pageVars:"function"==typeof t.pageVars?t.pageVars:void 0}},c=()=>{const t=r.dataLayerName;return e[t]=e[t]||[],e[t]},s=(...e)=>{c().push(arguments.length>1?e:e[0]),a("gtag push:",e)};t.push=(...e)=>s(...e),t.setConsent=e=>{s("consent","update",e||{})},t.isLoaded=()=>!!document.querySelector('script[src*="googletagmanager.com/gtm.js"]'),t.config=()=>({...r});const u=()=>{if(!r.id)return void a("GTM ID missing; aborting load.");if(t.isLoaded())return void a("GTM already loaded; skipping duplicate injection.");c().push({"gtm.start":(new Date).getTime(),event:"gtm.js"});const e=document.getElementsByTagName("script")[0],n=document.createElement("script");n.async=!0,n.src=`https://www.googletagmanager.com/gtm.js?id=${encodeURIComponent(r.id)}${"dataLayer"!==r.dataLayerName?`&l=${encodeURIComponent(r.dataLayerName)}`:""}${(()=>{const e=[];return r.envAuth&&e.push(`gtm_auth=${encodeURIComponent(r.envAuth)}`),r.envPreview&&e.push(`gtm_preview=${encodeURIComponent(r.envPreview)}`,"gtm_cookies_win=x"),e.length?`&${e.join("&")}`:""})()}`,e&&e.parentNode?e.parentNode.insertBefore(n,e):(document.head||document.documentElement).appendChild(n),a("Injected GTM script:",n.src)},g=()=>!r.ignoreDNT&&(()=>{const e=navigator,t=(e.doNotTrack||e.msDoNotTrack||e.navigator&&e.navigator.doNotTrack||"").toString().toLowerCase();return"1"===t||"yes"===t})()?(a("DNT is enabled; blocking GTM load (set ignoreDNT=true to override)."),!1):!r.blockOnDev||!(()=>{const t=e.location&&e.location.hostname||"";return"localhost"===t||"127.0.0.1"===t||t.endsWith(".local")||t.endsWith(".test")})()||(a("Development host detected; blocking GTM load (set blockOnDev=false to override)."),!1);t.init=(e={})=>{const t=i(),n=d(r,d(t,e));Object.assign(r,n),a("Config:",r),c(),s("consent","default",r.consentDefault),a("Applied default consent:",r.consentDefault),(()=>{const e={event:"moko.page_init",page_title:document.title||"",page_language:document.documentElement&&document.documentElement.lang||"",..."function"==typeof r.pageVars&&r.pageVars()||{}};s(e)})(),g()?u():a("GTM load prevented by configuration or environment.")};const m=()=>{!(!i().id&&!e.MOKO_GTM_ID)?t.init():a("No GTM ID detected; awaiting manual init via window.mokoGTM.init({ id: 'GTM-XXXXXXX' }).")};"complete"===document.readyState||"interactive"===document.readyState?setTimeout(m,0):document.addEventListener("DOMContentLoaded",m,{once:!0}),e.mokoGTM=t;try{const e=i();o(e.debug,!1)&&(r.debug=!0,a("Ready. You can call window.mokoGTM.init({ id: 'GTM-XXXXXXX' })."))}catch(e){}})();

1
src/media/js/template.min.js vendored Normal file
View File

@@ -0,0 +1 @@
!function(e,t){"use strict";var a="theme",n=e.matchMedia("(prefers-color-scheme: dark)"),r=t.documentElement;function o(e){r.setAttribute("data-bs-theme",e),r.setAttribute("data-aria-theme",e);try{localStorage.setItem(a,e)}catch(e){}}function d(){try{localStorage.removeItem(a)}catch(e){}}function i(){return n.matches?"dark":"light"}function c(){try{return localStorage.getItem(a)}catch(e){return null}}function l(){if(!t.getElementById("mokoThemeFab")){var a,l=t.createElement("div");l.id="mokoThemeFab",l.className=(a=(t.body.getAttribute("data-theme-fab-pos")||"br").toLowerCase(),/^(br|bl|tr|tl)$/.test(a)||(a="br"),"pos-"+a);var s=t.createElement("span");s.className="label",s.textContent="Light";var u=t.createElement("button");u.id="mokoThemeSwitch",u.type="button",u.setAttribute("role","switch"),u.setAttribute("aria-label","Toggle dark mode"),u.setAttribute("aria-checked","false");var m=t.createElement("span");m.className="switch";var h=t.createElement("span");h.className="knob",m.appendChild(h),u.appendChild(m);var f=t.createElement("span");f.className="label",f.textContent="Dark";var b=t.createElement("button");b.id="mokoThemeAuto",b.type="button",b.className="btn btn-sm btn-link text-decoration-none px-2",b.setAttribute("aria-label","Follow system theme"),b.textContent="Auto",u.addEventListener("click",function(){var e="dark"===(r.getAttribute("data-bs-theme")||"light").toLowerCase()?"light":"dark";o(e),u.setAttribute("aria-checked","dark"===e?"true":"false");var a=t.querySelector('meta[name="theme-color"]');a&&a.setAttribute("content","dark"===e?"#0f1115":"#ffffff")}),b.addEventListener("click",function(){d();var e=i();o(e),u.setAttribute("aria-checked","dark"===e?"true":"false")});var g=function(){if(!c()){var e=i();o(e),u.setAttribute("aria-checked","dark"===e?"true":"false")}};"function"==typeof n.addEventListener?n.addEventListener("change",g):"function"==typeof n.addListener&&n.addListener(g);var p=c()||i();u.setAttribute("aria-checked","dark"===p?"true":"false"),l.appendChild(s),l.appendChild(u),l.appendChild(f),l.appendChild(b),t.body.appendChild(l),e.mokoThemeFabStatus=function(){var a=t.getElementById("mokoThemeFab");if(!a)return{mounted:!1};var n=a.getBoundingClientRect();return{mounted:!0,rect:{top:n.top,left:n.left,width:n.width,height:n.height},zIndex:e.getComputedStyle(a).zIndex,posClass:a.className}},setTimeout(function(){var e=l.getBoundingClientRect();(e.width<10||e.height<10)&&(l.classList.add("debug-outline"),console.warn("[moko] Theme FAB mounted but appears too small — check CSS collisions."))},50)}}function s(){e.scrollY>50?t.body.classList.add("scrolled"):t.body.classList.remove("scrolled")}function u(){var a=t.getElementById("back-top");a&&a.addEventListener("click",function(t){t.preventDefault(),e.scrollTo({top:0,behavior:"smooth"})})}function m(){!function(){var e=c()||i();o(e);var a=function(){c()||o(i())};"function"==typeof n.addEventListener?n.addEventListener("change",a):"function"==typeof n.addListener&&n.addListener(a);var r=t.getElementById("themeSwitch"),l=t.getElementById("themeAuto");r&&(r.checked="dark"===e,r.addEventListener("change",function(){o(r.checked?"dark":"light")})),l&&l.addEventListener("click",function(){d(),o(i())})}(),"1"===t.body.getAttribute("data-theme-fab-enabled")&&l(),s(),e.addEventListener("scroll",s),t.querySelector(".drawer-toggle-left")||t.querySelector(".drawer-toggle-right"),u()}"loading"===t.readyState?t.addEventListener("DOMContentLoaded",m):m()}(window,document);