scratchblocks-plus 1.0.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.
Files changed (119) hide show
  1. package/LICENSE +19 -0
  2. package/README.md +193 -0
  3. package/browser.es.js +8 -0
  4. package/browser.js +8 -0
  5. package/build/scratchblocks-plus.min.es.js +12 -0
  6. package/build/scratchblocks-plus.min.es.js.map +1 -0
  7. package/build/scratchblocks-plus.min.js +12 -0
  8. package/build/scratchblocks-plus.min.js.map +1 -0
  9. package/build/translations-all-es.js +11 -0
  10. package/build/translations-all-es.js.map +1 -0
  11. package/build/translations-all.js +11 -0
  12. package/build/translations-all.js.map +1 -0
  13. package/build/translations-es.js +11 -0
  14. package/build/translations-es.js.map +1 -0
  15. package/build/translations.js +11 -0
  16. package/build/translations.js.map +1 -0
  17. package/index.d.ts +297 -0
  18. package/index.js +229 -0
  19. package/locales/ab.json +1630 -0
  20. package/locales/af.json +1630 -0
  21. package/locales/all.d.ts +108 -0
  22. package/locales/all.js +161 -0
  23. package/locales/am.json +1925 -0
  24. package/locales/an.json +1630 -0
  25. package/locales/ar.json +1924 -0
  26. package/locales/ast.json +1630 -0
  27. package/locales/az.json +1925 -0
  28. package/locales/be.json +1630 -0
  29. package/locales/bg.json +1924 -0
  30. package/locales/bn.json +1630 -0
  31. package/locales/ca.json +1930 -0
  32. package/locales/ckb.json +1630 -0
  33. package/locales/cs.json +1930 -0
  34. package/locales/cy.json +1929 -0
  35. package/locales/da.json +1924 -0
  36. package/locales/de.json +1929 -0
  37. package/locales/el.json +1931 -0
  38. package/locales/eo.json +1630 -0
  39. package/locales/es-419.json +1924 -0
  40. package/locales/es.json +1929 -0
  41. package/locales/et.json +1924 -0
  42. package/locales/eu.json +1924 -0
  43. package/locales/fa.json +1929 -0
  44. package/locales/fi.json +1924 -0
  45. package/locales/fil.json +1631 -0
  46. package/locales/forums.js +37 -0
  47. package/locales/fr.json +1929 -0
  48. package/locales/fy.json +1630 -0
  49. package/locales/ga.json +1924 -0
  50. package/locales/gd.json +1929 -0
  51. package/locales/gl.json +1924 -0
  52. package/locales/ha.json +1630 -0
  53. package/locales/he.json +1929 -0
  54. package/locales/hi.json +1635 -0
  55. package/locales/hr.json +1929 -0
  56. package/locales/ht.json +1630 -0
  57. package/locales/hu.json +1930 -0
  58. package/locales/hy.json +1630 -0
  59. package/locales/id.json +1929 -0
  60. package/locales/is.json +1924 -0
  61. package/locales/it.json +1929 -0
  62. package/locales/ja-Hira.json +1637 -0
  63. package/locales/ja.json +1931 -0
  64. package/locales/ka.json +1630 -0
  65. package/locales/kk.json +1632 -0
  66. package/locales/km.json +1630 -0
  67. package/locales/ko.json +1924 -0
  68. package/locales/ku.json +1632 -0
  69. package/locales/lt.json +1924 -0
  70. package/locales/lv.json +1924 -0
  71. package/locales/mi.json +1924 -0
  72. package/locales/mn.json +1631 -0
  73. package/locales/nb.json +1929 -0
  74. package/locales/nl.json +1929 -0
  75. package/locales/nn.json +1630 -0
  76. package/locales/nso.json +1630 -0
  77. package/locales/oc.json +1630 -0
  78. package/locales/or.json +1631 -0
  79. package/locales/pl.json +1929 -0
  80. package/locales/pt-br.json +1924 -0
  81. package/locales/pt.json +1929 -0
  82. package/locales/qu.json +1630 -0
  83. package/locales/rap.json +1632 -0
  84. package/locales/ro.json +1929 -0
  85. package/locales/ru.json +1929 -0
  86. package/locales/sk.json +1924 -0
  87. package/locales/sl.json +1929 -0
  88. package/locales/sr.json +1924 -0
  89. package/locales/sv.json +1924 -0
  90. package/locales/sw.json +1630 -0
  91. package/locales/th.json +1924 -0
  92. package/locales/tn.json +1630 -0
  93. package/locales/tr.json +1932 -0
  94. package/locales/uk.json +1924 -0
  95. package/locales/uz.json +1631 -0
  96. package/locales/vi.json +1925 -0
  97. package/locales/xh.json +1630 -0
  98. package/locales/zh-cn.json +1930 -0
  99. package/locales/zh-tw.json +1930 -0
  100. package/locales/zu.json +1918 -0
  101. package/package.json +81 -0
  102. package/scratch2/blocks.js +1000 -0
  103. package/scratch2/draw.js +452 -0
  104. package/scratch2/filter.js +78 -0
  105. package/scratch2/index.js +12 -0
  106. package/scratch2/style.css.js +148 -0
  107. package/scratch2/style.js +214 -0
  108. package/scratch3/blocks.js +1134 -0
  109. package/scratch3/draw.js +334 -0
  110. package/scratch3/index.js +12 -0
  111. package/scratch3/style.css.js +280 -0
  112. package/scratch3/style.js +877 -0
  113. package/syntax/blocks.js +921 -0
  114. package/syntax/commands.js +1755 -0
  115. package/syntax/dropdowns.js +688 -0
  116. package/syntax/extensions.js +34 -0
  117. package/syntax/index.js +17 -0
  118. package/syntax/model.js +566 -0
  119. package/syntax/syntax.js +1091 -0
