summaryrefslogtreecommitdiff
path: root/examples/ssr/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'examples/ssr/src/components')
-rw-r--r--examples/ssr/src/components/AddToCart.svelte53
-rw-r--r--examples/ssr/src/components/Cart.svelte34
-rw-r--r--examples/ssr/src/components/Container.astro13
-rw-r--r--examples/ssr/src/components/Header.astro49
-rw-r--r--examples/ssr/src/components/ProductListing.astro70
-rw-r--r--examples/ssr/src/components/TextDecorationSkip.astro23
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>&#32;</Fragment>}
+ </Fragment>
+ ))
+}