Skip to content

Commit 13e6853

Browse files
author
Rich Harris
committed
better eliza
1 parent 138680a commit 13e6853

File tree

3 files changed

+177
-44
lines changed

3 files changed

+177
-44
lines changed

content/tutorial/01-svelte/07-lifecycle/02-update/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ let div;
1414
+++let autoscroll = false;+++
1515

1616
beforeUpdate(() => {
17-
+++autoscroll = div && div.offsetHeight + div.scrollTop > div.scrollHeight - 20;+++
17+
+++ if (div) {
18+
const scrollableDistance = div.scrollHeight - div.offsetHeight;
19+
autoscroll = div.scrollTop > scrollableDistance - 20;
20+
}+++
1821
});
1922

2023
afterUpdate(() => {

content/tutorial/01-svelte/07-lifecycle/02-update/app-a/src/lib/App.svelte

Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@
2121
2222
const typing = { author: 'eliza', text: '...' };
2323
24-
let comments = [
25-
{ author: 'eliza', text: eliza.getInitial() }
26-
];
24+
let comments = [];
2725
2826
async function handleKeydown(event) {
2927
if (event.key === 'Enter' && event.target.value) {
@@ -49,37 +47,67 @@
4947
}
5048
</script>
5149

52-
<div class="chat">
53-
<h1>Eliza</h1>
54-
55-
<div class="scrollable" bind:this={div}>
56-
{#each comments as comment}
57-
<article class={comment.author}>
58-
<span>{comment.text}</span>
59-
</article>
60-
{/each}
50+
<div class="container">
51+
<div class="phone">
52+
<div class="chat" bind:this={div}>
53+
<header>
54+
<h1>Eliza</h1>
55+
56+
<article class="eliza">
57+
<span>{eliza.getInitial()}</span>
58+
</article>
59+
</header>
60+
61+
{#each comments as comment}
62+
<article class={comment.author}>
63+
<span>{comment.text}</span>
64+
</article>
65+
{/each}
66+
</div>
67+
68+
<input on:keydown={handleKeydown} />
6169
</div>
62-
63-
<input on:keydown={handleKeydown} />
6470
</div>
6571

6672
<style>
67-
.chat {
73+
.container {
74+
display: grid;
75+
place-items: center;
76+
height: 100%;
77+
}
78+
79+
.phone {
6880
display: flex;
6981
flex-direction: column;
82+
width: 100%;
7083
height: 100%;
71-
max-width: 320px;
7284
}
7385
74-
.scrollable {
86+
header {
87+
display: flex;
88+
flex-direction: column;
89+
height: 100%;
90+
padding: 4em 0 0 0;
91+
box-sizing: border-box;
92+
}
93+
94+
h1 {
95+
flex: 1;
96+
font-size: 1.4em;
97+
text-align: center;
98+
border-bottom: 1px solid var(--bg-1);
99+
}
100+
101+
.chat {
102+
height: 0;
75103
flex: 1 1 auto;
76-
border-top: 1px solid #eee;
77-
margin: 0 0 0.5em 0;
104+
padding: 0 1em;
78105
overflow-y: auto;
106+
scroll-behavior: smooth;
79107
}
80108
81109
article {
82-
margin: 0.5em 0;
110+
margin: 0 0 0.5em 0;
83111
}
84112
85113
.user {
@@ -103,4 +131,40 @@
103131
border-radius: 1em 1em 0 1em;
104132
word-break: break-all;
105133
}
134+
135+
input {
136+
margin: 0.5em 1em 1em 1em;
137+
}
138+
139+
@media (min-width: 400px) {
140+
.phone {
141+
background: var(--bg-1);
142+
position: relative;
143+
font-size: min(2.5vh, 1rem);
144+
width: auto;
145+
height: 36em;
146+
aspect-ratio: 9 / 16;
147+
border: 0.2em solid #222;
148+
border-radius: 1em;
149+
box-sizing: border-box;
150+
filter: drop-shadow(1px 1px 0px var(--fg-1)) drop-shadow(2px 2px 0px var(--fg-1)) drop-shadow(3px 3px 0px var(--fg-1))
151+
}
152+
153+
.phone::after {
154+
position: absolute;
155+
content: '';
156+
background: #222;
157+
width: 60%;
158+
height: 1em;
159+
left: 20%;
160+
top: 0;
161+
border-radius: 0 0 0.5em 0.5em
162+
}
163+
}
164+
165+
@media (prefers-reduced-motion) {
166+
.chat {
167+
scroll-behavior: auto;
168+
}
169+
}
106170
</style>

content/tutorial/01-svelte/07-lifecycle/02-update/app-b/src/lib/App.svelte

Lines changed: 89 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
let autoscroll = false;
1010
1111
beforeUpdate(() => {
12-
autoscroll = div && div.offsetHeight + div.scrollTop > div.scrollHeight - 20;
12+
if (div) {
13+
const scrollableDistance = div.scrollHeight - div.offsetHeight;
14+
autoscroll = div.scrollTop > scrollableDistance - 20;
15+
}
1316
});
1417
1518
afterUpdate(() => {
@@ -23,14 +26,10 @@
2326
2427
const typing = { author: 'eliza', text: '...' };
2528
26-
let comments = [
27-
{ author: 'eliza', text: eliza.getInitial() }
28-
];
29+
let comments = [];
2930
3031
async function handleKeydown(event) {
3132
if (event.key === 'Enter' && event.target.value) {
32-
event.target.value = '';
33-
3433
const comment = {
3534
author: 'user',
3635
text: event.target.value
@@ -41,6 +40,7 @@
4140
text: eliza.transform(comment.text)
4241
};
4342
43+
event.target.value = '';
4444
comments = [...comments, comment];
4545
4646
await pause(200 * (1 + Math.random()));
@@ -52,37 +52,67 @@
5252
}
5353
</script>
5454

55-
<div class="chat">
56-
<h1>Eliza</h1>
57-
58-
<div class="scrollable" bind:this={div}>
59-
{#each comments as comment}
60-
<article class={comment.author}>
61-
<span>{comment.text}</span>
62-
</article>
63-
{/each}
55+
<div class="container">
56+
<div class="phone">
57+
<div class="chat" bind:this={div}>
58+
<header>
59+
<h1>Eliza</h1>
60+
61+
<article class="eliza">
62+
<span>{eliza.getInitial()}</span>
63+
</article>
64+
</header>
65+
66+
{#each comments as comment}
67+
<article class={comment.author}>
68+
<span>{comment.text}</span>
69+
</article>
70+
{/each}
71+
</div>
72+
73+
<input on:keydown={handleKeydown} />
6474
</div>
65-
66-
<input on:keydown={handleKeydown} />
6775
</div>
6876

6977
<style>
70-
.chat {
78+
.container {
79+
display: grid;
80+
place-items: center;
81+
height: 100%;
82+
}
83+
84+
.phone {
85+
display: flex;
86+
flex-direction: column;
87+
width: 100%;
88+
height: 100%;
89+
}
90+
91+
header {
7192
display: flex;
7293
flex-direction: column;
7394
height: 100%;
74-
max-width: 320px;
95+
padding: 4em 0 0 0;
96+
box-sizing: border-box;
7597
}
7698
77-
.scrollable {
99+
h1 {
100+
flex: 1;
101+
font-size: 1.4em;
102+
text-align: center;
103+
border-bottom: 1px solid var(--bg-1);
104+
}
105+
106+
.chat {
107+
height: 0;
78108
flex: 1 1 auto;
79-
border-top: 1px solid #eee;
80-
margin: 0 0 0.5em 0;
109+
padding: 0 1em;
81110
overflow-y: auto;
111+
scroll-behavior: smooth;
82112
}
83113
84114
article {
85-
margin: 0.5em 0;
115+
margin: 0 0 0.5em 0;
86116
}
87117
88118
.user {
@@ -106,4 +136,40 @@
106136
border-radius: 1em 1em 0 1em;
107137
word-break: break-all;
108138
}
139+
140+
input {
141+
margin: 0.5em 1em 1em 1em;
142+
}
143+
144+
@media (min-width: 400px) {
145+
.phone {
146+
background: var(--bg-1);
147+
position: relative;
148+
font-size: min(2.5vh, 1rem);
149+
width: auto;
150+
height: 36em;
151+
aspect-ratio: 9 / 16;
152+
border: 0.2em solid #222;
153+
border-radius: 1em;
154+
box-sizing: border-box;
155+
filter: drop-shadow(1px 1px 0px var(--fg-1)) drop-shadow(2px 2px 0px var(--fg-1)) drop-shadow(3px 3px 0px var(--fg-1))
156+
}
157+
158+
.phone::after {
159+
position: absolute;
160+
content: '';
161+
background: #222;
162+
width: 60%;
163+
height: 1em;
164+
left: 20%;
165+
top: 0;
166+
border-radius: 0 0 0.5em 0.5em
167+
}
168+
}
169+
170+
@media (prefers-reduced-motion) {
171+
.chat {
172+
scroll-behavior: auto;
173+
}
174+
}
109175
</style>

0 commit comments

Comments
 (0)