Template
- Cart drawer: single-column layout matching the site — no bag icon, no dividers, square images, tighter type, discount code form, estimated total, and a Go to Checkout button - Cart: per-line loading state so one row's update no longer disables every other row or the checkout button - Discounts: cartDiscountCodesUpdate mutation plus discountCodes on the cart fragment, wired to an applyDiscountCode store action - Products: fix "load more" returning the same first page — the query now takes an `after` cursor and getProductsPage exposes pageInfo - Collections: cards match the product cards (no border, radius, blurb, or CTA row) at 4-up on desktop and 2-up on mobile; section headers match the products section - Shop Pay: cart permalink with payment=shop_pay instead of the hosted shop-js element - Buttons converted to the shadcn Button component throughout - PDP: swipeable image carousel with dots on mobile, sticky info column, colour swatches never fall back to variant photos - Rename the store from Stride to Shop; larger header wordmark Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jWbNNJLksC1QG8z8845FX
158 lines
3.0 KiB
JavaScript
158 lines
3.0 KiB
JavaScript
// Cart Fragment for consistent cart data
|
|
const CartFragment = `
|
|
fragment CartFragment on Cart {
|
|
id
|
|
checkoutUrl
|
|
totalQuantity
|
|
discountCodes {
|
|
code
|
|
applicable
|
|
}
|
|
cost {
|
|
subtotalAmount {
|
|
amount
|
|
currencyCode
|
|
}
|
|
totalAmount {
|
|
amount
|
|
currencyCode
|
|
}
|
|
totalTaxAmount {
|
|
amount
|
|
currencyCode
|
|
}
|
|
}
|
|
lines(first: 100) {
|
|
edges {
|
|
node {
|
|
id
|
|
quantity
|
|
cost {
|
|
totalAmount {
|
|
amount
|
|
currencyCode
|
|
}
|
|
}
|
|
merchandise {
|
|
... on ProductVariant {
|
|
id
|
|
title
|
|
selectedOptions {
|
|
name
|
|
value
|
|
}
|
|
price {
|
|
amount
|
|
currencyCode
|
|
}
|
|
image {
|
|
id
|
|
url
|
|
altText
|
|
width
|
|
height
|
|
}
|
|
product {
|
|
id
|
|
title
|
|
handle
|
|
vendor
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
|
|
// Create a new cart
|
|
export const CREATE_CART_MUTATION = `
|
|
${CartFragment}
|
|
mutation CreateCart($lines: [CartLineInput!]) {
|
|
cartCreate(input: { lines: $lines }) {
|
|
cart {
|
|
...CartFragment
|
|
}
|
|
userErrors {
|
|
field
|
|
message
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
|
|
// Add lines to cart
|
|
export const ADD_CART_LINES_MUTATION = `
|
|
${CartFragment}
|
|
mutation AddCartLines($cartId: ID!, $lines: [CartLineInput!]!) {
|
|
cartLinesAdd(cartId: $cartId, lines: $lines) {
|
|
cart {
|
|
...CartFragment
|
|
}
|
|
userErrors {
|
|
field
|
|
message
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
|
|
// Update cart lines
|
|
export const UPDATE_CART_LINES_MUTATION = `
|
|
${CartFragment}
|
|
mutation UpdateCartLines($cartId: ID!, $lines: [CartLineUpdateInput!]!) {
|
|
cartLinesUpdate(cartId: $cartId, lines: $lines) {
|
|
cart {
|
|
...CartFragment
|
|
}
|
|
userErrors {
|
|
field
|
|
message
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
|
|
// Remove lines from cart
|
|
export const REMOVE_CART_LINES_MUTATION = `
|
|
${CartFragment}
|
|
mutation RemoveCartLines($cartId: ID!, $lineIds: [ID!]!) {
|
|
cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {
|
|
cart {
|
|
...CartFragment
|
|
}
|
|
userErrors {
|
|
field
|
|
message
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
|
|
// Apply (or clear) discount codes on the cart
|
|
export const UPDATE_CART_DISCOUNT_CODES_MUTATION = `
|
|
${CartFragment}
|
|
mutation UpdateCartDiscountCodes($cartId: ID!, $discountCodes: [String!]) {
|
|
cartDiscountCodesUpdate(cartId: $cartId, discountCodes: $discountCodes) {
|
|
cart {
|
|
...CartFragment
|
|
}
|
|
userErrors {
|
|
field
|
|
message
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
|
|
// Get cart by ID
|
|
export const GET_CART_QUERY = `
|
|
${CartFragment}
|
|
query GetCart($cartId: ID!) {
|
|
cart(id: $cartId) {
|
|
...CartFragment
|
|
}
|
|
}
|
|
`;
|