mp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +206 -0
- data/exe/mp +6 -0
- data/lib/mp/app.rb +158 -0
- data/lib/mp/browser.rb +119 -0
- data/lib/mp/cdp.rb +119 -0
- data/lib/mp/cli.rb +36 -0
- data/lib/mp/deck.rb +268 -0
- data/lib/mp/frame_unblocker.rb +77 -0
- data/lib/mp/server.rb +224 -0
- data/lib/mp/slide_renderer.rb +184 -0
- data/lib/mp/terminal.rb +41 -0
- data/lib/mp/version.rb +5 -0
- data/lib/mp/web_socket.rb +49 -0
- data/lib/mp.rb +12 -0
- data/public/app.js +306 -0
- data/public/index.html +37 -0
- data/public/presenter.css +33 -0
- data/public/presenter.html +41 -0
- data/public/presenter.js +168 -0
- data/public/slides.js +35 -0
- data/public/style.css +93 -0
- data/themes/dark.css +26 -0
- data/themes/default.css +27 -0
- data/vendor/assets/katex/LICENSE +21 -0
- data/vendor/assets/katex/auto-render.min.js +1 -0
- data/vendor/assets/katex/fonts/KaTeX_AMS-Regular.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_AMS-Regular.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-Bold.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-Bold.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-Italic.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-Italic.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-Regular.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-Regular.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Math-Italic.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Math-Italic.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Script-Regular.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Script-Regular.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size1-Regular.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size1-Regular.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size2-Regular.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size2-Regular.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size3-Regular.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size3-Regular.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size4-Regular.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size4-Regular.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- data/vendor/assets/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- data/vendor/assets/katex/katex.min.css +1 -0
- data/vendor/assets/katex/katex.min.js +1 -0
- data/vendor/assets/xterm/LICENSE +21 -0
- data/vendor/assets/xterm/addon-fit.js +2 -0
- data/vendor/assets/xterm/xterm.css +285 -0
- data/vendor/assets/xterm/xterm.js +2 -0
- metadata +230 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="ja">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>発表者ビュー</title>
|
|
6
|
+
<link rel="stylesheet" href="_mp/vendor/katex/katex.min.css">
|
|
7
|
+
<link rel="stylesheet" href="_mp/style.css">
|
|
8
|
+
<style id="theme"></style>
|
|
9
|
+
<style id="deck-style"></style>
|
|
10
|
+
<link rel="stylesheet" href="_mp/presenter.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body class="presenter">
|
|
13
|
+
<div class="pane current-pane">
|
|
14
|
+
<div class="label">現在 <span id="page"></span></div>
|
|
15
|
+
<div class="frame" id="current-frame">
|
|
16
|
+
<div class="stage" id="current"></div>
|
|
17
|
+
<img id="mirror" alt="聴衆画面" hidden>
|
|
18
|
+
</div>
|
|
19
|
+
<div id="script" hidden></div>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="pane next-pane">
|
|
22
|
+
<div class="label">次</div>
|
|
23
|
+
<div class="frame" id="next-frame">
|
|
24
|
+
<div class="stage" id="next"></div>
|
|
25
|
+
<div id="end" hidden>最後のスライドです</div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="pane notes-pane">
|
|
29
|
+
<div class="label">ノート</div>
|
|
30
|
+
<div id="speaker-notes"></div>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="status">
|
|
33
|
+
<span id="elapsed">00:00</span>
|
|
34
|
+
<span id="clock"></span>
|
|
35
|
+
<span class="hints">→ 次へ ・ ← 前へ ・ Enter コマンド実行 ・ r タイマー ・ +/- ノート文字 ・ q 終了</span>
|
|
36
|
+
</div>
|
|
37
|
+
<script src="_mp/vendor/katex/katex.min.js"></script>
|
|
38
|
+
<script src="_mp/slides.js"></script>
|
|
39
|
+
<script src="_mp/presenter.js"></script>
|
|
40
|
+
</body>
|
|
41
|
+
</html>
|
data/public/presenter.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const $ = (id) => document.getElementById(id);
|
|
4
|
+
const FRAME_INTERVAL = 250;
|
|
5
|
+
|
|
6
|
+
let deck = null;
|
|
7
|
+
let state = { slide: 0, step: 0, script: null, ready: false };
|
|
8
|
+
let digits = "";
|
|
9
|
+
let startedAt = Date.now();
|
|
10
|
+
let noteSize = 26;
|
|
11
|
+
let mirrorRunning = false;
|
|
12
|
+
let mirrorSlide = null;
|
|
13
|
+
|
|
14
|
+
const socket = new WebSocket(`ws://${location.host}${location.pathname.replace(/presenter$/, "")}_mp/events?role=presenter`);
|
|
15
|
+
const send = (message) => {
|
|
16
|
+
if (socket.readyState === WebSocket.OPEN) socket.send(JSON.stringify(message));
|
|
17
|
+
};
|
|
18
|
+
const command = (cmd, args = {}) => send({ type: "command", cmd, ...args });
|
|
19
|
+
|
|
20
|
+
async function loadDeck() {
|
|
21
|
+
deck = await MpSlides.load($("current"), [$("current"), $("next")]);
|
|
22
|
+
document.title = `発表者ビュー - ${deck.title}`;
|
|
23
|
+
for (const stage of [$("current"), $("next")]) {
|
|
24
|
+
stage.querySelectorAll(".embed").forEach(describeEmbed);
|
|
25
|
+
}
|
|
26
|
+
layout();
|
|
27
|
+
render();
|
|
28
|
+
send({ type: "hello" });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ターミナルや Web は聴衆画面にだけ実体があるので、ここでは内容の説明を出す
|
|
32
|
+
function describeEmbed(el) {
|
|
33
|
+
const embed = deck.embeds[el.dataset.embed];
|
|
34
|
+
const text = document.createElement("pre");
|
|
35
|
+
text.className = "embed-summary";
|
|
36
|
+
text.textContent = embed.type === "terminal" ? ["ターミナル", ...embed.commands.map((c) => `$ ${c}`)].join("\n") : `Web\n${embed.src}`;
|
|
37
|
+
el.append(text);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function layout() {
|
|
41
|
+
if (!deck) return;
|
|
42
|
+
for (const [stage, frame] of [[$("current"), $("current-frame")], [$("next"), $("next-frame")]]) {
|
|
43
|
+
const box = frame.getBoundingClientRect();
|
|
44
|
+
const scale = Math.min(box.width / deck.size[0], box.height / deck.size[1]);
|
|
45
|
+
stage.style.transform = `translate(${(box.width - deck.size[0] * scale) / 2}px, ${(box.height - deck.size[1] * scale) / 2}px) scale(${scale})`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function showOn(stage, slide, step) {
|
|
50
|
+
[...stage.children].forEach((el, index) => {
|
|
51
|
+
el.classList.toggle("active", index === slide);
|
|
52
|
+
if (index === slide) {
|
|
53
|
+
el.querySelectorAll(".fragment").forEach((item, i) => item.classList.toggle("shown", i < step));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function render() {
|
|
59
|
+
if (!deck) return;
|
|
60
|
+
const { slide, step, script, ready } = state;
|
|
61
|
+
const stage = $("current");
|
|
62
|
+
const section = stage.children[slide];
|
|
63
|
+
if (!section) return;
|
|
64
|
+
showOn(stage, slide, step);
|
|
65
|
+
|
|
66
|
+
// 表示されていない項目が残っていれば、次に見えるのは同じスライドの次の項目
|
|
67
|
+
const fragments = section.querySelectorAll(".fragment").length;
|
|
68
|
+
const last = slide === deck.slides.length - 1;
|
|
69
|
+
const done = last && step >= fragments;
|
|
70
|
+
if (step < fragments) showOn($("next"), slide, step + 1);
|
|
71
|
+
else if (!last) showOn($("next"), slide + 1, 0);
|
|
72
|
+
$("next").hidden = done;
|
|
73
|
+
$("end").hidden = !done;
|
|
74
|
+
|
|
75
|
+
$("page").textContent = `${slide + 1} / ${deck.slides.length}`;
|
|
76
|
+
$("speaker-notes").textContent = deck.slides[slide].notes;
|
|
77
|
+
renderScript(script, ready);
|
|
78
|
+
updateMirror(section);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function renderScript(script, ready) {
|
|
82
|
+
$("script").hidden = script === null;
|
|
83
|
+
if (script === null) return;
|
|
84
|
+
if (!script.length) $("script").textContent = "台本のコマンドはすべて実行しました";
|
|
85
|
+
else $("script").textContent = `${ready ? "Enter で実行" : "入力待ち"}: ${script[0]}`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 実体のある埋め込みは、聴衆画面をそのまま映す
|
|
89
|
+
function updateMirror(section) {
|
|
90
|
+
const hasEmbed = !!section.querySelector(".embed");
|
|
91
|
+
if (mirrorSlide !== state.slide) $("mirror").hidden = true; // 前のスライドの画面を残さない
|
|
92
|
+
mirrorSlide = hasEmbed ? state.slide : null;
|
|
93
|
+
if (hasEmbed && !mirrorRunning) {
|
|
94
|
+
mirrorRunning = true;
|
|
95
|
+
send({ type: "frame" });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function onFrame(data) {
|
|
100
|
+
mirrorRunning = false;
|
|
101
|
+
if (mirrorSlide === null) return;
|
|
102
|
+
$("mirror").src = `data:image/jpeg;base64,${data}`;
|
|
103
|
+
$("mirror").hidden = false;
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
if (mirrorSlide !== null && !mirrorRunning) {
|
|
106
|
+
mirrorRunning = true;
|
|
107
|
+
send({ type: "frame" });
|
|
108
|
+
}
|
|
109
|
+
}, FRAME_INTERVAL);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function tick() {
|
|
113
|
+
const seconds = Math.floor((Date.now() - startedAt) / 1000);
|
|
114
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
115
|
+
$("elapsed").textContent = `${seconds >= 3600 ? `${Math.floor(seconds / 3600)}:` : ""}${pad(Math.floor(seconds / 60) % 60)}:${pad(seconds % 60)}`;
|
|
116
|
+
$("clock").textContent = new Date().toLocaleTimeString("ja-JP", { hour: "2-digit", minute: "2-digit" });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function setNoteSize(size) {
|
|
120
|
+
noteSize = Math.min(Math.max(size, 14), 60);
|
|
121
|
+
$("speaker-notes").style.fontSize = `${noteSize}px`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
window.addEventListener("keydown", (event) => {
|
|
125
|
+
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
|
126
|
+
const actions = {
|
|
127
|
+
ArrowRight: () => command("next"), ArrowDown: () => command("next"), PageDown: () => command("next"), " ": () => command("next"),
|
|
128
|
+
ArrowLeft: () => command("prev"), ArrowUp: () => command("prev"), PageUp: () => command("prev"),
|
|
129
|
+
Home: () => command("first"),
|
|
130
|
+
End: () => command("last"),
|
|
131
|
+
r: () => { startedAt = Date.now(); tick(); },
|
|
132
|
+
"+": () => setNoteSize(noteSize + 2),
|
|
133
|
+
"=": () => setNoteSize(noteSize + 2),
|
|
134
|
+
"-": () => setNoteSize(noteSize - 2),
|
|
135
|
+
q: () => send({ type: "quit" }),
|
|
136
|
+
};
|
|
137
|
+
if (/^\d$/.test(event.key)) {
|
|
138
|
+
digits += event.key;
|
|
139
|
+
} else if (event.key === "Enter") {
|
|
140
|
+
event.preventDefault();
|
|
141
|
+
if (digits) command("goto", { slide: Number(digits) - 1 });
|
|
142
|
+
else command("run");
|
|
143
|
+
digits = "";
|
|
144
|
+
} else if (actions[event.key]) {
|
|
145
|
+
event.preventDefault();
|
|
146
|
+
digits = "";
|
|
147
|
+
actions[event.key]();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
socket.onopen = () => send({ type: "hello" });
|
|
152
|
+
socket.onmessage = (event) => {
|
|
153
|
+
const message = JSON.parse(event.data);
|
|
154
|
+
if (message.type === "state") {
|
|
155
|
+
state = message;
|
|
156
|
+
render();
|
|
157
|
+
} else if (message.type === "frame") {
|
|
158
|
+
onFrame(message.data);
|
|
159
|
+
} else if (message.type === "reload") {
|
|
160
|
+
loadDeck();
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
window.addEventListener("resize", layout);
|
|
165
|
+
setInterval(tick, 1000);
|
|
166
|
+
tick();
|
|
167
|
+
setNoteSize(noteSize);
|
|
168
|
+
loadDeck();
|
data/public/slides.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// 聴衆画面と発表者ビューで共通のスライド読み込み
|
|
4
|
+
const MpSlides = {
|
|
5
|
+
async load(stage, stages = [stage]) {
|
|
6
|
+
const deck = await (await fetch("_mp/deck.json", { cache: "no-store" })).json();
|
|
7
|
+
document.getElementById("theme").textContent = deck.themeCss;
|
|
8
|
+
document.getElementById("deck-style").textContent = deck.style;
|
|
9
|
+
for (const target of stages) {
|
|
10
|
+
target.style.width = `${deck.size[0]}px`;
|
|
11
|
+
target.style.height = `${deck.size[1]}px`;
|
|
12
|
+
target.innerHTML = deck.slides.map((slide) => slide.html).join("");
|
|
13
|
+
target.querySelectorAll(".math").forEach((el) => {
|
|
14
|
+
katex.render(el.dataset.tex, el, { displayMode: el.dataset.display === "true", throwOnError: false });
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
await document.fonts.ready;
|
|
18
|
+
stages.forEach((target) => MpSlides.fitHeadings(target));
|
|
19
|
+
document.title = deck.title;
|
|
20
|
+
return deck;
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
// `# <!-- fit --> 見出し` を横幅いっぱいにする
|
|
24
|
+
fitHeadings(stage) {
|
|
25
|
+
stage.querySelectorAll(".fit").forEach((heading) => {
|
|
26
|
+
const span = document.createElement("span");
|
|
27
|
+
span.style.whiteSpace = "nowrap";
|
|
28
|
+
span.append(...heading.childNodes);
|
|
29
|
+
heading.append(span);
|
|
30
|
+
const available = heading.clientWidth;
|
|
31
|
+
const size = parseFloat(getComputedStyle(heading).fontSize);
|
|
32
|
+
heading.style.fontSize = `${Math.floor(size * (available / span.offsetWidth) * 0.98)}px`;
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
};
|
data/public/style.css
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
html, body { margin: 0; height: 100%; background: #000; overflow: hidden; }
|
|
2
|
+
|
|
3
|
+
#stage { position: absolute; left: 50%; top: 50%; overflow: hidden; }
|
|
4
|
+
|
|
5
|
+
section.slide {
|
|
6
|
+
--pad: 72px;
|
|
7
|
+
position: absolute;
|
|
8
|
+
inset: 0;
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
padding: 56px var(--pad);
|
|
13
|
+
padding-left: calc(var(--split-left, 0%) + var(--pad));
|
|
14
|
+
padding-right: calc(var(--split-right, 0%) + var(--pad));
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
visibility: hidden;
|
|
17
|
+
}
|
|
18
|
+
section.slide.active { visibility: visible; }
|
|
19
|
+
|
|
20
|
+
section.slide.cover, section.slide.lead { justify-content: center; }
|
|
21
|
+
section.slide.lead { text-align: center; align-items: center; }
|
|
22
|
+
|
|
23
|
+
/* 見出しの下を 2 列にする: <!-- _class: columns --> */
|
|
24
|
+
section.slide.columns {
|
|
25
|
+
display: grid;
|
|
26
|
+
grid-template-columns: 1fr 1fr;
|
|
27
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
28
|
+
gap: 0 24px;
|
|
29
|
+
}
|
|
30
|
+
section.slide.columns > h2 { grid-column: 1 / -1; }
|
|
31
|
+
|
|
32
|
+
.fragment { visibility: hidden; }
|
|
33
|
+
.fragment.shown { visibility: inherit; }
|
|
34
|
+
|
|
35
|
+
.bg-layer { position: absolute; top: 0; bottom: 0; display: flex; z-index: 0; }
|
|
36
|
+
.bg-image { flex: 1; background-position: center; background-repeat: no-repeat; }
|
|
37
|
+
section.slide > :not(.bg-layer, header, footer, .page-number) { position: relative; z-index: 1; }
|
|
38
|
+
|
|
39
|
+
section.slide > header, section.slide > footer, section.slide > .page-number {
|
|
40
|
+
position: absolute;
|
|
41
|
+
left: var(--pad);
|
|
42
|
+
right: var(--pad);
|
|
43
|
+
z-index: 2;
|
|
44
|
+
font-size: 18px;
|
|
45
|
+
opacity: .65;
|
|
46
|
+
}
|
|
47
|
+
section.slide > header { top: 20px; }
|
|
48
|
+
section.slide > footer { bottom: 20px; }
|
|
49
|
+
section.slide > .page-number { bottom: 20px; left: auto; right: 32px; }
|
|
50
|
+
|
|
51
|
+
.embed {
|
|
52
|
+
position: relative;
|
|
53
|
+
flex: 1;
|
|
54
|
+
min-height: 0;
|
|
55
|
+
min-width: 0;
|
|
56
|
+
margin: 12px 0 24px;
|
|
57
|
+
border-radius: 10px;
|
|
58
|
+
overflow: hidden;
|
|
59
|
+
background: #14161b;
|
|
60
|
+
box-sizing: border-box;
|
|
61
|
+
}
|
|
62
|
+
.terminal-host { position: fixed; z-index: 5; overflow: hidden; }
|
|
63
|
+
.terminal-host .xterm { height: 100%; }
|
|
64
|
+
.terminal-host .xterm-viewport { background: transparent !important; scrollbar-width: none; }
|
|
65
|
+
.embed-web { background: #fff; }
|
|
66
|
+
.embed-web iframe { width: 100%; height: 100%; border: 0; display: block; }
|
|
67
|
+
.shield {
|
|
68
|
+
position: absolute;
|
|
69
|
+
inset: 0;
|
|
70
|
+
width: 100%;
|
|
71
|
+
height: 100%;
|
|
72
|
+
border: 0;
|
|
73
|
+
padding: 0;
|
|
74
|
+
background: transparent;
|
|
75
|
+
cursor: pointer;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.highlight pre, pre.highlight { margin: 0 0 .55em; }
|
|
79
|
+
|
|
80
|
+
#notes, #help {
|
|
81
|
+
position: fixed;
|
|
82
|
+
z-index: 10;
|
|
83
|
+
box-sizing: border-box;
|
|
84
|
+
background: rgba(15, 17, 22, .94);
|
|
85
|
+
color: #f2f2f2;
|
|
86
|
+
font: 18px/1.6 "Hiragino Sans", system-ui, sans-serif;
|
|
87
|
+
}
|
|
88
|
+
#notes { left: 0; right: 0; bottom: 0; max-height: 35%; overflow: auto; padding: 16px 28px; white-space: pre-wrap; }
|
|
89
|
+
#help { top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 20px 32px; border-radius: 12px; }
|
|
90
|
+
#help h3 { margin: 0 0 12px; }
|
|
91
|
+
#help dl { display: grid; grid-template-columns: auto auto; gap: 4px 28px; margin: 0; }
|
|
92
|
+
#help dd { margin: 0; opacity: .8; }
|
|
93
|
+
[hidden] { display: none !important; }
|
data/themes/dark.css
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/* mp-dark */
|
|
2
|
+
section {
|
|
3
|
+
background: #12151c;
|
|
4
|
+
color: #e9ecf2;
|
|
5
|
+
font: 30px/1.55 "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP", system-ui, sans-serif;
|
|
6
|
+
--accent: #6ea8ff;
|
|
7
|
+
--muted: #222834;
|
|
8
|
+
}
|
|
9
|
+
section h1 { font-size: 68px; line-height: 1.2; margin: 0 0 .3em; }
|
|
10
|
+
section h2 { font-size: 44px; line-height: 1.25; margin: 0 0 .5em; padding-bottom: .2em; border-bottom: 3px solid var(--accent); }
|
|
11
|
+
section h3 { font-size: 34px; margin: .5em 0 .3em; }
|
|
12
|
+
section p, section ul, section ol, section blockquote, section table { margin: 0 0 .55em; }
|
|
13
|
+
section ul, section ol { padding-left: 1.2em; }
|
|
14
|
+
section li { margin: .15em 0; }
|
|
15
|
+
section a, section strong { color: var(--accent); }
|
|
16
|
+
section img { max-width: 100%; }
|
|
17
|
+
section code { font: .86em Menlo, monospace; background: var(--muted); padding: .1em .3em; border-radius: 5px; }
|
|
18
|
+
section pre { background: var(--muted); padding: 18px 22px; border-radius: 10px; overflow: hidden; line-height: 1.4; }
|
|
19
|
+
section pre code { background: none; padding: 0; font-size: 24px; }
|
|
20
|
+
section blockquote { border-left: 6px solid var(--accent); padding-left: .7em; color: #a7afbf; }
|
|
21
|
+
section table { border-collapse: collapse; }
|
|
22
|
+
section th, section td { border: 1px solid #3a4252; padding: .3em .7em; }
|
|
23
|
+
section th { background: var(--muted); }
|
|
24
|
+
|
|
25
|
+
section.cover h1 { color: var(--accent); }
|
|
26
|
+
section.invert { background: #f6f7fa; color: #1f2430; --muted: #e7eaf0; }
|
data/themes/default.css
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* mp default theme */
|
|
2
|
+
section {
|
|
3
|
+
background: #fff;
|
|
4
|
+
color: #1f2430;
|
|
5
|
+
font: 30px/1.55 "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP", system-ui, sans-serif;
|
|
6
|
+
--accent: #2563c9;
|
|
7
|
+
--muted: #f1f3f7;
|
|
8
|
+
}
|
|
9
|
+
section h1 { font-size: 68px; line-height: 1.2; margin: 0 0 .3em; }
|
|
10
|
+
section h2 { font-size: 44px; line-height: 1.25; margin: 0 0 .5em; padding-bottom: .2em; border-bottom: 3px solid var(--accent); }
|
|
11
|
+
section h3 { font-size: 34px; margin: .5em 0 .3em; }
|
|
12
|
+
section p, section ul, section ol, section blockquote, section table { margin: 0 0 .55em; }
|
|
13
|
+
section ul, section ol { padding-left: 1.2em; }
|
|
14
|
+
section li { margin: .15em 0; }
|
|
15
|
+
section a { color: var(--accent); }
|
|
16
|
+
section strong { color: var(--accent); }
|
|
17
|
+
section img { max-width: 100%; }
|
|
18
|
+
section code { font: .86em Menlo, monospace; background: var(--muted); padding: .1em .3em; border-radius: 5px; }
|
|
19
|
+
section pre { background: var(--muted); padding: 18px 22px; border-radius: 10px; overflow: hidden; line-height: 1.4; }
|
|
20
|
+
section pre code { background: none; padding: 0; font-size: 24px; }
|
|
21
|
+
section blockquote { border-left: 6px solid var(--accent); padding-left: .7em; color: #5a6272; }
|
|
22
|
+
section table { border-collapse: collapse; }
|
|
23
|
+
section th, section td { border: 1px solid #d5dae3; padding: .3em .7em; }
|
|
24
|
+
section th { background: var(--muted); }
|
|
25
|
+
|
|
26
|
+
section.cover h1 { color: var(--accent); }
|
|
27
|
+
section.invert { background: #161a22; color: #eef0f4; --muted: #262c38; }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2013-2020 Khan Academy and other contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,function(e){return function(){"use strict";var t={757:function(t){t.exports=e}},n={};function r(e){var o=n[e];if(void 0!==o)return o.exports;var i=n[e]={exports:{}};return t[e](i,i.exports,r),i.exports}r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,{a:t}),t},r.d=function(e,t){for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)};var o={};r.d(o,{default:function(){return p}});var i=r(757),a=r.n(i);const l=function(e,t,n){let r=n,o=0;const i=e.length;for(;r<t.length;){const n=t[r];if(o<=0&&t.slice(r,r+i)===e)return r;"\\"===n?r++:"{"===n?o++:"}"===n&&o--,r++}return-1},s=/^\\begin{/;var d=function(e,t){let n;const r=[],o=new RegExp("("+t.map(e=>e.left.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")).join("|")+")");for(;n=e.search(o),-1!==n;){n>0&&(r.push({type:"text",data:e.slice(0,n)}),e=e.slice(n));const o=t.findIndex(t=>e.startsWith(t.left));if(n=l(t[o].right,e,t[o].left.length),-1===n)break;const i=e.slice(0,n+t[o].right.length),a=s.test(i)?i:e.slice(t[o].left.length,n);r.push({type:"math",data:a,rawData:i,display:t[o].display}),e=e.slice(n+t[o].right.length)}return""!==e&&r.push({type:"text",data:e}),r};const c=function(e,t){const n=d(e,t.delimiters);if(1===n.length&&"text"===n[0].type)return null;const r=document.createDocumentFragment();for(let e=0;e<n.length;e++)if("text"===n[e].type)r.appendChild(document.createTextNode(n[e].data));else{const o=document.createElement("span");let i=n[e].data;t.displayMode=n[e].display;try{t.preProcess&&(i=t.preProcess(i)),a().render(i,o,t)}catch(o){if(!(o instanceof a().ParseError))throw o;t.errorCallback("KaTeX auto-render: Failed to parse `"+n[e].data+"` with ",o),r.appendChild(document.createTextNode(n[e].rawData));continue}r.appendChild(o)}return r},f=function(e,t){for(let o=0;o<e.childNodes.length;o++){const i=e.childNodes[o];if(3===i.nodeType){var n;let a=null!=(n=i.textContent)?n:"",l=i.nextSibling,s=0;for(;l&&l.nodeType===Node.TEXT_NODE;){var r;a+=null!=(r=l.textContent)?r:"",l=l.nextSibling,s++}const d=c(a,t);if(d){for(let e=0;e<s;e++)i.nextSibling.remove();o+=d.childNodes.length-1,e.replaceChild(d,i)}else o+=s}else if(1===i.nodeType){const e=" "+i.className+" ";!t.ignoredTags.has(i.nodeName.toLowerCase())&&t.ignoredClasses.every(t=>!e.includes(" "+t+" "))&&f(i,t)}}};var p=function(e,t){if(!e)throw new Error("No element provided to render");const n={};Object.assign(n,t),n.delimiters=n.delimiters||[{left:"$$",right:"$$",display:!0},{left:"\\(",right:"\\)",display:!1},{left:"\\begin{equation}",right:"\\end{equation}",display:!0},{left:"\\begin{align}",right:"\\end{align}",display:!0},{left:"\\begin{alignat}",right:"\\end{alignat}",display:!0},{left:"\\begin{gather}",right:"\\end{gather}",display:!0},{left:"\\begin{CD}",right:"\\end{CD}",display:!0},{left:"\\[",right:"\\]",display:!0}],n.ignoredTags=new Set((null==t?void 0:t.ignoredTags)||["script","noscript","style","textarea","pre","code","option"]),n.ignoredClasses=n.ignoredClasses||[],n.errorCallback=n.errorCallback||console.error,n.macros=n.macros||{},f(e,n)};return o=o.default}()});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|