hyperbook 0.90.0 → 0.91.1
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.
- package/dist/assets/code-input/auto-close-brackets.min.js +1 -1
- package/dist/assets/code-input/code-input.min.css +1 -1
- package/dist/assets/code-input/code-input.min.js +12 -1
- package/dist/assets/code-input/indent.min.js +1 -1
- package/dist/assets/directive-excalidraw/hyperbook-excalidraw.umd.js +1 -1
- package/dist/assets/directive-onlineide/style.css +8 -0
- package/dist/assets/directive-p5/client.js +113 -0
- package/dist/assets/directive-p5/style.css +67 -3
- package/dist/assets/directive-pyide/client.js +1226 -146
- package/dist/assets/directive-pyide/style.css +183 -6
- package/dist/assets/directive-sqlide/style.css +8 -0
- package/dist/assets/directive-typst/client.js +154 -14
- package/dist/assets/directive-typst/style.css +65 -4
- package/dist/assets/directive-webide/client.js +114 -0
- package/dist/assets/directive-webide/style.css +61 -3
- package/dist/index.js +252 -54
- package/dist/locales/de.json +12 -0
- package/dist/locales/en.json +12 -0
- package/package.json +3 -3
- package/dist/assets/directive-pyide/webworker.js +0 -86
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
flex-direction: column;
|
|
6
6
|
overflow: hidden;
|
|
7
7
|
gap: 8px;
|
|
8
|
+
height: var(--pyide-height, calc(100dvh - 80px));
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
.directive-pyide code-input {
|
|
@@ -14,7 +15,9 @@
|
|
|
14
15
|
.directive-pyide .container {
|
|
15
16
|
width: 100%;
|
|
16
17
|
overflow: hidden;
|
|
17
|
-
height:
|
|
18
|
+
min-height: 120px;
|
|
19
|
+
min-width: 120px;
|
|
20
|
+
flex: 0 0 200px;
|
|
18
21
|
display: flex;
|
|
19
22
|
flex-direction: column;
|
|
20
23
|
}
|
|
@@ -35,6 +38,57 @@
|
|
|
35
38
|
font-family: hyperbook-monospace, monospace;
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
.directive-pyide .output .error-line {
|
|
42
|
+
color: #b42318;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.directive-pyide .canvas-wrapper {
|
|
46
|
+
overflow: auto;
|
|
47
|
+
height: 100%;
|
|
48
|
+
border: 1px solid var(--color-spacer);
|
|
49
|
+
border-radius: 8px;
|
|
50
|
+
border-top-left-radius: 0;
|
|
51
|
+
border-top-right-radius: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.directive-pyide .canvas {
|
|
55
|
+
display: block;
|
|
56
|
+
width: auto;
|
|
57
|
+
height: auto;
|
|
58
|
+
min-height: 300px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.directive-pyide .canvas-header,
|
|
62
|
+
.directive-pyide .output-header {
|
|
63
|
+
border: 1px solid var(--color-spacer);
|
|
64
|
+
border-bottom: none;
|
|
65
|
+
border-top-left-radius: 8px;
|
|
66
|
+
border-top-right-radius: 8px;
|
|
67
|
+
padding: 8px 16px;
|
|
68
|
+
background-color: var(--color-spacer);
|
|
69
|
+
color: var(--color-text);
|
|
70
|
+
font-weight: 600;
|
|
71
|
+
text-align: center;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.directive-pyide .canvas-output-splitter {
|
|
75
|
+
display: none;
|
|
76
|
+
width: 100%;
|
|
77
|
+
height: 4px;
|
|
78
|
+
margin: 10px 0;
|
|
79
|
+
cursor: row-resize;
|
|
80
|
+
background: var(--color-spacer);
|
|
81
|
+
border-radius: 999px;
|
|
82
|
+
flex-shrink: 0;
|
|
83
|
+
touch-action: none;
|
|
84
|
+
opacity: 0.45;
|
|
85
|
+
transition: opacity 0.15s ease-in-out;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.directive-pyide .canvas-output-splitter:hover {
|
|
89
|
+
opacity: 0.65;
|
|
90
|
+
}
|
|
91
|
+
|
|
38
92
|
.directive-pyide .hidden {
|
|
39
93
|
display: none;
|
|
40
94
|
}
|
|
@@ -43,7 +97,43 @@
|
|
|
43
97
|
width: 100%;
|
|
44
98
|
display: flex;
|
|
45
99
|
flex-direction: column;
|
|
46
|
-
height:
|
|
100
|
+
min-height: 120px;
|
|
101
|
+
min-width: 120px;
|
|
102
|
+
flex: 1 1 400px;
|
|
103
|
+
overflow: hidden;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.directive-pyide .splitter {
|
|
107
|
+
background: var(--color-spacer);
|
|
108
|
+
border-radius: 999px;
|
|
109
|
+
flex-shrink: 0;
|
|
110
|
+
touch-action: none;
|
|
111
|
+
opacity: 0.45;
|
|
112
|
+
transition: opacity 0.15s ease-in-out;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.directive-pyide .splitter:hover {
|
|
116
|
+
opacity: 0.65;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.directive-pyide.split-vertical .splitter {
|
|
120
|
+
width: 100%;
|
|
121
|
+
height: 4px;
|
|
122
|
+
cursor: row-resize;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.directive-pyide.split-horizontal .splitter {
|
|
126
|
+
width: 4px;
|
|
127
|
+
height: 100%;
|
|
128
|
+
cursor: col-resize;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.directive-pyide.resizing {
|
|
132
|
+
user-select: none;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.directive-pyide.resizing .splitter {
|
|
136
|
+
opacity: 0.75;
|
|
47
137
|
}
|
|
48
138
|
|
|
49
139
|
.directive-pyide .editor {
|
|
@@ -52,6 +142,20 @@
|
|
|
52
142
|
flex: 1;
|
|
53
143
|
}
|
|
54
144
|
|
|
145
|
+
.directive-pyide .editor.running {
|
|
146
|
+
pointer-events: none;
|
|
147
|
+
opacity: 0.7;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.directive-pyide.locked-by-other {
|
|
151
|
+
outline: 2px solid #f59e0b;
|
|
152
|
+
outline-offset: 2px;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.directive-pyide.locked-by-other .buttons {
|
|
156
|
+
border-color: #f59e0b;
|
|
157
|
+
}
|
|
158
|
+
|
|
55
159
|
.directive-pyide .buttons {
|
|
56
160
|
display: flex;
|
|
57
161
|
border: 1px solid var(--color-spacer);
|
|
@@ -59,6 +163,7 @@
|
|
|
59
163
|
border-bottom: none;
|
|
60
164
|
border-bottom-left-radius: 0;
|
|
61
165
|
border-bottom-right-radius: 0;
|
|
166
|
+
overflow: hidden;
|
|
62
167
|
}
|
|
63
168
|
|
|
64
169
|
.directive-pyide .buttons.bottom {
|
|
@@ -90,10 +195,26 @@
|
|
|
90
195
|
cursor: pointer;
|
|
91
196
|
}
|
|
92
197
|
|
|
93
|
-
.directive-pyide .buttons:last-child {
|
|
198
|
+
.directive-pyide .buttons button:last-child {
|
|
94
199
|
border-right: none;
|
|
95
200
|
}
|
|
96
201
|
|
|
202
|
+
.directive-pyide .buttons:not(.bottom) button:first-child {
|
|
203
|
+
border-top-left-radius: 8px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.directive-pyide .buttons:not(.bottom) button:last-child {
|
|
207
|
+
border-top-right-radius: 8px;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.directive-pyide .buttons.bottom button:first-child {
|
|
211
|
+
border-bottom-left-radius: 8px;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.directive-pyide .buttons.bottom button:last-child {
|
|
215
|
+
border-bottom-right-radius: 8px;
|
|
216
|
+
}
|
|
217
|
+
|
|
97
218
|
.directive-pyide button.active {
|
|
98
219
|
background-color: var(--color-spacer);
|
|
99
220
|
}
|
|
@@ -108,24 +229,80 @@
|
|
|
108
229
|
opacity: 0.5;
|
|
109
230
|
}
|
|
110
231
|
|
|
232
|
+
.directive-pyide button.stopping {
|
|
233
|
+
pointer-events: auto;
|
|
234
|
+
cursor: progress;
|
|
235
|
+
opacity: 0.75;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.directive-pyide button.locked {
|
|
239
|
+
color: #b45309;
|
|
240
|
+
font-weight: 600;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.directive-pyide button.fullscreen {
|
|
244
|
+
flex: 0 0 auto;
|
|
245
|
+
min-width: 42px;
|
|
246
|
+
width: 42px;
|
|
247
|
+
padding: 8px 0;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.directive-pyide button.stop {
|
|
251
|
+
flex: 0 0 auto;
|
|
252
|
+
min-width: 96px;
|
|
253
|
+
color: #b42318;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.directive-pyide button.stop:disabled {
|
|
257
|
+
color: var(--color-text);
|
|
258
|
+
opacity: 0.5;
|
|
259
|
+
cursor: not-allowed;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.directive-pyide:fullscreen {
|
|
263
|
+
width: 100vw;
|
|
264
|
+
height: 100dvh !important;
|
|
265
|
+
padding: 12px;
|
|
266
|
+
box-sizing: border-box;
|
|
267
|
+
background-color: var(--color-background, var(--color--background, #fff));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.directive-pyide:fullscreen::backdrop {
|
|
271
|
+
background-color: var(--color-background, var(--color--background, #fff));
|
|
272
|
+
}
|
|
273
|
+
|
|
111
274
|
@media screen and (min-width: 1024px) {
|
|
112
275
|
.directive-pyide {
|
|
113
276
|
flex-direction: row;
|
|
114
|
-
height: calc(100dvh - 128px);
|
|
115
277
|
|
|
116
278
|
.output {
|
|
117
279
|
height: 100%;
|
|
118
280
|
}
|
|
119
281
|
|
|
120
282
|
.container {
|
|
121
|
-
flex: 1;
|
|
122
283
|
height: 100% !important;
|
|
123
284
|
}
|
|
124
285
|
|
|
125
286
|
.editor-container {
|
|
126
|
-
flex: 3;
|
|
127
287
|
height: 100%;
|
|
128
288
|
overflow: hidden;
|
|
129
289
|
}
|
|
130
290
|
}
|
|
291
|
+
|
|
292
|
+
.directive-pyide[data-canvas="true"].canvas-split-mode .canvas-wrapper,
|
|
293
|
+
.directive-pyide[data-canvas="true"].canvas-split-mode .output {
|
|
294
|
+
flex: 1 1 0;
|
|
295
|
+
min-height: 120px;
|
|
296
|
+
border-radius: 8px;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.directive-pyide[data-canvas="true"].canvas-split-mode .canvas-wrapper,
|
|
300
|
+
.directive-pyide[data-canvas="true"].canvas-split-mode .output {
|
|
301
|
+
border-top-left-radius: 0;
|
|
302
|
+
border-top-right-radius: 0;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.directive-pyide[data-canvas="true"].canvas-split-mode .canvas-output-splitter {
|
|
306
|
+
display: block;
|
|
307
|
+
}
|
|
131
308
|
}
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
border-radius: 8px;
|
|
4
4
|
background: #1e1e1e;
|
|
5
5
|
overflow: hidden;
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
height: var(--sqlide-height, calc(100dvh - 80px));
|
|
6
9
|
|
|
7
10
|
.jo_iconButton.img_whole-window-dark {
|
|
8
11
|
display: none;
|
|
@@ -19,6 +22,11 @@
|
|
|
19
22
|
}
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
.directive-sqlide .sql-online {
|
|
26
|
+
flex: 1;
|
|
27
|
+
min-height: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
.directive-sqlide .menu {
|
|
23
31
|
display: flex;
|
|
24
32
|
border-top: 1px solid var(--color-spacer);
|
|
@@ -1148,6 +1148,92 @@ hyperbook.typst = (function () {
|
|
|
1148
1148
|
// TYPST EDITOR
|
|
1149
1149
|
// ============================================================================
|
|
1150
1150
|
|
|
1151
|
+
function setupSplitter(elem, container, editorContainer, splitter) {
|
|
1152
|
+
if (!container || !editorContainer || !splitter) return;
|
|
1153
|
+
|
|
1154
|
+
const minPanelSize = 120;
|
|
1155
|
+
|
|
1156
|
+
const getIsHorizontal = () =>
|
|
1157
|
+
getComputedStyle(elem).flexDirection.startsWith('row');
|
|
1158
|
+
|
|
1159
|
+
const applySplitSize = (rawSize, isHorizontal) => {
|
|
1160
|
+
const total = isHorizontal ? elem.clientWidth : elem.clientHeight;
|
|
1161
|
+
const splitterSize = isHorizontal ? splitter.offsetWidth : splitter.offsetHeight;
|
|
1162
|
+
const maxSize = Math.max(minPanelSize, total - splitterSize - minPanelSize);
|
|
1163
|
+
const clamped = Math.max(minPanelSize, Math.min(rawSize, maxSize));
|
|
1164
|
+
container.style.flex = `0 0 ${clamped}px`;
|
|
1165
|
+
return clamped;
|
|
1166
|
+
};
|
|
1167
|
+
|
|
1168
|
+
const applyStoredSplitSize = () => {
|
|
1169
|
+
const isHorizontal = getIsHorizontal();
|
|
1170
|
+
elem.classList.toggle('split-horizontal', isHorizontal);
|
|
1171
|
+
elem.classList.toggle('split-vertical', !isHorizontal);
|
|
1172
|
+
const key = isHorizontal ? 'splitHorizontal' : 'splitVertical';
|
|
1173
|
+
const rawStored = Number(elem.dataset[key]);
|
|
1174
|
+
if (!Number.isFinite(rawStored) || rawStored <= 0) {
|
|
1175
|
+
container.style.flex = '';
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
applySplitSize(rawStored, isHorizontal);
|
|
1179
|
+
};
|
|
1180
|
+
|
|
1181
|
+
applyStoredSplitSize();
|
|
1182
|
+
|
|
1183
|
+
splitter.addEventListener('pointerdown', (event) => {
|
|
1184
|
+
event.preventDefault();
|
|
1185
|
+
splitter.setPointerCapture(event.pointerId);
|
|
1186
|
+
|
|
1187
|
+
const isHorizontal = getIsHorizontal();
|
|
1188
|
+
const key = isHorizontal ? 'splitHorizontal' : 'splitVertical';
|
|
1189
|
+
const startPointer = isHorizontal ? event.clientX : event.clientY;
|
|
1190
|
+
const startSize = isHorizontal
|
|
1191
|
+
? container.getBoundingClientRect().width
|
|
1192
|
+
: container.getBoundingClientRect().height;
|
|
1193
|
+
|
|
1194
|
+
elem.classList.add('resizing');
|
|
1195
|
+
|
|
1196
|
+
const onPointerMove = (moveEvent) => {
|
|
1197
|
+
const pointer = isHorizontal ? moveEvent.clientX : moveEvent.clientY;
|
|
1198
|
+
const delta = pointer - startPointer;
|
|
1199
|
+
const size = applySplitSize(startSize + delta, isHorizontal);
|
|
1200
|
+
elem.dataset[key] = String(Math.round(size));
|
|
1201
|
+
};
|
|
1202
|
+
|
|
1203
|
+
const onPointerUp = () => {
|
|
1204
|
+
elem.classList.remove('resizing');
|
|
1205
|
+
splitter.removeEventListener('pointermove', onPointerMove);
|
|
1206
|
+
splitter.removeEventListener('pointerup', onPointerUp);
|
|
1207
|
+
splitter.removeEventListener('pointercancel', onPointerUp);
|
|
1208
|
+
};
|
|
1209
|
+
|
|
1210
|
+
splitter.addEventListener('pointermove', onPointerMove);
|
|
1211
|
+
splitter.addEventListener('pointerup', onPointerUp);
|
|
1212
|
+
splitter.addEventListener('pointercancel', onPointerUp);
|
|
1213
|
+
});
|
|
1214
|
+
|
|
1215
|
+
window.addEventListener('resize', applyStoredSplitSize);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
const updateFullscreenButtonState = (elem, button) => {
|
|
1219
|
+
if (!elem || !button) return;
|
|
1220
|
+
const isFullscreen = document.fullscreenElement === elem;
|
|
1221
|
+
const label = i18nGet('ide-fullscreen-enter', 'Fullscreen');
|
|
1222
|
+
button.textContent = '⛶';
|
|
1223
|
+
button.title = label;
|
|
1224
|
+
button.setAttribute('aria-label', label);
|
|
1225
|
+
button.classList.toggle('active', isFullscreen);
|
|
1226
|
+
};
|
|
1227
|
+
|
|
1228
|
+
const toggleFullscreen = async (elem) => {
|
|
1229
|
+
if (!elem) return;
|
|
1230
|
+
if (document.fullscreenElement === elem) {
|
|
1231
|
+
await document.exitFullscreen();
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
await elem.requestFullscreen();
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1151
1237
|
class TypstEditor {
|
|
1152
1238
|
constructor({
|
|
1153
1239
|
elem,
|
|
@@ -1178,13 +1264,24 @@ hyperbook.typst = (function () {
|
|
|
1178
1264
|
this.preview = elem.querySelector('.typst-preview');
|
|
1179
1265
|
this.loadingIndicator = elem.querySelector('.typst-loading');
|
|
1180
1266
|
this.editor = elem.querySelector('.editor.typst');
|
|
1267
|
+
this.editorContainer = elem.querySelector('.editor-container');
|
|
1268
|
+
this.splitter = elem.querySelector('.splitter');
|
|
1181
1269
|
this.sourceTextarea = elem.querySelector('.typst-source');
|
|
1270
|
+
this.fullscreenBtn = elem.querySelector('.fullscreen');
|
|
1271
|
+
this.editorInitialized = false;
|
|
1272
|
+
|
|
1273
|
+
setupSplitter(this.elem, this.previewContainer, this.editorContainer, this.splitter);
|
|
1182
1274
|
|
|
1183
1275
|
// Setup UI callbacks
|
|
1184
1276
|
this.setupUICallbacks();
|
|
1185
1277
|
|
|
1186
1278
|
// Setup event handlers
|
|
1187
1279
|
this.setupEventHandlers();
|
|
1280
|
+
this.handleFullscreenChange = () => {
|
|
1281
|
+
updateFullscreenButtonState(this.elem, this.fullscreenBtn);
|
|
1282
|
+
};
|
|
1283
|
+
document.addEventListener('fullscreenchange', this.handleFullscreenChange);
|
|
1284
|
+
updateFullscreenButtonState(this.elem, this.fullscreenBtn);
|
|
1188
1285
|
|
|
1189
1286
|
// Initialize
|
|
1190
1287
|
this.initialize();
|
|
@@ -1208,12 +1305,14 @@ hyperbook.typst = (function () {
|
|
|
1208
1305
|
const resetBtn = this.elem.querySelector('.reset');
|
|
1209
1306
|
const addSourceFileBtn = this.elem.querySelector('.add-source-file');
|
|
1210
1307
|
const addBinaryFileBtn = this.elem.querySelector('.add-binary-file');
|
|
1308
|
+
const fullscreenBtn = this.elem.querySelector('.fullscreen');
|
|
1211
1309
|
|
|
1212
1310
|
downloadBtn?.addEventListener('click', () => this.handleExportPdf());
|
|
1213
1311
|
downloadProjectBtn?.addEventListener('click', () => this.handleExportProject());
|
|
1214
1312
|
resetBtn?.addEventListener('click', () => this.handleReset());
|
|
1215
1313
|
addSourceFileBtn?.addEventListener('click', () => this.handleAddSourceFile());
|
|
1216
1314
|
addBinaryFileBtn?.addEventListener('click', (e) => this.handleAddBinaryFile(e));
|
|
1315
|
+
fullscreenBtn?.addEventListener('click', () => this.handleFullscreenToggle());
|
|
1217
1316
|
}
|
|
1218
1317
|
|
|
1219
1318
|
/**
|
|
@@ -1221,8 +1320,9 @@ hyperbook.typst = (function () {
|
|
|
1221
1320
|
*/
|
|
1222
1321
|
async initialize() {
|
|
1223
1322
|
if (this.editor) {
|
|
1224
|
-
|
|
1225
|
-
|
|
1323
|
+
const initializeEditor = async () => {
|
|
1324
|
+
if (this.editorInitialized) return;
|
|
1325
|
+
this.editorInitialized = true;
|
|
1226
1326
|
await this.restoreState();
|
|
1227
1327
|
this.uiManager.updateTabs();
|
|
1228
1328
|
this.uiManager.updateBinaryFilesList();
|
|
@@ -1235,7 +1335,13 @@ hyperbook.typst = (function () {
|
|
|
1235
1335
|
this.saveState();
|
|
1236
1336
|
debouncedRerender();
|
|
1237
1337
|
});
|
|
1238
|
-
}
|
|
1338
|
+
};
|
|
1339
|
+
|
|
1340
|
+
// Edit mode - wait for code-input to load (or initialize immediately if already ready)
|
|
1341
|
+
this.editor.addEventListener('code-input_load', initializeEditor);
|
|
1342
|
+
if (this.editor.querySelector('textarea')) {
|
|
1343
|
+
await initializeEditor();
|
|
1344
|
+
}
|
|
1239
1345
|
} else if (this.sourceTextarea) {
|
|
1240
1346
|
// Preview mode
|
|
1241
1347
|
const initialCode = this.sourceTextarea.value;
|
|
@@ -1261,7 +1367,7 @@ hyperbook.typst = (function () {
|
|
|
1261
1367
|
const result = await window.store?.typst?.get(this.id);
|
|
1262
1368
|
|
|
1263
1369
|
if (result) {
|
|
1264
|
-
this.
|
|
1370
|
+
this.setEditorValue(result.code || this.fileManager.getCurrentContent());
|
|
1265
1371
|
|
|
1266
1372
|
if (result.sourceFiles) {
|
|
1267
1373
|
this.fileManager.sourceFiles = result.sourceFiles;
|
|
@@ -1280,11 +1386,11 @@ hyperbook.typst = (function () {
|
|
|
1280
1386
|
);
|
|
1281
1387
|
if (file) {
|
|
1282
1388
|
this.fileManager.currentFile = file;
|
|
1283
|
-
this.
|
|
1389
|
+
this.setEditorValue(this.fileManager.getCurrentContent());
|
|
1284
1390
|
}
|
|
1285
1391
|
}
|
|
1286
1392
|
} else {
|
|
1287
|
-
this.
|
|
1393
|
+
this.setEditorValue(this.fileManager.getCurrentContent());
|
|
1288
1394
|
}
|
|
1289
1395
|
}
|
|
1290
1396
|
|
|
@@ -1294,11 +1400,11 @@ hyperbook.typst = (function () {
|
|
|
1294
1400
|
async saveState() {
|
|
1295
1401
|
if (!this.editor) return;
|
|
1296
1402
|
|
|
1297
|
-
this.fileManager.updateCurrentContent(this.
|
|
1403
|
+
this.fileManager.updateCurrentContent(this.getEditorValue());
|
|
1298
1404
|
|
|
1299
1405
|
await window.store?.typst?.put({
|
|
1300
1406
|
id: this.id,
|
|
1301
|
-
code: this.
|
|
1407
|
+
code: this.getEditorValue(),
|
|
1302
1408
|
sourceFiles: this.fileManager.getSourceFiles(),
|
|
1303
1409
|
binaryFiles: this.binaryFiles,
|
|
1304
1410
|
currentFile: this.fileManager.currentFile.filename,
|
|
@@ -1311,7 +1417,7 @@ hyperbook.typst = (function () {
|
|
|
1311
1417
|
rerender() {
|
|
1312
1418
|
if (!this.editor) return;
|
|
1313
1419
|
|
|
1314
|
-
this.fileManager.updateCurrentContent(this.
|
|
1420
|
+
this.fileManager.updateCurrentContent(this.getEditorValue());
|
|
1315
1421
|
|
|
1316
1422
|
const mainFile = this.fileManager.findMainFile();
|
|
1317
1423
|
const mainCode = mainFile
|
|
@@ -1338,9 +1444,9 @@ hyperbook.typst = (function () {
|
|
|
1338
1444
|
*/
|
|
1339
1445
|
handleFileSwitch(filename) {
|
|
1340
1446
|
if (this.editor) {
|
|
1341
|
-
this.fileManager.updateCurrentContent(this.
|
|
1447
|
+
this.fileManager.updateCurrentContent(this.getEditorValue());
|
|
1342
1448
|
const content = this.fileManager.switchTo(filename);
|
|
1343
|
-
this.
|
|
1449
|
+
this.setEditorValue(content);
|
|
1344
1450
|
this.uiManager.updateTabs();
|
|
1345
1451
|
this.saveState();
|
|
1346
1452
|
}
|
|
@@ -1351,7 +1457,7 @@ hyperbook.typst = (function () {
|
|
|
1351
1457
|
*/
|
|
1352
1458
|
handleFilesChange() {
|
|
1353
1459
|
if (this.editor) {
|
|
1354
|
-
this.
|
|
1460
|
+
this.setEditorValue(this.fileManager.getCurrentContent());
|
|
1355
1461
|
}
|
|
1356
1462
|
this.saveState();
|
|
1357
1463
|
this.rerender();
|
|
@@ -1389,7 +1495,7 @@ hyperbook.typst = (function () {
|
|
|
1389
1495
|
}
|
|
1390
1496
|
|
|
1391
1497
|
if (this.editor) {
|
|
1392
|
-
this.
|
|
1498
|
+
this.setEditorValue(this.fileManager.getCurrentContent());
|
|
1393
1499
|
}
|
|
1394
1500
|
|
|
1395
1501
|
this.uiManager.updateTabs();
|
|
@@ -1463,7 +1569,7 @@ hyperbook.typst = (function () {
|
|
|
1463
1569
|
*/
|
|
1464
1570
|
async handleExportProject() {
|
|
1465
1571
|
const mainFile = this.fileManager.findMainFile();
|
|
1466
|
-
const code = mainFile ? mainFile.content :
|
|
1572
|
+
const code = mainFile ? mainFile.content : this.getEditorValue();
|
|
1467
1573
|
|
|
1468
1574
|
await this.exporter.export({
|
|
1469
1575
|
code,
|
|
@@ -1489,6 +1595,40 @@ hyperbook.typst = (function () {
|
|
|
1489
1595
|
window.location.reload();
|
|
1490
1596
|
}
|
|
1491
1597
|
}
|
|
1598
|
+
|
|
1599
|
+
async handleFullscreenToggle() {
|
|
1600
|
+
try {
|
|
1601
|
+
await toggleFullscreen(this.elem);
|
|
1602
|
+
} catch (error) {
|
|
1603
|
+
console.error(error.message);
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
getEditorValue() {
|
|
1608
|
+
if (!this.editor) return '';
|
|
1609
|
+
const textarea = this.editor.querySelector('textarea');
|
|
1610
|
+
if (textarea) return textarea.value;
|
|
1611
|
+
try {
|
|
1612
|
+
if (typeof this.editor.value === 'string') {
|
|
1613
|
+
return this.editor.value;
|
|
1614
|
+
}
|
|
1615
|
+
} catch (e) {}
|
|
1616
|
+
return this.editor.textContent || '';
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
setEditorValue(value) {
|
|
1620
|
+
if (!this.editor) return;
|
|
1621
|
+
const normalizedValue = value ?? '';
|
|
1622
|
+
const textarea = this.editor.querySelector('textarea');
|
|
1623
|
+
if (textarea) {
|
|
1624
|
+
textarea.value = normalizedValue;
|
|
1625
|
+
}
|
|
1626
|
+
try {
|
|
1627
|
+
this.editor.value = normalizedValue;
|
|
1628
|
+
} catch (e) {
|
|
1629
|
+
this.editor.textContent = normalizedValue;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1492
1632
|
}
|
|
1493
1633
|
|
|
1494
1634
|
// ============================================================================
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
flex-direction: column;
|
|
6
6
|
overflow: hidden;
|
|
7
7
|
gap: 8px;
|
|
8
|
-
height: calc(100dvh -
|
|
8
|
+
height: var(--typst-height, calc(100dvh - 80px));
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
code-input {
|
|
@@ -14,11 +14,14 @@ code-input {
|
|
|
14
14
|
|
|
15
15
|
.directive-typst .preview-container {
|
|
16
16
|
width: 100%;
|
|
17
|
+
min-height: 120px;
|
|
18
|
+
min-width: 120px;
|
|
17
19
|
border: 1px solid var(--color-spacer);
|
|
18
20
|
border-radius: 8px;
|
|
19
21
|
overflow: auto;
|
|
20
22
|
background-color: var(--color--background);
|
|
21
23
|
position: relative;
|
|
24
|
+
flex: 1 1 0;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
.directive-typst .typst-preview {
|
|
@@ -167,7 +170,42 @@ code-input {
|
|
|
167
170
|
width: 100%;
|
|
168
171
|
display: flex;
|
|
169
172
|
flex-direction: column;
|
|
170
|
-
height:
|
|
173
|
+
min-height: 120px;
|
|
174
|
+
min-width: 120px;
|
|
175
|
+
flex: 1 1 0;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.directive-typst .splitter {
|
|
179
|
+
background: var(--color-spacer);
|
|
180
|
+
border-radius: 999px;
|
|
181
|
+
flex-shrink: 0;
|
|
182
|
+
touch-action: none;
|
|
183
|
+
opacity: 0.45;
|
|
184
|
+
transition: opacity 0.15s ease-in-out;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.directive-typst .splitter:hover {
|
|
188
|
+
opacity: 0.65;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.directive-typst.split-vertical .splitter {
|
|
192
|
+
width: 100%;
|
|
193
|
+
height: 4px;
|
|
194
|
+
cursor: row-resize;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.directive-typst.split-horizontal .splitter {
|
|
198
|
+
width: 4px;
|
|
199
|
+
height: 100%;
|
|
200
|
+
cursor: col-resize;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.directive-typst.resizing {
|
|
204
|
+
user-select: none;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.directive-typst.resizing .splitter {
|
|
208
|
+
opacity: 0.75;
|
|
171
209
|
}
|
|
172
210
|
|
|
173
211
|
.directive-typst .file-tabs {
|
|
@@ -398,6 +436,7 @@ code-input {
|
|
|
398
436
|
border-bottom: none;
|
|
399
437
|
border-bottom-left-radius: 0;
|
|
400
438
|
border-bottom-right-radius: 0;
|
|
439
|
+
overflow: hidden;
|
|
401
440
|
}
|
|
402
441
|
|
|
403
442
|
.directive-typst .buttons.bottom {
|
|
@@ -428,10 +467,17 @@ code-input {
|
|
|
428
467
|
opacity: 0.6;
|
|
429
468
|
}
|
|
430
469
|
|
|
431
|
-
.directive-typst .buttons:last-child {
|
|
470
|
+
.directive-typst .buttons button:last-child {
|
|
432
471
|
border-right: none;
|
|
433
472
|
}
|
|
434
473
|
|
|
474
|
+
.directive-typst button.fullscreen {
|
|
475
|
+
flex: 0 0 auto;
|
|
476
|
+
min-width: 42px;
|
|
477
|
+
width: 42px;
|
|
478
|
+
padding: 8px 0;
|
|
479
|
+
}
|
|
480
|
+
|
|
435
481
|
.directive-typst button:hover {
|
|
436
482
|
background-color: var(--color-spacer);
|
|
437
483
|
}
|
|
@@ -447,10 +493,25 @@ code-input {
|
|
|
447
493
|
display: none !important;
|
|
448
494
|
}
|
|
449
495
|
|
|
496
|
+
.directive-typst:fullscreen {
|
|
497
|
+
width: 100vw;
|
|
498
|
+
height: 100dvh !important;
|
|
499
|
+
padding: 12px;
|
|
500
|
+
box-sizing: border-box;
|
|
501
|
+
background-color: var(--color-background, var(--color--background, #fff));
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.directive-typst:fullscreen::backdrop {
|
|
505
|
+
background-color: var(--color-background, var(--color--background, #fff));
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.directive-typst:fullscreen.preview-only {
|
|
509
|
+
height: 100dvh !important;
|
|
510
|
+
}
|
|
511
|
+
|
|
450
512
|
@media screen and (min-width: 1024px) {
|
|
451
513
|
.directive-typst:not(.preview-only) {
|
|
452
514
|
flex-direction: row;
|
|
453
|
-
height: calc(100dvh - 128px);
|
|
454
515
|
|
|
455
516
|
.preview-container {
|
|
456
517
|
flex: 1;
|