fragment-tools 0.1.19 → 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.
Files changed (102) hide show
  1. package/bin/index.js +1 -0
  2. package/package.json +5 -6
  3. package/src/cli/templates/three-fragment/index.js +6 -6
  4. package/src/cli/templates/three-orthographic/index.js +3 -3
  5. package/src/cli/templates/three-perspective/index.js +3 -3
  6. package/src/client/app/actions/resize.js +14 -0
  7. package/src/client/app/components/HintLoading.svelte +94 -0
  8. package/src/client/app/components/HintPaused.svelte +88 -0
  9. package/src/client/app/components/HintRecord.svelte +62 -0
  10. package/src/client/app/components/IconLocked.svelte +51 -0
  11. package/src/client/app/components/IconTriggers.svelte +48 -0
  12. package/src/client/app/components/Init.svelte +14 -27
  13. package/src/client/app/components/KeyBinding.svelte +3 -6
  14. package/src/client/app/helpers.js +4 -40
  15. package/src/client/app/hooks.js +41 -17
  16. package/src/client/app/inputs/MIDI.js +2 -1
  17. package/src/client/app/lib/canvas-recorder/CanvasRecorder.js +6 -1
  18. package/src/client/app/lib/gl/Renderer.js +1 -0
  19. package/src/client/app/lib/svelte-json-tree/ErrorNode.svelte +28 -0
  20. package/src/client/app/lib/svelte-json-tree/ErrorStack.svelte +31 -0
  21. package/src/client/app/lib/svelte-json-tree/Expandable.svelte +25 -0
  22. package/src/client/app/lib/svelte-json-tree/JSONArrayNode.svelte +38 -0
  23. package/src/client/app/lib/svelte-json-tree/JSONArrow.svelte +47 -0
  24. package/src/client/app/lib/svelte-json-tree/JSONFunctionNode.svelte +114 -0
  25. package/src/client/app/lib/svelte-json-tree/JSONIterableArrayNode.svelte +60 -0
  26. package/src/client/app/lib/svelte-json-tree/JSONIterableMapNode.svelte +87 -0
  27. package/src/client/app/lib/svelte-json-tree/JSONNested.svelte +94 -0
  28. package/src/client/app/lib/svelte-json-tree/JSONNode.svelte +91 -0
  29. package/src/client/app/lib/svelte-json-tree/JSONObjectNode.svelte +40 -0
  30. package/src/client/app/lib/svelte-json-tree/JSONStringNode.svelte +31 -0
  31. package/src/client/app/lib/svelte-json-tree/JSONValueNode.svelte +31 -0
  32. package/src/client/app/lib/svelte-json-tree/PreviewList.svelte +38 -0
  33. package/src/client/app/lib/svelte-json-tree/RegExpNode.svelte +42 -0
  34. package/src/client/app/lib/svelte-json-tree/Root.svelte +75 -0
  35. package/src/client/app/lib/svelte-json-tree/Summary.svelte +9 -0
  36. package/src/client/app/lib/svelte-json-tree/TypedArrayNode.svelte +56 -0
  37. package/src/client/app/lib/svelte-json-tree/index.js +1 -0
  38. package/src/client/app/lib/svelte-json-tree/utils.js +57 -0
  39. package/src/client/app/modules/Console/ConsoleLine.svelte +12 -11
  40. package/src/client/app/modules/Console.svelte +82 -17
  41. package/src/client/app/modules/Exports.svelte +48 -48
  42. package/src/client/app/modules/MidiPanel.svelte +12 -19
  43. package/src/client/app/modules/Monitor.svelte +147 -55
  44. package/src/client/app/modules/Params.svelte +127 -80
  45. package/src/client/app/renderers/2DRenderer.js +1 -0
  46. package/src/client/app/renderers/FragmentRenderer.js +1 -1
  47. package/src/client/app/renderers/P5GLRenderer.js +11 -5
  48. package/src/client/app/renderers/P5Renderer.js +7 -3
  49. package/src/client/app/renderers/THREERenderer.js +42 -79
  50. package/src/client/app/state/Sketch.svelte.js +538 -0
  51. package/src/client/app/state/errors.svelte.js +17 -0
  52. package/src/client/app/state/exports.svelte.js +152 -0
  53. package/src/client/app/state/layout.svelte.js +205 -0
  54. package/src/client/app/state/monitors.svelte.js +36 -0
  55. package/src/client/app/state/renderers.svelte.js +77 -0
  56. package/src/client/app/state/rendering.svelte.js +697 -0
  57. package/src/client/app/state/sketches.svelte.js +73 -0
  58. package/src/client/app/state/utils.svelte.js +65 -0
  59. package/src/client/app/ui/Build.svelte +53 -60
  60. package/src/client/app/ui/ErrorOverlay.svelte +2 -2
  61. package/src/client/app/ui/Field.svelte +63 -189
  62. package/src/client/app/ui/FieldGroup.svelte +4 -5
  63. package/src/client/app/ui/FieldSection.svelte +14 -9
  64. package/src/client/app/ui/FieldSpace.svelte +1 -1
  65. package/src/client/app/ui/FieldTrigger.svelte +86 -84
  66. package/src/client/app/ui/FieldTriggers.svelte +25 -24
  67. package/src/client/app/ui/FloatingParams.svelte +50 -12
  68. package/src/client/app/ui/Layout.svelte +24 -13
  69. package/src/client/app/ui/LayoutColumn.svelte +2 -2
  70. package/src/client/app/ui/LayoutComponent.svelte +86 -195
  71. package/src/client/app/ui/LayoutResizer.svelte +25 -37
  72. package/src/client/app/ui/LayoutRoot.svelte +3 -5
  73. package/src/client/app/ui/LayoutRow.svelte +2 -2
  74. package/src/client/app/ui/LayoutToolbar.svelte +17 -76
  75. package/src/client/app/ui/Module.svelte +31 -35
  76. package/src/client/app/ui/ModuleHeaderAction.svelte +23 -16
  77. package/src/client/app/ui/ModuleHeaderButton.svelte +3 -3
  78. package/src/client/app/ui/ModuleHeaderSelect.svelte +4 -12
  79. package/src/client/app/ui/ModuleRenderer.svelte +84 -22
  80. package/src/client/app/ui/ParamsOutput.svelte +61 -77
  81. package/src/client/app/ui/Preview.svelte +15 -4
  82. package/src/client/app/ui/SelectChevrons.svelte +1 -2
  83. package/src/client/app/ui/SketchRenderer.svelte +89 -701
  84. package/src/client/app/ui/SketchSelect.svelte +14 -49
  85. package/src/client/app/ui/fields/ButtonInput.svelte +14 -11
  86. package/src/client/app/ui/fields/CheckboxInput.svelte +5 -12
  87. package/src/client/app/ui/fields/ColorInput.svelte +46 -121
  88. package/src/client/app/ui/fields/FieldInputRow.svelte +5 -1
  89. package/src/client/app/ui/fields/ImageInput.svelte +14 -14
  90. package/src/client/app/ui/fields/Input.svelte +19 -25
  91. package/src/client/app/ui/fields/IntervalInput.svelte +22 -22
  92. package/src/client/app/ui/fields/NumberInput.svelte +32 -38
  93. package/src/client/app/ui/fields/ProgressInput.svelte +14 -13
  94. package/src/client/app/ui/fields/Select.svelte +34 -45
  95. package/src/client/app/ui/fields/TextInput.svelte +10 -6
  96. package/src/client/app/ui/fields/VectorInput.svelte +25 -30
  97. package/src/client/app/utils/canvas.utils.js +8 -8
  98. package/src/client/app/utils/color.utils.js +46 -13
  99. package/src/client/app/utils/fields.utils.js +1 -1
  100. package/src/client/app/utils/glsl.utils.js +1 -1
  101. package/src/client/app/utils/glslErrors.js +1 -1
  102. package/src/client/main.js +2 -2
