feat: markdoc

This commit is contained in:
Torsten Dittmann
2023-09-04 19:03:26 +02:00
parent 6583ef1133
commit 3eb9e72db0
23 changed files with 768 additions and 7 deletions

12
markdoc.config.json Normal file
View File

@@ -0,0 +1,12 @@
[
{
"id": "appwrite",
"path": "src/",
"schema": {
"path": ".svelte-kit/markdoc_schema.js",
"type": "esm",
"property": "default",
"watch": true
}
}
]

View File

@@ -27,21 +27,23 @@
"eslint": "^8.28.0", "eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte": "^2.30.0", "eslint-plugin-svelte": "^2.30.0",
"oslllo-svg-fixer": "^2.2.0",
"prettier": "^2.8.0", "prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.10.1", "prettier-plugin-svelte": "^2.10.1",
"sass": "^1.65.1", "sass": "^1.65.1",
"svelte": "^4.0.5", "svelte": "^4.0.5",
"svelte-check": "^3.4.3", "svelte-check": "^3.4.3",
"svelte-markdoc-preprocess": "^0.3.0",
"svelte-sequential-preprocessor": "^2.0.1", "svelte-sequential-preprocessor": "^2.0.1",
"svgtofont": "^3.22.0",
"tslib": "^2.4.1", "tslib": "^2.4.1",
"typescript": "^5.0.0", "typescript": "^5.0.0",
"vite": "^4.4.2", "vite": "^4.4.2",
"vitest": "^0.32.2", "vitest": "^0.32.2"
"oslllo-svg-fixer": "^2.2.0",
"svgtofont": "^3.22.0"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@fontsource/inter": "^5.0.8" "@fontsource/inter": "^5.0.8",
"highlight.js": "^11.8.0"
} }
} }

87
pnpm-lock.yaml generated
View File

