Make WordPress Themes

Changeset 357926


Ignore:
Timestamp:
11/08/2026 12:45:09 AM (less than one hour ago)
Author:
themedropbox
Message:

New version of Codersly Shop - 1.2.8

Location:
codersly-shop/1.2.8
Files:
1 added
23 edited
1 copied

Legend:

Unmodified
Added
Removed
  • codersly-shop/1.2.8/CHANGELOG.txt

    r356755 r357926  
     1v1.2.8 — Desktop logo label clarification (same version)
     2- The existing add-on Logo Max Height (px) control is now displayed as Desktop Logo Size (px).
     3- No duplicate control or settings migration: the saved value and sizing behavior are unchanged.
     4
     5v1.2.8 — Single shared logo, duplicate control cleanup (same version)
     6- Site Identity now exposes one Site Logo image for desktop and mobile.
     7- Removed the redundant, nonfunctional Desktop Logo Size control and the separate Mobile Logo image control.
     8- Existing licensed add-on Logo Max Height (px) remains the desktop height setting (no stored value changed).
     9- Mobile Logo Max Height (px) remains available for independent mobile sizing; previous mobile height value is preserved.
     10- Single-logo HTML replaces the device-image swap, keeping other 1.2.8 improvements intact.
     11
     12v1.2.8 — Device-specific Site Identity logo options (same version)
     13- Site Identity: existing custom logo renamed Desktop Logo, without changing its stored value.
     14- Optional Mobile Logo image; mobile inherits desktop logo when no separate image is chosen.
     15- Separate Desktop Logo Size (40px default) and Mobile Logo Size (30px default), each 16–200px.
     16- Responsive image selection covers all header variants; footer/logo elsewhere remains unchanged.
     17- All previous sticky-header, mobile drawer, submenu and branding fixes preserved.
     18
     19## 1.2.8
     20- Separated desktop and mobile sticky-header Customizer controls; existing desktop preference is preserved, new mobile setting defaults off.
     21- Enabled mobile-only sticky positioning for all five header layouts without moving mobile search, Cart, Hamburger or drawer.
     22- Fixed excess spacing between the mobile header logo and site title: now centered together as a compact 8px-gap group, without moving the cart or menu controls.
     23- Refined mobile branding alignment within the space before the unchanged cart and hamburger controls.
     24- Widened the mobile menu drawer and wrapped long contact text to prevent clipping.
     25- Enabled all levels of mobile menu submenus across every header variant, with accessible expand/collapse buttons.
     26- Increased the mobile header left padding from 8px to 18px to provide comfortable spacing for the logo and site title.
     27- Updated theme version metadata and bundled CSS files to 1.2.8.
     28
    129## 1.2.7
    230- Maintenance: moved Show Logo, Show Site Title, Show Tagline and Logo Max Height controls into the licensed companion add-on; the free theme now uses standard branding defaults.
  • codersly-shop/1.2.8/assets/css/header.css

    r346202 r357926  
    7171}
    7272
    73 /* Default logo size (desktop-friendly) */
    74 .bt-logo__img { max-height: 48px; }
     73/* One uploaded site logo is used at all viewport widths. */
     74/* Set a desktop cap on both header variants, overriding style.css's 40px. */
     75.bt-header .bt-logo__img, .bt-header .site-logo, .bt-header .custom-logo-link img { max-height: var(--bt-logo-h, 40px); width: auto; }
    7576
    7677/* -------------------- Primary Menu -------------------- */
    … …  
    531532  /* Reserve the right side for Cart + Hamburger. */
    532533  .bt-header-inner{
    533     padding: .35rem 8px !important;
     534    padding: .35rem 8px .35rem 18px !important;
    534535    gap: 8px;
    535536    position: relative;
    … …  
    552553  /* Smaller logo on mobile */
    553554  .bt-header .custom-logo-link img,
    554   .bt-logo__img{
    555     max-height: 30px !important;
     555  .bt-header .bt-logo__img,
     556  .bt-header .site-logo {
     557    max-height: var(--bt-logo-h-mobile, 30px) !important;
    556558    width: auto;
    557559  }
    … …  
    853855  }
    854856}
     857
     858
     859/* =========================================================
     860   v1.2.8 mobile refinement — centered branding, wider drawer,
     861   accessible nested navigation. Desktop layout is unchanged.
     862========================================================= */
     863@media (max-width: 768px) {
     864  /* Reserve the right-hand controls' existing positions: cart at 58px,
     865     hamburger at 8px. Center only within the space to their left. */
     866  .bt-header .bt-header-inner {
     867    padding: .35rem 114px .35rem 16px !important;
     868    justify-content: flex-start !important;
     869  }
     870  /* Treat the logo and site title as ONE tightly spaced branding group.
     871     Previously auto margins on .site-branding separated them widely. */
     872  .bt-header .bt-header-left {
     873    flex: 1 1 100% !important;
     874    min-width: 0;
     875    gap: 8px !important;
     876    padding-right: 0 !important;
     877    justify-content: center !important;
     878  }
     879  .bt-header .bt-header-left .site-branding {
     880    flex: 0 0 auto;
     881    width: auto;
     882    max-width: 100%;
     883    min-width: 0;
     884    margin: 0 !important;
     885    justify-content: center !important;
     886  }
     887  .bt-header .bt-header-left .bt-site-title {
     888    flex: 0 1 auto;
     889    min-width: 0;
     890    margin: 0 !important;
     891  }
     892  .bt-header .bt-header-left .bt-brand-title,
     893  .bt-header .bt-header-left .site-title {
     894    min-width: 0;
     895  }
     896
     897  /* 50vw clipped email/contact text; 68vw makes the drawer more usable. */
     898  .bt-drawer {
     899    width: 68vw;
     900    max-width: 380px;
     901    box-sizing: border-box;
     902  }
     903  .bt-drawer-inner,
     904  .bt-drawer-scroll,
     905  .bt-drawer-footer {
     906    box-sizing: border-box;
     907    min-width: 0;
     908  }
     909  .bt-drawer-footer,
     910  .bt-drawer-footer * {
     911    overflow-wrap: anywhere;
     912    word-break: normal;
     913  }
     914  .bt-drawer .bt-drawer-menu a {
     915    overflow-wrap: anywhere;
     916  }
     917
     918  /* Separate arrow button: tapping it expands the submenu without
     919     preventing navigation when the parent label has a real URL. */
     920  .bt-drawer .bt-drawer-menu li.menu-item-has-children > a {
     921    padding-right: 44px;
     922  }
     923  .bt-drawer .bt-drawer-menu li.menu-item-has-children > a::after {
     924    content: none;
     925  }
     926  .bt-drawer .bt-drawer-menu .bt-submenu-toggle {
     927    position: absolute;
     928    z-index: 1;
     929    right: 0;
     930    top: 0;
     931    display: flex;
     932    align-items: center;
     933    justify-content: center;
     934    width: 40px;
     935    min-height: 42px;
     936    padding: 0;
     937    border: 0;
     938    border-radius: 6px;
     939    background: transparent;
     940    color: var(--bt-fg);
     941    cursor: pointer;
     942  }
     943  .bt-drawer .bt-drawer-menu .bt-submenu-toggle::after {
     944    content: '';
     945    display: block;
     946    width: 8px;
     947    height: 8px;
     948    border-right: 2px solid currentColor;
     949    border-bottom: 2px solid currentColor;
     950    transform: translateY(-2px) rotate(45deg);
     951    transition: transform .15s ease;
     952  }
     953  .bt-drawer .bt-drawer-menu .bt-submenu-toggle[aria-expanded='true']::after {
     954    transform: translateY(2px) rotate(225deg);
     955  }
     956  .bt-drawer .bt-drawer-menu .bt-submenu-toggle:hover,
     957  .bt-drawer .bt-drawer-menu .bt-submenu-toggle:focus-visible {
     958    background: var(--bt-soft);
     959  }
     960  .bt-drawer .bt-drawer-menu .bt-submenu-toggle:focus-visible {
     961    outline: 2px solid var(--bt-accent);
     962    outline-offset: 2px;
     963  }
     964}
     965
     966@media (max-width: 360px) {
     967  .bt-header .bt-header-left .site-title {
     968    font-size: 16px !important;
     969  }
     970}
     971
     972/* =========================================================
     973   v1.2.8 — independently controlled MOBILE sticky header.
     974   The existing .bt-header--sticky setting remains desktop-only;
     975   mobile uses .bt-header--sticky-mobile, including header variants 2–5.
     976   Keep the separate search row in normal document flow and leave the
     977   fixed drawer/Cart/Hamburger positioning unchanged.
     978========================================================= */
     979@media (max-width: 768px) {
     980  .bt-header.bt-header--sticky-mobile {
     981    position: -webkit-sticky !important;
     982    position: sticky !important;
     983    top: 0 !important;
     984    z-index: 1001;
     985    background: var(--bt-bg, #fff);
     986    border-bottom: 1px solid var(--bt-b, #e5e7eb);
     987    box-shadow: 0 2px 6px rgba(0, 0, 0, .06) !important;
     988  }
     989  .bt-header.bt-header--sticky-mobile.bt-header-scrolled {
     990    box-shadow: 0 6px 20px rgba(0, 0, 0, .10) !important;
     991  }
     992}
  • codersly-shop/1.2.8/assets/css/header.min.css

    r346202 r357926  
    7171}
    7272
    73 /* Default logo size (desktop-friendly) */
    74 .bt-logo__img { max-height: 48px; }
     73/* One uploaded site logo is used at all viewport widths. */
     74/* Set a desktop cap on both header variants, overriding style.css's 40px. */
     75.bt-header .bt-logo__img, .bt-header .site-logo, .bt-header .custom-logo-link img { max-height: var(--bt-logo-h, 40px); width: auto; }
    7576
    7677/* -------------------- Primary Menu -------------------- */
    … …  
    531532  /* Reserve the right side for Cart + Hamburger. */
    532533  .bt-header-inner{
    533     padding: .35rem 8px !important;
     534    padding: .35rem 8px .35rem 18px !important;
    534535    gap: 8px;
    535536    position: relative;
    … …  
    552553  /* Smaller logo on mobile */
    553554  .bt-header .custom-logo-link img,
    554   .bt-logo__img{
    555     max-height: 30px !important;
     555  .bt-header .bt-logo__img,
     556  .bt-header .site-logo {
     557    max-height: var(--bt-logo-h-mobile, 30px) !important;
    556558    width: auto;
    557559  }
    … …  
    853855  }
    854856}
     857
     858
     859/* =========================================================
     860   v1.2.8 mobile refinement — centered branding, wider drawer,
     861   accessible nested navigation. Desktop layout is unchanged.
     862========================================================= */
     863@media (max-width: 768px) {
     864  /* Reserve the right-hand controls' existing positions: cart at 58px,
     865     hamburger at 8px. Center only within the space to their left. */
     866  .bt-header .bt-header-inner {
     867    padding: .35rem 114px .35rem 16px !important;
     868    justify-content: flex-start !important;
     869  }
     870  /* Treat the logo and site title as ONE tightly spaced branding group.
     871     Previously auto margins on .site-branding separated them widely. */
     872  .bt-header .bt-header-left {
     873    flex: 1 1 100% !important;
     874    min-width: 0;
     875    gap: 8px !important;
     876    padding-right: 0 !important;
     877    justify-content: center !important;
     878  }
     879  .bt-header .bt-header-left .site-branding {
     880    flex: 0 0 auto;
     881    width: auto;
     882    max-width: 100%;
     883    min-width: 0;
     884    margin: 0 !important;
     885    justify-content: center !important;
     886  }
     887  .bt-header .bt-header-left .bt-site-title {
     888    flex: 0 1 auto;
     889    min-width: 0;
     890    margin: 0 !important;
     891  }
     892  .bt-header .bt-header-left .bt-brand-title,
     893  .bt-header .bt-header-left .site-title {
     894    min-width: 0;
     895  }
     896
     897  /* 50vw clipped email/contact text; 68vw makes the drawer more usable. */
     898  .bt-drawer {
     899    width: 68vw;
     900    max-width: 380px;
     901    box-sizing: border-box;
     902  }
     903  .bt-drawer-inner,
     904  .bt-drawer-scroll,
     905  .bt-drawer-footer {
     906    box-sizing: border-box;
     907    min-width: 0;
     908  }
     909  .bt-drawer-footer,
     910  .bt-drawer-footer * {
     911    overflow-wrap: anywhere;
     912    word-break: normal;
     913  }
     914  .bt-drawer .bt-drawer-menu a {
     915    overflow-wrap: anywhere;
     916  }
     917
     918  /* Separate arrow button: tapping it expands the submenu without
     919     preventing navigation when the parent label has a real URL. */
     920  .bt-drawer .bt-drawer-menu li.menu-item-has-children > a {
     921    padding-right: 44px;
     922  }
     923  .bt-drawer .bt-drawer-menu li.menu-item-has-children > a::after {
     924    content: none;
     925  }
     926  .bt-drawer .bt-drawer-menu .bt-submenu-toggle {
     927    position: absolute;
     928    z-index: 1;
     929    right: 0;
     930    top: 0;
     931    display: flex;
     932    align-items: center;
     933    justify-content: center;
     934    width: 40px;
     935    min-height: 42px;
     936    padding: 0;
     937    border: 0;
     938    border-radius: 6px;
     939    background: transparent;
     940    color: var(--bt-fg);
     941    cursor: pointer;
     942  }
     943  .bt-drawer .bt-drawer-menu .bt-submenu-toggle::after {
     944    content: '';
     945    display: block;
     946    width: 8px;
     947    height: 8px;
     948    border-right: 2px solid currentColor;
     949    border-bottom: 2px solid currentColor;
     950    transform: translateY(-2px) rotate(45deg);
     951    transition: transform .15s ease;
     952  }
     953  .bt-drawer .bt-drawer-menu .bt-submenu-toggle[aria-expanded='true']::after {
     954    transform: translateY(2px) rotate(225deg);
     955  }
     956  .bt-drawer .bt-drawer-menu .bt-submenu-toggle:hover,
     957  .bt-drawer .bt-drawer-menu .bt-submenu-toggle:focus-visible {
     958    background: var(--bt-soft);
     959  }
     960  .bt-drawer .bt-drawer-menu .bt-submenu-toggle:focus-visible {
     961    outline: 2px solid var(--bt-accent);
     962    outline-offset: 2px;
     963  }
     964}
     965
     966@media (max-width: 360px) {
     967  .bt-header .bt-header-left .site-title {
     968    font-size: 16px !important;
     969  }
     970}
     971
     972/* =========================================================
     973   v1.2.8 — independently controlled MOBILE sticky header.
     974   The existing .bt-header--sticky setting remains desktop-only;
     975   mobile uses .bt-header--sticky-mobile, including header variants 2–5.
     976   Keep the separate search row in normal document flow and leave the
     977   fixed drawer/Cart/Hamburger positioning unchanged.
     978========================================================= */
     979@media (max-width: 768px) {
     980  .bt-header.bt-header--sticky-mobile {
     981    position: -webkit-sticky !important;
     982    position: sticky !important;
     983    top: 0 !important;
     984    z-index: 1001;
     985    background: var(--bt-bg, #fff);
     986    border-bottom: 1px solid var(--bt-b, #e5e7eb);
     987    box-shadow: 0 2px 6px rgba(0, 0, 0, .06) !important;
     988  }
     989  .bt-header.bt-header--sticky-mobile.bt-header-scrolled {
     990    box-shadow: 0 6px 20px rgba(0, 0, 0, .10) !important;
     991  }
     992}
  • codersly-shop/1.2.8/assets/js/customizer.js

    r356755 r357926  
    77  if (!api) return;
    88
    9   if (api('codersly_shop_header_sticky')) {
    10     api('codersly_shop_header_sticky', (value) => {
     9  // Keep the saved desktop setting and the new mobile setting independent.
     10  const stickySettings = {
     11    codersly_shop_header_sticky: 'bt-header--sticky',
     12    codersly_shop_header_sticky_mobile: 'bt-header--sticky-mobile'
     13  };
     14  Object.entries(stickySettings).forEach(([settingId, className]) => {
     15    if (!api(settingId)) return;
     16    api(settingId, (value) => {
    1117      const apply = (enabled) => {
    12         d.querySelectorAll('#masthead, .bt-header').forEach((header) => {
    13           header.classList.toggle('bt-header--sticky', !!enabled);
     18        const isEnabled = enabled === true || enabled === 1 || enabled === '1';
     19        d.querySelectorAll('.bt-header').forEach((header) => {
     20          header.classList.toggle(className, isEnabled);
     21          const activeClass = window.matchMedia('(max-width: 768px)').matches
     22            ? 'bt-header--sticky-mobile' : 'bt-header--sticky';
     23          header.classList.toggle('bt-header-scrolled',
     24            header.classList.contains(activeClass) && window.scrollY > 10);
    1425        });
    1526      };
    … …  
    1728      value.bind(apply);
    1829    });
    19   }
     30  });
    2031
    2132  const componentMap = {
  • codersly-shop/1.2.8/assets/js/header.js

    r345366 r357926  
    132132  });
    133133
    134   // Drawer accordion logic (NO auto-close on other parents)
    135   // - Parent items with children: toggle .is-open and aria-expanded
    136   // - Leaf links (no children): navigate and close drawer
     134  // Build accessible, independent dropdown controls for every nested drawer item.
     135  // Parent links remain links; their arrow buttons expand/collapse submenus.
     136  qsa('.bt-drawer-menu li', drawerInner || document).forEach((item, index) => {
     137    const submenu = Array.from(item.children).find((child) =>
     138      child.matches('ul.sub-menu, ul.children')
     139    );
     140    if (!submenu) return;
     141
     142    const link = Array.from(item.children).find((child) => child.matches('a'));
     143    if (!link) return;
     144
     145    item.classList.add('menu-item-has-children');
     146    const submenuId = submenu.id || `bt-drawer-submenu-${index + 1}`;
     147    submenu.id = submenuId;
     148
     149    const toggle = document.createElement('button');
     150    toggle.type = 'button';
     151    toggle.className = 'bt-submenu-toggle';
     152    toggle.setAttribute('aria-expanded', 'false');
     153    toggle.setAttribute('aria-controls', submenuId);
     154    toggle.setAttribute('aria-label', `Expand submenu: ${link.textContent.trim()}`);
     155    toggle.dataset.menuName = link.textContent.trim();
     156    link.insertAdjacentElement('afterend', toggle);
     157  });
     158
    137159  drawerInner?.addEventListener('click', (e) => {
    138     const link = e.target.closest('a');
    139     const li   = e.target.closest('li.menu-item');
    140     if (!link || !li) return;
    141 
    142     const hasChildren = li.classList.contains('menu-item-has-children');
    143     if (hasChildren) {
    144       e.preventDefault();
    145       li.classList.toggle('is-open');
    146       link.setAttribute(
    147         'aria-expanded',
    148         li.classList.contains('is-open') ? 'true' : 'false'
     160    const toggle = e.target.closest('.bt-submenu-toggle');
     161    if (toggle && drawerInner.contains(toggle)) {
     162      e.preventDefault();
     163      const item = toggle.closest('li.menu-item-has-children');
     164      if (!item) return;
     165      const open = item.classList.toggle('is-open');
     166      toggle.setAttribute('aria-expanded', String(open));
     167      toggle.setAttribute('aria-label',
     168        `${open ? 'Collapse' : 'Expand'} submenu: ${toggle.dataset.menuName}`);
     169      return;
     170    }
     171
     172    const link = e.target.closest('.bt-drawer-menu a');
     173    if (!link || !drawerInner.contains(link)) return;
     174    const item = link.parentElement?.matches('li.menu-item-has-children')
     175      ? link.parentElement : null;
     176    const href = (link.getAttribute('href') || '').trim();
     177    // A placeholder parent URL opens the submenu; real parent URLs still work.
     178    if (item && (!href || href === '#')) {
     179      const arrow = Array.from(item.children).find((child) =>
     180        child.matches('button.bt-submenu-toggle')
    149181      );
    150       return;
    151     }
    152 
    153     // Leaf item: allow navigation, then close drawer
    154     const href = link.getAttribute('href') || '';
     182      if (arrow) {
     183        e.preventDefault();
     184        arrow.click();
     185        return;
     186      }
     187    }
     188
     189    // Real destination links navigate normally. Close on in-page anchors too.
    155190    if (href.startsWith('#')) {
    156191      setTimeout(closeDrawer, 0);
    … …  
    172207
    173208    // Focus trap inside drawer
    174     const focusables = qsa(FOCUSABLE, drawer);
     209    const focusables = qsa(FOCUSABLE, drawer).filter((el) => el.getClientRects().length > 0);
    175210    if (!focusables.length) return;
    176211    const first = focusables[0];
    … …  
    205240  }
    206241
    207   /* -------- Sticky Shadow -------- */
    208   if (header?.classList.contains('bt-header--sticky')) {
    209     const applyShadow = () =>
    210       header.classList.toggle('bt-header-scrolled', window.scrollY > 10);
     242  /* -------- Responsive Sticky Shadow -------- */
     243  if (header) {
     244    const applyShadow = () => {
     245      const stickyClass = isDesktop()
     246        ? 'bt-header--sticky' : 'bt-header--sticky-mobile';
     247      header.classList.toggle('bt-header-scrolled',
     248        header.classList.contains(stickyClass) && window.scrollY > 10);
     249    };
    211250    applyShadow();
    212251    on('scroll', applyShadow, window);
     252    on('resize', applyShadow, window);
    213253  }
    214254
  • codersly-shop/1.2.8/assets/js/header.min.js

    r345366 r357926  
    132132  });
    133133
    134   // Drawer accordion logic (NO auto-close on other parents)
    135   // - Parent items with children: toggle .is-open and aria-expanded
    136   // - Leaf links (no children): navigate and close drawer
     134  // Build accessible, independent dropdown controls for every nested drawer item.
     135  // Parent links remain links; their arrow buttons expand/collapse submenus.
     136  qsa('.bt-drawer-menu li', drawerInner || document).forEach((item, index) => {
     137    const submenu = Array.from(item.children).find((child) =>
     138      child.matches('ul.sub-menu, ul.children')
     139    );
     140    if (!submenu) return;
     141
     142    const link = Array.from(item.children).find((child) => child.matches('a'));
     143    if (!link) return;
     144
     145    item.classList.add('menu-item-has-children');
     146    const submenuId = submenu.id || `bt-drawer-submenu-${index + 1}`;
     147    submenu.id = submenuId;
     148
     149    const toggle = document.createElement('button');
     150    toggle.type = 'button';
     151    toggle.className = 'bt-submenu-toggle';
     152    toggle.setAttribute('aria-expanded', 'false');
     153    toggle.setAttribute('aria-controls', submenuId);
     154    toggle.setAttribute('aria-label', `Expand submenu: ${link.textContent.trim()}`);
     155    toggle.dataset.menuName = link.textContent.trim();
     156    link.insertAdjacentElement('afterend', toggle);
     157  });
     158
    137159  drawerInner?.addEventListener('click', (e) => {
    138     const link = e.target.closest('a');
    139     const li   = e.target.closest('li.menu-item');
    140     if (!link || !li) return;
    141 
    142     const hasChildren = li.classList.contains('menu-item-has-children');
    143     if (hasChildren) {
    144       e.preventDefault();
    145       li.classList.toggle('is-open');
    146       link.setAttribute(
    147         'aria-expanded',
    148         li.classList.contains('is-open') ? 'true' : 'false'
     160    const toggle = e.target.closest('.bt-submenu-toggle');
     161    if (toggle && drawerInner.contains(toggle)) {
     162      e.preventDefault();
     163      const item = toggle.closest('li.menu-item-has-children');
     164      if (!item) return;
     165      const open = item.classList.toggle('is-open');
     166      toggle.setAttribute('aria-expanded', String(open));
     167      toggle.setAttribute('aria-label',
     168        `${open ? 'Collapse' : 'Expand'} submenu: ${toggle.dataset.menuName}`);
     169      return;
     170    }
     171
     172    const link = e.target.closest('.bt-drawer-menu a');
     173    if (!link || !drawerInner.contains(link)) return;
     174    const item = link.parentElement?.matches('li.menu-item-has-children')
     175      ? link.parentElement : null;
     176    const href = (link.getAttribute('href') || '').trim();
     177    // A placeholder parent URL opens the submenu; real parent URLs still work.
     178    if (item && (!href || href === '#')) {
     179      const arrow = Array.from(item.children).find((child) =>
     180        child.matches('button.bt-submenu-toggle')
    149181      );
    150       return;
    151     }
    152 
    153     // Leaf item: allow navigation, then close drawer
    154     const href = link.getAttribute('href') || '';
     182      if (arrow) {
     183        e.preventDefault();
     184        arrow.click();
     185        return;
     186      }
     187    }
     188
     189    // Real destination links navigate normally. Close on in-page anchors too.
    155190    if (href.startsWith('#')) {
    156191      setTimeout(closeDrawer, 0);
    … …  
    172207
    173208    // Focus trap inside drawer
    174     const focusables = qsa(FOCUSABLE, drawer);
     209    const focusables = qsa(FOCUSABLE, drawer).filter((el) => el.getClientRects().length > 0);
    175210    if (!focusables.length) return;
    176211    const first = focusables[0];
    … …  
    205240  }
    206241
    207   /* -------- Sticky Shadow -------- */
    208   if (header?.classList.contains('bt-header--sticky')) {
    209     const applyShadow = () =>
    210       header.classList.toggle('bt-header-scrolled', window.scrollY > 10);
     242  /* -------- Responsive Sticky Shadow -------- */
     243  if (header) {
     244    const applyShadow = () => {
     245      const stickyClass = isDesktop()
     246        ? 'bt-header--sticky' : 'bt-header--sticky-mobile';
     247      header.classList.toggle('bt-header-scrolled',
     248        header.classList.contains(stickyClass) && window.scrollY > 10);
     249    };
    211250    applyShadow();
    212251    on('scroll', applyShadow, window);
     252    on('resize', applyShadow, window);
    213253  }
    214254
  • codersly-shop/1.2.8/assets/js/main.js

    r330331 r357926  
    5656  /* ---------------- Sticky Header Shadow ---------------- */
    5757  const header = qs('.bt-header');
    58   if (header && header.classList.contains('bt-header--sticky')) {
    59     const onScroll = () =>
    60       header.classList.toggle('bt-header-scrolled', window.scrollY > 10);
     58  if (header) {
     59    const onScroll = () => {
     60      const active = (window.innerWidth <= 768)
     61        ? header.classList.contains('bt-header--sticky-mobile')
     62        : header.classList.contains('bt-header--sticky');
     63      header.classList.toggle('bt-header-scrolled', active && window.scrollY > 10);
     64    };
    6165    on('scroll', onScroll, window);
     66    on('resize', onScroll, window);
    6267    onScroll();
    6368  }
  • codersly-shop/1.2.8/functions.php

    r356755 r357926  
    2020 */
    2121if ( ! defined( 'CODERSLY_SHOP_VERSION' ) ) {
    22     define( 'CODERSLY_SHOP_VERSION', '1.2.7' );
     22    define( 'CODERSLY_SHOP_VERSION', '1.2.8' );
    2323}
    2424
    … …  
    212212        'inc/customizer/colors.php',
    213213        'inc/customizer/customizer.php',
     214        'inc/customizer/options-logo.php',
    214215        'inc/customizer/sanitize.php',
    215216        'inc/customizer/options-header.php',
  • codersly-shop/1.2.8/inc/assets.php

    r356332 r357926  
    1919        function codersly_shop_file_version( $relative_path ) {
    2020                $path = trailingslashit( get_template_directory() ) . ltrim( $relative_path, '/' );
    21                 return file_exists( $path ) ? (string) filemtime( $path ) : '1.1.4';
     21                return file_exists( $path ) ? (string) filemtime( $path ) : '1.2.8';
    2222        }
    2323}
  • codersly-shop/1.2.8/inc/class-codersly-shop-header-manager.php

    r356755 r357926  
    199199                        case 'logo':
    200200                                return ( codersly_shop_branding_show_logo()
    201                                         && function_exists( 'has_custom_logo' ) && has_custom_logo() )
     201                                        && codersly_shop_has_header_logo() )
    202202                                        || ( (bool) get_theme_mod( 'codersly_show_site_icon', false )
    203203                                                && function_exists( 'has_site_icon' ) && has_site_icon() );
  • codersly-shop/1.2.8/inc/customizer/options-header.php

    r320649 r357926  
    55 *
    66 * - Header variant select (1–5) — Free unlocks only 1; Pro unlocks 2–5
    7  * - Sticky header toggle
     7 * - Independent desktop and mobile sticky header toggles
    88 * - Component toggles (Search, Account, Cart)
    99 * - Live-preview for common toggles
    … …  
    120120
    121121        /**
    122          * Sticky Header
     122         * Independent Sticky Header controls
    123123         */
    124124        $wp_customize->add_setting(
    … …  
    134134                'codersly_shop_header_sticky',
    135135                array(
    136                         'label'       => __( 'Enable Sticky Header', 'codersly-shop' ),
    137                         'description' => __( 'Make the header stick to the top while scrolling.', 'codersly-shop' ),
     136                        'label'       => __( 'Enable Sticky Header (Desktop)', 'codersly-shop' ),
     137                        'description' => __( 'Keep the desktop header visible while scrolling. Does not affect mobile.', 'codersly-shop' ),
     138                        'section'     => 'codersly_shop_section_header',
     139                        'type'        => 'checkbox',
     140                )
     141        );
     142
     143        /**
     144         * Mobile sticky: separate from the existing desktop setting.
     145         * Off by default so upgrading does not silently change mobile behavior.
     146         */
     147        $wp_customize->add_setting(
     148                'codersly_shop_header_sticky_mobile',
     149                array(
     150                        'default'           => false,
     151                        'sanitize_callback' => 'codersly_shop_customize_sanitize_checkbox',
     152                        'transport'         => 'postMessage',
     153                )
     154        );
     155
     156        $wp_customize->add_control(
     157                'codersly_shop_header_sticky_mobile',
     158                array(
     159                        'label'       => __( 'Enable Sticky Header (Mobile)', 'codersly-shop' ),
     160                        'description' => __( 'Keep the mobile header visible while scrolling. Desktop setting is independent.', 'codersly-shop' ),
    138161                        'section'     => 'codersly_shop_section_header',
    139162                        'type'        => 'checkbox',
    … …  
    191214                                        'codersly_shop_header_show_cart',
    192215                                        'codersly_shop_header_sticky',
     216                                        'codersly_shop_header_sticky_mobile',
    193217                                        'codersly_shop_header_variant',
    194218                                ),
  • codersly-shop/1.2.8/inc/hooks.php

    r356755 r357926  
    304304        $show_tagline = codersly_shop_should_show_tagline();
    305305        $logo_h       = codersly_shop_logo_max_height();
    306 
    307         $css = ':root{--bt-logo-h:' . esc_attr( $logo_h ) . 'px;}';
     306        $logo_mobile_h = codersly_shop_mobile_logo_max_height();
     307
     308        $css = ':root{--bt-logo-h:' . esc_attr( $logo_h ) . 'px;--bt-logo-h-mobile:' . esc_attr( $logo_mobile_h ) . 'px;}';
    308309        if ( ! $show_title ) {
    309310                $css .= '.site-title,.bt-text-logo{display:none!important;}';
  • codersly-shop/1.2.8/inc/setup.php

    r356755 r357926  
    6060        if ( file_exists( $path ) ) {
    6161                $theme = wp_get_theme();
    62                 $ver   = $theme->get( 'Version' ) ? $theme->get( 'Version' ) : '1.2.7';
     62                $ver   = $theme->get( 'Version' ) ? $theme->get( 'Version' ) : '1.2.8';
    6363
    6464                wp_register_style( $handle, $uri, array(), $ver );
  • codersly-shop/1.2.8/inc/template-functions.php

    r356755 r357926  
    2828}
    2929
     30/** Maximum mobile header-logo height in pixels. */
     31function codersly_shop_mobile_logo_max_height() {
     32        $height = (int) get_theme_mod( 'codersly_shop_logo_height_mobile', 30 );
     33        return max( 16, min( 200, $height ) );
     34}
     35
     36/** Whether the shared WordPress Site Identity logo is configured. */
     37function codersly_shop_has_header_logo() {
     38        return (bool) absint( get_theme_mod( 'custom_logo' ) );
     39}
     40
     41/**
     42 * Return the single WordPress Site Identity logo used on all devices.
     43 * Desktop height comes from the existing premium Logo Max Height setting,
     44 * while mobile height is handled via responsive CSS.
     45 *
     46 * @param string $class CSS class of the logo image.
     47 * @return string Safe WordPress attachment-image markup.
     48 */
     49function codersly_shop_header_logo_images( $class = 'site-logo' ) {
     50        $logo_id = absint( get_theme_mod( 'custom_logo' ) );
     51        if ( ! $logo_id ) {
     52                return '';
     53        }
     54
     55        $logo_h = codersly_shop_logo_max_height();
     56        $attrs = array(
     57                'class'    => $class,
     58                'style'    => 'max-height:' . $logo_h . 'px;height:auto;width:auto;',
     59                'loading'  => 'eager',
     60                'decoding' => 'async',
     61        );
     62
     63        return wp_get_attachment_image( $logo_id, 'full', false, $attrs );
     64}
     65
    3066/** Whether site-title text should be displayed. */
    3167function codersly_shop_should_show_site_title() {
    … …  
    4682function codersly_shop_site_branding() {
    4783        $home         = esc_url( home_url( '/' ) );
    48         $has_logo     = codersly_shop_branding_show_logo()
    49                 && function_exists( 'has_custom_logo' ) && has_custom_logo();
     84        $has_logo     = codersly_shop_branding_show_logo() && codersly_shop_has_header_logo();
    5085        $show_title   = codersly_shop_should_show_site_title();
    5186        $show_tagline = codersly_shop_should_show_tagline();
    … …  
    5893        // 1) Logo.
    5994        if ( $has_logo ) {
    60                 $custom_logo_id = (int) get_theme_mod( 'custom_logo' );
    61                 $logo           = wp_get_attachment_image(
    62                         $custom_logo_id,
    63                         'full',
    64                         false,
    65                         array(
    66                                 'class'    => 'site-logo',
    67                                 'style'    => 'max-height:var(--bt-logo-h);height:auto;width:auto;',
    68                                 'loading'  => 'eager',
    69                                 'decoding' => 'async',
    70                         )
    71                 );
     95                $logo = codersly_shop_header_logo_images( 'site-logo' );
    7296                // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    7397                echo '<a class="bt-brand-logo" href="' . $home . '" rel="home" aria-label="' . esc_attr__( 'Home', 'codersly-shop' ) . '">' . $logo . '</a>';
  • codersly-shop/1.2.8/languages/codersly-shop.pot

    r356755 r357926  
    44msgid ""
    55msgstr ""
    6 "Project-Id-Version: Codersly Shop 1.2.7\n"
     6"Project-Id-Version: Codersly Shop 1.2.8\n"
    77"Report-Msgid-Bugs-To: https://codersly.com/support\n"
    88"POT-Creation-Date: 2026-08-31 16:45+0000\n"
  • codersly-shop/1.2.8/readme.txt

    r356755 r357926  
    44Tested up to: 6.9
    55Requires PHP: 7.4
    6 Stable tag: 1.2.7
     6Stable tag: 1.2.8
    77License: GPL-2.0-or-later
    88License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    4646
    4747== Changelog ==
     48
     49= 1.2.8 =
     50* Added independent Desktop and Mobile Sticky Header toggles in Customizer > Headers; mobile defaults off after upgrade.
     51* Increased the mobile header left padding from 8px to 18px, giving the logo and site title more space from the screen edge.
     52* Updated the theme release version metadata to 1.2.8.
    4853
    4954= 1.2.7 =
  • codersly-shop/1.2.8/style.css

    r356755 r357926  
    55Author URI: https://codersly.com/
    66Description: A clean, modern WooCommerce theme for single-store shops. Includes flexible headers, Elementor integration, and widgetized footers. Built for speed, accessibility, and customization via the WordPress Customizer.
    7 Version: 1.2.7
     7Version: 1.2.8
    88Requires at least: 6.3
    99Tested up to: 6.9
  • codersly-shop/1.2.8/template-parts/headers/components/logo.php

    r356755 r357926  
    1515
    1616$show_logo = codersly_shop_branding_show_logo();
    17 $has_logo  = $show_logo && function_exists( 'has_custom_logo' ) && has_custom_logo();
     17$has_logo  = $show_logo && codersly_shop_has_header_logo();
    1818$show_icon = (bool) get_theme_mod( 'codersly_show_site_icon', false );
    1919$has_icon  = $show_icon && function_exists( 'has_site_icon' ) && has_site_icon();
    … …  
    2525
    2626$home_url   = esc_url( home_url( '/' ) );
    27 $max_height = codersly_shop_logo_max_height();
    2827
    2928$args = (
    … …  
    4443                >
    4544                        <?php
    46                         $custom_logo_id = (int) get_theme_mod( 'custom_logo' );
    47                         echo wp_get_attachment_image(
    48                                 $custom_logo_id,
    49                                 'full',
    50                                 false,
    51                                 array(
    52                                         'class'    => 'bt-logo__img',
    53                                         'style'    => 'max-height:' . (int) $max_height . 'px;height:auto;width:auto;',
    54                                         'loading'  => 'eager',
    55                                         'decoding' => 'async',
    56                                 )
    57                         );
     45                        echo codersly_shop_header_logo_images( 'bt-logo__img' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    5846                        ?>
    5947                </a>
  • codersly-shop/1.2.8/template-parts/headers/header-1.php

    r346202 r357926  
    2323if ( get_theme_mod( 'codersly_shop_header_sticky', false ) ) {
    2424    $classes[] = 'bt-header--sticky';
     25}
     26// An independent class allows mobile sticky without enabling desktop sticky.
     27if ( get_theme_mod( 'codersly_shop_header_sticky_mobile', false ) ) {
     28        $classes[] = 'bt-header--sticky-mobile';
    2529}
    2630?>
    … …  
    158162                                'menu_class'     => 'bt-drawer-menu',
    159163                                'fallback_cb'    => '__return_empty_string',
    160                                 'depth'          => 1,
     164                                'depth'          => 0,
    161165                        )
    162166                );
  • codersly-shop/1.2.8/template-parts/headers/header-2.php

    r356755 r357926  
    2828$classes = array( 'bt-header', 'bt-header--v2', 'bt-header--pro' );
    2929
    30 // Sticky header (desktop only; controlled by Customizer).
     30// Desktop sticky (separate mobile toggle below).
    3131if ( get_theme_mod( 'codersly_shop_header_sticky', false ) ) {
    3232    $classes[] = 'bt-header--sticky';
     33}
     34// An independent class allows mobile sticky without enabling desktop sticky.
     35if ( get_theme_mod( 'codersly_shop_header_sticky_mobile', false ) ) {
     36        $classes[] = 'bt-header--sticky-mobile';
    3337}
    3438?>
    … …  
    137141                                'menu_class'     => 'bt-drawer-menu',
    138142                                'fallback_cb'    => '__return_empty_string',
    139                                 'depth'          => 2,
     143                                'depth'          => 0,
    140144                        )
    141145                );
  • codersly-shop/1.2.8/template-parts/headers/header-3.php

    r356755 r357926  
    3535if ( get_theme_mod( 'codersly_shop_header_sticky', false ) ) {
    3636        $classes[] = 'bt-header--sticky';
     37}
     38// An independent class allows mobile sticky without enabling desktop sticky.
     39if ( get_theme_mod( 'codersly_shop_header_sticky_mobile', false ) ) {
     40        $classes[] = 'bt-header--sticky-mobile';
    3741}
    3842?>
    … …  
    152156                                'menu_class'     => 'bt-drawer-menu',
    153157                                'fallback_cb'    => '__return_empty_string',
    154                                 'depth'          => 2,
     158                                'depth'          => 0,
    155159                        )
    156160                );
  • codersly-shop/1.2.8/template-parts/headers/header-4.php

    r356755 r357926  
    2626$classes = array( 'bt-header', 'bt-header--v4', 'bt-header--pro' );
    2727
    28 // Sticky header toggle (desktop only behavior adjusted in CSS below).
     28// Desktop sticky header; mobile has its own independent toggle.
    2929if ( get_theme_mod( 'codersly_shop_header_sticky', false ) ) {
    3030        $classes[] = 'bt-header--sticky';
     31}
     32// An independent class allows mobile sticky without enabling desktop sticky.
     33if ( get_theme_mod( 'codersly_shop_header_sticky_mobile', false ) ) {
     34        $classes[] = 'bt-header--sticky-mobile';
    3135}
    3236?>
  • codersly-shop/1.2.8/template-parts/headers/header-5.php

    r356755 r357926  
    88 * Features:
    99 * - Sticky on Desktop (when enabled from Customizer)
    10  * - Normal on Mobile
     10 * - Optional independent sticky on Mobile
    1111 * - Drawer menu toggle on Mobile
    1212 *
    … …  
    4141if ( get_theme_mod( 'codersly_shop_header_sticky', false ) ) {
    4242        $classes[] = 'bt-header--sticky';
     43}
     44// An independent class allows mobile sticky without enabling desktop sticky.
     45if ( get_theme_mod( 'codersly_shop_header_sticky_mobile', false ) ) {
     46        $classes[] = 'bt-header--sticky-mobile';
    4347}
    4448?>
    … …  
    126130</header>
    127131
    128 <!-- Sticky Desktop / Normal Mobile -->
     132<!-- Desktop and mobile sticky options are controlled independently. -->
    129133
    130134<!-- Mobile header search: page rules are supplied by the Codersly Shop Add-on. -->
    … …  
    150154                                'menu_class'     => 'bt-drawer-menu',
    151155                                'fallback_cb'    => '__return_empty_string',
    152                                 'depth'          => 2,
     156                                'depth'          => 0,
    153157                        )
    154158                );
Note: See TracChangeset for help on using the changeset viewer.