Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/floppy-bears-kneel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'snappycart': major
---

Getting ready for release by prepping the demo for users (developers).
24 changes: 17 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,39 @@
name: CI

on:
push:
branches: [master]
pull_request:
branches: [master]
push:
branches:
- $default-branch

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: '18'
cache: npm

- name: Install dependencies
run: npm install
run: npm ci

- name: Changesets status
env:
BASE_REF: ${{ github.base_ref || github.event.repository.default_branch }}
run: |
git fetch origin "$BASE_REF"
npx changeset status --since="origin/$BASE_REF"

- name: Run tests
run: npm run test
run: npm test

- name: Run linter
run: npm run lint
159 changes: 145 additions & 14 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { useMemo, useState } from 'react';
import CartDrawer from './cart/components/CartDrawer';
import CartIcon from './cart/components/CartIcon/CartIcon';
import { useCart } from './cart/hooks/useCart';
import type { CartProduct } from './cart/types/types';

import CartDrawer from './cart/components/CartDrawer';
import CartIcon from './cart/components/CartIcon/CartIcon';

import styles from './demo/DemoHome.module.scss';
import { SiteHeader } from './demo/components/SiteHeader/SiteHeader';
import { ProductGrid } from './demo/components/ProductGrid/ProductGrid';
import { Quickstart } from './demo/components/Quickstart/Quickstart';
import { UseCases } from './demo/components/UseCases/UseCases';
import { SiteFooter } from './demo/components/SiteFooter/SiteFooter';

export default function App() {
const { addItem } = useCart();
const [open, setOpen] = useState(false);
Expand All @@ -12,25 +20,148 @@ export default function App() {
() => [
{ id: 'apple', name: 'Apple', price: 0.6, imageUrl: 'apple.png' },
{ id: 'banana', name: 'Banana', price: 0.4, imageUrl: 'banana.png' },
{ id: 'orange', name: 'Orange', price: 0.55, imageUrl: 'orange.png' },
{ id: 'strawberry', name: 'Strawberries', price: 1.25, imageUrl: 'strawberry.png' },
],
[],
);

const handleAddStarterSet = () => {
addItem(products[0]);
addItem(products[1], 2);
addItem(products[2]);
};

return (
<>
<h1>Demo eCommerce</h1>

<div style={{ display: 'flex', gap: 12 }}>
<button onClick={() => addItem(products[0])} type="button">
Add Apple
</button>
<button onClick={() => addItem(products[1], 2)} type="button">
Add 2 Bananas
</button>
</div>
<div className={styles.appShell}>
<SiteHeader
onOpenCart={() => setOpen(true)}
links={[
{ label: 'Quickstart', href: '#quickstart' },
{ label: 'Use cases', href: '#use-cases' },
{ label: 'Demo shop', href: '#demo-shop' },
{ label: 'GitHub', href: 'https://github.com/idncod/snappycart', external: true },
{ label: 'npm', href: 'https://www.npmjs.com/package/snappycart', external: true },
]}
/>

<main className={styles.page}>
<section className={styles.hero}>
<div className={styles.heroGrid}>
<div className={styles.heroLeft}>
<p className={styles.kicker}>Integration starter</p>
<h1 className={styles.h1}>snappycart</h1>
<p className={styles.p}>
Add items, open the drawer, ship. Use the snippets below to integrate into React or
Next.js in minutes.
</p>

<div className={styles.heroActions}>
<button className={styles.primaryBtn} type="button" onClick={() => setOpen(true)}>
Open cart
</button>
<button className={styles.secondaryBtn} type="button" onClick={handleAddStarterSet}>
Add starter set
</button>
</div>

<div className={styles.badges}>
<span className={styles.badge}>React</span>
<span className={styles.badge}>TypeScript</span>
<span className={styles.badge}>SCSS</span>
<span className={styles.badge}>Headless-friendly</span>
</div>
</div>

<div className={styles.heroRight}>
<div className={styles.card}>
<div className={styles.cardTitle}>Step 1: Trigger cart actions</div>
<div className={styles.cardBody}>
<div className={styles.miniGrid}>
<button
type="button"
className={styles.miniBtn}
onClick={() => addItem(products[0])}
>
Add Apple
</button>
<button
type="button"
className={styles.miniBtn}
onClick={() => addItem(products[1], 2)}
>
Add 2 Bananas
</button>
<button
type="button"
className={styles.miniBtn}
onClick={() => addItem(products[3])}
>
Add Strawberries
</button>
<button type="button" className={styles.miniBtn} onClick={() => setOpen(true)}>
Open drawer
</button>
</div>
<div className={styles.tip}>
Tip: add items, then open the drawer. Everything here should mirror how users
integrate it.
</div>
</div>
</div>

<div className={styles.cardMuted}>
<div className={styles.cardTitle}>What you get</div>
<div className={styles.cardBody}>
<div className={styles.bullets}>
<div className={styles.bullet}>
<span className={styles.dot} /> CartProvider
</div>
<div className={styles.bullet}>
<span className={styles.dot} /> useCart()
</div>
<div className={styles.bullet}>
<span className={styles.dot} /> CartIcon + CartDrawer
</div>
<div className={styles.bullet}>
<span className={styles.dot} /> Types exported
</div>
</div>
</div>
</div>
</div>
</div>
</section>

<section id="quickstart" className={styles.section}>
<div className={styles.sectionHeader}>
<h2 className={styles.h2}>Quickstart</h2>
<p className={styles.note}>Copy paste, no ceremony.</p>
</div>
<Quickstart />
</section>

<section id="use-cases" className={styles.section}>
<div className={styles.sectionHeader}>
<h2 className={styles.h2}>Use cases</h2>
<p className={styles.note}>Buttons trigger real cart behavior.</p>
</div>
<UseCases products={products} onOpenCart={() => setOpen(true)} />
</section>

<section id="demo-shop" className={styles.section}>
<div className={styles.sectionHeader}>
<h2 className={styles.h2}>Demo shop</h2>
<p className={styles.note}>This is the “integration UI” people expect.</p>
</div>
<ProductGrid products={products} onAdd={(p, qty) => addItem(p, qty)} />
</section>
</main>

<SiteFooter />

<CartIcon onClick={() => setOpen(true)} />
<CartDrawer open={open} onClose={() => setOpen(false)} />
</>
</div>
);
}
7 changes: 6 additions & 1 deletion src/cart/components/CartIcon/CartIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ export default function CartIcon({ position = 'bottom-right', onClick }: CartIco
: 'sc-bottom-right';

return (
<button type="button" className={`sc-cart-button ${posClass}`} onClick={onClick}>
<button
type="button"
className={`sc-cart-button ${posClass}`}
onClick={onClick}
aria-label={`Open cart, ${totalItems} items`}
>
Cart
<span className="sc-cart-badge">{totalItems}</span>
</button>
Expand Down
Loading
Loading