hyperbook 0.99.0 → 0.100.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.
- package/dist/assets/codemirror/codemirror.bundle.js +10 -10
- package/dist/assets/directive-abc-music/style.css +23 -0
- package/dist/assets/directive-archive/style.css +9 -3
- package/dist/assets/directive-download/style.css +9 -3
- package/dist/assets/directive-openscad/client.js +77 -40
- package/dist/assets/directive-openscad/style.css +36 -3
- package/dist/assets/directive-p5/client.js +8 -7
- package/dist/assets/directive-p5/style.css +25 -0
- package/dist/assets/directive-protect/style.css +11 -5
- package/dist/assets/directive-pyide/client.js +1207 -170
- package/dist/assets/directive-pyide/style.css +158 -2
- package/dist/assets/directive-typst/style.css +44 -2
- package/dist/assets/directive-webide/client.js +40 -18
- package/dist/assets/directive-webide/style.css +31 -1
- package/dist/assets/shell.css +16 -16
- package/dist/index.js +558 -318
- package/dist/locales/de.json +1 -0
- package/dist/locales/en.json +1 -0
- package/package.json +7 -5
|
@@ -50,6 +50,132 @@
|
|
|
50
50
|
font-family: hyperbook-monospace, monospace;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/* Prompt bar, shown while the script waits for input. Styled as its own
|
|
54
|
+
console-like strip below the output/canvas panel so it reads as "the program
|
|
55
|
+
is waiting for you" rather than as part of the page chrome. */
|
|
56
|
+
.directive-pyide .stdin {
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-wrap: wrap;
|
|
59
|
+
align-items: center;
|
|
60
|
+
gap: 8px 10px;
|
|
61
|
+
flex: 0 0 auto;
|
|
62
|
+
margin-top: 8px;
|
|
63
|
+
padding: 10px 12px;
|
|
64
|
+
border: 1px solid var(--color-brand);
|
|
65
|
+
border-radius: 8px;
|
|
66
|
+
background-color: color-mix(in srgb, var(--color-brand) 7%, transparent);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.directive-pyide .stdin.hidden {
|
|
70
|
+
display: none;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Blinking caret marks the waiting state without needing extra markup. */
|
|
74
|
+
.directive-pyide .stdin::before {
|
|
75
|
+
content: "❯";
|
|
76
|
+
flex: 0 0 auto;
|
|
77
|
+
font-family: hyperbook-monospace, monospace;
|
|
78
|
+
font-weight: 700;
|
|
79
|
+
line-height: 1;
|
|
80
|
+
color: var(--color-brand);
|
|
81
|
+
animation: pyide-stdin-caret 1.4s ease-in-out infinite;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@keyframes pyide-stdin-caret {
|
|
85
|
+
0%,
|
|
86
|
+
100% {
|
|
87
|
+
opacity: 1;
|
|
88
|
+
}
|
|
89
|
+
50% {
|
|
90
|
+
opacity: 0.3;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@media (prefers-reduced-motion: reduce) {
|
|
95
|
+
.directive-pyide .stdin::before {
|
|
96
|
+
animation: none;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.directive-pyide .stdin .stdin-prompt {
|
|
101
|
+
flex: 0 1 auto;
|
|
102
|
+
min-width: 0;
|
|
103
|
+
font-family: hyperbook-monospace, monospace;
|
|
104
|
+
color: var(--color-text);
|
|
105
|
+
white-space: pre-wrap;
|
|
106
|
+
overflow-wrap: anywhere;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.directive-pyide .stdin .stdin-prompt:empty {
|
|
110
|
+
display: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* Grows to fill the row, and wraps to its own line when the prompt is long. */
|
|
114
|
+
.directive-pyide .stdin .stdin-field {
|
|
115
|
+
flex: 1 1 160px;
|
|
116
|
+
min-width: 0;
|
|
117
|
+
padding: 8px 12px;
|
|
118
|
+
border: 1px solid var(--color-spacer);
|
|
119
|
+
border-radius: 6px;
|
|
120
|
+
font-family: hyperbook-monospace, monospace;
|
|
121
|
+
font-size: 1em;
|
|
122
|
+
line-height: 1.4;
|
|
123
|
+
background-color: var(--color-background);
|
|
124
|
+
color: var(--color-text);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.directive-pyide .stdin .stdin-field:focus {
|
|
128
|
+
outline: none;
|
|
129
|
+
border-color: var(--color-brand);
|
|
130
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-brand) 25%, transparent);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Overrides the shared .directive-pyide button reset, which is borderless and
|
|
134
|
+
full-width for the tab/toolbar groups.
|
|
135
|
+
|
|
136
|
+
The fill is a tint of the brand mixed into --color-background rather than
|
|
137
|
+
flat --color-brand, and the label is always --color-text. That keeps the
|
|
138
|
+
contrast guaranteed by the theme's own background/text pairing in both
|
|
139
|
+
colour schemes: --color-brand-text is only defined for light mode, and
|
|
140
|
+
--color-brand-dark falls back to --color-brand, so neither can be relied on
|
|
141
|
+
to stay legible against a brand fill. */
|
|
142
|
+
.directive-pyide .stdin .stdin-submit {
|
|
143
|
+
flex: 0 0 auto;
|
|
144
|
+
padding: 8px 18px;
|
|
145
|
+
border: 1px solid var(--color-brand);
|
|
146
|
+
border-radius: 6px;
|
|
147
|
+
background-color: color-mix(
|
|
148
|
+
in srgb,
|
|
149
|
+
var(--color-brand) 18%,
|
|
150
|
+
var(--color-background)
|
|
151
|
+
);
|
|
152
|
+
color: var(--color-text);
|
|
153
|
+
font-weight: 600;
|
|
154
|
+
line-height: 1.4;
|
|
155
|
+
cursor: pointer;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.directive-pyide .stdin .stdin-submit:hover {
|
|
159
|
+
background-color: color-mix(
|
|
160
|
+
in srgb,
|
|
161
|
+
var(--color-brand) 32%,
|
|
162
|
+
var(--color-background)
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.directive-pyide .stdin .stdin-submit:active {
|
|
167
|
+
background-color: color-mix(
|
|
168
|
+
in srgb,
|
|
169
|
+
var(--color-brand) 45%,
|
|
170
|
+
var(--color-background)
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.directive-pyide .stdin .stdin-submit:focus-visible {
|
|
175
|
+
outline: 2px solid var(--color-text);
|
|
176
|
+
outline-offset: 2px;
|
|
177
|
+
}
|
|
178
|
+
|
|
53
179
|
.directive-pyide .output .error-line {
|
|
54
180
|
color: #b42318;
|
|
55
181
|
}
|
|
@@ -128,7 +254,11 @@
|
|
|
128
254
|
linear-gradient(45deg, transparent 75%, #cccccc 75%),
|
|
129
255
|
linear-gradient(-45deg, transparent 75%, #cccccc 75%);
|
|
130
256
|
background-size: 20px 20px;
|
|
131
|
-
background-position:
|
|
257
|
+
background-position:
|
|
258
|
+
0 0,
|
|
259
|
+
0 10px,
|
|
260
|
+
10px -10px,
|
|
261
|
+
-10px 0px;
|
|
132
262
|
}
|
|
133
263
|
|
|
134
264
|
.directive-pyide .canvas {
|
|
@@ -247,6 +377,31 @@
|
|
|
247
377
|
border-top-right-radius: 0;
|
|
248
378
|
}
|
|
249
379
|
|
|
380
|
+
/* Icon-only toolbar: the written labels (Reset/Copy/Download) made this row
|
|
381
|
+
wrap on narrow screens, so the wording moved into title/aria-label. */
|
|
382
|
+
.directive-pyide .buttons.bottom button {
|
|
383
|
+
flex: 0 0 auto;
|
|
384
|
+
min-width: 42px;
|
|
385
|
+
width: 42px;
|
|
386
|
+
padding: 8px 0;
|
|
387
|
+
display: flex;
|
|
388
|
+
align-items: center;
|
|
389
|
+
justify-content: center;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.directive-pyide .buttons.bottom button .icon {
|
|
393
|
+
width: 18px;
|
|
394
|
+
height: 18px;
|
|
395
|
+
display: block;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/* Fullscreen sits apart, at the trailing edge of the toolbar. */
|
|
399
|
+
.directive-pyide .buttons.bottom button.fullscreen {
|
|
400
|
+
margin-inline-start: auto;
|
|
401
|
+
border-right: none;
|
|
402
|
+
border-left: 1px solid var(--color-spacer);
|
|
403
|
+
}
|
|
404
|
+
|
|
250
405
|
.directive-pyide .test-heading {
|
|
251
406
|
font-size: 1.1em;
|
|
252
407
|
font-weight: bold;
|
|
@@ -375,7 +530,8 @@
|
|
|
375
530
|
border-top-right-radius: 0;
|
|
376
531
|
}
|
|
377
532
|
|
|
378
|
-
.directive-pyide[data-canvas="true"].canvas-split-mode
|
|
533
|
+
.directive-pyide[data-canvas="true"].canvas-split-mode
|
|
534
|
+
.canvas-output-splitter {
|
|
379
535
|
display: block;
|
|
380
536
|
}
|
|
381
537
|
}
|
|
@@ -343,8 +343,14 @@ code-input {
|
|
|
343
343
|
|
|
344
344
|
.directive-typst .binary-files-section summary .summary-indicator {
|
|
345
345
|
transition: transform 0.2s;
|
|
346
|
-
display: inline-
|
|
347
|
-
|
|
346
|
+
display: inline-flex;
|
|
347
|
+
align-items: center;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.directive-typst .binary-files-section summary .summary-indicator .icon {
|
|
351
|
+
width: 14px;
|
|
352
|
+
height: 14px;
|
|
353
|
+
display: block;
|
|
348
354
|
}
|
|
349
355
|
|
|
350
356
|
.directive-typst .binary-files-section[open] summary .summary-indicator {
|
|
@@ -484,6 +490,19 @@ code-input {
|
|
|
484
490
|
padding: 8px 0;
|
|
485
491
|
}
|
|
486
492
|
|
|
493
|
+
.directive-typst button.fullscreen .icon {
|
|
494
|
+
width: 18px;
|
|
495
|
+
height: 18px;
|
|
496
|
+
display: block;
|
|
497
|
+
margin: 0 auto;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.directive-typst .add-source-file .icon {
|
|
501
|
+
width: 16px;
|
|
502
|
+
height: 16px;
|
|
503
|
+
display: block;
|
|
504
|
+
}
|
|
505
|
+
|
|
487
506
|
.directive-typst button:hover {
|
|
488
507
|
background-color: var(--color-spacer);
|
|
489
508
|
}
|
|
@@ -531,3 +550,26 @@ code-input {
|
|
|
531
550
|
}
|
|
532
551
|
}
|
|
533
552
|
}
|
|
553
|
+
|
|
554
|
+
/* Icon-only toolbar: the written labels made this row wrap on narrow screens,
|
|
555
|
+
so the wording moved into title/aria-label. */
|
|
556
|
+
.directive-typst .buttons.bottom button {
|
|
557
|
+
flex: 0 0 auto;
|
|
558
|
+
min-width: 42px;
|
|
559
|
+
width: 42px;
|
|
560
|
+
padding: 8px 0;
|
|
561
|
+
display: flex;
|
|
562
|
+
align-items: center;
|
|
563
|
+
justify-content: center;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
.directive-typst .buttons.bottom button .icon {
|
|
567
|
+
width: 18px;
|
|
568
|
+
height: 18px;
|
|
569
|
+
display: block;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/* Fullscreen sits apart, at the trailing edge of the toolbar. */
|
|
573
|
+
.directive-typst .buttons.bottom button.fullscreen {
|
|
574
|
+
margin-inline-start: auto;
|
|
575
|
+
}
|
|
@@ -18,8 +18,13 @@ hyperbook.webide = (function () {
|
|
|
18
18
|
|
|
19
19
|
const applySplitSize = (rawSize, isHorizontal) => {
|
|
20
20
|
const total = isHorizontal ? elem.clientWidth : elem.clientHeight;
|
|
21
|
-
const splitterSize = isHorizontal
|
|
22
|
-
|
|
21
|
+
const splitterSize = isHorizontal
|
|
22
|
+
? splitter.offsetWidth
|
|
23
|
+
: splitter.offsetHeight;
|
|
24
|
+
const maxSize = Math.max(
|
|
25
|
+
minPanelSize,
|
|
26
|
+
total - splitterSize - minPanelSize,
|
|
27
|
+
);
|
|
23
28
|
const clamped = Math.max(minPanelSize, Math.min(rawSize, maxSize));
|
|
24
29
|
container.style.flex = `0 0 ${clamped}px`;
|
|
25
30
|
return clamped;
|
|
@@ -79,7 +84,6 @@ hyperbook.webide = (function () {
|
|
|
79
84
|
if (!elem || !button) return;
|
|
80
85
|
const isFullscreen = document.fullscreenElement === elem;
|
|
81
86
|
const label = hyperbook.i18n.get("ide-fullscreen-enter");
|
|
82
|
-
button.textContent = "⛶";
|
|
83
87
|
button.title = label;
|
|
84
88
|
button.setAttribute("aria-label", label);
|
|
85
89
|
button.classList.toggle("active", isFullscreen);
|
|
@@ -121,21 +125,39 @@ hyperbook.webide = (function () {
|
|
|
121
125
|
const btnJS = elem.querySelector("button.js");
|
|
122
126
|
|
|
123
127
|
// Initialize CodeMirror instances
|
|
124
|
-
const cmHTML = editorHTMLDiv
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
128
|
+
const cmHTML = editorHTMLDiv
|
|
129
|
+
? (() => {
|
|
130
|
+
const src = editorHTMLDiv.textContent;
|
|
131
|
+
editorHTMLDiv.textContent = "";
|
|
132
|
+
return HyperbookCM.create(editorHTMLDiv, {
|
|
133
|
+
lang: "html",
|
|
134
|
+
value: src,
|
|
135
|
+
onChange: () => update(),
|
|
136
|
+
});
|
|
137
|
+
})()
|
|
138
|
+
: null;
|
|
139
|
+
const cmCSS = editorCSSDiv
|
|
140
|
+
? (() => {
|
|
141
|
+
const src = editorCSSDiv.textContent;
|
|
142
|
+
editorCSSDiv.textContent = "";
|
|
143
|
+
return HyperbookCM.create(editorCSSDiv, {
|
|
144
|
+
lang: "css",
|
|
145
|
+
value: src,
|
|
146
|
+
onChange: () => update(),
|
|
147
|
+
});
|
|
148
|
+
})()
|
|
149
|
+
: null;
|
|
150
|
+
const cmJS = editorJSDiv
|
|
151
|
+
? (() => {
|
|
152
|
+
const src = editorJSDiv.textContent;
|
|
153
|
+
editorJSDiv.textContent = "";
|
|
154
|
+
return HyperbookCM.create(editorJSDiv, {
|
|
155
|
+
lang: "javascript",
|
|
156
|
+
value: src,
|
|
157
|
+
onChange: () => update(),
|
|
158
|
+
});
|
|
159
|
+
})()
|
|
160
|
+
: null;
|
|
139
161
|
|
|
140
162
|
const frame = elem.getElementsByTagName("iframe")[0];
|
|
141
163
|
const template = elem.getAttribute("data-template");
|
|
@@ -39,7 +39,7 @@ code-input {
|
|
|
39
39
|
padding: 8px 16px;
|
|
40
40
|
padding-left: 0px;
|
|
41
41
|
overflow: hidden;
|
|
42
|
-
white-space:nowrap;
|
|
42
|
+
white-space: nowrap;
|
|
43
43
|
text-overflow: ellipsis;
|
|
44
44
|
background-color: var(--color-background);
|
|
45
45
|
color: var(--color-text);
|
|
@@ -148,6 +148,13 @@ code-input {
|
|
|
148
148
|
padding: 8px 0;
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
.directive-webide button.fullscreen .icon {
|
|
152
|
+
width: 18px;
|
|
153
|
+
height: 18px;
|
|
154
|
+
display: block;
|
|
155
|
+
margin: 0 auto;
|
|
156
|
+
}
|
|
157
|
+
|
|
151
158
|
.directive-webide button:hover {
|
|
152
159
|
background-color: var(--color-spacer);
|
|
153
160
|
}
|
|
@@ -186,3 +193,26 @@ code-input {
|
|
|
186
193
|
}
|
|
187
194
|
}
|
|
188
195
|
}
|
|
196
|
+
|
|
197
|
+
/* Icon-only toolbar: the written labels made this row wrap on narrow screens,
|
|
198
|
+
so the wording moved into title/aria-label. */
|
|
199
|
+
.directive-webide .buttons.bottom button {
|
|
200
|
+
flex: 0 0 auto;
|
|
201
|
+
min-width: 42px;
|
|
202
|
+
width: 42px;
|
|
203
|
+
padding: 8px 0;
|
|
204
|
+
display: flex;
|
|
205
|
+
align-items: center;
|
|
206
|
+
justify-content: center;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.directive-webide .buttons.bottom button .icon {
|
|
210
|
+
width: 18px;
|
|
211
|
+
height: 18px;
|
|
212
|
+
display: block;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* Fullscreen sits apart, at the trailing edge of the toolbar. */
|
|
216
|
+
.directive-webide .buttons.bottom button.fullscreen {
|
|
217
|
+
margin-inline-start: auto;
|
|
218
|
+
}
|
package/dist/assets/shell.css
CHANGED
|
@@ -140,25 +140,16 @@ header.inverted>.branding:hover {
|
|
|
140
140
|
color: var(--color-text);
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
/* `active` and `empty` sit on the <details>, not on the <summary>. */
|
|
144
|
+
.section.active>.name>.label {
|
|
144
145
|
color: var(--color-brand);
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
.section .name.empty {
|
|
148
|
-
color: var(--color-text-deactivated);
|
|
149
|
-
cursor: pointer;
|
|
150
|
-
font-style: italic;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
148
|
.section>.name:hover {
|
|
154
149
|
background: var(--color-spacer);
|
|
155
150
|
}
|
|
156
151
|
|
|
157
|
-
.section>.name
|
|
158
|
-
background: none;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
.section>.name.active {
|
|
152
|
+
.section.active>.name {
|
|
162
153
|
background: var(--color-background);
|
|
163
154
|
color: var(--color-brand);
|
|
164
155
|
}
|
|
@@ -698,14 +689,23 @@ nav li+li {
|
|
|
698
689
|
text-decoration: none;
|
|
699
690
|
}
|
|
700
691
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
692
|
+
/* The row always toggles the section, so it always looks clickable. Only the
|
|
693
|
+
title tells the two kinds of section apart: a section without its own page
|
|
694
|
+
is set in italics and is not a link.
|
|
704
695
|
|
|
705
|
-
|
|
696
|
+
Both rules are scoped with child combinators. Sections nest, so a descendant
|
|
697
|
+
selector would style a subsection according to its parent — a subsection with
|
|
698
|
+
content sitting inside an empty section came out italic. */
|
|
699
|
+
.section.empty>summary.name>.label {
|
|
706
700
|
font-style: italic;
|
|
707
701
|
}
|
|
708
702
|
|
|
703
|
+
/* A section that has its own page: the title is a real link and behaves like
|
|
704
|
+
one, while clicking elsewhere in the row just expands the section. */
|
|
705
|
+
.section:not(.empty)>summary.name>.label:hover {
|
|
706
|
+
text-decoration: underline;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
709
|
.section summary.name:after {
|
|
710
710
|
content: "\002B";
|
|
711
711
|
width: 1.2rem;
|