Merge branch 'master' into feat/abstract-block-class

pull/2608/head
Rich Harris 5 years ago committed by GitHub
commit 98bd5a1916
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -54,7 +54,7 @@ npm run test -- -g transition
## svelte.dev
The source code for https://svelte.dev, including all the documentation, lives in the [site](site) directory. The site is built with [Sapper](https://sapper.svelte.technology). To develop locally:
The source code for https://svelte.dev, including all the documentation, lives in the [site](site) directory. The site is built with [Sapper](https://sapper.svelte.dev). To develop locally:
```bash
cd site

2
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.0.0-beta.25",
"version": "3.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

@ -92,5 +92,6 @@
],
"sourceMap": true,
"instrument": true
}
},
"dependencies": {}
}

@ -17,16 +17,20 @@ By default, the REPL will fetch the most recent version of Svelte from https://u
## REPL GitHub integration
In order for the REPL's GitHub integration to work properly when running locally, you will need to create a GitHub OAuth app. Set its authorization callback URL to `http://localhost:3000/auth/callback`, and in this project, create `site/.env` containing:
```
GITHUB_CLIENT_ID=[your app's client id]
GITHUB_CLIENT_SECRET=[your app's client secret]
BASEURL=http://localhost:3000
```
In order for the REPL's GitHub integration to work properly when running locally, you will need to:
- [create a GitHub OAuth app](https://github.com/settings/developers):
- set `Authorization callback URL` to `http://localhost:3000/auth/callback`;
- set `Application name` as you like, and `Homepage URL` as `http://localhost:3000/`;
- create the app and take note of `Client ID` and `Client Secret`
- in this repo, create `site/.env` containing:
```
GITHUB_CLIENT_ID=[your app's Client ID]
GITHUB_CLIENT_SECRET=[your app's Client Secret]
BASEURL=http://localhost:3000
```
## Translating the API docs
Anchors are automatically generated using headings in the documentation and by default (for the english language) they are latinised to make sure the URL is always conforming to RFC3986.
If we need to translate the API documentation to a language using unicode chars, we can setup this app to export the correct anchors by setting up `SLUG_PRESERVE_UNICODE` to `true` and `SLUG_LANG` to the ISO 639-1 two-letter language code of your choice in `config.js`.
If we need to translate the API documentation to a language using unicode chars, we can setup this app to export the correct anchors by setting up `SLUG_PRESERVE_UNICODE` to `true` in `config.js`.

@ -1,3 +1,2 @@
export const SLUG_PRESERVE_UNICODE = false;
export const SLUG_SEPARATOR = '_';
export const SLUG_LANG = 'en';

@ -92,6 +92,6 @@ We don't take this lightly: hopefully once you've experienced Svelte 3 you'll un
## Still to come
As grueling as this release has been, we're nowhere near finished. We have a ton of ideas for generating smarter, more compact code, and a long feature wish-list. [Sapper](https://sapper.svelte.technology), our Next.js-style app framework, is still in the middle of being updated to use Svelte 3. The [Svelte Native](https://svelte-native.technology/) community project, which allows you to write Android and iOS apps in Svelte, is making solid progress but deserves more complete support from core. We don't yet have the bounty of editor extensions, syntax highlighters, component kits, devtools and so on that other frameworks have, and we should fix that. We *really* want to add first-class TypeScript support.
As grueling as this release has been, we're nowhere near finished. We have a ton of ideas for generating smarter, more compact code, and a long feature wish-list. [Sapper](https://sapper.svelte.dev), our Next.js-style app framework, is still in the middle of being updated to use Svelte 3. The [Svelte Native](https://svelte-native.technology/) community project, which allows you to write Android and iOS apps in Svelte, is making solid progress but deserves more complete support from core. We don't yet have the bounty of editor extensions, syntax highlighters, component kits, devtools and so on that other frameworks have, and we should fix that. We *really* want to add first-class TypeScript support.
But in the meantime we think Svelte 3 is the best way to build web apps yet. Take an hour to go through the [tutorial](tutorial) and we hope to convince you of the same. Either way, we'd love to see you in our [Discord chatroom](https://discord.gg/yy75DKs) and on [GitHub](https://github.com/sveltejs/svelte) — everyone is welcome, especially you.

@ -2,7 +2,7 @@
title: Before we begin
---
> Temporary note: This document is a work-in-progress. Please forgive any missing or misleading parts, and don't be shy about asking for help in the [Discord chatroom](https://discord.gg/yy75DKs). The [tutorial](tutorial) is more complete; start there.
> Temporary note: This document is a work-in-progress. Please forgive any missing or misleading parts, and don't be shy about asking for help in the [Discord chatroom](https://discord.gg/yy75DKs). The [tutorial](tutorial) is more complete; start there.
This page contains detailed API reference documentation. It's intended to be a resource for people who already have some familiarity with Svelte.

@ -56,6 +56,8 @@ To change component state and trigger a re-render, just assign to a locally decl
Update expressions (`count += 1`) and property assignments (`obj.x = y`) have the same effect.
Because Svelte's reactivity is based on assignments, using array methods like `.push()` and `.splice()` won't automatically trigger updates. Options for getting around this can be found in the [tutorial](tutorial/updating-arrays-and-objects).
```html
<script>
let count = 0;

@ -366,7 +366,13 @@ Components can emit events using [createEventDispatcher](docs#createEventDispatc
<SomeComponent on:whatever={handler}/>
```
---
As with DOM events, if the `on:` directive is used without a value, the component will *forward* the event, meaning that a consumer of the component can listen for it.
```html
<SomeComponent on:whatever/>
```
### Element bindings
@ -749,6 +755,8 @@ The `in:` and `out:` directives are not bidirectional. An in transition will con
{/if}
```
> By default intro transitions will not play on first render. You can modify this behaviour by setting `intro: true` when you [create a component](docs#Client-side_component_API).
#### Transition parameters
---
@ -983,7 +991,7 @@ Named slots can also expose values. The `let:` directive goes on the element wit
{/each}
</ul>
</slot name="footer"></slot>
<slot name="footer"></slot>
```

@ -176,8 +176,39 @@ Retrieves the context that belongs to the closest parent component with the spec
#### `createEventDispatcher`
TODO
```js
dispatch: ((name: string, detail?: any) => void) = createEventDispatcher();
```
---
Creates an event dispatcher that can be used to dispatch [component events](docs#Component_events). Event dispatchers are functions that can take two arguments: `name` and `detail`.
Component events created with `createEventDispatcher` create a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture) and are not cancellable with `event.preventDefault()`. The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) property and can contain any type of data.
```html
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
</script>
<button on:click="{() => dispatch('notify', 'detail value')}">Fire Event</button>
```
---
Events dispatched from child components can be listened to in their parent. Any data provided when the event was dispatched is available on the `detail` property of the event object.
```html
<script>
function callbackFunction(event) {
console.log(`Notify fired! Detail: ${event.detail}`)
}
</script>
<Child on:notify="{callbackFunction}"/>
```
### `svelte/store`
@ -475,21 +506,81 @@ TODO
* fade, fly, slide, scale, draw
* crossfade...
### `svelte/animation`
### `svelte/animate`
TODO
The `svelte/animate` module exports one function for use with svelte [animations](docs#Animations).
#### `flip`
```sv
animate:flip={params}
```
The `flip` function calculates the start and end position of an element and animates between them, translating the `x` and `y` values. `flip` stands for [First, Last, Invert, Play](https://aerotwist.com/blog/flip-your-animations/).
`flip` accepts the following parameters:
* `delay` (`number`, default 0) — milliseconds before starting
* `duration` (`number` | `function`, default `d => Math.sqrt(d) * 120`) — see below
* `easing` (`function`, default [`cubicOut`](docs#cubicOut)) — an [easing function](docs#svelte_easing)
`duration` can be be provided as either:
- a `number`, in milliseconds.
- a function, `distance: number => duration: number`, receiving the distance the element will travel in pixels and returning the duration in milliseconds. This allows you to assign a duration that is relative to the distance travelled by each element.
---
You can see a full example on the [animations tutorial](tutorial/animate)
```html
<script>
import { flip } from 'svelte/animate';
import { quintOut } from 'svelte/easing';
let list = [1, 2, 3];
</script>
{#each list as n (n)}
<div animate:flip="{{delay: 250, duration: 250, easing: quintOut}}">
{n}
</div>
{/each}
```
* TODO this doesn't even exist yet
TODO
### `svelte/easing`
* TODO could have nice little interactive widgets showing the different functions, maybe
### `svelte/register`
TODO
To render Svelte components in Node.js without bundling, use `require('svelte/register')`. After that, you can use `require` to include any `.svelte` file.
```js
require('svelte/register');
const App = require('./App.svelte').default;
...
const { html, css, head } = App.render({ answer: 42 });
```
> The `.default` is necessary because we're converting from native JavaScript modules to the CommonJS modules recognised by Node. Note that if your component imports JavaScript modules, they will fail to load in Node and you will need to use a bundler instead.
To set compile options, or to use a custom file extension, call the `register` hook as a function:
```js
require('svelte/register')({
extensions: ['.customextension'], // defaults to ['.html', '.svelte']
preserveComments: true
});
```
### Client-side component API
@ -500,8 +591,6 @@ TODO
const component = new Component(options)
```
---
A client-side component — that is, a component compiled with `generate: 'dom'` (or the `generate` option left unspecified) is a JavaScript class.
```js

@ -153,6 +153,30 @@ compiled: {
-->
### `svelte.parse`
```js
ast: object = svelte.parse(
source: string,
options?: {
filename?: string,
customElement?: boolean
}
)
```
---
The `parse` function parses a component, returning only its abstract syntax tree. Unlike compiling with the `generate: false` option, this will not perform any validation or other analysis of the component beyond parsing it.
```js
const svelte = require('svelte/compiler');
const ast = svelte.parse(source, { filename: 'App.svelte' });
```
### `svelte.preprocess`
```js

@ -29,4 +29,4 @@ Each tutorial chapter will have a 'Show me' button that you can click if you get
## Understanding components
In Svelte, an application is composed from one or more *components*. A component is a reusable self-contained block of code that encapsulates HTML, CSS and JavaScript that belong together, written into a `.svelte` file. The 'hello world' example on the right is a simple component.
In Svelte, an application is composed from one or more *components*. A component is a reusable self-contained block of code that encapsulates HTML, CSS and JavaScript that belong together, written into a `.svelte` file. The 'hello world' example in the code editor is a simple component.

@ -12,4 +12,4 @@ In Svelte, you do this with the special `{@html ...}` tag:
<p>{@html string}</p>
```
> Svelte doesn't perform any sanitization of the data before it gets inserted into the DOM. In other words, it's critical that you manually escape HTML that comes from sources you don't trust, otherwise you risk exposing your users to XSS attacks.
> Svelte doesn't perform any sanitization of the expression inside `{@html ...}` before it gets inserted into the DOM. In other words, if you use this feature it's critical that you manually escape HTML that comes from sources you don't trust, otherwise you risk exposing your users to XSS attacks.

@ -39,6 +39,8 @@ It starts to get a bit boilerplatey though, especially if your component subscri
<h1>The count is {$count}</h1>
```
> Auto-subscription only works with store variables that are declared (or imported) at the top-level scope of a component.
You're not limited to using `$count` inside the markup, either — you can use it anywhere in the `<script>` as well, such as in event handlers or reactive declarations.
> Any name beginning with `$` is assumed to refer to a store value. It's effectively a reserved character — Svelte will prevent you from declaring your own variables with a `$` prefix.

@ -6,6 +6,6 @@ You've now finished the Svelte tutorial and are ready to start building apps. Yo
To get set up in your local development environment, check out [the quickstart guide](blog/the-easiest-way-to-get-started).
If you're looking for a more expansive framework that includes routing, server-side rendering and everything else, take a look at [Sapper](https://sapper.svelte.technology).
If you're looking for a more expansive framework that includes routing, server-side rendering and everything else, take a look at [Sapper](https://sapper.svelte.dev).
Most importantly: since you're now a member of the Svelte community, you should [join our friendly Discord chatroom](https://discord.gg/yy75DKs). That's where you'll find fellow Svelte users, and it's where we plan the future of the framework.

1137
site/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -4,8 +4,7 @@
"description": "Docs and examples for Svelte",
"scripts": {
"dev": "sapper dev",
"sapper": "sapper build --legacy && npm run update_shimport",
"update_shimport": "cp node_modules/shimport/index.js __sapper__/build/client/shimport@0.0.14.js",
"sapper": "sapper build --legacy",
"update": "node scripts/update_template.js && node scripts/get-contributors.js",
"start": "node __sapper__/build",
"cy:run": "cypress run",
@ -20,7 +19,6 @@
"do-not-zip": "^1.0.0",
"express-session": "^1.15.6",
"golden-fleece": "^1.0.9",
"limax": "^1.7.0",
"marked": "^0.6.1",
"node-fetch": "^2.3.0",
"passport": "^0.4.0",
@ -38,6 +36,8 @@
"@babel/plugin-transform-runtime": "^7.2.0",
"@babel/preset-env": "^7.3.1",
"@babel/runtime": "^7.3.1",
"@sindresorhus/slugify": "^0.9.1",
"@sveltejs/site-kit": "^1.0.3",
"@sveltejs/svelte-repl": "0.0.10",
"chokidar": "^2.1.2",
"degit": "^2.1.3",
@ -55,9 +55,8 @@
"rollup-plugin-replace": "^2.1.0",
"rollup-plugin-svelte": "^5.0.3",
"rollup-plugin-terser": "^4.0.4",
"sapper": "^0.26.0-alpha.12",
"shimport": "0.0.16",
"svelte": "^3.0.0-beta.28"
"sapper": "^0.26.0",
"svelte": "^3.1.0"
},
"engines": {
"node": ">=10.0.0"

@ -1,3 +1,4 @@
import '@sveltejs/site-kit/base.css';
import * as sapper from '@sapper/app';
sapper.start({

@ -1,39 +0,0 @@
<!--
-----------------------------------------------
svg icon
- https://github.com/jacobmischka/svelte-feather-icon
- https://feathericons.com/
-----------------------------------------------
-->
<script>
export let clas = '';
export let name;
export let size = 20;
</script>
<!-- style="--color: {color ? color : 'currentColor'}" -->
<svg class="{'icon ' + clas}" width={size} height={size}>
<use xlink:href='#{name}' />
</svg>
<style>
.icon {
position: relative;
/* width: 1.2em;
height: 1.2em;
top: -0.123em; */
overflow: hidden;
vertical-align: middle;
-o-object-fit: contain;
object-fit: contain;
-webkit-transform-origin: center center;
transform-origin: center center;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
fill: none;
}
</style>

Before

Width:  |  Height:  |  Size: 828 B

@ -1,115 +0,0 @@
<!--
-----------------------------------------------
inline-svg sprite
- common used svg-stuff (feather-icons)
- advantage of css-styling
- https://github.com/jacobmischka/svelte-feather-icon
- https://feathericons.com/
- if requred we can split out app-controls to REPL only
-----------------------------------------------
-->
<svg style='display:none'>
<symbol id='arrow-left' class='icon' viewBox='0 0 24 24'>
<line x1='19' y1='12' x2='5' y2='12' />
<polyline points='12 19 5 12 12 5' />
</symbol>
<symbol id='arrow-right' class='icon' viewBox='0 0 24 24'>
<line x1='5' y1='12' x2='19' y2='12' />
<polyline points='12 5 19 12 12 19' />
</symbol>
<symbol id='arrow-up' class='icon' viewBox='0 0 24 24'>
<line x1='12' y1='19' x2='12' y2='5' />
<polyline points='5 12 12 5 19 12' />
</symbol>
<symbol id='arrow-down' class='icon' viewBox='0 0 24 24'>
<line x1='12' y1='5' x2='12' y2='19' />
<polyline points='19 12 12 19 5 12' />
</symbol>
<symbol id='check' class='icon' viewBox='0 0 24 24'>
<polyline points='20 6 9 17 4 12' />
</symbol>
<symbol id='close' class='icon' viewBox='0 0 24 24'>
<line x1='18' y1='6' x2='6' y2='18' />
<line x1='6' y1='6' x2='18' y2='18' />
</symbol>
<symbol id='download' class='icon' viewBox='0 0 24 24'>
<path d='M21 15V19A2 2 0 0 1 19 21H5A2 2 0 0 1 3 19V15' />
<polyline points='7 10 12 15 17 10' />
<line x1='12' y1='15' x2='12' y2='3' />
</symbol>
<symbol id='edit' class='icon' viewBox='0 0 24 24'>
<path d='M20 14.66V20a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5.34' />
<polygon points='18 2 22 6 12 16 8 16 8 12 18 2' />
</symbol>
<symbol id='github' class='icon' viewBox='0 0 24 24'>
<path d='M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22' />
</symbol>
<symbol id='git-branch' class='icon' viewBox='0 0 24 24'>
<line x1='6' y1='3' x2='6' y2='15' />
<circle cx='18' cy='6' r='3' />
<circle cx='6' cy='18' r='3' />
<path d='M18 9a9 9 0 0 1-9 9' />
</symbol>
<symbol id='log-in' class='icon' viewBox='0 0 24 24'>
<path d='M15 3H19A2 2 0 0 1 21 5V19A2 2 0 0 1 19 21H15' />
<polyline points='10 17 15 12 10 7' />
<line x1='15' y1='12' x2='3' y2='12' />
</symbol>
<symbol id='maximize' class='icon' viewBox='0 0 24 24'>
<path d='M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3' />
</symbol>
<symbol id='maximize-2' class='icon' viewBox='0 0 24 24'>
<polyline points='15 3 21 3 21 9' />
<polyline points='9 21 3 21 3 15' />
<line x1='21' y1='3' x2='14' y2='10' />
<line x1='3' y1='21' x2='10' y2='14' />
</symbol>
<symbol id='menu' class='icon' viewBox='0 0 24 24'>
<line x1='3' y1='12' x2='21' y2='12' />
<line x1='3' y1='6' x2='21' y2='6' />
<line x1='3' y1='18' x2='21' y2='18' />
</symbol>
<symbol id='message-square' class='icon' viewBox='0 0 24 24'>
<path d='M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z' />
</symbol>
<symbol id='minus' class='icon' viewBox='0 0 24 24'>
<line x1='5' y1='12' x2='19' y2='12' />
</symbol>
<symbol id='plus' class='icon' viewBox='0 0 24 24'>
<line x1='12' y1='5' x2='12' y2='19' />
<line x1='5' y1='12' x2='19' y2='12' />
</symbol>
<symbol id='save' class='icon' viewBox='0 0 24 24'>
<path d='M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z' />
<polyline points='17 21 17 13 7 13 7 21' />
<polyline points='7 3 7 8 15 8' />
</symbol>
<symbol id="link" class="icon" viewBox="0 0 24 24">
<path d="M9,7L6,7A2 2 0 0 0 6,17L9,17"/>
<path d="M15,7L18,7A2 2 0 0 1 18,17L15,17"/>
<path d="M7,12L17,12"/>
</symbol>
<symbol id="chevron" class="icon" viewBox="0 0 24 24">
<path d="M2,7 L12,17 L20,7"/>
</symbol>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

@ -1,277 +0,0 @@
<script>
import { onMount } from 'svelte';
import Icon from './Icon.svelte';
import { page } from '@sapper/app';
export let segment;
let open = false;
let visible = true;
// hide nav whenever we navigate
page.subscribe(() => {
open = false;
});
// TODO remove this post-https://github.com/sveltejs/svelte/issues/1914
let ul;
onMount(() => {
function handler(event) {
if (!open) {
event.preventDefault();
event.stopPropagation();
open = true;
}
}
ul.addEventListener('touchstart', handler, {
capture: true
});
return () => {
ul.removeEventListener('touchstart', handler, {
capture: true
});
};
});
// Prevents navbar to show/hide when clicking in docs sidebar
let hash_changed = false;
function handle_hashchange() {
hash_changed = true;
}
let last_scroll = 0;
function handle_scroll() {
const scroll = window.pageYOffset;
if (!hash_changed) {
visible = (scroll < 50 || scroll < last_scroll);
}
last_scroll = scroll;
hash_changed = false;
}
</script>
<style>
header {
position: fixed;
display: flex;
align-items: center;
justify-content: space-between;
width: 100vw;
height: var(--nav-h);
padding: 0 var(--side-nav);
margin: 0 auto;
background-color: white;
box-shadow: 0 -0.4rem 0.9rem 0.2rem rgba(0,0,0,.5);
font-family: var(--font);
z-index: 100;
user-select: none;
transform: translate(0,calc(-100% - 1rem));
transition: transform 0.2s;
}
header.visible {
transform: none;
}
nav {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: var(--nav-h);
padding: 0 var(--side-nav) 0 var(--side-nav);
display: flex;
align-items: center;
justify-content: space-between;
background-color: transparent;
transform: none;
transition: none;
box-shadow: none;
}
.primary {
list-style: none;
font-family: var(--font);
margin: 0;
line-height: 1;
}
li {
display: block;
display: none;
}
li.active {
display: block;
}
ul {
position: relative;
padding: 0 3rem 0 0;
background: url(/icons/chevron.svg) calc(100% - 1em) 0.05em no-repeat;
background-size: 1em 1em;
}
ul::after {
/* prevent clicks from registering if nav is closed */
position: absolute;
content: '';
width: 100%;
height: 100%;
left: 0;
top: 0;
}
ul.open {
padding: 0 0 1em 0;
background: white;
border-left: 1px solid #eee;
border-right: 1px solid #eee;
border-bottom: 1px solid #eee;
border-radius: 0 0 var(--border-r) var(--border-r);
align-self: start;
}
ul.open li {
display: block;
text-align: right
}
ul.open::after {
display: none;
}
ul li a {
font-size: var(--h5);
padding: 0 .8rem;
}
ul.open li a {
padding: 1.5rem 3.7rem 1.5rem 4rem;
display: block;
}
ul.open li:first-child a {
padding-top: 2.3rem;
}
.primary :global(svg) {
width: 2rem;
height: 2rem;
}
.home {
position: relative;
top: -.1rem;
width: 18rem;
height: 4.2rem;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
background: url(/svelte-logo-horizontal.svg) 0 50% no-repeat;
background-size: auto 100%;
/* z-index: 11; */
}
.active {
color: var(--prime)
}
.modal-background {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
background-color: rgba(255, 255, 255, 0.9);
}
a {
color: inherit;
border-bottom: none;
transition: none;
}
li:not(.active) a:hover {
color: var(--flash);
}
@media (min-width: 840px) {
ul {
padding: 0;
background: none;
}
ul.open {
padding: 0;
background: white;
border: none;
align-self: initial;
}
ul.open li {
display: inline;
text-align: left;
}
ul.open li a {
font-size: var(--h5);
padding: 0 .8rem;
display: inline;
}
ul::after {
display: none;
}
li {
display: inline !important;
}
.hide-if-desktop {
display: none !important;
}
}
</style>
<svelte:window on:hashchange={handle_hashchange} on:scroll={handle_scroll} />
<header class:visible="{visible || open}">
<nav>
<a rel="prefetch" href='.' class="home" title='Homepage'></a>
{#if open}
<div class="modal-background hide-if-desktop" on:click="{() => open = false}"></div>
{/if}
<ul
bind:this={ul}
class="primary"
class:open
on:mouseenter="{() => open = true}"
on:mouseleave="{() => open = false}"
>
<li class="hide-if-desktop" class:active="{!segment}"><a rel="prefetch" href=".">Home</a></li>
<li class:active="{segment === 'tutorial'}"><a rel="prefetch" href="tutorial">Tutorial</a></li>
<li class:active="{segment === 'docs'}"><a rel="prefetch" href="docs">API Docs</a></li>
<li class:active="{segment === 'examples'}"><a rel="prefetch" href="examples">Examples</a></li>
<li class:active="{segment === 'repl'}"><a rel="prefetch" href="repl">REPL</a></li>
<li class:active="{segment === 'blog'}"><a rel="prefetch" href="blog">Blog</a></li>
<li><a href="https://sapper.svelte.technology">Sapper</a></li>
<li>
<a href="https://discord.gg/yy75DKs" title="Discord Chat">
<Icon name="message-square" />
</a>
</li>
<li>
<a href="https://github.com/sveltejs/svelte" title="Github Repo">
<Icon name="github" />
</a>
</li>
</ul>
</nav>
</header>

@ -1,28 +0,0 @@
<!--
-----------------------------------------------
svg svelte-logo 1.0
- style doesn't like var(--xxx)???
-----------------------------------------------
-->
<script>
export let outer = '';
export let inner = '';
export let size;
</script>
<svg class='logo' viewBox='0 0 103 124' width={size} height={size}>
<path style='{outer === "none" ? "fill:none; stroke:none;" : outer || "fill:var(--prime)"}' d='M96.33,20.61C85.38,4.93,63.74.28,48.09,10.25L20.61,27.77A31.46,31.46,0,0,0,6.37,48.88,33.22,33.22,0,0,0,9.64,70.2,31.52,31.52,0,0,0,4.93,82a33.61,33.61,0,0,0,5.73,25.41c11,15.68,32.6,20.33,48.25,10.36l27.48-17.52a31.48,31.48,0,0,0,14.24-21.11A33.22,33.22,0,0,0,97.36,57.8,31.52,31.52,0,0,0,102.07,46a33.57,33.57,0,0,0-5.74-25.41' />
<path style='{(inner === "none") ? "fill:none; stroke:none;" : inner || "fill:white"}' d='M45.41,108.86A21.81,21.81,0,0,1,22,100.18,20.2,20.2,0,0,1,18.53,84.9a19,19,0,0,1,.65-2.57l.52-1.58,1.41,1a35.32,35.32,0,0,0,10.75,5.37l1,.31-.1,1a6.2,6.2,0,0,0,1.11,4.08A6.57,6.57,0,0,0,41,95.19a6,6,0,0,0,1.68-.74L70.11,76.94a5.76,5.76,0,0,0,2.59-3.83,6.09,6.09,0,0,0-1-4.6,6.58,6.58,0,0,0-7.06-2.62,6.21,6.21,0,0,0-1.69.74L52.43,73.31a19.88,19.88,0,0,1-5.58,2.45,21.82,21.82,0,0,1-23.43-8.68A20.2,20.2,0,0,1,20,51.8a19,19,0,0,1,8.56-12.7L56,21.59a19.88,19.88,0,0,1,5.58-2.45A21.81,21.81,0,0,1,85,27.82,20.2,20.2,0,0,1,88.47,43.1a19,19,0,0,1-.65,2.57l-.52,1.58-1.41-1a35.32,35.32,0,0,0-10.75-5.37l-1-.31.1-1a6.2,6.2,0,0,0-1.11-4.08,6.57,6.57,0,0,0-7.06-2.62,6,6,0,0,0-1.68.74L36.89,51.06a5.71,5.71,0,0,0-2.58,3.83,6,6,0,0,0,1,4.6,6.58,6.58,0,0,0,7.06,2.62,6.21,6.21,0,0,0,1.69-.74l10.48-6.68a19.88,19.88,0,0,1,5.58-2.45,21.82,21.82,0,0,1,23.43,8.68A20.2,20.2,0,0,1,87,76.2a19,19,0,0,1-8.56,12.7L51,106.41a19.88,19.88,0,0,1-5.58,2.45' />
</svg>
<style>
.logo {
position: relative;
vertical-align: middle;
stroke-miterlimit: 10;
stroke-width: 3.5;
stroke-linecap: round;
stroke-linejoin: round;
}
</style>

@ -1,68 +0,0 @@
<script>
export let style;
let show = false;
$: if (typeof document !== 'undefined') {
if (show) document.body.classList.add('css-debug')
else document.body.classList.remove('css-debug')
}
</script>
<!--
-----------------------------------------------
simple css-debug
-----------------------------------------------
-->
<label {style}>
<input type="checkbox" bind:checked={show}> grid
</label>
{#if show}
<div class='guide horizontal' style='top: calc(var(--nav-h) + var(--top-offset))' />
<div class='guide vertical' style='left: var(--side-page)' />
<div class='guide vertical' style='right: var(--side-page)' />
<div class='guide vertical' style='left: var(--side-nav)' />
<div class='guide vertical' style='right: var(--side-nav)' />
{/if}
<style>
label {
position: fixed;
padding: 0.3rem 1rem;
font-size: 1.2rem;
cursor: pointer;
user-select: none;
opacity: 0.5;
font: 300 1rem/1.7 var(--font-ui);
z-index: 30;
}
label:hover {
opacity: 1
}
input {
display: none
}
.guide {
position: fixed;
opacity: .5;
z-index: 30
}
.horizontal {
width: 100%;
height: 0
}
.vertical {
width: 0;
height: 100vh
}
:global(.css-debug *) {
outline: 1px solid rgba(73, 177, 238, 0.25);
}
</style>

@ -1,28 +0,0 @@
<!--
-----------------------------------------------
svg svelte-isometry 1.0
- first simple try to simplify iso-grafics
-----------------------------------------------
-->
<script>
export let style = '';
export let size = '';
</script>
<svg class='svelte-iso' viewBox='0 0 128 128' width={size} height={size}>
<polygon {style} points="107.94 92 107.94 36 64.01 8 20.06 35.99 20.06 92.01 64 120 107.94 92" />
<polyline {style} points="107.94 36 64.01 64 64 120" />
<line {style} x1="64.01" y1="64" x2="20.06" y2="35.99" />
</svg>
<style>
.svelte-iso {
position: relative;
vertical-align: middle;
stroke-miterlimit: 10;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
</style>

@ -1,81 +0,0 @@
<!--
NOTE
from time to time <input type="color"> is crashing on chrome!
no idea why?
even with all extensions off
-->
{#if color}
<input ref:prop class="color" on:input="change(this)" type="color" name={color} /> {/if}
{#if text}
<input ref:prop on:input="change(this)" type="text" name={text} />
{/if}
<style>
input,
input:active,
input:focus {
border: none;
outline: none;
cursor: pointer;
}
input[type=text] {
border: .1rem solid var(--text);
padding: .8rem 1.4rem;
font: 300 var(--code-fs)/1.7 var(--font-mono);
color: var(--second);
text-indent: 0;
transition: all .2s var(--out-back);
}
input[type=text]:focus {
border-color: var(--flash);
color: var(--flash);
text-indent: .8rem;
}
.color {
position: relative;
top: 0;
width: 100%;
height: 100%;
}
/* input-color-reset */
::-webkit-color-swatch {
border: none
}
::-webkit-color-swatch-wrapper {
padding: 0
}
::-moz-color-swatch,
::-moz-focus-inner {
border: none
}
::-moz-focus-inner {
padding: 0
}
</style>
<script>
import CustomProps from '../utils/css-custom-properties.js';
export default {
oncreate() {
this.cssprop = new CustomProps();
let prop = this.refs.prop;
prop.value = this.cssprop.get(prop.name);
},
methods: {
change(prop) {
return this.cssprop.set(prop.name, prop.value)
}
}
};
</script>

@ -1,49 +0,0 @@
<button class='toast' on:click='reload()'>
Site has been updated — tap to reload
</button>
<style>
.toast {
position: fixed;
left: 0;
bottom: 0;
margin: 0;
border-radius: 0;
width: 100%;
background-color: var(--prime);
cursor: pointer;
color: white;
padding: 3.2rem 4rem;
text-align: left;
font: 300 var(--h6) var(--font-ui);
z-index: 99;
animation: slide-up 0.4s ease-out;
}
@keyframes slide-up {
0% {
transform: translate(0, 100%);
}
100% {
transform: translate(0, 0);
}
}
</style>
<script>
export default {
methods: {
reload() {
window.location.reload();
}
},
setup(Toast) {
Toast.show = () => {
const target = document.createDocumentFragment();
new Toast({ target });
document.body.appendChild(target);
Toast.show = () => {};
};
}
};
</script>

@ -0,0 +1,52 @@
<script>
import { Section } from '@sveltejs/site-kit';
import IntersectionObserver from '../../components/IntersectionObserver.svelte';
import ReplWidget from '../../components/Repl/ReplWidget.svelte';
export let id;
</script>
<style>
.example {
width: 100%;
}
.example :global(a) {
color: inherit;
}
.example > :global(p) {
margin: 4.4rem 2.4rem 2.4rem 0;
}
.repl-container {
width: 100%;
height: 420px;
border-radius: var(--border-r);
overflow: hidden;
}
@media (min-width: 920px) {
.example {
display: grid;
grid-template-columns: 1fr 3fr;
grid-gap: 0.5em;
align-items: start;
}
}
</style>
<Section>
<div class="example">
<slot></slot>
<div class="repl-container">
<IntersectionObserver once let:intersecting top={400}>
{#if intersecting}
<!-- <Lazy this={loadReplWidget} example={id}/> -->
<ReplWidget example={id}/>
{/if}
</IntersectionObserver>
</div>
</div>
</Section>

@ -1,19 +1,37 @@
<script>
import { page, preloading } from '@sapper/app';
import InlineSvg from '../components/InlineSvg.svelte';
import { stores } from '@sapper/app';
import { Icon, Icons, Nav, NavItem } from '@sveltejs/site-kit';
import PreloadingIndicator from '../components/PreloadingIndicator.svelte';
import Nav from '../components/TopNav.svelte';
const { page, preloading } = stores();
export let segment;
</script>
<Icons/>
{#if $preloading}
<PreloadingIndicator/>
{/if}
<InlineSvg />
{#if $page.path !== '/repl/embed'}
<Nav {segment}/>
<Nav {segment} {page} logo="svelte-logo-horizontal.svg">
<NavItem segment="tutorial">Tutorial</NavItem>
<NavItem segment="docs">API</NavItem>
<NavItem segment="examples">Examples</NavItem>
<NavItem segment="repl">REPL</NavItem>
<NavItem segment="blog">Blog</NavItem>
<NavItem external="https://sapper.svelte.dev">Sapper</NavItem>
<NavItem external="https://discord.gg/yy75DKs" title="Discord Chat">
<Icon name="message-square"/>
</NavItem>
<NavItem external="https://github.com/sveltejs/svelte" title="GitHub Repo">
<Icon name="github"/>
</NavItem>
</Nav>
{/if}
<main>

@ -1,6 +1,6 @@
import fs from 'fs';
import path from 'path';
import { extract_frontmatter, langs, link_renderer } from '../../utils/markdown.js';
import { extract_frontmatter, langs, link_renderer } from '@sveltejs/site-kit/utils/markdown.js';
import marked from 'marked';
import PrismJS from 'prismjs';
import 'prismjs/components/prism-bash';

@ -48,19 +48,12 @@
a {
position: relative;
opacity: 0.75;
transition: opacity 0.2s;
transition: color 0.2s;
border-bottom: none;
padding: 0;
color: var(--second);
}
@media (min-width: 832px) {
a {
color: white;
}
}
.section {
display: block;
padding: 0 0 .8rem 0;
@ -78,22 +71,33 @@
}
.section:hover,
.subsection:hover {
.subsection:hover,
.active {
color: var(--flash);
opacity: 1
}
.subsection[data-level="4"] {
padding-left: 1.2rem;
}
.active { opacity: 1 }
.icon-container {
position: absolute;
top: -.2rem;
right: 2.4rem;
}
@media (min-width: 832px) {
a {
color: var(--sidebar-text);
}
a:hover,
.section:hover,
.subsection:hover,
.active {
color: white
}
}
</style>
<ul

@ -1,8 +1,8 @@
import fs from 'fs';
import path from 'path';
import { SLUG_PRESERVE_UNICODE } from '../../../config';
import { extract_frontmatter, extract_metadata, langs, link_renderer } from '../../utils/markdown.js';
import { makeSessionSlugProcessor } from '../../utils/slug';
import { SLUG_PRESERVE_UNICODE, SLUG_SEPARATOR } from '../../../config';
import { extract_frontmatter, extract_metadata, langs, link_renderer } from '@sveltejs/site-kit/utils/markdown.js';
import { make_session_slug_processor } from '@sveltejs/site-kit/utils/slug';
import marked from 'marked';
import PrismJS from 'prismjs';
import 'prismjs/components/prism-bash';
@ -38,7 +38,10 @@ const blockTypes = [
];
export default function() {
const makeSlug = makeSessionSlugProcessor(SLUG_PRESERVE_UNICODE);
const makeSlug = make_session_slug_processor({
preserve_unicode: SLUG_PRESERVE_UNICODE,
separator: SLUG_SEPARATOR
});
return fs
.readdirSync(`content/docs`)

@ -6,359 +6,11 @@
</script>
<script>
import { onMount } from 'svelte';
import GuideContents from './_GuideContents.svelte';
import Icon from '../../components/Icon.svelte';
import { getFragment } from '../../utils/navigation';
import { Docs } from '@sveltejs/site-kit'
export let sections;
let active_section;
let container;
let aside;
let show_contents = false;
onMount(() => {
// don't update `active_section` for headings above level 4, see _sections.js
const anchors = container.querySelectorAll('[id]:not([data-scrollignore])');
let positions;
const onresize = () => {
const { top } = container.getBoundingClientRect();
positions = [].map.call(anchors, anchor => {
return anchor.getBoundingClientRect().top - top;
});
}
let last_id = getFragment();
const onscroll = () => {
const top = -window.scrollY;
let i = anchors.length;
while (i--) {
if (positions[i] + top < 40) {
const anchor = anchors[i];
const { id } = anchor;
if (id !== last_id) {
active_section = id;
last_id = id;
}
return;
}
}
};
window.addEventListener('scroll', onscroll, true);
window.addEventListener('resize', onresize, true);
// wait for fonts to load...
const timeouts = [
setTimeout(onresize, 1000),
setTimeout(onscroll, 5000)
];
onresize();
onscroll();
return () => {
window.removeEventListener('scroll', onscroll, true);
window.removeEventListener('resize', onresize, true);
timeouts.forEach(timeout => clearTimeout(timeout));
};
});
</script>
<style>
aside {
position: fixed;
background-color: white;
left: 0.8rem;
bottom: 0.8rem;
width: 2em;
height: 2em;
overflow: hidden;
border: 1px solid #eee;
box-shadow: 1px 1px 6px rgba(0,0,0,0.1);
transition: width 0.2s, height 0.2s;
}
aside button {
position: absolute;
bottom: 0;
left: 0;
width: 3.4rem;
height: 3.4rem;
}
aside.open {
width: calc(100vw - 3rem);
height: calc(100vh - var(--nav-h));
}
aside.open::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: calc(100% - 2rem);
height: 2em;
background: linear-gradient(to top, rgba(255,255,255,0) 0%, rgba(255,255,255,0.7) 50%, rgba(255,255,255,1) 100%);
pointer-events: none;
z-index: 2;
}
aside::after {
content: '';
position: absolute;
left: 0;
bottom: 1.9em;
width: calc(100% - 2rem);
height: 2em;
background: linear-gradient(to bottom, rgba(255,255,255,0) 0%, rgba(255,255,255,0.7) 50%, rgba(255,255,255,1) 100%);
pointer-events: none;
}
.sidebar {
position: absolute;
font-family: var(--font);
overflow-y: auto;
width: 100%;
height: 100%;
padding: 4em 1.6rem 2em 3.2rem;
bottom: 2em;
}
.content {
width: 100%;
margin: 0;
padding: var(--top-offset) var(--side-nav);
tab-size: 2;
-moz-tab-size: 2;
}
@media (min-width: 832px) { /* can't use vars in @media :( */
aside {
display: block;
width: var(--sidebar-w);
height: 100vh;
top: 0;
left: 0;
overflow: hidden;
box-shadow: none;
border: none;
overflow: hidden;
background-color: var(--second);
color: white;
}
aside.open::before {
display: none;
}
aside::after {
content: '';
bottom: 0;
height: var(--top-offset);
background: linear-gradient(to bottom, rgba(103,103,120,0) 0%, rgba(103,103,120,0.7) 50%, rgba(103,103,120,1) 100%);
}
aside button {
display: none;
}
.sidebar {
padding: var(--top-offset) 0 6.4rem 3.2rem;
font-family: var(--font);
overflow-y: auto;
height: 100%;
bottom: auto;
width: 100%;
}
.content {
padding-left: calc(var(--sidebar-w) + var(--side-nav));
}
.content :global(.side-by-side) {
display: grid;
grid-template-columns: calc(50% - 0.5em) calc(50% - 0.5em);
grid-gap: 1em;
}
}
.content h2 {
margin-top: 8rem;
padding: 2rem 1.6rem 4rem 0.2rem;
border-top: var(--border-w) solid #6767785b; /* based on --second */
color: var(--text);
line-height: 1;
font-size: var(--h3);
letter-spacing: .05em;
text-transform: uppercase;
}
.content section:first-of-type > h2 {
margin-top: 0;
}
.content :global(h4) {
margin: 2em 0 1em 0;
}
.content :global(.offset-anchor) {
position: relative;
display: block;
top: calc(-1 * (var(--nav-h) + var(--top-offset) - 1rem));
width: 0;
height: 0;
}
.content :global(.anchor) {
position: absolute;
display: block;
background: url(/icons/link.svg) 0 50% no-repeat;
background-size: 1em 1em;
width: 1.4em;
height: 1em;
left: -1.3em;
opacity: 0;
transition: opacity 0.2s;
border: none !important; /* TODO get rid of linkify */
}
@media (min-width: 768px) {
.content :global(h2):hover :global(.anchor),
.content :global(h3):hover :global(.anchor),
.content :global(h4):hover :global(.anchor),
.content :global(h5):hover :global(.anchor),
.content :global(h6):hover :global(.anchor) {
opacity: 1;
}
.content :global(h5) :global(.anchor),
.content :global(h6) :global(.anchor) {
top: 0.5em;
}
}
.content :global(h3),
.content :global(h3 > code) {
margin: 6.4rem 0 0 0;
padding: 2rem 1.6rem 5.6rem .2rem;
color: var(--text);
border-top: var(--border-w) solid #6767781f; /* based on --second */
background: transparent;
line-height: 1;
}
.content :global(h3):first-of-type {
border: none;
margin: 0;
}
/* avoid doubled border-top */
.content :global(h3 > code) {
border-radius: 0 0 0 0;
border: none;
font-size: var(--h4);
line-height: 1.2;
}
.content :global(h4),
.content :global(h4 > code) {
font-weight: 600;
font-size: var(--h4);
color: var(--second);
margin: 6.4rem 0 1.6rem 0;
padding-left: 0;
background: transparent;
line-height: 1;
padding: 0;
}
.content :global(h5) {
font-size: 2rem;
}
.content :global(code) {
padding: .3rem .8rem .3rem;
margin: 0 0.2rem;
top: -.1rem;
background: var(--back-api);
}
.content :global(pre) :global(code) {
padding: 0;
margin: 0;
top: 0;
background: transparent;
}
.content :global(pre) {
margin: 0 0 2em 0;
}
.content :global(.icon) {
width: 2rem;
height: 2rem;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
fill: none;
}
.content :global(table) {
margin: 0 0 2em 0;
}
section > :global(.code-block) > :global(pre) {
display: inline-block;
background: var(--back-api);
color: white;
padding: .3rem .8rem;
margin: 0;
max-width: 100%;
}
section > :global(.code-block)> :global(pre.language-markup) {
padding: .3rem .8rem .2rem;
background: var(--back-api);
}
section > :global(p) {
max-width: var(--linemax)
}
small {
font-size: var(--h5);
float: right;
pointer-events: all;
color: var(--prime);
cursor: pointer;
}
/* no linkify on these */
small a { all: unset }
small a:before { all: unset }
section :global(blockquote) {
color: hsl(204, 100%, 50%);
border: 2px solid var(--flash);
}
section :global(blockquote) :global(code) {
background: hsl(204, 100%, 95%) !important;
color: hsl(204, 100%, 50%);
}
</style>
<svelte:head>
<title>API Docs • Svelte</title>
@ -367,31 +19,4 @@
<meta name="Description" content="Cybernetically enhanced web apps">
</svelte:head>
<div bind:this={container} class='content listify'>
{#each sections as section}
<section data-id={section.slug}>
<h2>
<span class="offset-anchor" id={section.slug}></span>
<a href="docs#{section.slug}" class="anchor" aria-hidden></a>
{section.metadata.title}
<small>
<a href='https://github.com/sveltejs/svelte/edit/master/site/content/docs/{section.file}' title='edit this section'>
<Icon name='edit' /></a>
</small>
</h2>
{@html section.html}
</section>
{/each}
</div>
<aside bind:this={aside} class="sidebar-container" class:open={show_contents}>
<div class="sidebar" on:click="{() => show_contents = false}"> <!-- scroll container -->
<GuideContents {sections} {active_section} {show_contents} />
</div>
<button on:click="{() => show_contents = !show_contents}">
<Icon name="{show_contents? 'close' : 'menu'}"/>
</button>
</aside>
<Docs {sections}/>

@ -22,7 +22,7 @@
.section-title {
display: block;
padding: 0 0 .8rem 0;
padding: 0 0 0.8rem 0;
font: 400 var(--h6) var(--font);
text-transform: uppercase;
letter-spacing: 0.12em;
@ -32,7 +32,7 @@
a {
display: flex;
position: relative;
color: white;
color: var(--sidebar-text);
border-bottom: none;
padding: 0.2rem 3rem;
margin: 0 -3rem;
@ -42,17 +42,19 @@
}
a:hover {
color: var(--flash);
color: white;
}
a.active {
background: rgba(255, 255, 255, 0.1) calc(100% - 3rem) 50% no-repeat url(/icons/arrow-right.svg);
background: rgba(0, 0, 0, 0.15) calc(100% - 3rem) 50% no-repeat
url(/icons/arrow-right.svg);
background-size: 1em 1em;
color: white;
}
a.active.loading {
background: rgba(255, 255, 255, 0.1) calc(100% - 3rem) 50% no-repeat url(/icons/loading.svg);
background: rgba(0, 0, 0, 0.1) calc(100% - 3rem) 50% no-repeat
url(/icons/loading.svg);
background-size: 1em 1em;
color: white;
}
@ -63,34 +65,34 @@
width: 5rem;
height: 5rem;
border-radius: 2px;
box-shadow: 1px 1px 3px rgba(0,0,0,0.13);
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.13);
margin: 0.2em 0.5em 0.2em 0;
}
</style>
<ul class="examples-toc">
{#each sections as section}
<li>
<span class="section-title">
{section.title}
</span>
<li>
<span class="section-title">
{section.title}
</span>
{#each section.examples as example}
<a
href="examples#{example.slug}"
class="row"
class:active="{example.slug === active_section}"
class:loading="{isLoading}"
>
<img
class="thumbnail"
alt="{example.title} thumbnail"
src="examples/thumbnails/{example.slug}.jpg"
>
{#each section.examples as example}
<a
href="examples#{example.slug}"
class="row"
class:active="{example.slug === active_section}"
class:loading="{isLoading}"
>
<img
class="thumbnail"
alt="{example.title} thumbnail"
src="examples/thumbnails/{example.slug}.jpg"
/>
<span>{example.title}</span>
</a>
{/each}
</li>
<span>{example.title}</span>
</a>
{/each}
</li>
{/each}
</ul>

@ -26,7 +26,7 @@
svelteUrl
} from '../../config';
import { process_example } from '../../utils/examples';
import { getFragment } from '../../utils/navigation';
import { getFragment } from '@sveltejs/site-kit/utils/navigation';
import TableOfContents from './_TableOfContents.svelte';
export let sections;
@ -97,11 +97,9 @@
</svelte:head>
<div class='examples-container' bind:clientWidth={width}>
<div
class="viewport offset-{offset}"
>
<div class="viewport offset-{offset}">
<TableOfContents {sections} active_section={active_slug} {isLoading} />
<div class="toc" class:loading={isLoading}>
<div class="repl-container" class:loading={isLoading}>
<Repl
bind:this={repl}
{svelteUrl}
@ -136,10 +134,24 @@
grid-auto-rows: 100%;
}
.toc.loading {
.repl-container.loading {
opacity: 0.6;
}
/* temp fix for #2499 and #2550 while waiting for a fix for https://github.com/sveltejs/svelte-repl/issues/8 */
.repl-container :global(.tab-content),
.repl-container :global(.tab-content.visible) {
pointer-events: all;
opacity: 1;
}
.repl-container :global(.tab-content) {
visibility: hidden;
}
.repl-container :global(.tab-content.visible) {
visibility: visible;
}
.offset-1 { transform: translate(-33.333%, 0); }
.offset-2 { transform: translate(-66.666%, 0); }

@ -1,13 +1,11 @@
<script>
import Blurb from './_components/Blurb.svelte';
import { Blurb, Hero, Section } from '@sveltejs/site-kit';
// import Blurb from './_components/Blurb.svelte';
import Example from './_components/Example.svelte';
import WhosUsingSvelte from './_components/WhosUsingSvelte.svelte';
import IntersectionObserver from '../components/IntersectionObserver.svelte';
// import Lazy from '../components/Lazy.svelte';
import ReplWidget from '../components/Repl/ReplWidget.svelte';
import contributors from './_contributors.js';
let sy = 0;
// TODO this causes a Sapper CSS bug...
// function loadReplWidget() {
// console.log('lazy loading');
@ -16,77 +14,18 @@
</script>
<style>
.container {
position: relative;
margin: 10rem auto;
padding: 0 var(--side-nav);
max-width: 120rem;
}
.container h3 { color: var(--text) }
.container ul { list-style: none }
/* max line-length ~60 chars */
li:not(.box) > p {
max-width: var(--linemax)
}
/* darken text for accesibility */
/* TODO does this belong elsewhere? */
:global(.back-light) {
--text: hsl(36, 3%, 44%);
}
.hero {
margin: 10rem auto;
}
.hero h3, .logotype {
position: relative;
left: 1.6rem;
}
.hero h3 {
font-size: 2rem;
}
.logotype {
height: 4rem;
}
.logo {
position: absolute;
top: -4rem;
right: 0rem;
width: 52rem;
will-change: transform;
display: none;
}
.examples {
background: var(--second);
color: white;
overflow: hidden;
}
.example {
width: 100%;
}
.example a {
color: inherit;
}
.example > p {
margin: 4.4rem 2.4rem 2.4rem 0;
}
.repl-container {
width: 100%;
height: 420px;
border-radius: var(--border-r);
overflow: hidden;
}
.contributor {
width: 2.4em;
height: 2.4em;
@ -98,45 +37,6 @@
margin: 0 0.5em 0.5em 0;
border: 2px solid var(--second);
}
@media (min-width: 640px) {
.logotype {
height: 6rem;
}
.hero h3 {
font-size: var(--h3);
}
}
@media (min-width: 800px) {
.logo {
display: block;
}
.hero {
margin: 15rem auto;
}
.hero h3, .logotype {
left: 3rem;
}
}
@media (min-width: 920px) {
.example {
display: grid;
grid-template-columns: 1fr 3fr;
grid-gap: 0.5em;
align-items: start;
}
}
@media (min-width: 1200px) {
.logo {
right: calc(50vw - 60rem);
}
}
</style>
<svelte:head>
@ -147,78 +47,83 @@
<meta name="Description" content="Cybernetically enhanced web apps">
</svelte:head>
<svelte:window bind:scrollY={sy}/>
<Hero
title="Svelte"
tagline="Cybernetically enhanced web apps"
outline="svelte-logo-outline.svg"
logotype="svelte-logotype.svg"
/>
<img alt="Svelte logo" class="logo" src="svelte-logo-outline.svg" style="transform: translate(0, {sy * .2}px)">
<Blurb>
<a href="blog/write-less-code" slot="one">
<h2>Write less code</h2>
<p>Build boilerplate-free components using languages you already know — HTML, CSS and JavaScript</p>
<section class="hero container">
<img alt="Svelte logotype" class="logotype" src="svelte-logotype.svg">
<h3>Cybernetically enhanced web apps</h3>
</section>
<span class="learn-more">learn more</span>
</a>
<Blurb/>
<a href="blog/virtual-dom-is-pure-overhead" slot="two">
<h2>No virtual DOM</h2>
<p>Svelte compiles your code to tiny, framework-less vanilla JS — your app starts fast and stays fast</p>
<span class="learn-more">learn more</span>
</a>
<a href="blog/svelte-3-rethinking-reactivity" slot="three">
<h2>Truly reactive</h2>
<p>No more complex state management libraries — Svelte brings reactivity to JavaScript itself</p>
<span class="learn-more">learn more</span>
</a>
<div class="description" slot="what">
<p>Svelte is a radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue do the bulk of their work in the <em>browser</em>, Svelte shifts that work into a <em>compile step</em> that happens when you build your app.</p>
<p>Instead of using techniques like virtual DOM diffing, Svelte writes code that surgically updates the DOM when the state of your app changes.</p>
<p><a href="blog/svelte-3-rethinking-reactivity">Read the introductory blog post</a> to learn more.</p>
</div>
<div style="grid-area: start; display: flex; flex-direction: column; min-width: 0" slot="how">
<pre class="language-bash" style="margin: 0 0 1em 0; min-width: 0; min-height: 0">
npx degit sveltejs/template my-svelte-project
cd my-svelte-project
npm install
npm run dev & open http://localhost:5000
</pre>
<p style="flex: 1">See the <a href="blog/the-easiest-way-to-get-started">quickstart guide</a> for more information.</p>
<p class="cta"><a rel="prefetch" href="tutorial">Learn Svelte</a></p>
</div>
</Blurb>
<div class="examples">
<section class="container example">
<Example id="hello-world">
<p>Svelte components are built on top of HTML. Just add data.</p>
</Example>
<div class="repl-container">
<IntersectionObserver once let:intersecting top={400}>
{#if intersecting}
<!-- <Lazy this={loadReplWidget} example="hello-world"/> -->
<ReplWidget example="hello-world"/>
{/if}
</IntersectionObserver>
</div>
</section>
<section class="container example">
<Example id="nested-components">
<p>CSS is component-scoped by default — no more style collisions or specificity wars. Or you can <a href="/blog/svelte-css-in-js">use your favourite CSS-in-JS library</a>.</p>
</Example>
<div class="repl-container">
<IntersectionObserver once let:intersecting top={400}>
{#if intersecting}
<!-- <Lazy this={loadReplWidget} example="nested-components"/> -->
<ReplWidget example="nested-components"/>
{/if}
</IntersectionObserver>
</div>
</section>
<section class="container example">
<Example id="reactive-assignments">
<p>Trigger efficient, granular updates by assigning to local variables. The compiler does the rest.</p>
</Example>
<div class="repl-container">
<IntersectionObserver once let:intersecting top={400}>
{#if intersecting}
<!-- <Lazy this={loadReplWidget} example="reactive-assignments"/> -->
<ReplWidget example="reactive-assignments"/>
{/if}
</IntersectionObserver>
</div>
</section>
<section class="container example">
<Example id="svg-transitions">
<p>Build beautiful UIs with a powerful, performant transition engine built right into the framework.</p>
<div class="repl-container">
<IntersectionObserver once let:intersecting top={400}>
{#if intersecting}
<!-- <Lazy this={loadReplWidget} example="svg-transitions"/> -->
<ReplWidget example="svg-transitions"/>
{/if}
</IntersectionObserver>
</div>
</section>
</Example>
</div>
<section class="container">
<Section>
<h3>Who's using Svelte?</h3>
<WhosUsingSvelte/>
</section>
</Section>
<section class="container">
<Section>
<h3>Contributors</h3>
<p>Svelte is free and open source software, made possible by the work of dozens of volunteers. <a href="https://github.com/sveltejs/svelte">Join us!</a></p>
@ -230,4 +135,4 @@
href="https://github.com/{contributor}"
>{contributor}</a>
{/each}
</section>
</Section>

@ -1,11 +1,12 @@
<script>
import { createEventDispatcher } from 'svelte';
import UserMenu from './UserMenu.svelte';
import Icon from '../../../../components/Icon.svelte';
import { Icon } from '@sveltejs/site-kit';
import * as doNotZip from 'do-not-zip';
import downloadBlob from '../../_utils/downloadBlob.js';
import { user } from '../../../../user.js';
import { enter } from '../../../../utils/events.js';
import { isMac } from '../../../../utils/compat.js';
const dispatch = createEventDispatcher();
@ -20,8 +21,6 @@
let justSaved = false;
let justForked = false;
const isMac = typeof navigator !== 'undefined' && navigator.platform === 'MacIntel';
function wait(ms) {
return new Promise(f => setTimeout(f, ms));
}

@ -27,7 +27,7 @@
let repl;
let gist;
let name = 'loading...';
let name = 'Loading...';
let zen_mode = false;
let relaxed = false;
let width = process.browser ? window.innerWidth : 1000;
@ -58,7 +58,9 @@
if (gist_id) {
relaxed = false;
fetch(`gist/${gist_id}`).then(r => r.json()).then(data => {
fetch(`gist/${gist_id}`)
.then(r => r.json())
.then(data => {
gist = data;
const { description, files } = data;
@ -155,6 +157,20 @@
transform: translate(-50%, 0);
}
/* temp fix for #2499 and #2550 while waiting for a fix for https://github.com/sveltejs/svelte-repl/issues/8 */
.viewport :global(.tab-content),
.viewport :global(.tab-content.visible) {
pointer-events: all;
opacity: 1;
}
.viewport :global(.tab-content) {
visibility: hidden;
}
.viewport :global(.tab-content.visible) {
visibility: visible;
}
.zen-mode {
position: fixed;
width: 100%;
@ -187,7 +203,7 @@
</style>
<svelte:head>
<title>REPL • Svelte</title>
<title>{name} • REPL • Svelte</title>
<meta name="twitter:title" content="Svelte REPL">
<meta name="twitter:description" content="Cybernetically enhanced web apps">
@ -198,9 +214,9 @@
<div class="repl-outer {zen_mode ? 'zen-mode' : ''}" class:mobile>
<AppControls
{name}
{gist}
{repl}
bind:name
bind:zen_mode
on:forked={handle_fork}
/>

@ -1,6 +1,6 @@
<script>
import { goto } from '@sapper/app';
import Icon from '../../../components/Icon.svelte';
import { Icon } from '@sveltejs/site-kit';
export let sections;
export let slug;
@ -30,13 +30,17 @@
display: block;
padding: 0.7em 0;
text-align: center;
opacity: 0.7;
opacity: 0.75;
color: white;
}
a:hover {
opacity: 1;
}
a.disabled, a.disabled:hover, a.disabled:active {
color: white;
opacity: 0.4;
opacity: 0.3;
}
span {

@ -3,7 +3,7 @@ import * as path from 'path';
import marked from 'marked';
import PrismJS from 'prismjs';
import send from '@polka/send';
import { extract_frontmatter, extract_metadata, langs, link_renderer } from '../../../utils/markdown';
import { extract_frontmatter, extract_metadata, langs, link_renderer } from '@sveltejs/site-kit/utils/markdown';
const cache = new Map();

@ -18,7 +18,7 @@
import { getContext } from 'svelte';
import ScreenToggle from '../../../components/ScreenToggle.svelte';
import Icon from '../../../components/Icon.svelte';
import { Icon } from '@sveltejs/site-kit';
import TableOfContents from './_TableOfContents.svelte';
import {
@ -151,7 +151,7 @@
height: 100%;
border-right: 1px solid var(--second);
background-color: var(--second);
color: white;
color: var(--sidebar-text);
}
.chapter-markup {
@ -165,6 +165,7 @@
margin: 4rem 0 1.6rem 0;
font-size: var(--h3);
line-height: 1;
font-weight: 400;
color: white;
}
@ -173,16 +174,21 @@
}
.chapter-markup :global(a) {
color: var(--sidebar-text);
}
.chapter-markup :global(a:hover) {
color: white;
}
.chapter-markup :global(ul) {
padding: 0 0 0 2em;
}
.chapter-markup :global(blockquote) {
background-color: rgba(255,255,255,.1);
color: white;
background-color: rgba(0,0,0,.17);
color: var(--sidebar-text);
}
.chapter-markup::-webkit-scrollbar {
@ -198,22 +204,22 @@
.chapter-markup :global(p) > :global(code),
.chapter-markup :global(ul) :global(code) {
color: white;
background: rgba(255,255,255,.1);
padding: .2em .4em;
color: var(--sidebar-text);
background: rgba(0,0,0,.12);
padding: .2em .4em .3em;
white-space: nowrap;
position: relative;
top: -0.1em;
}
.controls {
border-top: 1px solid rgba(255,255,255,.1);
border-top: 1px solid rgba(255,255,255,.15);
padding: 1em 0 0 0;
display: flex;
}
.show {
background: rgba(255,255,255,.1);
background: rgba(0,0,0,.4);
padding: .2em .7em .3em;
border-radius: var(--border-r);
top: .1em;
@ -223,22 +229,17 @@
}
.show:hover {
background: rgba(255,255,255,.2);
background: rgba(0,0,0,.65);
color: white;
}
a.next {
/* border-bottom: none; */
padding-right: 1.2em;
background: no-repeat 100% 50% url(/icons/arrow-right.svg);
background-size: 1em 1em;
margin-left: auto;
}
a.next:hover {
/* border-bottom: 2px solid currentColor; */
/* text-decoration: underline; */
}
.improve-chapter {
padding: 1em 0 .5em 0;
}

@ -1,6 +1,6 @@
import * as fs from 'fs';
import send from '@polka/send';
import { extract_frontmatter } from '../../utils/markdown';
import { extract_frontmatter } from '@sveltejs/site-kit/utils/markdown';
let json;

@ -82,11 +82,12 @@ if (process.env.GITHUB_CLIENT_ID) {
res.end(`
<body style="font-family: sans-serif; background: rgb(255,215,215); border: 2px solid red; margin: 0; padding: 1em;">
<h1>Missing .env file</h1>
<p>In order to use GitHub authentication, you will need to <a target="_blank" href="https://github.com/settings/developers">register an OAuth application</a> with <code>gist</code> and <code>read:user</code> scopes, and create a .env file:</p>
<p>In order to use GitHub authentication, you will need to <a target="_blank" href="https://github.com/settings/developers">register an OAuth application</a> and create a local .env file:</p>
<pre>GITHUB_CLIENT_ID=[YOUR_APP_ID]\nGITHUB_CLIENT_SECRET=[YOUR_APP_SECRET]\nBASEURL=http://localhost:3000</pre>
<p>The <code>BASEURL</code> variable should match the callback URL specified for your app.</p>
<p>See also <a target="_blank" href="https://github.com/sveltejs/svelte/tree/master/site#repl-github-integration">here</a></p>
</body>
`);
});

@ -7,7 +7,6 @@
%sapper.base%
<link rel='stylesheet' href='global.css'>
<link href=prism.css rel=stylesheet>
<link rel='manifest' href='manifest.json'>
<link rel='icon' type='image/png' href='favicon.png'>

@ -0,0 +1 @@
export const isMac = typeof navigator !== 'undefined' && navigator.platform === 'MacIntel';

@ -1,61 +0,0 @@
import * as fleece from 'golden-fleece';
export function extract_frontmatter(markdown) {
const match = /---\r?\n([\s\S]+?)\r?\n---/.exec(markdown);
const frontMatter = match[1];
const content = markdown.slice(match[0].length);
const metadata = {};
frontMatter.split('\n').forEach(pair => {
const colonIndex = pair.indexOf(':');
metadata[pair.slice(0, colonIndex).trim()] = pair
.slice(colonIndex + 1)
.trim();
});
return { metadata, content };
}
export function extract_metadata(line, lang) {
try {
if (lang === 'html' && line.startsWith('<!--') && line.endsWith('-->')) {
return fleece.evaluate(line.slice(4, -3).trim());
}
if (
lang === 'js' ||
(lang === 'json' && line.startsWith('/*') && line.endsWith('*/'))
) {
return fleece.evaluate(line.slice(2, -2).trim());
}
} catch (err) {
// TODO report these errors, don't just squelch them
return null;
}
}
// map lang to prism-language-attr
export const langs = {
bash: 'bash',
html: 'markup',
sv: 'markup',
js: 'javascript',
css: 'css'
};
// links renderer
export function link_renderer (href, title, text) {
let target_attr = '';
let title_attr = '';
if (href.startsWith("http")) {
target_attr = ' target="_blank"';
}
if (title !== null) {
title_attr = ` title="${title}"`;
}
return `<a href="${href}"${target_attr}${title_attr}>${text}</a>`;
}

@ -1 +0,0 @@
export const getFragment = () => window.location.hash.slice(1);

@ -1,14 +1,20 @@
import limax from 'limax';
import {SLUG_LANG, SLUG_SEPARATOR} from '../../config';
import slugify from '@sindresorhus/slugify';
import {SLUG_SEPARATOR} from '../../config';
/* latinizer processor */
/* url-safe processor */
export const limaxProcessor = (string, lang = SLUG_LANG) => limax(string, {
custom: ['$'],
separator: SLUG_SEPARATOR,
maintainCase: true,
lang
});
export const urlsafeSlugProcessor = string =>
slugify(string, {
customReplacements: [ // runs before any other transformations
['$', 'DOLLAR'], // `$destroy` & co
['-', 'DASH'], // conflicts with `separator`
],
separator: SLUG_SEPARATOR,
decamelize: false,
lowercase: false
})
.replace(/DOLLAR/g, '$')
.replace(/DASH/g, '-');
/* unicode-preserver processor */
@ -40,7 +46,7 @@ export const unicodeSafeProcessor = string =>
.chunks
.reduce((accum, chunk) => {
const processed = chunk.type === 'process'
? limaxProcessor(chunk.string)
? urlsafeSlugProcessor(chunk.string)
: chunk.string;
processed.length > 0 && accum.push(processed);
@ -52,7 +58,7 @@ export const unicodeSafeProcessor = string =>
/* session processor */
export const makeSessionSlugProcessor = (preserveUnicode = false) => {
const processor = preserveUnicode ? unicodeSafeProcessor : limaxProcessor;
const processor = preserveUnicode ? unicodeSafeProcessor : urlsafeSlugProcessor;
const seen = new Set();
return string => {

@ -46,6 +46,7 @@
--flash: #40b3ff;
--heading: var(--second);
--text: #444;
--sidebar-text: rgba(255, 255, 255, .75);
--border-w: .3rem; /* border-width */
--border-r: .4rem; /* border-radius */
}
@ -469,7 +470,6 @@ input[type="checkbox"]::before {
top: 0;
left: 0;
background: var(--second);
-webkit-transition: .25s ease-out;
/* box-sizing: border-box; */
box-sizing: content-box;
}
@ -489,7 +489,7 @@ input[type="checkbox"]::after {
border-radius: 1em;
background: white;
box-shadow: 0 0px 1px rgba(0,0,0,.4), 0 4px 2px rgba(0,0,0,.1);
-webkit-transition: .2s ease-out;
-webkit-transition: background .2s ease-out, left .2s ease-out;
}
input[type="checkbox"]:checked::after {

@ -1,5 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 103 124">
<path fill="black" d='M96.33,20.61C85.38,4.93,63.74.28,48.09,10.25L20.61,27.77A31.46,31.46,0,0,0,6.37,48.88,33.22,33.22,0,0,0,9.64,70.2,31.52,31.52,0,0,0,4.93,82a33.61,33.61,0,0,0,5.73,25.41c11,15.68,32.6,20.33,48.25,10.36l27.48-17.52a31.48,31.48,0,0,0,14.24-21.11A33.22,33.22,0,0,0,97.36,57.8,31.52,31.52,0,0,0,102.07,46a33.57,33.57,0,0,0-5.74-25.41
M45.41,108.86A21.81,21.81,0,0,1,22,100.18,20.2,20.2,0,0,1,18.53,84.9a19,19,0,0,1,.65-2.57l.52-1.58,1.41,1a35.32,35.32,0,0,0,10.75,5.37l1,.31-.1,1a6.2,6.2,0,0,0,1.11,4.08A6.57,6.57,0,0,0,41,95.19a6,6,0,0,0,1.68-.74L70.11,76.94a5.76,5.76,0,0,0,2.59-3.83,6.09,6.09,0,0,0-1-4.6,6.58,6.58,0,0,0-7.06-2.62,6.21,6.21,0,0,0-1.69.74L52.43,73.31a19.88,19.88,0,0,1-5.58,2.45,21.82,21.82,0,0,1-23.43-8.68A20.2,20.2,0,0,1,20,51.8a19,19,0,0,1,8.56-12.7L56,21.59a19.88,19.88,0,0,1,5.58-2.45A21.81,21.81,0,0,1,85,27.82,20.2,20.2,0,0,1,88.47,43.1a19,19,0,0,1-.65,2.57l-.52,1.58-1.41-1a35.32,35.32,0,0,0-10.75-5.37l-1-.31.1-1a6.2,6.2,0,0,0-1.11-4.08,6.57,6.57,0,0,0-7.06-2.62,6,6,0,0,0-1.68.74L36.89,51.06a5.71,5.71,0,0,0-2.58,3.83,6,6,0,0,0,1,4.6,6.58,6.58,0,0,0,7.06,2.62,6.21,6.21,0,0,0,1.69-.74l10.48-6.68a19.88,19.88,0,0,1,5.58-2.45,21.82,21.82,0,0,1,23.43,8.68A20.2,20.2,0,0,1,87,76.2a19,19,0,0,1-8.56,12.7L51,106.41a19.88,19.88,0,0,1-5.58,2.45' />
<!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 98.2 118" style="enable-background:new 0 0 98.2 118;" xml:space="preserve">
<path d="M91.9,15.6C81-0.1,59.3-4.7,43.7,5.3L16.2,22.8C8.7,27.5,3.5,35.2,2,43.9c-1.3,7.3-0.2,14.8,3.3,21.3
c-2.4,3.6-4,7.6-4.7,11.8c-1.6,8.9,0.5,18.1,5.7,25.4c11,15.7,32.6,20.3,48.2,10.4L82,95.3c7.5-4.7,12.7-12.4,14.2-21.1
c1.3-7.3,0.2-14.8-3.3-21.3c2.4-3.6,4-7.6,4.7-11.8C99.2,32.1,97.2,22.9,91.9,15.6 M41,103.9c-8.9,2.3-18.2-1.2-23.4-8.7
c-3.2-4.4-4.4-9.9-3.5-15.3c0.2-0.9,0.4-1.7,0.6-2.6l0.5-1.6l1.4,1c3.3,2.4,6.9,4.2,10.8,5.4l1,0.3l-0.1,1c-0.1,1.4,0.3,2.9,1.1,4.1
c1.6,2.3,4.4,3.4,7.1,2.7c0.6-0.2,1.2-0.4,1.7-0.7l27.4-17.5c1.4-0.9,2.3-2.2,2.6-3.8c0.3-1.6-0.1-3.3-1-4.6
c-1.6-2.3-4.4-3.3-7.1-2.6c-0.6,0.2-1.2,0.4-1.7,0.7L48,68.3c-1.7,1.1-3.6,1.9-5.6,2.4c-8.9,2.3-18.2-1.2-23.4-8.7
c-3.1-4.4-4.4-9.9-3.4-15.3c0.9-5.2,4.1-9.9,8.6-12.7l27.4-17.5c1.7-1.1,3.6-1.9,5.6-2.5c8.9-2.3,18.2,1.2,23.4,8.7
c3.2,4.4,4.4,9.9,3.5,15.3c-0.2,0.9-0.4,1.7-0.7,2.6l-0.5,1.6l-1.4-1c-3.3-2.4-6.9-4.2-10.8-5.4l-1-0.3l0.1-1
c0.1-1.4-0.3-2.9-1.1-4.1c-1.6-2.3-4.4-3.3-7.1-2.6c-0.6,0.2-1.2,0.4-1.7,0.7L32.5,46.1c-1.4,0.9-2.3,2.2-2.6,3.8
c-0.3,1.6,0.1,3.3,1,4.6c1.6,2.3,4.4,3.3,7.1,2.6c0.6-0.2,1.2-0.4,1.7-0.7l10.5-6.7c1.7-1.1,3.6-1.9,5.6-2.5
c8.9-2.3,18.2,1.2,23.4,8.7c3.2,4.4,4.4,9.9,3.5,15.3c-0.9,5.2-4.1,9.9-8.6,12.7l-27.4,17.5C44.9,102.5,43,103.3,41,103.9"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -1,5 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 103 124">
<path fill="none" stroke="#ff3e00" stroke-width=".25" d='M96.33,20.61C85.38,4.93,63.74.28,48.09,10.25L20.61,27.77A31.46,31.46,0,0,0,6.37,48.88,33.22,33.22,0,0,0,9.64,70.2,31.52,31.52,0,0,0,4.93,82a33.61,33.61,0,0,0,5.73,25.41c11,15.68,32.6,20.33,48.25,10.36l27.48-17.52a31.48,31.48,0,0,0,14.24-21.11A33.22,33.22,0,0,0,97.36,57.8,31.52,31.52,0,0,0,102.07,46a33.57,33.57,0,0,0-5.74-25.41' />
<path fill="none" stroke="#ff3e00" stroke-width=".25" d='M45.41,108.86A21.81,21.81,0,0,1,22,100.18,20.2,20.2,0,0,1,18.53,84.9a19,19,0,0,1,.65-2.57l.52-1.58,1.41,1a35.32,35.32,0,0,0,10.75,5.37l1,.31-.1,1a6.2,6.2,0,0,0,1.11,4.08A6.57,6.57,0,0,0,41,95.19a6,6,0,0,0,1.68-.74L70.11,76.94a5.76,5.76,0,0,0,2.59-3.83,6.09,6.09,0,0,0-1-4.6,6.58,6.58,0,0,0-7.06-2.62,6.21,6.21,0,0,0-1.69.74L52.43,73.31a19.88,19.88,0,0,1-5.58,2.45,21.82,21.82,0,0,1-23.43-8.68A20.2,20.2,0,0,1,20,51.8a19,19,0,0,1,8.56-12.7L56,21.59a19.88,19.88,0,0,1,5.58-2.45A21.81,21.81,0,0,1,85,27.82,20.2,20.2,0,0,1,88.47,43.1a19,19,0,0,1-.65,2.57l-.52,1.58-1.41-1a35.32,35.32,0,0,0-10.75-5.37l-1-.31.1-1a6.2,6.2,0,0,0-1.11-4.08,6.57,6.57,0,0,0-7.06-2.62,6,6,0,0,0-1.68.74L36.89,51.06a5.71,5.71,0,0,0-2.58,3.83,6,6,0,0,0,1,4.6,6.58,6.58,0,0,0,7.06,2.62,6.21,6.21,0,0,0,1.69-.74l10.48-6.68a19.88,19.88,0,0,1,5.58-2.45,21.82,21.82,0,0,1,23.43,8.68A20.2,20.2,0,0,1,87,76.2a19,19,0,0,1-8.56,12.7L51,106.41a19.88,19.88,0,0,1-5.58,2.45' />
<!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 98.4 118.3" style="enable-background:new 0 0 98.4 118.3;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#FF3E00;stroke-width:0.25;}
</style>
<path class="st0" d="M92,15.7C81.1,0.1,59.5-4.6,43.8,5.4L16.3,22.9C8.8,27.6,3.6,35.3,2.1,44c-1.3,7.3-0.2,14.8,3.3,21.3
c-2.4,3.6-4,7.6-4.7,11.8c-1.6,8.9,0.5,18.1,5.7,25.4c11,15.7,32.6,20.3,48.2,10.4l27.5-17.5c7.5-4.7,12.7-12.4,14.2-21.1
c1.3-7.3,0.2-14.8-3.3-21.3c2.4-3.6,4-7.6,4.7-11.8C99.4,32.2,97.3,23.1,92,15.7"/>
<path class="st0" d="M41.1,104c-8.9,2.3-18.2-1.2-23.4-8.7c-3.2-4.4-4.4-9.9-3.5-15.3c0.2-0.9,0.4-1.7,0.6-2.6l0.5-1.6l1.4,1
c3.3,2.4,6.9,4.2,10.8,5.4l1,0.3l-0.1,1c-0.1,1.4,0.3,2.9,1.1,4.1c1.6,2.3,4.4,3.4,7.1,2.7c0.6-0.2,1.2-0.4,1.7-0.7l27.4-17.5
c1.4-0.9,2.3-2.2,2.6-3.8c0.3-1.6-0.1-3.3-1-4.6c-1.6-2.3-4.4-3.3-7.1-2.6c-0.6,0.2-1.2,0.4-1.7,0.7l-10.5,6.7
c-1.7,1.1-3.6,1.9-5.6,2.4c-8.9,2.3-18.2-1.2-23.4-8.7c-3.1-4.4-4.4-9.9-3.4-15.3c0.9-5.2,4.1-9.9,8.6-12.7l27.4-17.5
c1.7-1.1,3.6-1.9,5.6-2.5c8.9-2.3,18.2,1.2,23.4,8.7c3.2,4.4,4.4,9.9,3.5,15.3c-0.2,0.9-0.4,1.7-0.7,2.6L83,42.4l-1.4-1
c-3.3-2.4-6.9-4.2-10.8-5.4l-1-0.3l0.1-1c0.1-1.4-0.3-2.9-1.1-4.1c-1.6-2.3-4.4-3.3-7.1-2.6c-0.6,0.2-1.2,0.4-1.7,0.7L32.6,46.2
C31.2,47,30.3,48.4,30,50c-0.3,1.6,0.1,3.3,1,4.6c1.6,2.3,4.4,3.3,7.1,2.6c0.6-0.2,1.2-0.4,1.7-0.7l10.5-6.7
c1.7-1.1,3.6-1.9,5.6-2.5c8.9-2.3,18.2,1.2,23.4,8.7c3.2,4.4,4.4,9.9,3.5,15.3c-0.9,5.2-4.1,9.9-8.6,12.7l-27.4,17.5
C45,102.6,43.1,103.5,41.1,104"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -1,5 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 103 124">
<path fill="#ff3e00" d='M96.33,20.61C85.38,4.93,63.74.28,48.09,10.25L20.61,27.77A31.46,31.46,0,0,0,6.37,48.88,33.22,33.22,0,0,0,9.64,70.2,31.52,31.52,0,0,0,4.93,82a33.61,33.61,0,0,0,5.73,25.41c11,15.68,32.6,20.33,48.25,10.36l27.48-17.52a31.48,31.48,0,0,0,14.24-21.11A33.22,33.22,0,0,0,97.36,57.8,31.52,31.52,0,0,0,102.07,46a33.57,33.57,0,0,0-5.74-25.41' />
<path fill="white" d='M45.41,108.86A21.81,21.81,0,0,1,22,100.18,20.2,20.2,0,0,1,18.53,84.9a19,19,0,0,1,.65-2.57l.52-1.58,1.41,1a35.32,35.32,0,0,0,10.75,5.37l1,.31-.1,1a6.2,6.2,0,0,0,1.11,4.08A6.57,6.57,0,0,0,41,95.19a6,6,0,0,0,1.68-.74L70.11,76.94a5.76,5.76,0,0,0,2.59-3.83,6.09,6.09,0,0,0-1-4.6,6.58,6.58,0,0,0-7.06-2.62,6.21,6.21,0,0,0-1.69.74L52.43,73.31a19.88,19.88,0,0,1-5.58,2.45,21.82,21.82,0,0,1-23.43-8.68A20.2,20.2,0,0,1,20,51.8a19,19,0,0,1,8.56-12.7L56,21.59a19.88,19.88,0,0,1,5.58-2.45A21.81,21.81,0,0,1,85,27.82,20.2,20.2,0,0,1,88.47,43.1a19,19,0,0,1-.65,2.57l-.52,1.58-1.41-1a35.32,35.32,0,0,0-10.75-5.37l-1-.31.1-1a6.2,6.2,0,0,0-1.11-4.08,6.57,6.57,0,0,0-7.06-2.62,6,6,0,0,0-1.68.74L36.89,51.06a5.71,5.71,0,0,0-2.58,3.83,6,6,0,0,0,1,4.6,6.58,6.58,0,0,0,7.06,2.62,6.21,6.21,0,0,0,1.69-.74l10.48-6.68a19.88,19.88,0,0,1,5.58-2.45,21.82,21.82,0,0,1,23.43,8.68A20.2,20.2,0,0,1,87,76.2a19,19,0,0,1-8.56,12.7L51,106.41a19.88,19.88,0,0,1-5.58,2.45' />
<!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 98.1 118" style="enable-background:new 0 0 98.1 118;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FF3E00;}
.st1{fill:#FFFFFF;}
</style>
<path class="st0" d="M91.8,15.6C80.9-0.1,59.2-4.7,43.6,5.2L16.1,22.8C8.6,27.5,3.4,35.2,1.9,43.9c-1.3,7.3-0.2,14.8,3.3,21.3
c-2.4,3.6-4,7.6-4.7,11.8c-1.6,8.9,0.5,18.1,5.7,25.4c11,15.7,32.6,20.3,48.2,10.4l27.5-17.5c7.5-4.7,12.7-12.4,14.2-21.1
c1.3-7.3,0.2-14.8-3.3-21.3c2.4-3.6,4-7.6,4.7-11.8C99.2,32.1,97.1,22.9,91.8,15.6"/>
<path class="st1" d="M40.9,103.9c-8.9,2.3-18.2-1.2-23.4-8.7c-3.2-4.4-4.4-9.9-3.5-15.3c0.2-0.9,0.4-1.7,0.6-2.6l0.5-1.6l1.4,1
c3.3,2.4,6.9,4.2,10.8,5.4l1,0.3l-0.1,1c-0.1,1.4,0.3,2.9,1.1,4.1c1.6,2.3,4.4,3.4,7.1,2.7c0.6-0.2,1.2-0.4,1.7-0.7L65.5,72
c1.4-0.9,2.3-2.2,2.6-3.8c0.3-1.6-0.1-3.3-1-4.6c-1.6-2.3-4.4-3.3-7.1-2.6c-0.6,0.2-1.2,0.4-1.7,0.7l-10.5,6.7
c-1.7,1.1-3.6,1.9-5.6,2.4c-8.9,2.3-18.2-1.2-23.4-8.7c-3.1-4.4-4.4-9.9-3.4-15.3c0.9-5.2,4.1-9.9,8.6-12.7l27.5-17.5
c1.7-1.1,3.6-1.9,5.6-2.5c8.9-2.3,18.2,1.2,23.4,8.7c3.2,4.4,4.4,9.9,3.5,15.3c-0.2,0.9-0.4,1.7-0.7,2.6l-0.5,1.6l-1.4-1
c-3.3-2.4-6.9-4.2-10.8-5.4l-1-0.3l0.1-1c0.1-1.4-0.3-2.9-1.1-4.1c-1.6-2.3-4.4-3.3-7.1-2.6c-0.6,0.2-1.2,0.4-1.7,0.7L32.4,46.1
c-1.4,0.9-2.3,2.2-2.6,3.8s0.1,3.3,1,4.6c1.6,2.3,4.4,3.3,7.1,2.6c0.6-0.2,1.2-0.4,1.7-0.7l10.5-6.7c1.7-1.1,3.6-1.9,5.6-2.5
c8.9-2.3,18.2,1.2,23.4,8.7c3.2,4.4,4.4,9.9,3.5,15.3c-0.9,5.2-4.1,9.9-8.6,12.7l-27.5,17.5C44.8,102.5,42.9,103.3,40.9,103.9"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -1,61 +1,61 @@
import {strict as assert} from 'assert';
import {limaxProcessor, unicodeSafeProcessor} from '../../src/utils/slug';
import {SLUG_SEPARATOR as _, SLUG_LANG} from '../../config';
import {urlsafeSlugProcessor, unicodeSafeProcessor} from '../../src/utils/slug';
import {SLUG_SEPARATOR as _} from '../../config';
describe('slug', () => {
describe('limaxProcessor (latinize unicode)', () => {
describe('urlsafeSlugProcessor', () => {
describe('ascii', () => {
it('space separated words', () => {
assert.equal(
limaxProcessor('Text expressions'),
`text${_}expressions`
urlsafeSlugProcessor('Text expressions'),
`Text${_}expressions`
);
});
it('numbered text', () => {
assert.equal(
limaxProcessor('1. export creates'),
urlsafeSlugProcessor('1. export creates'),
`1${_}export${_}creates`
);
});
it('punctuated text', () => {
assert.equal(
limaxProcessor('svelte.VERSION'),
`svelte${_}version`
urlsafeSlugProcessor('svelte.VERSION'),
`svelte${_}VERSION`
);
});
it('text starting with the dollar sign', () => {
assert.equal(
limaxProcessor('$destroy method'),
urlsafeSlugProcessor('$destroy method'),
`$destroy${_}method`
);
});
it('numbered text containing the dollar sign', () => {
assert.equal(
limaxProcessor('1. export $destroy'),
urlsafeSlugProcessor('1. export $destroy'),
`1${_}export${_}$destroy`
);
});
it('text containing the equal char', () => {
assert.equal(
limaxProcessor('script context=module'),
urlsafeSlugProcessor('script context=module'),
`script${_}context${_}module`
);
});
it('text containing the colon char', () => {
assert.equal(
limaxProcessor('svelte:body'),
urlsafeSlugProcessor('svelte:body'),
`svelte${_}body`
);
});
it('text containing the slash char', () => {
assert.equal(
limaxProcessor('svelte/motion'),
urlsafeSlugProcessor('svelte/motion'),
`svelte${_}motion`
);
});
it('text containing the comma char', () => {
assert.equal(
limaxProcessor('svelte, motion'),
urlsafeSlugProcessor('svelte, motion'),
`svelte${_}motion`
);
});
@ -63,156 +63,150 @@ describe('slug', () => {
describe('unicode', () => {
it('should translate symbols to English', () => {
assert.equal(
limaxProcessor('Ich ♥ Deutsch'),
`ich${_}love${_}deutsch`
urlsafeSlugProcessor('Ich ♥ Deutsch'),
`Ich${_}love${_}Deutsch`
);
});
it('should remove emoji', () => {
assert.equal(
limaxProcessor('Ich 😍 Deutsch'),
`ich${_}deutsch`
);
});
it('should translate symbols to the given language (German)', () => {
assert.equal(
limaxProcessor('Ich ♥ Deutsch', 'de'),
`ich${_}liebe${_}deutsch`
urlsafeSlugProcessor('Ich 😍 Deutsch'),
`Ich${_}Deutsch`
);
});
});
describe('cyricllic', () => {
it('space separated words', () => {
assert.equal(
limaxProcessor('Всплытие и перехват событий'),
`vsplytie${_}i${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('Всплытие и перехват событий'),
`Vsplytie${_}i${_}perehvat${_}sobytij`
);
});
it('numbered text', () => {
assert.equal(
limaxProcessor('1 Всплытие и перехват событий'),
`1${_}vsplytie${_}i${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('1 Всплытие и перехват событий'),
`1${_}Vsplytie${_}i${_}perehvat${_}sobytij`
);
});
it('punctuated text', () => {
assert.equal(
limaxProcessor('.Всплытие.и.перехват событий'),
`vsplytie${_}i${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('.Всплытие.и.перехват событий'),
`Vsplytie${_}i${_}perehvat${_}sobytij`
);
});
it('text starting with the dollar sign', () => {
assert.equal(
limaxProcessor('$Всплытие $ перехват событий'),
`$vsplytie${_}$${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('$Всплытие $ перехват событий'),
`$Vsplytie${_}$${_}perehvat${_}sobytij`
);
});
it('text containing the dollar sign', () => {
assert.equal(
limaxProcessor('Всплытие$перехват'),
`vsplytie$perekhvat`
urlsafeSlugProcessor('Всплытие$перехват'),
`Vsplytie$perehvat`
);
});
it('text containing the equal char', () => {
assert.equal(
limaxProcessor('Всплытие = перехват=событий'),
`vsplytie${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('Всплытие = перехват=событий'),
`Vsplytie${_}perehvat${_}sobytij`
);
});
it('text containing the colon char', () => {
assert.equal(
limaxProcessor('Всплытие : перехват:событий'),
`vsplytie${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('Всплытие : перехват:событий'),
`Vsplytie${_}perehvat${_}sobytij`
);
});
it('text containing the slash char', () => {
assert.equal(
limaxProcessor('Всплытие / перехват/событий'),
`vsplytie${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('Всплытие / перехват/событий'),
`Vsplytie${_}perehvat${_}sobytij`
);
});
it('text containing the comma char', () => {
assert.equal(
limaxProcessor('Всплытие, перехват'),
`vsplytie${_}perekhvat`
urlsafeSlugProcessor('Всплытие, перехват'),
`Vsplytie${_}perehvat`
);
});
});
describe('ascii + cyricllic', () => {
it('space separated words', () => {
assert.equal(
limaxProcessor('Всплытие и export перехват событий'),
`vsplytie${_}i${_}export${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('Всплытие и export перехват событий'),
`Vsplytie${_}i${_}export${_}perehvat${_}sobytij`
);
});
it('ascii word concatenated to a cyricllic word', () => {
assert.equal(
limaxProcessor('exportВсплытие'),
'exportvsplytie'
urlsafeSlugProcessor('exportВсплытие'),
'exportVsplytie'
);
});
it('cyricllic word concatenated to an ascii word', () => {
assert.equal(
limaxProcessor('Всплытиеexport'),
`vsplytieexport`
urlsafeSlugProcessor('Всплытиеexport'),
`Vsplytieexport`
);
});
it('numbered text', () => {
assert.equal(
limaxProcessor('1 export Всплытие и перехват событий'),
`1${_}export${_}vsplytie${_}i${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('1 export Всплытие и перехват событий'),
`1${_}export${_}Vsplytie${_}i${_}perehvat${_}sobytij`
);
});
it('punctuated text', () => {
assert.equal(
limaxProcessor('.Всплытие.export.и.перехват событий'),
`vsplytie${_}export${_}i${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('.Всплытие.export.и.перехват событий'),
`Vsplytie${_}export${_}i${_}perehvat${_}sobytij`
);
});
it('text starting with the dollar sign, followed by ascii char', () => {
assert.equal(
limaxProcessor('$exportВсплытие перехват событий'),
`$exportvsplytie${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('$exportВсплытие перехват событий'),
`$exportVsplytie${_}perehvat${_}sobytij`
);
});
it('text starting with the dollar sign, followed by unicode char', () => {
assert.equal(
limaxProcessor('$Всплытие export перехват событий'),
`$vsplytie${_}export${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('$Всплытие export перехват событий'),
`$Vsplytie${_}export${_}perehvat${_}sobytij`
);
});
it('text containing the dollar sign, followed by ascii char', () => {
assert.equal(
limaxProcessor('export $destroy a component prop Всплытие и перехват событий'),
`export${_}$destroy${_}a${_}component${_}prop${_}vsplytie${_}i${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('export $destroy a component prop Всплытие и перехват событий'),
`export${_}$destroy${_}a${_}component${_}prop${_}Vsplytie${_}i${_}perehvat${_}sobytij`
);
});
it('text containing the dollar sign, followed by unicode char', () => {
assert.equal(
limaxProcessor('Всплытие export $Всплытие a component prop Всплытие и перехват событий'),
`vsplytie${_}export${_}$vsplytie${_}a${_}component${_}prop${_}vsplytie${_}i${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('Всплытие export $Всплытие a component prop Всплытие и перехват событий'),
`Vsplytie${_}export${_}$Vsplytie${_}a${_}component${_}prop${_}Vsplytie${_}i${_}perehvat${_}sobytij`
);
});
it('text containing the equal char', () => {
assert.equal(
limaxProcessor('script context=module Всплытие=и перехват событий'),
`script${_}context${_}module${_}vsplytie${_}i${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('script context=module Всплытие=и перехват событий'),
`script${_}context${_}module${_}Vsplytie${_}i${_}perehvat${_}sobytij`
);
});
it('text containing the colon char', () => {
assert.equal(
limaxProcessor('svelte:body Всплытие и:перехват событий'),
`svelte${_}body${_}vsplytie${_}i${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('svelte:body Всплытие и:перехват событий'),
`svelte${_}body${_}Vsplytie${_}i${_}perehvat${_}sobytij`
);
});
it('text containing the slash char', () => {
assert.equal(
limaxProcessor('svelte/motion Всплытие и / перехват/событий'),
`svelte${_}motion${_}vsplytie${_}i${_}perekhvat${_}sobytii`
urlsafeSlugProcessor('svelte/motion Всплытие и / перехват/событий'),
`svelte${_}motion${_}Vsplytie${_}i${_}perehvat${_}sobytij`
);
});
it('text containing the comma char', () => {
assert.equal(
limaxProcessor('Всплытие, export'),
`vsplytie${_}export`
urlsafeSlugProcessor('Всплытие, export'),
`Vsplytie${_}export`
);
});
});
@ -223,7 +217,7 @@ describe('slug', () => {
it('space separated words', () => {
assert.equal(
unicodeSafeProcessor('Text expressions'),
`text${_}expressions`
`Text${_}expressions`
);
});
it('numbered text', () => {
@ -235,7 +229,7 @@ describe('slug', () => {
it('punctuated text', () => {
assert.equal(
unicodeSafeProcessor('svelte.VERSION'),
`svelte${_}version`
`svelte${_}VERSION`
);
});
it('text starting with the dollar sign', () => {
@ -279,13 +273,13 @@ describe('slug', () => {
it('should preserve symbols', () => {
assert.equal(
unicodeSafeProcessor('Ich ♥ Deutsch'),
`ich${_}love${_}deutsch`
`Ich${_}love${_}Deutsch`
);
});
it('should remove emoji', () => {
assert.equal(
unicodeSafeProcessor('Ich 😍 Deutsch'),
`ich${_}deutsch`
`Ich${_}Deutsch`
);
});
});

@ -11,7 +11,9 @@ export default class CatchBlock extends AbstractBlock {
this.scope = scope.child();
this.scope.add(parent.error, parent.expression.dependencies, this);
this.children = map_children(component, parent, this.scope, info.children);
this.warn_if_empty_block();
if (!info.skip) {
this.warn_if_empty_block();
}
}
}

@ -7,6 +7,8 @@ export default class PendingBlock extends AbstractBlock {
super(component, parent, scope, info);
this.children = map_children(component, parent, scope, info.children);
this.warn_if_empty_block();
if (!info.skip) {
this.warn_if_empty_block();
}
}
}

@ -12,6 +12,8 @@ export default class ThenBlock extends AbstractBlock {
this.scope.add(parent.value, parent.expression.dependencies, this);
this.children = map_children(component, parent, this.scope, info.children);
this.warn_if_empty_block();
if (!info.skip) {
this.warn_if_empty_block();
}
}
}

@ -169,14 +169,15 @@ export default function dom(
scope = scope.parent;
}
if (node.type === 'AssignmentExpression') {
if (node.type === 'AssignmentExpression' || node.type === 'UpdateExpression') {
const assignee = node.type === 'AssignmentExpression' ? node.left : node.argument;
let names = [];
if (node.left.type === 'MemberExpression') {
const left_object_name = get_object(node.left).name;
if (assignee.type === 'MemberExpression') {
const left_object_name = get_object(assignee).name;
left_object_name && (names = [left_object_name]);
} else {
names = extract_names(node.left);
names = extract_names(assignee);
}
if (node.operator === '=' && nodes_match(node.left, node.right)) {
@ -189,9 +190,10 @@ export default function dom(
code.overwrite(node.start, node.end, dirty.map(n => component.invalidate(n)).join('; '));
} else {
const single = (
node.left.type === 'Identifier' &&
node.type === 'AssignmentExpression' &&
assignee.type === 'Identifier' &&
parent.type === 'ExpressionStatement' &&
node.left.name[0] !== '$'
assignee.name[0] !== '$'
);
names.forEach(name => {
@ -201,7 +203,7 @@ export default function dom(
const variable = component.var_lookup.get(name);
if (variable && (variable.hoistable || variable.global || variable.module)) return;
if (single) {
if (single && !(variable.subscribable && variable.reassigned)) {
code.prependRight(node.start, `$$invalidate('${name}', `);
code.appendLeft(node.end, `)`);
} else {
@ -213,18 +215,6 @@ export default function dom(
}
}
else if (node.type === 'UpdateExpression') {
const { name } = get_object(node.argument);
if (scope.find_owner(name) !== component.instance_scope) return;
const variable = component.var_lookup.get(name);
if (variable && variable.hoistable) return;
pending_assignments.add(name);
component.has_reactive_assignments = true;
}
if (pending_assignments.size > 0) {
if (node.type === 'ArrowFunctionExpression') {
const insert = Array.from(pending_assignments).map(name => component.invalidate(name)).join('; ');
@ -423,14 +413,15 @@ export default function dom(
${set && `$$self.$set = ${set};`}
${reactive_declarations.length > 0 && deindent`
${injected.length && `let ${injected.join(', ')};`}
${reactive_declarations.length > 0 && deindent`
$$self.$$.update = ($$dirty = { ${Array.from(all_reactive_dependencies).map(n => `${n}: 1`).join(', ')} }) => {
${reactive_declarations}
};
`}
${fixed_reactive_declarations}
`}
return ${stringify_props(filtered_declarations)};
}

@ -11,7 +11,7 @@ import Slot from './handlers/Slot';
import Tag from './handlers/Tag';
import Text from './handlers/Text';
import Title from './handlers/Title';
import { CompileOptions } from '../../interfaces';
import { AppendTarget, CompileOptions } from '../../interfaces';
type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void;
@ -36,8 +36,6 @@ const handlers: Record<string, Handler> = {
Window: noop
};
type AppendTarget = any; // TODO
export default class Renderer {
has_bindings = false;
code = '';

@ -4,8 +4,7 @@ import { snip } from '../../utils/snip';
import Renderer from '../Renderer';
import { stringify_props } from '../../utils/stringify_props';
import { get_slot_scope } from './shared/get_slot_scope';
type AppendTarget = any; // TODO
import { AppendTarget } from '../../../interfaces';
function stringify_attribute(chunk: Node) {
if (chunk.type === 'Text') {
@ -111,4 +110,4 @@ export default function(node, renderer: Renderer, options) {
const slots = stringify_props(slot_fns);
renderer.append(`\${@validate_component(${expression}, '${node.name}').$$render($$result, ${props}, ${bindings}, ${slots})}`);
}
}

@ -75,12 +75,10 @@ export class Scope {
if (node.kind === 'var' && this.block && this.parent) {
this.parent.add_declaration(node);
} else if (node.type === 'VariableDeclaration') {
const initialised = !!node.init;
node.declarations.forEach((declarator: Node) => {
extract_names(declarator.id).forEach(name => {
this.declarations.set(name, node);
if (initialised) this.initialised_declarations.add(name);
if (declarator.init) this.initialised_declarations.add(name);
});
});
} else {

@ -1,4 +1,5 @@
export { default as compile } from './compile/index';
export { default as parse } from './parse/index';
export { default as preprocess } from './preprocess/index';
export const VERSION = '__VERSION__';

@ -61,6 +61,11 @@ export interface CompileOptions {
preserveWhitespace?: boolean;
}
export interface ParserOptions {
filename?: string;
customElement?: boolean;
}
export interface Visitor {
enter: (node: Node) => void;
leave?: (node: Node) => void;

@ -3,7 +3,7 @@ export function append(target, node) {
}
export function insert(target, node, anchor) {
target.insertBefore(node, anchor);
target.insertBefore(node, anchor || null);
}
export function detach(node) {

@ -2,7 +2,7 @@ export function get_spread_update(levels, updates) {
const update = {};
const to_null_out = {};
const accounted_for = {};
const accounted_for = { $$scope: 1 };
let i = levels.length;
while (i--) {
@ -34,4 +34,4 @@ export function get_spread_update(levels, updates) {
}
return update;
}
}

@ -3,14 +3,9 @@ import fragment from './state/fragment';
import { whitespace } from '../utils/patterns';
import { reserved } from '../utils/names';
import full_char_code_at from '../utils/full_char_code_at';
import { Node, Ast } from '../interfaces';
import { Node, Ast, ParserOptions } from '../interfaces';
import error from '../utils/error';
interface ParserOptions {
filename?: string;
customElement?: boolean;
}
type ParserState = (parser: Parser) => (ParserState | void);
export class Parser {

@ -36,7 +36,7 @@ export default function mustache(parser: Parser) {
parser.allow_whitespace();
// {/if} or {/each}
// {/if}, {/each} or {/await}
if (parser.eat('/')) {
let block = parser.current();
let expected;
@ -172,7 +172,8 @@ export default function mustache(parser: Parser) {
start,
end: null,
type: 'ThenBlock',
children: []
children: [],
skip: false
};
await_block.then = then_block;
@ -196,7 +197,8 @@ export default function mustache(parser: Parser) {
start,
end: null,
type: 'CatchBlock',
children: []
children: [],
skip: false
};
await_block.catch = catch_block;
@ -235,19 +237,22 @@ export default function mustache(parser: Parser) {
start: null,
end: null,
type: 'PendingBlock',
children: []
children: [],
skip: true
},
then: {
start: null,
end: null,
type: 'ThenBlock',
children: []
children: [],
skip: true
},
catch: {
start: null,
end: null,
type: 'CatchBlock',
children: []
children: [],
skip: true
},
} :
{
@ -287,13 +292,6 @@ export default function mustache(parser: Parser) {
parser.allow_whitespace();
parser.eat(')', true);
parser.allow_whitespace();
} else if (parser.eat('@')) {
block.key = parser.read_identifier();
if (!block.key) parser.error({
code: `expected-name`,
message: `Expected name`
});
parser.allow_whitespace();
}
}
@ -310,7 +308,15 @@ export default function mustache(parser: Parser) {
parser.stack.push(block);
if (type === 'AwaitBlock') {
const child_block = await_block_shorthand ? block.then : block.pending;
let child_block;
if (await_block_shorthand) {
block.then.skip = false;
child_block = block.then;
} else {
block.pending.skip = false;
child_block = block.pending;
}
child_block.start = parser.index;
parser.stack.push(child_block);
}

@ -2,8 +2,10 @@ import { isIdentifierStart, isIdentifierChar } from 'acorn';
import full_char_code_at from './full_char_code_at';
export const globals = new Set([
'alert',
'Array',
'Boolean',
'confirm',
'console',
'Date',
'decodeURI',
@ -24,6 +26,7 @@ export const globals = new Set([
'parseInt',
'process',
'Promise',
'prompt',
'RegExp',
'Set',
'String',

@ -19,6 +19,7 @@
"pending": {
"start": 19,
"end": 39,
"skip": false,
"type": "PendingBlock",
"children": [
{
@ -53,6 +54,7 @@
"then": {
"start": 39,
"end": 88,
"skip": false,
"type": "ThenBlock",
"children": [
{
@ -98,6 +100,7 @@
"catch": {
"start": 88,
"end": 140,
"skip": false,
"type": "CatchBlock",
"children": [
{
@ -158,4 +161,4 @@
"css": null,
"instance": null,
"module": null
}
}

@ -0,0 +1,4 @@
<div>
<slot />
<div {...$$props}></div>
</div>

@ -0,0 +1,19 @@
export default {
html: `
<div>
<input />
<div class="foo"></div>
</div>
`,
async test({ assert, component, target }) {
component.value = 'foo';
assert.htmlEqual(target.innerHTML, `
<div>
<input />
<div class="foo"></div>
</div>
`);
}
};

@ -0,0 +1,8 @@
<script>
import Nested from './Nested.svelte';
export let value = '';
</script>
<Nested class="foo">
<input bind:value />
</Nested>

@ -1,5 +1,6 @@
<script>
export let value;
export let value_with_default = undefined;
</script>
<input bind:value>

@ -1,6 +1,7 @@
<script>
export let x;
export let y;
export let z = undefined;
</script>
<div>{x} {y}</div>

@ -0,0 +1,11 @@
export default {
html: `
<p>4</p>
`,
test({ assert, component, target }) {
assert.htmlEqual(target.innerHTML, `
<p>4</p>
`);
}
};

@ -0,0 +1,6 @@
<script>
const num = 2;
$: squared = num * num;
</script>
<p>{squared}</p>

@ -0,0 +1,8 @@
export default {
html: `0`,
async test({ assert, component, target }) {
await component.increment();
assert.htmlEqual(target.innerHTML, `1`);
}
};

@ -0,0 +1,11 @@
<script>
import { writable } from '../../../../store.js';
const foo = writable(0);
export function increment() {
$foo++;
}
</script>
{$foo}

@ -0,0 +1,3 @@
export default {
html: `42`,
};

@ -0,0 +1,7 @@
<script>
import { writable } from 'svelte/store';
let foo = writable(0);
foo = writable(42);
</script>
{$foo}

@ -0,0 +1,9 @@
<script>
let promise;
</script>
{#await promise}
<p>Loading</p>
{:then data}
<p>Data: {data}</p>
{/await}

@ -0,0 +1,7 @@
<script>
let promise;
</script>
{#await promise then data}
<p>Data: {data}</p>
{/await}
Loading…
Cancel
Save