Make WordPress Themes

Changeset 357429


Ignore:
Timestamp:
11/05/2026 02:07:55 PM (10 hours ago)
Author:
themedropbox
Message:

New version of NanoSpace - 2.1.0

Location:
nanospace/2.1.0
Files:
4 added
17 edited
1 copied

Legend:

Unmodified
Added
Removed
  • nanospace/2.1.0/assets/css/woocommerce.css

    r357206 r357429  
    1 body{--wc-primary:var(--nanospace-color-accent);--wc-primary-text:var(--nanospace-color-background);--wc-secondary:color-mix(in srgb, var(--nanospace-color-text) 6%, var(--nanospace-color-background));--wc-secondary-text:var(--nanospace-color-text);--wc-highlight:var(--nanospace-color-accent);--wc-highligh-text:var(--nanospace-color-background);--wc-content-bg:var(--nanospace-color-background);--wc-subtext:var(--nanospace-color-muted);--wc-form-border-color:var(--nanospace-color-muted);--wc-form-border-radius:.75rem;--wc-form-color-background:var(--nanospace-color-background);--wc-form-color-text:var(--nanospace-color-text);--wc-separator-color:var(--nanospace-color-border);--wc-card-border-radius:var(--nanospace-radius-card)}.content-area .site-main>.nanospace-shop,.content-area--sidebar-none .entry-content>.woocommerce,.content-area--sidebar-none .site-main>article:has(>.entry-content>.woocommerce:first-child)>.entry-header{max-inline-size:var(--nanospace-width-wide)}.content-area--sidebar-none .woocommerce-Tabs-panel.entry-content>*{margin-inline:0}.woocommerce ul.products{--nanospace-shop-columns:4;gap:calc(2 * var(--nanospace-space)) var(--nanospace-space);clear:both;grid-template-columns:repeat(2,minmax(0,1fr));display:grid}.woocommerce ul.products.columns-1{--nanospace-shop-columns:1}.woocommerce ul.products.columns-2{--nanospace-shop-columns:2}.woocommerce ul.products.columns-3{--nanospace-shop-columns:3}.woocommerce ul.products.columns-5{--nanospace-shop-columns:5}.woocommerce ul.products.columns-6{--nanospace-shop-columns:6}@media (width>=48rem){.woocommerce ul.products{grid-template-columns:repeat(var(--nanospace-shop-columns), minmax(0, 1fr))}}.woocommerce ul.products:before,.woocommerce ul.products:after{display:none}.woocommerce ul.products[class*=columns-] li.product,.woocommerce-page ul.products[class*=columns-] li.product{float:none;inline-size:auto;margin:0}.woocommerce ul.products li.product .woocommerce-loop-product__title{font-size:var(--nanospace-font-size)}.woocommerce :is(ul.products li.product,div.product) .price{color:var(--nanospace-color-text)}.woocommerce :is(ul.products li.product,div.product) .price del{color:var(--nanospace-color-muted);opacity:1}.woocommerce .price ins{text-decoration:none}.woocommerce span.onsale{background-color:var(--nanospace-color-accent);min-block-size:auto;color:var(--nanospace-color-background);border-radius:var(--nanospace-radius-pill);padding:.25rem .625rem;line-height:1.5}.woocommerce :is(a,button,input).button,.woocommerce #respond input#submit{border-radius:var(--nanospace-radius-pill);background:var(--nanospace-color-pale);color:var(--nanospace-color-text);border:0;padding:.6875rem 1.375rem;font-weight:500;line-height:1.2}.woocommerce :is(a,button,input).button.alt{background:var(--nanospace-color-accent);color:var(--nanospace-color-background)}.woocommerce :is(a,button,input).button:is(:disabled,.disabled){color:var(--nanospace-color-text);padding:.6875rem 1.375rem}.woocommerce :is(form .form-row :is(.input-text,select),.quantity .qty,.woocommerce-ordering select),.woocommerce-page :is(form .form-row :is(.input-text,select),.woocommerce-ordering select){border:1px solid var(--nanospace-color-muted);background-color:var(--nanospace-color-background);color:var(--nanospace-color-text);border-radius:.75rem;padding:.625rem .875rem;line-height:1.2}.woocommerce .quantity .qty{inline-size:4.5em;padding-inline:.5rem}.woocommerce div.product form.cart{flex-wrap:wrap;gap:.5rem;display:flex}.woocommerce div.product form.cart:before,.woocommerce div.product form.cart:after{display:none}.woocommerce div.product form.cart :is(div.quantity,.button){float:none;margin:0}:is(.wc-block-components-text-input input,.wc-block-components-textarea,.wc-blocks-components-select :is(.wc-blocks-components-select__container,.wc-blocks-components-select__select),.wc-block-gateway-container .wc-block-gateway-input){background-color:var(--nanospace-color-background)!important;color:var(--nanospace-color-text)!important}.wc-block-cart:is(.is-mobile,.is-small,.is-medium) table.wc-block-cart-items .wc-block-cart-items__row{grid-template-columns:80px minmax(0,1fr)}.wc-block-cart:is(.is-mobile,.is-small,.is-medium) table.wc-block-cart-items .wc-block-cart-item__quantity{flex-wrap:wrap}.woocommerce form .show-password-input{min-block-size:1.5rem;min-inline-size:1.5rem}:is(.woocommerce-message,.woocommerce-info,.woocommerce-error){border-radius:var(--nanospace-radius-card);background-color:var(--wc-secondary);color:var(--nanospace-color-text)}:is(.woocommerce-message,.woocommerce-info,.woocommerce-error) a:not(.button){color:var(--nanospace-color-accent)}.woocommerce-MyAccount-navigation ul{margin:0 0 var(--nanospace-space);padding:0;list-style:none}.woocommerce-MyAccount-navigation li{border-block-end:1px solid var(--nanospace-color-border)}.woocommerce-MyAccount-navigation a{padding-block:.5rem;text-decoration:none;display:block}.woocommerce-MyAccount-navigation .is-active a{color:var(--nanospace-color-text);font-weight:600}.woocommerce div.product .woocommerce-tabs ul.tabs{border-block-end:1px solid var(--nanospace-color-border);flex-wrap:wrap;gap:.25rem;margin-block-end:var(--nanospace-space);padding:0;display:flex}.woocommerce div.product .woocommerce-tabs ul.tabs:before,.woocommerce div.product .woocommerce-tabs ul.tabs li:before,.woocommerce div.product .woocommerce-tabs ul.tabs li:after{display:none}.woocommerce div.product .woocommerce-tabs ul.tabs li{background:0 0;border:1px solid #0000;border-radius:.375rem .375rem 0 0;margin:0 0 -1px;padding:0}.woocommerce div.product .woocommerce-tabs ul.tabs li a{color:var(--nanospace-color-muted);padding:.625rem 1rem}.woocommerce div.product .woocommerce-tabs ul.tabs li a:hover{text-decoration:underline 1px}.woocommerce div.product .woocommerce-tabs ul.tabs li.active{border-color:var(--nanospace-color-border);border-block-end-color:var(--nanospace-color-background);background:var(--nanospace-color-background)}.woocommerce div.product .woocommerce-tabs ul.tabs li.active a{color:var(--nanospace-color-text)}.woocommerce :is(table.shop_table,table.shop_table :is(td,th),table.shop_attributes,table.shop_attributes :is(td,th),nav.woocommerce-pagination ul,nav.woocommerce-pagination ul li,ul.order_details li,.woocommerce-customer-details address,#reviews #comments ol.commentlist li .comment-text){border-color:var(--nanospace-color-border)}.woocommerce table.shop_attributes tr:nth-child(2n) :is(td,th){background:var(--wc-secondary)}.woocommerce nav.woocommerce-pagination ul li :is(a,span){color:var(--nanospace-color-text)}.woocommerce nav.woocommerce-pagination ul li :is(a:hover,a:focus-visible){text-decoration:underline 1px}.woocommerce nav.woocommerce-pagination ul li span.current{background:var(--wc-secondary);color:var(--nanospace-color-text)}.woocommerce .star-rating:before{color:var(--nanospace-color-border)}.woocommerce :is(small.note,#reviews h2 small,#reviews h2 small a,.woocommerce-breadcrumb),.woocommerce #reviews #comments ol.commentlist li .meta{color:var(--nanospace-color-muted)}:is(.woocommerce-cart,.woocommerce-checkout,#add_payment_method) #payment{border-radius:var(--nanospace-radius-card);background:var(--wc-secondary)}:is(.woocommerce-cart,.woocommerce-checkout,#add_payment_method) #payment div.payment_box{background:var(--nanospace-color-background);color:var(--nanospace-color-text)}:is(.woocommerce-cart,.woocommerce-checkout,#add_payment_method) #payment div.payment_box:before{border-block-end-color:var(--nanospace-color-background)}.woocommerce div.product div.images .woocommerce-product-gallery__trigger{background:var(--nanospace-color-background)}.woocommerce div.product div.images .woocommerce-product-gallery__trigger:before{border-color:var(--nanospace-color-text)}.woocommerce div.product div.images .woocommerce-product-gallery__trigger:after{background:var(--nanospace-color-text)}.nanospace-cart .wc-block-mini-cart__button{min-block-size:2.75rem;min-inline-size:2.75rem;color:inherit}.nanospace-cart .wc-block-mini-cart__button:hover{border-radius:var(--nanospace-radius-pill);background:var(--nanospace-color-pale)}.wc-block-mini-cart__drawer .components-modal__content{background:var(--nanospace-color-background);color:var(--nanospace-color-text)}.wc-block-components-drawer__screen-overlay--is-hidden .wc-block-mini-cart__drawer{visibility:hidden}
     1body{--wc-primary:var(--nanospace-color-accent);--wc-primary-text:var(--nanospace-color-background);--wc-secondary:color-mix(in srgb, var(--nanospace-color-text) 6%, var(--nanospace-color-background));--wc-secondary-text:var(--nanospace-color-text);--wc-highlight:var(--nanospace-color-accent);--wc-highligh-text:var(--nanospace-color-background);--wc-content-bg:var(--nanospace-color-background);--wc-subtext:var(--nanospace-color-muted);--wc-form-border-color:var(--nanospace-color-muted);--wc-form-border-radius:.75rem;--wc-form-color-background:var(--nanospace-color-background);--wc-form-color-text:var(--nanospace-color-text);--wc-separator-color:var(--nanospace-color-border);--wc-card-border-radius:var(--nanospace-radius-card)}.content-area .site-main>.nanospace-shop,.content-area--sidebar-none .entry-content>.woocommerce{max-inline-size:var(--nanospace-width-wide)}.content-area--sidebar-none .site-main:has(>.nanospace-shop)>.page-header--band .page-header__text{padding-inline:max(var(--nanospace-space), (100% - var(--nanospace-width-wide)) / 2)}.content-area--sidebar-none .site-main>article:has(>.entry-content>.woocommerce:first-child)>.entry-header{max-inline-size:var(--nanospace-width-wide)}.content-area--sidebar-none .woocommerce-Tabs-panel.entry-content>*{margin-inline:0}.woocommerce ul.products{--nanospace-shop-columns:4;gap:calc(2 * var(--nanospace-space)) var(--nanospace-space);clear:both;grid-template-columns:repeat(2,minmax(0,1fr));display:grid}.woocommerce ul.products.columns-1{--nanospace-shop-columns:1}.woocommerce ul.products.columns-2{--nanospace-shop-columns:2}.woocommerce ul.products.columns-3{--nanospace-shop-columns:3}.woocommerce ul.products.columns-5{--nanospace-shop-columns:5}.woocommerce ul.products.columns-6{--nanospace-shop-columns:6}@media (width>=48rem){.woocommerce ul.products{grid-template-columns:repeat(var(--nanospace-shop-columns), minmax(0, 1fr))}}.woocommerce ul.products:before,.woocommerce ul.products:after{display:none}.woocommerce ul.products[class*=columns-] li.product,.woocommerce-page ul.products[class*=columns-] li.product{float:none;inline-size:auto;margin:0}.woocommerce ul.products li.product .woocommerce-loop-product__title{font-size:var(--nanospace-font-size)}.woocommerce :is(ul.products li.product,div.product) .price{color:var(--nanospace-color-text)}.woocommerce :is(ul.products li.product,div.product) .price del{color:var(--nanospace-color-muted);opacity:1}.woocommerce .price ins{text-decoration:none}.woocommerce span.onsale{background-color:var(--nanospace-color-accent);min-block-size:auto;color:var(--nanospace-color-background);border-radius:var(--nanospace-radius-pill);padding:.25rem .625rem;line-height:1.5}.woocommerce :is(a,button,input).button,.woocommerce #respond input#submit{border-radius:var(--nanospace-radius-pill);background:var(--nanospace-color-pale);color:var(--nanospace-color-text);border:0;padding:.6875rem 1.375rem;font-weight:500;line-height:1.2}.woocommerce :is(a,button,input).button.alt{background:var(--nanospace-color-accent);color:var(--nanospace-color-background)}.woocommerce :is(a,button,input).button:is(:disabled,.disabled){color:var(--nanospace-color-text);padding:.6875rem 1.375rem}.woocommerce :is(form .form-row :is(.input-text,select),.quantity .qty,.woocommerce-ordering select),.woocommerce-page :is(form .form-row :is(.input-text,select),.woocommerce-ordering select){border:1px solid var(--nanospace-color-muted);background-color:var(--nanospace-color-background);color:var(--nanospace-color-text);border-radius:.75rem;padding:.625rem .875rem;line-height:1.2}.woocommerce .quantity .qty{inline-size:4.5em;padding-inline:.5rem}.woocommerce div.product form.cart{flex-wrap:wrap;gap:.5rem;display:flex}.woocommerce div.product form.cart:before,.woocommerce div.product form.cart:after{display:none}.woocommerce div.product form.cart :is(div.quantity,.button){float:none;margin:0}:is(.wc-block-components-text-input input,.wc-block-components-textarea,.wc-blocks-components-select :is(.wc-blocks-components-select__container,.wc-blocks-components-select__select),.wc-block-gateway-container .wc-block-gateway-input){background-color:var(--nanospace-color-background)!important;color:var(--nanospace-color-text)!important}.wc-block-cart:is(.is-mobile,.is-small,.is-medium) table.wc-block-cart-items .wc-block-cart-items__row{grid-template-columns:80px minmax(0,1fr)}.wc-block-cart:is(.is-mobile,.is-small,.is-medium) table.wc-block-cart-items .wc-block-cart-item__quantity{flex-wrap:wrap}.woocommerce form .show-password-input{min-block-size:1.5rem;min-inline-size:1.5rem}:is(.woocommerce-message,.woocommerce-info,.woocommerce-error){border-radius:var(--nanospace-radius-card);background-color:var(--wc-secondary);color:var(--nanospace-color-text)}:is(.woocommerce-message,.woocommerce-info,.woocommerce-error) a:not(.button){color:var(--nanospace-color-accent)}.woocommerce-MyAccount-navigation ul{margin:0 0 var(--nanospace-space);padding:0;list-style:none}.woocommerce-MyAccount-navigation li{border-block-end:1px solid var(--nanospace-color-border)}.woocommerce-MyAccount-navigation a{padding-block:.5rem;text-decoration:none;display:block}.woocommerce-MyAccount-navigation .is-active a{color:var(--nanospace-color-text);font-weight:600}.woocommerce div.product .woocommerce-tabs ul.tabs{border-block-end:1px solid var(--nanospace-color-border);flex-wrap:wrap;gap:.25rem;margin-block-end:var(--nanospace-space);padding:0;display:flex}.woocommerce div.product .woocommerce-tabs ul.tabs:before,.woocommerce div.product .woocommerce-tabs ul.tabs li:before,.woocommerce div.product .woocommerce-tabs ul.tabs li:after{display:none}.woocommerce div.product .woocommerce-tabs ul.tabs li{background:0 0;border:1px solid #0000;border-radius:.375rem .375rem 0 0;margin:0 0 -1px;padding:0}.woocommerce div.product .woocommerce-tabs ul.tabs li a{color:var(--nanospace-color-muted);padding:.625rem 1rem}.woocommerce div.product .woocommerce-tabs ul.tabs li a:hover{text-decoration:underline 1px}.woocommerce div.product .woocommerce-tabs ul.tabs li.active{border-color:var(--nanospace-color-border);border-block-end-color:var(--nanospace-color-background);background:var(--nanospace-color-background)}.woocommerce div.product .woocommerce-tabs ul.tabs li.active a{color:var(--nanospace-color-text)}.woocommerce :is(table.shop_table,table.shop_table :is(td,th),table.shop_attributes,table.shop_attributes :is(td,th),nav.woocommerce-pagination ul,nav.woocommerce-pagination ul li,ul.order_details li,.woocommerce-customer-details address,#reviews #comments ol.commentlist li .comment-text){border-color:var(--nanospace-color-border)}.woocommerce table.shop_attributes tr:nth-child(2n) :is(td,th){background:var(--wc-secondary)}.woocommerce nav.woocommerce-pagination ul li :is(a,span){color:var(--nanospace-color-text)}.woocommerce nav.woocommerce-pagination ul li :is(a:hover,a:focus-visible){text-decoration:underline 1px}.woocommerce nav.woocommerce-pagination ul li span.current{background:var(--wc-secondary);color:var(--nanospace-color-text)}.woocommerce .star-rating:before{color:var(--nanospace-color-border)}.woocommerce :is(small.note,#reviews h2 small,#reviews h2 small a,.woocommerce-breadcrumb),.woocommerce #reviews #comments ol.commentlist li .meta{color:var(--nanospace-color-muted)}:is(.woocommerce-cart,.woocommerce-checkout,#add_payment_method) #payment{border-radius:var(--nanospace-radius-card);background:var(--wc-secondary)}:is(.woocommerce-cart,.woocommerce-checkout,#add_payment_method) #payment div.payment_box{background:var(--nanospace-color-background);color:var(--nanospace-color-text)}:is(.woocommerce-cart,.woocommerce-checkout,#add_payment_method) #payment div.payment_box:before{border-block-end-color:var(--nanospace-color-background)}.woocommerce div.product div.images .woocommerce-product-gallery__trigger{background:var(--nanospace-color-background)}.woocommerce div.product div.images .woocommerce-product-gallery__trigger:before{border-color:var(--nanospace-color-text)}.woocommerce div.product div.images .woocommerce-product-gallery__trigger:after{background:var(--nanospace-color-text)}.nanospace-cart .wc-block-mini-cart__button{min-block-size:2.75rem;min-inline-size:2.75rem;color:inherit}.nanospace-cart .wc-block-mini-cart__button:hover{border-radius:var(--nanospace-radius-pill);background:var(--nanospace-color-pale)}.wc-block-mini-cart__drawer .components-modal__content{background:var(--nanospace-color-background);color:var(--nanospace-color-text)}.wc-block-components-drawer__screen-overlay--is-hidden .wc-block-mini-cart__drawer{visibility:hidden}
  • nanospace/2.1.0/assets/js/customizer-mega.js

    r357206 r357429  
    1 (()=>{let n=window.wp.customize,{values:i}=window.nanospaceMega,o=t=>`nanospace_mega[${t}]`;function u(t){let e=o(t);return n.has(e)?n(e):n.create(e,e,i[t]??"",{transport:"refresh",previewer:n.previewer})}function r(t){t.params.type==="nav_menu_item"&&t.deferred.embedded.done(()=>{let e=u(t.params.menu_item_id),a=t.container[0].querySelector(".nanospace-mega-toggle"),s=t.container[0].querySelector(".nanospace-mega-columns");if(!a||!s)return;let c=()=>{let d=e.get();a.checked=d!=="",s.value=d||"3",s.disabled=d===""};a.addEventListener("change",()=>e.set(a.checked?s.value:"")),s.addEventListener("change",()=>{a.checked&&e.set(s.value)}),e.bind(c),c()})}n.bind("saved",t=>{for(let e of t.nav_menu_item_updates??[]){if(e.status!=="inserted"||!n.has(o(e.previous_post_id)))continue;let a=n(o(e.previous_post_id));if(i[e.post_id]=a.get(),n.remove(o(e.previous_post_id)),n.has(o(e.post_id))){let s=n(o(e.post_id));s.set(i[e.post_id]),s._dirty=!1}}}),n.control.each(r),n.control.bind("add",r)})();
     1(()=>{let n=window.wp.customize,{values:d}=window.nanospaceMega,o=s=>`nanospace_mega[${s}]`;function u(s){let e=o(s);return n.has(e)?n(e):n.create(e,e,d[s]??"",{transport:"postMessage",previewer:n.previewer})}function c(s){s.params.type==="nav_menu_item"&&s.deferred.embedded.done(()=>{let e=u(s.params.menu_item_id),a=s.container[0].querySelector(".nanospace-mega-toggle"),t=s.container[0].querySelector(".nanospace-mega-columns");if(!a||!t)return;let r=()=>{let i=e.get();a.checked=i!=="",t.value=i||"3",t.disabled=i===""},p=i=>{e.set(i),n.previewer.send("nanospace-mega")};a.addEventListener("change",()=>p(a.checked?t.value:"")),t.addEventListener("change",()=>{a.checked&&p(t.value)}),e.bind(r),r()})}n.bind("saved",s=>{for(let e of s.nav_menu_item_updates??[]){if(e.status!=="inserted"||!n.has(o(e.previous_post_id)))continue;let a=n(o(e.previous_post_id));if(d[e.post_id]=a.get(),n.remove(o(e.previous_post_id)),n.has(o(e.post_id))){let t=n(o(e.post_id));t.set(d[e.post_id]),t._dirty=!1}}}),n.control.each(c),n.control.bind("add",c)})();
  • nanospace/2.1.0/assets/js/editor-layout.js

    r357206 r357429  
    1 (()=>{let{registerPlugin:i}=window.wp.plugins,{PluginDocumentSettingPanel:s}=window.wp.editor,{SelectControl:c,ToggleControl:l}=window.wp.components,{useSelect:d,useDispatch:p}=window.wp.data,n=window.wp.element.createElement,{title:r,selects:w,hideTitle:u}=window.nanospaceLayout;function m(){let t=d(e=>e("core/editor").getEditedPostAttribute("meta"),[]),{editPost:g}=p("core/editor");if(!t||!("_nanospace_width"in t))return null;let a=e=>o=>g({meta:{[e]:o}});return n(s,{name:"nanospace-layout",title:r,className:"nanospace-layout-panel"},...Object.entries(w).map(([e,[o,h]])=>n(c,{key:e,label:o,value:t[e]??"",options:Object.entries(h).map(([_,P])=>({value:_,label:P})),onChange:a(e)})),n(l,{label:u,checked:!!t._nanospace_hide_title,onChange:a("_nanospace_hide_title")}))}i("nanospace-layout",{render:m})})();
     1(()=>{let{registerPlugin:d}=window.wp.plugins,{PluginDocumentSettingPanel:u}=window.wp.editor,{MediaUpload:p,MediaUploadCheck:m}=window.wp.blockEditor,{Button:c,SelectControl:g,ToggleControl:_}=window.wp.components,{useSelect:r,useDispatch:w}=window.wp.data,{createElement:e,useRef:h}=window.wp.element,{title:b,selects:f,hideTitle:v,image:l}=window.nanospaceLayout;function y({id:n,onChange:i}){let o=h(null),a=r(t=>{let s=n?t("core").getMedia(n):null;return s?.media_details?.sizes?.medium?.source_url??s?.source_url??""},[n]);return e("div",{className:"nanospace-band-image",role:"group","aria-labelledby":"nanospace-band-image-label"},e("p",{id:"nanospace-band-image-label"},l.label),a?e("img",{src:a,alt:"",style:{display:"block",maxWidth:"100%"}}):null,e(m,null,e(p,{allowedTypes:["image"],value:n||void 0,onSelect:t=>i(t.id),render:({open:t})=>e(c,{ref:o,variant:"secondary",onClick:t,__next40pxDefaultSize:!0},n?l.replace:l.choose)})),n?e(c,{variant:"link",isDestructive:!0,onClick:()=>{i(0),o.current?.focus()}},l.remove):null,e("p",{className:"components-base-control__help"},l.help))}function C(){let n=r(a=>a("core/editor").getEditedPostAttribute("meta"),[]),{editPost:i}=w("core/editor");if(!n||!("_nanospace_width"in n))return null;let o=a=>t=>i({meta:{[a]:t}});return e(u,{name:"nanospace-layout",title:b,className:"nanospace-layout-panel"},...Object.entries(f).map(([a,[t,s]])=>e(g,{key:a,label:t,value:n[a]??"",options:Object.entries(s).map(([P,k])=>({value:P,label:k})),onChange:o(a)})),e(_,{label:v,checked:!!n._nanospace_hide_title,onChange:o("_nanospace_hide_title")}),e(y,{id:n._nanospace_page_header_image??0,onChange:o("_nanospace_page_header_image")}))}d("nanospace-layout",{render:C})})();
  • nanospace/2.1.0/inc/class-customizer.php

    r357206 r357429  
    8080                self::colors( $wp_customize );
    8181                self::typography( $wp_customize );
     82                self::live_styles( $wp_customize );
    8283                self::layout_section( $wp_customize );
    8384                self::blog( $wp_customize );
    … …  
    116117                                        'default'           => $defaults[ $key ],
    117118                                        'sanitize_callback' => array( Global_Styles::class, 'sanitize_color' ),
     119                                        'transport'         => 'postMessage',
    118120                                )
    119121                        );
    … …  
    161163                                        'default'           => $defaults[ $key ],
    162164                                        'sanitize_callback' => array( Global_Styles::class, 'sanitize_color' ),
     165                                        'transport'         => 'postMessage',
    163166                                )
    164167                        );
    … …  
    210213                                'choices' => $fonts,
    211214                        ),
    212                         'refresh'
     215                        'postMessage'
    213216                );
    214217                self::add(
    … …  
    223226                                'choices' => array( '' => __( 'Same as body', 'nanospace' ) ) + $fonts,
    224227                        ),
    225                         'refresh'
     228                        'postMessage'
    226229                );
    227230                self::add(
    … …  
    236239                                'choices' => $weights,
    237240                        ),
    238                         'refresh'
     241                        'postMessage'
    239242                );
    240243                self::add(
    … …  
    254257                                ),
    255258                        ),
    256                         'refresh'
     259                        'postMessage'
    257260                );
    258261                self::add(
    … …  
    271274                                ),
    272275                        ),
    273                         'refresh'
     276                        'postMessage'
     277                );
     278        }
     279
     280        /**
     281         * Colors and typography preview without reloading the page: the stylesheets they feed are
     282         * rendered again on the server (selective refresh), so the derived colors and the fluid type
     283         * scale come from the same code as on the front end. The dark mode setting itself still
     284         * reloads: it adds and removes scripts.
     285         *
     286         * @param \WP_Customize_Manager $wp_customize Customizer manager.
     287         */
     288        private static function live_styles( \WP_Customize_Manager $wp_customize ): void {
     289                $ids = static fn ( array $keys ): array => array_map( static fn ( string $key ): string => Global_Styles::MOD . "[{$key}]", $keys );
     290
     291                $wp_customize->selective_refresh->add_partial(
     292                        'nanospace_global_styles',
     293                        array(
     294                                'selector'            => '#global-styles-inline-css',
     295                                'settings'            => $ids( array( 'text', 'background', 'accent', 'border', 'font_body', 'font_heading', 'heading_weight', 'font_size', 'line_height' ) ),
     296                                'container_inclusive' => false,
     297                                'render_callback'     => array( Global_Styles::class, 'stylesheet' ),
     298                        )
     299                );
     300                $wp_customize->selective_refresh->add_partial(
     301                        'nanospace_dark_styles',
     302                        array(
     303                                'selector'            => '#nanospace-dark-inline-css',
     304                                'settings'            => $ids( array( 'dark_text', 'dark_background', 'dark_accent', 'dark_border' ) ),
     305                                'container_inclusive' => false,
     306                                'render_callback'     => array( Global_Styles::class, 'dark_css' ),
     307                        )
    274308                );
    275309        }
    … …  
    454488                        )
    455489                );
    456                 $d  = Page_Header::defaults();
    457                 $id = static fn ( string $key ): string => Page_Header::MOD . "[{$key}]";
    458                 foreach ( array(
    459                         'on_archive'  => __( 'Show on the blog, archives and search', 'nanospace' ),
    460                         'on_post'     => __( 'Show on posts', 'nanospace' ),
    461                         'on_page'     => __( 'Show on pages', 'nanospace' ),
    462                         'breadcrumbs' => __( 'Show breadcrumbs (from Yoast SEO, Rank Math or Breadcrumb NavXT)', 'nanospace' ),
    463                 ) as $key => $label ) {
     490                $d      = Page_Header::defaults();
     491                $id     = static fn ( string $key ): string => Page_Header::MOD . "[{$key}]";
     492                $checks = array(
     493                        'on_archive' => __( 'Show on the blog, archives and search', 'nanospace' ),
     494                        'on_post'    => __( 'Show on posts', 'nanospace' ),
     495                        'on_page'    => __( 'Show on pages', 'nanospace' ),
     496                );
     497                if ( Shop::active() ) {
     498                        $checks['on_shop'] = __( 'Show on the shop and product categories (in place of WooCommerce\'s title)', 'nanospace' );
     499                }
     500                $checks['breadcrumbs'] = __( 'Show breadcrumbs (from Yoast SEO, Rank Math or Breadcrumb NavXT)', 'nanospace' );
     501                foreach ( $checks as $key => $label ) {
    464502                        self::add(
    465503                                $wp_customize,
  • nanospace/2.1.0/inc/class-global-styles.php

    r357206 r357429  
    357357
    358358        /**
     359         * The theme.json stylesheet as core prints it for a classic theme (block styles go with each
     360         * block), for the Customizer's selective refresh of colors and typography.
     361         */
     362        public static function stylesheet(): string {
     363                wp_clean_theme_json_cache();
     364                $filtered = false !== has_filter( 'wp_theme_json_get_style_nodes', 'wp_filter_out_block_nodes' );
     365                if ( ! $filtered ) {
     366                        add_filter( 'wp_theme_json_get_style_nodes', 'wp_filter_out_block_nodes' );
     367                }
     368                $css = wp_get_global_stylesheet();
     369                if ( ! $filtered ) {
     370                        remove_filter( 'wp_theme_json_get_style_nodes', 'wp_filter_out_block_nodes' );
     371                }
     372                return $css;
     373        }
     374
     375        /**
    359376         * Dark mode: the dark colors replace the presets while the system asks for dark (`system`) or
    360377         * always (`dark`), unless the visitor chose light; and whenever the visitor chose dark. The
    361          * toggle's script loads when the toggle
    362          * is placed, and always in the Customizer preview, where the toggle can be placed after the
    363          * page loaded.
     378         * rules sit in their own inline style, which the Customizer re-renders when a dark color
     379         * changes. The toggle's script loads when the toggle is placed, and always in the Customizer
     380         * preview, where the toggle can be placed after the page loaded.
    364381         */
    365382        public static function dark_styles(): void {
    … …  
    367384                        return;
    368385                }
     386                wp_register_style( 'nanospace-dark', false, array( 'nanospace' ), Theme::version() );
     387                wp_add_inline_style( 'nanospace-dark', self::dark_css() );
     388                wp_enqueue_style( 'nanospace-dark' );
     389
     390                foreach ( array( 'desktop', 'mobile', 'drawer' ) as $layout ) {
     391                        if ( is_customize_preview() || ( ! Page_Builders::replaces( 'header' ) && in_array( 'scheme', self::flatten( Builder::layout( 'header', $layout ) ), true ) ) ) {
     392                                wp_enqueue_script_module( 'nanospace-scheme', get_theme_file_uri( 'assets/js/scheme.js' ), array(), Theme::version() );
     393                                return;
     394                        }
     395                }
     396        }
     397
     398        /**
     399         * The dark mode rules (see dark_styles()).
     400         */
     401        public static function dark_css(): string {
    369402                $s    = self::settings();
    370403                $vars = sprintf(
    … …  
    383416                        : '';
    384417                $rule = static fn ( string $root ): string => "{$root}{{$vars}}" . ( '' === $logo ? '' : str_replace( '{}', "{$root} ", $logo ) );
    385                 wp_add_inline_style(
    386                         'nanospace',
    387                         ':root[data-nanospace-scheme=light]{color-scheme:light}' .
     418                return ':root[data-nanospace-scheme=light]{color-scheme:light}' .
    388419                        $rule( ':root[data-nanospace-scheme=dark]' ) .
    389420                        ( 'dark' === self::dark()
    390421                                ? $rule( ':root:not([data-nanospace-scheme=light])' )
    391                                 : '@media (prefers-color-scheme:dark){' . $rule( ':root:not([data-nanospace-scheme=light])' ) . '}' )
    392                 );
    393 
    394                 foreach ( array( 'desktop', 'mobile', 'drawer' ) as $layout ) {
    395                         if ( is_customize_preview() || ( ! Page_Builders::replaces( 'header' ) && in_array( 'scheme', self::flatten( Builder::layout( 'header', $layout ) ), true ) ) ) {
    396                                 wp_enqueue_script_module( 'nanospace-scheme', get_theme_file_uri( 'assets/js/scheme.js' ), array(), Theme::version() );
    397                                 return;
    398                         }
    399                 }
     422                                : '@media (prefers-color-scheme:dark){' . $rule( ':root:not([data-nanospace-scheme=light])' ) . '}' );
    400423        }
    401424
  • nanospace/2.1.0/inc/class-layout.php

    r357206 r357429  
    1515/**
    1616 * The `layout` theme mod sets the sidebar per content type (posts, pages, archives). Each post or
    17  * page can override it, and choose a full-width or canvas layout, hide its title, and turn the
    18  * page header band and the transparent header on or off, from a panel in the block editor's sidebar (or a meta box in the
    19  * classic editor). The values are the theme's own post meta.
     17 * page can override it, and choose a full-width or canvas layout, hide its title, turn the
     18 * page header band and the transparent header on or off and give the band its own image, from a
     19 * panel in the block editor's sidebar (or a meta box in the classic editor). The values are the
     20 * theme's own post meta.
    2021 */
    2122final class Layout {
    … …  
    3738
    3839        /**
    39          * Per-post meta: key => allowed values ('' = the site default) or 'bool'.
     40         * Per-post meta: key => allowed values ('' = the site default), 'bool', or 'image' (an image
     41         * attachment ID, 0 = the site default).
    4042         */
    4143        public const META = array(
    42                 '_nanospace_sidebar'     => array( '', 'right', 'left', 'none' ),
    43                 '_nanospace_width'       => array( '', 'full', 'canvas' ),
    44                 '_nanospace_hide_title'  => 'bool',
    45                 '_nanospace_page_header' => array( '', 'on', 'off' ),
    46                 '_nanospace_image_style' => array( '', 'below', 'above', 'header', 'hidden' ),
    47                 '_nanospace_transparent' => array( '', 'on', 'off' ),
     44                '_nanospace_sidebar'           => array( '', 'right', 'left', 'none' ),
     45                '_nanospace_width'             => array( '', 'full', 'canvas' ),
     46                '_nanospace_hide_title'        => 'bool',
     47                '_nanospace_page_header'       => array( '', 'on', 'off' ),
     48                '_nanospace_image_style'       => array( '', 'below', 'above', 'header', 'hidden' ),
     49                '_nanospace_transparent'       => array( '', 'on', 'off' ),
     50                '_nanospace_page_header_image' => 'image',
    4851        );
    4952
    … …  
    5558                add_action( 'enqueue_block_editor_assets', array( self::class, 'editor_assets' ) );
    5659                add_action( 'add_meta_boxes', array( self::class, 'meta_box' ) );
     60                add_action( 'admin_enqueue_scripts', array( self::class, 'meta_box_assets' ) );
    5761                add_action( 'save_post', array( self::class, 'save_meta_box' ), 10, 2 );
    5862                add_filter( 'template_include', array( self::class, 'canvas' ) );
    … …  
    8892         * @param string $key   Meta key.
    8993         * @param mixed  $value Raw value.
    90          * @return string|bool
    91          */
    92         public static function sanitize_meta( string $key, mixed $value ): string|bool {
     94         * @return string|bool|int
     95         */
     96        public static function sanitize_meta( string $key, mixed $value ): string|bool|int {
    9397                $allowed = self::META[ $key ] ?? array();
    9498                if ( 'bool' === $allowed ) {
    9599                        return in_array( $value, array( true, 1, '1', 'true' ), true );
     100                }
     101                if ( 'image' === $allowed ) {
     102                        $id = is_numeric( $value ) ? absint( $value ) : 0;
     103                        return $id && wp_attachment_is_image( $id ) ? $id : 0;
    96104                }
    97105                return in_array( $value, $allowed, true ) ? $value : '';
    … …  
    119127                foreach ( self::post_types() as $type ) {
    120128                        foreach ( self::META as $key => $allowed ) {
    121                                 $bool = 'bool' === $allowed;
     129                                $scalar = match ( $allowed ) {
     130                                        'bool'  => array( 'boolean', false ),
     131                                        'image' => array( 'integer', 0 ),
     132                                        default => null,
     133                                };
    122134                                register_post_meta(
    123135                                        $type,
    124136                                        $key,
    125137                                        array(
    126                                                 'type'              => $bool ? 'boolean' : 'string',
     138                                                'type'              => $scalar ? $scalar[0] : 'string',
    127139                                                'single'            => true,
    128                                                 'default'           => $bool ? false : '',
    129                                                 'show_in_rest'      => $bool ? true : array( 'schema' => array( 'enum' => $allowed ) ),
    130                                                 'sanitize_callback' => static fn ( mixed $value ): string|bool => self::sanitize_meta( $key, $value ),
     140                                                'default'           => $scalar ? $scalar[1] : '',
     141                                                'show_in_rest'      => $scalar ? true : array( 'schema' => array( 'enum' => $allowed ) ),
     142                                                'sanitize_callback' => static fn ( mixed $value ): string|bool|int => self::sanitize_meta( $key, $value ),
    131143                                                'auth_callback'     => static fn ( bool $allowed, string $meta_key, int $post_id ): bool => current_user_can( 'edit_post', $post_id ),
    132144                                        )
    … …  
    141153         * @param string $key Meta key.
    142154         */
    143         public static function meta( string $key ): string|bool {
     155        public static function meta( string $key ): string|bool|int {
    144156                $id = is_singular() ? get_queried_object_id() : 0;
    145157                return self::sanitize_meta( $key, $id ? get_post_meta( $id, $key, true ) : '' );
    … …  
    221233                        return;
    222234                }
    223                 wp_enqueue_script( 'nanospace-editor-layout', get_theme_file_uri( 'assets/js/editor-layout.js' ), array( 'wp-plugins', 'wp-editor', 'wp-components', 'wp-data', 'wp-element' ), Theme::version(), true );
     235                wp_enqueue_script( 'nanospace-editor-layout', get_theme_file_uri( 'assets/js/editor-layout.js' ), array( 'wp-plugins', 'wp-editor', 'wp-block-editor', 'wp-components', 'wp-core-data', 'wp-data', 'wp-element' ), Theme::version(), true );
    224236                wp_add_inline_script(
    225237                        'nanospace-editor-layout',
    … …  
    229241                                        'selects'   => self::labels(),
    230242                                        'hideTitle' => __( 'Hide the title', 'nanospace' ),
     243                                        'image'     => self::image_labels(),
    231244                                )
    232245                        ) . ';',
    233246                        'before'
    234247                );
     248        }
     249
     250        /**
     251         * Labels of the page header image field, shared by the meta box and the editor panel.
     252         *
     253         * @return array{label: string, help: string, choose: string, replace: string, remove: string}
     254         */
     255        public static function image_labels(): array {
     256                return array(
     257                        'label'   => __( 'Page header image', 'nanospace' ),
     258                        'help'    => __( 'Shown behind the page header when it is on. Without one, the image from Customize → Page header.', 'nanospace' ),
     259                        'choose'  => __( 'Choose image', 'nanospace' ),
     260                        'replace' => __( 'Replace image', 'nanospace' ),
     261                        'remove'  => __( 'Remove image', 'nanospace' ),
     262                );
     263        }
     264
     265        /**
     266         * The media library and the image field's script for the classic meta box.
     267         *
     268         * @param string $hook Admin page.
     269         */
     270        public static function meta_box_assets( string $hook ): void {
     271                $screen = get_current_screen();
     272                if ( ! in_array( $hook, array( 'post.php', 'post-new.php' ), true ) || ! $screen || $screen->is_block_editor() || ! in_array( $screen->post_type, self::post_types(), true ) ) {
     273                        return;
     274                }
     275                wp_enqueue_media();
     276                wp_enqueue_script( 'nanospace-meta-box', get_theme_file_uri( 'assets/js/meta-box.js' ), array( 'media-editor' ), Theme::version(), true );
     277                wp_add_inline_script( 'nanospace-meta-box', 'var nanospaceMetaBox = ' . wp_json_encode( self::image_labels() ) . ';', 'before' );
    235278        }
    236279
    … …  
    257300        public static function render_meta_box( \WP_Post $post ): void {
    258301                wp_nonce_field( 'nanospace-layout', 'nanospace-layout-nonce' );
    259                 $value = static fn ( string $key ): string|bool => self::sanitize_meta( $key, get_post_meta( $post->ID, $key, true ) );
     302                $value = static fn ( string $key ): string|bool|int => self::sanitize_meta( $key, get_post_meta( $post->ID, $key, true ) );
    260303                $field = static function ( string $key, string $label, array $choices ) use ( $value ): void {
    261304                        printf( '<p><label for="%1$s">%2$s</label><br><select id="%1$s" name="%1$s">', esc_attr( $key ), esc_html( $label ) );
    … …  
    273316                        esc_html__( 'Hide the title', 'nanospace' )
    274317                );
     318                $image  = (int) $value( '_nanospace_page_header_image' );
     319                $labels = self::image_labels();
     320                printf(
     321                        '<div class="nanospace-band-image" role="group" aria-labelledby="nanospace-band-image-label"><p id="nanospace-band-image-label">%1$s</p><div class="nanospace-band-image__preview">%2$s</div><input type="hidden" name="_nanospace_page_header_image" value="%3$s"><p><button type="button" class="button nanospace-band-image__choose">%4$s</button> <button type="button" class="button-link button-link-delete nanospace-band-image__remove"%5$s>%6$s</button></p><p class="description">%7$s</p></div>',
     322                        esc_html( $labels['label'] ),
     323                        $image ? wp_get_attachment_image(
     324                                $image,
     325                                'medium',
     326                                false,
     327                                array(
     328                                        'alt'   => '',
     329                                        'style' => 'display:block;max-width:100%;height:auto',
     330                                )
     331                        ) : '',
     332                        esc_attr( (string) $image ),
     333                        esc_html( $image ? $labels['replace'] : $labels['choose'] ),
     334                        $image ? '' : ' hidden',
     335                        esc_html( $labels['remove'] ),
     336                        esc_html( $labels['help'] )
     337                );
    275338        }
    276339
    … …  
    291354                }
    292355                update_post_meta( $post_id, '_nanospace_hide_title', isset( $_POST['_nanospace_hide_title'] ) );
     356                $image = isset( $_POST['_nanospace_page_header_image'] ) ? absint( wp_unslash( $_POST['_nanospace_page_header_image'] ) ) : 0;
     357                update_post_meta( $post_id, '_nanospace_page_header_image', self::sanitize_meta( '_nanospace_page_header_image', $image ) );
    293358        }
    294359
  • nanospace/2.1.0/inc/class-mega-menu.php

    r357206 r357429  
    6868                add_action( 'wp_nav_menu_item_custom_fields_customize_template', array( self::class, 'customize_fields' ) );
    6969                add_action( 'customize_controls_enqueue_scripts', array( self::class, 'customize_script' ) );
     70                add_action( 'customize_preview_init', array( self::class, 'preview_script' ) );
    7071        }
    7172
    … …  
    152153                return array(
    153154                        'type'              => 'nanospace_mega',
    154                         'transport'         => 'refresh',
     155                        'transport'         => 'postMessage',
    155156                        'capability'        => 'edit_theme_options',
    156157                        'default'           => '',
    … …  
    212213                wp_enqueue_script( 'nanospace-customizer-mega', get_theme_file_uri( 'assets/js/customizer-mega.js' ), array( 'customize-nav-menus' ), Theme::version(), true );
    213214                wp_add_inline_script( 'nanospace-customizer-mega', 'var nanospaceMega = ' . wp_json_encode( array( 'values' => (object) $values ) ) . ';', 'before' );
     215        }
     216
     217        /**
     218         * In the preview: the script that re-renders the header menus (selective refresh) when a
     219         * field changes, and the panel styles, which a menu may need once a field is ticked.
     220         */
     221        public static function preview_script(): void {
     222                wp_enqueue_script( 'nanospace-customize-preview-mega', get_theme_file_uri( 'assets/js/customize-preview-mega.js' ), array( 'customize-preview', 'customize-selective-refresh' ), Theme::version(), true );
     223                add_action( 'wp_enqueue_scripts', array( self::class, 'enqueue_styles' ) );
     224        }
     225
     226        /**
     227         * The panel styles.
     228         */
     229        public static function enqueue_styles(): void {
     230                wp_enqueue_style( 'nanospace-mega', get_theme_file_uri( 'assets/css/mega-menu.css' ), array( 'nanospace' ), Theme::version() );
    214231        }
    215232
    … …  
    331348                        foreach ( is_array( $items ) ? $items : array() as $item ) {
    332349                                if ( 0 === (int) $item->menu_item_parent && self::is_mega( (int) $item->ID ) ) {
    333                                         wp_enqueue_style( 'nanospace-mega', get_theme_file_uri( 'assets/css/mega-menu.css' ), array( 'nanospace' ), Theme::version() );
     350                                        self::enqueue_styles();
    334351                                        return;
    335352                                }
  • nanospace/2.1.0/inc/class-page-header.php

    r357206 r357429  
    1414
    1515/**
    16  * The `page_header` theme mod turns the band on per content type (archives on by default) and
    17  * sets its image, overlay and breadcrumbs; a post or page can turn it on or off for itself
    18  * (`_nanospace_page_header`, NanoSpace\Layout). Without the band, archives keep a plain title.
     16 * The `page_header` theme mod turns the band on per content type (archives on by default; the
     17 * WooCommerce shop and product archives off) and sets its image, overlay and breadcrumbs; a post
     18 * or page can turn it on or off for itself (`_nanospace_page_header`, NanoSpace\Layout) and
     19 * give it its own image (`_nanospace_page_header_image`). Without
     20 * the band, archives keep a plain title and WooCommerce prints its own.
    1921 *
    2022 * Breadcrumbs come from Yoast SEO, Rank Math or Breadcrumb NavXT when one is active; the theme
    … …  
    3133         * Defaults.
    3234         *
    33          * @return array{on_archive: bool, on_post: bool, on_page: bool, breadcrumbs: bool, image: int, overlay: int}
     35         * @return array{on_archive: bool, on_post: bool, on_page: bool, on_shop: bool, breadcrumbs: bool, image: int, overlay: int}
    3436         */
    3537        public static function defaults(): array {
    … …  
    3840                        'on_post'     => false,
    3941                        'on_page'     => false,
     42                        'on_shop'     => false,
    4043                        'breadcrumbs' => true,
    4144                        'image'       => 0,
    … …  
    4750         * Stored settings over the defaults, sanitized.
    4851         *
    49          * @return array{on_archive: bool, on_post: bool, on_page: bool, breadcrumbs: bool, image: int, overlay: int}
     52         * @return array{on_archive: bool, on_post: bool, on_page: bool, on_shop: bool, breadcrumbs: bool, image: int, overlay: int}
    5053         */
    5154        public static function settings(): array {
    … …  
    5760                        'on_post'     => Blog::sanitize_bool( $stored['on_post'] ?? $d['on_post'] ),
    5861                        'on_page'     => Blog::sanitize_bool( $stored['on_page'] ?? $d['on_page'] ),
     62                        'on_shop'     => Blog::sanitize_bool( $stored['on_shop'] ?? $d['on_shop'] ),
    5963                        'breadcrumbs' => Blog::sanitize_bool( $stored['breadcrumbs'] ?? $d['breadcrumbs'] ),
    6064                        'image'       => absint( $stored['image'] ?? 0 ),
    … …  
    7478
    7579        /**
    76          * Whether the band shows on the current view.
     80         * Whether the band shows on the current view. On WooCommerce's views only the shop, product
     81         * archives and product search can have it; a product keeps WooCommerce's title.
    7782         */
    7883        public static function shown(): bool {
    79                 if ( is_404() || ( is_front_page() && is_home() ) || Shop::view() || Community::view() ) {
     84                if ( is_404() || ( is_front_page() && is_home() ) || Community::view() ) {
    8085                        return false;
     86                }
     87                if ( Shop::view() ) {
     88                        return ! is_singular() && self::settings()['on_shop'];
    8189                }
    8290                $own = Layout::meta( '_nanospace_page_header' );
    … …  
    92100
    93101        /**
    94          * The band's title: the post, archive or search title, or the blog page's.
     102         * The band's image: the post's or page's own (`_nanospace_page_header_image`), else the
     103         * site-wide one; 0 for none.
     104         */
     105        public static function image(): int {
     106                $own = (int) Layout::meta( '_nanospace_page_header_image' );
     107                return $own ? $own : self::settings()['image'];
     108        }
     109
     110        /**
     111         * The band's title: the post, archive or search title, the blog page's, or WooCommerce's
     112         * shop, product archive or product search title.
    95113         */
    96114        public static function title(): string {
     115                if ( Shop::view() ) {
     116                        return wp_kses_post( woocommerce_page_title( false ) );
     117                }
    97118                if ( is_singular() ) {
    98119                        return Layout::hide_title() ? '' : esc_html( single_post_title( '', false ) ?? '' );
    … …  
    129150
    130151        /**
     152         * The archive description under the band's title. Not on the shop: its post type
     153         * description is WooCommerce's own boilerplate, and the shop page's content prints below.
     154         */
     155        public static function description(): void {
     156                if ( ! is_singular() && ! ( Shop::view() && is_shop() ) ) {
     157                        the_archive_description( '<div class="archive-description">', '</div>' );
     158                }
     159        }
     160
     161        /**
    131162         * Prints the band, or on archives without it the plain title; nothing on bbPress and
    132          * BuddyPress views, whose page title is the h1.
     163         * BuddyPress views, whose page title is the h1, nor on WooCommerce's without the band.
    133164         */
    134165        public static function render(): void {
    … …  
    138169                if ( self::shown() ) {
    139170                        get_template_part( 'template-parts/page-header' );
    140                 } elseif ( ! is_singular() && ! is_home() && ! is_404() ) {
     171                } elseif ( ! is_singular() && ! is_home() && ! is_404() && ! Shop::view() ) {
    141172                        echo '<header class="page-header"><h1 class="page-title">' . self::title() . '</h1>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped in title().
    142173                        the_archive_description( '<div class="archive-description">', '</div>' );
  • nanospace/2.1.0/inc/class-shop.php

    r357206 r357429  
    1616 * per page in Customize → WooCommerce → Product Catalog), a "Shop sidebar" widget area beside the
    1717 * shop and products (sidebar per `layout[sidebar_shop]`, right by default), the cart (WooCommerce's
    18  * Mini-Cart block) and account header elements, and `woocommerce.css`, which maps WooCommerce's
     18 * Mini-Cart block) and account header elements, the page header band on the shop and product
     19 * archives when it is on, and `woocommerce.css`, which maps WooCommerce's
    1920 * colors and controls to the theme's tokens. Block and shortcode cart and checkout both take the
    2021 * theme's buttons and fields; the cart and checkout never have a sidebar.
    … …  
    5455                add_action( 'wp_enqueue_scripts', array( self::class, 'enqueue' ), 20 );
    5556                add_filter( 'woocommerce_checkout_coupon_message', array( self::class, 'coupon_message' ) );
     57                add_action( 'template_redirect', array( self::class, 'band' ) );
     58        }
     59
     60        /**
     61         * Under the page header band (`page_header[on_shop]`), the band has the title and a product
     62         * archive's description, so WooCommerce prints neither.
     63         */
     64        public static function band(): void {
     65                if ( self::view() && Page_Header::shown() ) {
     66                        add_filter( 'woocommerce_show_page_title', '__return_false' );
     67                        remove_action( 'woocommerce_archive_description', 'woocommerce_taxonomy_archive_description' );
     68                }
    5669        }
    5770
  • nanospace/2.1.0/languages/nanospace.pot

    r357220 r357429  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: NanoSpace 2.0.1\n"
     5"Project-Id-Version: NanoSpace 2.1.0\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/theme/nanospace\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
    … …  
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2026-11-01T04:29:05+00:00\n"
     12"POT-Creation-Date: 2026-11-05T00:13:41+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.12.0\n"
    … …  
    9797
    9898#: inc/class-admin.php:134
    99 #: inc/class-customizer.php:767
     99#: inc/class-customizer.php:805
    100100msgid "Footer credit"
    101101msgstr ""
    … …  
    165165#: inc/class-builder-control.php:56
    166166#: inc/class-builder.php:162
    167 #: inc/class-customizer.php:725
     167#: inc/class-customizer.php:763
    168168#: inc/class-page-builders.php:99
    169169#: inc/class-starter-content.php:66
    … …  
    388388msgstr ""
    389389
    390 #: inc/class-customizer.php:99
     390#: inc/class-customizer.php:100
    391391msgid "Colors"
    392392msgstr ""
    393393
    394 #: inc/class-customizer.php:100
     394#: inc/class-customizer.php:101
    395395msgid "Muted text and the link hover color are derived from these. A warning shows when text or the accent falls below WCAG AA contrast."
    396396msgstr ""
    397397
    398 #: inc/class-customizer.php:107
     398#: inc/class-customizer.php:108
    399399#: inc/class-global-styles.php:321
    400400msgid "Text"
    401401msgstr ""
    402402
    403 #: inc/class-customizer.php:108
     403#: inc/class-customizer.php:109
    404404#: inc/class-global-styles.php:322
    405405msgid "Background"
    406406msgstr ""
    407407
    408 #: inc/class-customizer.php:109
     408#: inc/class-customizer.php:110
    409409msgid "Accent (links, buttons)"
    410410msgstr ""
    411411
    412 #: inc/class-customizer.php:110
     412#: inc/class-customizer.php:111
    413413msgid "Borders and dividers"
    414414msgstr ""
    415415
    416 #: inc/class-customizer.php:140
     416#: inc/class-customizer.php:142
    417417#: template-parts/builder/scheme-toggle.php:17
    418418msgid "Dark mode"
    419419msgstr ""
    420420
    421 #: inc/class-customizer.php:141
     421#: inc/class-customizer.php:143
    422422msgid "Follow each visitor's system setting, or start every visitor in dark. Add the Dark mode toggle to the header to let visitors switch."
    423423msgstr ""
    424424
    425 #: inc/class-customizer.php:143
    426 #: inc/class-customizer.php:552
    427 #: inc/class-customizer.php:587
    428 #: inc/class-layout.php:343
     425#: inc/class-customizer.php:145
     426#: inc/class-customizer.php:590
     427#: inc/class-customizer.php:625
     428#: inc/class-layout.php:408
    429429msgid "Off"
    430430msgstr ""
    431431
    432 #: inc/class-customizer.php:144
     432#: inc/class-customizer.php:146
    433433msgid "Follow the visitor's system"
    434434msgstr ""
    435435
    436 #: inc/class-customizer.php:145
     436#: inc/class-customizer.php:147
    437437msgid "Start in dark"
    438438msgstr ""
    439439
    440 #: inc/class-customizer.php:152
     440#: inc/class-customizer.php:154
    441441msgid "Dark mode: text"
    442442msgstr ""
    443443
    444 #: inc/class-customizer.php:153
     444#: inc/class-customizer.php:155
    445445msgid "Dark mode: background"
    446446msgstr ""
    447447
    448 #: inc/class-customizer.php:154
     448#: inc/class-customizer.php:156
    449449msgid "Dark mode: accent"
    450450msgstr ""
    451451
    452 #: inc/class-customizer.php:155
     452#: inc/class-customizer.php:157
    453453msgid "Dark mode: borders and dividers"
    454454msgstr ""
    455455
    456 #: inc/class-customizer.php:188
     456#: inc/class-customizer.php:191
    457457msgid "Typography"
    458458msgstr ""
    459459
    460 #: inc/class-customizer.php:209
     460#: inc/class-customizer.php:212
    461461msgid "Body font"
    462462msgstr ""
    463463
    464 #: inc/class-customizer.php:222
     464#: inc/class-customizer.php:225
    465465msgid "Heading font"
    466466msgstr ""
    467467
    468 #: inc/class-customizer.php:223
     468#: inc/class-customizer.php:226
    469469msgid "Same as body"
    470470msgstr ""
    471471
    472 #: inc/class-customizer.php:235
     472#: inc/class-customizer.php:238
    473473msgid "Heading weight"
    474474msgstr ""
    475475
    476 #: inc/class-customizer.php:248
     476#: inc/class-customizer.php:251
    477477msgid "Base font size (px)"
    478478msgstr ""
    479479
    480 #: inc/class-customizer.php:249
     480#: inc/class-customizer.php:252
    481481msgid "Headings scale with it."
    482482msgstr ""
    483483
    484 #: inc/class-customizer.php:266
     484#: inc/class-customizer.php:269
    485485msgid "Line height"
    486486msgstr ""
    487487
    488 #: inc/class-customizer.php:286
    489 #: inc/class-layout.php:228
    490 #: inc/class-layout.php:243
     488#: inc/class-customizer.php:320
     489#: inc/class-layout.php:240
     490#: inc/class-layout.php:286
    491491msgid "Layout"
    492492msgstr ""
    493493
    494 #: inc/class-customizer.php:287
     494#: inc/class-customizer.php:321
    495495msgid "A post or page can choose its own sidebar in its Layout panel. The sidebar shows only while the Sidebar widget area has widgets."
    496496msgstr ""
    497497
    498 #: inc/class-customizer.php:292
    499 #: inc/class-layout.php:307
     498#: inc/class-customizer.php:326
     499#: inc/class-layout.php:372
    500500msgid "Right"
    501501msgstr ""
    502502
    503 #: inc/class-customizer.php:293
    504 #: inc/class-layout.php:308
     503#: inc/class-customizer.php:327
     504#: inc/class-layout.php:373
    505505msgid "Left"
    506506msgstr ""
    507507
    508 #: inc/class-customizer.php:294
    509 #: inc/class-layout.php:309
     508#: inc/class-customizer.php:328
     509#: inc/class-layout.php:374
    510510msgid "None"
    511511msgstr ""
    512512
    513 #: inc/class-customizer.php:297
     513#: inc/class-customizer.php:331
    514514msgid "Sidebar on posts"
    515515msgstr ""
    516516
    517 #: inc/class-customizer.php:298
     517#: inc/class-customizer.php:332
    518518msgid "Sidebar on pages"
    519519msgstr ""
    520520
    521 #: inc/class-customizer.php:299
     521#: inc/class-customizer.php:333
    522522msgid "Sidebar on the blog, archives and search"
    523523msgstr ""
    524524
    525 #: inc/class-customizer.php:302
     525#: inc/class-customizer.php:336
    526526msgid "Sidebar on the shop and products (Shop sidebar widgets; never on the cart or checkout)"
    527527msgstr ""
    528528
    529 #: inc/class-customizer.php:330
     529#: inc/class-customizer.php:364
    530530msgid "Blog"
    531531msgstr ""
    532532
    533 #: inc/class-customizer.php:345
     533#: inc/class-customizer.php:379
    534534msgid "Archive layout"
    535535msgstr ""
    536536
    537 #: inc/class-customizer.php:346
     537#: inc/class-customizer.php:380
    538538msgid "For the blog, categories, tags, authors, dates and search results."
    539539msgstr ""
    540540
    541 #: inc/class-customizer.php:348
     541#: inc/class-customizer.php:382
    542542msgid "List, image beside the excerpt"
    543543msgstr ""
    544544
    545 #: inc/class-customizer.php:349
     545#: inc/class-customizer.php:383
    546546msgid "Grid of cards"
    547547msgstr ""
    548548
    549 #: inc/class-customizer.php:350
     549#: inc/class-customizer.php:384
    550550msgid "Minimal: titles and dates"
    551551msgstr ""
    552552
    553 #: inc/class-customizer.php:363
     553#: inc/class-customizer.php:397
    554554msgid "Grid columns on wide screens"
    555555msgstr ""
    556556
    557 #: inc/class-customizer.php:379
     557#: inc/class-customizer.php:413
    558558msgid "Excerpt length (words)"
    559559msgstr ""
    560560
    561 #: inc/class-customizer.php:396
     561#: inc/class-customizer.php:430
    562562msgid "Show featured images in archives"
    563563msgstr ""
    564564
    565 #: inc/class-customizer.php:410
     565#: inc/class-customizer.php:444
    566566msgid "Featured image on posts and pages"
    567567msgstr ""
    568568
    569 #: inc/class-customizer.php:411
     569#: inc/class-customizer.php:445
    570570msgid "A post or page can choose its own in its Layout panel."
    571571msgstr ""
    572572
    573 #: inc/class-customizer.php:413
    574 #: inc/class-layout.php:324
     573#: inc/class-customizer.php:447
     574#: inc/class-layout.php:389
    575575msgid "Below the title"
    576576msgstr ""
    577577
    578 #: inc/class-customizer.php:414
    579 #: inc/class-layout.php:325
     578#: inc/class-customizer.php:448
     579#: inc/class-layout.php:390
    580580msgid "Above the title"
    581581msgstr ""
    582582
    583 #: inc/class-customizer.php:415
    584 #: inc/class-layout.php:326
     583#: inc/class-customizer.php:449
     584#: inc/class-layout.php:391
    585585msgid "Header with the title on it"
    586586msgstr ""
    587587
    588 #: inc/class-customizer.php:416
    589 #: inc/class-layout.php:327
     588#: inc/class-customizer.php:450
     589#: inc/class-layout.php:392
    590590msgid "Hidden"
    591591msgstr ""
    592592
    593 #: inc/class-customizer.php:422
     593#: inc/class-customizer.php:456
    594594msgid "Author box on posts (when the author has a biography)"
    595595msgstr ""
    596596
    597 #: inc/class-customizer.php:423
     597#: inc/class-customizer.php:457
    598598msgid "Previous and next post links"
    599599msgstr ""
    600600
    601 #: inc/class-customizer.php:424
     601#: inc/class-customizer.php:458
    602602msgid "Reading time on posts"
    603603msgstr ""
    604604
    605 #: inc/class-customizer.php:425
     605#: inc/class-customizer.php:459
    606606msgid "Reading progress bar on posts"
    607607msgstr ""
    608608
    609 #: inc/class-customizer.php:451
    610 #: inc/class-layout.php:331
     609#: inc/class-customizer.php:485
     610#: inc/class-layout.php:396
    611611#: inc/class-theme.php:49
    612612msgid "Page header"
    613613msgstr ""
    614614
    615 #: inc/class-customizer.php:452
     615#: inc/class-customizer.php:486
    616616msgid "A band at the top of the content with the title, breadcrumbs and the Page header widget area. A post or page can turn it on or off in its Layout panel."
    617617msgstr ""
    618618
    619 #: inc/class-customizer.php:459
     619#: inc/class-customizer.php:493
    620620msgid "Show on the blog, archives and search"
    621621msgstr ""
    622622
    623 #: inc/class-customizer.php:460
     623#: inc/class-customizer.php:494
    624624msgid "Show on posts"
    625625msgstr ""
    626626
    627 #: inc/class-customizer.php:461
     627#: inc/class-customizer.php:495
    628628msgid "Show on pages"
    629629msgstr ""
    630630
    631 #: inc/class-customizer.php:462
     631#: inc/class-customizer.php:498
     632msgid "Show on the shop and product categories (in place of WooCommerce's title)"
     633msgstr ""
     634
     635#: inc/class-customizer.php:500
    632636msgid "Show breadcrumbs (from Yoast SEO, Rank Math or Breadcrumb NavXT)"
    633637msgstr ""
    634638
    635 #: inc/class-customizer.php:490
     639#: inc/class-customizer.php:528
    636640msgid "Background image"
    637641msgstr ""
    638642
    639 #: inc/class-customizer.php:503
     643#: inc/class-customizer.php:541
    640644msgid "Overlay on the image (%)"
    641645msgstr ""
    642646
    643 #: inc/class-customizer.php:504
     647#: inc/class-customizer.php:542
    644648msgid "At least 60%, so white text stays readable on any image."
    645649msgstr ""
    646650
    647 #: inc/class-customizer.php:524
     651#: inc/class-customizer.php:562
    648652#: inc/class-page-builders.php:70
    649653#: inc/class-theme.php:45
    … …  
    651655msgstr ""
    652656
    653 #: inc/class-customizer.php:530
     657#: inc/class-customizer.php:568
    654658msgid "Header layout"
    655659msgstr ""
    656660
    657 #: inc/class-customizer.php:540
     661#: inc/class-customizer.php:578
    658662msgid "Mobile header below (px)"
    659663msgstr ""
    660664
    661 #: inc/class-customizer.php:541
     665#: inc/class-customizer.php:579
    662666msgid "Screens narrower than this show the mobile header and menu button."
    663667msgstr ""
    664668
    665 #: inc/class-customizer.php:553
     669#: inc/class-customizer.php:591
    666670msgid "Always"
    667671msgstr ""
    668672
    669 #: inc/class-customizer.php:554
     673#: inc/class-customizer.php:592
    670674msgid "Reveal on scroll up"
    671675msgstr ""
    672676
    673 #: inc/class-customizer.php:557
     677#: inc/class-customizer.php:595
    674678msgid "Sticky header: desktop"
    675679msgstr ""
    676680
    677 #: inc/class-customizer.php:558
     681#: inc/class-customizer.php:596
    678682msgid "Sticky header: mobile"
    679683msgstr ""
    680684
    681 #: inc/class-customizer.php:569
     685#: inc/class-customizer.php:607
    682686msgid "Keeps the main header row at the top of the window. \"Reveal on scroll up\" hides it while scrolling down."
    683687msgstr ""
    684688
    685 #: inc/class-customizer.php:584
    686 #: inc/class-layout.php:339
     689#: inc/class-customizer.php:622
     690#: inc/class-layout.php:404
    687691msgid "Transparent header"
    688692msgstr ""
    689693
    690 #: inc/class-customizer.php:585
     694#: inc/class-customizer.php:623
    691695msgid "Lays the header over the image at the top of the page: the page header with a background image, or a post's image header, on views without a sidebar. Elsewhere the header stays solid. A post or page can turn it on or off in its Layout panel."
    692696msgstr ""
    693697
    694 #: inc/class-customizer.php:588
     698#: inc/class-customizer.php:626
    695699msgid "Front page"
    696700msgstr ""
    697701
    698 #: inc/class-customizer.php:589
     702#: inc/class-customizer.php:627
    699703msgid "All pages"
    700704msgstr ""
    701705
    702 #: inc/class-customizer.php:602
     706#: inc/class-customizer.php:640
    703707msgid "Transparent header: text"
    704708msgstr ""
    705709
    706 #: inc/class-customizer.php:603
     710#: inc/class-customizer.php:641
    707711msgid "Light text sits on a dark overlay over the image; dark text turns the overlay white. Either stays readable on any image."
    708712msgstr ""
    709713
    710 #: inc/class-customizer.php:605
     714#: inc/class-customizer.php:643
    711715msgid "Light"
    712716msgstr ""
    713717
    714 #: inc/class-customizer.php:606
     718#: inc/class-customizer.php:644
    715719msgid "Dark"
    716720msgstr ""
    717721
    718 #: inc/class-customizer.php:624
     722#: inc/class-customizer.php:662
    719723msgid "Transparent header: logo"
    720724msgstr ""
    721725
    722 #: inc/class-customizer.php:625
     726#: inc/class-customizer.php:663
    723727msgid "Optional. Shown instead of the logo while the header is transparent, e.g. a white version."
    724728msgstr ""
    725729
    726730#. translators: %d: button number.
    727 #: inc/class-customizer.php:640
     731#: inc/class-customizer.php:678
    728732#, php-format
    729733msgid "Button %d: label"
    730734msgstr ""
    731735
    732 #: inc/class-customizer.php:641
     736#: inc/class-customizer.php:679
    733737msgid "The button shows once it has a label."
    734738msgstr ""
    735739
    736740#. translators: %d: button number.
    737 #: inc/class-customizer.php:653
     741#: inc/class-customizer.php:691
    738742#, php-format
    739743msgid "Button %d: link"
    740744msgstr ""
    741745
    742 #: inc/class-customizer.php:661
     746#: inc/class-customizer.php:699
    743747msgid "Announcement: text"
    744748msgstr ""
    745749
    746 #: inc/class-customizer.php:661
     750#: inc/class-customizer.php:699
    747751msgid "One short line. The announcement shows once it has text."
    748752msgstr ""
    749753
    750 #: inc/class-customizer.php:662
     754#: inc/class-customizer.php:700
    751755msgid "Announcement: badge"
    752756msgstr ""
    753757
    754 #: inc/class-customizer.php:662
     758#: inc/class-customizer.php:700
    755759msgid "A word before the text, such as \"New\". Optional."
    756760msgstr ""
    757761
    758 #: inc/class-customizer.php:663
     762#: inc/class-customizer.php:701
    759763msgid "Announcement: link"
    760764msgstr ""
    761765
    762 #: inc/class-customizer.php:664
     766#: inc/class-customizer.php:702
    763767msgid "Announcement: link text"
    764768msgstr ""
    765769
    766 #: inc/class-customizer.php:664
     770#: inc/class-customizer.php:702
    767771msgid "Shown when there is a link. Default: \"Learn more\"."
    768772msgstr ""
    769773
    770 #: inc/class-customizer.php:697
     774#: inc/class-customizer.php:735
    771775msgid "Logo in dark mode"
    772776msgstr ""
    773777
    774 #: inc/class-customizer.php:698
     778#: inc/class-customizer.php:736
    775779msgid "Optional. Shown instead of the logo while dark colors show (Colors → Dark mode), e.g. a light version. Needs a logo above."
    776780msgstr ""
    777781
    778 #: inc/class-customizer.php:730
     782#: inc/class-customizer.php:768
    779783msgid "Footer layout"
    780784msgstr ""
    781785
    782 #: inc/class-customizer.php:739
     786#: inc/class-customizer.php:777
    783787msgid "Footer widget columns"
    784788msgstr ""
    785789
    786 #: inc/class-customizer.php:740
     790#: inc/class-customizer.php:778
    787791msgid "Each widget in the Footer area fills one column. Columns stack on small screens."
    788792msgstr ""
    789793
    790794#. translators: %s: list of tokens such as {year}.
    791 #: inc/class-customizer.php:770
     795#: inc/class-customizer.php:808
    792796#, php-format
    793797msgid "Leave empty to show no credit. Tokens: %s."
    794798msgstr ""
    795799
    796 #: inc/class-customizer.php:806
     800#: inc/class-customizer.php:844
    797801#: inc/class-social.php:101
    798802msgid "Social profiles"
    799803msgstr ""
    800804
    801 #: inc/class-customizer.php:807
     805#: inc/class-customizer.php:845
    802806msgid "Fill in the profiles to link. The Social icons element of the header or footer shows them."
    803807msgstr ""
    804808
    805809#. translators: %d: HTML element number.
    806 #: inc/class-customizer.php:894
     810#: inc/class-customizer.php:932
    807811#, php-format
    808812msgid "HTML %d"
    809813msgstr ""
    810814
    811 #: inc/class-customizer.php:895
     815#: inc/class-customizer.php:933
    812816msgid "Text or HTML for the HTML element. Shows once it has content."
    813817msgstr ""
    … …  
    837841msgstr ""
    838842
    839 #: inc/class-global-styles.php:436
     843#: inc/class-global-styles.php:459
    840844msgid "Small"
    841845msgstr ""
    842846
    843 #: inc/class-global-styles.php:437
     847#: inc/class-global-styles.php:460
    844848msgid "Medium"
    845849msgstr ""
    846850
    847 #: inc/class-global-styles.php:438
     851#: inc/class-global-styles.php:461
    848852msgid "Large"
    849853msgstr ""
    850854
    851 #: inc/class-global-styles.php:439
     855#: inc/class-global-styles.php:462
    852856msgid "Extra large"
    853857msgstr ""
    854858
    855 #: inc/class-global-styles.php:440
     859#: inc/class-global-styles.php:463
    856860msgid "Huge"
    857861msgstr ""
    858862
    859 #: inc/class-layout.php:230
    860 #: inc/class-layout.php:273
     863#: inc/class-layout.php:242
     864#: inc/class-layout.php:316
    861865msgid "Hide the title"
    862866msgstr ""
    863867
    864 #: inc/class-layout.php:301
     868#: inc/class-layout.php:257
     869msgid "Page header image"
     870msgstr ""
     871
     872#: inc/class-layout.php:258
     873msgid "Shown behind the page header when it is on. Without one, the image from Customize → Page header."
     874msgstr ""
     875
     876#: inc/class-layout.php:259
     877msgid "Choose image"
     878msgstr ""
     879
     880#: inc/class-layout.php:260
     881msgid "Replace image"
     882msgstr ""
     883
     884#: inc/class-layout.php:261
     885msgid "Remove image"
     886msgstr ""
     887
     888#: inc/class-layout.php:366
    865889msgid "Default"
    866890msgstr ""
    867891
    868 #: inc/class-layout.php:304
     892#: inc/class-layout.php:369
    869893#: inc/class-page-builders.php:92
    870894#: inc/class-theme.php:41
    … …  
    873897msgstr ""
    874898
    875 #: inc/class-layout.php:313
     899#: inc/class-layout.php:378
    876900msgid "Content width"
    877901msgstr ""
    878902
    879 #: inc/class-layout.php:316
     903#: inc/class-layout.php:381
    880904msgid "Full width, for page builders"
    881905msgstr ""
    882906
    883 #: inc/class-layout.php:317
     907#: inc/class-layout.php:382
    884908msgid "Canvas: no header or footer"
    885909msgstr ""
    886910
    887 #: inc/class-layout.php:321
     911#: inc/class-layout.php:386
    888912msgid "Featured image"
    889913msgstr ""
    890914
    891 #: inc/class-layout.php:334
     915#: inc/class-layout.php:399
    892916msgid "Show"
    893917msgstr ""
    894918
    895 #: inc/class-layout.php:335
     919#: inc/class-layout.php:400
    896920msgid "Hide"
    897921msgstr ""
    898922
    899 #: inc/class-layout.php:342
     923#: inc/class-layout.php:407
    900924msgid "On, over the page header or image header"
    901925msgstr ""
    902926
    903 #: inc/class-mega-menu.php:180
    904 #: inc/class-mega-menu.php:247
     927#: inc/class-mega-menu.php:181
     928#: inc/class-mega-menu.php:264
    905929msgid "Mega menu: show this item's submenu as columns in the desktop header"
    906930msgstr ""
    907931
    908 #: inc/class-mega-menu.php:185
    909 #: inc/class-mega-menu.php:250
     932#: inc/class-mega-menu.php:186
     933#: inc/class-mega-menu.php:267
    910934msgid "Columns"
    911935msgstr ""
    … …  
    970994
    971995#. translators: %s: the search query.
    972 #: inc/class-page-header.php:102
     996#: inc/class-page-header.php:123
    973997#, php-format
    974998msgid "Search results for: %s"
    975999msgstr ""
    9761000
    977 #: inc/class-page-header.php:117
     1001#: inc/class-page-header.php:138
    9781002msgid "Breadcrumbs"
    9791003msgstr ""
  • nanospace/2.1.0/readme.txt

    r357220 r357429  
    5959== Changelog ==
    6060
     61= 2.1.0 =
     62
     63* Colors, typography and mega menu settings now preview in the Customizer without a reload.
     64* Optional page header band on the WooCommerce shop and product categories (off by default).
     65* Pages can pick their own page header image.
     66
    6167= 2.0.1 =
    6268
  • nanospace/2.1.0/src/css/woocommerce.css

    r357206 r357429  
    3434}
    3535
     36/* Without a sidebar, the band's text starts where the wide product grid does. */
     37.content-area--sidebar-none
     38        .site-main:has(> .nanospace-shop)
     39        > .page-header--band
     40        .page-header__text {
     41        padding-inline: max(var(--nanospace-space), (100% - var(--nanospace-width-wide)) / 2);
     42}
     43
    3644/* Above a shortcode's wide content (My account, the shortcode cart), the title is wide too. */
    3745.content-area--sidebar-none
  • nanospace/2.1.0/src/js/customizer-mega.js

    r357206 r357429  
    66 * fields show on top-level items only (customizer.css). When a new item is saved, core gives it
    77 * its real ID and a new control; the value moves to the setting under that ID.
     8 *
     9 * The preview follows without a reload: the setting reaches it by postMessage, then
     10 * `nanospace-mega` asks it to re-render the header menus on the server (selective refresh,
     11 * assets/js/customize-preview-mega.js).
    812 */
    913(() => {
    … …  
    1822                        ? api(key)
    1923                        : api.create(key, key, values[itemId] ?? "", {
    20                                         transport: "refresh",
     24                                        transport: "postMessage",
    2125                                        previewer: api.previewer,
    2226                                });
    … …  
    3640                                columns.disabled = v === "";
    3741                        };
    38                         toggle.addEventListener("change", () => value.set(toggle.checked ? columns.value : ""));
     42                        const change = (v) => {
     43                                value.set(v);
     44                                api.previewer.send("nanospace-mega");
     45                        };
     46                        toggle.addEventListener("change", () => change(toggle.checked ? columns.value : ""));
    3947                        columns.addEventListener("change", () => {
    40                                 if (toggle.checked) value.set(columns.value);
     48                                if (toggle.checked) change(columns.value);
    4149                        });
    4250                        value.bind(render);
  • nanospace/2.1.0/src/js/editor-layout.js

    r357206 r357429  
    33 * assets/js/editor-layout.js by bin/build-theme.ts; a classic script after the wp-* packages.
    44 * Labels and choices come from PHP (`nanospaceLayout`), shared with the classic meta box.
    5  * The panel shows only for post types with the layout meta.
     5 * The panel shows only for post types with the layout meta. The page header image is picked from
     6 * the media library (`_nanospace_page_header_image`, 0 = the site-wide image).
    67 */
    78(() => {
    89        const { registerPlugin } = window.wp.plugins;
    910        const { PluginDocumentSettingPanel } = window.wp.editor;
    10         const { SelectControl, ToggleControl } = window.wp.components;
     11        const { MediaUpload, MediaUploadCheck } = window.wp.blockEditor;
     12        const { Button, SelectControl, ToggleControl } = window.wp.components;
    1113        const { useSelect, useDispatch } = window.wp.data;
    12         const h = window.wp.element.createElement;
    13         /** @type {{ title: string, selects: Record<string, [string, Record<string, string>]>, hideTitle: string }} */
    14         const { title, selects, hideTitle } = window.nanospaceLayout;
     14        const { createElement: h, useRef } = window.wp.element;
     15        /** @type {{ title: string, selects: Record<string, [string, Record<string, string>]>, hideTitle: string, image: Record<"label" | "help" | "choose" | "replace" | "remove", string> }} */
     16        const { title, selects, hideTitle, image } = window.nanospaceLayout;
     17
     18        /** The page header image: a preview, a media library button and a remove button. */
     19        function ImageField({ id, onChange }) {
     20                const choose = useRef(null);
     21                const src = useSelect(
     22                        (select) => {
     23                                const media = id ? select("core").getMedia(id) : null;
     24                                return media?.media_details?.sizes?.medium?.source_url ?? media?.source_url ?? "";
     25                        },
     26                        [id],
     27                );
     28                return h(
     29                        "div",
     30                        {
     31                                className: "nanospace-band-image",
     32                                role: "group",
     33                                "aria-labelledby": "nanospace-band-image-label",
     34                        },
     35                        h("p", { id: "nanospace-band-image-label" }, image.label),
     36                        src ? h("img", { src, alt: "", style: { display: "block", maxWidth: "100%" } }) : null,
     37                        h(
     38                                MediaUploadCheck,
     39                                null,
     40                                h(MediaUpload, {
     41                                        allowedTypes: ["image"],
     42                                        value: id || undefined,
     43                                        onSelect: (media) => onChange(media.id),
     44                                        render: ({ open }) =>
     45                                                h(
     46                                                        Button,
     47                                                        { ref: choose, variant: "secondary", onClick: open, __next40pxDefaultSize: true },
     48                                                        id ? image.replace : image.choose,
     49                                                ),
     50                                }),
     51                        ),
     52                        id
     53                                ? h(
     54                                                Button,
     55                                                {
     56                                                        variant: "link",
     57                                                        isDestructive: true,
     58                                                        onClick: () => {
     59                                                                onChange(0);
     60                                                                choose.current?.focus();
     61                                                        },
     62                                                },
     63                                                image.remove,
     64                                        )
     65                                : null,
     66                        h("p", { className: "components-base-control__help" }, image.help),
     67                );
     68        }
    1569
    1670        function Panel() {
    … …  
    3791                                onChange: set("_nanospace_hide_title"),
    3892                        }),
     93                        h(ImageField, {
     94                                id: meta._nanospace_page_header_image ?? 0,
     95                                onChange: set("_nanospace_page_header_image"),
     96                        }),
    3997                );
    4098        }
  • nanospace/2.1.0/style.css

    r357220 r357429  
    55Author URI: https://labinator.com/
    66Description: NanoSpace is a fast, accessible multipurpose classic theme with drag-and-drop header and footer builders. It suits blogs, business sites, shops and communities, and works with WooCommerce, bbPress, BuddyPress, Elementor and Beaver Builder. Translation-ready with full RTL support.
    7 Version: 2.0.1
     7Version: 2.1.0
    88Requires at least: 7.1.4
    99Tested up to: 7.1
  • nanospace/2.1.0/template-parts/page-header.php

    r357206 r357429  
    1010
    1111$nanospace_band  = NanoSpace\Page_Header::settings();
    12 $nanospace_image = $nanospace_band['image'] ? wp_get_attachment_image(
    13         $nanospace_band['image'],
     12$nanospace_id    = NanoSpace\Page_Header::image();
     13$nanospace_image = $nanospace_id ? wp_get_attachment_image(
     14        $nanospace_id,
    1415        'full',
    1516        false,
    … …  
    2930                <?php endif; ?>
    3031                <?php
    31                 if ( ! is_singular() ) {
    32                         the_archive_description( '<div class="archive-description">', '</div>' );
    33                 }
     32                NanoSpace\Page_Header::description();
    3433                if ( is_active_sidebar( 'intro' ) ) {
    3534                        echo '<div class="page-header__widgets">';
  • nanospace/2.1.0/woocommerce.php

    r357206 r357429  
    11<?php
    22/**
    3  * WooCommerce's shop, product archives and single products (NanoSpace\Shop). Cart, checkout and
    4  * account are ordinary pages and use page.php's layout through index.php.
     3 * WooCommerce's shop, product archives and single products (NanoSpace\Shop), under the page
     4 * header band where it is on (NanoSpace\Page_Header). Cart, checkout and account are ordinary
     5 * pages and use page.php's layout through index.php.
    56 *
    67 * @package NanoSpace
    … …  
    1314<div class="<?php echo esc_attr( NanoSpace\Layout::content_classes() ); ?>">
    1415        <main id="main" class="site-main">
     16                <?php NanoSpace\Page_Header::render(); ?>
    1517                <div class="nanospace-shop">
    1618                        <?php woocommerce_content(); ?>
Note: See TracChangeset for help on using the changeset viewer.