@@ -8,6 +8,12 @@ dependencies:
'@fontsource/inter': '@fontsource/inter':
specifier: ^5.0.8 specifier: ^5.0.8
version: 5.0.8 version: 5.0.8
highlight.js:
specifier: ^11.8.0
version: 11.8.0
shiki:
specifier: ^0.14.4
version: 0.14.4
devDependencies: devDependencies:
'@melt-ui/pp': '@melt-ui/pp':
@@ -58,6 +64,9 @@ devDependencies:
svelte-check: svelte-check:
specifier: ^3.4.3 specifier: ^3.4.3
version: 3.5.0(postcss@8.4.27)(sass@1.65.1)(svelte@4.2.0) version: 3.5.0(postcss@8.4.27)(sass@1.65.1)(svelte@4.2.0)
svelte-markdoc-preprocess:
specifier: ^0.3.0
version: 0.3.0
svelte-sequential-preprocessor: svelte-sequential-preprocessor:
specifier: ^2.0.1 specifier: ^2.0.1
version: 2.0.1 version: 2.0.1
@@ -799,6 +808,21 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/sourcemap-codec': 1.4.15
dev: true dev: true
/@markdoc/markdoc@0.3.2:
resolution: {integrity: sha512-D0SaanaSkTIARvQu+zQqPEpKcvYUBR/mfac9e8JzS89P7eXhiNWPonUN7avRS1saZHpIQWIRote97qT+jGk5Gw==}
engines: {node: '>=14.7.0'}
peerDependencies:
'@types/react': '*'
react: '*'
peerDependenciesMeta:
'@types/react':
optional: true
react:
optional: true
optionalDependencies:
'@types/markdown-it': 12.2.3
dev: true
/@melt-ui/pp@0.1.2(@melt-ui/svelte@0.40.0)(svelte@4.2.0): /@melt-ui/pp@0.1.2(@melt-ui/svelte@0.40.0)(svelte@4.2.0):
resolution: {integrity: sha512-GZeqp7UWLNZUC2dJpREnZrWMR88vy27WO7C3cIBz4KW3/CFD19FjNkd3VbSRfcRryrMkdnEs9nu2VUa8/0u58w==} resolution: {integrity: sha512-GZeqp7UWLNZUC2dJpREnZrWMR88vy27WO7C3cIBz4KW3/CFD19FjNkd3VbSRfcRryrMkdnEs9nu2VUa8/0u58w==}
engines: {pnpm: '>=8.6.3'} engines: {pnpm: '>=8.6.3'}
@@ -1134,6 +1158,25 @@ packages:
'@types/node': 20.5.0 '@types/node': 20.5.0
dev: true dev: true
/@types/linkify-it@3.0.3:
resolution: {integrity: sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g==}
dev: true
optional: true
/@types/markdown-it@12.2.3:
resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==}
requiresBuild: true
dependencies:
'@types/linkify-it': 3.0.3
'@types/mdurl': 1.0.2
dev: true
optional: true
/@types/mdurl@1.0.2:
resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==}
dev: true
optional: true
/@types/node@16.9.1: /@types/node@16.9.1:
resolution: {integrity: sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==} resolution: {integrity: sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==}
dev: true dev: true
@@ -1422,6 +1465,10 @@ packages:
engines: {node: '>=12'} engines: {node: '>=12'}
dev: true dev: true
/ansi-sequence-parser@1.1.1:
resolution: {integrity: sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==}
dev: false
/ansi-styles@4.3.0: /ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -2723,6 +2770,15 @@ packages:
kind-of: 4.0.0 kind-of: 4.0.0
dev: true dev: true
/highlight.js@11.8.0:
resolution: {integrity: sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg==}
engines: {node: '>=12.0.0'}
dev: false
/html-escaper@3.0.3:
resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==}
dev: true
/htmlparser2@8.0.2: /htmlparser2@8.0.2:
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
dependencies: dependencies:
@@ -3056,7 +3112,6 @@ packages:
/jsonc-parser@3.2.0: /jsonc-parser@3.2.0:
resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
dev: true
/jsonfile@6.1.0: /jsonfile@6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
@@ -4155,6 +4210,15 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/shiki@0.14.4:
resolution: {integrity: sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==}
dependencies:
ansi-sequence-parser: 1.1.1
jsonc-parser: 3.2.0
vscode-oniguruma: 1.7.0
vscode-textmate: 8.0.0
dev: false
/siginfo@2.0.0: /siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
dev: true dev: true
@@ -4459,6 +4523,19 @@ packages:
svelte: 4.2.0 svelte: 4.2.0
dev: true dev: true
/svelte-markdoc-preprocess@0.3.0:
resolution: {integrity: sha512-o1VisVNqRdeCTjYbhxtpsxGquujKT3Ksnk4ttdPxi2dWKFBO1IvtxGKiDudVMMI+s3mcsbu/uA/0bYfeqsf+DQ==}
dependencies:
'@markdoc/markdoc': 0.3.2
html-escaper: 3.0.3
js-yaml: 4.1.0
svelte: 4.2.0
typescript: 5.1.6
transitivePeerDependencies:
- '@types/react'
- react
dev: true
/svelte-preprocess@5.0.4(postcss@8.4.27)(sass@1.65.1)(svelte@4.2.0)(typescript@5.1.6): /svelte-preprocess@5.0.4(postcss@8.4.27)(sass@1.65.1)(svelte@4.2.0)(typescript@5.1.6):
resolution: {integrity: sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==} resolution: {integrity: sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==}
engines: {node: '>= 14.10.0'} engines: {node: '>= 14.10.0'}
@@ -5015,6 +5092,14 @@ packages:
- terser - terser
dev: true dev: true
/vscode-oniguruma@1.7.0:
resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==}
dev: false
/vscode-textmate@8.0.0:
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
dev: false
/which@2.0.2: /which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}

View File