@@ -0,0 +1,40 @@
1
+ <script>
2
+ import JSONNested from './JSONNested.svelte';
3
+ import JSONNode from './JSONNode.svelte';
4
+ import PreviewList from './PreviewList.svelte';
5
+
6
+ let { value, summary: summaryText } = $props();
7
+
8
+ let keys = $derived(Object.getOwnPropertyNames(value));
9
+ let previewKeys = $derived(keys.slice(0, 5));
10
+ </script>
11
+
12
+ <JSONNested {keys}>
13
+ {#snippet summary()}
14
+ <span class="label">{summaryText ?? '{…}'}</span>
15
+ {/snippet}
16
+
17
+ {#snippet preview(root)}
18
+ <PreviewList
19
+ list={previewKeys}
20
+ hasMore={previewKeys.length < keys.length}
21
+ prefix={summaryText ? `${summaryText} {` : '{ '}
22
+ postfix={' }'}
23
+ {root}
24
+ >
25
+ {#snippet item(key)}
26
+ <span class="property">{key}</span>
27
+ <span class="operator">{': '}</span>
28
+ <JSONNode value={value[key]} />
29
+ {/snippet}
30
+ </PreviewList>
31
+ {/snippet}
32
+
33
+ {#snippet itemKey(key)}
34
+ <span class="property">{key}</span>
35
+ {/snippet}
36
+
37
+ {#snippet itemValue(key)}
38
+ <JSONNode value={value[key]} />
39
+ {/snippet}
40
+ </JSONNested>
@@ -0,0 +1,31 @@
1
+ <script>
2
+ import { useState } from './utils.js';
3
+
4
+ let { value } = $props();
5
+
6
+ const map = {
7
+ '\n': '\\n',
8
+ '\t': '\\t',
9
+ '\r': '\\r',
10
+ };
11
+
12
+ let serialised = $derived(value.replace(/[\n\t\r]/g, (_) => map[_]));
13
+
14
+ const { displayMode } = useState();
15
+ </script>
16
+
17
+ {#if displayMode === 'summary'}
18
+ <span
19
+ >"{serialised.slice(0, 30) + (serialised.length > 30 ? '…' : '')}"</span
20
+ >
21
+ {:else}
22
+ <span>"{serialised}"</span>
23
+ {/if}
24
+
25
+ <style>
26
+ span {
27
+ color: var(--string-color);
28
+ word-break: break-all;
29
+ word-wrap: break-word;
30
+ }
31
+ </style>
@@ -0,0 +1,31 @@
1
+ <script>
2
+ let { value, nodeType } = $props();
3
+ </script>
4
+
5
+ <span class={nodeType}>
6
+ {value}
7
+ </span>
8
+
9
+ <style>
10
+ .Date {
11
+ color: var(--date-color);
12
+ }
13
+ .BigInt {
14
+ color: var(--number-color);
15
+ }
16
+ .Number {
17
+ color: var(--number-color);
18
+ }
19
+ .Boolean {
20
+ color: var(--boolean-color);
21
+ }
22
+ .Null {
23
+ color: var(--null-color);
24
+ }
25
+ .Undefined {
26
+ color: var(--undefined-color);
27
+ }
28
+ .Symbol {
29
+ color: var(--symbol-color);
30
+ }
31
+ </style>
@@ -0,0 +1,38 @@
1
+ <script>
2
+ let {
3
+ list,
4
+ label = undefined,
5
+ prefix = undefined,
6
+ postfix = undefined,
7
+ root = false,
8
+ hasMore,
9
+ item,
10
+ } = $props();
11
+ </script>
12
+
13
+ <!-- {#if root} -->
14
+ {#if prefix}
15
+ {#if label}
16
+ <span class="label">{label}</span>
17
+ {/if}
18
+ <span class="operator">{prefix} </span>
19
+ {/if}
20
+ {#each list as node, index}
21
+ {@render item?.(node)}
22
+ {#if index < list.length - 1}
23
+ <span class="comma operator">,</span>
24
+ {/if}
25
+ {/each}
26
+ {#if hasMore}
27
+ <span class="comma operator">,</span>
28
+ <span class="operator">…</span>
29
+ {/if}
30
+ {#if postfix}<span class="operator">{postfix}</span>{/if}
31
+
32
+ <!-- {/if} -->
33
+
34
+ <style>
35
+ .comma {
36
+ margin-right: 0.5em;
37
+ }
38
+ </style>
@@ -0,0 +1,42 @@
1
+ <script>
2
+ import JSONNested from './JSONNested.svelte';
3
+ import JSONNode from './JSONNode.svelte';
4
+
5
+ let { value } = $props();
6
+
7
+ let str = $derived(value.toString());
8
+
9
+ const keys = [
10
+ 'lastIndex',
11
+ 'dotAll',
12
+ 'flags',
13
+ 'global',
14
+ 'hasIndices',
15
+ 'ignoreCase',
16
+ 'multiline',
17
+ 'source',
18
+ 'sticky',
19
+ 'unicode',
20
+ ];
21
+ </script>
22
+
23
+ <JSONNested {keys}>
24
+ {#snippet summary()}
25
+ <span class="regex">{str}</span>
26
+ {/snippet}
27
+ {#snippet preview(root)}
28
+ <span class="regex">{str}</span>
29
+ {/snippet}
30
+ {#snippet itemKey(key)}
31
+ <span class="internal">{String(key)}</span>
32
+ {/snippet}
33
+ {#snippet itemValue(key)}
34
+ <JSONNode value={value[key]} />
35
+ {/snippet}
36
+ </JSONNested>
37
+
38
+ <style>
39
+ .regex {
40
+ color: var(--regex-color);
41
+ }
42
+ </style>
@@ -0,0 +1,75 @@
1
+ <script>
2
+ import { setContext } from 'svelte';
3
+ import JSONNode from './JSONNode.svelte';
4
+
5
+ let { value } = $props();
6
+
7
+ setContext('root', true);
8
+ </script>
9
+
10
+ <div>
11
+ <JSONNode {value} />
12
+ </div>
13
+
14
+ <style>
15
+ div {
16
+ --string-color: var(--json-tree-string-color, #cb3f41);
17
+ --symbol-color: var(--json-tree-symbol-color, #cb3f41);
18
+ --boolean-color: var(--json-tree-boolean-color, #112aa7);
19
+ --function-color: var(--json-tree-function-color, #112aa7);
20
+ --number-color: var(--json-tree-number-color, #3029cf);
21
+ --label-color: var(--json-tree-label-color, #871d8f);
22
+ --property-color: var(--json-tree-property-color, #000000);
23
+ --arrow-color: var(--json-tree-arrow-color, #727272);
24
+ --operator-color: var(--json-tree-operator-color, #727272);
25
+ --null-color: var(--json-tree-null-color, #8d8d8d);
26
+ --undefined-color: var(--json-tree-undefined-color, #8d8d8d);
27
+ --date-color: var(--json-tree-date-color, #8d8d8d);
28
+ --internal-color: var(--json-tree-internal-color, grey);
29
+ --regex-color: var(--json-tree-regex-color, var(--string-color));
30
+ --li-identation: var(--json-tree-li-indentation, 1em);
31
+ --li-line-height: var(--json-tree-li-line-height, 1.3);
32
+ font-size: var(--json-tree-font-size, 12px);
33
+ font-family: var(
34
+ --json-tree-font-family,
35
+ 'Courier New',
36
+ Courier,
37
+ monospace
38
+ );
39
+
40
+ display: flex;
41
+ flex-direction: column;
42
+ }
43
+ div :global(li) {
44
+ line-height: var(--li-line-height);
45
+ display: var(--li-display, list-item);
46
+ list-style: none;
47
+ }
48
+ div,
49
+ div :global(ul) {
50
+ padding: 0;
51
+ margin: 0;
52
+ }
53
+
54
+ .expandable {
55
+ margin-left: var(--li-identation);
56
+ }
57
+ div {
58
+ cursor: default;
59
+ }
60
+ div :global(.label) {
61
+ color: var(--label-color);
62
+ }
63
+ div :global(.property) {
64
+ color: var(--property-color);
65
+ }
66
+ div :global(.internal) {
67
+ color: var(--internal-color);
68
+ }
69
+ div :global(.operator) {
70
+ color: var(--operator-color);
71
+ }
72
+ span {
73
+ white-space: pre-wrap;
74
+ }
75
+ </style>
@@ -0,0 +1,9 @@
1
+ <script>
2
+ import { setContext } from 'svelte';
3
+
4
+ let { children } = $props();
5
+
6
+ setContext('displayMode', 'summary');
7
+ </script>
8
+
9
+ {@render children?.()}
@@ -0,0 +1,56 @@
1
+ <script>
2
+ import JSONNested from './JSONNested.svelte';
3
+ import JSONNode from './JSONNode.svelte';
4
+ import PreviewList from './PreviewList.svelte';
5
+
6
+ let { value, nodeType } = $props();
7
+
8
+ const TO_STRING_TAG = 'Symbol(Symbol.toStringTag)';
9
+ const internalKeys = [
10
+ 'buffer',
11
+ 'byteLength',
12
+ 'byteOffset',
13
+ 'length',
14
+ TO_STRING_TAG,
15
+ ];
16
+ let keys = $derived([
17
+ ...Object.getOwnPropertyNames(value),
18
+ ...internalKeys,
19
+ ]);
20
+ let previewList = $derived(value.slice(0, 5));
21
+
22
+ function getValue(key) {
23
+ if (key === TO_STRING_TAG) {
24
+ return value[Symbol.toStringTag];
25
+ }
26
+ return value[key];
27
+ }
28
+ </script>
29
+
30
+ <JSONNested {keys}>
31
+ {#snippet summary()}
32
+ <span class="label">{nodeType}({value.length})</span>
33
+ {/snippet}
34
+ {#snippet preview(root)}
35
+ <PreviewList
36
+ list={previewList}
37
+ hasMore={previewList.length < value.length}
38
+ label="{nodeType}({value.length}) "
39
+ prefix="["
40
+ postfix="]"
41
+ {root}
42
+ >
43
+ {#snippet item(value)}
44
+ <JSONNode {value} />
45
+ {/snippet}
46
+ </PreviewList>
47
+ {/snippet}
48
+ {#snippet itemKey(key)}
49
+ <span class={internalKeys.includes(key) ? 'internal' : 'property'}
50
+ >{String(key)}</span
51
+ >
52
+ {/snippet}
53
+ {#snippet itemValue(key)}
54
+ <JSONNode value={getValue(key)} />
55
+ {/snippet}
56
+ </JSONNested>
@@ -0,0 +1 @@
1
+ export { default } from './Root.svelte';
@@ -0,0 +1,57 @@
1
+ import { getContext, setContext } from 'svelte';
2
+
3
+ export function getShouldExpandNode({
4
+ defaultExpandedPaths,
5
+ defaultExpandedLevel,
6
+ }) {
7
+ const defaultExpandedPathsParts = defaultExpandedPaths.map((path) =>
8
+ path.split('.'),
9
+ );
10
+ function matchPath(keyPath) {
11
+ outer: for (const parts of defaultExpandedPathsParts) {
12
+ if (keyPath.length > parts.length) continue;
13
+ const length = Math.min(keyPath.length, parts.length);
14
+ for (let i = 0; i < length; i++) {
15
+ if (parts[i] !== '*' && parts[i] !== String(keyPath[i]))
16
+ continue outer;
17
+ }
18
+ return true;
19
+ }
20
+ return false;
21
+ }
22
+
23
+ return function ({ keyPath, level }) {
24
+ return level <= defaultExpandedLevel || matchPath(keyPath);
25
+ };
26
+ }
27
+
28
+ export function objType(obj, shouldTreatIterableAsObject) {
29
+ const type = Object.prototype.toString.call(obj).slice(8, -1);
30
+ if (type === 'Object') {
31
+ if (
32
+ !shouldTreatIterableAsObject &&
33
+ typeof obj[Symbol.iterator] === 'function'
34
+ ) {
35
+ return 'Iterable';
36
+ }
37
+ return obj.constructor.name;
38
+ }
39
+
40
+ return type;
41
+ }
42
+
43
+ export function useState() {
44
+ const root = getContext('root');
45
+ const displayMode = getContext('displayMode');
46
+ const expandable = getContext('expandable');
47
+ const expanded = getContext('expanded');
48
+ const toggleExpand = getContext('toggleExpand');
49
+
50
+ return {
51
+ root,
52
+ displayMode,
53
+ expandable,
54
+ expanded,
55
+ toggleExpand,
56
+ };
57
+ }
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import JSONTree from 'svelte-json-tree';
2
+ import JSONTree from '../../lib/svelte-json-tree';
3
3
  // import ConsoleTable from './ConsoleTable.svelte';
4
4
 
5
5
  export let log;
@@ -17,7 +17,7 @@
17
17
  <div
18
18
  class="log console-{log.level}"
19
19
  style="padding-left: {level * 8}px"
20
- on:click={log.level === 'group' ? toggleGroupCollapse : undefined}
20
+ onclick={log.level === 'group' ? toggleGroupCollapse : undefined}
21
21
  >
22
22
  {#if log.count > 1}
23
23
  <div class="count">
@@ -29,7 +29,7 @@
29
29
  <div
30
30
  class="arrow"
31
31
  class:expand={!log.collapsed}
32
- on:click={toggleGroupCollapse}
32
+ onclick={toggleGroupCollapse}
33
33
  >
34
34
 
35
35
  </div>
@@ -68,7 +68,7 @@
68
68
  </div>
69
69
  {/if}
70
70
  {#each new Array(level - 1) as _, idx}
71
- <div class="outline" style="left: {idx * 15 + 15}px" />
71
+ <div class="outline" style="left: {idx * 15 + 15}px"></div>
72
72
  {/each}
73
73
  </div>
74
74
 
@@ -88,27 +88,28 @@
88
88
 
89
89
  <style>
90
90
  .log {
91
- --json-tree-string-color: rgba(240, 240, 240, 0.6);
91
+ --json-tree-string-color: #17d08e;
92
92
  --arrow-sign: rgba(255, 255, 255, 0.5);
93
93
  --json-tree-font-size: var(--font-size-input);
94
94
  --json-tree-font-family: var(--font-mono);
95
95
  --json-tree-number-color: #9980ff;
96
- --json-tree-symbol-color: #cb3f41;
96
+ --json-tree-symbol-color: #0a0606;
97
97
  --json-tree-boolean-color: #9980ff;
98
98
  --json-tree-function-color: var(--color-active);
99
99
  /* --json-tree-number-color: #3029cf; */
100
100
  --json-tree-property-color: #5db0d7;
101
- --json-tree-label-color: #17d08e;
101
+ --json-tree-label-color: rgba(240, 240, 240, 0.6);
102
102
  --json-tree-arrow-color: #727272;
103
103
  --json-tree-null-color: #8d8d8d;
104
104
  --json-tree-undefined-color: #8d8d8d;
105
105
  --json-tree-date-color: #8d8d8d;
106
- --json-tree-li-indentation: 12px;
106
+ --json-tree-li-indentation: 20px;
107
+ --json-tree-li-line-height: 1.5;
107
108
 
108
109
  position: relative;
109
110
 
110
111
  display: flex;
111
- padding: 4px 0 3px;
112
+ padding: 4px 0;
112
113
 
113
114
  color: rgba(255, 255, 255, 0.5);
114
115
 
@@ -118,7 +119,7 @@
118
119
 
119
120
  .args {
120
121
  display: flex;
121
- flex-direction: column;
122
+ gap: 6px;
122
123
  }
123
124
 
124
125
  .string {
@@ -183,7 +184,7 @@
183
184
  }
184
185
 
185
186
  .log :global(.arrow) {
186
- margin-right: 10px;
187
+ padding-right: 6px;
187
188
  }
188
189
 
189
190
  .log :global(.String) {
@@ -1,37 +1,94 @@
1
1
  <script>
2
+ import { onMount } from 'svelte';
2
3
  import Module from '../ui/Module.svelte';
3
4
  import ModuleHeaderAction from '../ui/ModuleHeaderAction.svelte';
4
- import { logs } from '../stores/console';
5
5
  import ConsoleLine from './Console/ConsoleLine.svelte';
6
- import { afterUpdate } from 'svelte';
7
6
 
8
- export let mID;
9
- export let hasHeader;
7
+ let { id, headless = false } = $props();
10
8
 
9
+ let logs = $state([]);
10
+ let mirrored = ['log', 'warn', 'error', 'dir'];
11
+ let refs = {};
12
+ let clear = console.clear;
13
+ /** @type {HTMLDivElement}*/
11
14
  let scrollableContainer;
12
15
 
13
- function clear() {
14
- $logs = [];
16
+ function enable() {
17
+ mirrored.forEach((key) => {
18
+ const ref = console[`${key}`];
19
+ refs[`${key}`] = ref;
20
+ // window[`${key}`] = ref;
21
+
22
+ console[`${key}`] = (...args) => {
23
+ let isFromVite = args.some(
24
+ (log) => typeof log === 'string' && log.includes('[vite]'),
25
+ );
26
+
27
+ if (!isFromVite) {
28
+ ref(...args);
29
+
30
+ if (logs.length > 0) {
31
+ const lastLog = logs[logs.length - 1];
32
+ const { level: lastLevel, args: lastArgs } = lastLog;
33
+
34
+ if (lastLevel === key && lastArgs[0] === args[0]) {
35
+ logs[logs.length - 1].count++;
36
+ return;
37
+ }
38
+ }
39
+
40
+ logs.push({
41
+ level: key,
42
+ args,
43
+ count: 1,
44
+ });
45
+ }
46
+ };
47
+ });
48
+
49
+ console.clear = () => {
50
+ clear();
51
+ logs = [];
52
+ };
53
+ }
54
+
55
+ function disable() {
56
+ mirrored.forEach((key) => {
57
+ const ref = refs[key];
58
+
59
+ console[`${key}`] = ref;
60
+ });
61
+
62
+ console.clear = clear;
15
63
  }
16
64
 
17
- afterUpdate(() => {
18
- if (scrollableContainer) {
19
- scrollableContainer.scrollTop = scrollableContainer.scrollHeight;
20
- }
65
+ onMount(() => {
66
+ enable();
67
+ return () => {
68
+ disable();
69
+ };
21
70
  });
22
71
  </script>
23
72
 
24
- <Module {mID} {hasHeader} name="console" scrollable={false}>
25
- <svelte:fragment slot="header-right">
26
- <ModuleHeaderAction border label="Clear" on:click={() => clear()}
27
- >clear</ModuleHeaderAction
73
+ <Module {id} {headless} name="console" scrollable={false}>
74
+ {#snippet headerRight()}
75
+ <ModuleHeaderAction
76
+ permanent
77
+ border
78
+ label="Clear"
79
+ onclick={(e) => {
80
+ e.preventDefault();
81
+ e.stopPropagation();
82
+
83
+ logs = [];
84
+ }}>clear</ModuleHeaderAction
28
85
  >
29
- </svelte:fragment>
86
+ {/snippet}
30
87
  <div class="container">
31
88
  <div class="list">
32
89
  <div class="scroll" bind:this={scrollableContainer}>
33
- {#each $logs as log}
34
- <ConsoleLine {log} />
90
+ {#each logs as log}
91
+ <ConsoleLine log={$state.snapshot(log)} />
35
92
  {/each}
36
93
  </div>
37
94
  </div>
@@ -65,6 +122,14 @@
65
122
  height: 100%;
66
123
  overflow-x: hidden;
67
124
  overflow-y: scroll;
125
+
126
+ scroll-snap-type: y proximity;
127
+ }
128
+
129
+ .scroll::after {
130
+ display: block;
131
+ content: '';
132
+ scroll-snap-align: end;
68
133
  }
69
134
 
70
135
  .scroll::-webkit-scrollbar {