mirror of https://github.com/sveltejs/svelte
- move tutorial's ScreenToggle.svelte to src/components and makes it generic (it now accept a list of labels) - add a navigation util to export getFragment() - move mapbox_setup, svelteUrl, rollupUrl in a config - docs/index.svelte: removes an unused import, use getFragment, use onscroll in the second setTimeout - global.css: add a couple of vars and set width/height on the page Closes #2460pull/2466/head
parent
bb888f69d2
commit
39c172ef83
@ -0,0 +1,5 @@
|
|||||||
|
// REPL props
|
||||||
|
|
||||||
|
export const svelteUrl = `https://unpkg.com/svelte@beta`;
|
||||||
|
export const rollupUrl = `https://unpkg.com/rollup@1/dist/rollup.browser.js`;
|
||||||
|
export const mapbox_setup = `window.MAPBOX_ACCESS_TOKEN = process.env.MAPBOX_ACCESS_TOKEN;`;
|
@ -0,0 +1,143 @@
|
|||||||
|
<script>
|
||||||
|
import { afterUpdate } from 'svelte';
|
||||||
|
import Icon from '../../components/Icon.svelte';
|
||||||
|
|
||||||
|
export let sections = [];
|
||||||
|
export let active_section = null;
|
||||||
|
|
||||||
|
let ul;
|
||||||
|
|
||||||
|
afterUpdate(() => {
|
||||||
|
const active = ul.querySelector('.active');
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
const { top, bottom } = active.getBoundingClientRect();
|
||||||
|
|
||||||
|
const min = 200;
|
||||||
|
const max = window.innerHeight - 200;
|
||||||
|
|
||||||
|
if (top > max) {
|
||||||
|
ul.parentNode.scrollBy({
|
||||||
|
top: top - max,
|
||||||
|
left: 0,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
} else if (bottom < min) {
|
||||||
|
ul.parentNode.scrollBy({
|
||||||
|
top: bottom - min,
|
||||||
|
left: 0,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ul
|
||||||
|
bind:this={ul}
|
||||||
|
class="examples-toc"
|
||||||
|
on:mouseenter="{() => prevent_sidebar_scroll = true}"
|
||||||
|
on:mouseleave="{() => prevent_sidebar_scroll = false}"
|
||||||
|
>
|
||||||
|
{#each sections as section}
|
||||||
|
<li>
|
||||||
|
<span class="section-title">
|
||||||
|
{section.title}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{#each section.examples as example}
|
||||||
|
<a href="examples#{example.slug}">
|
||||||
|
<div
|
||||||
|
class="row"
|
||||||
|
class:active="{example.slug === active_section}"
|
||||||
|
>
|
||||||
|
<div class="info">
|
||||||
|
<div
|
||||||
|
class="thumbnail"
|
||||||
|
style="background-image: url(examples/thumbnails/{example.slug}.png)"
|
||||||
|
></div>
|
||||||
|
<div class="example-title">
|
||||||
|
{example.title}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#if example.slug === active_section}
|
||||||
|
<Icon name="arrow-right" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.examples-toc {
|
||||||
|
overflow-y: auto;
|
||||||
|
height: 100%;
|
||||||
|
border-right: 1px solid var(--second);
|
||||||
|
background-color: var(--second);
|
||||||
|
color: white;
|
||||||
|
padding: 2em 2em 0 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.examples-toc li {
|
||||||
|
display: block;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin: 0 0 4.8rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
position: relative;
|
||||||
|
opacity: 0.7;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
display: block;
|
||||||
|
padding: 0 0 .8rem 0;
|
||||||
|
font: 400 var(--h6) var(--font);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-title {
|
||||||
|
display: block;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
font-family: var(--font);
|
||||||
|
padding: 0 0 0.2em 0.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-title:hover {
|
||||||
|
color: var(--flash);
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
opacity: 1;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
position: relative;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail {
|
||||||
|
background: white 50% 50% no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
width: 5rem;
|
||||||
|
height: 5rem;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: 1px 1px 3px rgba(0,0,0,0.13);
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,101 +1,137 @@
|
|||||||
|
<!-- FIXME sometimes it adds a trailing slash when landing -->
|
||||||
<script context="module">
|
<script context="module">
|
||||||
export async function preload() {
|
export async function preload({params, query}) {
|
||||||
const groups = await this.fetch(`examples.json`).then(r => r.json());
|
const sections = await this.fetch(`examples.json`).then(r => r.json());
|
||||||
|
const title_by_slug = sections.reduce((acc, {examples}) => {
|
||||||
|
examples.forEach(({slug, title}) => {
|
||||||
|
acc[slug] = title;
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return acc;
|
||||||
groups
|
}, {});
|
||||||
};
|
|
||||||
|
return {sections, title_by_slug};
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export let groups;
|
import { onMount } from 'svelte';
|
||||||
</script>
|
import { goto } from '@sapper/app';
|
||||||
|
import Repl from '@sveltejs/svelte-repl';
|
||||||
<style>
|
|
||||||
.content {
|
import ScreenToggle from '../../components/ScreenToggle.svelte';
|
||||||
max-width: 120rem;
|
import {
|
||||||
padding: 0 var(--side-nav);
|
mapbox_setup, // needed for context API example
|
||||||
margin: 0 auto;
|
rollupUrl,
|
||||||
|
svelteUrl
|
||||||
|
} from '../../config';
|
||||||
|
import { process_example } from '../../utils/examples';
|
||||||
|
import { getFragment } from '../../utils/navigation';
|
||||||
|
import TableOfContents from './_TableOfContents.svelte';
|
||||||
|
|
||||||
|
export let sections;
|
||||||
|
export let title_by_slug;
|
||||||
|
|
||||||
|
let active_slug;
|
||||||
|
let width;
|
||||||
|
let offset = 1;
|
||||||
|
let repl;
|
||||||
|
|
||||||
|
$: title = title_by_slug[active_slug] || '';
|
||||||
|
$: first_slug = sections[0].examples[0].slug;
|
||||||
|
$: if (repl) {
|
||||||
|
fetch(`examples/${active_slug}.json`)
|
||||||
|
.then(async response => {
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
repl.set({
|
||||||
|
components: process_example(data.files)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$: mobile = width < 768; // note: same as per media query below
|
||||||
|
|
||||||
h1 { margin: 6rem 0 6rem -0.05em }
|
onMount(() => {
|
||||||
|
const onhashchange = () => {
|
||||||
|
active_slug = getFragment();
|
||||||
|
offset = 1;
|
||||||
|
};
|
||||||
|
window.addEventListener('hashchange', onhashchange, false);
|
||||||
|
|
||||||
h2 {
|
if (getFragment()) {
|
||||||
margin: 0 0 1em 0;
|
active_slug = getFragment();
|
||||||
font: 600 var(--h4) var(--font);
|
} else {
|
||||||
border-bottom: var(--border-w) solid #eee;
|
active_slug = first_slug;
|
||||||
text-transform: uppercase;
|
goto(`examples#${active_slug}`);
|
||||||
letter-spacing: .05em;
|
|
||||||
padding: 0 0 0.2em 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
section { margin: 0 0 4rem 0 }
|
return () => {
|
||||||
|
window.removeEventListener('hashchange', onhashchange, false);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
.example {
|
<svelte:head>
|
||||||
display: flex;
|
<title>{title} {title ? '•' : ''} Svelte Examples</title>
|
||||||
flex-wrap: wrap;
|
|
||||||
align-items: center;
|
<meta name="twitter:title" content="Svelte examples">
|
||||||
justify-content: center;
|
<meta name="twitter:description" content="Cybernetically enhanced web apps">
|
||||||
text-align: center;
|
<meta name="Description" content="Interactive example Svelte apps">
|
||||||
font: 300 var(--h5) var(--font);
|
</svelte:head>
|
||||||
}
|
|
||||||
|
<div class='examples-container' bind:clientWidth={width}>
|
||||||
|
<div class="viewport offset-{offset}">
|
||||||
|
<TableOfContents {sections} active_section={active_slug} />
|
||||||
|
<Repl
|
||||||
|
bind:this={repl}
|
||||||
|
{svelteUrl}
|
||||||
|
{rollupUrl}
|
||||||
|
orientation={mobile ? 'columns' : 'rows'}
|
||||||
|
fixed={mobile}
|
||||||
|
relaxed
|
||||||
|
injectedJS={mapbox_setup}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{#if mobile}
|
||||||
|
<ScreenToggle bind:offset labels={['index', 'input', 'output']}/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
.thumbnail {
|
<style>
|
||||||
|
.examples-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: white 50% 50% no-repeat;
|
height: calc(100vh - var(--nav-h));
|
||||||
background-size: contain;
|
overflow: hidden;
|
||||||
width: 5rem;
|
padding: 0 0 42px 0;
|
||||||
height: 5rem;
|
box-sizing: border-box;
|
||||||
margin: .8rem 33%;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: var(--border-r);
|
|
||||||
box-shadow: 1px 1px 2px rgba(0,0,0,0.13);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.e-grid {
|
.viewport {
|
||||||
display: grid;
|
display: grid;
|
||||||
/* grid-gap: 2.4rem; */
|
width: 300%;
|
||||||
grid-template-columns: repeat(2, 1fr);
|
height: 100%;
|
||||||
align-items: center;
|
grid-template-columns: 33.333% 66.666%;
|
||||||
|
transition: transform .3s;
|
||||||
|
grid-auto-rows: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 720px) {
|
.offset-1 { transform: translate(-33.333%, 0); }
|
||||||
.e-grid {
|
.offset-2 { transform: translate(-66.666%, 0); }
|
||||||
grid-template-columns: repeat(4, 1fr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1080px) {
|
@media (min-width: 768px) {
|
||||||
.e-grid {
|
.examples-container { padding: 0 }
|
||||||
grid-template-columns: repeat(6, 1fr);
|
|
||||||
|
.viewport {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: var(--sidebar-mid-w) auto;
|
||||||
|
grid-auto-rows: 100%;
|
||||||
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.offset-1, .offset-2 { transform: none; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<svelte:head>
|
|
||||||
<title>Examples • Svelte</title>
|
|
||||||
|
|
||||||
<meta name="twitter:title" content="Svelte examples">
|
|
||||||
<meta name="twitter:description" content="Cybernetically enhanced web apps">
|
|
||||||
<meta name="Description" content="Interactive example Svelte apps">
|
|
||||||
</svelte:head>
|
|
||||||
|
|
||||||
<div class="content">
|
|
||||||
<h1>Examples</h1>
|
|
||||||
|
|
||||||
{#each groups as group}
|
|
||||||
<section class="">
|
|
||||||
<h2>{group.title}</h2>
|
|
||||||
|
|
||||||
<div class="e-grid">
|
|
||||||
{#each group.examples as example}
|
|
||||||
<a class="example" href="repl?example={example.slug}">
|
|
||||||
<div class="thumbnail" style="background-image: url(examples/thumbnails/{example.slug}.png)"></div>
|
|
||||||
<p>{example.title}</p>
|
|
||||||
</a>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { goto } from '@sapper/app';
|
import { goto } from '@sapper/app';
|
||||||
import Icon from '../../../../components/Icon.svelte';
|
import Icon from '../../../components/Icon.svelte';
|
||||||
|
|
||||||
export let sections;
|
export let sections;
|
||||||
export let slug;
|
export let slug;
|
@ -0,0 +1 @@
|
|||||||
|
export const getFragment = () => window.location.hash.slice(1);
|
Loading…
Reference in new issue