(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(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 '