this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(runtime): sync current url to displayed slide

Upgrades the wrapper components to Lit for easy custom web components.

+137 -39
+16 -5
core/markdoc-config.ts
··· 1 - import { Config } from "@markdoc/markdoc"; 1 + import { Config, Node, nodes, Tag } from "@markdoc/markdoc"; 2 2 import { createFenceNode } from "./nodes/fence.ts"; 3 3 import type { Includes } from "./types.ts"; 4 4 5 5 export function createMarkdocConfig() { 6 6 const includes: Includes = new Set(); 7 + let slideNum = 0; 7 8 const config: Config = { 8 9 tags: { 9 10 slide: { 10 - render: "section", 11 - }, 12 - content: { 13 - render: "div", 11 + render: "morkdeck-slide", 12 + async transform(node, config) { 13 + slideNum++; 14 + 15 + return new Tag( 16 + "morkdeck-slide", 17 + { id: `slide-${slideNum}` }, 18 + await Promise.resolve(node.transformChildren(config)), 19 + ); 20 + }, 14 21 }, 15 22 }, 16 23 nodes: { 17 24 fence: createFenceNode(includes), 25 + document: { 26 + ...nodes.document, 27 + render: "morkdeck-presentation", 28 + }, 18 29 }, 19 30 }; 20 31
+1 -3
core/renderer.ts
··· 27 27 groups.push(currentGroup); 28 28 29 29 ast.children = groups.map((children) => 30 - new Node("tag", undefined, [ 31 - new Node("tag", undefined, children, "content"), 32 - ], "slide") 30 + new Node("tag", undefined, children, "slide") 33 31 ); 34 32 35 33 const { config, includes } = createMarkdocConfig();
+61
templates/components/presentation.eta
··· 1 + <script type="module"> 2 + import { LitElement, html, css } from 'lit'; 3 + 4 + class Presentation extends LitElement { 5 + static styles = css` 6 + :host { 7 + display: block; 8 + width: 100vw; 9 + height: 100vh; 10 + overflow-y: scroll; 11 + scroll-behavior: smooth; 12 + scroll-snap-type: y mandatory; 13 + } 14 + ` 15 + 16 + constructor() { 17 + super() 18 + 19 + this.observer = new IntersectionObserver(this.updateUrl, { 20 + root: this, 21 + threshold: 1 22 + }) 23 + } 24 + 25 + connectedCallback() { 26 + super.connectedCallback() 27 + document.addEventListener("readystatechange", e => { 28 + if (event.target.readyState === "complete") { 29 + const url = new URL(document.URL) 30 + 31 + if (url.hash) { 32 + document.querySelector(url.hash).scrollIntoView({ behavior: "instant"}) 33 + } 34 + 35 + document.querySelectorAll("morkdeck-slide").forEach(e => this.observer.observe(e)) 36 + } 37 + }) 38 + } 39 + 40 + updateUrl(entries) { 41 + for (const entry of entries) { 42 + if (entry.isIntersecting) { 43 + const url = new URL(document.URL) 44 + const id = entry.target.getAttribute("id") 45 + 46 + url.hash = `#${id}` 47 + 48 + location.replace(url.toString()) 49 + 50 + break; 51 + } 52 + } 53 + } 54 + 55 + render () { 56 + return html`<slot></slot>` 57 + } 58 + } 59 + 60 + customElements.define("morkdeck-presentation", Presentation) 61 + </script>
+44
templates/components/slide.eta
··· 1 + <script type="module"> 2 + import { LitElement, html, css } from 'lit'; 3 + 4 + class Slide extends LitElement { 5 + static styles = css` 6 + :host { 7 + display: block; 8 + width: 100%; 9 + height: 100%; 10 + scroll-snap-align: center; 11 + position: relative; 12 + } 13 + 14 + :host > section { 15 + container: slide / inline-size; 16 + box-sizing: border-box; 17 + position: absolute; 18 + inset: 0; 19 + margin: auto; 20 + aspect-ratio: 16 / 9; 21 + max-width: 100%; 22 + max-height: 100%; 23 + 24 + display: flex; 25 + flex-direction: column; 26 + justify-content: center; 27 + align-items: center; 28 + 29 + padding: 6cqmin; 30 + background: #1f1d2e; 31 + } 32 + ` 33 + 34 + render() { 35 + return html` 36 + <section> 37 + <slot></slot> 38 + </section> 39 + ` 40 + } 41 + } 42 + 43 + customElements.define("morkdeck-slide", Slide) 44 + </script>
+7
templates/partials/importmap.eta
··· 1 + <script type="importmap"> 2 + { 3 + "imports": { 4 + "lit": "https://cdn.jsdelivr.net/gh/lit/dist@3/core/lit-core.min.js" 5 + } 6 + } 7 + </script>
+4 -31
templates/partials/slide-styles.eta
··· 22 22 margin: 0; 23 23 } 24 24 25 + ul, ol { 26 + padding-left: 0; 27 + } 28 + 25 29 pre { 26 30 margin: 0; 27 31 font-variation-settings: "MONO" 1; ··· 34 38 } 35 39 36 40 article { 37 - width: 100vw; 38 - height: 100vh; 39 - overflow-y: scroll; 40 - scroll-behavior: smooth; 41 - scroll-snap-type: y mandatory; 42 - } 43 - 44 - section { 45 - width: 100%; 46 - height: 100%; 47 - scroll-snap-align: center; 48 - position: relative; 49 - } 50 - 51 - section > div { 52 - container: slide / inline-size; 53 - box-sizing: border-box; 54 - position: absolute; 55 - inset: 0; 56 - margin: auto; 57 - aspect-ratio: 16 / 9; 58 - max-width: 100%; 59 - max-height: 100%; 60 - 61 - display: flex; 62 - flex-direction: column; 63 - justify-content: center; 64 - align-items: center; 65 - 66 - padding: 6cqmin; 67 - background: #1f1d2e; 68 41 } 69 42 70 43 h1 {
+4
templates/presentation.eta
··· 4 4 <title><%= it.title || (it.devMode ? "Dev" : "Presentation") %></title> 5 5 6 6 <%~ include("./partials/slide-styles") %> 7 + 8 + <%~ include("./partials/importmap") %> 9 + <%~ include("./components/presentation") %> 10 + <%~ include("./components/slide") %> 7 11 </head> 8 12 <body> 9 13 <%~ it.body %>