diff options
Diffstat (limited to 'examples/ssr/src/components')
-rw-r--r-- | examples/ssr/src/components/AddToCart.svelte | 53 | ||||
-rw-r--r-- | examples/ssr/src/components/Cart.svelte | 34 | ||||
-rw-r--r-- | examples/ssr/src/components/Container.astro | 13 | ||||
-rw-r--r-- | examples/ssr/src/components/Header.astro | 49 | ||||
-rw-r--r-- | examples/ssr/src/components/ProductListing.astro | 70 | ||||
-rw-r--r-- | examples/ssr/src/components/TextDecorationSkip.astro | 23 |
6 files changed, 242 insertions, 0 deletions
diff --git a/examples/ssr/src/components/AddToCart.svelte b/examples/ssr/src/components/AddToCart.svelte new file mode 100644 index 000000000..bae888b6b --- /dev/null +++ b/examples/ssr/src/components/AddToCart.svelte @@ -0,0 +1,53 @@ +<script> + import { addToUserCart } from '../api'; + let { id, name } = $props() + + function notifyCartItem(id) { + window.dispatchEvent(new CustomEvent('add-to-cart', { + detail: id + })); + } + + async function addToCart() { + await addToUserCart(id, name); + notifyCartItem(id); + } +</script> +<style> + button { + display:block; + padding:0.5em 1em 0.5em 1em; + border-radius:100px; + border:none; + font-size: 1.4em; + position:relative; + background:#0652DD; + cursor:pointer; + height:2em; + width:10em; + overflow:hidden; + transition:transform 0.1s; + z-index:1; +} +button:hover { + transform:scale(1.1); +} + +.pretext { + color:#fff; + background:#0652DD; + position:absolute; + top:0; + left:0; + height:100%; + width:100%; + display:flex; + justify-content:center; + align-items:center; + font-family: 'Quicksand', sans-serif; + text-transform: uppercase; +} +</style> +<button click={addToCart}> + <span class="pretext">Add to cart</span> +</button> diff --git a/examples/ssr/src/components/Cart.svelte b/examples/ssr/src/components/Cart.svelte new file mode 100644 index 000000000..5d4b7d251 --- /dev/null +++ b/examples/ssr/src/components/Cart.svelte @@ -0,0 +1,34 @@ +<script> + let { count } = $props() + let items = new Set(); + + function onAddToCart(ev) { + const id = ev.detail; + items.add(id); + count++; + } +</script> +<style> + .cart { + display: flex; + align-items: center; + text-decoration: none; + color: inherit; + } + .cart :first-child { + margin-right: 5px; + } + + .cart-icon { + font-size: 36px; + } + + .count { + font-size: 24px; + } +</style> +<svelte:window onadd-to-cart={onAddToCart}/> +<a href="/cart" class="cart"> + <span class="material-icons cart-icon">shopping_cart</span> + <span class="count">{count}</span> +</a> diff --git a/examples/ssr/src/components/Container.astro b/examples/ssr/src/components/Container.astro new file mode 100644 index 000000000..f1741156c --- /dev/null +++ b/examples/ssr/src/components/Container.astro @@ -0,0 +1,13 @@ +--- +const { tag = 'div' } = Astro.props; +const Tag = tag; +--- + +<style> + .container { + width: 1248px; /** TODO: responsive */ + margin-left: auto; + margin-right: auto; + } +</style> +<Tag class="container"><slot /></Tag> diff --git a/examples/ssr/src/components/Header.astro b/examples/ssr/src/components/Header.astro new file mode 100644 index 000000000..d266733e9 --- /dev/null +++ b/examples/ssr/src/components/Header.astro @@ -0,0 +1,49 @@ +--- +import TextDecorationSkip from './TextDecorationSkip.astro'; +import Cart from './Cart.svelte'; +import { getCart } from '../api'; + +const cart = await getCart(Astro.request); +const cartCount = cart.items.reduce((sum, item) => sum + item.count, 0); +--- + +<style> + @import url('https://fonts.googleapis.com/css2?family=Lobster&display=swap'); + + header { + margin: 1rem 2rem; + display: flex; + justify-content: space-between; + } + + h1 { + margin: 0; + font-family: 'Lobster', cursive; + color: black; + } + + a, + a:visited { + color: inherit; + text-decoration: none; + } + + .right-pane { + display: flex; + } + + .material-icons { + font-size: 36px; + margin-right: 1rem; + } +</style> +<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" /> +<header> + <h1><a href="/"><TextDecorationSkip text="Online Store" /></a></h1> + <div class="right-pane"> + <a href="/login"> + <span class="material-icons"> login</span> + </a> + <Cart client:idle count={cartCount} /> + </div> +</header> diff --git a/examples/ssr/src/components/ProductListing.astro b/examples/ssr/src/components/ProductListing.astro new file mode 100644 index 000000000..14e6e1d8c --- /dev/null +++ b/examples/ssr/src/components/ProductListing.astro @@ -0,0 +1,70 @@ +--- +import type { Product } from '../api'; + +interface Props { + products: Product[]; +} + +const { products } = Astro.props; +--- + +<style> + ul { + list-style-type: none; + margin: 0; + padding: 0; + display: flex; + } + + figure { + width: 200px; + padding: 7px; + border: 1px solid black; + display: flex; + flex-direction: column; + } + + figure figcaption { + text-align: center; + line-height: 1.6; + } + + figure img { + width: 100%; + height: 250px; + object-fit: cover; + } + + .product a { + display: block; + text-decoration: none; + color: inherit; + } + + .name { + font-weight: 500; + } + + .price { + font-size: 90%; + color: #787878; + } +</style> +<slot name="title" /> +<ul> + { + products.map((product) => ( + <li class="product"> + <a href={`/products/${product.id}`}> + <figure> + <img src={product.image} /> + <figcaption> + <div class="name">{product.name}</div> + <div class="price">${product.price}</div> + </figcaption> + </figure> + </a> + </li> + )) + } +</ul> diff --git a/examples/ssr/src/components/TextDecorationSkip.astro b/examples/ssr/src/components/TextDecorationSkip.astro new file mode 100644 index 000000000..707027763 --- /dev/null +++ b/examples/ssr/src/components/TextDecorationSkip.astro @@ -0,0 +1,23 @@ +--- +interface Props { + text: string; +} + +const { text } = Astro.props; +const words = text.split(' '); +const last = words.length - 1; +--- + +<style> + span { + text-decoration: underline; + } +</style> +{ + words.map((word, i) => ( + <Fragment> + <span>{word}</span> + {i !== last && <Fragment> </Fragment>} + </Fragment> + )) +} |