1import{LitElement,createRef,css,html,nothing,ref,unsafeHTML,when}from"@lit";import{storefrontClient}from"@nova/storefront";import styles from"@nova/styles";import{formatPrice,t}from"@nova/utils";class NovaMiniCart extends LitElement{static properties={initialItems:{type:Array},items:{type:Array,state:!0},emptyCartCtaText:{type:String},emptyCartCtaUrl:{type:String},callOutText:{type:String},freeShippingData:{type:Object},compareAtPrices:{type:Object,state:!0},continueSell:{type:Object,state:!0},maxValues:{type:Object,state:!0},latestPrices:{type:Object,state:!0}};get count(){return this.items.reduce((acc,current)=>acc+Number.parseInt(current.quantity),0)}get subtotal(){return this.items.reduce((acc,current)=>{const key=current.key,hasLineDiscount=Number.parseFloat(current.line_level_total_discount||0)>0,latest=this.latestPrices?.[key],priceToUse=!hasLineDiscount&&typeof latest=="number"?latest:Number.parseFloat(current.final_price);return acc+priceToUse*current.quantity},0)}get formattedSubtotal(){return formatPrice(this.subtotal)}async queryVariantData(items){const compareAtPrices={},continueSell={},maxValues={},latestPrices={};await Promise.all(items.map(async item=>{const data=await this.getVariantData(item);data&&(compareAtPrices[item.key]=data.compareAtPrice,continueSell[item.key]=data.inventoryPolicy,maxValues[item.key]=data.max,latestPrices[item.key]=data.price)})),this.compareAtPrices=compareAtPrices,this.continueSell=continueSell,this.maxValues=maxValues,this.latestPrices=latestPrices}getVariantData=async currentItem=>{const variantData=await storefrontClient.getVariantById(currentItem.variant_id);if(!variantData){const matchedItem=this.initialItems.find(item=>item.key===currentItem.key);return matchedItem?{price:Number.parseFloat(matchedItem.final_price||0),compareAtPrice:Number.parseFloat(matchedItem.compare_at_price||0),max:matchedItem.inventory_quantity,inventoryPolicy:matchedItem.inventory_policy!=="continue"}:null}return{price:variantData.price,compareAtPrice:variantData.compareAtPrice,max:variantData.quantityAvailable,inventoryPolicy:variantData.currentlyNotInStock}};get itemCount(){return this.items.reduce((sum,item)=>sum+(Number(item.quantity)||0),0)}$cartDrawer=createRef();$cartItemCountWrapper=createRef();constructor(){super(),document.addEventListener("nova:cart:open",this._handleOpenCart),document.addEventListener("nova:cart:close",this._handleCloseCart),document.addEventListener("nova:cart:refresh",this.refresh),document.addEventListener("discount_kit:cart_changed",this.refresh),this.initialItems=[],this.items=[],this.compareAtPrices={},this.continueSell={},this.maxValues={},this.latestPrices={}}connectedCallback(){super.connectedCallback(),this.emptyCartCtaText=this.getAttribute("empty-cart-cta-text"),this.emptyCartCtaUrl=this.getAttribute("empty-cart-cta-url"),this.callOutText=this.getAttribute("call-out-text"),this._initializeFreeShippingData()}_initializeFreeShippingData(){typeof __NOVA_GLOBAL__<"u"?this.freeShippingData={freeShippingThreshold:__NOVA_GLOBAL__.freeShippingThreshold||0,gwpThreshold:__NOVA_GLOBAL__.gwpThreshold||0}:this.freeShippingData={freeShippingThreshold:0,gwpThreshold:0}}disconnectedCallback(){document.removeEventListener("nova:cart:open",this._handleOpenCart),document.removeEventListener("nova:cart:close",this._handleCloseCart),document.removeEventListener("nova:cart:refresh",this.refresh)}_handleOpenCart=async()=>{await this.updateComplete,this.$cartDrawer.value&&this.$cartDrawer.value.show(),this.$cartItemCountWrapper.value&&this.$cartItemCountWrapper.value.removeAttribute("aria-hidden")};_handleCloseCart=async()=>{await this.updateComplete,this.$cartDrawer.value&&this.$cartDrawer.value.hide()};_hardRefreshCart=async()=>{const res=await fetch("/cart.js");if(!res.ok)throw new Error("Error fetching cart for hard refresh");const cart=await res.json(),updates={};for(const item of cart.items)updates[item.key]=item.quantity;const updateRes=await fetch("/cart/update.js",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({updates})});if(!updateRes.ok)throw new Error("Error updating cart for hard refresh");return updateRes.json()};refresh=async()=>{try{await this._hardRefreshCart();const response=await fetch("/cart.js");if(!response.ok)throw new Error("Error fetching cart");const data=await response.json();this.items=data.items,this.queryVariantData(this.items),await this.updateComplete,this.$cartItemCountWrapper.value&&this.$cartItemCountWrapper.value.setAttribute("aria-hidden",!0)}catch(e){console.error("Error fetching cart",e)}};willUpdate(changedProperties){changedProperties.has("initialItems")&&(this.items=this.initialItems,this.queryVariantData(this.items)),changedProperties.has("items")&&(document.dispatchEvent(new CustomEvent("nova:cart:items-count",{detail:{count:this.count}})),document.dispatchEvent(new CustomEvent("nova:changeQuantityFinished"),{bubbles:!0}))}get callOutSection(){const div=document.createElement("div");return div.classList.add("call-out-container"),div.innerHTML=this.callOutText,div}_renderEmptyState=()=>html` 2 <div class="empty-state"> 3 <p>${t("cart.general.empty")}</p> 4 <a href=${this.emptyCartCtaUrl} class="btn btn--primary"> 5 ${unsafeHTML(this.emptyCartCtaText)} 6 </a> 7 </div> 8 `;continue_shopping;_renderItems=()=>html` 9 ${__NOVA_GLOBAL__.showCartProgressBar===!0?html`<nova-free-shipping-threshold .freeShippingData=${this.freeShippingData}></nova-free-shipping-threshold>`:nothing} 10 ${this.callOutText?this.callOutSection:nothing} 11 <div class="items" part="items"> 12 ${this.items.map(item=>{const key=item.key,hasLineDiscount=Number.parseFloat(item.line_level_total_discount||0)>0,latest=this.latestPrices?.[key],priceToUse=!hasLineDiscount&&typeof latest=="number"?latest:Number.parseFloat(item.final_price),mergedItem={...item,final_price:priceToUse};return html` 13 <nova-cart-item
14 @nova-change=${this.refresh} 15 .item=${mergedItem} 16 .compareAtPrice=${this.compareAtPrices[key]||nothing} 17 .inventoryPolicy=${this.continueSell[key]||nothing} 18 .max=${this.maxValues[key]||nothing} 19 > 20 </nova-cart-item> 21 `})} 22 </div> 23 <!-- BEAM START --> 24 <div data-beam-widget="select-nonprofit" data-cart-empty="true" style="padding:20px 20px; border-top: 0.820513px solid rgb(182, 170, 155);"> 25 <beam-select-nonprofit 26 apiKey="pTGFJhV8Ll7U.31ace206-a512-4997-bc68-221745d6510b" 27 storeId="437" 28 lang="en" 29 ></beam-select-nonprofit> 30 </div> 31 <!-- BEAM END --> 32 <div slot="footer" class="summary"> 33 ${this.itemCount?html`<div class="summary__item-count"> 34 <p>${t("cart.general.order_summary")}</p> 35 <p>${this.itemCount} ${t("cart.general.items")}</p> 36 </div>`:nothing} 37 <div class="summary__total"> 38 <p>${t("cart.general.subtotal")}</p> 39 <p>${this.formattedSubtotal}</p> 40 </div> 41 <sl-button href="/checkout">${t("cart.general.checkout")}</sl-button> 42 </div> 43 `;render(){return html` 44 <sl-drawer class="drawer" ${ref(this.$cartDrawer)}> 45 <div slot="label" ${ref(this.$cartItemCountWrapper)}> 46 <span>${t("cart.general.title")}</span> 47 ${this.itemCount?html`<span class="header__item-count">(${this.itemCount})</span>`:nothing} 48 </div> 49 ${when(!this.items.length,this._renderEmptyState,this._renderItems)} 50 </sl-drawer> 51 `}static styles=[styles.flex,css` 52 :host { 53 display: block; 54 } 55 .drawer { 56 --size: 100%; 57 --header-spacing: 30px 30px 20px 30px; 58 --body-spacing: 0px 30px; 59 --footer-spacing: 0; 60 } 61 @media screen and (min-width: 430px) { 62 .drawer { 63 --size: 430px; 64 } 65 } 66 .drawer::part(base) { 67 z-index: var(--nova-z-index-navigation); 68 } 69 .drawer::part(overlay) { 70 fill: var(--nova-utility-overlay, rgba(0, 0, 0, 0.5)); 71 } 72 .drawer::part(panel) { 73 background-color: var(--nova-color-brand-beige); 74 overflow: hidden; 75 } 76 .drawer::part(header) { 77 align-items: baseline; 78 border-bottom: 1px solid var(--nova-color-brand-taupe); 79 } 80 .header__item-count { 81 font-size: 18px; 82 font-weight: 400; 83 font-family: var(--nova-font-italic-primary); 84 } 85 .drawer::part(title) { 86 text-transform: uppercase; 87 font-family: var(--nova-font-bold); 88 font-size: 18px; 89 line-height: 130%; 90 font-weight: 700; 91 padding: 20px; 92 } 93 .drawer::part(header-actions) { 94 padding: var(--nova-space-sm); 95 } 96 .drawer::part(close-button) { 97 width: 16px; 98 height: 16px; 99 } 100 .drawer::part(close-button__base) { 101 color: black; 102 padding: 0; 103 font-size: 20px; 104 } 105 .drawer::part(body) { 106 padding: 0; 107 } 108 .empty-state { 109 display: flex; 110 row-gap: var(--nova-space-sm); 111 flex-direction: column; 112 justify-content: flex-start; 113 align-items: center; 114 padding: var(--nova-space-xl) var(--nova-space-sm); 115 } 116 @media screen and (min-width: 768px) { 117 .empty-state { 118 padding-top: var(--nova-space-lg); 119 } 120 } 121 .empty-state p { 122 font-size: 14px; 123 margin: 0; 124 } 125 sl-button, 126 a.btn { 127 display: flex; 128 } 129 sl-button::part(base), 130 a.btn { 131 background-color: var(--nova-color-white); 132 color: var(--nova-color-brand-charcoal); 133 min-height: 35px; 134 width: 100%; 135 border: none; 136 border-radius: var(--nova-border-rounded); 137 align-items: center; 138 font: var(--nova-h8-font); 139 text-transform: uppercase; 140 transition: background-color 0.2s, color 0.2s, border-color 0.2s; 141 } 142 a.btn { 143 padding-inline: var(--nova-button-padding-x); 144 width: auto; 145 text-decoration: none; 146 } 147 sl-button::part(base):hover, 148 a.btn:hover { 149 background-color: var(--nova-color-brand-charcoal); 150 color: var(--nova-color-white); 151 } 152 .call-out-container { 153 padding: var(--nova-space-sm); 154 border-bottom: 1px solid var(--nova-color-brand-taupe); 155 } 156 .call-out-container :where(h1, h2, h3, h4, h5, h6, p) { 157 font: var(--nova-h7-font); 158 text-transform: uppercase; 159 margin: 0; 160 } 161 .call-out-container em { 162 font-weight: 400; 163 font-family: var(--nova-font-italic-primary); 164 } 165 .call-out-container a { 166 color: inherit; 167 } 168 .items { 169 padding-top: 20px; 170 } 171 .summary { 172 border-top: 1px solid var(--nova-color-brand-taupe); 173 padding: var(--nova-space-sm); 174 font-size: 14px; 175 font-style: normal; 176 font-weight: 400; 177 line-height: 140%; 178 } 179 .summary__total, 180 .summary__item-count { 181 display: flex; 182 justify-content: space-between; 183 } 184 .summary__item-count { 185 margin-bottom: var(--nova-space-xsm); 186 } 187 .summary__total { 188 margin-bottom: var(--nova-space-sm); 189 } 190 .summary__total p, 191 .summary__item-count p { 192 margin: 0; 193 } 194 .summary sl-button::part(base) { 195 background-color: var(--nova-color-brand-charcoal); 196 color: var(--nova-color-white); 197 text-transform: uppercase; 198 } 199 200 /* HACK: The main font family 'HelveticaNeueETPro-75-Bold' renders the ® symbol on the baseline instead of raising it like a superscript. 201 Apply a hack to visually raise the ® symbol and make it appear as a true superscript. */ 202 .superscript { 203 /* HACK: Need to enforce superscript for heading font family */ 204 font-size: 50% !important; 205 vertical-align: super; 206 } 207 208 em .superscript { 209 font-size: inherit !important; 210 vertical-align: baseline; 211 font-style: italic; 212 } 213 `]}customElements.define("nova-mini-cart",NovaMiniCart); 214//# sourceMappingURL=/cdn/shop/t/424/assets/component-mini-cart.js.map?v=173252806257553476501783361503
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.