diff --git a/src/content/docs/dropins/checkout/tutorials/Mini cart can be enabled in the slide-out panel b/src/content/docs/dropins/checkout/tutorials/Mini cart can be enabled in the slide-out panel new file mode 100644 index 000000000..b887b63a2 --- /dev/null +++ b/src/content/docs/dropins/checkout/tutorials/Mini cart can be enabled in the slide-out panel @@ -0,0 +1,218 @@ +### Tutorial: Implementing Mini Cart Functionality + +#### Introduction +The following tutorial describes how to enable the `MiniCart` in a slide-out panel on boilerplate. This cart drop-in component enables functionality to display cart items, manage quantities, and proceed to checkout. + +#### Step 1: CSS Styling for MiniCart + +Update `commerce-mini-cart.css` with the following styles: + +```css +.cart-mini-cart { + display: flex; + flex-direction: column; + height: 100%; + padding: var(--spacing-small) var(--spacing-small) var(--spacing-medium); + box-sizing: border-box; +} + +.cart-mini-cart__empty-cart { + width: 100%; + max-width: 800px; + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-self: center; +} + +.cart-mini-cart__heading { + display: grid; + row-gap: var(--spacing-xsmall); + font: var(--type-headline-2-default-font); + letter-spacing: var(--type-headline-2-default-letter-spacing); +} + +.cart-mini-cart__heading-divider { + width: 100%; + margin: var(--spacing-xxsmall) 0 0 0; +} + +.cart-mini-cart__products { + flex: 1; + overflow-y: auto; + max-height: 100%; + padding-bottom: var(--spacing-medium); +} + +.cart-mini-cart__products .cart-cart-summary-list__heading { + padding: 0; +} + +.cart-mini-cart__products .dropin-cart-item__configurations li { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.cart-mini-cart__footer { + display: grid; + grid-auto-flow: row; + gap: var(--spacing-small); + padding-top: var(--spacing-small); + row-gap: var(--spacing-xsmall); +} + +.cart-mini-cart__footer__estimated-total { + font: var(--type-body-1-emphasized-font); + letter-spacing: var(--type-body-1-emphasized-letter-spacing); + display: grid; + grid-template: max-content / 1fr auto; + gap: var(--spacing-xsmall); +} + +.cart-mini-cart__footer__estimated-total-excluding-taxes { + font: var(--type-body-2-default-font); + letter-spacing: var(--type-body-2-default-letter-spacing); + display: grid; + grid-template: max-content / 1fr auto; + gap: var(--spacing-xsmall); + color: var(--color-neutral-700); +} + +.cart-mini-cart__productListFooter, +.cart-mini-cart__preCheckoutSection { + font: var(--type-body-2-default-font); + letter-spacing: var(--type-body-2-default-letter-spacing); + color: var(--color-neutral-800); +} + +.cart-mini-cart__footer__ctas { + display: grid; + grid-auto-flow: row; + gap: var(--spacing-xsmall); + padding-top: var(--spacing-small); +} +``` + +These styles ensure the `MiniCart` adjusts to different screen sizes while maintaining a clean layout for displaying products and totals. + +#### Step 2: JavaScript Logic for Mini Cart + +Update `commerce-mini-cart.js` with the following logic to initialize and manage `MiniCart` functionality: + +```javascript +try { + const config = readBlockConfig(block); + + const startShoppingURL = config['start-shopping-url'] || '/'; + const cartURL = config['cart-url'] || '/cart'; + const checkoutURL = config['checkout-url'] || '/checkout'; + + const routes = { + routeEmptyCartCTA: () => rootLink(startShoppingURL), + routeCart: () => rootLink(cartURL), + routeCheckout: () => rootLink(checkoutURL), + routeProduct: (product) => rootLink(`/products/${product.url.urlKey}/${product.topLevelSku}`), + isOpen: false, + }; + + const cart = await initializeCart(); + await provider.render(MiniCart, routes)(block); + + if (cart) { + events.emit('cart/data', cart); + events.emit('cart/initialized', cart); + } + + events.on('cart/updated', (cartData) => cartData && events.emit('cart/data', cartData), { eager: true }); + +} catch (error) { + console.error('Error initializing cart:', error); + events.emit('cart/data', null); +} +``` + +This sets up the `MiniCart` by reading configuration settings and initializing the cart. It also handles events like cart updates and initialization, ensuring the cart data is always current. + +#### Step 3: Integrating MiniCart with Header + +Update `header.css` to integrate the `MiniCart` panel with the header navigation: + +```css +header nav .nav-tools-wrapper { + position: relative; + display: flex; + align-items: center; +} + +/* Mini Cart Panel */ +header nav .nav-tools .minicart-panel { + position: fixed; + top: 0; + right: -400px; + width: 100%; + max-width: 400px; + height: 100vh; + background-color: var(--background-color); + z-index: 999; + box-sizing: border-box; + transition: right 0.3s ease-in-out; + overflow-y: auto; + box-shadow: var(--shape-shadow-2); +} + +header nav .nav-tools .nav-tools-panel--show { + right: 0; +} + +/* Hide navigation sections when mini cart is open */ +header nav .nav-tools .minicart-panel.nav-tools-panel--show ~ .nav-sections [aria-expanded="true"] { + display: none; +} + +/* Hide overlay when mini cart is open */ +header nav .nav-tools .minicart-panel.nav-tools-panel--show ~ .overlay.show { + display: none; +} +``` + +These styles position the `MiniCart` panel off-screen and slide it into view when activated. + +#### Step 4: JavaScript Logic for Header Integration + +Update `header.js` to handle `MiniCart` interactions: + +```javascript +if (stateChanged && show) { + publishShoppingCartViewEvent(); + toggleAllNavSections(navSections); + overlay.classList.remove('show'); +} + +cartButton.addEventListener('click', (e) => { + e.stopPropagation(); + toggleMiniCart(); +}); + +function updateCartCounter(data) { + if (data?.totalQuantity) { + cartButton.setAttribute('data-count', data.totalQuantity); + cartButton.setAttribute('aria-label', `Cart with ${data.totalQuantity} items`); + } else { + cartButton.removeAttribute('data-count'); + cartButton.setAttribute('aria-label', 'Cart'); + } +} + +events.on('cart/data', updateCartCounter, { eager: true }); +events.on('cart/updated', updateCartCounter, { eager: true }); +events.on('cart/initialized', updateCartCounter, { eager: true }); +``` + +This ensures the `MiniCart` can be toggled by clicking the cart button and updates the cart counter based on the cart data. + +With these changes, the `MiniCart` will appear in a slide-out panel when you click the cart button. + +![Mini Cart Slide-out Screenshot](https://github.com/user-attachments/assets/4dc11bda-ac44-4c71-afdb-a814c06c0390)