mirror of https://github.com/sveltejs/svelte
commit
863eff9516
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
let name = 'world';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>Hello {name}!</h1>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Adding data"
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<script>
|
||||||
|
let src = 'tutorial/image.gif';
|
||||||
|
let name = 'Rick Astley';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- {src} is short for src={src} -->
|
||||||
|
<img {src} alt="{name} dancing">
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Dynamic attributes"
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<style>
|
||||||
|
p {
|
||||||
|
color: purple;
|
||||||
|
font-family: 'Comic Sans MS';
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<p>Styled!</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Styling"
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
<script>
|
||||||
|
import Nested from './Nested.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
p {
|
||||||
|
color: purple;
|
||||||
|
font-family: 'Comic Sans MS';
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<p>These styles...</p>
|
||||||
|
<Nested/>
|
@ -0,0 +1 @@
|
|||||||
|
<p>...don't affect this element</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Nested components"
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
let string = `here's some <strong>HTML!!!</strong>`;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>{@html string}</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "HTML tags"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Introduction"
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button on:click={handleClick}>
|
||||||
|
Clicked {count} {count === 1 ? 'time' : 'times'}
|
||||||
|
</button>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Reactive assignments"
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
<script>
|
||||||
|
let count = 1;
|
||||||
|
|
||||||
|
// the `$:` means 're-run whenever these values change'
|
||||||
|
$: doubled = count * 2;
|
||||||
|
$: quadrupled = doubled * 2;
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button on:click={handleClick}>
|
||||||
|
Count: {count}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<p>{count} * 2 = {doubled}</p>
|
||||||
|
<p>{doubled} * 2 = {quadrupled}</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Reactive declarations"
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
$: if (count >= 10) {
|
||||||
|
alert(`count is dangerously high!`);
|
||||||
|
count = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button on:click={handleClick}>
|
||||||
|
Clicked {count} {count === 1 ? 'time' : 'times'}
|
||||||
|
</button>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Reactive statements"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Reactivity"
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
export let answer;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>The answer is {answer}</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Declaring props"
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
<script>
|
||||||
|
import Nested from './Nested.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Nested answer={42}/>
|
||||||
|
<Nested/>
|
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
export let answer = 'a mystery';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>The answer is {answer}</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Default values"
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
import Info from './Info.svelte';
|
||||||
|
|
||||||
|
const pkg = {
|
||||||
|
name: 'svelte',
|
||||||
|
version: 3,
|
||||||
|
speed: 'blazing',
|
||||||
|
website: 'https://svelte.technology'
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Info {...pkg}/>
|
@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
export let name;
|
||||||
|
export let version;
|
||||||
|
export let speed;
|
||||||
|
export let website;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The <code>{name}</code> package is {speed} fast.
|
||||||
|
Download version {version} from <a href="https://www.npmjs.com/package/{name}">npm</a>
|
||||||
|
and <a href={website}>learn more here</a>
|
||||||
|
</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Spread props"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Props"
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<script>
|
||||||
|
let user = { loggedIn: false };
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
user.loggedIn = !user.loggedIn;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if user.loggedIn}
|
||||||
|
<button on:click={toggle}>
|
||||||
|
Log out
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if !user.loggedIn}
|
||||||
|
<button on:click={toggle}>
|
||||||
|
Log in
|
||||||
|
</button>
|
||||||
|
{/if}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "If blocks"
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
<script>
|
||||||
|
let user = { loggedIn: false };
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
user.loggedIn = !user.loggedIn;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if user.loggedIn}
|
||||||
|
<button on:click={toggle}>
|
||||||
|
Log out
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<button on:click={toggle}>
|
||||||
|
Log in
|
||||||
|
</button>
|
||||||
|
{/if}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Else blocks"
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
let x = 7;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if x > 10}
|
||||||
|
<p>{x} is greater than 10</p>
|
||||||
|
{:else if 5 > x}
|
||||||
|
<p>{x} is less than 5</p>
|
||||||
|
{:else}
|
||||||
|
<p>{x} is between 5 and 10</p>
|
||||||
|
{/if}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Else-if blocks"
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
<script>
|
||||||
|
let cats = [
|
||||||
|
{ id: 'J---aiyznGQ', name: 'Keyboard Cat' },
|
||||||
|
{ id: 'z_AbfPXTKms', name: 'Maru' },
|
||||||
|
{ id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>The Famous Cats of YouTube</h1>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{#each cats as { id, name }, i}
|
||||||
|
<li><a target="_blank" href="https://www.youtube.com/watch?v={id}">
|
||||||
|
{i + 1}: {name}
|
||||||
|
</a></li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Each blocks"
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
<script>
|
||||||
|
import Thing from './Thing.svelte';
|
||||||
|
|
||||||
|
let things = [
|
||||||
|
{ id: 1, value: 'a' },
|
||||||
|
{ id: 2, value: 'b' },
|
||||||
|
{ id: 3, value: 'c' },
|
||||||
|
{ id: 4, value: 'd' },
|
||||||
|
{ id: 5, value: 'e' }
|
||||||
|
];
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
things = things.slice(1);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button on:click={handleClick}>
|
||||||
|
Remove first thing
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#each things as thing (thing.id)}
|
||||||
|
<Thing value={thing.value}/>
|
||||||
|
{/each}
|
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
// `value` is updated whenever the prop value changes...
|
||||||
|
export let value;
|
||||||
|
|
||||||
|
// ...but `valueAtStart` is fixed upon initialisation
|
||||||
|
const valueAtStart = value;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>{valueAtStart} / {value}</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Keyed each blocks"
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
<script>
|
||||||
|
let promise = getRandomNumber();
|
||||||
|
|
||||||
|
async function getRandomNumber() {
|
||||||
|
const res = await fetch(`tutorial/random-number`);
|
||||||
|
const text = await res.text();
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
return text;
|
||||||
|
} else {
|
||||||
|
throw new Error(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
promise = getRandomNumber();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button on:click={handleClick}>
|
||||||
|
generate random number
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#await promise}
|
||||||
|
<p>...waiting</p>
|
||||||
|
{:then number}
|
||||||
|
<p>The number is {number}</p>
|
||||||
|
{:catch error}
|
||||||
|
<p style="color: red">{error.message}</p>
|
||||||
|
{/await}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Await blocks"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Logic"
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
let m = { x: 0, y: 0 };
|
||||||
|
|
||||||
|
function handleMousemove(event) {
|
||||||
|
m.x = event.clientX;
|
||||||
|
m.y = event.clientY;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div { width: 100%; height: 100%; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div on:mousemove={handleMousemove}>
|
||||||
|
The mouse position is {m.x} x {m.y}
|
||||||
|
</div>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "DOM events"
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
let m = { x: 0, y: 0 };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div { width: 100%; height: 100%; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div on:mousemove="{e => m = { x: e.clientX, y: e.clientY }}">
|
||||||
|
The mouse position is {m.x} x {m.y}
|
||||||
|
</div>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Inline handlers"
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
function handleClick() {
|
||||||
|
alert('no more alerts')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button on:click|once={handleClick}>
|
||||||
|
Click me
|
||||||
|
</button>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Event modifiers"
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
import Inner from './Inner.svelte';
|
||||||
|
|
||||||
|
function handleMessage(event) {
|
||||||
|
alert(event.detail.text);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Inner on:message={handleMessage}/>
|
@ -0,0 +1,15 @@
|
|||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
function sayHello() {
|
||||||
|
dispatch('message', {
|
||||||
|
text: 'Hello!'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button on:click={sayHello}>
|
||||||
|
Click to say hello
|
||||||
|
</button>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Component events"
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
import Outer from './Outer.svelte';
|
||||||
|
|
||||||
|
function handleMessage(event) {
|
||||||
|
alert(event.detail.text);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Outer on:message={handleMessage}/>
|
@ -0,0 +1,15 @@
|
|||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
function sayHello() {
|
||||||
|
dispatch('message', {
|
||||||
|
text: 'Hello!'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button on:click={sayHello}>
|
||||||
|
Click to say hello
|
||||||
|
</button>
|
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
import Inner from './Inner.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Inner on:message/>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Event forwarding"
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
import FancyButton from './FancyButton.svelte';
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
alert('clicked');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FancyButton on:click={handleClick}/>
|
@ -0,0 +1,15 @@
|
|||||||
|
<style>
|
||||||
|
button {
|
||||||
|
font-family: 'Comic Sans MS';
|
||||||
|
font-size: 2em;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
color: royalblue;
|
||||||
|
background: gold;
|
||||||
|
border-radius: 1em;
|
||||||
|
box-shadow: 2px 2px 4px rgba(0,0,0,0.5);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<button on:click>
|
||||||
|
Click me
|
||||||
|
</button>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "DOM event forwarding"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Events"
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
<script>
|
||||||
|
let name = '';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<input bind:value={name} placeholder="enter your name">
|
||||||
|
<p>Hello {name || 'stranger'}!</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Text inputs"
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
let a = 1;
|
||||||
|
let b = 2;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=number bind:value={a} min=0 max=10>
|
||||||
|
<input type=range bind:value={a} min=0 max=10>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=number bind:value={b} min=0 max=10>
|
||||||
|
<input type=range bind:value={b} min=0 max=10>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<p>{a} + {b} = {a + b}</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Numeric inputs"
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
<script>
|
||||||
|
let yes = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=checkbox bind:checked={yes}>
|
||||||
|
Yes! Send me regular email spam
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{#if yes}
|
||||||
|
<p>Thank you. We will bombard your inbox and sell your personal details.</p>
|
||||||
|
{:else}
|
||||||
|
<p>You must opt in to continue. If you're not paying, you're the product.</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<button disabled={!yes}>
|
||||||
|
Subscribe
|
||||||
|
</button>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Checkbox inputs"
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
<script>
|
||||||
|
let scoops = 1;
|
||||||
|
let flavours = ['Mint choc chip'];
|
||||||
|
|
||||||
|
let menu = [
|
||||||
|
'Cookies and cream',
|
||||||
|
'Mint choc chip',
|
||||||
|
'Raspberry ripple'
|
||||||
|
];
|
||||||
|
|
||||||
|
function join(flavours) {
|
||||||
|
if (flavours.length === 1) return flavours[0];
|
||||||
|
return `${flavours.slice(0, -1).join(', ')} and ${flavours[flavours.length - 1]}`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h2>Size</h2>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio bind:group={scoops} value={1}>
|
||||||
|
One scoop
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio bind:group={scoops} value={2}>
|
||||||
|
Two scoops
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio bind:group={scoops} value={3}>
|
||||||
|
Three scoops
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<h2>Flavours</h2>
|
||||||
|
|
||||||
|
{#each menu as flavour}
|
||||||
|
<label>
|
||||||
|
<input type=checkbox bind:group={flavours} value={flavour}>
|
||||||
|
{flavour}
|
||||||
|
</label>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#if flavours.length === 0}
|
||||||
|
<p>Please select at least one flavour</p>
|
||||||
|
{:else if flavours.length > scoops}
|
||||||
|
<p>Can't order more flavours than scoops!</p>
|
||||||
|
{:else}
|
||||||
|
<p>
|
||||||
|
You ordered {scoops} {scoops === 1 ? 'scoop' : 'scoops'}
|
||||||
|
of {join(flavours)}
|
||||||
|
</p>
|
||||||
|
{/if}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Group inputs"
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
import marked from 'marked';
|
||||||
|
let value = `Some words are *italic*, some are **bold**`;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
textarea { width: 100%; height: 200px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<textarea bind:value></textarea>
|
||||||
|
|
||||||
|
{@html marked(value)}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Textarea inputs"
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
<script>
|
||||||
|
let questions = [
|
||||||
|
{ id: 1, text: `Where did you go to school?` },
|
||||||
|
{ id: 2, text: `What is your mother's name?` },
|
||||||
|
{ id: 3, text: `What is another personal fact that an attacker could easily find with Google?` }
|
||||||
|
];
|
||||||
|
|
||||||
|
let selected;
|
||||||
|
|
||||||
|
let answer = '';
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
alert(`answered question ${selected.id} (${selected.text}) with "${answer}"`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
input { display: block; width: 500px; max-width: 100%; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h2>Insecurity questions</h2>
|
||||||
|
|
||||||
|
<form on:submit|preventDefault={handleSubmit}>
|
||||||
|
<select bind:value={selected} on:change="{() => answer = ''}">
|
||||||
|
{#each questions as question}
|
||||||
|
<option value={question}>
|
||||||
|
{question.text}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<input bind:value={answer}>
|
||||||
|
|
||||||
|
<button disabled={!answer} type=submit>
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p>selected question {selected ? selected.id : '[waiting...]'}</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Select bindings"
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
<script>
|
||||||
|
let scoops = 1;
|
||||||
|
let flavours = ['Mint choc chip'];
|
||||||
|
|
||||||
|
let menu = [
|
||||||
|
'Cookies and cream',
|
||||||
|
'Mint choc chip',
|
||||||
|
'Raspberry ripple'
|
||||||
|
];
|
||||||
|
|
||||||
|
function join(flavours) {
|
||||||
|
if (flavours.length === 1) return flavours[0];
|
||||||
|
return `${flavours.slice(0, -1).join(', ')} and ${flavours[flavours.length - 1]}`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h2>Size</h2>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio bind:group={scoops} value={1}>
|
||||||
|
One scoop
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio bind:group={scoops} value={2}>
|
||||||
|
Two scoops
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio bind:group={scoops} value={3}>
|
||||||
|
Three scoops
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<h2>Flavours</h2>
|
||||||
|
|
||||||
|
<select multiple bind:value={flavours}>
|
||||||
|
{#each menu as flavour}
|
||||||
|
<option value={flavour}>
|
||||||
|
{flavour}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
{#if flavours.length === 0}
|
||||||
|
<p>Please select at least one flavour</p>
|
||||||
|
{:else if flavours.length > scoops}
|
||||||
|
<p>Can't order more flavours than scoops!</p>
|
||||||
|
{:else}
|
||||||
|
<p>
|
||||||
|
You ordered {scoops} {scoops === 1 ? 'scoop' : 'scoops'}
|
||||||
|
of {join(flavours)}
|
||||||
|
</p>
|
||||||
|
{/if}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Select multiple"
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
<script>
|
||||||
|
let todos = [
|
||||||
|
{ done: false, text: 'finish Svelte tutorial' },
|
||||||
|
{ done: false, text: 'build an app' },
|
||||||
|
{ done: false, text: 'world domination' }
|
||||||
|
];
|
||||||
|
|
||||||
|
function add() {
|
||||||
|
todos = todos.concat({ done: false, text: '' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
todos = todos.filter(t => !t.done);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>Todos</h1>
|
||||||
|
|
||||||
|
{#each todos as todo}
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type=checkbox
|
||||||
|
bind:checked={todo.done}
|
||||||
|
>
|
||||||
|
|
||||||
|
<input
|
||||||
|
placeholder="What needs to be done?"
|
||||||
|
bind:value={todo.text}
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
<button on:click={add}>
|
||||||
|
Add new
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button on:click={clear}>
|
||||||
|
Clear completed
|
||||||
|
</button>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Each block bindings"
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
<script>
|
||||||
|
// These values are bound to properties of the video
|
||||||
|
let time = 0;
|
||||||
|
let duration;
|
||||||
|
let paused = true;
|
||||||
|
|
||||||
|
let showControls = true;
|
||||||
|
let showControlsTimeout;
|
||||||
|
|
||||||
|
function handleMousemove(e) {
|
||||||
|
// Make the controls visible, but fade out after
|
||||||
|
// 2.5 seconds of inactivity
|
||||||
|
clearTimeout(showControlsTimeout);
|
||||||
|
showControlsTimeout = setTimeout(() => showControls = false, 2500);
|
||||||
|
showControls = true;
|
||||||
|
|
||||||
|
if (e.which !== 1) return; // mouse not down
|
||||||
|
if (!duration) return; // video not loaded yet
|
||||||
|
|
||||||
|
const { left, right } = this.getBoundingClientRect();
|
||||||
|
time = duration * (e.clientX - left) / (right - left);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMousedown(e) {
|
||||||
|
// we can't rely on the built-in click event, because it fires
|
||||||
|
// after a drag — we have to listen for clicks ourselves
|
||||||
|
|
||||||
|
function handleMouseup() {
|
||||||
|
if (paused) e.target.play();
|
||||||
|
else e.target.pause();
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
e.target.removeEventListener('mouseup', handleMouseup);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.target.addEventListener('mouseup', handleMouseup);
|
||||||
|
|
||||||
|
setTimeout(cancel, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
function format(seconds) {
|
||||||
|
if (isNaN(seconds)) return '...';
|
||||||
|
|
||||||
|
const minutes = Math.floor(seconds / 60);
|
||||||
|
seconds = Math.floor(seconds % 60);
|
||||||
|
if (seconds < 10) seconds = '0' + seconds;
|
||||||
|
|
||||||
|
return `${minutes}:${seconds}`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
transition: opacity 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
color: white;
|
||||||
|
text-shadow: 0 0 8px black;
|
||||||
|
font-size: 1.4em;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
width: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time:last-child { text-align: right }
|
||||||
|
|
||||||
|
progress {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 10px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress::-webkit-progress-bar {
|
||||||
|
background-color: rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
progress::-webkit-progress-value {
|
||||||
|
background-color: rgba(255,255,255,0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
video {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h1>Caminandes: Llamigos</h1>
|
||||||
|
<p>From <a href="https://cloud.blender.org/open-projects">Blender Open Projects</a>. CC-BY</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<video
|
||||||
|
poster="http://svelte-assets.surge.sh/caminandes-llamigos.jpg"
|
||||||
|
src="http://svelte-assets.surge.sh/caminandes-llamigos.mp4"
|
||||||
|
on:mousemove={handleMousemove}
|
||||||
|
on:mousedown={handleMousedown}
|
||||||
|
bind:currentTime={time}
|
||||||
|
bind:duration
|
||||||
|
bind:paused
|
||||||
|
></video>
|
||||||
|
|
||||||
|
<div class="controls" style="opacity: {duration && showControls ? 1 : 0}">
|
||||||
|
<progress value="{(time / duration) || 0}"/>
|
||||||
|
|
||||||
|
<div class="info">
|
||||||
|
<span class="time">{format(time)}</span>
|
||||||
|
<span>click anywhere to {paused ? 'play' : 'pause'} / drag to seek</span>
|
||||||
|
<span class="time">{format(duration)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Media elements"
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<script>
|
||||||
|
let w;
|
||||||
|
let h;
|
||||||
|
let size = 42;
|
||||||
|
let text = 'edit me';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
input { display: block; }
|
||||||
|
div { display: inline-block; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<input type=range bind:value={size}>
|
||||||
|
<input bind:value={text}>
|
||||||
|
|
||||||
|
<p>size: {w}px x {h}px</p>
|
||||||
|
|
||||||
|
<div bind:clientWidth={w} bind:clientHeight={h}>
|
||||||
|
<span style="font-size: {size}px">{text}</span>
|
||||||
|
</div>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Dimensions"
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<script>
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
let canvas;
|
||||||
|
let ctx;
|
||||||
|
let running = false;
|
||||||
|
|
||||||
|
const r = Math.random();
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
let frame;
|
||||||
|
|
||||||
|
(function loop() {
|
||||||
|
frame = requestAnimationFrame(loop);
|
||||||
|
|
||||||
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
for (let p = 0; p < imageData.data.length; p += 4) {
|
||||||
|
const i = p / 4;
|
||||||
|
const x = i % canvas.width;
|
||||||
|
const y = i / canvas.height >>> 0;
|
||||||
|
|
||||||
|
const t = window.performance.now();
|
||||||
|
|
||||||
|
const r = 64 + (128 * x / canvas.width) + (64 * Math.sin(t / 1000));
|
||||||
|
const g = 64 + (128 * y / canvas.height) + (64 * Math.cos(t / 1000));
|
||||||
|
const b = 128;
|
||||||
|
|
||||||
|
imageData.data[p + 0] = r;
|
||||||
|
imageData.data[p + 1] = g;
|
||||||
|
imageData.data[p + 2] = b;
|
||||||
|
imageData.data[p + 3] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.putImageData(imageData, 0, 0);
|
||||||
|
}());
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelAnimationFrame(frame);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #666;
|
||||||
|
-webkit-mask: url(logo-mask.svg) 50% 50% no-repeat;
|
||||||
|
mask: url(logo-mask.svg) 50% 50% no-repeat;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<canvas
|
||||||
|
bind:this={canvas}
|
||||||
|
width={32}
|
||||||
|
height={32}
|
||||||
|
></canvas>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "bind:this={canvas}"
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
<script>
|
||||||
|
import Keypad from './Keypad.svelte';
|
||||||
|
|
||||||
|
let pin;
|
||||||
|
$: view = pin ? pin.replace(/\d(?!$)/g, '•') : 'enter your pin';
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
alert(`submitted ${pin}`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1 style="color: {pin ? '#333' : '#ccc'}">{view}</h1>
|
||||||
|
|
||||||
|
<Keypad bind:value={pin} on:submit={handleSubmit}/>
|
@ -0,0 +1,40 @@
|
|||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
|
export let value = '';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
const select = num => () => value += num;
|
||||||
|
const clear = () => value = '';
|
||||||
|
const submit = () => dispatch('submit');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.keypad {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 5em);
|
||||||
|
grid-template-rows: repeat(4, 3em);
|
||||||
|
grid-gap: 0.5em
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 0
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="keypad">
|
||||||
|
<button on:click={select(1)}>1</button>
|
||||||
|
<button on:click={select(2)}>2</button>
|
||||||
|
<button on:click={select(3)}>3</button>
|
||||||
|
<button on:click={select(4)}>4</button>
|
||||||
|
<button on:click={select(5)}>5</button>
|
||||||
|
<button on:click={select(6)}>6</button>
|
||||||
|
<button on:click={select(7)}>7</button>
|
||||||
|
<button on:click={select(8)}>8</button>
|
||||||
|
<button on:click={select(9)}>9</button>
|
||||||
|
|
||||||
|
<button disabled={!value} on:click={clear}>clear</button>
|
||||||
|
<button on:click={select(0)}>0</button>
|
||||||
|
<button disabled={!value} on:click={submit}>submit</button>
|
||||||
|
</div>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Component bindings"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Bindings"
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
<script>
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
let photos = [];
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`);
|
||||||
|
photos = await res.json();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.photos {
|
||||||
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(5, 1fr);
|
||||||
|
grid-gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure, img {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h1>Photo album</h1>
|
||||||
|
|
||||||
|
<div class="photos">
|
||||||
|
{#each photos as photo}
|
||||||
|
<figure>
|
||||||
|
<img src={photo.thumbnailUrl} alt={photo.title}>
|
||||||
|
<figcaption>{photo.title}</figcaption>
|
||||||
|
</figure>
|
||||||
|
{:else}
|
||||||
|
<!-- this block renders when photos.length === 0 -->
|
||||||
|
<p>loading...</p>
|
||||||
|
{/each}
|
||||||
|
</div>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "onMount"
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
import { onInterval } from './utils.js';
|
||||||
|
|
||||||
|
let seconds = 0;
|
||||||
|
onInterval(() => seconds += 1, 1000);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The page has been open for
|
||||||
|
{seconds} {seconds === 1 ? 'second' : 'seconds'}
|
||||||
|
</p>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "onDestroy"
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
import { onDestroy } from 'svelte';
|
||||||
|
|
||||||
|
export function onInterval(callback, milliseconds) {
|
||||||
|
const interval = setInterval(callback, milliseconds);
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
clearInterval(interval);
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
<script>
|
||||||
|
import Eliza from 'elizanode';
|
||||||
|
import { beforeUpdate, afterUpdate } from 'svelte';
|
||||||
|
|
||||||
|
let div;
|
||||||
|
let autoscroll;
|
||||||
|
|
||||||
|
beforeUpdate(() => {
|
||||||
|
autoscroll = div && (div.offsetHeight + div.scrollTop) > (div.scrollHeight - 20);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterUpdate(() => {
|
||||||
|
if (autoscroll) div.scrollTo(0, div.scrollHeight);
|
||||||
|
});
|
||||||
|
|
||||||
|
const eliza = new Eliza();
|
||||||
|
|
||||||
|
let comments = [
|
||||||
|
{ author: 'eliza', text: eliza.getInitial() }
|
||||||
|
];
|
||||||
|
|
||||||
|
function handleKeydown(event) {
|
||||||
|
if (event.which === 13) {
|
||||||
|
const text = event.target.value;
|
||||||
|
if (!text) return;
|
||||||
|
|
||||||
|
comments = comments.concat({
|
||||||
|
author: 'user',
|
||||||
|
text
|
||||||
|
});
|
||||||
|
|
||||||
|
event.target.value = '';
|
||||||
|
|
||||||
|
const reply = eliza.transform(text);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
comments = comments.concat({
|
||||||
|
author: 'eliza',
|
||||||
|
text: '...',
|
||||||
|
placeholder: true
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
comments = comments.filter(comment => !comment.placeholder).concat({
|
||||||
|
author: 'eliza',
|
||||||
|
text: reply
|
||||||
|
});
|
||||||
|
}, 500 + Math.random() * 500);
|
||||||
|
}, 200 + Math.random() * 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.chat {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
max-width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollable {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
margin: 0 0 0.5em 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eliza span {
|
||||||
|
background-color: #eee;
|
||||||
|
border-radius: 1em 1em 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user span {
|
||||||
|
background-color: #0074D9;
|
||||||
|
color: white;
|
||||||
|
border-radius: 1em 1em 0 1em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="chat">
|
||||||
|
<h1>Eliza</h1>
|
||||||
|
|
||||||
|
<div class="scrollable" bind:this={div}>
|
||||||
|
{#each comments as comment}
|
||||||
|
<article class={comment.author}>
|
||||||
|
<span>{comment.text}</span>
|
||||||
|
</article>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input on:keydown={handleKeydown}>
|
||||||
|
</div>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "beforeUpdate and afterUpdate"
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
<script>
|
||||||
|
import { tick } from 'svelte';
|
||||||
|
|
||||||
|
let text = `Select some text and hit the tab key to toggle uppercase`;
|
||||||
|
|
||||||
|
async function handleKeydown(event) {
|
||||||
|
if (event.which !== 9) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const { selectionStart, selectionEnd, value } = this;
|
||||||
|
const selection = value.slice(selectionStart, selectionEnd);
|
||||||
|
|
||||||
|
const replacement = /[a-z]/.test(selection)
|
||||||
|
? selection.toUpperCase()
|
||||||
|
: selection.toLowerCase();
|
||||||
|
|
||||||
|
text = (
|
||||||
|
value.slice(0, selectionStart) +
|
||||||
|
replacement +
|
||||||
|
value.slice(selectionEnd)
|
||||||
|
);
|
||||||
|
|
||||||
|
await tick();
|
||||||
|
this.selectionStart = selectionStart;
|
||||||
|
this.selectionEnd = selectionEnd;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<textarea value={text} on:keydown={handleKeydown}></textarea>
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "tick"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Lifecycle"
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
<script>
|
||||||
|
import { count } from './stores.js';
|
||||||
|
import Incrementer from './Incrementer.svelte';
|
||||||
|
import Decrementer from './Decrementer.svelte';
|
||||||
|
import Resetter from './Resetter.svelte';
|
||||||
|
|
||||||
|
let count_value;
|
||||||
|
|
||||||
|
const unsubscribe = count.subscribe(value => {
|
||||||
|
count_value = value;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>The count is {count_value}</h1>
|
||||||
|
|
||||||
|
<Incrementer/>
|
||||||
|
<Decrementer/>
|
||||||
|
<Resetter/>
|
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
import { count } from './stores.js';
|
||||||
|
|
||||||
|
function decrement() {
|
||||||
|
count.update(n => n - 1);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button on:click={decrement}>
|
||||||
|
-
|
||||||
|
</button>
|
@ -1,11 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
let count = 0;
|
import { count } from './stores.js';
|
||||||
|
|
||||||
function increment() {
|
function increment() {
|
||||||
count += 1;
|
count.update(n => n + 1);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button on:click={increment}>
|
<button on:click={increment}>
|
||||||
clicks: {count}
|
+
|
||||||
</button>
|
</button>
|
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
import { count } from './stores.js';
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
count.set(0);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button on:click={reset}>
|
||||||
|
reset
|
||||||
|
</button>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue