orz-slides 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.
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Builds the self-contained `.slides.html` shell:
3
+ * <head> reveal.js CSS + KaTeX CSS + the slide theme (inline or CDN link)
4
+ * + the editor chrome styles
5
+ * <body> an empty .reveal/.slides container, the editor chrome (FAB + docked
6
+ * CodeMirror panel + banners), the embedded deck source in
7
+ * <script id="orz-deck">, the engine bundle (inline or CDN), a config
8
+ * object, the boot call, and the in-file app (assets/app.js).
9
+ *
10
+ * The deck source in #orz-deck is the single source of truth: the engine renders
11
+ * it on load, and the editor re-serialises it on save (self-reproducing).
12
+ */
13
+ /** Prevent an embedded `</script>` in user content from closing the block. */
14
+ function escapeForScript(s) {
15
+ return s.replace(/<\/(script)/gi, '<\\/$1');
16
+ }
17
+ function escapeHtml(s) {
18
+ return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
19
+ }
20
+ const CHROME_CSS = `
21
+ html, body { margin: 0; height: 100%; }
22
+ html { --orz-vsplit: 42%; }
23
+ .reveal { height: 100%; }
24
+ [data-mode="edit"] .reveal { height: calc(100% - var(--orz-vsplit)); }
25
+
26
+ /* Edit control — a circular, theme-tinted button (color = --accent) that
27
+ app.js positions just above reveal's left/right arrows, reading as part of
28
+ the control cluster. The unused up/down arrows are hidden to make room. */
29
+ .reveal .controls .navigate-up, .reveal .controls .navigate-down { display: none; }
30
+ .orz-edit-ctrl {
31
+ position: fixed; left: 24px; bottom: 18px; z-index: 30;
32
+ width: 40px; height: 40px; padding: 0; box-sizing: border-box;
33
+ border: 0; border-radius: 50%;
34
+ background: rgba(130,130,130,.16);
35
+ background: color-mix(in srgb, var(--accent, #888) 16%, transparent);
36
+ color: var(--accent, #888); cursor: pointer;
37
+ display: flex; align-items: center; justify-content: center;
38
+ font-size: 19px; line-height: 1; opacity: .85;
39
+ transition: opacity .15s, transform .15s, background .15s;
40
+ }
41
+ .orz-edit-ctrl:hover {
42
+ opacity: 1; transform: scale(1.1);
43
+ background: color-mix(in srgb, var(--accent, #888) 30%, transparent);
44
+ }
45
+ [data-mode="edit"] .orz-edit-ctrl { display: none; }
46
+ .orz-edit-ctrl svg { width: 19px; height: 19px; display: block; }
47
+
48
+ #orz-panel {
49
+ display: flex; flex-direction: column;
50
+ position: fixed; left: 0; right: 0; bottom: 0; height: var(--orz-vsplit); z-index: 40;
51
+ background: #1f2228; border-top: 1px solid #333; box-shadow: 0 -2px 16px rgba(0,0,0,.3);
52
+ transform: translateY(calc(100% + 28px)); transition: transform .22s ease;
53
+ }
54
+ [data-mode="edit"] #orz-panel { transform: translateY(0); }
55
+ /* vertical resize handle on the panel's top edge (drag to set editor/deck split) */
56
+ #orz-vdivider { position: absolute; top: 0; left: 0; right: 0; height: 6px; z-index: 44; cursor: row-resize; }
57
+ #orz-vdivider:hover, #orz-vdivider.dragging { background: #3b82f6; }
58
+ /* close tab — a small handle on the editor's top edge that slides it away */
59
+ #orz-close {
60
+ position: absolute; top: -19px; left: 50%; transform: translateX(-50%);
61
+ width: 50px; height: 19px; z-index: 46; padding: 0;
62
+ display: inline-flex; align-items: center; justify-content: center;
63
+ border: 0; border-radius: 8px 8px 0 0; background: #23262c; color: #c2c8d0;
64
+ cursor: pointer; box-shadow: 0 -2px 8px rgba(0,0,0,.18);
65
+ }
66
+ #orz-close:hover { background: #383d45; color: #fff; }
67
+ #orz-close svg { width: 15px; height: 15px; display: block; }
68
+ #orz-toolbar {
69
+ display: flex; align-items: center; gap: 3px; flex-wrap: wrap;
70
+ padding: 7px 10px; background: #23262c; border-bottom: 1px solid #34383f;
71
+ }
72
+ #orz-toolbar .ic {
73
+ width: 32px; height: 30px; padding: 0; display: inline-flex; align-items: center; justify-content: center;
74
+ background: transparent; border: 0; border-radius: 7px; color: #c2c8d0; cursor: pointer;
75
+ transition: background .12s, color .12s;
76
+ }
77
+ #orz-toolbar .ic:hover { background: #383d45; color: #fff; }
78
+ #orz-toolbar .ic:active { transform: translateY(1px); }
79
+ #orz-toolbar .ic svg { width: 17px; height: 17px; display: block; }
80
+ #orz-toolbar .ic.primary { background: #3b82f6; color: #fff; }
81
+ #orz-toolbar .ic.primary:hover { background: #2f6fe0; }
82
+ #orz-toolbar .ic.active { background: #3b82f6; color: #fff; }
83
+ #orz-toolbar .ic.danger:hover { background: #b4434333; color: #ff8a8a; }
84
+ #orz-toolbar select {
85
+ font: 500 12.5px/1 system-ui, sans-serif; color: #e6e8ec; background: #34383f;
86
+ border: 1px solid #454b55; border-radius: 7px; padding: 6px 8px; cursor: pointer; margin: 0 2px;
87
+ }
88
+ #orz-toolbar #orz-copy { font: 500 11px/1 system-ui, sans-serif; color: #6b7480; text-decoration: none;
89
+ padding: 0 4px; white-space: nowrap; }
90
+ #orz-toolbar #orz-copy:hover { color: #cdd3df; }
91
+ #orz-toolbar .orz-sep { width: 1px; height: 20px; background: #3c414a; margin: 0 5px; }
92
+ #orz-toolbar .orz-pos { color: #9aa3b2; font: 600 12px/1 system-ui, sans-serif; padding: 0 4px; min-width: 40px; text-align: center; }
93
+ #orz-toolbar .orz-spacer { flex: 1; }
94
+ #orz-toolbar #orz-brand {
95
+ display: inline-flex; align-items: center; gap: 6px; text-decoration: none;
96
+ color: #cdd3df; padding: 2px 7px; border-radius: 7px;
97
+ }
98
+ #orz-toolbar #orz-brand:hover { color: #fff; background: #383d45; }
99
+ #orz-toolbar #orz-brand .orz-logo svg { height: 22px; width: auto; display: block; }
100
+ #orz-toolbar #orz-brand .orz-brand-name { font: 700 13px/1 system-ui, sans-serif; letter-spacing: .01em; }
101
+ #orz-toolbar #orz-brand .orz-gh { display: inline-flex; opacity: .55; }
102
+ #orz-toolbar #orz-brand:hover .orz-gh { opacity: 1; }
103
+ #orz-toolbar #orz-brand .orz-gh svg { width: 15px; height: 15px; display: block; }
104
+ #orz-editor-host { flex: 1; min-height: 0; overflow: hidden; }
105
+ #orz-editor-host .CodeMirror { height: 100%; font-size: 14px; }
106
+ #orz-ta { width: 100%; height: 100%; box-sizing: border-box; border: 0; padding: 10px;
107
+ font: 14px/1.5 ui-monospace, Menlo, Consolas, monospace; }
108
+
109
+ .orz-banner {
110
+ position: fixed; left: 50%; top: 14px; transform: translateX(-50%); z-index: 60;
111
+ display: none; align-items: center; gap: 10px;
112
+ background: #2b2f36; color: #eee; border: 1px solid #444; border-radius: 8px;
113
+ padding: 9px 14px; font: 13px/1.3 system-ui, sans-serif; box-shadow: 0 4px 16px rgba(0,0,0,.3);
114
+ }
115
+ .orz-banner.show { display: flex; }
116
+ .orz-banner button { font: 500 12.5px system-ui, sans-serif; color: #e6e8ec; background: #3a3f48;
117
+ border: 1px solid #4a505a; border-radius: 6px; padding: 5px 10px; cursor: pointer; }
118
+ #orz-toast {
119
+ position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%) translateY(20px);
120
+ z-index: 70; background: #111; color: #fff; padding: 9px 16px; border-radius: 8px;
121
+ font: 13px system-ui, sans-serif; opacity: 0; transition: opacity .2s, transform .2s; pointer-events: none;
122
+ }
123
+ #orz-toast.show { opacity: .95; transform: translateX(-50%) translateY(0); }
124
+
125
+ /* layout picker popover */
126
+ #orz-layout-menu { position: fixed; z-index: 75; display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
127
+ width: 320px; max-height: 64vh; overflow: auto; padding: 8px; box-sizing: border-box;
128
+ background: #23262c; border: 1px solid #3c414a; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.5); }
129
+ #orz-layout-menu[hidden] { display: none; }
130
+ .orz-layout-tile { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 7px 4px;
131
+ background: transparent; border: 1px solid transparent; border-radius: 8px; cursor: pointer; color: #c2c8d0; }
132
+ .orz-layout-tile:hover { background: #2f343c; border-color: #454b55; color: #fff; }
133
+ .orz-layout-tile svg { width: 74px; height: 46px; display: block; }
134
+ .orz-layout-tile .lname { font: 500 11px/1.15 system-ui, sans-serif; text-align: center; }
135
+ .orz-layout-more { grid-column: 1 / -1; display: block; text-align: center; padding: 9px 8px 4px;
136
+ margin-top: 3px; border-top: 1px solid #3c414a; color: #9aa3b2; text-decoration: none;
137
+ font: 600 12px/1 system-ui, sans-serif; }
138
+ .orz-layout-more:hover { color: #fff; }
139
+ `;
140
+ /** Inline line-icons (stroke = currentColor) for the editor toolbar. */
141
+ function svg(path) {
142
+ return `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${path}</svg>`;
143
+ }
144
+ /** Canonical 24-viewBox icons (shared across the orz family) for functions that
145
+ * exist on every surface, so the same function shows the same glyph. */
146
+ function ic24(path) {
147
+ return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${path}</svg>`;
148
+ }
149
+ const ICON = {
150
+ done: svg('<path d="M3 8.4l3.2 3.2L13 4.8"/>'),
151
+ deck: svg('<path d="M2.5 5h6M2.5 11h2.5M8 11h5.5"/><circle cx="10" cy="5" r="1.7"/><circle cx="5.5" cy="11" r="1.7"/>'),
152
+ prev: svg('<path d="M10 3.5L5.5 8l4.5 4.5"/>'),
153
+ next: svg('<path d="M6 3.5L10.5 8 6 12.5"/>'),
154
+ add: svg('<path d="M8 3.2v9.6M3.2 8h9.6"/>'),
155
+ dup: svg('<rect x="5.5" y="5.5" width="7.3" height="7.3" rx="1.3"/><path d="M3.2 10V4.3A1.1 1.1 0 0 1 4.3 3.2h5.7"/>'),
156
+ del: svg('<path d="M3 4.5h10M6.2 4.5V3.3a.8.8 0 0 1 .8-.8h2a.8.8 0 0 1 .8.8v1.2M4.9 4.5l.5 8a1 1 0 0 0 1 .95h3.2a1 1 0 0 0 1-.95l.5-8"/>'),
157
+ up: svg('<path d="M8 13V3.4M4 7.2l4-4 4 4"/>'),
158
+ down: svg('<path d="M8 3v9.6M4 8.8l4 4 4-4"/>'),
159
+ download: ic24('<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M7 10l5 5 5-5"/><path d="M12 15V3"/>'),
160
+ save: ic24('<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><path d="M17 21v-8H7v8M7 3v5h8"/>'),
161
+ pencil: ic24('<path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"/>'),
162
+ collapseDown: ic24('<path d="M6 9l6 6 6-6"/>'),
163
+ layout: ic24('<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/>'),
164
+ };
165
+ /** The orz mark — the "orz" wordmark knocked out of a weathered green seal
166
+ * (rough-edged, stone-textured). From wangyu16/logoes-and-icons (orz.svg);
167
+ * IDs are namespaced `orzlogo-*` so they can't collide with user SVGs. */
168
+ const ORZ_LOGO = "<svg viewBox=\"-5 -5 180 100\" xmlns=\"http://www.w3.org/2000/svg\" class=\"orz-mark\" aria-hidden=\"true\"><defs><filter id=\"orzlogo-rough\" x=\"-10%\" y=\"-10%\" width=\"120%\" height=\"120%\"><feTurbulence type=\"fractalNoise\" baseFrequency=\"0.04\" numOctaves=\"3\" result=\"noise\" /><feDisplacementMap in=\"SourceGraphic\" in2=\"noise\" scale=\"2.5\" xChannelSelector=\"R\" yChannelSelector=\"G\" /></filter><path d=\"M 20,23 C 33,16 57,17 84,13 C 111,8 137,4 153,6 C 165,7 170,13 169,25 L 167,66 C 166,79 159,87 146,89 C 121,93 92,92 60,91 C 41,90 27,92 16,89 C 6,86 1,79 1,67 L 1,50 C 1,35 7,25 20,23 Z\" id=\"orzlogo-seal\" /><filter id=\"orzlogo-stone\" x=\"-10%\" y=\"-10%\" width=\"120%\" height=\"120%\"><feTurbulence type=\"fractalNoise\" baseFrequency=\"0.95\" numOctaves=\"2\" seed=\"11\" result=\"noise\" /><feColorMatrix in=\"noise\" type=\"saturate\" values=\"0\" result=\"mono\" /><feComponentTransfer in=\"mono\" result=\"grain\"><feFuncA type=\"table\" tableValues=\"0 0.16\" /></feComponentTransfer></filter><mask id=\"orzlogo-mask\"><use href=\"#orzlogo-seal\" fill=\"white\" /><path d=\"M37.81 80.31Q30.44 80.31 24.50 77Q18.56 73.69 15.25 67.75Q11.94 61.81 11.94 54.19L11.94 54.19Q11.94 41.69 21.13 35.56Q30.31 29.44 43.69 29.44L43.69 29.44Q49.81 29.44 55.13 32.44Q60.44 35.44 63.69 41.06Q66.94 46.69 66.94 54.06L66.94 54.06Q66.94 62.06 62.81 68Q58.69 73.94 52 77.13Q45.31 80.31 37.81 80.31L37.81 80.31ZM36.44 73.19Q48.06 73.19 54.06 67.94Q60.06 62.69 60.06 52.56L60.06 52.56Q60.06 45.69 55.38 40.69Q50.69 35.69 42.31 35.69L42.31 35.69Q36.69 35.69 30.94 37.81Q25.19 39.94 21.44 44.19Q17.69 48.44 17.69 54.44L17.69 54.44Q17.69 59.44 20.19 63.75Q22.69 68.06 27 70.63Q31.31 73.19 36.44 73.19L36.44 73.19ZM87.94 80.19Q82.81 70.19 79.88 56.69Q76.94 43.19 76.94 33.31L76.94 33.31Q76.94 29.44 78.69 28.31L78.69 28.31Q79.69 27.69 80.19 27.69L80.19 27.69Q81.06 27.69 81.50 29.06Q81.94 30.44 82.44 34.06L82.44 34.06L83.06 38.56Q84.44 31.81 88.38 27.88Q92.31 23.94 98.06 23.94L98.06 23.94Q104.44 23.94 107.56 26.38Q110.69 28.81 110.69 34.44L110.69 34.44Q104.44 31.44 99.31 31.44L99.31 31.44Q94.44 31.44 90.94 34.06Q87.44 36.69 86.06 41.81L86.06 41.81Q84.94 45.31 84.94 48.44L84.94 48.44Q84.94 51.81 85.88 54.75Q86.81 57.69 88.81 61.94L88.81 61.94Q90.69 66.31 91.75 69.44Q92.81 72.56 92.94 76.19L92.94 76.19Q92.94 78.31 91.44 79.25Q89.94 80.19 87.94 80.19L87.94 80.19ZM160.56 66.19Q163.06 68.06 163.06 70.19L163.06 70.19Q163.06 73.56 157.31 75.81Q151.56 78.06 144.31 79.13Q137.06 80.19 132.81 80.19L132.81 80.19Q128.06 80.19 123.75 78.63Q119.44 77.06 119.44 73.19L119.44 73.19Q119.44 69.44 123.63 63.44Q127.81 57.44 133.69 51.19L133.69 51.19L117.56 51.19Q116.31 51.19 116.31 48.94L116.31 48.94Q116.31 47.19 116.69 46.50Q117.06 45.81 117.69 45.69Q118.31 45.56 120.06 45.56L120.06 45.56L139.31 45.56Q143.94 39.69 146.38 35.50Q148.81 31.31 148.81 27.69L148.81 27.69Q148.81 24.06 146.31 21.19L146.31 21.19Q142.44 20.44 138.81 20.44L138.81 20.44Q131.94 20.44 127.19 22.75Q122.44 25.06 121.94 28.81L121.94 28.81Q119.06 28.81 118.13 27.81Q117.19 26.81 117.19 24.44L117.19 24.44Q117.19 21.94 119.75 19.63Q122.31 17.31 126.94 15.88Q131.56 14.44 137.31 14.44L137.31 14.44Q142.06 14.44 147.31 15.56L147.31 15.56Q150.56 16.19 152.81 19.69Q155.06 23.19 155.06 27.44L155.06 27.44Q155.06 31.19 152.75 35.31Q150.44 39.44 145.94 45.56L145.94 45.56L152.06 45.56Q156.81 45.56 158.38 46.06Q159.94 46.56 159.94 48.06L159.94 48.06Q159.94 49.31 159.13 50.19Q158.31 51.06 157.44 51.06L157.44 51.06L140.19 51.06Q134.06 57.94 130.81 63.25Q127.56 68.56 128.19 70.81L128.19 70.81Q128.69 73.19 135.94 74.06L135.94 74.06Q144.06 74.06 149.69 72.13Q155.31 70.19 160.56 66.19L160.56 66.19Z\" fill=\"black\" stroke=\"black\" stroke-width=\"3\" stroke-linejoin=\"round\" stroke-linecap=\"round\" /></mask></defs><g filter=\"url(#orzlogo-rough)\"><use href=\"#orzlogo-seal\" fill=\"#96d969\" mask=\"url(#orzlogo-mask)\" /><use href=\"#orzlogo-seal\" fill=\"#6ea84d\" opacity=\"0.28\" filter=\"url(#orzlogo-stone)\" mask=\"url(#orzlogo-mask)\" /><use href=\"#orzlogo-seal\" fill=\"none\" stroke=\"#c8f7a5\" stroke-width=\"1.5\" stroke-linejoin=\"round\" stroke-linecap=\"round\" stroke-opacity=\"0.42\" mask=\"url(#orzlogo-mask)\" /><use href=\"#orzlogo-seal\" fill=\"none\" stroke=\"#5f8f44\" stroke-width=\"1.2\" stroke-linejoin=\"round\" stroke-linecap=\"round\" stroke-opacity=\"0.35\" mask=\"url(#orzlogo-mask)\" /></g></svg>";
169
+ /** GitHub mark (fill = currentColor). */
170
+ const GH_ICON = '<svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.6 7.6 0 0 1 2-.27c.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>';
171
+ /** Editor-header brand: logo + app name + GitHub link (whole thing → repo). */
172
+ const BRAND = '<a id="orz-brand" href="https://github.com/wangyu16/orz-slides" target="_blank" rel="noopener noreferrer" title="orz-slides on GitHub">' +
173
+ `<span class="orz-logo">${ORZ_LOGO}</span>` +
174
+ '<span class="orz-brand-name">slides</span>' +
175
+ `<span class="orz-gh">${GH_ICON}</span>` +
176
+ '</a>';
177
+ export function buildHtml(o) {
178
+ // Inline mode embeds base.css once + every theme as a toggleable <style>
179
+ // (only the active one matches media), so the editor can switch themes with
180
+ // no network. CDN mode links the default theme; the editor swaps the link.
181
+ const themeTag = o.theme.mode === 'inline'
182
+ ? `<style id="orz-theme-base">\n${o.theme.base}\n</style>\n`
183
+ + o.theme.themes
184
+ .map((t) => `<style class="orz-theme-css" data-theme-css="${escapeHtml(t.id)}" media="${t.id === o.defaultTheme ? 'all' : 'not all'}">\n${t.css}\n</style>`)
185
+ .join('\n')
186
+ : `<link id="orz-theme-base" rel="stylesheet" href="${escapeHtml((o.themes.find((t) => t.id === o.defaultTheme) || o.themes[0]).href)}">`;
187
+ const rendererTag = o.renderer.mode === 'inline'
188
+ ? `<script data-orz-asset="engine">${escapeForScript(o.renderer.js)}</script>`
189
+ : `<script data-orz-asset="engine" src="${escapeHtml(o.renderer.src)}"></script>`;
190
+ const revealCssTag = o.revealCss.mode === 'inline'
191
+ ? `<style>\n${o.revealCss.reset}\n</style>\n<style>\n${o.revealCss.core}\n</style>`
192
+ : `<link rel="stylesheet" href="${escapeHtml(o.revealCss.resetUrl)}">\n`
193
+ + `<link rel="stylesheet" href="${escapeHtml(o.revealCss.coreUrl)}">`;
194
+ const config = {
195
+ version: o.rendererVersion,
196
+ docId: o.docId,
197
+ filename: o.filename,
198
+ rendererVersion: o.rendererVersion,
199
+ // NB: the update SOURCE (manifest/packages/host) is hardcoded in app.js, not
200
+ // here — a config field must never be able to redirect the self-update.
201
+ defaultTheme: o.defaultTheme,
202
+ themes: o.themes,
203
+ ratio: o.ratio,
204
+ enhancers: { mermaidJs: o.cdn.mermaidJs, smilesJs: o.cdn.smilesJs, chartJs: o.cdn.chartJs },
205
+ editorLibs: o.editorLibs,
206
+ };
207
+ return `<!DOCTYPE html>
208
+ <html lang="en" data-mode="present" data-theme="${escapeHtml(o.defaultTheme)}">
209
+ <head>
210
+ <meta charset="utf-8">
211
+ <meta name="viewport" content="width=device-width, initial-scale=1">
212
+ <title>${escapeHtml(o.title)}</title>
213
+ <meta name="generator" content="orz-slides">
214
+ ${revealCssTag}
215
+ <link rel="stylesheet" href="${escapeHtml(o.cdn.katexCss)}">
216
+ ${themeTag}
217
+ <style>${CHROME_CSS}</style>
218
+ </head>
219
+ <body>
220
+ <div class="reveal"><div class="slides"></div></div>
221
+
222
+ <button id="orz-edit-fab" class="orz-edit-ctrl" title="Edit this deck">${ICON.pencil}</button>
223
+
224
+ <div id="orz-panel">
225
+ <div id="orz-vdivider" title="Drag to resize"></div>
226
+ <button id="orz-close" title="Close editor — back to presenting">${ICON.collapseDown}</button>
227
+ <div id="orz-toolbar">
228
+ ${BRAND}
229
+ <span class="orz-sep"></span>
230
+ <button id="orz-save" class="ic primary" title="Save (Ctrl/Cmd+S)">${ICON.save}</button>
231
+ <button id="orz-download" class="ic" title="Download a copy">${ICON.download}</button>
232
+ <span class="orz-sep"></span>
233
+ <button id="orz-prev" class="ic" title="Previous slide">${ICON.prev}</button>
234
+ <span id="orz-pos" class="orz-pos">1 / 1</span>
235
+ <button id="orz-next" class="ic" title="Next slide">${ICON.next}</button>
236
+ <span class="orz-sep"></span>
237
+ <button id="orz-add" class="ic" title="Add a slide after this one">${ICON.add}</button>
238
+ <button id="orz-dup" class="ic" title="Duplicate this slide">${ICON.dup}</button>
239
+ <button id="orz-del" class="ic danger" title="Delete this slide">${ICON.del}</button>
240
+ <button id="orz-up" class="ic" title="Move slide earlier">${ICON.up}</button>
241
+ <button id="orz-down" class="ic" title="Move slide later">${ICON.down}</button>
242
+ <span class="orz-spacer"></span>
243
+ <button id="orz-layout-btn" class="ic" title="Slide layout" aria-haspopup="true" aria-expanded="false">${ICON.layout}</button>
244
+ <button id="orz-deck-btn" class="ic" title="Deck settings (theme, footer, ratio, title)">${ICON.deck}</button>
245
+ <select id="orz-theme" title="Theme"></select>
246
+ <a id="orz-copy" href="https://markdown.orz.how" target="_blank" rel="noopener noreferrer" title="orz-markdown">© orz-markdown</a>
247
+ </div>
248
+ <div id="orz-editor-host"><textarea id="orz-ta" spellcheck="false"></textarea></div>
249
+ </div>
250
+
251
+ <div id="orz-layout-menu" hidden role="menu" aria-label="Slide layouts"></div>
252
+
253
+ <div id="orz-update" class="orz-banner"><span class="upd-text"></span><button id="orz-upd-apply" class="upd-primary">Update</button><button id="orz-upd-dismiss">Dismiss</button></div>
254
+ <div id="orz-served-note" class="orz-banner"><span>This is a published page &mdash; edits can&rsquo;t be saved back to the server.</span><button id="orz-served-download">Download copy</button><button id="orz-served-dismiss">Dismiss</button></div>
255
+ <div id="orz-toast"></div>
256
+
257
+ <script type="text/orz-slides" id="orz-deck">
258
+ ${escapeForScript(o.source)}
259
+ </script>
260
+
261
+ ${rendererTag}
262
+ <script data-orz-asset="config">window.__ORZ_SLIDES__ = ${JSON.stringify(config)};</script>
263
+ <script>
264
+ (function () {
265
+ function boot() { if (window.orzslides) window.orzslides.mount(); }
266
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
267
+ else boot();
268
+ })();
269
+ </script>
270
+ <script>${o.runtime}</script>
271
+ <script data-orz-asset="app">${o.appJs}</script>
272
+ </body>
273
+ </html>
274
+ `;
275
+ }
package/dist/types.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * orz-slides — shared types (the locked interface for all modules).
3
+ *
4
+ * The parser (WP1) produces a `Deck`; the layout engine (WP2) turns a
5
+ * `LayoutNode` into grid DOM; the assembler (WP5) renders a `Slide` to a reveal
6
+ * `<section>`. These types are the contract — do not change them without
7
+ * updating BUILD-PLAN.md and the affected modules.
8
+ *
9
+ * See DESIGN.md §5 for the authoring syntax these types model, and
10
+ * docs/dom-contract.md for the rendered DOM/CSS contract.
11
+ */
12
+ export {};