|
4 | 4 |
|
5 | 5 | /** @type {import('./console').Log} */ |
6 | 6 | export let log; |
7 | | - export let depth = 1; |
| 7 | + export let depth = 0; |
8 | 8 |
|
9 | 9 | function toggle_group_collapse() { |
10 | 10 | log.collapsed = !log.collapsed; |
11 | 11 | } |
| 12 | +
|
| 13 | + let style; |
| 14 | +
|
| 15 | + /** @param {string} text */ |
| 16 | + function sanitize_css(text) { |
| 17 | + style ??= document.createElement('span').style; |
| 18 | + style.cssText = text; |
| 19 | +
|
| 20 | + for (const key in style) { |
| 21 | + const value = style[key]; |
| 22 | + if (typeof value === 'string' && value.includes('url(')) { |
| 23 | + style[key] = value.replace(/url\([^)]+\)/g, ''); |
| 24 | + } |
| 25 | + } |
| 26 | +
|
| 27 | + style.position = 'static'; |
| 28 | + return style.cssText; |
| 29 | + } |
| 30 | +
|
| 31 | + /** @param {any[]} [args] */ |
| 32 | + function format_args(args = []) { |
| 33 | + if (args.length === 0) return args; |
| 34 | +
|
| 35 | + if (typeof args[0] !== 'string') { |
| 36 | + return args.map((value) => ({ type: 'value', value })); |
| 37 | + } |
| 38 | +
|
| 39 | + args = args.slice(); |
| 40 | +
|
| 41 | + const parts = args.shift().split(/(%[sdifoOc])/g); |
| 42 | +
|
| 43 | + const formatted = []; |
| 44 | +
|
| 45 | + if (parts[0] !== '') { |
| 46 | + formatted.push({ type: 'value', value: parts[0] }); |
| 47 | + } |
| 48 | +
|
| 49 | + for (let i = 1; i < parts.length; i += 2) { |
| 50 | + const type = parts[i]; |
| 51 | + const next = parts[i + 1]; |
| 52 | + const value = args.shift(); |
| 53 | +
|
| 54 | + switch (type) { |
| 55 | + case '%s': |
| 56 | + formatted.push({ type: 'value', value: String(value), formatted: true }); |
| 57 | + break; |
| 58 | +
|
| 59 | + case '%d': |
| 60 | + case '%i': |
| 61 | + formatted.push({ |
| 62 | + type: 'value', |
| 63 | + value: typeof value === 'symbol' ? NaN : parseInt(value, 10), |
| 64 | + formatted: true |
| 65 | + }); |
| 66 | + break; |
| 67 | +
|
| 68 | + case '%f': |
| 69 | + formatted.push({ |
| 70 | + type: 'value', |
| 71 | + value: typeof value === 'symbol' ? NaN : parseFloat(value), |
| 72 | + formatted: true |
| 73 | + }); |
| 74 | + break; |
| 75 | +
|
| 76 | + case '%o': |
| 77 | + case '%O': |
| 78 | + formatted.push({ type: 'value', value, formatted: true }); |
| 79 | + break; |
| 80 | +
|
| 81 | + case '%c': |
| 82 | + formatted.push({ |
| 83 | + type: 'style', |
| 84 | + style: sanitize_css(String(value)), |
| 85 | + value: next, |
| 86 | + formatted: true |
| 87 | + }); |
| 88 | + break; |
| 89 | + } |
| 90 | +
|
| 91 | + if (type !== '%c' && next !== '') { |
| 92 | + formatted.push({ type: 'value', value: next, formatted: true }); |
| 93 | + } |
| 94 | + } |
| 95 | +
|
| 96 | + for (const value of args) { |
| 97 | + formatted.push({ type: 'value', value }); |
| 98 | + } |
| 99 | +
|
| 100 | + return formatted; |
| 101 | + } |
12 | 102 | </script> |
13 | 103 |
|
14 | 104 | {#if log.command === 'table'} |
|
39 | 129 | {:else if log.command === 'table'} |
40 | 130 | <JSONNode value={log.data} /> |
41 | 131 | {:else} |
42 | | - {#each log.args ?? [] as arg} |
43 | | - <JSONNode value={arg} defaultExpandedLevel={log.expanded ? 1 : 0} /> |
44 | | - {/each} |
| 132 | + <span class="values"> |
| 133 | + {#each format_args(log.args) as part} |
| 134 | + <!-- we need to do some funky stuff to make whitespace behave as it does in devtools --> |
| 135 | + {#if !part.formatted} |
| 136 | + {' '} |
| 137 | + {/if}{#if part.type === 'value'} |
| 138 | + <JSONNode value={part.value} defaultExpandedLevel={log.expanded ? 1 : 0} /> |
| 139 | + {:else} |
| 140 | + <span class="styled" style={part.style}>{part.value}</span> |
| 141 | + {/if} |
| 142 | + {/each} |
| 143 | + </span> |
45 | 144 | {/if} |
46 | 145 | </div> |
47 | 146 |
|
|
54 | 153 | </div> |
55 | 154 | {/if} |
56 | 155 |
|
57 | | - {#each new Array(depth - 1) as _, idx} |
| 156 | + {#each new Array(depth) as _, idx} |
58 | 157 | <div class="outline" style="left: {idx * 15 + 15}px"></div> |
59 | 158 | {/each} |
60 | 159 | </div> |
|
103 | 202 | } |
104 | 203 |
|
105 | 204 | .log { |
106 | | - padding: 5px 10px 5px var(--indent); |
| 205 | + padding: 0.5rem 1rem 0.5rem calc(1rem + var(--indent)); |
107 | 206 | display: flex; |
| 207 | + gap: 1rem; |
108 | 208 | width: 100%; |
109 | | - font-size: 12px; |
| 209 | + font-size: 1.2rem; |
110 | 210 | font-family: var(--sk-font-mono); |
111 | 211 | align-items: center; |
112 | 212 | } |
113 | 213 |
|
114 | 214 | .log.expandable { |
115 | 215 | cursor: pointer; |
116 | | - padding-left: calc(var(--indent) + 1em); |
| 216 | + } |
| 217 | +
|
| 218 | + .values { |
| 219 | + display: block; |
| 220 | + flex: 1; |
117 | 221 | } |
118 | 222 |
|
119 | 223 | .stack { |
120 | 224 | display: grid; |
121 | 225 | grid-template-columns: minmax(0, auto) minmax(auto, 1fr); |
122 | 226 | grid-gap: 0 2rem; |
123 | | - font-size: 12px; |
| 227 | + font-size: 1.2rem; |
124 | 228 | font-family: var(--sk-font-mono); |
125 | 229 | margin: 0 1rem 0.4rem calc(1em + var(--indent)); |
126 | 230 | overflow: hidden; |
|
172 | 276 | } |
173 | 277 |
|
174 | 278 | .arrow { |
175 | | - position: absolute; |
176 | 279 | font-size: 0.9rem; |
177 | 280 | transition: 150ms; |
178 | 281 | transform-origin: 50% 50%; |
179 | | - transform: translateX(-1.2rem) translateY(-1px); |
| 282 | + transform: translateY(-1px); |
180 | 283 | } |
181 | 284 |
|
182 | 285 | .arrow.expand { |
183 | | - transform: translateX(-1.2rem) translateY(0px) rotateZ(90deg); |
| 286 | + transform: translateY(0px) rotateZ(90deg); |
| 287 | + } |
| 288 | +
|
| 289 | + .styled { |
| 290 | + white-space: pre-wrap; |
184 | 291 | } |
185 | 292 | </style> |
0 commit comments