solarite 0.1.0 → 0.2.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/benchmarks/naive/Solarite.min.js +4 -0
- package/benchmarks/naive/index.html +14 -0
- package/benchmarks/naive/main.js +339 -0
- package/benchmarks/naive/package-lock.json +13 -0
- package/benchmarks/naive/package.json +23 -0
- package/benchmarks/readme.md +48 -0
- package/build/build.bat +3 -2
- package/build/build.js +1 -1
- package/dist/Solarite-debug.js +1941 -2791
- package/dist/Solarite.js +1697 -2511
- package/dist/Solarite.min.js +3 -3
- package/dist/udomdiff-license.txt +18 -0
- package/docs/index.md +695 -235
- package/docs/js/Playground.js +1 -1
- package/docs/js/codemirror/codemirror6.js +3683 -3206
- package/docs/js/codemirror/themeSolarIce.js +2 -2
- package/docs/js/documentation.js +2 -2
- package/docs/js/ui/CodeEditor.js +183 -45
- package/docs/js/ui/FlexResizer.js +15 -5
- package/docs/js/util/Errors.js +11 -0
- package/docs/media/documentation.css +6 -3
- package/index.html +462 -26
- package/package.json +1 -1
- package/readme.md +11 -1
- package/src/solarite/ExprPath.js +422 -135
- package/src/solarite/Globals.js +53 -0
- package/src/solarite/NodeGroup.js +300 -388
- package/src/solarite/Shell.js +31 -33
- package/src/solarite/Solarite.js +17 -2
- package/src/solarite/Template.js +75 -25
- package/src/solarite/Util.js +131 -7
- package/src/solarite/createSolarite.js +32 -25
- package/src/solarite/getArg.js +12 -12
- package/src/solarite/hash.js +18 -35
- package/src/solarite/r.js +128 -118
- package/src/solarite/watch3.js +98 -0
- package/src/{solarite → unused}/NodeGroupManager.js +86 -224
- package/src/unused/onConnect.js +79 -0
- package/src/{solarite → unused}/watch.js +2 -2
- package/src/{solarite → unused}/watch2.js +4 -4
- package/src/{solarite → util}/MultiValueMap.js +23 -12
- package/src/util/WeakArray.js +33 -0
- package/tests/Solarite.test.js +1108 -166
- package/tests/Testimony.js +274 -67
- package/tests/index.html +6 -35
- package/tests/run.bat +2 -0
- package/tests/NodeGroup.test.js +0 -115
- package/tests/Shell.test.js +0 -75
|
@@ -14,7 +14,7 @@ function themeSolarIce(lang, isDark=false) {
|
|
|
14
14
|
text = isDark ? "#aaa" : 'black',
|
|
15
15
|
darkBackground = "#21252b",
|
|
16
16
|
highlightBackground = isDark ? "#2c313a" : '#ddd',
|
|
17
|
-
background = isDark ? "
|
|
17
|
+
background = isDark ? "transparent" : 'white',
|
|
18
18
|
tooltipBackground = "#353a42",
|
|
19
19
|
selection = isDark ? "#234" : '#ccc',
|
|
20
20
|
cursor = "#528bff"
|
|
@@ -146,7 +146,7 @@ function themeSolarIce(lang, isDark=false) {
|
|
|
146
146
|
tag: [t.atom], // Css value like 'Arial' or 'none'. Keyword 'super' in javascript
|
|
147
147
|
color: lang === 'js'
|
|
148
148
|
? (isDark ? '#26f' : '#00f')
|
|
149
|
-
: (isDark ? '#
|
|
149
|
+
: (isDark ? '#26f' : '')
|
|
150
150
|
},
|
|
151
151
|
{
|
|
152
152
|
tag: [t.unit],
|
package/docs/js/documentation.js
CHANGED
|
@@ -21,12 +21,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
21
21
|
|
|
22
22
|
let prefix = `
|
|
23
23
|
<style>
|
|
24
|
-
html[dark] { background:
|
|
24
|
+
html[dark] { background: #0f1318; color: white }
|
|
25
25
|
body { font: 12px Arial; background: transparent !important }
|
|
26
26
|
</style>`;
|
|
27
27
|
let value = lines.join('\n');
|
|
28
28
|
|
|
29
|
-
let pg = new Playground({value, language: pre.getAttribute('lang'), width: 75, maxHeight:
|
|
29
|
+
let pg = new Playground({value, language: pre.getAttribute('lang'), width: 75, maxHeight: 1000, prefix, limitCodeEditorHeight: true})
|
|
30
30
|
pre.replaceWith(pg);
|
|
31
31
|
}
|
|
32
32
|
})
|
package/docs/js/ui/CodeEditor.js
CHANGED
|
@@ -246,7 +246,7 @@ export default class CodeEditor extends Solarite {
|
|
|
246
246
|
let doc = this.ownerDocument || window.top.document;
|
|
247
247
|
if (isDark === undefined)
|
|
248
248
|
isDark = doc.documentElement.hasAttribute('dark');
|
|
249
|
-
|
|
249
|
+
|
|
250
250
|
let languageExtensions = this.getLanguageExtension(this.language, this.languageConfig)
|
|
251
251
|
return [
|
|
252
252
|
//basicSetup,
|
|
@@ -258,8 +258,6 @@ export default class CodeEditor extends Solarite {
|
|
|
258
258
|
//foldGutter(),
|
|
259
259
|
drawSelection(),
|
|
260
260
|
indentUnit.of("\t"),
|
|
261
|
-
this.compartments.tabSize.of(EditorState.tabSize.of(this.tabSize)),
|
|
262
|
-
this.compartments.lineWrapping.of(wordWrap ? EditorView.lineWrapping : []),
|
|
263
261
|
EditorState.allowMultipleSelections.of(true),
|
|
264
262
|
indentOnInput(),
|
|
265
263
|
bracketMatching(),
|
|
@@ -285,11 +283,14 @@ export default class CodeEditor extends Solarite {
|
|
|
285
283
|
|
|
286
284
|
Extensions.changeDetection(this),
|
|
287
285
|
Extensions.asyncField,
|
|
286
|
+
|
|
288
287
|
|
|
288
|
+
syntaxHighlighting(defaultHighlightStyle, {fallback: true}), // fallback: true lets us use our own theme.
|
|
289
|
+
|
|
290
|
+
// Compartments let options be changed after init.
|
|
289
291
|
this.compartments.theme.of(themeSolarIce(this.language, isDark)),
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
292
|
+
this.compartments.tabSize.of(EditorState.tabSize.of(this.tabSize)),
|
|
293
|
+
this.compartments.lineWrapping.of(wordWrap ? EditorView.lineWrapping : []),
|
|
293
294
|
this.compartments.language.of(languageExtensions)
|
|
294
295
|
];
|
|
295
296
|
}
|
|
@@ -516,7 +517,7 @@ export default class CodeEditor extends Solarite {
|
|
|
516
517
|
|
|
517
518
|
|
|
518
519
|
render() {
|
|
519
|
-
this
|
|
520
|
+
r(this)`
|
|
520
521
|
<code-editor>
|
|
521
522
|
<style>
|
|
522
523
|
:host { position: relative; display: flex; flex-direction: column; min-width: 0; min-height: 0 }
|
|
@@ -609,18 +610,38 @@ var ParseUtil = {
|
|
|
609
610
|
wrap: parseMixed((node, docInput) => {
|
|
610
611
|
if (node.name == "StyleText")
|
|
611
612
|
return {parser: cssParser}
|
|
612
|
-
if (node.name == "ScriptText")
|
|
613
|
+
if (node.name == "ScriptText"/* || node.name == "Interpolation"*/)
|
|
613
614
|
return {parser: ParseUtil.jsParser}
|
|
614
615
|
|
|
615
616
|
// Use javascript parser for template expressions
|
|
616
617
|
if (node.type.name === 'Document' && docInput.doc) {
|
|
617
618
|
let code = docInput.doc.sliceString(node.from, node.to);
|
|
618
619
|
let overlay = [];
|
|
619
|
-
code.replace(/\${/g, (a, startIndex
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
620
|
+
//code.replace(/\${/g, (a, startIndex) => {
|
|
621
|
+
|
|
622
|
+
let ranges = ParseUtil.findJavaScriptRanges(code, 0);
|
|
623
|
+
|
|
624
|
+
if (ranges.length) {
|
|
625
|
+
|
|
626
|
+
ranges = ranges.map(item => ({
|
|
627
|
+
from: node.from + item[0],
|
|
628
|
+
to: node.from + item[1]
|
|
629
|
+
}));
|
|
630
|
+
|
|
631
|
+
overlay.push(...ranges);
|
|
632
|
+
}
|
|
633
|
+
//});
|
|
634
|
+
|
|
635
|
+
// Make sure overlays don't overlap.
|
|
636
|
+
// TODO: Is this still necessary?
|
|
637
|
+
overlay.sort((a, b) => a.from - b.from);
|
|
638
|
+
for (let i=0; i<overlay.length-1; i++) {
|
|
639
|
+
let cur = overlay[i];
|
|
640
|
+
let next = overlay[i+1];
|
|
641
|
+
if (cur.to >= next.from)
|
|
642
|
+
cur.to = next.from;
|
|
643
|
+
}
|
|
644
|
+
|
|
624
645
|
return {
|
|
625
646
|
parser: ParseUtil.jsParser,
|
|
626
647
|
overlay
|
|
@@ -637,8 +658,11 @@ var ParseUtil = {
|
|
|
637
658
|
let code = docInput.doc.sliceString(node.from, node.to);
|
|
638
659
|
|
|
639
660
|
// Only if node text starts and ends with tags, allowing for spaces.
|
|
640
|
-
if (code.match(/^`\s*</) && code.match(/>\s*`$/))
|
|
641
|
-
return {
|
|
661
|
+
if (code.match(/^`\s*</)/* && code.match(/>\s*`$/)*/) {
|
|
662
|
+
return {
|
|
663
|
+
parser: ParseUtil.htmlParser,
|
|
664
|
+
}
|
|
665
|
+
}
|
|
642
666
|
}
|
|
643
667
|
return null;
|
|
644
668
|
})
|
|
@@ -661,10 +685,107 @@ var ParseUtil = {
|
|
|
661
685
|
top: "Template"
|
|
662
686
|
|
|
663
687
|
}),
|
|
664
|
-
|
|
665
|
-
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Used by javascriptWithHtml()
|
|
691
|
+
* Handles single and multiline comments and all three string types.
|
|
692
|
+
* TODO: This needs tests!
|
|
693
|
+
* @param str {string}
|
|
694
|
+
* @param startIndex {int}
|
|
695
|
+
* @returns {int[][]} */
|
|
696
|
+
findJavaScriptRanges(str, startIndex) {
|
|
697
|
+
let depth = 0;
|
|
698
|
+
let depthStack = [];
|
|
699
|
+
let inString = null;
|
|
700
|
+
let stringStack = [];
|
|
701
|
+
let inComment = null;
|
|
702
|
+
|
|
703
|
+
let result = [];
|
|
704
|
+
|
|
705
|
+
for (let i = startIndex; i < str.length; i++) {
|
|
706
|
+
|
|
707
|
+
let char = str[i];
|
|
708
|
+
if (inString && char === '\\') { // Skip escaped characters in strings.
|
|
709
|
+
i++;
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
let nextChar = i + 1 < str.length ? str[i + 1] : '';
|
|
713
|
+
|
|
714
|
+
// String start/end
|
|
715
|
+
if (!inComment) {
|
|
716
|
+
if (!inString && (char === '`' || char === '`' || char === '`')) {
|
|
717
|
+
inString = char;
|
|
718
|
+
if (char === '`') {
|
|
719
|
+
if (i > startIndex) {
|
|
720
|
+
result.push([startIndex, i]);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
else if (inString === char) {
|
|
725
|
+
if (inString === '`')
|
|
726
|
+
startIndex = i + 1;
|
|
727
|
+
inString = null;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
if (!inString) {
|
|
733
|
+
// Comment start/end
|
|
734
|
+
if (char === '/' && (nextChar === '*' || nextChar === '/')) {
|
|
735
|
+
inComment = nextChar === '*' ? 'block' : 'line';
|
|
736
|
+
i++; // Skip the next character as it's part of the comment syntax
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// End block comment
|
|
740
|
+
else if (inComment === 'block' && char === '*' && nextChar === '/') {
|
|
741
|
+
inComment = null;
|
|
742
|
+
i++; // Skip the '/' character
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// End line comment
|
|
746
|
+
else if (inComment === 'line' && char === '\n')
|
|
747
|
+
inComment = null;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Template literal boundaries
|
|
751
|
+
if (!inComment) {
|
|
752
|
+
|
|
753
|
+
if (inString) {
|
|
754
|
+
if (char === '$' && nextChar === '{') {
|
|
755
|
+
startIndex = i;
|
|
756
|
+
i++; // Skip the '{' character
|
|
757
|
+
stringStack.push(inString);
|
|
758
|
+
inString = null;
|
|
759
|
+
depthStack.push(depth);
|
|
760
|
+
depth = 0;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
else {
|
|
765
|
+
if (char === '{')
|
|
766
|
+
depth++;
|
|
767
|
+
|
|
768
|
+
else if (char === '}') {
|
|
769
|
+
if (depth === 0) {
|
|
770
|
+
inString = stringStack.pop();
|
|
771
|
+
depth = depthStack.pop();
|
|
772
|
+
if (i > startIndex)
|
|
773
|
+
result.push([startIndex, i+1]);
|
|
774
|
+
}
|
|
775
|
+
else
|
|
776
|
+
depth--;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
return result;
|
|
783
|
+
},
|
|
784
|
+
|
|
666
785
|
/**
|
|
786
|
+
* @deprecated
|
|
667
787
|
* Used by javascriptWithHtml()
|
|
788
|
+
* TODO: This needs tests!
|
|
668
789
|
* @param str {string}
|
|
669
790
|
* @param startIndex {int}
|
|
670
791
|
* @returns {int} -1 if no match. */
|
|
@@ -672,56 +793,73 @@ var ParseUtil = {
|
|
|
672
793
|
let stack = 0;
|
|
673
794
|
let inString = null;
|
|
674
795
|
let inComment = null;
|
|
675
|
-
|
|
676
|
-
for (let i=startIndex; i<str.length; i++) {
|
|
796
|
+
|
|
797
|
+
for (let i = startIndex; i < str.length; i++) {
|
|
677
798
|
let char = str[i];
|
|
678
799
|
if (inString && char === '\\') { // Skip escaped characters in strings.
|
|
679
800
|
i++;
|
|
680
801
|
continue;
|
|
681
802
|
}
|
|
682
|
-
let nextChar = i + 1 < str.length ? str[i+1] : '';
|
|
683
|
-
|
|
803
|
+
let nextChar = i + 1 < str.length ? str[i + 1] : '';
|
|
804
|
+
|
|
684
805
|
// String start/end
|
|
685
|
-
if (
|
|
686
|
-
inString
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
// Comment start/end
|
|
691
|
-
if (!inString && char === '/' && (nextChar === '*' || nextChar === '/')) {
|
|
692
|
-
inComment = nextChar === '*' ? 'block' : 'line';
|
|
693
|
-
i++; // Skip the next character as it's part of the comment syntax
|
|
806
|
+
if (!inComment) {
|
|
807
|
+
if (!inString && (char === '`' || char === '`' || char === '`'))
|
|
808
|
+
inString = char;
|
|
809
|
+
else if (inString === char)
|
|
810
|
+
inString = null;
|
|
694
811
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
812
|
+
|
|
813
|
+
// Comment start/end
|
|
814
|
+
if (!inString) {
|
|
815
|
+
if (char === '/' && (nextChar === '*' || nextChar === '/')) {
|
|
816
|
+
inComment = nextChar === '*' ? 'block' : 'line';
|
|
817
|
+
i++; // Skip the next character as it's part of the comment syntax
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// End block comment
|
|
821
|
+
else if (inComment === 'block' && char === '*' && nextChar === '/') {
|
|
822
|
+
inComment = null;
|
|
823
|
+
i++; // Skip the '/' character
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// End line comment
|
|
827
|
+
else if (inComment === 'line' && char === '\n')
|
|
828
|
+
inComment = null;
|
|
698
829
|
}
|
|
699
|
-
|
|
700
|
-
inComment = null;
|
|
701
|
-
|
|
830
|
+
|
|
702
831
|
// Template literal boundaries
|
|
703
832
|
if (!inString && !inComment) {
|
|
704
|
-
if (char === '
|
|
833
|
+
if (char === '{')
|
|
834
|
+
stack++;
|
|
835
|
+
|
|
836
|
+
else if (char === '$' && nextChar === '{') {
|
|
705
837
|
stack++;
|
|
706
838
|
i++; // Skip the '{' character
|
|
707
|
-
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
else if (char === '}') {
|
|
708
842
|
if (stack === 0)
|
|
709
843
|
return i; // Matching closing brace found
|
|
710
844
|
stack--;
|
|
711
845
|
}
|
|
712
846
|
}
|
|
713
847
|
}
|
|
714
|
-
|
|
848
|
+
|
|
715
849
|
return -1;
|
|
716
850
|
}
|
|
717
851
|
};
|
|
718
852
|
|
|
719
853
|
|
|
720
854
|
/**
|
|
721
|
-
* @typedef ToolbarButton
|
|
855
|
+
* @typedef {Object} ToolbarButton
|
|
722
856
|
* @property {string} html
|
|
723
|
-
* @property {function(el:Node|HTMLElement)} update */
|
|
724
|
-
|
|
857
|
+
* @property {function(el:Node|HTMLElement)=} update */
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
*
|
|
861
|
+
*/
|
|
862
|
+
export class CodeEditorToolbar extends HTMLElement {
|
|
725
863
|
|
|
726
864
|
/** @type {object} Should have functions for everything the buttons array uses. */
|
|
727
865
|
ed;
|
|
@@ -770,7 +908,7 @@ export class CodeEditorToolbar extends Solarite {
|
|
|
770
908
|
|
|
771
909
|
if (typeof buttons === 'string')
|
|
772
910
|
buttons = buttons.split(/[,\s]+/g);
|
|
773
|
-
|
|
911
|
+
|
|
774
912
|
for (let button of buttons||[]) {
|
|
775
913
|
let item = typeof button === 'string'
|
|
776
914
|
? this.buttonTemplates[button]
|
|
@@ -812,7 +950,7 @@ export class CodeEditorToolbar extends Solarite {
|
|
|
812
950
|
}
|
|
813
951
|
|
|
814
952
|
render() {
|
|
815
|
-
this
|
|
953
|
+
r(this)`
|
|
816
954
|
<code-editor-toolbar>
|
|
817
955
|
<style>
|
|
818
956
|
:host { display: block }
|
|
@@ -836,5 +974,5 @@ export class CodeEditorToolbar extends Solarite {
|
|
|
836
974
|
}
|
|
837
975
|
|
|
838
976
|
}
|
|
839
|
-
|
|
977
|
+
customElements.define('code-editor-toolbar', CodeEditorToolbar);
|
|
840
978
|
|
|
@@ -3,8 +3,7 @@ import Draggable2 from "../util/Draggable2.js";
|
|
|
3
3
|
import Util from "../util/Util.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Put this element between flex children to allow resizing them.
|
|
7
|
-
* TODO: Allow vertical resizing. */
|
|
6
|
+
* Put this element between flex children to allow resizing them. */
|
|
8
7
|
export default class FlexResizer extends Solarite {
|
|
9
8
|
|
|
10
9
|
onStart = Util.callback();
|
|
@@ -61,9 +60,15 @@ export default class FlexResizer extends Solarite {
|
|
|
61
60
|
}
|
|
62
61
|
});
|
|
63
62
|
}
|
|
64
|
-
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* It's vertical if the user drags the resizer vertically to resize.
|
|
66
|
+
* When vertical, the resizer will be stretched horizontally to fill the available space.
|
|
67
|
+
* @returns {boolean} */
|
|
65
68
|
isVertical() {
|
|
66
|
-
|
|
69
|
+
if (this.parentNode) {
|
|
70
|
+
return getComputedStyle(this.parentNode).flexDirection === 'row';
|
|
71
|
+
}
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
/** @return {Number} */
|
|
@@ -127,10 +132,15 @@ export default class FlexResizer extends Solarite {
|
|
|
127
132
|
:host {
|
|
128
133
|
display: block; z-index: 1;
|
|
129
134
|
|
|
130
|
-
/* We put the resize region (the margin thickness) all to the right / top bc vertical scrollbars
|
|
135
|
+
/* We put the resize region (the margin thickness) all to the right / top bc vertical scrollbars
|
|
136
|
+
* are often to the left, and tab bars below the top.*/
|
|
131
137
|
${this.isVertical()
|
|
138
|
+
|
|
139
|
+
/* Stretch horizontally */
|
|
132
140
|
? `min-width: ${this.thickness-1}px !important; max-width: ${this.thickness-1}px !important;
|
|
133
141
|
margin-left: -1px; margin-right: -${this.thickness-1}px; cursor: ew-resize`
|
|
142
|
+
|
|
143
|
+
/* Stretch vertically */
|
|
134
144
|
: `min-height: ${this.thickness}px !important; max-height: ${this.thickness}px !important;
|
|
135
145
|
margin-top: -${this.thickness/2}px; margin-bottom: -${this.thickness/2}px; cursor: ns-resize`
|
|
136
146
|
};
|
package/docs/js/util/Errors.js
CHANGED
|
@@ -4,6 +4,17 @@ export function assert(val) {
|
|
|
4
4
|
if (!val) {
|
|
5
5
|
debugger;
|
|
6
6
|
throw new Error('Assertion failed: ' + val);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
var Errors = {
|
|
10
|
+
getStack(ignoreTop=0, ignoreRegex) {
|
|
11
|
+
var e = new Error();
|
|
12
|
+
if (!e.stack) return []; // There is no stack in IE.
|
|
13
|
+
return e.stack
|
|
14
|
+
.split('\n')
|
|
15
|
+
.slice(ignoreTop+2)
|
|
16
|
+
.map(line => line.trim().replace(/^at /, ''))
|
|
17
|
+
.filter(line => !ignoreRegex || !line.match(ignoreRegex));
|
|
7
18
|
}
|
|
8
19
|
}
|
|
9
20
|
//#ENDIF
|
|
@@ -8,8 +8,11 @@
|
|
|
8
8
|
font-weight: 400;
|
|
9
9
|
src: url("FiraCode400.woff2") format("woff")
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
html[dark] {
|
|
12
|
+
/*--card-background: #0b0e12 !important;*/
|
|
13
|
+
--card-border: #1a1c1e !important;
|
|
14
|
+
}
|
|
15
|
+
html { background: var(--background) !important; font-size: 18px !important }
|
|
13
16
|
body::before { content: ''; position: fixed; inset: 0;
|
|
14
17
|
opacity: .03; filter: grayscale(75%);
|
|
15
18
|
background: url('solarite-machine.webp') no-repeat -200px -200px / 140% auto ; }
|
|
@@ -41,7 +44,7 @@ html:not([dark]) #write h3 { color: #678; }
|
|
|
41
44
|
#write h6 { font-size: 100%; font-weight: normal; margin-top: .75em; margin-bottom: 0; text-decoration: underline }
|
|
42
45
|
|
|
43
46
|
|
|
44
|
-
#write :is(p, h2, h3, h4, h5, h6, ol, ul) { max-width:
|
|
47
|
+
#write :is(p, h2, h3, h4, h5, h6, ol, ul) { max-width: 800px }
|
|
45
48
|
#write p { text-align: justify }
|
|
46
49
|
#write a, #write a:visited { color: #08c; text-decoration: none}
|
|
47
50
|
#write a:hover { color: #08c; text-decoration: underline }
|