diff options
Diffstat (limited to 'examples')
23 files changed, 306 insertions, 310 deletions
diff --git a/examples/with-nanostores/README.md b/examples/with-nanostores/README.md index bbbc896b1..e5070d816 100644 --- a/examples/with-nanostores/README.md +++ b/examples/with-nanostores/README.md @@ -6,4 +6,4 @@ npm init astro -- --template with-nanostores [](https://stackblitz.com/github/withastro/astro/tree/latest/examples/with-nanostores) -This example showcases using [`nanostores`](https://github.com/nanostores/nanostores) to provide shared state between components from different frameworks. +This example showcases using [`nanostores`](https://github.com/nanostores/nanostores) to provide shared state between components of any framework. [**Read our documentation on sharing state**](https://docs.astro.build/en/core-concepts/sharing-state/) for a complete breakdown of this project, along with guides to use React, Vue, Svelte, or Solid! diff --git a/examples/with-nanostores/astro.config.mjs b/examples/with-nanostores/astro.config.mjs index 4b50887cd..3e161041b 100644 --- a/examples/with-nanostores/astro.config.mjs +++ b/examples/with-nanostores/astro.config.mjs @@ -1,12 +1,8 @@ import { defineConfig } from 'astro/config'; import preact from '@astrojs/preact'; -import react from '@astrojs/react'; -import svelte from '@astrojs/svelte'; -import vue from '@astrojs/vue'; -import solid from '@astrojs/solid-js'; // https://astro.build/config export default defineConfig({ // Enable many frameworks to support all different kinds of components. - integrations: [preact(), react(), svelte(), vue(), solid()], + integrations: [preact()], }); diff --git a/examples/with-nanostores/package.json b/examples/with-nanostores/package.json index 8c91ea5c7..cb68d7d73 100644 --- a/examples/with-nanostores/package.json +++ b/examples/with-nanostores/package.json @@ -10,21 +10,11 @@ }, "dependencies": { "@nanostores/preact": "^0.1.3", - "@nanostores/react": "^0.1.5", - "@nanostores/vue": "^0.4.1", "nanostores": "^0.5.12", - "preact": "^10.7.3", - "react": "^18.1.0", - "react-dom": "^18.1.0", - "solid-nanostores": "0.0.6", - "vue": "^3.2.37" + "preact": "^10.7.3" }, "devDependencies": { - "@astrojs/preact": "^0.4.0", - "@astrojs/react": "^0.3.0", - "@astrojs/solid-js": "^0.3.0", - "@astrojs/svelte": "^0.3.0", - "@astrojs/vue": "^0.3.0", + "@astrojs/preact": "^0.3.1", "astro": "^1.0.0-beta.66" } } diff --git a/examples/with-nanostores/public/assets/logo.svg b/examples/with-nanostores/public/assets/logo.svg deleted file mode 100644 index d751556b2..000000000 --- a/examples/with-nanostores/public/assets/logo.svg +++ /dev/null @@ -1,12 +0,0 @@ -<svg width="193" height="256" fill="none" xmlns="http://www.w3.org/2000/svg"> - <style> - #flame { fill: #FF5D01; } - #a { fill: #000014; } - @media (prefers-color-scheme: dark) { - #a { fill: #fff; } - } - </style> - - <path id="a" fill-rule="evenodd" clip-rule="evenodd" d="M131.496 18.929c1.943 2.413 2.935 5.67 4.917 12.181l43.309 142.27a180.277 180.277 0 00-51.778-17.53L99.746 60.56a3.67 3.67 0 00-7.042.01l-27.857 95.232a180.224 180.224 0 00-52.01 17.557l43.52-142.281c1.989-6.502 2.983-9.752 4.927-12.16a15.999 15.999 0 016.484-4.798c2.872-1.154 6.271-1.154 13.07-1.154h31.085c6.807 0 10.211 0 13.085 1.157a16 16 0 016.488 4.806z" fill="url(#paint0_linear)"/> - <path id="flame" fill-rule="evenodd" clip-rule="evenodd" d="M136.678 180.151c-7.14 6.105-21.39 10.268-37.804 10.268-20.147 0-37.033-6.272-41.513-14.707-1.602 4.835-1.962 10.367-1.962 13.902 0 0-1.055 17.355 11.016 29.426 0-6.268 5.081-11.349 11.349-11.349 10.743 0 10.731 9.373 10.721 16.977v.679c0 11.542 7.054 21.436 17.086 25.606a23.27 23.27 0 01-2.339-10.2c0-11.008 6.463-15.107 13.973-19.87 5.977-3.79 12.616-8.001 17.192-16.449a31.013 31.013 0 003.744-14.82c0-3.299-.513-6.479-1.463-9.463z" /> -</svg> diff --git a/examples/with-nanostores/public/images/astronaut-figurine.png b/examples/with-nanostores/public/images/astronaut-figurine.png Binary files differnew file mode 100644 index 000000000..f5a278b9c --- /dev/null +++ b/examples/with-nanostores/public/images/astronaut-figurine.png diff --git a/examples/with-nanostores/public/robots.txt b/examples/with-nanostores/public/robots.txt deleted file mode 100644 index 1f53798bb..000000000 --- a/examples/with-nanostores/public/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / diff --git a/examples/with-nanostores/src/cartStore.ts b/examples/with-nanostores/src/cartStore.ts new file mode 100644 index 000000000..21543a73e --- /dev/null +++ b/examples/with-nanostores/src/cartStore.ts @@ -0,0 +1,31 @@ +import { atom, map } from 'nanostores'; + +export const isCartOpen = atom(false); + +export type CartItem = { + id: string; + name: string; + imageSrc: string; + quantity: number; +} + +export type CartItemDisplayInfo = Pick<CartItem, 'id' | 'name' | 'imageSrc'>; + +export const cartItems = map<Record<string, CartItem>>({}); + +export function addCartItem({ id, name, imageSrc }) { + const existingEntry = cartItems.get()[id]; + if (existingEntry) { + cartItems.setKey(id, { + ...existingEntry, + quantity: existingEntry.quantity + 1, + }); + } else { + cartItems.setKey(id, { + id, + name, + imageSrc, + quantity: 1, + }); + } +} diff --git a/examples/with-nanostores/src/components/AddToCartForm.tsx b/examples/with-nanostores/src/components/AddToCartForm.tsx new file mode 100644 index 000000000..2f1befb9f --- /dev/null +++ b/examples/with-nanostores/src/components/AddToCartForm.tsx @@ -0,0 +1,22 @@ +import { isCartOpen, addCartItem } from '../cartStore'; +import type { CartItemDisplayInfo } from '../cartStore'; +import type { ComponentChildren } from 'preact'; + +type Props = { + item: CartItemDisplayInfo; + children: ComponentChildren; +} + +export default function AddToCartForm({ item, children }: Props) { + function addToCart(e: SubmitEvent) { + e.preventDefault(); + isCartOpen.set(true); + addCartItem(item); + } + + return ( + <form onSubmit={addToCart}> + {children} + </form> + ) +} diff --git a/examples/with-nanostores/src/components/AdminsReact.jsx b/examples/with-nanostores/src/components/AdminsReact.jsx deleted file mode 100644 index f2b38a3cd..000000000 --- a/examples/with-nanostores/src/components/AdminsReact.jsx +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from 'react'; -import { useStore } from '@nanostores/react'; - -import { admins } from '../store/admins.js'; -import { counter, increaseCounter, decreaseCounter } from '../store/counter.js'; - -const AdminsReact = () => { - const list = useStore(admins); - const count = useStore(counter); - - return ( - <> - <h1>React</h1> - <ul> - {list.map((admin) => ( - <li key={admin.id}>{JSON.stringify(admin, null, 2)}</li> - ))} - </ul> - <div> - <h3>Counter</h3> - <p>{count.value}</p> - <button onClick={decreaseCounter}>-1</button> - <button onClick={increaseCounter}>+1</button> - </div> - <br /> - </> - ); -}; - -export default AdminsReact; diff --git a/examples/with-nanostores/src/components/AdminsSolid.jsx b/examples/with-nanostores/src/components/AdminsSolid.jsx deleted file mode 100644 index 8ad2756a3..000000000 --- a/examples/with-nanostores/src/components/AdminsSolid.jsx +++ /dev/null @@ -1,30 +0,0 @@ -import { createSignal } from 'solid-js'; -import { useStore } from 'solid-nanostores'; - -import { admins } from '../store/admins.js'; -import { counter, increaseCounter, decreaseCounter } from '../store/counter.js'; - -const AdminsSolid = () => { - const list = useStore(admins); - const count = useStore(counter); - - return ( - <> - <h1>Solid</h1> - <ul> - {list.map((admin) => ( - <li key={admin.id}>{JSON.stringify(admin, null, 2)}</li> - ))} - </ul> - <div> - <h3>Counter</h3> - <p>{count.value}</p> - <button onClick={decreaseCounter}>-1</button> - <button onClick={increaseCounter}>+1</button> - </div> - <br /> - </> - ); -}; - -export default AdminsSolid; diff --git a/examples/with-nanostores/src/components/AdminsSvelte.svelte b/examples/with-nanostores/src/components/AdminsSvelte.svelte deleted file mode 100644 index bae3fbef8..000000000 --- a/examples/with-nanostores/src/components/AdminsSvelte.svelte +++ /dev/null @@ -1,20 +0,0 @@ -<script> - import { admins } from '../store/admins.js'; - import { counter, increaseCounter, decreaseCounter } from '../store/counter.js'; -</script> - -<h1>Svelte</h1> -<ul> - {#each $admins as admin} - <li>{JSON.stringify(admin, null, 2)}</li> - {/each} -</ul> -<div> - <h3>Counter</h3> - <p>{$counter.value}</p> - <button on:click={decreaseCounter}>-1</button> - <button on:click={increaseCounter}>+1</button> -</div> -<br /> -<!-- Just to get rid of a warning --> -<slot /> diff --git a/examples/with-nanostores/src/components/AdminsVue.vue b/examples/with-nanostores/src/components/AdminsVue.vue deleted file mode 100644 index 5eb73dd3d..000000000 --- a/examples/with-nanostores/src/components/AdminsVue.vue +++ /dev/null @@ -1,33 +0,0 @@ -<template> - <div> - <h1>Vue</h1> - <ul> - <li v-for="admin in list" :key="admin.id"> - {{ JSON.stringify(admin, null, 2) }} - </li> - </ul> - <div> - <h3>Counter</h3> - <p>{{ count.value }}</p> - <button @click="decreaseCounter">-1</button> - <button @click="increaseCounter">+1</button> - </div> - <br /> - </div> -</template> - -<script> -import { useStore } from '@nanostores/vue'; - -import { admins } from '../store/admins.js'; -import { counter, increaseCounter, decreaseCounter } from '../store/counter.js'; - -export default { - setup() { - const list = useStore(admins); - const count = useStore(counter); - - return { list, count, increaseCounter, decreaseCounter }; - }, -}; -</script> diff --git a/examples/with-nanostores/src/components/CartFlyout.module.css b/examples/with-nanostores/src/components/CartFlyout.module.css new file mode 100644 index 000000000..cee43dd4c --- /dev/null +++ b/examples/with-nanostores/src/components/CartFlyout.module.css @@ -0,0 +1,29 @@ +.container { + position: fixed; + right: 0; + top: var(--nav-height); + height: 100vh; + background: var(--color-bg-2); + padding-inline: 2rem; + min-width: min(90vw, 300px); + border-left: 3px solid var(--color-bg-3); +} + +.list { + list-style: none; + padding: 0; +} + +.listItem { + display: flex; + gap: 1rem; + align-items: center; +} + +.listItem * { + margin-block: 0.3rem; +} + +.listItemImg { + width: 4rem; +} diff --git a/examples/with-nanostores/src/components/CartFlyout.tsx b/examples/with-nanostores/src/components/CartFlyout.tsx new file mode 100644 index 000000000..29fd7a882 --- /dev/null +++ b/examples/with-nanostores/src/components/CartFlyout.tsx @@ -0,0 +1,26 @@ +import { useStore } from '@nanostores/preact'; +import { cartItems, isCartOpen } from '../cartStore'; +import styles from './CartFlyout.module.css'; + +export default function CartFlyout() { + const $isCartOpen = useStore(isCartOpen); + const $cartItems = useStore(cartItems); + + return ( + <aside hidden={!$isCartOpen} className={styles.container}> + {Object.values($cartItems).length ? ( + <ul className={styles.list} role="list"> + {Object.values($cartItems).map(cartItem => ( + <li className={styles.listItem}> + <img className={styles.listItemImg} src={cartItem.imageSrc} alt={cartItem.name} /> + <div> + <h3>{cartItem.name}</h3> + <p>Quantity: {cartItem.quantity}</p> + </div> + </li> + ))} + </ul> + ) : <p>Your cart is empty!</p>} + </aside> + ); +} diff --git a/examples/with-nanostores/src/components/CartFlyoutToggle.tsx b/examples/with-nanostores/src/components/CartFlyoutToggle.tsx new file mode 100644 index 000000000..9c94bc831 --- /dev/null +++ b/examples/with-nanostores/src/components/CartFlyoutToggle.tsx @@ -0,0 +1,10 @@ +import { useStore } from '@nanostores/preact'; +import { isCartOpen } from '../cartStore'; + + +export default function CartFlyoutToggle() { + const $isCartOpen = useStore(isCartOpen); + return ( + <button onClick={() => isCartOpen.set(!$isCartOpen)}>Cart</button> + ) +} diff --git a/examples/with-nanostores/src/components/FigurineDescription.astro b/examples/with-nanostores/src/components/FigurineDescription.astro new file mode 100644 index 000000000..8d801d53a --- /dev/null +++ b/examples/with-nanostores/src/components/FigurineDescription.astro @@ -0,0 +1,36 @@ +<h1>Astronaut Figurine</h1> +<p class="limited-edition-badge">Limited Edition</p> +<p>The limited edition Astronaut Figurine is the perfect gift for any Astro contributor. This fully-poseable action figurine comes equipped with:</p> +<ul> + <li>A fabric space suit with adjustible straps</li> + <li>Boots lightly dusted by the lunar surface *</li> + <li>An adjustable space visor</li> +</ul> +<p> + <sub>* Dust not actually from the lunar surface</sub> +</p> + +<style> + h1 { + margin: 0; + margin-block-start: 2rem; + } + + .limited-edition-badge { + font-weight: 700; + text-transform: uppercase; + background-image: linear-gradient(0deg,var(--astro-blue), var(--astro-pink)); + background-size: 100% 200%; + background-position-y: 100%; + border-radius: 0.4rem; + animation: pulse 4s ease-in-out infinite; + display: inline-block; + color: white; + padding: 0.2rem 0.4rem; + } + + @keyframes pulse { + 0%, 100% { background-position-y: 0%; } + 50% { background-position-y: 80%; } + } +</style> diff --git a/examples/with-nanostores/src/layouts/Layout.astro b/examples/with-nanostores/src/layouts/Layout.astro new file mode 100644 index 000000000..0eb4ecb76 --- /dev/null +++ b/examples/with-nanostores/src/layouts/Layout.astro @@ -0,0 +1,106 @@ +--- +import CartFlyoutToggle from '../components/CartFlyoutToggle'; +import CartFlyout from '../components/CartFlyout'; + +export interface Props { + title: string; +} + +const { title } = Astro.props as Props; +--- + +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width"> + <link rel="icon" type="image/x-icon" href="/favicon.ico" /> + <title>{title}</title> +</head> +<body> + <header> + <nav> + <a href="/" class="nav-header"><span style="color: var(--astro-blue)">Astro</span> storefront</a> + <CartFlyoutToggle client:load /> + </nav> + </header> + <slot /> + <CartFlyout client:load /> +</body> +</html> + +<style is:global> + :root { + --font-family: system-ui, sans-serif; + --font-size-base: clamp(1rem, 0.34vw + 0.91rem, 1.19rem); + --font-size-lg: clamp(1.2rem, 0.7vw + 1.2rem, 1.5rem); + --font-size-xl: clamp(2.0rem, 1.75vw + 1.35rem, 2.75rem); + + --color-text: hsl(12, 5%, 4%); + --color-bg: hsl(17, 20%, 97%); + --color-bg-2: hsl(17, 20%, 94%); + --color-bg-3: hsl(17, 20%, 88%); + --astro-blue: #4F39FA; + --astro-pink: #DA62C4; + + --content-max-width: 90ch; + --nav-height: clamp(2.44rem, 2.38vw + 1.85rem, 3.75rem); + } + + h1 { + font-size: var(--font-size-xl); + } + + button { + border: none; + color: var(--astro-blue); + border: 2px solid var(--astro-blue); + transition: color 0.2s, background-color 0.2s; + background-color: transparent; + padding: 0.4rem 0.8rem; + border-radius: 0.4rem; + font-family: var(--font-family); + font-size: var(--font-size-base); + font-weight: bold; + cursor: pointer; + } + + button:hover { + background-color: var(--astro-blue); + color: white; + } +</style> + +<style> + html { + font-family: var(--font-family); + font-size: var(--font-size-base); + color: var(--color-text); + background-color: var(--color-bg); + } + + body { + margin: 0; + } + + header { + background: var(--color-bg-2); + } + + nav { + max-width: var(--content-max-width); + height: var(--nav-height); + margin: auto; + padding-inline: 1rem; + display: flex; + justify-content: space-between; + align-items: center; + } + + .nav-header, .nav-header:visited { + font-size: var(--font-size-base); + font-weight: bold; + color: inherit; + text-decoration: none; + } +</style> diff --git a/examples/with-nanostores/src/pages/index.astro b/examples/with-nanostores/src/pages/index.astro index cedc0ac60..965428ab3 100644 --- a/examples/with-nanostores/src/pages/index.astro +++ b/examples/with-nanostores/src/pages/index.astro @@ -1,50 +1,48 @@ --- -// Style Imports -import "../styles/global.css"; -import "../styles/home.css"; +import type { CartItemDisplayInfo } from '../cartStore'; +import Layout from '../layouts/Layout.astro'; +import AddToCartForm from '../components/AddToCartForm'; +import FigurineDescription from '../components/FigurineDescription.astro'; -// Component Imports -import AdminsReact from "../components/AdminsReact.jsx"; -import AdminsSvelte from "../components/AdminsSvelte.svelte"; -import AdminsVue from "../components/AdminsVue.vue"; -import AdminsSolid from "../components/AdminsSolid.jsx"; - -// Full Astro Component Syntax: -// https://docs.astro.build/core-concepts/astro-components/ +const item: CartItemDisplayInfo = { + id: 'astronaut-figurine', + name: 'Astronaut Figurine', + imageSrc: '/images/astronaut-figurine.png', +}; --- +<Layout title={item.name}> + <main> + <div class="product-layout"> + <div> + <FigurineDescription /> + <AddToCartForm item={item} client:load> + <button type="submit">Add to cart</button> + </AddToCartForm> + </div> + <img src={item.imageSrc} alt={item.name} /> + </div> + </main> +</Layout> + +<style> + main { + margin: auto; + padding: 1em; + max-width: var(--content-max-width); + } -<html lang="en"> - <head> - <meta charset="UTF-8" /> - <meta name="viewport" content="width=device-width" /> - <title>Astro</title> + .product-layout { + display: grid; + gap: 2rem; + grid-template-columns: repeat(auto-fit, minmax(20rem, max-content)); + } - <link rel="icon" type="image/x-icon" href="/favicon.ico" /> + .product-layout img { + width: 100%; + max-width: 26rem; + } - <style> - header { - display: flex; - flex-direction: column; - gap: 1em; - max-width: min(100%, 68ch); - } - </style> - </head> - <body> - <main> - <header> - <div> - <img width="60" height="80" src="/assets/logo.svg" alt="Astro logo" /> - <h1> - Welcome to <a href="https://astro.build/">Astro</a> - - <a href="https://github.com/nanostores/nanostores">nanostores</a> - </h1> - </div> - </header> - <AdminsReact client:load /> - <AdminsSvelte client:load /> - <AdminsVue client:load /> - <AdminsSolid client:load /> - </main> - </body> -</html> + button[type="submit"] { + margin-block-start: 1rem; + } +</style> diff --git a/examples/with-nanostores/src/store/admins.js b/examples/with-nanostores/src/store/admins.js deleted file mode 100644 index 8a4a6f4d2..000000000 --- a/examples/with-nanostores/src/store/admins.js +++ /dev/null @@ -1,7 +0,0 @@ -import { computed } from 'nanostores'; - -import { users } from './users.js'; - -const admins = computed(users, (list) => list.filter((user) => user.isAdmin)); - -export { admins }; diff --git a/examples/with-nanostores/src/store/counter.js b/examples/with-nanostores/src/store/counter.js deleted file mode 100644 index d4c29ad62..000000000 --- a/examples/with-nanostores/src/store/counter.js +++ /dev/null @@ -1,15 +0,0 @@ -import { atom } from 'nanostores'; - -const initialValue = { value: 0 }; - -const counter = atom(initialValue); - -function increaseCounter() { - counter.set({ value: counter.get().value + 1 }); -} - -function decreaseCounter() { - counter.set({ value: counter.get().value - 1 }); -} - -export { counter, increaseCounter, decreaseCounter }; diff --git a/examples/with-nanostores/src/store/users.js b/examples/with-nanostores/src/store/users.js deleted file mode 100644 index 7a2e23e9d..000000000 --- a/examples/with-nanostores/src/store/users.js +++ /dev/null @@ -1,30 +0,0 @@ -import { atom } from 'nanostores'; - -const initialValue = [ - { - id: 1, - name: 'User Admin', - age: 28, - isAdmin: true, - }, - { - id: 2, - name: 'NOT Admin', - age: 35, - isAdmin: false, - }, - { - id: 3, - name: 'Another Admin', - age: 46, - isAdmin: true, - }, -]; - -const users = atom(initialValue); - -const addUser = function addUser(user) { - users.set([...users.get(), user]); -}; - -export { users, addUser }; diff --git a/examples/with-nanostores/src/styles/global.css b/examples/with-nanostores/src/styles/global.css deleted file mode 100644 index 8ef8122cb..000000000 --- a/examples/with-nanostores/src/styles/global.css +++ /dev/null @@ -1,29 +0,0 @@ -* { - box-sizing: border-box; - margin: 0; -} - -:root { - font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, - Apple Color Emoji, Segoe UI Emoji; - font-size: 1rem; - --user-font-scale: 1rem - 16px; - font-size: clamp(0.875rem, 0.4626rem + 1.0309vw + var(--user-font-scale), 1.125rem); -} - -body { - padding: 4rem 2rem; - width: 100%; - min-height: 100vh; - display: grid; - justify-content: center; - background: #f9fafb; - color: #111827; -} - -@media (prefers-color-scheme: dark) { - body { - background: #111827; - color: #fff; - } -} diff --git a/examples/with-nanostores/src/styles/home.css b/examples/with-nanostores/src/styles/home.css deleted file mode 100644 index c2f50cb19..000000000 --- a/examples/with-nanostores/src/styles/home.css +++ /dev/null @@ -1,40 +0,0 @@ -:root { - --font-mono: Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', - 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, - 'Courier New', Courier, monospace; - --color-light: #f3f4f6; -} - -@media (prefers-color-scheme: dark) { - :root { - --color-light: #1f2937; - } -} - -a { - color: inherit; -} - -header > div { - font-size: clamp(2rem, -0.4742rem + 6.1856vw, 2.75rem); -} - -header > div { - display: flex; - flex-direction: column; - align-items: center; -} - -header h1 { - font-size: 1em; - font-weight: 500; -} -header img { - width: 2em; - height: 2.667em; -} - -h2 { - font-weight: 500; - font-size: clamp(1.5rem, 1rem + 1.25vw, 2rem); -} |