this repo has no description
0
fork

Configure Feed

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

init commit with basic functionality

Graham Barber e2f0ed01

+335
+63
commands/dev.ts
··· 1 + import { Command } from "@cliffy/command"; 2 + import { Eta } from "@eta-dev/eta"; 3 + import { renderBody } from "../parse/render.ts"; 4 + 5 + const eta = new Eta({ views: Deno.cwd() + "/templates" }); 6 + 7 + export const dev = new Command() 8 + .arguments("<source:string>") 9 + .description("Serve, watch, and rebuild ") 10 + .action(async (_opts: unknown, source: string) => { 11 + await Promise.all([ 12 + watchFile(source), 13 + Deno.serve(makeHandler(source)), 14 + ]); 15 + }); 16 + 17 + async function watchFile(path: string) { 18 + const channel = openChannel(); 19 + const watcher = Deno.watchFs(path); 20 + 21 + for await (const _ of watcher) { 22 + channel.postMessage("change"); 23 + } 24 + } 25 + 26 + function openChannel() { 27 + return new BroadcastChannel("live-reload"); 28 + } 29 + 30 + function makeHandler(path: string) { 31 + const LIVE_RELOAD_ROUTE = new URLPattern({ pathname: "/live-reload" }); 32 + const channel = openChannel(); 33 + 34 + return async (req: Request) => { 35 + const match = LIVE_RELOAD_ROUTE.exec(req.url); 36 + 37 + if (match) { 38 + const upgrade = req.headers.get("upgrade") ?? ""; 39 + if (upgrade.toLowerCase() !== "websocket") { 40 + return new Response("no upgrade specified"); 41 + } 42 + 43 + const { socket, response } = Deno.upgradeWebSocket(req); 44 + 45 + channel.onmessage = () => { 46 + socket.send("reload"); 47 + }; 48 + 49 + return response; 50 + } 51 + 52 + return new Response( 53 + eta.render("live-reload", { body: await renderBody(path) }), 54 + { 55 + status: 200, 56 + headers: { 57 + "Content-Type": "text/html", 58 + "Cache-Control": "no-store", 59 + }, 60 + }, 61 + ); 62 + }; 63 + }
+11
deno.json
··· 1 + { 2 + "tasks": { 3 + "dev": "deno run --watch main.ts" 4 + }, 5 + "imports": { 6 + "@cliffy/command": "jsr:@cliffy/command@1.0.0-rc.8", 7 + "@eta-dev/eta": "jsr:@eta-dev/eta@^3.5.0", 8 + "@markdoc/markdoc": "https://esm.sh/@markdoc/markdoc@0.5.2" 9 + "@std/assert": "jsr:@std/assert@1" 10 + } 11 + }
+93
deno.lock
··· 1 + { 2 + "version": "5", 3 + "specifiers": { 4 + "jsr:@cliffy/command@1.0.0-rc.8": "1.0.0-rc.8", 5 + "jsr:@cliffy/flags@1.0.0-rc.8": "1.0.0-rc.8", 6 + "jsr:@cliffy/internal@1.0.0-rc.8": "1.0.0-rc.8", 7 + "jsr:@cliffy/table@1.0.0-rc.8": "1.0.0-rc.8", 8 + "jsr:@eta-dev/eta@^3.5.0": "3.5.0", 9 + "jsr:@std/assert@1": "1.0.13", 10 + "jsr:@std/fmt@~1.0.2": "1.0.8", 11 + "jsr:@std/internal@^1.0.6": "1.0.9", 12 + "jsr:@std/text@~1.0.7": "1.0.15", 13 + "npm:@markdoc/markdoc@*": "0.5.2" 14 + }, 15 + "jsr": { 16 + "@cliffy/command@1.0.0-rc.8": { 17 + "integrity": "758147790797c74a707e5294cc7285df665422a13d2a483437092ffce40b5557", 18 + "dependencies": [ 19 + "jsr:@cliffy/flags", 20 + "jsr:@cliffy/internal", 21 + "jsr:@cliffy/table", 22 + "jsr:@std/fmt", 23 + "jsr:@std/text" 24 + ] 25 + }, 26 + "@cliffy/flags@1.0.0-rc.8": { 27 + "integrity": "0f1043ce6ef037ba1cb5fe6b1bcecb25dc2f29371a1c17f278ab0f45e4b6f46c", 28 + "dependencies": [ 29 + "jsr:@std/text" 30 + ] 31 + }, 32 + "@cliffy/internal@1.0.0-rc.8": { 33 + "integrity": "34cdf2fad9b084b5aed493b138d573f52d4e988767215f7460daf0b918ff43d8" 34 + }, 35 + "@cliffy/table@1.0.0-rc.8": { 36 + "integrity": "8bbcdc2ba5e0061b4b13810a24e6f5c6ab19c09f0cce9eb691ccd76c7c6c9db5", 37 + "dependencies": [ 38 + "jsr:@std/fmt" 39 + ] 40 + }, 41 + "@eta-dev/eta@3.5.0": { 42 + "integrity": "6b70827efc14c7cbf08498ac7a922ecab003641caf3852a6cb5b1b12ee58fb37" 43 + }, 44 + "@std/assert@1.0.13": { 45 + "integrity": "ae0d31e41919b12c656c742b22522c32fb26ed0cba32975cb0de2a273cb68b29", 46 + "dependencies": [ 47 + "jsr:@std/internal" 48 + ] 49 + }, 50 + "@std/fmt@1.0.8": { 51 + "integrity": "71e1fc498787e4434d213647a6e43e794af4fd393ef8f52062246e06f7e372b7" 52 + }, 53 + "@std/internal@1.0.9": { 54 + "integrity": "bdfb97f83e4db7a13e8faab26fb1958d1b80cc64366501af78a0aee151696eb8" 55 + }, 56 + "@std/text@1.0.15": { 57 + "integrity": "91f5cc1e12779a3d95f1be34e763f9c28a75a078b7360e6fcaef0d8d9b1e3e7f" 58 + } 59 + }, 60 + "npm": { 61 + "@markdoc/markdoc@0.5.2": { 62 + "integrity": "sha512-clrqWpJ3+S8PXigRE+zBIs6LVZYXaJ7JTDFq1CcCWc4xpoB2kz+9qRUQQ4vXtLUjQ8ige1BGdMruV6gM/2gloA==", 63 + "optionalDependencies": [ 64 + "@types/linkify-it", 65 + "@types/markdown-it" 66 + ] 67 + }, 68 + "@types/linkify-it@3.0.5": { 69 + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==" 70 + }, 71 + "@types/markdown-it@12.2.3": { 72 + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", 73 + "dependencies": [ 74 + "@types/linkify-it", 75 + "@types/mdurl" 76 + ] 77 + }, 78 + "@types/mdurl@2.0.0": { 79 + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==" 80 + } 81 + }, 82 + "remote": { 83 + "https://esm.sh/@markdoc/markdoc@0.5.2": "76be956a8424e9b05c24b594a7714b39730fbd2b8e577db754606a211dfb4b89", 84 + "https://esm.sh/@markdoc/markdoc@0.5.2/denonext/markdoc.mjs": "3d8780797f37e2a81843a33cea9081ad7c500f49549badc6aee2b1bec5d97149" 85 + }, 86 + "workspace": { 87 + "dependencies": [ 88 + "jsr:@cliffy/command@1.0.0-rc.8", 89 + "jsr:@eta-dev/eta@^3.5.0", 90 + "jsr:@std/assert@1" 91 + ] 92 + } 93 + }
+9
main.ts
··· 1 + import { Command } from "@cliffy/command"; 2 + import { dev } from "./commands/dev.ts"; 3 + 4 + await new Command() 5 + .name("morkdeck") 6 + .version("0.0.0") 7 + .description("Turn Markdoc files into web-powered slide decks") 8 + .command("dev", dev) 9 + .parse();
+41
parse/render.ts
··· 1 + import Markdoc, { Config, Node } from "@markdoc/markdoc"; 2 + 3 + const config: Config = { 4 + tags: { 5 + slide: { 6 + render: "section", 7 + }, 8 + content: { 9 + render: "div", 10 + }, 11 + }, 12 + }; 13 + 14 + export async function renderBody(path: string) { 15 + const file = await Deno.readTextFile(path); 16 + const ast = Markdoc.parse(file); 17 + 18 + const groups: Node[][] = []; 19 + let currentGroup: Node[] = []; 20 + 21 + for (const child of ast.children) { 22 + if (child.type !== "hr") { 23 + currentGroup.push(child); 24 + } else { 25 + groups.push(currentGroup); 26 + currentGroup = []; 27 + } 28 + } 29 + 30 + groups.push(currentGroup); 31 + 32 + ast.children = groups.map((children) => 33 + new Node("tag", undefined, [ 34 + new Node("tag", undefined, children, "content"), 35 + ], "slide") 36 + ); 37 + 38 + const tree = Markdoc.transform(ast, config); 39 + 40 + return Markdoc.renderers.html(tree); 41 + }
+16
slides.mdoc
··· 1 + # Hello There 2 + 3 + This is my presentation 4 + 5 + --- 6 + 7 + ## Yes 8 + 9 + - A presentation 10 + - It has slides 11 + - It has bullets! 12 + 13 + --- 14 + 15 + ## Thank You 16 +
+102
templates/live-reload.eta
··· 1 + <!doctype html> 2 + <html> 3 + <head> 4 + <title>Dev</title> 5 + <link rel="preconnect" href="https://fonts.googleapis.com"> 6 + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 7 + <link href="https://fonts.googleapis.com/css2?family=Recursive:slnt,wght,CASL,CRSV,MONO@-15..0,300..1000,0..1,0..1,0..1&display=swap" rel="stylesheet"> 8 + 9 + <style> 10 + body { 11 + margin: 0; 12 + box-sizing: border-box; 13 + font-family: "Recursive", sans-serif; 14 + background-color: #191724; 15 + color: #e0def4; 16 + } 17 + 18 + article { 19 + width: 100vw; 20 + height: 100vh; 21 + overflow-y: scroll; 22 + scroll-behavior: smooth; 23 + scroll-snap-type: y mandatory; 24 + } 25 + 26 + section { 27 + width: 100%; 28 + height: 100%; 29 + scroll-snap-align: center; 30 + position: relative; 31 + } 32 + 33 + section div { 34 + container: slide / inline-size; 35 + box-sizing: border-box; 36 + position: absolute; 37 + inset: 0; 38 + margin: auto; 39 + aspect-ratio: 16 / 9; 40 + max-width: 100%; 41 + max-height: 100%; 42 + 43 + padding: 6cqmin; 44 + background: #1f1d2e; 45 + } 46 + 47 + h1 { 48 + font-size: 8cqi; 49 + margin: 0; 50 + font-weight: 900; 51 + } 52 + 53 + h2 { 54 + font-size: 6cqi; 55 + margin-top: 0; 56 + margin-bottom: 3cqi; 57 + font-weight: 900; 58 + } 59 + 60 + h1:first-of-type { 61 + font-size: 10cqi; 62 + margin-bottom: 3cqi; 63 + font-weight: 900; 64 + line-height: 0.8em; 65 + } 66 + 67 + h1:first-of-type ~ :is(h2, h3, h4, h5, h6, p) { 68 + font-size: 2.8cqi; 69 + font-weight: 600; 70 + color: #908caa; 71 + margin: 0; 72 + } 73 + 74 + div:has(h1:first-of-type) { 75 + display: flex; 76 + flex-direction: column; 77 + justify-content: end; 78 + } 79 + 80 + p, ul, ol { 81 + font-size: 3cqi; 82 + } 83 + </style> 84 + </head> 85 + <body> 86 + <%~ it.body %> 87 + <script> 88 + const src = new WebSocket("/live-reload") 89 + 90 + src.addEventListener("message", e => { 91 + if (e.data === "reload") { 92 + src.close() 93 + location.reload() 94 + } 95 + }) 96 + 97 + src.addEventListener("open", () => { 98 + console.log("live reload connected") 99 + }) 100 + </script> 101 + </body> 102 + </html>