Skip to content

Commit 2b105ce

Browse files
committed
[feat] mobile version of tutorial
1 parent 940c684 commit 2b105ce

File tree

6 files changed

+113
-23
lines changed

6 files changed

+113
-23
lines changed

src/lib/components/SplitPane.svelte

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919
let dragging = false;
2020
let w = 0;
2121
let h = 0;
22+
let position = pos;
2223
23-
// constrain pos
24+
// constrain position
2425
$: if (container) {
2526
const size = type === 'horizontal' ? w : h;
2627
@@ -40,7 +41,7 @@
4041
? Math.max(min_px, Math.min(max_px, pos_px))
4142
: Math.min(max_px, Math.max(min_px, pos_px));
4243
43-
pos = pos.endsWith('%') ? `${(100 * pos_px) / size}%` : `${pos_px}px`;
44+
position = pos.endsWith('%') ? (size ? `${(100 * pos_px) / size}%` : '0%') : `${pos_px}px`;
4445
}
4546
4647
/**
@@ -55,7 +56,7 @@
5556
const pos_px = type === 'horizontal' ? x - left : y - top;
5657
const size = type === 'horizontal' ? w : h;
5758
58-
pos = pos.endsWith('%') ? `${(100 * pos_px) / size}%` : `${pos_px}px`;
59+
position = pos.endsWith('%') ? `${(100 * pos_px) / size}%` : `${pos_px}px`;
5960
6061
dispatch('change');
6162
}
@@ -132,7 +133,7 @@
132133
bind:this={container}
133134
bind:clientWidth={w}
134135
bind:clientHeight={h}
135-
style="--pos: {pos}"
136+
style="--pos: {position}"
136137
>
137138
<div class="pane">
138139
<slot name="a" />
@@ -142,12 +143,14 @@
142143
<slot name="b" />
143144
</div>
144145

145-
<div
146-
class="{type} divider"
147-
class:disabled
148-
use:drag={(e) => update(e.clientX, e.clientY)}
149-
use:touchDrag={(e) => update(e.touches[0].clientX, e.touches[0].clientY)}
150-
/>
146+
{#if pos !== '0%' && pos !== '100%'}
147+
<div
148+
class="{type} divider"
149+
class:disabled
150+
use:drag={(e) => update(e.clientX, e.clientY)}
151+
use:touchDrag={(e) => update(e.touches[0].clientX, e.touches[0].clientY)}
152+
/>
153+
{/if}
151154
</div>
152155

153156
{#if dragging}

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

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
import SplitPane from '$lib/components/SplitPane.svelte';
66
import Editor from './Editor.svelte';
77
import Folder from './Folder.svelte';
8-
import { dev } from '$app/environment';
8+
import { browser, dev } from '$app/environment';
99
import ImageViewer from './ImageViewer.svelte';
1010
import Sidebar from './Sidebar.svelte';
1111
import Chrome from './Chrome.svelte';
1212
import { Icon } from '@sveltejs/site-kit';
1313
import Loading from './Loading.svelte';
1414
import { PUBLIC_USE_FILESYSTEM } from '$env/static/public';
1515
import ContextMenu from './ContextMenu.svelte';
16+
import ScreenToggle from './ScreenToggle.svelte';
1617
1718
/** @type {import('./$types').PageData} */
1819
export let data;
@@ -42,6 +43,10 @@
4243
4344
let path = '/';
4445
46+
let width = browser ? window.innerWidth : 1000;
47+
let selected_view = 0;
48+
$: mobile = width < 768;
49+
4550
/** @type {Record<string, import('$lib/types').Stub>} */
4651
let b;
4752
$: {
@@ -303,17 +308,22 @@
303308
const hidden = new Set(['__client.js', 'node_modules']);
304309
</script>
305310
306-
<svelte:window on:message={handle_message} />
311+
<svelte:window on:message={handle_message} bind:innerWidth={width} />
307312
308313
<svelte:head>
309314
<title>{data.section.chapter.title} / {data.section.title} • Svelte Tutorial</title>
310315
</svelte:head>
311316
312317
<ContextMenu />
313318
314-
<div class="container">
315-
<SplitPane type="horizontal" min="360px" max="50%" pos="33%">
316-
<section class="content" slot="a">
319+
<div class="container" style="--toggle-height: {mobile ? '4.6rem' : '0px'}">
320+
<SplitPane
321+
type="horizontal"
322+
min={mobile ? '0px' : '360px'}
323+
max={mobile ? '100%' : '50%'}
324+
pos={mobile ? (selected_view === 0 ? '100%' : '0%') : '33%'}
325+
>
326+
<section slot="a" class="content">
317327
<Sidebar
318328
index={data.index}
319329
section={data.section}
@@ -323,8 +333,13 @@
323333
/>
324334
</section>
325335
326-
<section slot="b">
327-
<SplitPane type="vertical" min="100px" max="-100px" pos="50%">
336+
<section slot="b" class:hidden={mobile && selected_view === 0}>
337+
<SplitPane
338+
type="vertical"
339+
min={mobile ? '0px' : '100px'}
340+
max={mobile ? '100%' : '50%'}
341+
pos={mobile ? (selected_view === 1 ? '100%' : '0%') : '50%'}
342+
>
328343
<section slot="a">
329344
<SplitPane type="horizontal" min="80px" max="300px" pos="200px">
330345
<section class="navigator" slot="a">
@@ -333,6 +348,7 @@
333348
{...data.section.scope}
334349
files={current_stubs.filter((stub) => !hidden.has(stub.basename))}
335350
expanded
351+
read_only={mobile}
336352
/>
337353
</div>
338354
@@ -353,13 +369,18 @@
353369
</section>
354370
355371
<section class="editor-container" slot="b">
356-
<Editor stubs={current_stubs} selected={$selected} on:change={update_stub} />
372+
<Editor
373+
stubs={current_stubs}
374+
selected={$selected}
375+
read_only={mobile}
376+
on:change={update_stub}
377+
/>
357378
<ImageViewer selected={$selected} />
358379
</section>
359380
</SplitPane>
360381
</section>
361382
362-
<section class="preview" slot="b">
383+
<section slot="b" class="preview">
363384
<Chrome
364385
{path}
365386
{loading}
@@ -395,12 +416,15 @@
395416
</SplitPane>
396417
</section>
397418
</SplitPane>
419+
{#if mobile}
420+
<ScreenToggle labels={['Tutorial', 'Input', 'Output']} bind:selected={selected_view} />
421+
{/if}
398422
</div>
399423
400424
<style>
401425
.container {
402426
--border-color: hsl(206, 44%, 90%);
403-
height: 100%;
427+
height: calc(100% - var(--toggle-height));
404428
max-height: 100%;
405429
}
406430
@@ -485,4 +509,8 @@
485509
position: relative;
486510
background-color: var(--light-blue);
487511
}
512+
513+
.hidden {
514+
display: none;
515+
}
488516
</style>

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
export let stubs;
2323
/** @type {import('$lib/types').Stub | null} */
2424
export let selected = null;
25+
export let read_only = false;
2526
2627
const dispatch = createEventDispatcher();
2728
@@ -179,6 +180,10 @@
179180
instance.update_files(stubs);
180181
}
181182
183+
$: if (instance) {
184+
instance.editor.updateOptions({ readOnly: read_only });
185+
}
186+
182187
$: if (instance && stubs /* to retrigger on stubs change */) {
183188
const model = selected && models.get(selected.name);
184189
instance.editor.setModel(model ?? null);
@@ -219,4 +224,12 @@
219224
div :global(.monaco-editor .view-overlays .current-line) {
220225
border: none;
221226
}
227+
228+
/* reposition overlay message that appears when trying to edit in readonly mode */
229+
div :global(.monaco-editor-overlaymessage) {
230+
margin-top: 6rem;
231+
}
232+
div :global(.monaco-editor-overlaymessage .anchor.below) {
233+
display: none;
234+
}
222235
</style>

src/routes/tutorial/[slug]/File.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
/** @type {import('$lib/types').FileStub} */
66
export let file;
7+
export let read_only = false;
78
89
/** @type {import('$lib/types').FileTreeContext} */
910
const { select, selected, edit, remove } = getContext('filetree');
@@ -21,7 +22,7 @@
2122
2223
/** @param {MouseEvent} e */
2324
function open_menu(e) {
24-
if (restricted.has(file.basename)) return;
25+
if (restricted.has(file.basename) || read_only) return;
2526
open(e.clientX, e.clientY, [
2627
{
2728
name: 'Rename',

src/routes/tutorial/[slug]/Folder.svelte

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
/** @type {Array<import('$lib/types').Stub>} */
1919
export let files;
2020
21+
export let read_only = false;
22+
2123
/** @type {'idle' | 'add_file' | 'add_folder' | 'edit_folder'} */
2224
let state = 'idle';
2325
let new_name = '';
@@ -43,7 +45,7 @@
4345
4446
/** @param {MouseEvent} e */
4547
function open_menu(e) {
46-
if (depth === 0) return;
48+
if (depth === 0 || read_only) return;
4749
4850
open(e.clientX, e.clientY, [
4951
{
@@ -154,13 +156,14 @@
154156
prefix={directory.name + '/'}
155157
depth={depth + 1}
156158
files={children}
159+
{read_only}
157160
/>
158161
</li>
159162
{/each}
160163

161164
{#each child_files as file}
162165
<li>
163-
<File {file} />
166+
<File {file} {read_only} />
164167
</li>
165168
{/each}
166169
</ul>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<script>
2+
/** @type {string[]} */
3+
export let labels;
4+
export let selected = 0;
5+
</script>
6+
7+
<div class="toggle">
8+
{#each labels as label, index}
9+
<button class:selected={selected === index} on:click={() => (selected = index)}>
10+
{label}
11+
</button>
12+
{/each}
13+
</div>
14+
15+
<style>
16+
.toggle {
17+
position: fixed;
18+
bottom: 0;
19+
width: 100%;
20+
height: var(--toggle-height);
21+
display: flex;
22+
justify-content: center;
23+
align-items: center;
24+
border-top: 1px solid var(--second);
25+
background-color: white;
26+
}
27+
button {
28+
margin: 0 0.15em;
29+
width: 4em;
30+
height: 1em;
31+
padding: 0.3em 0.4em;
32+
border-radius: var(--border-r);
33+
line-height: 1em;
34+
box-sizing: content-box;
35+
color: #888;
36+
border: 1px solid var(--back-light);
37+
}
38+
.selected {
39+
background-color: var(--prime);
40+
color: white;
41+
}
42+
</style>

0 commit comments

Comments
 (0)