Skip to content

Commit 3cb5795

Browse files
authored
convert to svelte 5/TS (#417)
* convert to state * convert another store to state * more * more conversion * more * more * more * convert more stuff * more * convert more * more
1 parent 8a52f97 commit 3cb5795

File tree

8 files changed

+261
-238
lines changed

8 files changed

+261
-238
lines changed

apps/svelte.dev/src/routes/tutorial/[...slug]/+page.svelte

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,7 @@
99
import Output from './Output.svelte';
1010
import { ScreenToggle } from '@sveltejs/site-kit/components';
1111
import Sidebar from './Sidebar.svelte';
12-
import {
13-
creating,
14-
files,
15-
reset_files,
16-
selected_file,
17-
selected_name,
18-
solution
19-
} from './state.svelte';
12+
import { solution, workspace } from './state.svelte';
2013
import { create_directories } from './utils';
2114
import { needs_webcontainers, text_files } from './shared';
2215
import OutputRollup from './OutputRollup.svelte';
@@ -93,10 +86,8 @@
9386
return files;
9487
}
9588
96-
// for the things we can't do with media queries
97-
9889
beforeNavigate(() => {
99-
previous_files = $files;
90+
previous_files = workspace.files;
10091
});
10192
10293
afterNavigate(async () => {
@@ -105,7 +96,7 @@
10596
const will_delete = previous_files.some((file) => !(file.name in a));
10697
10798
if (data.exercise.path !== path || will_delete) paused = true;
108-
await reset($files);
99+
await reset(workspace.files);
109100
110101
path = data.exercise.path;
111102
paused = false;
@@ -137,40 +128,40 @@
137128
}
138129
139130
function select_file(name: string | null) {
140-
const file = name && $files.find((file) => file.name === name);
131+
const file = name && workspace.files.find((file) => file.name === name);
141132
142133
if (!file && name) {
143134
// trigger file creation input. first, create any intermediate directories
144-
const new_directories = create_directories(name, $files);
135+
const new_directories = create_directories(name, workspace.files);
145136
146137
if (new_directories.length > 0) {
147-
reset_files([...$files, ...new_directories]);
138+
workspace.reset_files([...workspace.files, ...new_directories]);
148139
}
149140
150141
// find the parent directory
151142
const parent = name.split('/').slice(0, -1).join('/');
152143
153-
creating.set({
144+
workspace.creating = {
154145
parent,
155146
type: 'file'
156-
});
147+
};
157148
158149
show_filetree = true;
159150
} else {
160151
show_filetree = false;
161-
selected_name.set(name);
152+
workspace.selected_name = name;
162153
}
163154
164155
show_editor = true;
165156
}
166157
167158
function navigate_to_file(name: string) {
168-
if (name === $selected_name) return;
159+
if (name === workspace.selected_name) return;
169160
170161
select_file(name);
171162
172163
if (mobile) {
173-
const q = new URLSearchParams({ file: $selected_name || '' });
164+
const q = new URLSearchParams({ file: workspace.selected_name || '' });
174165
history.pushState({}, '', `?${q}`);
175166
}
176167
}
@@ -191,21 +182,23 @@
191182
192183
let a = $derived(create_files(data.exercise.a));
193184
let b = $derived(create_files({ ...data.exercise.a, ...data.exercise.b }));
185+
186+
// for the things we can't do with media queries
194187
let mobile = $derived(w < 800);
195188
196189
$effect(() => {
197-
files.set(Object.values(a));
190+
workspace.files = Object.values(a);
198191
});
199192
200193
$effect(() => {
201194
solution.set(b);
202195
});
203196
204197
$effect(() => {
205-
selected_name.set(data.exercise.focus);
198+
workspace.selected_name = data.exercise.focus;
206199
});
207200
208-
let completed = $derived(is_completed($files, b));
201+
let completed = $derived(is_completed(workspace.files, b));
209202
</script>
210203

211204
<svelte:head>
@@ -248,7 +241,7 @@
248241
exercise={data.exercise}
249242
{completed}
250243
toggle={() => {
251-
reset_files(Object.values(completed ? a : b));
244+
workspace.reset_files(Object.values(completed ? a : b));
252245
}}
253246
/>
254247

@@ -277,7 +270,7 @@
277270
<section slot="a" class="navigator">
278271
{#if mobile}
279272
<button class="file" onclick={() => (show_filetree = !show_filetree)}>
280-
{$selected_file?.name.replace(
273+
{workspace.selected_name?.replace(
281274
data.exercise.scope.prefix,
282275
data.exercise.scope.name + '/'
283276
) ?? 'Files'}
@@ -294,7 +287,7 @@
294287

295288
<section slot="b" class="editor-container">
296289
<Editor exercise={data.exercise} warnings={adapter_state.warnings} />
297-
<ImageViewer selected={$selected_file} />
290+
<ImageViewer selected={workspace.selected_file} />
298291

299292
{#if mobile && show_filetree}
300293
<div class="mobile-filetree">
@@ -333,7 +326,7 @@
333326
const url = new URL(location.origin + location.pathname);
334327

335328
if (show_editor) {
336-
url.searchParams.set('file', $selected_name ?? '');
329+
url.searchParams.set('file', workspace.selected_name ?? '');
337330
}
338331

339332
history.pushState({}, '', url); // TODO use SvelteKit pushState

apps/svelte.dev/src/routes/tutorial/[...slug]/Editor.svelte

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import { svelteTheme } from '@sveltejs/repl/theme';
1414
import { basicSetup } from 'codemirror';
1515
import { onMount, tick } from 'svelte';
16-
import { files, selected_file, selected_name, update_file } from './state.svelte';
16+
import { workspace } from './state.svelte';
1717
import { autocomplete_for_svelte } from '@sveltejs/site-kit/codemirror';
1818
import type { Diagnostic } from '@codemirror/lint';
1919
import type { Exercise, Stub } from '$lib/tutorial';
@@ -48,8 +48,7 @@
4848
4949
let installed_vim = false;
5050
51-
/** @param {import('$lib/tutorial').Stub[]} $files */
52-
async function reset($files: Stub[]) {
51+
async function reset(files: Stub[]) {
5352
if (skip_reset) return;
5453
5554
let should_install_vim = localStorage.getItem('vim') === 'true';
@@ -66,7 +65,7 @@
6665
extensions.push(vim());
6766
}
6867
69-
for (const file of $files) {
68+
for (const file of files) {
7069
if (file.type !== 'file') continue;
7170
7271
let state = editor_states.get(file.name);
@@ -86,7 +85,7 @@
8685
editor_states.set(file.name, transaction.state);
8786
state = transaction.state;
8887
89-
if ($selected_name === file.name) {
88+
if (workspace.selected_name === file.name) {
9089
editor_view.setState(state);
9190
}
9291
}
@@ -101,9 +100,9 @@
101100
lang = [
102101
svelte(),
103102
...autocomplete_for_svelte(
104-
() => $selected_file!.name,
103+
() => workspace.selected_name!,
105104
() =>
106-
$files
105+
files
107106
.filter(
108107
(file) =>
109108
file.type === 'file' &&
@@ -127,11 +126,11 @@
127126
}
128127
}
129128
130-
function select_state($selected_name: string | null) {
129+
function select_state(selected_name: string | null) {
131130
if (skip_reset) return;
132131
133132
const state =
134-
($selected_name && editor_states.get($selected_name)) ||
133+
(selected_name && editor_states.get(selected_name)) ||
135134
EditorState.create({
136135
doc: '',
137136
extensions: [EditorState.readOnly.of(true)]
@@ -146,17 +145,17 @@
146145
async dispatch(transaction) {
147146
editor_view.update([transaction]);
148147
149-
if (transaction.docChanged && $selected_file) {
148+
if (transaction.docChanged && workspace.selected_file) {
150149
skip_reset = true;
151150
152-
// TODO do we even need to update `$files`? maintaining separate editor states is probably sufficient
153-
update_file({
154-
...$selected_file,
151+
// TODO do we even need to update `workspace.files`? maintaining separate editor states is probably sufficient
152+
workspace.update_file({
153+
...workspace.selected_file,
155154
contents: editor_view.state.doc.toString()
156155
});
157156
158157
// keep `editor_states` updated so that undo/redo history is preserved for files independently
159-
editor_states.set($selected_file.name, editor_view.state);
158+
editor_states.set(workspace.selected_file.name, editor_view.state);
160159
161160
await tick();
162161
skip_reset = false;
@@ -177,26 +176,26 @@
177176
skip_reset = false;
178177
179178
editor_states.clear();
180-
await reset($files);
179+
await reset(workspace.files);
181180
182181
if (editor_view) {
183182
// could be false if onMount returned early
184-
select_state($selected_name);
183+
select_state(workspace.selected_name);
185184
}
186185
});
187186
188187
$effect(() => {
189-
reset($files);
188+
reset(workspace.files);
190189
});
191190
192191
$effect(() => {
193-
select_state($selected_name);
192+
select_state(workspace.selected_name);
194193
});
195194
196195
$effect(() => {
197196
if (editor_view) {
198-
if ($selected_name) {
199-
const current_warnings = warnings[$selected_name] || [];
197+
if (workspace.selected_name) {
198+
const current_warnings = warnings[workspace.selected_name] || [];
200199
const diagnostics = current_warnings.map((warning) => {
201200
/** @type {import('@codemirror/lint').Diagnostic} */
202201
const diagnostic: Diagnostic = {
@@ -245,15 +244,15 @@
245244
}, 200);
246245
}}
247246
>
248-
{#if !browser && $selected_file}
247+
{#if !browser && workspace.selected_file}
249248
<div class="fake">
250249
<div class="fake-gutter">
251-
{#each $selected_file.contents.split('\n') as _, i}
250+
{#each workspace.selected_file.contents.split('\n') as _, i}
252251
<div class="fake-line">{i + 1}</div>
253252
{/each}
254253
</div>
255254
<div class="fake-content">
256-
{#each $selected_file.contents.split('\n') as line}
255+
{#each workspace.selected_file.contents.split('\n') as line}
257256
<pre>{line || ' '}</pre>
258257
{/each}
259258
</div>

apps/svelte.dev/src/routes/tutorial/[...slug]/Loading.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { load_webcontainer, reset } from './adapter.svelte';
3-
import { files } from './state.svelte';
3+
import { workspace } from './state.svelte';
44
55
interface Props {
66
initial: boolean;
@@ -69,7 +69,7 @@
6969
onclick={async () => {
7070
error = null;
7171
load_webcontainer(true);
72-
await reset($files);
72+
await reset(workspace.files);
7373
}}>clicking here</button
7474
>.
7575
</p>
Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,43 @@
1-
<script>
1+
<script lang="ts">
22
import * as context from './context.js';
33
import Item from './Item.svelte';
44
import file_icon from '$lib/icons/file.svg';
5-
import { selected_name, solution } from '../state.svelte';
5+
import { solution, workspace } from '../state.svelte';
6+
import type { FileStub, MenuItem } from '$lib/tutorial';
67
7-
/** @type {import('$lib/tutorial').FileStub} */
8-
export let file;
8+
interface Props {
9+
file: FileStub;
10+
depth: number;
11+
}
912
10-
/** @type {number} */
11-
export let depth;
13+
let { file, depth }: Props = $props();
1214
1315
const { rename, remove, select } = context.get();
1416
15-
let renaming = false;
17+
let renaming = $state(false);
1618
17-
$: can_remove = !$solution[file.name];
19+
let can_remove = $derived(!$solution[file.name]);
1820
19-
/** @type {import('$lib/tutorial').MenuItem[]} */
20-
$: actions = can_remove
21-
? [
22-
{
23-
icon: 'rename',
24-
label: 'Rename',
25-
fn: () => {
26-
renaming = true;
21+
let actions: MenuItem[] = $derived(
22+
can_remove
23+
? [
24+
{
25+
icon: 'rename',
26+
label: 'Rename',
27+
fn: () => {
28+
renaming = true;
29+
}
30+
},
31+
{
32+
icon: 'delete',
33+
label: 'Delete',
34+
fn: () => {
35+
remove(file);
36+
}
2737
}
28-
},
29-
{
30-
icon: 'delete',
31-
label: 'Delete',
32-
fn: () => {
33-
remove(file);
34-
}
35-
}
36-
]
37-
: [];
38+
]
39+
: []
40+
);
3841
</script>
3942

4043
<Item
@@ -43,16 +46,16 @@
4346
{renaming}
4447
basename={file.basename}
4548
icon={file_icon}
46-
selected={file.name === $selected_name}
49+
selected={file.name === workspace.selected_name}
4750
{actions}
48-
on:click={() => select(file.name)}
49-
on:edit={() => {
51+
onclick={() => select(file.name)}
52+
onedit={() => {
5053
renaming = true;
5154
}}
52-
on:rename={(e) => {
53-
rename(file, e.detail.basename);
55+
onrename={(basename) => {
56+
rename(file, basename);
5457
}}
55-
on:cancel={() => {
58+
oncancel={() => {
5659
renaming = false;
5760
}}
5861
/>

0 commit comments

Comments
 (0)