(function () { "use strict"; var src = document.getElementById("src"); var slideEl = document.getElementById("slide"); var counterEl = document.getElementById("counter"); var barEl = document.getElementById("bar"); var wrap = document.getElementById("wrap"); var prevBtn = document.getElementById("prev"); var nextBtn = document.getElementById("next"); var copyBtn = document.getElementById("copy"); var SAMPLE = [ "# .mdeck", "## Slides from plain text", "", "This deck is the demo, and its source is in the editor: change a word there and watch this slide change.", "", "---", "# Why", "## A deck shouldn't take longer than the meeting", "", "- Dragging boxes isn't the job", "- Your words are the job", "- So type them, and let the slides follow", "", "---", "# How it works", "", "- `#` for a title, `##` for a subtitle", "- `-` for a point like this one", "- **bold**, *italic* and `code` work inline", "- `---` on its own line starts a new slide", "", "Any other line is a paragraph, like this one.", "", "---", "# Free, right now", "", "- This editor and the live preview", "- Arrow keys or swipe to present", "- **Copy deck as HTML**: one file that opens in any browser", "- Nothing is saved or sent: your deck stays in this tab", "", "---", "# Who it's for", "", "Anyone who'd rather type a deck than drag one: the weekly update, the demo, the talk, the class notes.", "", "---", "# Pro, if you want more", "", "- Saved decks and themes", "- Speaker notes", "- PDF export and a shareable link", "- **$5/mo**, the founding price", "", "Pro isn't built yet, and nothing is charged today.", "", "---", "# Your turn", "", "Select everything in the editor, delete it, and type your own.", "Or [get early access to Pro](https://github.com/teahubxyz/time/issues/new?template=early-access.yml&title=Early+access%3A+.mdeck&venture=mdecks&plan=Pro)." ].join("\n"); function esc(s) { return s.replace(/&/g, "&").replace(//g, ">"); } function inline(s) { var out = esc(s); out = out.replace(/\*\*([^*]+)\*\*/g, "$1"); out = out.replace(/\*([^*]+)\*/g, "$1"); out = out.replace(/`([^`]+)`/g, "$1"); // Handle links - only http and https out = out.replace(/\[([^\]]+)\]\((https?:\/\/[^)\s\"'<>]+)\)/g, '$1'); return out; } // Split raw text into slides on lines that are only "---". function splitSlides(text) { var lines = text.split(/\r?\n/); var slides = [[]]; for (var i = 0; i < lines.length; i++) { if (/^\s*---+\s*$/.test(lines[i])) { slides.push([]); } else { slides[slides.length - 1].push(lines[i]); } } return slides; } // Render one slide's lines to HTML. function renderSlide(lines) { var html = ""; var inList = false; var hasContent = false; for (var i = 0; i < lines.length; i++) { var line = lines[i]; var t = line.trim(); if (t === "") { if (inList) { html += ""; inList = false; } continue; } hasContent = true; if (t.indexOf("## ") === 0) { if (inList) { html += ""; inList = false; } html += "

" + inline(t.slice(3)) + "

"; } else if (t.indexOf("# ") === 0) { if (inList) { html += ""; inList = false; } html += "

" + inline(t.slice(2)) + "

"; } else if (t.indexOf("- ") === 0 || t.indexOf("* ") === 0) { if (!inList) { html += ""; inList = false; } html += "

" + inline(line) + "

"; } } if (inList) html += ""; if (!hasContent) html = '

(empty slide)

'; return html; } var slides = []; var current = 0; function parse() { slides = splitSlides(src.value); if (slides.length === 0) slides = [[]]; if (current >= slides.length) current = slides.length - 1; if (current < 0) current = 0; render(); } function render() { slideEl.innerHTML = renderSlide(slides[current]); counterEl.textContent = (current + 1) + " / " + slides.length; var pct = slides.length <= 1 ? 100 : (current / (slides.length - 1)) * 100; barEl.style.width = pct + "%"; prevBtn.disabled = current === 0; nextBtn.disabled = current === slides.length - 1; } function go(delta) { var next = current + delta; if (next < 0 || next > slides.length - 1) return; current = next; render(); } src.addEventListener("input", parse); prevBtn.addEventListener("click", function () { go(-1); }); nextBtn.addEventListener("click", function () { go(1); }); document.addEventListener("keydown", function (e) { if (e.target === src) return; // don't steal keys while typing if (e.key === "ArrowRight" || e.key === "PageDown" || e.key === " ") { e.preventDefault(); go(1); } else if (e.key === "ArrowLeft" || e.key === "PageUp") { e.preventDefault(); go(-1); } else if (e.key === "Home") { current = 0; render(); } else if (e.key === "End") { current = slides.length - 1; render(); } }); // Swipe navigation. var touchX = null; wrap.addEventListener("touchstart", function (e) { touchX = e.touches[0].clientX; }, { passive: true }); wrap.addEventListener("touchend", function (e) { if (touchX === null) return; var dx = e.changedTouches[0].clientX - touchX; if (Math.abs(dx) > 40) go(dx < 0 ? 1 : -1); touchX = null; }, { passive: true }); // Build the self-contained export deck. function buildExport() { var slidesHtml = slides.map(function (s) { return '
' + renderSlide(s) + "
"; }).join("\n"); return "\n\n\n\n" + "\n" + "Deck — .mdeck\n\n\n\n
\n
\n" + slidesHtml + "\n
\n
\n