@nocturnium/svelte-ide 1.3.0 → 1.5.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/README.md +26 -4
- package/dist/components/ai/AIEditPreview.svelte +36 -6
- package/dist/components/ai/AIPanel.svelte +42 -14
- package/dist/components/core/Button.svelte +11 -4
- package/dist/components/core/Icon.svelte +19 -1
- package/dist/components/core/ResizeHandle.svelte +90 -6
- package/dist/components/core/ResizeHandle.svelte.d.ts +6 -0
- package/dist/components/core/Tooltip.svelte +13 -2
- package/dist/components/editor/CustomEditor.svelte +34 -0
- package/dist/components/editor/CustomEditor.svelte.d.ts +5 -1
- package/dist/components/editor/EchoCursorLayer.svelte +4 -1
- package/dist/components/editor/GhostBracketLayer.svelte +17 -7
- package/dist/components/editor/GitBlameLayer.svelte +10 -3
- package/dist/components/editor/InlineDiagnosticsLayer.svelte +226 -13
- package/dist/components/editor/InlineDiagnosticsLayer.svelte.d.ts +7 -0
- package/dist/components/editor/InlineDiffLayer.svelte +8 -2
- package/dist/components/editor/PluginPreviewSandbox.svelte +10 -2
- package/dist/components/editor/ProblemsPanel.svelte +40 -5
- package/dist/components/editor/SnippetPalette.svelte +63 -20
- package/dist/components/editor/core/diagnostics.js +4 -1
- package/dist/components/editor/core/extract-variable.d.ts +48 -0
- package/dist/components/editor/core/extract-variable.js +457 -0
- package/dist/components/editor/core/index.d.ts +2 -0
- package/dist/components/editor/core/index.js +2 -0
- package/dist/components/editor/core/organize-imports.d.ts +38 -0
- package/dist/components/editor/core/organize-imports.js +249 -0
- package/dist/components/editor/core/snippet-manager.js +3 -3
- package/dist/components/plugins/PluginCard.svelte +21 -1
- package/dist/components/plugins/PluginPanel.svelte +17 -3
- package/dist/styles/theme.css +8 -1
- package/package.json +1 -1
|
@@ -174,7 +174,8 @@
|
|
|
174
174
|
onclick={() => handleClick(info)}
|
|
175
175
|
onkeydown={(e) => e.key === 'Enter' && handleClick(info)}
|
|
176
176
|
role="button"
|
|
177
|
-
tabindex={-1}
|
|
177
|
+
tabindex={onCommitClick ? 0 : -1}
|
|
178
|
+
aria-label={onCommitClick ? `View commit ${info.commitSha} by ${info.author}` : undefined}
|
|
178
179
|
>
|
|
179
180
|
<!-- Color indicator bar -->
|
|
180
181
|
<div class="git-blame-bar"></div>
|
|
@@ -240,7 +241,9 @@
|
|
|
240
241
|
<div class="tooltip-uncommitted-badge">Uncommitted changes</div>
|
|
241
242
|
{/if}
|
|
242
243
|
|
|
243
|
-
|
|
244
|
+
{#if onCommitClick}
|
|
245
|
+
<div class="tooltip-hint">Click to view full commit</div>
|
|
246
|
+
{/if}
|
|
244
247
|
</div>
|
|
245
248
|
{/if}
|
|
246
249
|
{/if}
|
|
@@ -295,11 +298,15 @@
|
|
|
295
298
|
cursor: pointer;
|
|
296
299
|
transition: background 0.1s ease;
|
|
297
300
|
overflow: hidden;
|
|
301
|
+
/* Recency tint ramp: in 'age' colorMode --blame-color runs green (recent)
|
|
302
|
+
-> gray (old), so a faint wash of it across the whole row makes the
|
|
303
|
+
green->gray gradient actually visible instead of a flat dark fill. */
|
|
304
|
+
background: color-mix(in srgb, var(--blame-color, #6b7280) 22%, transparent);
|
|
298
305
|
}
|
|
299
306
|
|
|
300
307
|
.git-blame-row:hover,
|
|
301
308
|
.git-blame-row--hovered {
|
|
302
|
-
background:
|
|
309
|
+
background: color-mix(in srgb, var(--blame-color, #6b7280) 34%, transparent);
|
|
303
310
|
}
|
|
304
311
|
|
|
305
312
|
.git-blame-row--uncommitted {
|
|
@@ -34,6 +34,13 @@
|
|
|
34
34
|
showSquiggles?: boolean;
|
|
35
35
|
/** Show gutter icons */
|
|
36
36
|
showGutterIcons?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Show the diagnostic message inline at the end of its line (Error Lens
|
|
39
|
+
* style), always visible — so the message no longer requires hovering the
|
|
40
|
+
* thin squiggle. The whole line becomes the hover/click target for the
|
|
41
|
+
* detailed tooltip. Default true.
|
|
42
|
+
*/
|
|
43
|
+
showInlineMessages?: boolean;
|
|
37
44
|
/** Callback when fix is applied */
|
|
38
45
|
onApplyFix?: (diagnostic: Diagnostic, fix: DiagnosticFix) => void;
|
|
39
46
|
/** Callback when diagnostic is clicked */
|
|
@@ -49,10 +56,19 @@
|
|
|
49
56
|
enabled = true,
|
|
50
57
|
showSquiggles = true,
|
|
51
58
|
showGutterIcons = true,
|
|
59
|
+
showInlineMessages = true,
|
|
52
60
|
onApplyFix,
|
|
53
61
|
onDiagnosticClick
|
|
54
62
|
}: Props = $props();
|
|
55
63
|
|
|
64
|
+
// Severity ordering for picking a line's primary (most severe) diagnostic.
|
|
65
|
+
const SEVERITY_RANK: Record<DiagnosticSeverity, number> = {
|
|
66
|
+
error: 0,
|
|
67
|
+
warning: 1,
|
|
68
|
+
info: 2,
|
|
69
|
+
hint: 3
|
|
70
|
+
};
|
|
71
|
+
|
|
56
72
|
let diagnostics = $state<Diagnostic[]>([]);
|
|
57
73
|
let hoveredDiagnostic = $state<Diagnostic | null>(null);
|
|
58
74
|
let tooltipPosition = $state({ top: 0, left: 0 });
|
|
@@ -100,10 +116,22 @@
|
|
|
100
116
|
return 'hint';
|
|
101
117
|
}
|
|
102
118
|
|
|
119
|
+
// One always-visible inline message per affected line: the most severe
|
|
120
|
+
// diagnostic on that line, plus a count of how many others share it.
|
|
121
|
+
const lineMessages = $derived(() =>
|
|
122
|
+
linesWithDiagnostics().map((line) => {
|
|
123
|
+
const diags = diagnosticsByLine().get(line) || [];
|
|
124
|
+
const primary = [...diags].sort(
|
|
125
|
+
(a, b) => SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity]
|
|
126
|
+
)[0];
|
|
127
|
+
return { line, primary, count: diags.length, severity: getLineSeverity(line) };
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
|
|
103
131
|
/**
|
|
104
132
|
* Handle mouse enter on diagnostic
|
|
105
133
|
*/
|
|
106
|
-
function handleMouseEnter(diagnostic: Diagnostic, event: MouseEvent) {
|
|
134
|
+
function handleMouseEnter(diagnostic: Diagnostic, event: MouseEvent | FocusEvent) {
|
|
107
135
|
hoveredDiagnostic = diagnostic;
|
|
108
136
|
const rect = (event.currentTarget as HTMLElement).getBoundingClientRect();
|
|
109
137
|
tooltipPosition = {
|
|
@@ -168,7 +196,38 @@
|
|
|
168
196
|
</script>
|
|
169
197
|
|
|
170
198
|
{#if enabled && diagnostics.length > 0}
|
|
171
|
-
<div class="diagnostics-layer"
|
|
199
|
+
<div class="diagnostics-layer">
|
|
200
|
+
<!-- Inline messages (Error Lens style): the message is ALWAYS visible at the
|
|
201
|
+
end of its line, and the full-line-height row — not the 4px squiggle — is
|
|
202
|
+
the hover/click/focus target for the detailed tooltip. -->
|
|
203
|
+
{#if showInlineMessages}
|
|
204
|
+
<div class="diagnostics-messages" style="left: {gutterWidth}px;">
|
|
205
|
+
{#each lineMessages() as { line, primary, count, severity } (line)}
|
|
206
|
+
<button
|
|
207
|
+
type="button"
|
|
208
|
+
class="diagnostic-row diagnostic-row--{severity}"
|
|
209
|
+
style="top: {line * lineHeight}px; height: {lineHeight}px;"
|
|
210
|
+
aria-label="{severity}: {primary.message}{count > 1
|
|
211
|
+
? ` (and ${count - 1} more on this line)`
|
|
212
|
+
: ''}"
|
|
213
|
+
onmouseenter={(e) => handleMouseEnter(primary, e)}
|
|
214
|
+
onmouseleave={handleMouseLeave}
|
|
215
|
+
onfocus={(e) => handleMouseEnter(primary, e)}
|
|
216
|
+
onblur={handleMouseLeave}
|
|
217
|
+
onclick={() => onDiagnosticClick?.(primary)}
|
|
218
|
+
>
|
|
219
|
+
<span class="row-chip">
|
|
220
|
+
<span class="row-icon" aria-hidden="true">{getSeverityIcon(severity)}</span>
|
|
221
|
+
<span class="row-message">{primary.message}</span>
|
|
222
|
+
{#if count > 1}
|
|
223
|
+
<span class="row-count" aria-hidden="true">+{count - 1}</span>
|
|
224
|
+
{/if}
|
|
225
|
+
</span>
|
|
226
|
+
</button>
|
|
227
|
+
{/each}
|
|
228
|
+
</div>
|
|
229
|
+
{/if}
|
|
230
|
+
|
|
172
231
|
<!-- Gutter icons -->
|
|
173
232
|
{#if showGutterIcons}
|
|
174
233
|
<div class="diagnostics-gutter" style="width: {gutterWidth}px;">
|
|
@@ -192,9 +251,9 @@
|
|
|
192
251
|
</div>
|
|
193
252
|
{/if}
|
|
194
253
|
|
|
195
|
-
<!-- Squiggly underlines -->
|
|
254
|
+
<!-- Squiggly underlines (decorative cue; interaction lives on the row above) -->
|
|
196
255
|
{#if showSquiggles}
|
|
197
|
-
<div class="diagnostics-squiggles" style="left: {gutterWidth}px;">
|
|
256
|
+
<div class="diagnostics-squiggles" style="left: {gutterWidth}px;" aria-hidden="true">
|
|
198
257
|
{#each diagnostics as diagnostic (diagnostic.id)}
|
|
199
258
|
{@const startCol = diagnostic.range.start.column}
|
|
200
259
|
{@const endCol = diagnostic.range.end.column}
|
|
@@ -210,10 +269,6 @@
|
|
|
210
269
|
left: {startCol * charWidth}px;
|
|
211
270
|
width: {width}px;
|
|
212
271
|
"
|
|
213
|
-
onmouseenter={(e) => handleMouseEnter(diagnostic, e)}
|
|
214
|
-
onmouseleave={handleMouseLeave}
|
|
215
|
-
role="button"
|
|
216
|
-
tabindex={-1}
|
|
217
272
|
>
|
|
218
273
|
<svg class="squiggle-svg" {width} height="4" viewBox="0 0 {width} 4">
|
|
219
274
|
<path d={generateSquigglePath(width)} stroke={color} stroke-width="1" fill="none" />
|
|
@@ -336,19 +391,19 @@
|
|
|
336
391
|
}
|
|
337
392
|
|
|
338
393
|
.gutter-icon--error .icon-text {
|
|
339
|
-
color:
|
|
394
|
+
color: var(--ide-error);
|
|
340
395
|
}
|
|
341
396
|
|
|
342
397
|
.gutter-icon--warning .icon-text {
|
|
343
|
-
color:
|
|
398
|
+
color: var(--ide-warning);
|
|
344
399
|
}
|
|
345
400
|
|
|
346
401
|
.gutter-icon--info .icon-text {
|
|
347
|
-
color:
|
|
402
|
+
color: var(--ide-info);
|
|
348
403
|
}
|
|
349
404
|
|
|
350
405
|
.gutter-icon--hint .icon-text {
|
|
351
|
-
color:
|
|
406
|
+
color: var(--ide-text-muted);
|
|
352
407
|
}
|
|
353
408
|
|
|
354
409
|
.icon-count {
|
|
@@ -376,8 +431,166 @@
|
|
|
376
431
|
|
|
377
432
|
.squiggle {
|
|
378
433
|
position: absolute;
|
|
379
|
-
|
|
434
|
+
/* Decorative now — the full-line row above owns hover/click. */
|
|
435
|
+
pointer-events: none;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/* Inline messages (Error Lens style) */
|
|
439
|
+
.diagnostics-messages {
|
|
440
|
+
position: absolute;
|
|
441
|
+
top: 0;
|
|
442
|
+
right: 0;
|
|
443
|
+
height: 100%;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.diagnostic-row {
|
|
447
|
+
position: absolute;
|
|
448
|
+
left: 0;
|
|
449
|
+
right: 0;
|
|
450
|
+
display: flex;
|
|
451
|
+
align-items: center;
|
|
452
|
+
justify-content: flex-end;
|
|
453
|
+
margin: 0;
|
|
454
|
+
/* Reserve a left gap so the right-aligned chip never butts directly against
|
|
455
|
+
code text on a long line — code and message keep a visible breathing gap. */
|
|
456
|
+
padding: 0 8px 0 16px;
|
|
457
|
+
background: transparent;
|
|
458
|
+
border: none;
|
|
459
|
+
border-left: 2px solid transparent;
|
|
460
|
+
font: inherit;
|
|
380
461
|
cursor: pointer;
|
|
462
|
+
pointer-events: auto;
|
|
463
|
+
overflow: hidden;
|
|
464
|
+
transition: background 0.12s ease;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/* The message sits in an opaque chip so it stays legible even if it overlaps
|
|
468
|
+
code on a long line — the row's faint full-width tint is just the line
|
|
469
|
+
highlight / hit target underneath. */
|
|
470
|
+
.row-chip {
|
|
471
|
+
display: inline-flex;
|
|
472
|
+
align-items: center;
|
|
473
|
+
gap: 6px;
|
|
474
|
+
max-width: min(100%, 64ch);
|
|
475
|
+
padding: 1px 8px;
|
|
476
|
+
border-radius: 6px;
|
|
477
|
+
overflow: hidden;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.row-icon {
|
|
481
|
+
flex-shrink: 0;
|
|
482
|
+
font-size: 11px;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.row-message {
|
|
486
|
+
overflow: hidden;
|
|
487
|
+
font-size: 12px;
|
|
488
|
+
line-height: 1.4;
|
|
489
|
+
white-space: nowrap;
|
|
490
|
+
text-overflow: ellipsis;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
.row-count {
|
|
494
|
+
flex-shrink: 0;
|
|
495
|
+
min-width: 16px;
|
|
496
|
+
padding: 1px 5px;
|
|
497
|
+
border-radius: 8px;
|
|
498
|
+
background: color-mix(in srgb, var(--ide-text-muted) 22%, transparent);
|
|
499
|
+
font-size: 10px;
|
|
500
|
+
font-weight: 600;
|
|
501
|
+
color: var(--ide-text-secondary, #aaa);
|
|
502
|
+
text-align: center;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/* On genuinely narrow (phone) viewports an inline message would overprint code
|
|
506
|
+
with no room for the reserved gap — drop it there and rely on the gutter icon
|
|
507
|
+
+ tooltip instead. Tablets (641–768px) keep the message: the opaque severity
|
|
508
|
+
chip and the reserved left gap below keep it legible and off the code. */
|
|
509
|
+
@media (max-width: 480px) {
|
|
510
|
+
.diagnostics-messages {
|
|
511
|
+
display: none;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/* Tablet (481–768px): keep the message on-screen but cap the chip so a long
|
|
516
|
+
message ellipsizes within the pane instead of clipping past the right edge,
|
|
517
|
+
and hold the reserved left gap so it never overprints code. */
|
|
518
|
+
@media (max-width: 768px) {
|
|
519
|
+
.diagnostic-row .row-chip {
|
|
520
|
+
max-width: min(100%, 40ch);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
.diagnostic-row:focus-visible {
|
|
525
|
+
outline: 1px solid var(--ide-interactive, #4f8cc9);
|
|
526
|
+
outline-offset: -1px;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.diagnostic-row--error {
|
|
530
|
+
background: color-mix(in srgb, var(--ide-error) 9%, transparent);
|
|
531
|
+
border-left-color: color-mix(in srgb, var(--ide-error) 55%, transparent);
|
|
532
|
+
}
|
|
533
|
+
.diagnostic-row--error:hover,
|
|
534
|
+
.diagnostic-row--error:focus-visible {
|
|
535
|
+
background: color-mix(in srgb, var(--ide-error) 17%, transparent);
|
|
536
|
+
}
|
|
537
|
+
.diagnostic-row--error .row-icon,
|
|
538
|
+
.diagnostic-row--error .row-message {
|
|
539
|
+
color: var(--ide-error);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.diagnostic-row--warning {
|
|
543
|
+
background: color-mix(in srgb, var(--ide-warning) 9%, transparent);
|
|
544
|
+
border-left-color: color-mix(in srgb, var(--ide-warning) 55%, transparent);
|
|
545
|
+
}
|
|
546
|
+
.diagnostic-row--warning:hover,
|
|
547
|
+
.diagnostic-row--warning:focus-visible {
|
|
548
|
+
background: color-mix(in srgb, var(--ide-warning) 17%, transparent);
|
|
549
|
+
}
|
|
550
|
+
.diagnostic-row--warning .row-icon,
|
|
551
|
+
.diagnostic-row--warning .row-message {
|
|
552
|
+
color: var(--ide-warning);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.diagnostic-row--info {
|
|
556
|
+
background: color-mix(in srgb, var(--ide-info) 8%, transparent);
|
|
557
|
+
border-left-color: color-mix(in srgb, var(--ide-info) 50%, transparent);
|
|
558
|
+
}
|
|
559
|
+
.diagnostic-row--info:hover,
|
|
560
|
+
.diagnostic-row--info:focus-visible {
|
|
561
|
+
background: color-mix(in srgb, var(--ide-info) 16%, transparent);
|
|
562
|
+
}
|
|
563
|
+
.diagnostic-row--info .row-icon,
|
|
564
|
+
.diagnostic-row--info .row-message {
|
|
565
|
+
color: var(--ide-info);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
.diagnostic-row--hint {
|
|
569
|
+
background: color-mix(in srgb, var(--ide-text-muted) 7%, transparent);
|
|
570
|
+
border-left-color: color-mix(in srgb, var(--ide-text-muted) 45%, transparent);
|
|
571
|
+
}
|
|
572
|
+
.diagnostic-row--hint:hover,
|
|
573
|
+
.diagnostic-row--hint:focus-visible {
|
|
574
|
+
background: color-mix(in srgb, var(--ide-text-muted) 14%, transparent);
|
|
575
|
+
}
|
|
576
|
+
.diagnostic-row--hint .row-icon,
|
|
577
|
+
.diagnostic-row--hint .row-message {
|
|
578
|
+
color: var(--ide-text-muted);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/* Opaque chip surfaces: an elevated base tinted by severity, so the message
|
|
582
|
+
reads cleanly whether it floats over empty space or over code. */
|
|
583
|
+
.diagnostic-row--error .row-chip {
|
|
584
|
+
background: color-mix(in srgb, var(--ide-error) 16%, var(--ide-bg-elevated, #252536));
|
|
585
|
+
}
|
|
586
|
+
.diagnostic-row--warning .row-chip {
|
|
587
|
+
background: color-mix(in srgb, var(--ide-warning) 16%, var(--ide-bg-elevated, #252536));
|
|
588
|
+
}
|
|
589
|
+
.diagnostic-row--info .row-chip {
|
|
590
|
+
background: color-mix(in srgb, var(--ide-info) 14%, var(--ide-bg-elevated, #252536));
|
|
591
|
+
}
|
|
592
|
+
.diagnostic-row--hint .row-chip {
|
|
593
|
+
background: color-mix(in srgb, var(--ide-text-muted) 14%, var(--ide-bg-elevated, #252536));
|
|
381
594
|
}
|
|
382
595
|
|
|
383
596
|
.squiggle--deprecated {
|
|
@@ -25,6 +25,13 @@ interface Props {
|
|
|
25
25
|
showSquiggles?: boolean;
|
|
26
26
|
/** Show gutter icons */
|
|
27
27
|
showGutterIcons?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Show the diagnostic message inline at the end of its line (Error Lens
|
|
30
|
+
* style), always visible — so the message no longer requires hovering the
|
|
31
|
+
* thin squiggle. The whole line becomes the hover/click target for the
|
|
32
|
+
* detailed tooltip. Default true.
|
|
33
|
+
*/
|
|
34
|
+
showInlineMessages?: boolean;
|
|
28
35
|
/** Callback when fix is applied */
|
|
29
36
|
onApplyFix?: (diagnostic: Diagnostic, fix: DiagnosticFix) => void;
|
|
30
37
|
/** Callback when diagnostic is clicked */
|
|
@@ -50,7 +50,10 @@
|
|
|
50
50
|
case 'added':
|
|
51
51
|
return 'var(--ide-status-created)';
|
|
52
52
|
case 'modified':
|
|
53
|
-
|
|
53
|
+
// Modified indicator is BLUE to match the diff legend (Modified = blue).
|
|
54
|
+
// --ide-status-modified resolves to aurora-yellow (amber), which
|
|
55
|
+
// contradicts the legend; drive it from --ide-info (#60a5fa) instead.
|
|
56
|
+
return 'var(--ide-info)';
|
|
54
57
|
case 'removed':
|
|
55
58
|
return 'var(--ide-status-deleted)';
|
|
56
59
|
default:
|
|
@@ -175,7 +178,10 @@
|
|
|
175
178
|
onclick={() => handleClick(group.changes[0])}
|
|
176
179
|
onkeydown={(e) => e.key === 'Enter' && handleClick(group.changes[0])}
|
|
177
180
|
role="button"
|
|
178
|
-
tabindex={-1}
|
|
181
|
+
tabindex={onChangeClick ? 0 : -1}
|
|
182
|
+
aria-label={onChangeClick
|
|
183
|
+
? `${getLabel(group.type)}: ${group.changes.length} line${group.changes.length !== 1 ? 's' : ''} — view full diff`
|
|
184
|
+
: undefined}
|
|
179
185
|
title="{getLabel(group.type)}: {group.changes.length} line{group.changes.length !== 1
|
|
180
186
|
? 's'
|
|
181
187
|
: ''}"
|
|
@@ -739,7 +739,10 @@
|
|
|
739
739
|
line-height: 1.5;
|
|
740
740
|
color: var(--ide-text-primary, #f4f1e0);
|
|
741
741
|
overflow: auto;
|
|
742
|
-
|
|
742
|
+
/* Wrap long single-line transformed output (e.g. Minify) instead of
|
|
743
|
+
clipping it off the pane's right edge with no scroll affordance. */
|
|
744
|
+
white-space: pre-wrap;
|
|
745
|
+
overflow-wrap: anywhere;
|
|
743
746
|
}
|
|
744
747
|
|
|
745
748
|
/* Split view */
|
|
@@ -793,6 +796,7 @@
|
|
|
793
796
|
|
|
794
797
|
.diff-line__num {
|
|
795
798
|
width: 40px;
|
|
799
|
+
flex-shrink: 0;
|
|
796
800
|
color: var(--ide-text-muted, #a8c5d9);
|
|
797
801
|
text-align: right;
|
|
798
802
|
padding-right: 8px;
|
|
@@ -801,6 +805,7 @@
|
|
|
801
805
|
|
|
802
806
|
.diff-line__sign {
|
|
803
807
|
width: 16px;
|
|
808
|
+
flex-shrink: 0;
|
|
804
809
|
color: var(--ide-text-muted, #a8c5d9);
|
|
805
810
|
}
|
|
806
811
|
|
|
@@ -814,7 +819,10 @@
|
|
|
814
819
|
|
|
815
820
|
.diff-line__content {
|
|
816
821
|
flex: 1;
|
|
817
|
-
|
|
822
|
+
min-width: 0;
|
|
823
|
+
/* Wrap long single-line diff output instead of clipping it off-pane. */
|
|
824
|
+
white-space: pre-wrap;
|
|
825
|
+
overflow-wrap: anywhere;
|
|
818
826
|
}
|
|
819
827
|
|
|
820
828
|
.diff-line--add .diff-line__content {
|
|
@@ -426,7 +426,9 @@
|
|
|
426
426
|
}
|
|
427
427
|
|
|
428
428
|
.action-btn.active {
|
|
429
|
-
|
|
429
|
+
/* interactive accent stays BLUE per owner brand decision
|
|
430
|
+
(was an off-token #a855f7 purple literal) */
|
|
431
|
+
color: var(--ide-interactive, #4f8cc9);
|
|
430
432
|
}
|
|
431
433
|
|
|
432
434
|
.close-btn {
|
|
@@ -571,6 +573,9 @@
|
|
|
571
573
|
|
|
572
574
|
.diagnostic-message {
|
|
573
575
|
flex: 1;
|
|
576
|
+
/* min-width:0 lets the message shrink/ellipsize instead of forcing the
|
|
577
|
+
metadata (code/chip/[Ln,Col]) to absorb the squeeze first */
|
|
578
|
+
min-width: 0;
|
|
574
579
|
overflow: hidden;
|
|
575
580
|
text-overflow: ellipsis;
|
|
576
581
|
white-space: nowrap;
|
|
@@ -582,22 +587,52 @@
|
|
|
582
587
|
}
|
|
583
588
|
|
|
584
589
|
.diagnostic-source {
|
|
590
|
+
flex-shrink: 0;
|
|
585
591
|
font-size: 10px;
|
|
586
592
|
padding: 1px 4px;
|
|
587
|
-
|
|
593
|
+
/* nudged a notch lighter (0.1 -> 0.16) so the chip label clears AA */
|
|
594
|
+
background: rgba(255, 255, 255, 0.16);
|
|
588
595
|
border-radius: 2px;
|
|
589
|
-
|
|
596
|
+
/* lifted from --ide-text-muted (~3:1, below AA at 10-11px) to clear 4.5:1 */
|
|
597
|
+
color: var(--ide-text-secondary, #aaa);
|
|
590
598
|
}
|
|
591
599
|
|
|
592
600
|
.diagnostic-code {
|
|
601
|
+
flex-shrink: 0;
|
|
593
602
|
font-family: monospace;
|
|
594
603
|
font-size: 10px;
|
|
595
|
-
|
|
604
|
+
/* lifted from --ide-text-muted so TS codes (TS2552/TS6133) clear AA */
|
|
605
|
+
color: var(--ide-text-secondary, #aaa);
|
|
596
606
|
}
|
|
597
607
|
|
|
598
608
|
.diagnostic-location {
|
|
609
|
+
flex-shrink: 0;
|
|
599
610
|
font-family: monospace;
|
|
600
611
|
font-size: 10px;
|
|
601
|
-
|
|
612
|
+
/* lifted from --ide-text-muted so [Ln, Col] coords clear AA */
|
|
613
|
+
color: var(--ide-text-secondary, #aaa);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/* Narrow viewports: collapse the single-line row into two lines so the
|
|
617
|
+
message stays readable instead of truncating to a single glyph while the
|
|
618
|
+
code / chip / [Ln, Col] keep full width. The icon + message hold line one
|
|
619
|
+
(message gets a 2-line clamp); the source/code/location metadata wrap to a
|
|
620
|
+
second, gutter-indented line. */
|
|
621
|
+
@media (max-width: 480px) {
|
|
622
|
+
.diagnostic-item {
|
|
623
|
+
flex-wrap: wrap;
|
|
624
|
+
row-gap: 2px;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.diagnostic-message {
|
|
628
|
+
/* take the full first line so metadata is pushed to line two */
|
|
629
|
+
flex: 1 1 100%;
|
|
630
|
+
/* message is the LAST field to truncate: allow up to 2 lines */
|
|
631
|
+
white-space: normal;
|
|
632
|
+
display: -webkit-box;
|
|
633
|
+
-webkit-line-clamp: 2;
|
|
634
|
+
line-clamp: 2;
|
|
635
|
+
-webkit-box-orient: vertical;
|
|
636
|
+
}
|
|
602
637
|
}
|
|
603
638
|
</style>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { SnippetManager, Snippet } from './core/snippet-manager';
|
|
10
|
+
import Icon from '../core/Icon.svelte';
|
|
10
11
|
|
|
11
12
|
interface Props {
|
|
12
13
|
/** Snippet manager instance */
|
|
@@ -174,6 +175,9 @@
|
|
|
174
175
|
bind:value={searchQuery}
|
|
175
176
|
/>
|
|
176
177
|
<span class="snippet-hint">Tab: categories, Enter: insert, Esc: close</span>
|
|
178
|
+
<button class="snippet-close" type="button" aria-label="Close" onclick={() => onClose?.()}>
|
|
179
|
+
<Icon name="close" size={18} />
|
|
180
|
+
</button>
|
|
177
181
|
</div>
|
|
178
182
|
|
|
179
183
|
<div class="snippet-categories">
|
|
@@ -318,10 +322,39 @@
|
|
|
318
322
|
|
|
319
323
|
.snippet-hint {
|
|
320
324
|
font-size: 11px;
|
|
321
|
-
color: var(--ide-text-
|
|
325
|
+
color: var(--ide-text-secondary, #a8c5d9);
|
|
322
326
|
white-space: nowrap;
|
|
323
327
|
}
|
|
324
328
|
|
|
329
|
+
.snippet-close {
|
|
330
|
+
display: inline-flex;
|
|
331
|
+
align-items: center;
|
|
332
|
+
justify-content: center;
|
|
333
|
+
flex: none;
|
|
334
|
+
width: 44px;
|
|
335
|
+
height: 44px;
|
|
336
|
+
margin: -8px -4px -8px 0;
|
|
337
|
+
padding: 0;
|
|
338
|
+
background: transparent;
|
|
339
|
+
border: none;
|
|
340
|
+
border-radius: 6px;
|
|
341
|
+
color: var(--ide-text-secondary, #a8c5d9);
|
|
342
|
+
cursor: pointer;
|
|
343
|
+
transition:
|
|
344
|
+
background 0.15s ease,
|
|
345
|
+
color 0.15s ease;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.snippet-close:hover {
|
|
349
|
+
background: color-mix(in srgb, var(--ide-text-primary) 8%, transparent);
|
|
350
|
+
color: var(--ide-text-primary, #f4f1e0);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.snippet-close:focus-visible {
|
|
354
|
+
outline: 2px solid var(--ide-interactive-focus);
|
|
355
|
+
outline-offset: 2px;
|
|
356
|
+
}
|
|
357
|
+
|
|
325
358
|
.snippet-categories {
|
|
326
359
|
display: flex;
|
|
327
360
|
gap: 4px;
|
|
@@ -343,13 +376,18 @@
|
|
|
343
376
|
}
|
|
344
377
|
|
|
345
378
|
.category-tab:hover {
|
|
346
|
-
background:
|
|
379
|
+
background: color-mix(in srgb, var(--ide-text-primary) 5%, transparent);
|
|
347
380
|
color: var(--ide-text-primary, #f4f1e0);
|
|
348
381
|
}
|
|
349
382
|
|
|
350
383
|
.category-tab.active {
|
|
351
|
-
background:
|
|
352
|
-
color:
|
|
384
|
+
background: color-mix(in srgb, var(--ide-interactive) 20%, transparent);
|
|
385
|
+
color: var(--ide-interactive);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.category-tab:focus-visible {
|
|
389
|
+
outline: 2px solid var(--ide-interactive-focus);
|
|
390
|
+
outline-offset: 2px;
|
|
353
391
|
}
|
|
354
392
|
|
|
355
393
|
.snippet-content {
|
|
@@ -367,7 +405,7 @@
|
|
|
367
405
|
.snippet-empty {
|
|
368
406
|
padding: 24px;
|
|
369
407
|
text-align: center;
|
|
370
|
-
color: var(--ide-text-
|
|
408
|
+
color: var(--ide-text-secondary, #a8c5d9);
|
|
371
409
|
font-size: 13px;
|
|
372
410
|
}
|
|
373
411
|
|
|
@@ -385,7 +423,12 @@
|
|
|
385
423
|
|
|
386
424
|
.snippet-item:hover,
|
|
387
425
|
.snippet-item.selected {
|
|
388
|
-
background:
|
|
426
|
+
background: color-mix(in srgb, var(--ide-interactive) 12%, transparent);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.snippet-item:focus-visible {
|
|
430
|
+
outline: 2px solid var(--ide-interactive-focus);
|
|
431
|
+
outline-offset: -2px;
|
|
389
432
|
}
|
|
390
433
|
|
|
391
434
|
.snippet-item-header {
|
|
@@ -399,9 +442,9 @@
|
|
|
399
442
|
font-family: monospace;
|
|
400
443
|
font-size: 12px;
|
|
401
444
|
padding: 2px 6px;
|
|
402
|
-
background:
|
|
445
|
+
background: color-mix(in srgb, var(--ide-interactive) 20%, transparent);
|
|
403
446
|
border-radius: 4px;
|
|
404
|
-
color:
|
|
447
|
+
color: var(--ide-interactive);
|
|
405
448
|
}
|
|
406
449
|
|
|
407
450
|
.snippet-name {
|
|
@@ -413,15 +456,15 @@
|
|
|
413
456
|
.snippet-badge {
|
|
414
457
|
margin-left: auto;
|
|
415
458
|
padding: 1px 6px;
|
|
416
|
-
background:
|
|
459
|
+
background: color-mix(in srgb, var(--ide-success) 20%, transparent);
|
|
417
460
|
border-radius: 4px;
|
|
418
461
|
font-size: 10px;
|
|
419
|
-
color:
|
|
462
|
+
color: var(--ide-success);
|
|
420
463
|
}
|
|
421
464
|
|
|
422
465
|
.snippet-item-desc {
|
|
423
466
|
font-size: 11px;
|
|
424
|
-
color: var(--ide-text-
|
|
467
|
+
color: var(--ide-text-secondary, #a8c5d9);
|
|
425
468
|
}
|
|
426
469
|
|
|
427
470
|
/* Preview pane */
|
|
@@ -448,7 +491,7 @@
|
|
|
448
491
|
.preview-category {
|
|
449
492
|
font-size: 11px;
|
|
450
493
|
padding: 2px 8px;
|
|
451
|
-
background:
|
|
494
|
+
background: color-mix(in srgb, var(--ide-text-primary) 10%, transparent);
|
|
452
495
|
border-radius: 4px;
|
|
453
496
|
color: var(--ide-text-secondary, #a8c5d9);
|
|
454
497
|
}
|
|
@@ -472,13 +515,13 @@
|
|
|
472
515
|
}
|
|
473
516
|
|
|
474
517
|
:global(.preview-tabstop) {
|
|
475
|
-
background:
|
|
518
|
+
background: color-mix(in srgb, var(--ide-interactive) 30%, transparent);
|
|
476
519
|
border-radius: 2px;
|
|
477
520
|
padding: 0 2px;
|
|
478
521
|
}
|
|
479
522
|
|
|
480
523
|
:global(.preview-variable) {
|
|
481
|
-
color:
|
|
524
|
+
color: var(--ide-success);
|
|
482
525
|
}
|
|
483
526
|
|
|
484
527
|
.preview-footer {
|
|
@@ -486,12 +529,12 @@
|
|
|
486
529
|
justify-content: space-between;
|
|
487
530
|
margin-top: 12px;
|
|
488
531
|
font-size: 11px;
|
|
489
|
-
color: var(--ide-text-
|
|
532
|
+
color: var(--ide-text-secondary, #a8c5d9);
|
|
490
533
|
}
|
|
491
534
|
|
|
492
535
|
.preview-footer code {
|
|
493
536
|
font-family: monospace;
|
|
494
|
-
background:
|
|
537
|
+
background: color-mix(in srgb, var(--ide-text-primary) 10%, transparent);
|
|
495
538
|
padding: 1px 4px;
|
|
496
539
|
border-radius: 2px;
|
|
497
540
|
}
|
|
@@ -505,9 +548,9 @@
|
|
|
505
548
|
.lang-tag {
|
|
506
549
|
font-size: 10px;
|
|
507
550
|
padding: 2px 6px;
|
|
508
|
-
background:
|
|
551
|
+
background: color-mix(in srgb, var(--ide-info) 20%, transparent);
|
|
509
552
|
border-radius: 3px;
|
|
510
|
-
color:
|
|
553
|
+
color: var(--ide-info);
|
|
511
554
|
}
|
|
512
555
|
|
|
513
556
|
.preview-empty {
|
|
@@ -515,7 +558,7 @@
|
|
|
515
558
|
align-items: center;
|
|
516
559
|
justify-content: center;
|
|
517
560
|
height: 100%;
|
|
518
|
-
color: var(--ide-text-
|
|
561
|
+
color: var(--ide-text-secondary, #a8c5d9);
|
|
519
562
|
font-size: 13px;
|
|
520
563
|
}
|
|
521
564
|
|
|
@@ -525,6 +568,6 @@
|
|
|
525
568
|
padding: 8px 16px;
|
|
526
569
|
border-top: 1px solid var(--ide-border, #a8c5d9);
|
|
527
570
|
font-size: 11px;
|
|
528
|
-
color: var(--ide-text-
|
|
571
|
+
color: var(--ide-text-secondary, #a8c5d9);
|
|
529
572
|
}
|
|
530
573
|
</style>
|