@@ -0,0 +1,452 @@
1
+ /* for constructing SVGs */
2
+
3
+ function assert(bool, message) {
4
+ if (!bool) {
5
+ throw new Error(`Assertion failed! ${message || ""}`)
6
+ }
7
+ }
8
+
9
+ // set by SVG.init
10
+ let document
11
+ let xml
12
+
13
+ const directProps = {
14
+ textContent: true,
15
+ }
16
+
17
+ export default class SVG {
18
+ static init(window) {
19
+ document = window.document
20
+ const DOMParser = window.DOMParser
21
+ xml = new DOMParser().parseFromString("<xml></xml>", "application/xml")
22
+ SVG.XMLSerializer = window.XMLSerializer
23
+ }
24
+
25
+ static makeCanvas() {
26
+ return document.createElement("canvas")
27
+ }
28
+
29
+ static cdata(content) {
30
+ return xml.createCDATASection(content)
31
+ }
32
+
33
+ static el(name, props) {
34
+ const el = document.createElementNS("http://www.w3.org/2000/svg", name)
35
+ return SVG.setProps(el, props)
36
+ }
37
+
38
+ static setProps(el, props) {
39
+ for (const key in props) {
40
+ const value = String(props[key])
41
+ if (directProps[key]) {
42
+ el[key] = value
43
+ } else if (
44
+ props[key] != null &&
45
+ Object.prototype.hasOwnProperty.call(props, key)
46
+ ) {
47
+ el.setAttributeNS(null, key, value)
48
+ }
49
+ }
50
+ return el
51
+ }
52
+
53
+ static withChildren(el, children) {
54
+ for (const child of children) {
55
+ el.appendChild(child)
56
+ }
57
+ return el
58
+ }
59
+
60
+ static group(children) {
61
+ return SVG.withChildren(SVG.el("g"), children)
62
+ }
63
+
64
+ static newSVG(width, height, scale) {
65
+ return SVG.el("svg", {
66
+ version: "1.1",
67
+ width: width * scale,
68
+ height: height * scale,
69
+ viewBox: `0 0 ${width} ${height}`,
70
+ })
71
+ }
72
+
73
+ static polygon(props) {
74
+ return SVG.el("polygon", { ...props, points: props.points.join(" ") })
75
+ }
76
+
77
+ static path(props) {
78
+ return SVG.el("path", { ...props, path: null, d: props.path.join(" ") })
79
+ }
80
+
81
+ static text(x, y, content, props) {
82
+ const text = SVG.el("text", { ...props, x: x, y: y, textContent: content })
83
+ return text
84
+ }
85
+
86
+ static symbol(href) {
87
+ return SVG.el("use", {
88
+ href: href,
89
+ })
90
+ }
91
+
92
+ static move(dx, dy, el) {
93
+ SVG.setProps(el, {
94
+ transform: `translate(${dx} ${dy})`,
95
+ })
96
+ return el
97
+ }
98
+
99
+ // translatePath takes a path string such as "M 0 0 L 0 10 L 10 0 Z", fins
100
+ // the individual X/Y components, and translates them by dx/dy, so as to
101
+ // "move" the path.
102
+ //
103
+ // This is not a particularly good way of doing this, but given we control
104
+ // the inputs to it it works well enough I guess?
105
+ static translatePath(dx, dy, path) {
106
+ let isX = true
107
+ const parts = path.split(/\s+/)
108
+ const out = []
109
+ for (let i = 0; i < parts.length; i++) {
110
+ let part = parts[i]
111
+ if (part === "A") {
112
+ const j = i + 5
113
+ out.push("A")
114
+ while (i < j) {
115
+ out.push(parts[++i])
116
+ }
117
+ continue
118
+ } else if (/[A-Za-z]/.test(part)) {
119
+ // This assertion means the path was not a valid sequence of
120
+ // [operation, X coordinate, Y coordinate, ...].
121
+ //
122
+ // It could indicate missing whitespace between the coordinates and the
123
+ // operation.
124
+ assert(isX, "translatePath: invalid argument")
125
+ } else {
126
+ part = +part
127
+ part += isX ? dx : dy
128
+ isX = !isX
129
+ }
130
+ out.push(part)
131
+ }
132
+ return out.join(" ")
133
+ }
134
+
135
+ /* shapes */
136
+
137
+ static rect(w, h, props) {
138
+ return SVG.el("rect", { ...props, x: 0, y: 0, width: w, height: h })
139
+ }
140
+
141
+ static ellipse(w, h, props) {
142
+ return SVG.el("ellipse", {
143
+ ...props,
144
+ cx: w / 2,
145
+ cy: h / 2,
146
+ rx: w / 2,
147
+ ry: h / 2,
148
+ })
149
+ }
150
+
151
+ static arc(p1x, p1y, p2x, p2y, rx, ry) {
152
+ return `L ${p1x} ${p1y} A ${rx} ${ry} 0 0 1 ${p2x} ${p2y}`
153
+ }
154
+
155
+ static arcw(p1x, p1y, p2x, p2y, rx, ry) {
156
+ return `L ${p1x} ${p1y} A ${rx} ${ry} 0 0 0 ${p2x} ${p2y}`
157
+ }
158
+
159
+ static roundedPath(w, h) {
160
+ const r = h / 2
161
+ return [
162
+ "M",
163
+ r,
164
+ 0,
165
+ SVG.arc(w - r, 0, w - r, h, r, r),
166
+ SVG.arc(r, h, r, 0, r, r),
167
+ "Z",
168
+ ]
169
+ }
170
+
171
+ static roundedRect(w, h, props) {
172
+ return SVG.path({ ...props, path: SVG.roundedPath(w, h) })
173
+ }
174
+
175
+ static pointedPath(w, h) {
176
+ const r = h / 2
177
+ return [
178
+ "M",
179
+ r,
180
+ 0,
181
+ "L",
182
+ w - r,
183
+ 0,
184
+ w,
185
+ r,
186
+ "L",
187
+ w,
188
+ r,
189
+ w - r,
190
+ h,
191
+ "L",
192
+ r,
193
+ h,
194
+ 0,
195
+ r,
196
+ "L",
197
+ 0,
198
+ r,
199
+ r,
200
+ 0,
201
+ "Z",
202
+ ]
203
+ }
204
+
205
+ static pointedRect(w, h, props) {
206
+ return SVG.path({ ...props, path: SVG.pointedPath(w, h) })
207
+ }
208
+
209
+ static getTop(w) {
210
+ return `M 0 3
211
+ L 3 0
212
+ L 13 0
213
+ L 16 3
214
+ L 24 3
215
+ L 27 0
216
+ L ${w - 3} 0
217
+ L ${w} 3`
218
+ }
219
+
220
+ static getRingTop(w) {
221
+ return `M 0 3
222
+ L 3 0
223
+ L 7 0
224
+ L 10 3
225
+ L 16 3
226
+ L 19 0
227
+ L ${w - 3} 0
228
+ L ${w} 3`
229
+ }
230
+
231
+ static getRightAndBottom(w, y, hasNotch, inset) {
232
+ if (typeof inset === "undefined") {
233
+ inset = 0
234
+ }
235
+ let arr = ["L", w, y - 3, "L", w - 3, y]
236
+ if (hasNotch) {
237
+ arr = arr.concat([
238
+ "L",
239
+ inset + 27,
240
+ y,
241
+ "L",
242
+ inset + 24,
243
+ y + 3,
244
+ "L",
245
+ inset + 16,
246
+ y + 3,
247
+ "L",
248
+ inset + 13,
249
+ y,
250
+ ])
251
+ }
252
+ if (inset > 0) {
253
+ arr = arr.concat(["L", inset + 2, y, "L", inset, y + 2])
254
+ } else {
255
+ arr = arr.concat(["L", inset + 3, y, "L", 0, y - 3])
256
+ }
257
+ return arr.join(" ")
258
+ }
259
+
260
+ static getArm(w, armTop) {
261
+ return `L 15 ${armTop - 2}
262
+ L 17 ${armTop}
263
+ L ${w - 3} ${armTop}
264
+ L ${w} ${armTop + 3}`
265
+ }
266
+
267
+ static stackRect(w, h, props) {
268
+ return SVG.path({
269
+ ...props,
270
+ path: [SVG.getTop(w), SVG.getRightAndBottom(w, h, true, 0), "Z"],
271
+ })
272
+ }
273
+
274
+ static capPath(w, h) {
275
+ return [SVG.getTop(w), SVG.getRightAndBottom(w, h, false, 0), "Z"]
276
+ }
277
+
278
+ static capRect(w, h, props) {
279
+ return SVG.path({ ...props, path: SVG.capPath(w, h) })
280
+ }
281
+
282
+ static hatRect(w, h, props) {
283
+ return SVG.path({
284
+ ...props,
285
+ path: [
286
+ "M",
287
+ 0,
288
+ 12,
289
+ SVG.arc(0, 12, 80, 10, 80, 80),
290
+ "L",
291
+ w - 3,
292
+ 10,
293
+ "L",
294
+ w,
295
+ 10 + 3,
296
+ SVG.getRightAndBottom(w, h, true),
297
+ "Z",
298
+ ],
299
+ })
300
+ }
301
+
302
+ static curve(p1x, p1y, p2x, p2y, roundness) {
303
+ roundness = roundness || 0.42
304
+ const midX = (p1x + p2x) / 2.0
305
+ const midY = (p1y + p2y) / 2.0
306
+ const cx = Math.round(midX + roundness * (p2y - p1y))
307
+ const cy = Math.round(midY - roundness * (p2x - p1x))
308
+ return `${cx} ${cy} ${p2x} ${p2y}`
309
+ }
310
+
311
+ static procHatBase(w, h, archRoundness, props) {
312
+ // TODO use arc()
313
+ archRoundness = Math.min(0.2, 35 / w)
314
+ return SVG.path({
315
+ ...props,
316
+ path: [
317
+ "M",
318
+ 0,
319
+ 15,
320
+ "Q",
321
+ SVG.curve(0, 15, w, 15, archRoundness),
322
+ SVG.getRightAndBottom(w, h, true),
323
+ "M",
324
+ -1,
325
+ 13,
326
+ "Q",
327
+ SVG.curve(-1, 13, w + 1, 13, archRoundness),
328
+ "Q",
329
+ SVG.curve(w + 1, 13, w, 16, 0.6),
330
+ "Q",
331
+ SVG.curve(w, 16, 0, 16, -archRoundness),
332
+ "Q",
333
+ SVG.curve(0, 16, -1, 13, 0.6),
334
+ "Z",
335
+ ],
336
+ })
337
+ }
338
+
339
+ static procHatCap(w, h, archRoundness) {
340
+ // TODO use arc()
341
+ // TODO this doesn't look quite right
342
+ return SVG.path({
343
+ path: [
344
+ "M",
345
+ -1,
346
+ 13,
347
+ "Q",
348
+ SVG.curve(-1, 13, w + 1, 13, archRoundness),
349
+ "Q",
350
+ SVG.curve(w + 1, 13, w, 16, 0.6),
351
+ "Q",
352
+ SVG.curve(w, 16, 0, 16, -archRoundness),
353
+ "Q",
354
+ SVG.curve(0, 16, -1, 13, 0.6),
355
+ "Z",
356
+ ],
357
+ class: "sb-define-hat-cap",
358
+ })
359
+ }
360
+
361
+ static procHatRect(w, h, props) {
362
+ const q = 52
363
+ const y = h - q
364
+
365
+ const archRoundness = Math.min(0.2, 35 / w)
366
+
367
+ return SVG.move(
368
+ 0,
369
+ y,
370
+ SVG.group([
371
+ SVG.procHatBase(w, q, archRoundness, props),
372
+ SVG.procHatCap(w, q, archRoundness),
373
+ ]),
374
+ )
375
+ }
376
+
377
+ static mouthRect(w, h, isFinal, lines, props) {
378
+ let y = lines[0].height
379
+ const p = [SVG.getTop(w), SVG.getRightAndBottom(w, y, true, 15)]
380
+ for (let i = 1; i < lines.length; i += 2) {
381
+ const isLast = i + 2 === lines.length
382
+
383
+ y += lines[i].height - 3
384
+ p.push(SVG.getArm(w, y))
385
+
386
+ const hasNotch = !(isLast && isFinal)
387
+ const inset = isLast ? 0 : 15
388
+ y += lines[i + 1].height + 3
389
+ p.push(SVG.getRightAndBottom(w, y, hasNotch, inset))
390
+ }
391
+ return SVG.path({ ...props, path: p })
392
+ }
393
+
394
+ static ringRect(w, h, cy, cw, ch, shape, props) {
395
+ const r = 8
396
+ const func =
397
+ shape === "reporter"
398
+ ? SVG.roundedPath
399
+ : shape === "boolean"
400
+ ? SVG.pointedPath
401
+ : SVG.capPath
402
+ return SVG.path({
403
+ ...props,
404
+ path: [
405
+ "M",
406
+ r,
407
+ 0,
408
+ SVG.arcw(r, 0, 0, r, r, r),
409
+ SVG.arcw(0, h - r, r, h, r, r),
410
+ SVG.arcw(w - r, h, w, h - r, r, r),
411
+ SVG.arcw(w, r, w - r, 0, r, r),
412
+ "Z",
413
+ SVG.translatePath(4, cy || 4, func(cw, ch).join(" ")),
414
+ ],
415
+ "fill-rule": "even-odd",
416
+ })
417
+ }
418
+
419
+ static commentRect(w, h, props) {
420
+ const r = 6
421
+ return SVG.path({
422
+ ...props,
423
+ class: "sb-comment",
424
+ path: [
425
+ "M",
426
+ r,
427
+ 0,
428
+ SVG.arc(w - r, 0, w, r, r, r),
429
+ SVG.arc(w, h - r, w - r, h, r, r),
430
+ SVG.arc(r, h, 0, h - r, r, r),
431
+ SVG.arc(0, r, r, 0, r, r),
432
+ "Z",
433
+ ],
434
+ })
435
+ }
436
+
437
+ static commentLine(width, props) {
438
+ return SVG.move(
439
+ -width,
440
+ 9,
441
+ SVG.rect(width, 2, { ...props, class: "sb-comment-line" }),
442
+ )
443
+ }
444
+
445
+ static strikethroughLine(w, props) {
446
+ return SVG.path({
447
+ ...props,
448
+ path: ["M", 0, 0, "L", w, 0],
449
+ class: "sb-diff sb-diff-del",
450
+ })
451
+ }
452
+ }
@@ -0,0 +1,78 @@
1
+ import SVG from "./draw.js"
2
+
3
+ export default class Filter {
4
+ constructor(id, props) {
5
+ this.el = SVG.el("filter", {
6
+ ...props,
7
+ id: id,
8
+ x0: "-50%",
9
+ y0: "-50%",
10
+ width: "200%",
11
+ height: "200%",
12
+ })
13
+ this.highestId = 0
14
+ }
15
+
16
+ fe(name, props, children) {
17
+ const shortName = name.toLowerCase().replace(/gaussian|osite/, "")
18
+ const id = `${shortName}-${++this.highestId}`
19
+ this.el.appendChild(
20
+ SVG.withChildren(
21
+ SVG.el(`fe${name}`, { ...props, result: id }),
22
+ children || [],
23
+ ),
24
+ )
25
+ return id
26
+ }
27
+
28
+ comp(op, in1, in2, props) {
29
+ return this.fe("Composite", { ...props, operator: op, in: in1, in2: in2 })
30
+ }
31
+
32
+ subtract(in1, in2) {
33
+ return this.comp("arithmetic", in1, in2, { k2: +1, k3: -1 })
34
+ }
35
+
36
+ offset(dx, dy, in1) {
37
+ return this.fe("Offset", {
38
+ in: in1,
39
+ dx: dx,
40
+ dy: dy,
41
+ })
42
+ }
43
+
44
+ flood(color, opacity, in1) {
45
+ return this.fe("Flood", {
46
+ in: in1,
47
+ "flood-color": color,
48
+ "flood-opacity": opacity,
49
+ })
50
+ }
51
+
52
+ blur(dev, in1) {
53
+ return this.fe("GaussianBlur", {
54
+ in: in1,
55
+ stdDeviation: `${dev} ${dev}`,
56
+ })
57
+ }
58
+
59
+ colorMatrix(in1, values) {
60
+ return this.fe("ColorMatrix", {
61
+ in: in1,
62
+ type: "matrix",
63
+ values: values.join(" "),
64
+ })
65
+ }
66
+
67
+ merge(children) {
68
+ this.fe(
69
+ "Merge",
70
+ {},
71
+ children.map(name =>
72
+ SVG.el("feMergeNode", {
73
+ in: name,
74
+ }),
75
+ ),
76
+ )
77
+ }
78
+ }
@@ -0,0 +1,12 @@
1
+ import SVG from "./draw.js"
2
+ import { LabelView } from "./blocks.js"
3
+ import style from "./style.js"
4
+
5
+ export function init(window) {
6
+ SVG.init(window)
7
+
8
+ LabelView.measuring = SVG.makeCanvas().getContext("2d")
9
+ }
10
+
11
+ export const makeStyle = style.makeStyle
12
+ export { newView } from "./blocks.js"
@@ -0,0 +1,148 @@
1
+ // Processed by Rollup
2
+ export default `
3
+ .sb-label {
4
+ font-family: Lucida Grande, Verdana, Arial, DejaVu Sans, sans-serif;
5
+ font-weight: bold;
6
+ fill: #fff;
7
+ font-size: 10px;
8
+ word-spacing: +1px;
9
+ }
10
+
11
+ .sb-obsolete {
12
+ fill: #d42828;
13
+ }
14
+ .sb-motion {
15
+ fill: #4a6cd4;
16
+ }
17
+ .sb-looks {
18
+ fill: #8a55d7;
19
+ }
20
+ .sb-sound {
21
+ fill: #bb42c3;
22
+ }
23
+ .sb-pen {
24
+ fill: #0e9a6c;
25
+ }
26
+ .sb-events {
27
+ fill: #c88330;
28
+ }
29
+ .sb-control {
30
+ fill: #e1a91a;
31
+ }
32
+ .sb-sensing {
33
+ fill: #2ca5e2;
34
+ }
35
+ .sb-operators {
36
+ fill: #5cb712;
37
+ }
38
+ .sb-variables {
39
+ fill: #ee7d16;
40
+ }
41
+ .sb-list {
42
+ fill: #cc5b22;
43
+ }
44
+ .sb-custom {
45
+ fill: #632d99;
46
+ }
47
+ .sb-custom-arg {
48
+ fill: #5947b1;
49
+ }
50
+ .sb-extension {
51
+ fill: #4b4a60;
52
+ }
53
+ .sb-grey {
54
+ fill: #969696;
55
+ }
56
+
57
+ .sb-bevel {
58
+ filter: url(#bevelFilter);
59
+ }
60
+
61
+ .sb-input {
62
+ filter: url(#inputBevelFilter);
63
+ }
64
+ .sb-input-number,
65
+ .sb-input-string,
66
+ .sb-input-number-dropdown {
67
+ fill: #fff;
68
+ }
69
+ .sb-literal-number,
70
+ .sb-literal-string,
71
+ .sb-literal-number-dropdown,
72
+ .sb-literal-dropdown {
73
+ font-weight: normal;
74
+ font-size: 9px;
75
+ word-spacing: 0;
76
+ }
77
+ .sb-literal-number,
78
+ .sb-literal-string,
79
+ .sb-literal-number-dropdown {
80
+ fill: #000;
81
+ }
82
+
83
+ .sb-darker {
84
+ filter: url(#inputDarkFilter);
85
+ }
86
+
87
+ .sb-outline {
88
+ stroke: #fff;
89
+ stroke-opacity: 0.2;
90
+ stroke-width: 2;
91
+ fill: none;
92
+ }
93
+
94
+ .sb-define-hat-cap {
95
+ stroke: #632d99;
96
+ stroke-width: 1;
97
+ fill: #8e2ec2;
98
+ }
99
+
100
+ .sb-comment {
101
+ fill: #ffffa5;
102
+ stroke: #d0d1d2;
103
+ stroke-width: 1;
104
+ }
105
+ .sb-comment-line {
106
+ fill: #ffff80;
107
+ }
108
+ .sb-comment-label {
109
+ font-family: Helvetica, Arial, DejaVu Sans, sans-serif;
110
+ font-weight: bold;
111
+ fill: #5c5d5f;
112
+ word-spacing: 0;
113
+ font-size: 12px;
114
+ }
115
+
116
+ .sb-diff {
117
+ fill: none;
118
+ stroke: #000;
119
+ }
120
+ .sb-diff-ins {
121
+ stroke-width: 2px;
122
+ }
123
+ .sb-diff-del {
124
+ stroke-width: 3px;
125
+ }
126
+
127
+ /* Block highlight styles */
128
+ .sb-highlight:not(.sb-blink) {
129
+ fill: #FBF883 !important;
130
+ }
131
+
132
+ /* Blinking animation for jump-to-block */
133
+ .sb-blink {
134
+ animation: sb-blink-animation 0.5s 3;
135
+ }
136
+
137
+ @keyframes sb-blink-animation {
138
+ 0% {
139
+ fill: #FBF883;
140
+ }
141
+ 50% {
142
+ fill: #FBF883;
143
+ animation-timing-function: step-start;
144
+ }
145
+ 100% {
146
+ }
147
+ }
148
+ `