@@ -0,0 +1,206 @@
<script context="module" lang="ts">
import { writable, type Writable } from 'svelte/store';
export type LayoutContext = Writable<
Record<string, {
text: string;
step?: number;
}>
>;
</script>
<script lang="ts">
import { Docs } from '$lib/layouts';
import Sidebar from '$routes/docs/Sidebar.svelte';
import { getContext, setContext } from 'svelte';
export let title: string;
export let difficulty: string;
export let readtime: string;
setContext<LayoutContext>('headings', writable({}));
const headings = getContext<LayoutContext>('headings');
</script>
<svelte:head>
<title>{title}</title>
</svelte:head>
<Docs variant="two-side-navs">
<Sidebar />
<main class="u-contents">
<article class="aw-article u-contents">
<header class="aw-article-header">
<div class="aw-article-header-start u-flex-vertical aw-u-cross-start">
<button
class="
aw-button is-text aw-is-only-mobile
aw-u-padding-block-0 aw-u-padding-inline-start-0 aw-u-padding-inline-end-12"
aria-label="previous page"
>
<span class="icon-cheveron-left" aria-hidden="true" />
</button>
<ul class="aw-metadata aw-caption-400">
{#if difficulty}
<li>{difficulty}</li>
{/if}
{#if readtime}
<li>{readtime} min</li>
{/if}
</ul>
<div class="u-position-relative u-flex u-cross-center">
<button
class="
aw-button is-text is-icon aw-u-cross-center aw-u-size-40
u-position-absolute u-inset-inline-start-0 aw-u-translate-x-negative"
aria-label="previous page"
>
<span
class="icon-cheveron-left aw-u-font-size-24 aw-u-color-text-primary"
aria-hidden="true"
/>
</button>
<h1 class="aw-title">{title}</h1>
</div>
</div>
<div class="aw-article-header-end" />
</header>
<div class="aw-article-content">
<slot />
<section class="aw-content-footer">
<header class="aw-content-footer-header">
<div class="aw-content-footer-header-start">
<h5 class="aw-main-body-500 aw-u-color-text-primary">Was this page helpful?</h5>
<div class="u-flex u-gap-8">
<input
class="aw-radio-button is-like"
type="radio"
aria-label="Helpful"
name="happy"
/>
<input
class="aw-radio-button is-dislike"
type="radio"
aria-label="UnHelpful"
name="happy"
/>
</div>
</div>
<div class="aw-content-footer-header-end">
<ul class="aw-metadata aw-caption-400">
<li>Last updated on July 16, 2023</li>
<li>
<button class="">
<!-- TODO: wait for implement icons in website -->
<span class="icon-edit" aria-hidden="true" />
<span>Update on GitHub</span>
</button>
</li>
</ul>
</div>
</header>
<div class="aw-card is-transparent" style="--card-padding:1rem">
<label for="message">
<span class="aw-u-color-text-primary">What did you like?</span>
<span class="">(optional)</span>
</label>
<textarea
class="aw-input-text u-margin-block-start-8"
id="message"
placeholder="Write your message"
/>
<div class="u-flex u-main-end u-margin-block-start-16">
<button class="aw-button is-text">
<span class="">Cancel</span>
</button>
<button class="aw-button">
<span class="">Submit</span>
</button>
</div>
</div>
</section>
</div>
<aside class="aw-references-menu aw-u-padding-inline-start-24">
<div class="aw-references-menu-content">
<div class="u-flex u-main-space-between u-cross-center u-gap-16">
<h5 class="aw-references-menu-title aw-eyebrow">On This Page</h5>
</div>
<ol class="aw-references-menu-list">
{#each Object.entries($headings) as [id, heading]}
<li class="aw-references-menu-item">
<a href={`#${id}`} class="aw-references-menu-link">
{#if heading.step !== undefined}
<span class="aw-numeric-badge">{heading.step}</span>
{/if}
<span class="aw-caption-400">{heading.text}</span>
</a>
</li>
{/each}
</ol>
<div class="u-sep-block-start u-padding-block-start-20">
<a class="aw-button is-text u-main-start aw-u-padding-inline-0" href=".">
<span class="icon-arrow-up" aria-hidden="true" />
<span class="aw-sub-body-500">Back to top</span>
</a>
</div>
</div>
</aside>
</article>
</main>
<footer class="aw-main-footer u-margin-block-start-48 u-small">
<div class="aw-main-footer-grid-1">
<ul class="aw-main-footer-grid-1-column-1 u-flex u-gap-8">
<li>
<button class="aw-icon-button" aria-label="Appwrite on Discord">
<span class="icon-discord" aria-hidden="true" />
</button>
</li>
<li>
<button class="aw-icon-button" aria-label="Appwrite GitHub">
<span class="icon-github" aria-hidden="true" />
</button>
</li>
<li>
<button class="aw-icon-button" aria-label="Appwrite on Twitter">
<span class="icon-twitter" aria-hidden="true" />
</button>
</li>
<li>
<button class="aw-icon-button" aria-label="Appwrite on LinkedIn">
<span class="icon-linkedin" aria-hidden="true" />
</button>
</li>
<li>
<button class="aw-icon-button" aria-label="Appwrite YouTube">
<span class="icon-youtube" aria-hidden="true" />
</button>
</li>
</ul>
<div class="aw-main-footer-grid-1-column-2">
<div class="aw-select is-colored">
<button class="physical-select">
<span class="icon-moon" aria-hidden="true" />
<span>Dark</span>
</button>
<span class="icon-cheveron-down" aria-hidden="true" />
</div>
</div>
<ul class="aw-main-footer-grid-1-column-3 aw-main-footer-links">
<li>
<a href=".">Supports</a>
</li>
<li>
<a href=".">Status</a>
</li>
<li>
<a href=".">Changelog</a>
</li>
</ul>
<div class="aw-main-footer-grid-1-column-4 aw-main-footer-copyright">
Copyright © 2023 Appwrite
</div>
</div>
</footer>
</Docs>

View File

@@ -0,0 +1,5 @@
<script lang="ts">
export let content: string;
</script>
<span class="aw-inline-code">{@html content}</span>

View File

@@ -0,0 +1,81 @@
<script context="module" lang="ts">
import 'highlight.js/styles/panda-syntax-dark.css';
import hljs from 'highlight.js/lib/core';
import dart from 'highlight.js/lib/languages/dart';
import javascript from 'highlight.js/lib/languages/javascript';
import typescript from 'highlight.js/lib/languages/typescript';
import xml from 'highlight.js/lib/languages/xml';
import shell from 'highlight.js/lib/languages/shell';
import markdown from 'highlight.js/lib/languages/markdown';
import json from 'highlight.js/lib/languages/json';
import swift from 'highlight.js/lib/languages/swift';
import php from 'highlight.js/lib/languages/php';
import { getContext, hasContext } from 'svelte';
import type { CodeContext } from '../tags/MultiCode.svelte';
hljs.registerLanguage('dart', dart);
hljs.registerLanguage('js', javascript);
hljs.registerLanguage('ts', typescript);
hljs.registerLanguage('xml', xml);
hljs.registerLanguage('html', xml);
hljs.registerLanguage('sh', shell);
hljs.registerLanguage('md', markdown);
hljs.registerLanguage('json', json);
hljs.registerLanguage('swift', swift);
hljs.registerLanguage('php', php);
</script>
<script lang="ts">
export let content: string;
export let language: string;
export let process: boolean;
const insideMultiCode = hasContext('multi-code');
const selected = insideMultiCode ? getContext<CodeContext>('multi-code').selected : null;
if (insideMultiCode) {
getContext<CodeContext>('multi-code').snippets.update((n) => {
n.add(language);
return n;
});
}
const result = process ? hljs.highlight(content, { language: language ?? 'sh' }).value : content;
</script>
{#if insideMultiCode}
{#if $selected === language}
<pre><code class={`language-${language}`}>{@html result}</code></pre>
{/if}
{:else}
<section class="aw-code-snippet" aria-label="code-snippet panel">
<header class="aw-code-snippet-header">
<div class="aw-code-snippet-header-start">
<div class="u-flex u-gap-16">
<div class="aw-tag"><span class="text">Default</span></div>
</div>
</div>
<div class="aw-code-snippet-header-end">
<ul class="buttons-list u-flex u-gap-8">
<li class="buttons-list-item u-flex u-cross-child-scenter">
<div class="aw-select">
<select>
<option value="Web SDK">Web SDK</option>
</select>
<span class="icon-cheveron-down" aria-hidden="true" />
</div>
</li>
<li class="buttons-list-item aw-u-padding-inline-start-20">
<button class="aw-icon-button" aria-label="copy code from code-snippet"
><span class="icon-duplicate" aria-hidden="true" /></button
>
</li>
</ul>
</div>
</header>
<div class="aw-code-snippet-content">
<pre><code class={`language-${language}`}>{@html result}</code></pre>
</div>
</section>
{/if}

View File

@@ -0,0 +1,34 @@
<script lang="ts">
import { getContext, hasContext, onMount } from 'svelte';
import type { LayoutContext } from '../layouts/Tutorial.svelte';
export let level: number;
export let id: string | undefined = undefined;
export let step: number | undefined = undefined;
const tag = `h${level}`;
let element: HTMLElement | undefined;
$: if (element && hasContext('headings')) {
getContext<LayoutContext>('headings').update((n) => {
if (id === undefined) {
return n;
}
n[id] = {
step,
text: element?.textContent ?? ''
};
return n;
});
}
</script>
<svelte:element
this={tag}
{id}
bind:this={element}
class="aw-main-body-500 aw-u-color-text-primary"
>
<slot />
</svelte:element>

View File

@@ -0,0 +1,9 @@
<script lang="ts">
export let src: string;
export let alt: string;
export let title: string;
</script>
<div class="aw-media">
<img {src} {alt} {title} loading="lazy" />
</div>

View File

@@ -0,0 +1,6 @@
<script lang="ts">
export let href: string;
export let title: string;
</script>
<a class="aw-link" {href} {title}><slot /></a>

View File

@@ -0,0 +1,5 @@
<script lang="ts">
export let ordered: boolean;
</script>
<svelte:element this={ordered ? 'ol' : 'ul'} class="aw-list"><slot /></svelte:element>

View File

@@ -0,0 +1 @@
<p class="aw-paragraph-md"><slot /></p>

View File

@@ -0,0 +1,7 @@
<div class="aw-table-wrapper">
<div class="aw-table-scroll">
<table class="aw-table">
<slot />
</table>
</div>
</div>

View File

@@ -0,0 +1,3 @@
<tbody class="aw-table-body">
<slot />
</tbody>

View File

@@ -0,0 +1,7 @@
<script lang="ts">
export let align: string;
</script>
<td class="aw-table-col">
<slot />
</td>

View File

@@ -0,0 +1,11 @@
<script lang="ts">
import type { HTMLThAttributes } from 'svelte/elements';
export let align: HTMLThAttributes['align'] = undefined;
</script>
<th class="aw-table-head-col" {align}>
<span class="aw-eyebrow">
<slot />
</span>
</th>

View File

@@ -0,0 +1,3 @@
<thead class="aw-table-header">
<slot />
</thead>

View File

@@ -0,0 +1,3 @@
<tr class="aw-table-row">
<slot />
</tr>

View File

@@ -0,0 +1,15 @@
<script context="module">
export { default as Code } from './Code.svelte';
export { default as Fence } from './Fence.svelte';
export { default as Heading } from './Heading.svelte';
export { default as List } from './List.svelte';
export { default as Paragraph } from './Paragraph.svelte';
export { default as Image } from './Image.svelte';
export { default as Link } from './Link.svelte';
export { default as Table } from './Table.svelte';
export { default as Tbody } from './Tbody.svelte';
export { default as Td } from './Td.svelte';
export { default as Th } from './Th.svelte';
export { default as Thead } from './Thead.svelte';
export { default as Tr } from './Tr.svelte';
</script>

View File

@@ -0,0 +1,55 @@
<script context="module" lang="ts">
import type { Writable } from 'svelte/store';
export type CodeContext = {
selected: Writable<string | null>;
snippets: Writable<Set<string>>;
};
</script>
<script lang="ts">
import { getContext, setContext } from 'svelte';
import { writable } from 'svelte/store';
setContext<CodeContext>('multi-code', {
selected: writable(null),
snippets: writable(new Set())
});
const { snippets, selected } = getContext<CodeContext>('multi-code');
snippets.subscribe(n => {
if ($selected === null && n.size > 0) {
$selected = Array.from(n)[0];
}
})
</script>
<section class="aw-code-snippet" aria-label="code-snippet panel">
<header class="aw-code-snippet-header">
<div class="aw-code-snippet-header-start">
<div class="u-flex u-gap-16">
<div class="aw-tag"><span class="text">Default</span></div>
</div>
</div>
<div class="aw-code-snippet-header-end">
<ul class="buttons-list u-flex u-gap-8">
<li class="buttons-list-item u-flex u-cross-child-scenter">
<div class="aw-select">
<select bind:value={$selected}>
{#each Array.from($snippets) as language}
<option value={language}>{language}</option>
{/each}
</select>
<span class="icon-cheveron-down" aria-hidden="true" />
</div>
</li>
<li class="buttons-list-item aw-u-padding-inline-start-20">
<button class="aw-icon-button" aria-label="copy code from code-snippet"
><span class="icon-duplicate" aria-hidden="true" /></button
>
</li>
</ul>
</div>
</header>
<div class="aw-code-snippet-content"><slot /></div>
</section>

View File

@@ -0,0 +1,19 @@
<script lang="ts">
import Heading from '../nodes/Heading.svelte';
export let id: string;
export let step: number;
export let title: string;
</script>
<section class="aw-article-content-section is-with-line">
<section class="aw-article-content-sub-section">
<header class="aw-article-content-header">
<span class="aw-numeric-badge">{step}</span>
<Heading level={2} {id} {step}>
{title}
</Heading>
</header>
<slot />
</section>
</section>

View File

@@ -0,0 +1,4 @@
<script context="module">
export { default as Section } from './Section.svelte';
export { default as MultiCode } from './MultiCode.svelte';
</script>

View File

@@ -0,0 +1,168 @@
---
title: Hello world
difficulty: beginner
readtime: 3
---
Text can be **bold**, _italic_, ~~strikethrough~~or a [link to another page](#).
There should be whitespace between paragraphs.
There should be whitespace between paragraphs. We recommend including a README, or a file with information about your project.
# Header 1 {% #header-1 %}
This is a normal paragraph following a header. GitHub is a code hosting platform for version control and collaboration. It lets you and others work together on projects from anywhere.
## Header 2 {% #header-2 %}
> This is a blockquote following a header.
>
> When something is important enough, you do it even if the odds are not in your favor.
### Header 3 {% #header-3 %}
This is a fenced codeblock:
```js
// Javascript code with syntax highlighting.
const cars = ["BMW", "Volvo", "Mini"];
let text = "";
for (let x of cars) {
text += x + " ";
}
```
And you can also have `inline code`.
#### Header 4
* This is an unordered list following a header.
* This is an unordered list following a header.
* This is an unordered list following a header.
##### Header 5
1. This is an ordered list following a header.
1. This is an ordered list following a header.
1. This is an ordered list following a header.
###### Header 6
This is a nice table:
| head1 | head two | three |
| ----------------- | ----------------- | ----------------- |
| ok | good swedish fish | nice |
| out of stock | good and plenty | nice |
| ok | good `oreos` | hmm |
| ok | good `zoute` drop | yumm |
### There's a horizontal rule below this.
---
### And a nested list:
- level 1 item
- level 2 item
- level 2 item
- level 3 item
- level 3 item
- level 1 item
- level 2 item
- level 2 item
- level 2 item
- level 1 item
- level 2 item
- level 2 item
- level 1 item
### Image
![](https://pink.appwrite.io/articles/announcement.png)
{% section #featured-products-1 step=1 title="Featured products 1" %}
Lorem ipsum dolor sit amet consectetur. Id nisi quam nisl iaculis semper nibh egestas ut. Dictum tortor arcu feugiat metus pellentesque posuere.
{% /section %}
{% section #featured-products-2 step=2 title="Featured products 2" %}
Lorem ipsum dolor sit amet consectetur. Id nisi quam nisl iaculis semper nibh egestas ut. Dictum tortor arcu feugiat metus pellentesque posuere.
## Sub title
{% multicode %}
```js
const sdk = require('node-appwrite');
const client = new sdk.Client();
const users = new sdk.Users(client);
client
.setEndpoint('https://cloud.appwrite.io/v1')
.setProject('5df5acd0d48c2')
.setKey('919c2d18fb5d4...a2ae413da83346ad2');
const promise = users.create('[USER_ID]');
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
});
```
```php
<?php
use Appwrite\Client;
use Appwrite\Services\Users;
$client = new Client();
$client
->setEndpoint('https://cloud.appwrite.io/v1')
->setProject('5df5acd0d48c2')
->setKey('919c2d18fb5d4...a2ae413da83346ad2');
$users = new Users($client);
$result = $users->create('[USER_ID]');
```
```swift
import Appwrite
func main() async throws {
let client = Client()
.setEndpoint("https://cloud.appwrite.io/v1")
.setProject("5df5acd0d48c2")
.setKey("919c2d18fb5d4...a2ae413da83346ad2")
let users = Users(client)
let user = try await users.create(
userId: "[USER_ID]"
)
print(String(describing: user)
}
```
{% /multicode %}
## Sub title
Lorem ipsum dolor sit amet consectetur. Id nisi quam nisl iaculis semper nibh egestas ut. Dictum tortor arcu feugiat metus pellentesque posuere.
{% /section %}
{% section #featured-products-3 step=3 title="Featured products 3" %}
Lorem ipsum dolor sit amet consectetur. Id nisi quam nisl iaculis semper nibh egestas ut. Dictum tortor arcu feugiat metus pellentesque posuere.
## Sub title
Lorem ipsum dolor sit amet consectetur. Id nisi quam nisl iaculis semper nibh egestas ut. Dictum tortor arcu feugiat metus pellentesque posuere.
## Sub title
Lorem ipsum dolor sit amet consectetur. Id nisi quam nisl iaculis semper nibh egestas ut. Dictum tortor arcu feugiat metus pellentesque posuere.
{% /section %}

View File

@@ -1,12 +1,32 @@
import { dirname, join } from "path";
import { fileURLToPath } from "url";
import { vitePreprocess } from '@sveltejs/kit/vite';
import { preprocessMeltUI } from '@melt-ui/pp'; import { preprocessMeltUI } from '@melt-ui/pp';
import { markdoc } from 'svelte-markdoc-preprocess';
import sequence from 'svelte-sequential-preprocessor'; import sequence from 'svelte-sequential-preprocessor';
import adapter from '@sveltejs/adapter-auto'; import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';
function absoulute (path) {
return join(dirname(fileURLToPath(import.meta.url)), path)
}
/** @type {import('@sveltejs/kit').Config}*/ /** @type {import('@sveltejs/kit').Config}*/
const config = { const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors // Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors // for more information about preprocessors
preprocess: sequence([vitePreprocess(), preprocessMeltUI()]), preprocess: sequence([
vitePreprocess(),
markdoc({
generateSchema: true,
nodes: absoulute('./src/markdoc/nodes/_Module.svelte'),
tags: absoulute('./src/markdoc/tags/_Module.svelte'),
layouts: {
default: absoulute('./src/markdoc/layouts/Tutorial.svelte'),
}
}),
preprocessMeltUI()
]),
extensions: ['.markdoc', '.svelte'],
kit: { kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter. // If your environment is not supported or you settled on a specific environment, switch out the adapter.