inspector-ng 0.0.15 → 0.0.22
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 +9 -7
- package/esm2022/lib/checkpoints.mjs +84 -2
- package/esm2022/lib/distances.mjs +84 -2
- package/esm2022/lib/inspector.component.mjs +246 -45
- package/esm2022/lib/types.mjs +1 -1
- package/fesm2022/inspector-ng.mjs +411 -46
- package/fesm2022/inspector-ng.mjs.map +1 -1
- package/lib/checkpoints.d.ts +5 -0
- package/lib/distances.d.ts +2 -2
- package/lib/inspector.component.d.ts +20 -3
- package/lib/types.d.ts +3 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, PLATFORM_ID, Inject, Injectable, signal, Optional, makeEnvironmentProviders, viewChild, inject, computed, HostListener, Input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
2
|
+
import { InjectionToken, PLATFORM_ID, Inject, Injectable, signal, Optional, makeEnvironmentProviders, viewChild, inject, computed, effect, HostListener, Input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { isPlatformBrowser } from '@angular/common';
|
|
4
4
|
import * as i2 from '@angular/router';
|
|
5
5
|
import { Router } from '@angular/router';
|
|
@@ -14,6 +14,7 @@ const RESTORE_CHECKPOINT = '[Inspector Checkpoints] Restore';
|
|
|
14
14
|
const DATABASE_NAME = 'inspector-ng';
|
|
15
15
|
const DATABASE_VERSION = 1;
|
|
16
16
|
const STORE_NAME = 'checkpoints';
|
|
17
|
+
const RESTORE_SETTLE_DELAY_MS = 100;
|
|
17
18
|
const INSPECTOR_CHECKPOINT_REPOSITORY = new InjectionToken('INSPECTOR_CHECKPOINT_REPOSITORY');
|
|
18
19
|
function inspectorCheckpointMetaReducer(reducer) {
|
|
19
20
|
return (state, action) => {
|
|
@@ -168,6 +169,34 @@ class InspectorCheckpointService {
|
|
|
168
169
|
this.busy.set(false);
|
|
169
170
|
}
|
|
170
171
|
}
|
|
172
|
+
async importCheckpoint(value) {
|
|
173
|
+
this.error.set(null);
|
|
174
|
+
if (!isCheckpointRecord(value)) {
|
|
175
|
+
this.error.set('The selected file is not a valid inspector-ng checkpoint. Expected a version 1 checkpoint JSON file.');
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
this.busy.set(true);
|
|
179
|
+
try {
|
|
180
|
+
const persisted = await this.repository.list();
|
|
181
|
+
const checkpoint = {
|
|
182
|
+
...value,
|
|
183
|
+
id: createCheckpointId(),
|
|
184
|
+
name: nextAutomaticName(value.name, persisted.map(({ name }) => name)),
|
|
185
|
+
createdAt: new Date().toISOString(),
|
|
186
|
+
lastUsedAt: undefined,
|
|
187
|
+
};
|
|
188
|
+
await this.repository.put(checkpoint);
|
|
189
|
+
this.checkpoints.set([checkpoint, ...persisted].sort(recentActivityFirst));
|
|
190
|
+
return checkpoint;
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
this.error.set(this.storageMessage(error, 'The checkpoint could not be imported.'));
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
this.busy.set(false);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
171
200
|
async restore(id) {
|
|
172
201
|
this.error.set(null);
|
|
173
202
|
if (!this.store) {
|
|
@@ -181,12 +210,14 @@ class InspectorCheckpointService {
|
|
|
181
210
|
if (!checkpoint)
|
|
182
211
|
throw new Error('Checkpoint not found. It may have been deleted in another tab.');
|
|
183
212
|
const state = cloneJson(checkpoint.state, `“${checkpoint.name}” could not be decoded. Delete it and save a new checkpoint.`);
|
|
184
|
-
this.
|
|
213
|
+
this.restoreState(state);
|
|
185
214
|
if (this.router &&
|
|
186
215
|
this.router.url !== checkpoint.route &&
|
|
187
216
|
!await this.router.navigateByUrl(checkpoint.route)) {
|
|
188
217
|
throw new Error(`The state was restored, but navigation to “${checkpoint.route}” was cancelled.`);
|
|
189
218
|
}
|
|
219
|
+
await delay(RESTORE_SETTLE_DELAY_MS);
|
|
220
|
+
this.restoreState(state);
|
|
190
221
|
const recentlyUsedCheckpoint = {
|
|
191
222
|
...checkpoint,
|
|
192
223
|
lastUsedAt: new Date().toISOString(),
|
|
@@ -205,6 +236,32 @@ class InspectorCheckpointService {
|
|
|
205
236
|
this.busy.set(false);
|
|
206
237
|
}
|
|
207
238
|
}
|
|
239
|
+
async navigateToRoute(route) {
|
|
240
|
+
this.error.set(null);
|
|
241
|
+
if (!this.router) {
|
|
242
|
+
this.error.set('The Angular Router is unavailable, so the Inspector cannot navigate.');
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
this.busy.set(true);
|
|
246
|
+
try {
|
|
247
|
+
if (this.router.url !== route && !await this.router.navigateByUrl(route)) {
|
|
248
|
+
throw new Error(`Navigation to “${route}” was cancelled.`);
|
|
249
|
+
}
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
this.error.set(this.messageFor(error, 'The route could not be opened.'));
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
finally {
|
|
257
|
+
this.busy.set(false);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
resolveRoute(query) {
|
|
261
|
+
if (!isPlatformBrowser(this.platformId))
|
|
262
|
+
return null;
|
|
263
|
+
return resolveRouteQuery(query, this.currentPathname());
|
|
264
|
+
}
|
|
208
265
|
async rename(id, name) {
|
|
209
266
|
this.error.set(null);
|
|
210
267
|
const nextName = name.trim();
|
|
@@ -252,6 +309,9 @@ class InspectorCheckpointService {
|
|
|
252
309
|
clearError() {
|
|
253
310
|
this.error.set(null);
|
|
254
311
|
}
|
|
312
|
+
restoreState(state) {
|
|
313
|
+
this.store?.dispatch({ type: RESTORE_CHECKPOINT, state });
|
|
314
|
+
}
|
|
255
315
|
currentRoute() {
|
|
256
316
|
if (!isPlatformBrowser(this.platformId))
|
|
257
317
|
return '/';
|
|
@@ -296,6 +356,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
296
356
|
type: Inject,
|
|
297
357
|
args: [PLATFORM_ID]
|
|
298
358
|
}] }] });
|
|
359
|
+
function delay(milliseconds) {
|
|
360
|
+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
361
|
+
}
|
|
299
362
|
function provideInspectorCheckpoints() {
|
|
300
363
|
return makeEnvironmentProviders([
|
|
301
364
|
IndexedDbCheckpointRepository,
|
|
@@ -321,6 +384,25 @@ function nextAutomaticName(route, names) {
|
|
|
321
384
|
return candidate;
|
|
322
385
|
}
|
|
323
386
|
}
|
|
387
|
+
function resolveRouteQuery(query, basePathname) {
|
|
388
|
+
const raw = query.trim();
|
|
389
|
+
if (!raw)
|
|
390
|
+
return null;
|
|
391
|
+
if (raw.startsWith('/'))
|
|
392
|
+
return raw;
|
|
393
|
+
if (raw === '.' || raw === '..' || raw.startsWith('./') || raw.startsWith('../')) {
|
|
394
|
+
const base = basePathname.startsWith('/') ? basePathname : `/${basePathname}`;
|
|
395
|
+
// Resolve against the current route as a directory: "./x" appends to it
|
|
396
|
+
// and "../x" moves up one route level, like Angular's relative navigation.
|
|
397
|
+
const directory = base.endsWith('/') ? base : `${base}/`;
|
|
398
|
+
const url = new URL(raw, `http://inspector.local${directory}`);
|
|
399
|
+
const pathname = url.pathname.length > 1 && url.pathname.endsWith('/')
|
|
400
|
+
? url.pathname.slice(0, -1)
|
|
401
|
+
: url.pathname;
|
|
402
|
+
return `${pathname}${url.search}${url.hash}`;
|
|
403
|
+
}
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
324
406
|
function cloneJson(value, failureMessage = 'The NgRx root state is not JSON-serializable. Remove circular or unsupported values and try again.') {
|
|
325
407
|
try {
|
|
326
408
|
const serialized = JSON.stringify(value);
|
|
@@ -386,7 +468,7 @@ const rectsEqual = (a, b, epsilon = 0.5) => {
|
|
|
386
468
|
Math.abs(a.height - b.height) < epsilon);
|
|
387
469
|
};
|
|
388
470
|
|
|
389
|
-
const getDistanceOverlay = (rectA, rectB) => {
|
|
471
|
+
const getDistanceOverlay = (rectA, rectB, relation) => {
|
|
390
472
|
const rightA = rectA.left + rectA.width;
|
|
391
473
|
const bottomA = rectA.top + rectA.height;
|
|
392
474
|
const rightB = rectB.left + rectB.width;
|
|
@@ -395,6 +477,8 @@ const getDistanceOverlay = (rectA, rectB) => {
|
|
|
395
477
|
const centerAY = rectA.top + rectA.height / 2;
|
|
396
478
|
let horizontal = null;
|
|
397
479
|
let vertical = null;
|
|
480
|
+
let horizontalDistances = [];
|
|
481
|
+
let verticalDistances = [];
|
|
398
482
|
const connectors = [];
|
|
399
483
|
const separatedX = rightA <= rectB.left || rightB <= rectA.left;
|
|
400
484
|
const separatedY = bottomA <= rectB.top || bottomB <= rectA.top;
|
|
@@ -404,6 +488,7 @@ const getDistanceOverlay = (rectA, rectB) => {
|
|
|
404
488
|
const x2 = aIsLeft ? rectB.left : rectA.left;
|
|
405
489
|
const y = centerAY;
|
|
406
490
|
horizontal = { x1, x2, y, value: Math.abs(x2 - x1) };
|
|
491
|
+
horizontalDistances = [horizontal];
|
|
407
492
|
const edgeBX = aIsLeft ? rectB.left : rightB;
|
|
408
493
|
if (y < rectB.top) {
|
|
409
494
|
connectors.push({ x1: edgeBX, y1: y, x2: edgeBX, y2: rectB.top });
|
|
@@ -418,6 +503,7 @@ const getDistanceOverlay = (rectA, rectB) => {
|
|
|
418
503
|
const y2 = aIsTop ? rectB.top : rectA.top;
|
|
419
504
|
const x = centerAX;
|
|
420
505
|
vertical = { y1, y2, x, value: Math.abs(y2 - y1) };
|
|
506
|
+
verticalDistances = [vertical];
|
|
421
507
|
const edgeBY = aIsTop ? rectB.top : bottomB;
|
|
422
508
|
if (x < rectB.left) {
|
|
423
509
|
connectors.push({ x1: x, y1: edgeBY, x2: rectB.left, y2: edgeBY });
|
|
@@ -426,12 +512,66 @@ const getDistanceOverlay = (rectA, rectB) => {
|
|
|
426
512
|
connectors.push({ x1: x, y1: edgeBY, x2: rightB, y2: edgeBY });
|
|
427
513
|
}
|
|
428
514
|
}
|
|
515
|
+
if (!separatedX && !separatedY) {
|
|
516
|
+
const nestedRects = getNestedRects(rectA, rectB, relation);
|
|
517
|
+
if (nestedRects) {
|
|
518
|
+
const { inner, outer } = nestedRects;
|
|
519
|
+
const innerRight = inner.left + inner.width;
|
|
520
|
+
const innerBottom = inner.top + inner.height;
|
|
521
|
+
const outerRight = outer.left + outer.width;
|
|
522
|
+
const outerBottom = outer.top + outer.height;
|
|
523
|
+
const horizontalY = inner.top + inner.height / 2;
|
|
524
|
+
const verticalX = inner.left + inner.width / 2;
|
|
525
|
+
const startHorizontal = {
|
|
526
|
+
x1: outer.left,
|
|
527
|
+
x2: inner.left,
|
|
528
|
+
y: horizontalY,
|
|
529
|
+
value: inner.left - outer.left,
|
|
530
|
+
};
|
|
531
|
+
const endHorizontal = {
|
|
532
|
+
x1: innerRight,
|
|
533
|
+
x2: outerRight,
|
|
534
|
+
y: horizontalY,
|
|
535
|
+
value: outerRight - innerRight,
|
|
536
|
+
};
|
|
537
|
+
const startVertical = {
|
|
538
|
+
y1: outer.top,
|
|
539
|
+
y2: inner.top,
|
|
540
|
+
x: verticalX,
|
|
541
|
+
value: inner.top - outer.top,
|
|
542
|
+
};
|
|
543
|
+
const endVertical = {
|
|
544
|
+
y1: innerBottom,
|
|
545
|
+
y2: outerBottom,
|
|
546
|
+
x: verticalX,
|
|
547
|
+
value: outerBottom - innerBottom,
|
|
548
|
+
};
|
|
549
|
+
horizontalDistances = [startHorizontal, endHorizontal].filter(({ value }) => value > 0.5);
|
|
550
|
+
verticalDistances = [startVertical, endVertical].filter(({ value }) => value > 0.5);
|
|
551
|
+
const horizontalBoundary = nearestPositiveBoundary(startHorizontal.value, endHorizontal.value);
|
|
552
|
+
const verticalBoundary = nearestPositiveBoundary(startVertical.value, endVertical.value);
|
|
553
|
+
if (horizontalBoundary === 'start') {
|
|
554
|
+
horizontal = startHorizontal;
|
|
555
|
+
}
|
|
556
|
+
else if (horizontalBoundary === 'end') {
|
|
557
|
+
horizontal = endHorizontal;
|
|
558
|
+
}
|
|
559
|
+
if (verticalBoundary === 'start') {
|
|
560
|
+
vertical = startVertical;
|
|
561
|
+
}
|
|
562
|
+
else if (verticalBoundary === 'end') {
|
|
563
|
+
vertical = endVertical;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
429
567
|
const viewport = getViewportSize();
|
|
430
568
|
return {
|
|
431
569
|
rectA,
|
|
432
570
|
rectB,
|
|
433
571
|
horizontal,
|
|
434
572
|
vertical,
|
|
573
|
+
horizontalDistances,
|
|
574
|
+
verticalDistances,
|
|
435
575
|
connectors: connectors
|
|
436
576
|
.map((segment) => ({
|
|
437
577
|
x1: clamp(segment.x1, 0, viewport.width),
|
|
@@ -443,6 +583,30 @@ const getDistanceOverlay = (rectA, rectB) => {
|
|
|
443
583
|
Math.abs(segment.y1 - segment.y2) > 0.5),
|
|
444
584
|
};
|
|
445
585
|
};
|
|
586
|
+
const getNestedRects = (rectA, rectB, relation) => {
|
|
587
|
+
if (relation === 'a-inside-b')
|
|
588
|
+
return { inner: rectA, outer: rectB };
|
|
589
|
+
if (relation === 'b-inside-a')
|
|
590
|
+
return { inner: rectB, outer: rectA };
|
|
591
|
+
if (containsRect(rectA, rectB))
|
|
592
|
+
return { inner: rectB, outer: rectA };
|
|
593
|
+
if (containsRect(rectB, rectA))
|
|
594
|
+
return { inner: rectA, outer: rectB };
|
|
595
|
+
return null;
|
|
596
|
+
};
|
|
597
|
+
const containsRect = (outer, inner) => inner.left >= outer.left &&
|
|
598
|
+
inner.top >= outer.top &&
|
|
599
|
+
inner.left + inner.width <= outer.left + outer.width &&
|
|
600
|
+
inner.top + inner.height <= outer.top + outer.height;
|
|
601
|
+
const nearestPositiveBoundary = (startDistance, endDistance) => {
|
|
602
|
+
const startIsPositive = startDistance > 0.5;
|
|
603
|
+
const endIsPositive = endDistance > 0.5;
|
|
604
|
+
if (!startIsPositive)
|
|
605
|
+
return endIsPositive ? 'end' : null;
|
|
606
|
+
if (!endIsPositive)
|
|
607
|
+
return 'start';
|
|
608
|
+
return startDistance <= endDistance ? 'start' : 'end';
|
|
609
|
+
};
|
|
446
610
|
|
|
447
611
|
const getRectFromDom = (element) => {
|
|
448
612
|
const rect = element.getBoundingClientRect();
|
|
@@ -771,11 +935,11 @@ const GENERATED_EXTRA_PET_SPRITES = {
|
|
|
771
935
|
|
|
772
936
|
const INSPECTOR_COMMAND_ACTIONS = [
|
|
773
937
|
{ id: 'save', label: 'Save', ariaLabel: 'Save checkpoint', keywords: 'save checkpoint capture state' },
|
|
774
|
-
{ id: '
|
|
938
|
+
{ id: 'import', label: 'Paste', ariaLabel: 'Import checkpoint from clipboard', keywords: 'import paste load open json checkpoint restore clipboard' },
|
|
775
939
|
{ id: 'type', label: 'Type', ariaLabel: 'Toggle typography overlay', keywords: 'type typography text overlay' },
|
|
776
940
|
{ id: 'vertical', label: 'V', ariaLabel: 'Vertical guides', keywords: 'vertical v guide guides' },
|
|
777
941
|
{ id: 'horizontal', label: 'H', ariaLabel: 'Horizontal guides', keywords: 'horizontal h guide guides' },
|
|
778
|
-
{ id: '
|
|
942
|
+
{ id: 'select', label: 'Inspect', ariaLabel: 'Inspect mode', keywords: 'inspect select pointer element alt i' },
|
|
779
943
|
];
|
|
780
944
|
const INSPECTOR_PETS = [
|
|
781
945
|
{
|
|
@@ -925,6 +1089,7 @@ class inspectorComponent {
|
|
|
925
1089
|
this.overlayRoot = viewChild('overlayRoot');
|
|
926
1090
|
this.checkpointDialog = viewChild('checkpointDialog');
|
|
927
1091
|
this.checkpointSearch = viewChild('checkpointSearch');
|
|
1092
|
+
this.checkpointRename = viewChild('checkpointRename');
|
|
928
1093
|
this.highlightColor = '#4f8cff';
|
|
929
1094
|
this.guideColor = '#ff7a00';
|
|
930
1095
|
this.hoverHighlightEnabled = true;
|
|
@@ -949,12 +1114,17 @@ class inspectorComponent {
|
|
|
949
1114
|
return terms.every((term) => searchableText.includes(term));
|
|
950
1115
|
});
|
|
951
1116
|
});
|
|
952
|
-
this.
|
|
1117
|
+
this.navigateTarget = computed(() => this.checkpointService?.resolveRoute(this.checkpointQuery()) ?? null);
|
|
1118
|
+
this.actionIndexOffset = computed(() => this.filteredCheckpoints().length + (this.navigateTarget() ? 1 : 0));
|
|
1119
|
+
this.commandResultCount = computed(() => this.actionIndexOffset() + this.filteredInspectorActions().length);
|
|
953
1120
|
this.activeCommandResultId = computed(() => {
|
|
954
1121
|
const checkpoint = this.filteredCheckpoints()[this.activeCommandIndex()];
|
|
955
1122
|
if (checkpoint)
|
|
956
1123
|
return `inspector-checkpoint-${checkpoint.id}`;
|
|
957
|
-
|
|
1124
|
+
if (this.navigateTarget() && this.activeCommandIndex() === this.filteredCheckpoints().length) {
|
|
1125
|
+
return 'inspector-navigate';
|
|
1126
|
+
}
|
|
1127
|
+
const actionIndex = this.activeCommandIndex() - this.actionIndexOffset();
|
|
958
1128
|
const action = this.filteredInspectorActions()[actionIndex];
|
|
959
1129
|
return action ? `inspector-action-${action.id}` : null;
|
|
960
1130
|
});
|
|
@@ -962,6 +1132,29 @@ class inspectorComponent {
|
|
|
962
1132
|
this.toolMode = signal('none');
|
|
963
1133
|
this.guideOrientation = signal('vertical');
|
|
964
1134
|
this.guides = signal([]);
|
|
1135
|
+
this.guideDistances = computed(() => {
|
|
1136
|
+
const distances = [];
|
|
1137
|
+
const preview = this.guidePreview();
|
|
1138
|
+
const visibleGuides = preview
|
|
1139
|
+
? [...this.guides(), preview]
|
|
1140
|
+
: this.guides();
|
|
1141
|
+
for (const orientation of ['vertical', 'horizontal']) {
|
|
1142
|
+
const positions = visibleGuides
|
|
1143
|
+
.filter((guide) => guide.orientation === orientation)
|
|
1144
|
+
.map((guide) => guide.position)
|
|
1145
|
+
.filter((position, index, allPositions) => allPositions.indexOf(position) === index)
|
|
1146
|
+
.sort((positionA, positionB) => positionA - positionB);
|
|
1147
|
+
for (let index = 1; index < positions.length; index += 1) {
|
|
1148
|
+
const start = positions[index - 1];
|
|
1149
|
+
const end = positions[index];
|
|
1150
|
+
const value = end - start;
|
|
1151
|
+
if (value > 0.5) {
|
|
1152
|
+
distances.push({ orientation, start, end, value });
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
return distances;
|
|
1157
|
+
});
|
|
965
1158
|
this.hoverRect = signal(null);
|
|
966
1159
|
this.selectedGuideId = signal(null);
|
|
967
1160
|
this.selectedMeasurement = signal(null);
|
|
@@ -990,11 +1183,19 @@ class inspectorComponent {
|
|
|
990
1183
|
this.draggingGuideId = null;
|
|
991
1184
|
this.selectedElement = null;
|
|
992
1185
|
this.hoverElement = null;
|
|
1186
|
+
this.hasSelectedPet = false;
|
|
993
1187
|
this.toastTimer = null;
|
|
994
1188
|
this.trackGuide = (_index, guide) => guide.id;
|
|
995
1189
|
this.trackTextBlock = (_index, block) => block.id;
|
|
996
1190
|
this.trackConnector = (_index, connector) => `${connector.x1}:${connector.y1}:${connector.x2}:${connector.y2}`;
|
|
997
1191
|
this.isBrowser = isPlatformBrowser(platformId);
|
|
1192
|
+
effect(() => {
|
|
1193
|
+
if (!this.editingCheckpointId())
|
|
1194
|
+
return;
|
|
1195
|
+
const input = this.checkpointRename()?.nativeElement;
|
|
1196
|
+
input?.focus();
|
|
1197
|
+
input?.select();
|
|
1198
|
+
});
|
|
998
1199
|
}
|
|
999
1200
|
ngOnInit() {
|
|
1000
1201
|
if (!this.isBrowser)
|
|
@@ -1050,9 +1251,57 @@ class inspectorComponent {
|
|
|
1050
1251
|
this.showCheckpointToast(this.checkpointService.error(), true);
|
|
1051
1252
|
}
|
|
1052
1253
|
}
|
|
1254
|
+
downloadCheckpoint(checkpoint, event) {
|
|
1255
|
+
event?.stopPropagation();
|
|
1256
|
+
if (!this.isBrowser)
|
|
1257
|
+
return;
|
|
1258
|
+
const blob = new Blob([JSON.stringify(checkpoint, null, 2)], { type: 'application/json' });
|
|
1259
|
+
const url = URL.createObjectURL(blob);
|
|
1260
|
+
const anchor = document.createElement('a');
|
|
1261
|
+
anchor.href = url;
|
|
1262
|
+
anchor.download = this.checkpointFileName(checkpoint);
|
|
1263
|
+
document.body.appendChild(anchor);
|
|
1264
|
+
anchor.click();
|
|
1265
|
+
anchor.remove();
|
|
1266
|
+
URL.revokeObjectURL(url);
|
|
1267
|
+
this.showCheckpointToast(`Exported “${checkpoint.name}”.`);
|
|
1268
|
+
}
|
|
1269
|
+
async beginImport() {
|
|
1270
|
+
if (!this.checkpointService || this.checkpointService.busy())
|
|
1271
|
+
return;
|
|
1272
|
+
let text;
|
|
1273
|
+
try {
|
|
1274
|
+
text = await navigator.clipboard.readText();
|
|
1275
|
+
}
|
|
1276
|
+
catch {
|
|
1277
|
+
this.showCheckpointToast('Could not read clipboard.', true);
|
|
1278
|
+
return;
|
|
1279
|
+
}
|
|
1280
|
+
let parsed;
|
|
1281
|
+
try {
|
|
1282
|
+
parsed = JSON.parse(text);
|
|
1283
|
+
}
|
|
1284
|
+
catch {
|
|
1285
|
+
this.showCheckpointToast('The clipboard does not contain valid JSON.', true);
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
const checkpoint = await this.checkpointService.importCheckpoint(parsed);
|
|
1289
|
+
if (checkpoint) {
|
|
1290
|
+
this.showCheckpointToast(`Imported “${checkpoint.name}”.`);
|
|
1291
|
+
if (this.commandBarOpen()) {
|
|
1292
|
+
const index = this.filteredInspectorActions().findIndex(({ id }) => id === 'import');
|
|
1293
|
+
if (index >= 0)
|
|
1294
|
+
this.setActiveInspectorAction(index);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
else if (this.checkpointService.error()) {
|
|
1298
|
+
this.showCheckpointToast(this.checkpointService.error(), true);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1053
1301
|
async openCheckpointCommandBar() {
|
|
1054
1302
|
if (!this.checkpointService || !this.isBrowser || this.commandBarOpen())
|
|
1055
1303
|
return;
|
|
1304
|
+
this.randomizePet();
|
|
1056
1305
|
this.commandBarOpen.set(true);
|
|
1057
1306
|
this.checkpointQuery.set('');
|
|
1058
1307
|
this.activeCommandIndex.set(0);
|
|
@@ -1081,19 +1330,14 @@ class inspectorComponent {
|
|
|
1081
1330
|
}
|
|
1082
1331
|
cyclePet(event) {
|
|
1083
1332
|
event?.stopPropagation();
|
|
1084
|
-
this.
|
|
1333
|
+
this.randomizePet();
|
|
1085
1334
|
this.checkpointSearch()?.nativeElement.focus();
|
|
1086
1335
|
}
|
|
1087
1336
|
setActiveCheckpoint(index) {
|
|
1088
1337
|
this.activeCommandIndex.set(index);
|
|
1089
1338
|
}
|
|
1090
|
-
shouldShowCheckpointRoute(checkpoint) {
|
|
1091
|
-
if (!checkpoint.route.trim())
|
|
1092
|
-
return false;
|
|
1093
|
-
return this.normalizeCheckpointLabel(checkpoint.name) !== this.normalizeCheckpointLabel(checkpoint.route);
|
|
1094
|
-
}
|
|
1095
1339
|
setActiveInspectorAction(index) {
|
|
1096
|
-
this.activeCommandIndex.set(this.
|
|
1340
|
+
this.activeCommandIndex.set(this.actionIndexOffset() + index);
|
|
1097
1341
|
}
|
|
1098
1342
|
async executeInspectorAction(action) {
|
|
1099
1343
|
if (this.checkpointService?.busy())
|
|
@@ -1115,6 +1359,9 @@ class inspectorComponent {
|
|
|
1115
1359
|
this.setActiveInspectorAction(index);
|
|
1116
1360
|
}
|
|
1117
1361
|
break;
|
|
1362
|
+
case 'import':
|
|
1363
|
+
await this.beginImport();
|
|
1364
|
+
break;
|
|
1118
1365
|
case 'vertical':
|
|
1119
1366
|
this.activateGuideOrientation('vertical');
|
|
1120
1367
|
this.closeCheckpointCommandBar();
|
|
@@ -1123,10 +1370,6 @@ class inspectorComponent {
|
|
|
1123
1370
|
this.activateGuideOrientation('horizontal');
|
|
1124
1371
|
this.closeCheckpointCommandBar();
|
|
1125
1372
|
break;
|
|
1126
|
-
case 'off':
|
|
1127
|
-
this.closeCheckpointCommandBar();
|
|
1128
|
-
this.disableInspector();
|
|
1129
|
-
break;
|
|
1130
1373
|
}
|
|
1131
1374
|
}
|
|
1132
1375
|
async restoreCheckpoint(checkpoint) {
|
|
@@ -1139,6 +1382,37 @@ class inspectorComponent {
|
|
|
1139
1382
|
this.commandBarOpen.set(false);
|
|
1140
1383
|
this.showCheckpointToast(`Restored “${checkpoint.name}”.`);
|
|
1141
1384
|
}
|
|
1385
|
+
activateCheckpoint(checkpoint, event) {
|
|
1386
|
+
if (this.deletingCheckpointId() === checkpoint.id ||
|
|
1387
|
+
this.editingCheckpointId() === checkpoint.id) {
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
if (event?.shiftKey) {
|
|
1391
|
+
void this.navigateToCheckpoint(checkpoint);
|
|
1392
|
+
}
|
|
1393
|
+
else {
|
|
1394
|
+
void this.restoreCheckpoint(checkpoint);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
async navigateToCheckpoint(checkpoint) {
|
|
1398
|
+
if (!this.checkpointService || this.checkpointService.busy())
|
|
1399
|
+
return;
|
|
1400
|
+
if (!await this.checkpointService.navigateToRoute(checkpoint.route))
|
|
1401
|
+
return;
|
|
1402
|
+
this.checkpointDialog()?.nativeElement.close();
|
|
1403
|
+
this.commandBarOpen.set(false);
|
|
1404
|
+
this.showCheckpointToast(`Navigated to “${checkpoint.route}” — state unchanged.`);
|
|
1405
|
+
}
|
|
1406
|
+
async navigateToQueryRoute() {
|
|
1407
|
+
const target = this.navigateTarget();
|
|
1408
|
+
if (!this.checkpointService || !target || this.checkpointService.busy())
|
|
1409
|
+
return;
|
|
1410
|
+
if (!await this.checkpointService.navigateToRoute(target))
|
|
1411
|
+
return;
|
|
1412
|
+
this.checkpointDialog()?.nativeElement.close();
|
|
1413
|
+
this.commandBarOpen.set(false);
|
|
1414
|
+
this.showCheckpointToast(`Navigated to “${target}” — state unchanged.`);
|
|
1415
|
+
}
|
|
1142
1416
|
beginRename(checkpoint, event) {
|
|
1143
1417
|
event?.stopPropagation();
|
|
1144
1418
|
if (this.checkpointService?.busy())
|
|
@@ -1146,11 +1420,6 @@ class inspectorComponent {
|
|
|
1146
1420
|
this.editingCheckpointId.set(checkpoint.id);
|
|
1147
1421
|
this.deletingCheckpointId.set(null);
|
|
1148
1422
|
this.renameDraft.set(checkpoint.name);
|
|
1149
|
-
queueMicrotask(() => {
|
|
1150
|
-
const input = this.checkpointDialog()?.nativeElement.querySelector('.inspector-command-row__rename');
|
|
1151
|
-
input?.focus();
|
|
1152
|
-
input?.select();
|
|
1153
|
-
});
|
|
1154
1423
|
}
|
|
1155
1424
|
updateRenameDraft(event) {
|
|
1156
1425
|
this.renameDraft.set(event.target.value);
|
|
@@ -1205,7 +1474,17 @@ class inspectorComponent {
|
|
|
1205
1474
|
this.selectedGuideId.set(guide.id);
|
|
1206
1475
|
}
|
|
1207
1476
|
formatEdges(edges) {
|
|
1208
|
-
|
|
1477
|
+
const top = String(formatValue(edges.top));
|
|
1478
|
+
const right = String(formatValue(edges.right));
|
|
1479
|
+
const bottom = String(formatValue(edges.bottom));
|
|
1480
|
+
const left = String(formatValue(edges.left));
|
|
1481
|
+
if (top === right && top === bottom && top === left)
|
|
1482
|
+
return top;
|
|
1483
|
+
if (top === bottom && right === left)
|
|
1484
|
+
return `${top} ${right}`;
|
|
1485
|
+
if (right === left)
|
|
1486
|
+
return `${top} ${right} ${bottom}`;
|
|
1487
|
+
return `${top} ${right} ${bottom} ${left}`;
|
|
1209
1488
|
}
|
|
1210
1489
|
formatGap(selected) {
|
|
1211
1490
|
return `${formatValue(selected.gap.row)} / ${formatValue(selected.gap.column)}`;
|
|
@@ -1214,13 +1493,38 @@ class inspectorComponent {
|
|
|
1214
1493
|
const key = event.key.toLowerCase();
|
|
1215
1494
|
if (this.checkpointService &&
|
|
1216
1495
|
!event.repeat &&
|
|
1217
|
-
|
|
1218
|
-
event.
|
|
1496
|
+
event.altKey &&
|
|
1497
|
+
!event.ctrlKey &&
|
|
1498
|
+
!event.metaKey &&
|
|
1499
|
+
!event.shiftKey &&
|
|
1219
1500
|
key === 'p') {
|
|
1220
1501
|
event.preventDefault();
|
|
1221
1502
|
this.commandBarOpen() ? this.closeCheckpointCommandBar() : void this.openCheckpointCommandBar();
|
|
1222
1503
|
return;
|
|
1223
1504
|
}
|
|
1505
|
+
if (!event.repeat &&
|
|
1506
|
+
event.altKey &&
|
|
1507
|
+
!event.ctrlKey &&
|
|
1508
|
+
!event.metaKey &&
|
|
1509
|
+
!event.shiftKey &&
|
|
1510
|
+
key === 'i') {
|
|
1511
|
+
event.preventDefault();
|
|
1512
|
+
this.setToolMode('select');
|
|
1513
|
+
if (this.commandBarOpen())
|
|
1514
|
+
this.closeCheckpointCommandBar();
|
|
1515
|
+
return;
|
|
1516
|
+
}
|
|
1517
|
+
if (this.checkpointService &&
|
|
1518
|
+
!event.repeat &&
|
|
1519
|
+
event.altKey &&
|
|
1520
|
+
!event.ctrlKey &&
|
|
1521
|
+
!event.metaKey &&
|
|
1522
|
+
!event.shiftKey &&
|
|
1523
|
+
key === 's') {
|
|
1524
|
+
event.preventDefault();
|
|
1525
|
+
void this.saveCheckpoint();
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1224
1528
|
if (this.commandBarOpen()) {
|
|
1225
1529
|
this.handleCommandBarKeydown(event, key);
|
|
1226
1530
|
return;
|
|
@@ -1266,12 +1570,6 @@ class inspectorComponent {
|
|
|
1266
1570
|
this.clearGuides();
|
|
1267
1571
|
this.refreshTypographyBlocks();
|
|
1268
1572
|
}
|
|
1269
|
-
normalizeCheckpointLabel(value) {
|
|
1270
|
-
return value
|
|
1271
|
-
.trim()
|
|
1272
|
-
.toLocaleLowerCase()
|
|
1273
|
-
.replace(/^\/+|\/+$/g, '');
|
|
1274
|
-
}
|
|
1275
1573
|
handlePointerMove(event) {
|
|
1276
1574
|
if (!this.enabled() || !this.isBrowser) {
|
|
1277
1575
|
return;
|
|
@@ -1382,8 +1680,12 @@ class inspectorComponent {
|
|
|
1382
1680
|
handleCommandBarKeydown(event, key) {
|
|
1383
1681
|
const checkpoints = this.filteredCheckpoints();
|
|
1384
1682
|
const actions = this.filteredInspectorActions();
|
|
1683
|
+
const navigateIndex = checkpoints.length;
|
|
1684
|
+
const hasNavigateRow = this.navigateTarget() !== null;
|
|
1385
1685
|
const activeCheckpoint = checkpoints[this.activeCommandIndex()];
|
|
1386
|
-
const
|
|
1686
|
+
const activeNavigateRow = hasNavigateRow && this.activeCommandIndex() === navigateIndex;
|
|
1687
|
+
const actionOffset = navigateIndex + (hasNavigateRow ? 1 : 0);
|
|
1688
|
+
const activeActionIndex = this.activeCommandIndex() - actionOffset;
|
|
1387
1689
|
const activeAction = actions[activeActionIndex];
|
|
1388
1690
|
const target = event.target;
|
|
1389
1691
|
const isRenameInput = target?.classList?.contains('inspector-command-row__rename') ?? false;
|
|
@@ -1407,14 +1709,32 @@ class inspectorComponent {
|
|
|
1407
1709
|
}
|
|
1408
1710
|
if (isRenameInput)
|
|
1409
1711
|
return;
|
|
1712
|
+
if (key === 'f2' && activeCheckpoint) {
|
|
1713
|
+
event.preventDefault();
|
|
1714
|
+
this.beginRename(activeCheckpoint);
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
if (key === 'delete' && activeCheckpoint) {
|
|
1718
|
+
event.preventDefault();
|
|
1719
|
+
void this.confirmDelete(activeCheckpoint);
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1410
1722
|
if (key === 'arrowdown') {
|
|
1411
1723
|
event.preventDefault();
|
|
1412
|
-
if (
|
|
1724
|
+
if (activeAction && checkpoints.length) {
|
|
1725
|
+
this.activeCommandIndex.set(0);
|
|
1726
|
+
}
|
|
1727
|
+
else if (activeCheckpoint) {
|
|
1413
1728
|
const nextIndex = this.activeCommandIndex() < checkpoints.length - 1
|
|
1414
1729
|
? this.activeCommandIndex() + 1
|
|
1415
|
-
:
|
|
1730
|
+
: hasNavigateRow
|
|
1731
|
+
? navigateIndex
|
|
1732
|
+
: actions.length ? actionOffset : this.activeCommandIndex();
|
|
1416
1733
|
this.activeCommandIndex.set(nextIndex);
|
|
1417
1734
|
}
|
|
1735
|
+
else if (activeNavigateRow && actions.length) {
|
|
1736
|
+
this.activeCommandIndex.set(actionOffset);
|
|
1737
|
+
}
|
|
1418
1738
|
this.scrollActiveCommandIntoView();
|
|
1419
1739
|
return;
|
|
1420
1740
|
}
|
|
@@ -1423,27 +1743,48 @@ class inspectorComponent {
|
|
|
1423
1743
|
if (activeAction && checkpoints.length) {
|
|
1424
1744
|
this.activeCommandIndex.set(checkpoints.length - 1);
|
|
1425
1745
|
}
|
|
1746
|
+
else if (activeNavigateRow && checkpoints.length) {
|
|
1747
|
+
this.activeCommandIndex.set(checkpoints.length - 1);
|
|
1748
|
+
}
|
|
1426
1749
|
else if (activeCheckpoint) {
|
|
1427
|
-
|
|
1750
|
+
const nextIndex = this.activeCommandIndex() > 0
|
|
1751
|
+
? this.activeCommandIndex() - 1
|
|
1752
|
+
: actions.length
|
|
1753
|
+
? actionOffset + actions.length - 1
|
|
1754
|
+
: hasNavigateRow ? navigateIndex : 0;
|
|
1755
|
+
this.activeCommandIndex.set(nextIndex);
|
|
1428
1756
|
}
|
|
1429
1757
|
this.scrollActiveCommandIntoView();
|
|
1430
1758
|
return;
|
|
1431
1759
|
}
|
|
1432
|
-
if (key === 'arrowright' && (activeCheckpoint || activeAction) && actions.length) {
|
|
1760
|
+
if (key === 'arrowright' && (activeCheckpoint || activeNavigateRow || activeAction) && actions.length) {
|
|
1433
1761
|
event.preventDefault();
|
|
1434
1762
|
const nextActionIndex = activeAction
|
|
1435
1763
|
? Math.min(activeActionIndex + 1, actions.length - 1)
|
|
1436
1764
|
: 0;
|
|
1437
|
-
this.activeCommandIndex.set(
|
|
1765
|
+
this.activeCommandIndex.set(actionOffset + nextActionIndex);
|
|
1438
1766
|
this.scrollActiveCommandIntoView();
|
|
1439
1767
|
return;
|
|
1440
1768
|
}
|
|
1441
|
-
if (key === 'arrowleft' && activeAction) {
|
|
1769
|
+
if (key === 'arrowleft' && (activeCheckpoint || activeNavigateRow || activeAction) && actions.length) {
|
|
1442
1770
|
event.preventDefault();
|
|
1443
|
-
|
|
1771
|
+
const nextActionIndex = activeAction
|
|
1772
|
+
? (activeActionIndex - 1 + actions.length) % actions.length
|
|
1773
|
+
: actions.length - 1;
|
|
1774
|
+
this.activeCommandIndex.set(actionOffset + nextActionIndex);
|
|
1444
1775
|
this.scrollActiveCommandIntoView();
|
|
1445
1776
|
return;
|
|
1446
1777
|
}
|
|
1778
|
+
if (key === 'enter' && event.shiftKey && activeCheckpoint && !this.deletingCheckpointId()) {
|
|
1779
|
+
event.preventDefault();
|
|
1780
|
+
void this.navigateToCheckpoint(activeCheckpoint);
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
if (key === 'enter' && activeNavigateRow) {
|
|
1784
|
+
event.preventDefault();
|
|
1785
|
+
void this.navigateToQueryRoute();
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1447
1788
|
if (key === 'enter' && activeCheckpoint && !this.deletingCheckpointId()) {
|
|
1448
1789
|
event.preventDefault();
|
|
1449
1790
|
void this.restoreCheckpoint(activeCheckpoint);
|
|
@@ -1474,6 +1815,13 @@ class inspectorComponent {
|
|
|
1474
1815
|
this.checkpointToastIsError.set(false);
|
|
1475
1816
|
}, 2500);
|
|
1476
1817
|
}
|
|
1818
|
+
checkpointFileName(checkpoint) {
|
|
1819
|
+
const safe = checkpoint.name
|
|
1820
|
+
.replace(/[\\/:*?"<>|]/g, '-')
|
|
1821
|
+
.replace(/^-+|-+$/g, '')
|
|
1822
|
+
.trim();
|
|
1823
|
+
return `${safe || 'checkpoint'}.json`;
|
|
1824
|
+
}
|
|
1477
1825
|
selectElementAtPoint(event) {
|
|
1478
1826
|
const overlay = this.overlayRoot()?.nativeElement ?? null;
|
|
1479
1827
|
const target = getTargetElement({ x: event.clientX, y: event.clientY }, overlay);
|
|
@@ -1508,13 +1856,19 @@ class inspectorComponent {
|
|
|
1508
1856
|
if (!this.altPressed() ||
|
|
1509
1857
|
!this.selectedElement ||
|
|
1510
1858
|
!this.hoverElement ||
|
|
1511
|
-
this.selectedElement === this.hoverElement
|
|
1512
|
-
this.selectedElement.contains(this.hoverElement) ||
|
|
1513
|
-
this.hoverElement.contains(this.selectedElement)) {
|
|
1859
|
+
this.selectedElement === this.hoverElement) {
|
|
1514
1860
|
this.distanceOverlay.set(null);
|
|
1515
1861
|
return;
|
|
1516
1862
|
}
|
|
1517
|
-
this.
|
|
1863
|
+
const relation = this.getDistanceRelation(this.selectedElement, this.hoverElement);
|
|
1864
|
+
this.distanceOverlay.set(getDistanceOverlay(getRectFromDom(this.selectedElement), getRectFromDom(this.hoverElement), relation));
|
|
1865
|
+
}
|
|
1866
|
+
getDistanceRelation(elementA, elementB) {
|
|
1867
|
+
if (elementB.contains(elementA))
|
|
1868
|
+
return 'a-inside-b';
|
|
1869
|
+
if (elementA.contains(elementB))
|
|
1870
|
+
return 'b-inside-a';
|
|
1871
|
+
return undefined;
|
|
1518
1872
|
}
|
|
1519
1873
|
refreshTypographyBlocks() {
|
|
1520
1874
|
if (!this.isBrowser || !this.enabled() || !this.showTypography()) {
|
|
@@ -1536,6 +1890,17 @@ class inspectorComponent {
|
|
|
1536
1890
|
},
|
|
1537
1891
|
})));
|
|
1538
1892
|
}
|
|
1893
|
+
randomizePet() {
|
|
1894
|
+
const currentIndex = this.hasSelectedPet ? this.petIndex() : null;
|
|
1895
|
+
const availableCount = currentIndex === null
|
|
1896
|
+
? INSPECTOR_PETS.length
|
|
1897
|
+
: INSPECTOR_PETS.length - 1;
|
|
1898
|
+
const randomOffset = Math.floor(Math.random() * availableCount);
|
|
1899
|
+
this.petIndex.set(currentIndex === null
|
|
1900
|
+
? randomOffset
|
|
1901
|
+
: (currentIndex + 1 + randomOffset) % INSPECTOR_PETS.length);
|
|
1902
|
+
this.hasSelectedPet = true;
|
|
1903
|
+
}
|
|
1539
1904
|
addGuide(guide) {
|
|
1540
1905
|
const nextGuides = [...this.guides(), guide];
|
|
1541
1906
|
this.guides.set(nextGuides);
|
|
@@ -1592,11 +1957,11 @@ class inspectorComponent {
|
|
|
1592
1957
|
return null;
|
|
1593
1958
|
}
|
|
1594
1959
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: inspectorComponent, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1595
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: inspectorComponent, isStandalone: true, selector: "inspector-overlay", inputs: { highlightColor: "highlightColor", guideColor: "guideColor", hoverHighlightEnabled: "hoverHighlightEnabled" }, host: { listeners: { "window:keydown": "handleKeydown($event)", "window:keyup": "handleKeyup($event)", "window:pointermove": "handlePointerMove($event)", "window:pointerup": "handlePointerUp()", "window:click": "handleClick($event)", "window:resize": "handleViewportChange()", "window:scroll": "handleViewportChange()" } }, viewQueries: [{ propertyName: "overlayRoot", first: true, predicate: ["overlayRoot"], descendants: true, isSignal: true }, { propertyName: "checkpointDialog", first: true, predicate: ["checkpointDialog"], descendants: true, isSignal: true }, { propertyName: "checkpointSearch", first: true, predicate: ["checkpointSearch"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"inspector-root\" #overlayRoot>\n @if (checkpointService) {\n <dialog\n #checkpointDialog\n class=\"inspector-command-dialog\"\n aria-labelledby=\"inspector-command-title\"\n (cancel)=\"$event.preventDefault(); closeCheckpointCommandBar()\"\n (click)=\"handleCheckpointDialogClick($event)\"\n >\n <section class=\"inspector-command\" (click)=\"$event.stopPropagation()\">\n <header class=\"inspector-command__search\">\n <label\n id=\"inspector-command-title\"\n class=\"inspector-visually-hidden\"\n for=\"inspector-checkpoint-search\"\n >\n inspector-ng command palette\n </label>\n <button\n type=\"button\"\n class=\"inspector-command__pet-switcher\"\n [attr.aria-label]=\"'Change pet. Current pet: ' + activePet().name\"\n [title]=\"'Change pet: ' + activePet().name\"\n (click)=\"cyclePet($event)\"\n >\n <img\n class=\"inspector-command__pet-sprite\"\n [src]=\"activePet().spriteSrc\"\n alt=\"\"\n aria-hidden=\"true\"\n draggable=\"false\"\n />\n </button>\n <input\n #checkpointSearch\n id=\"inspector-checkpoint-search\"\n type=\"search\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n placeholder=\"inspector-ng\u2026\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"commandBarOpen()\"\n [value]=\"checkpointQuery()\"\n [attr.aria-controls]=\"'inspector-checkpoint-results inspector-command-actions'\"\n [attr.aria-activedescendant]=\"activeCommandResultId()\"\n (input)=\"updateCheckpointQuery($event)\"\n />\n </header>\n\n @if (checkpointService.error(); as error) {\n <p\n class=\"inspector-command__message inspector-command__message--error\"\n role=\"alert\"\n >\n {{ error }}\n </p>\n }\n\n <div\n id=\"inspector-checkpoint-results\"\n class=\"inspector-command__results\"\n role=\"listbox\"\n aria-label=\"Saved checkpoints\"\n >\n @if (checkpointService.loading()) {\n <p class=\"inspector-command__message\" role=\"status\">Loading\u2026</p>\n } @else if (\n !checkpointService.checkpoints().length && !checkpointQuery().trim()\n ) {\n <p class=\"inspector-command__message\" role=\"status\">\n No checkpoints yet\n </p>\n } @else if (\n !filteredCheckpoints().length && !filteredInspectorActions().length\n ) {\n <p class=\"inspector-command__message\" role=\"status\">No matches</p>\n } @else {\n @for (\n checkpoint of filteredCheckpoints();\n track checkpoint.id;\n let index = $index\n ) {\n <div\n class=\"inspector-command-row\"\n role=\"option\"\n [id]=\"'inspector-checkpoint-' + checkpoint.id\"\n [attr.data-command-index]=\"index\"\n [attr.aria-selected]=\"activeCommandIndex() === index\"\n [class.is-active]=\"activeCommandIndex() === index\"\n [class.is-busy]=\"\n checkpointService.busy() && activeCommandIndex() === index\n \"\n (mouseenter)=\"setActiveCheckpoint(index)\"\n (click)=\"\n deletingCheckpointId() === checkpoint.id ||\n editingCheckpointId() === checkpoint.id\n ? null\n : restoreCheckpoint(checkpoint)\n \"\n >\n @if (deletingCheckpointId() === checkpoint.id) {\n <span class=\"inspector-command-row__confirm\"\n >Delete \u201C{{ checkpoint.name }}\u201D?</span\n >\n <span class=\"inspector-command-row__confirm-actions\">\n <button\n type=\"button\"\n class=\"is-danger\"\n (click)=\"confirmDelete(checkpoint, $event)\"\n >\n Delete\n </button>\n <button type=\"button\" (click)=\"cancelDelete($event)\">\n Keep\n </button>\n </span>\n } @else if (editingCheckpointId() === checkpoint.id) {\n <input\n class=\"inspector-command-row__rename\"\n aria-label=\"Checkpoint name\"\n [value]=\"renameDraft()\"\n (input)=\"updateRenameDraft($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n } @else {\n <span class=\"inspector-command-row__content\">\n <span class=\"inspector-command-row__name\">\n @if (\n checkpointService.busy() &&\n activeCommandIndex() === index\n ) {\n Restoring\u2026\n } @else {\n {{ checkpoint.name }}\n }\n </span>\n <span class=\"inspector-command-row__meta\">\n @if (shouldShowCheckpointRoute(checkpoint)) {\n <span class=\"inspector-command-row__route\">{{\n checkpoint.route\n }}</span>\n <span\n class=\"inspector-command-row__separator\"\n aria-hidden=\"true\"\n >\u00B7</span\n >\n }\n <span class=\"inspector-command-row__activity\">\n {{ checkpoint.lastUsedAt ? \"Used\" : \"Saved\" }}\n {{\n formatRelativeTime(checkpointActivityAt(checkpoint))\n }}\n </span>\n </span>\n </span>\n <span class=\"inspector-command-row__actions\">\n <button\n type=\"button\"\n (click)=\"beginRename(checkpoint, $event)\"\n [attr.aria-label]=\"'Rename ' + checkpoint.name\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"m11.8 1.8 2.4 2.4-8.3 8.3-3.1.7.7-3.1zm-8 10.4 1.5-.3-1.2-1.2z\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n (click)=\"beginDelete(checkpoint, $event)\"\n [attr.aria-label]=\"'Delete ' + checkpoint.name\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M5.5 2h5l.5 1H14v1.25H2V3h3zm-2 3.25h9L12 14H4z\"\n />\n </svg>\n </button>\n </span>\n }\n </div>\n }\n }\n </div>\n\n @if (filteredInspectorActions().length) {\n <footer\n id=\"inspector-command-actions\"\n class=\"inspector-command__actions\"\n role=\"listbox\"\n aria-label=\"Inspector actions\"\n aria-orientation=\"horizontal\"\n >\n @for (\n action of filteredInspectorActions();\n track action.id;\n let index = $index\n ) {\n <button\n type=\"button\"\n role=\"option\"\n class=\"inspector-command-action\"\n [id]=\"'inspector-action-' + action.id\"\n [attr.data-command-index]=\"filteredCheckpoints().length + index\"\n [attr.aria-label]=\"action.ariaLabel\"\n [attr.aria-selected]=\"\n activeCommandIndex() === filteredCheckpoints().length + index\n \"\n [attr.aria-disabled]=\"checkpointService.busy()\"\n [class.is-selected]=\"\n activeCommandIndex() === filteredCheckpoints().length + index\n \"\n [class.is-active]=\"\n (action.id === 'select' && toolMode() === 'select') ||\n (action.id === 'type' && showTypography()) ||\n (action.id === 'vertical' &&\n toolMode() === 'guides' &&\n guideOrientation() === 'vertical') ||\n (action.id === 'horizontal' &&\n toolMode() === 'guides' &&\n guideOrientation() === 'horizontal')\n \"\n [class.inspector-command-action--danger]=\"action.id === 'off'\"\n [disabled]=\"checkpointService.busy()\"\n (mouseenter)=\"setActiveInspectorAction(index)\"\n (click)=\"executeInspectorAction(action)\"\n >\n @switch (action.id) {\n @case (\"select\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 2l8 8-3 .7L6.7 13 6 10 3 2z\" />\n </svg>\n }\n @case (\"type\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 4V2h10v2h-4v10H7V4z\" />\n </svg>\n }\n @case (\"save\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M2.5 2h9.6l1.4 1.4V14h-11zm2 1.5v3h6v-3zm.5 6V12h6V9.5z\"\n />\n </svg>\n }\n @case (\"vertical\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M7.25 2h1.5v12h-1.5z\" />\n </svg>\n }\n @case (\"horizontal\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M2 7.25h12v1.5H2z\" />\n </svg>\n }\n @case (\"off\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M7.25 1.5h1.5v6h-1.5zM4.1 3.35l.96 1.15A4.25 4.25 0 1 0 10.94 4.5l.96-1.15A5.75 5.75 0 1 1 4.1 3.35z\"\n />\n </svg>\n }\n }\n <span>{{ action.label }}</span>\n </button>\n }\n </footer>\n }\n </section>\n </dialog>\n }\n\n @if (checkpointToast(); as toast) {\n <p\n class=\"inspector-checkpoint-toast\"\n [class.inspector-checkpoint-toast--error]=\"checkpointToastIsError()\"\n [attr.role]=\"checkpointToastIsError() ? 'alert' : 'status'\"\n >\n {{ toast }}\n </p>\n }\n\n @if (enabled() && toolMode() === \"select\") {\n @if (hoverRect() && hoverHighlightEnabled) {\n <div\n class=\"inspector-box inspector-box--hover\"\n [style.left.px]=\"hoverRect()!.left\"\n [style.top.px]=\"hoverRect()!.top\"\n [style.width.px]=\"hoverRect()!.width\"\n [style.height.px]=\"hoverRect()!.height\"\n [style.--inspector-accent]=\"highlightColor\"\n ></div>\n }\n\n @if (selectedMeasurement(); as selected) {\n @if (selected.gap.active && selected.parentRect) {\n <div\n class=\"inspector-box inspector-box--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top\"\n [style.width.px]=\"selected.parentRect.width\"\n [style.height.px]=\"selected.parentRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top - 8\"\n >\n G {{ formatGap(selected) }}\n </div>\n }\n\n <div\n class=\"inspector-box inspector-box--margin\"\n [style.left.px]=\"selected.marginRect.left\"\n [style.top.px]=\"selected.marginRect.top\"\n [style.width.px]=\"selected.marginRect.width\"\n [style.height.px]=\"selected.marginRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--margin\"\n [style.left.px]=\"selected.marginRect.left\"\n [style.top.px]=\"selected.marginRect.top - 8\"\n >\n M {{ formatEdges(selected.margin) }}\n </div>\n\n <div\n class=\"inspector-box inspector-box--selected\"\n [style.left.px]=\"selected.rect.left\"\n [style.top.px]=\"selected.rect.top\"\n [style.width.px]=\"selected.rect.width\"\n [style.height.px]=\"selected.rect.height\"\n [style.--inspector-accent]=\"highlightColor\"\n >\n <div class=\"inspector-label\">{{ selectedMetaLine() }}</div>\n </div>\n\n <div\n class=\"inspector-box inspector-box--padding\"\n [style.left.px]=\"selected.paddingRect.left\"\n [style.top.px]=\"selected.paddingRect.top\"\n [style.width.px]=\"selected.paddingRect.width\"\n [style.height.px]=\"selected.paddingRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--padding\"\n [style.left.px]=\"selected.paddingRect.left\"\n [style.top.px]=\"\n selected.paddingRect.top + selected.paddingRect.height + 8\n \"\n >\n P {{ formatEdges(selected.padding) }}\n </div>\n }\n }\n\n @if (enabled() && showTypography()) {\n @for (block of textBlocks(); track block.id) {\n <div\n class=\"inspector-text-chip\"\n [style.left.px]=\"block.rect.left\"\n [style.top.px]=\"block.rect.top - 8\"\n >\n <span\n class=\"inspector-text-chip__swatch\"\n [style.background]=\"block.styles.color\"\n ></span>\n <span>{{ block.styles.fontSize }}</span>\n <span>{{ block.styles.lineHeight }}</span>\n <span>{{ block.styles.color }}</span>\n </div>\n }\n }\n\n @if (enabled() && altPressed() && distanceOverlay(); as distance) {\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectA.left\"\n [style.top.px]=\"distance.rectA.top\"\n [style.width.px]=\"distance.rectA.width\"\n [style.height.px]=\"distance.rectA.height\"\n ></div>\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectB.left\"\n [style.top.px]=\"distance.rectB.top\"\n [style.width.px]=\"distance.rectB.width\"\n [style.height.px]=\"distance.rectB.height\"\n ></div>\n\n @for (\n connector of distance.connectors;\n track trackConnector($index, connector)\n ) {\n <div\n class=\"inspector-connector\"\n [class.inspector-connector--vertical]=\"connector.x1 === connector.x2\"\n [class.inspector-connector--horizontal]=\"connector.y1 === connector.y2\"\n [style.left.px]=\"Math.min(connector.x1, connector.x2)\"\n [style.top.px]=\"Math.min(connector.y1, connector.y2)\"\n [style.width.px]=\"Math.max(1, Math.abs(connector.x2 - connector.x1))\"\n [style.height.px]=\"Math.max(1, Math.abs(connector.y2 - connector.y1))\"\n ></div>\n }\n\n @if (distance.horizontal && distance.horizontal.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--horizontal\"\n [style.left.px]=\"\n Math.min(distance.horizontal.x1!, distance.horizontal.x2!)\n \"\n [style.top.px]=\"distance.horizontal.y!\"\n [style.width.px]=\"\n Math.abs(distance.horizontal.x2! - distance.horizontal.x1!)\n \"\n ></div>\n <div\n class=\"inspector-distance-tag\"\n [style.left.px]=\"\n (distance.horizontal.x1! + distance.horizontal.x2!) / 2\n \"\n [style.top.px]=\"distance.horizontal.y! + 10\"\n >\n {{ formatValue(distance.horizontal.value) }}\n </div>\n }\n\n @if (distance.vertical && distance.vertical.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--vertical\"\n [style.left.px]=\"distance.vertical.x!\"\n [style.top.px]=\"Math.min(distance.vertical.y1!, distance.vertical.y2!)\"\n [style.height.px]=\"\n Math.abs(distance.vertical.y2! - distance.vertical.y1!)\n \"\n ></div>\n <div\n class=\"inspector-distance-tag inspector-distance-tag--vertical\"\n [style.left.px]=\"distance.vertical.x! + 10\"\n [style.top.px]=\"(distance.vertical.y1! + distance.vertical.y2!) / 2\"\n >\n {{ formatValue(distance.vertical.value) }}\n </div>\n }\n }\n\n @if (enabled()) {\n @if (toolMode() === \"guides\") {\n @if (guidePreview(); as preview) {\n <div\n class=\"inspector-guide inspector-guide--preview\"\n [class.inspector-guide--vertical]=\"preview.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"\n preview.orientation === 'horizontal'\n \"\n [style.left.px]=\"\n preview.orientation === 'vertical' ? preview.position : null\n \"\n [style.top.px]=\"\n preview.orientation === 'horizontal' ? preview.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n >\n <span class=\"inspector-guide-line\"></span>\n </div>\n }\n }\n\n @for (guide of guides(); track guide.id) {\n <button\n type=\"button\"\n class=\"inspector-guide\"\n [class.inspector-guide--vertical]=\"guide.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"guide.orientation === 'horizontal'\"\n [class.inspector-guide--selected]=\"selectedGuideId() === guide.id\"\n [style.left.px]=\"\n guide.orientation === 'vertical' ? guide.position : null\n \"\n [style.top.px]=\"\n guide.orientation === 'horizontal' ? guide.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n [attr.aria-label]=\"\n (guide.orientation === 'vertical' ? 'Vertical' : 'Horizontal') +\n ' guide at ' +\n formatValue(guide.position) +\n ' pixels'\n \"\n (pointerdown)=\"startGuideDrag($event, guide)\"\n >\n <span class=\"inspector-guide-line\"></span>\n </button>\n }\n }\n</div>\n", styles: [":host{--inspector-panel: oklch(20% .012 280 / .92);--inspector-panel-edge: oklch(100% 0 0 / .08);--inspector-text: oklch(96% .005 280);--inspector-muted: oklch(70% .014 280);--inspector-faint: oklch(56% .012 280);--inspector-blue: oklch(68% .15 255);--inspector-blue-soft: oklch(68% .15 255 / .14);--inspector-orange: oklch(78% .14 70);--inspector-green: oklch(74% .15 150);--inspector-violet: oklch(72% .15 305);--inspector-radius: 8px;--inspector-shadow: 0 12px 32px oklch(6% .02 280 / .5);--inspector-font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--inspector-ease: cubic-bezier(.16, 1, .3, 1);position:fixed;inset:0;z-index:2147;pointer-events:none;font-family:var(--inspector-font);color:var(--inspector-text);-webkit-font-smoothing:antialiased}.inspector-root{position:fixed;inset:0;pointer-events:none}.inspector-command-dialog{--command-surface: oklch(17.5% .012 280);--command-surface-active: oklch(25% .012 280);--command-edge: oklch(100% 0 0 / .08);--command-text: oklch(96% .005 280);--command-muted: oklch(68% .014 280);--command-faint: oklch(52% .012 280);--command-accent: oklch(72% .13 255);--command-danger: oklch(68% .17 25);box-sizing:border-box;inset-block-start:max(10vh,48px);width:min(420px,calc(100vw - 24px));max-width:none;max-height:min(360px,calc(100vh - 64px));margin:0 auto;padding:0;overflow:hidden;border:1px solid var(--command-edge);border-radius:var(--inspector-radius);background:var(--command-surface);color:var(--command-text);box-shadow:var(--inspector-shadow);opacity:0;pointer-events:auto;transform:translateY(-4px);transition:opacity .1s ease,transform .1s ease,overlay .1s allow-discrete,display .1s allow-discrete;font-family:var(--inspector-font);-webkit-font-smoothing:antialiased}.inspector-command-dialog[open]{opacity:1;transform:none;transition-duration:.14s;transition-timing-function:var(--inspector-ease)}@starting-style{.inspector-command-dialog[open]{opacity:0;transform:translateY(-4px)}}.inspector-command-dialog::backdrop{background:#01010266}.inspector-command{display:grid;grid-template-rows:auto auto 1fr auto;min-width:0;min-height:0;max-height:min(360px,calc(100vh - 64px))}.inspector-command__search{display:flex;align-items:center;gap:8px;min-height:40px;padding:0 11px;border-bottom:1px solid var(--command-edge)}.inspector-command__pet-switcher{display:block;width:28px;height:28px;flex:0 0 auto;padding:0;overflow:hidden;border:0;border-radius:4px;background:transparent;cursor:pointer;opacity:.72;transition:opacity .14s var(--inspector-ease),transform .1s var(--inspector-ease)}.inspector-command__pet-sprite{display:block;width:500%;height:100%;max-width:none;image-rendering:pixelated;-webkit-user-select:none;user-select:none;transform:translate(0)}.inspector-command__search:focus-within .inspector-command__pet-switcher,.inspector-command__pet-switcher:hover,.inspector-command__pet-switcher:focus-visible{opacity:1}.inspector-command__pet-switcher:hover,.inspector-command__pet-switcher:focus-visible{background:#6aa7f41f}.inspector-command__pet-switcher:active{transform:scale(.94)}.inspector-command__pet-switcher:focus-visible{outline:1px solid var(--command-accent);outline-offset:1px}@media (prefers-reduced-motion: no-preference){.inspector-command__search:focus-within .inspector-command__pet-sprite{animation:inspector-pet-cycle 1s steps(1,end) infinite}}@keyframes inspector-pet-cycle{0%,19.99%{transform:translate(0)}20%,39.99%{transform:translate(-20%)}40%,59.99%{transform:translate(-40%)}60%,79.99%{transform:translate(-60%)}80%,to{transform:translate(-80%)}}.inspector-command__search input,.inspector-command-row__rename{min-width:0;border:0;outline:0;background:transparent;color:var(--command-text);font:inherit}.inspector-command__search input{flex:1 1 auto;width:100%;height:39px;padding:0;font-size:13px;font-weight:450;line-height:1.3}.inspector-command__search input::placeholder{color:var(--command-faint);opacity:1}.inspector-command__search input::-webkit-search-cancel-button{display:none}.inspector-command__results{min-height:0;max-height:260px;overflow:auto;padding:5px;scrollbar-width:thin;scrollbar-color:oklch(100% 0 0 / .1) transparent}.inspector-command-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:6px;min-height:34px;padding:0 7px 0 9px;border-radius:5px;cursor:pointer;-webkit-user-select:none;user-select:none}.inspector-command-row.is-active{background:var(--command-surface-active);box-shadow:inset 0 0 0 1px #6aa7f49e}.inspector-command-row.is-busy{cursor:wait;pointer-events:none;opacity:.7}.inspector-command-row__content{display:flex;align-items:baseline;gap:8px;min-width:0;overflow:hidden}.inspector-command-row__name{flex:0 1 auto;min-width:3ch;overflow:hidden;color:var(--command-text);font-size:12px;font-weight:500;line-height:1.25;text-overflow:ellipsis;white-space:nowrap}.inspector-command-row__meta{display:inline-flex;flex:0 1 auto;align-items:baseline;gap:4px;min-width:0;overflow:hidden;color:var(--command-faint);font-size:11px;font-weight:400;line-height:1.25;text-overflow:ellipsis;white-space:nowrap}.inspector-command-row__route{min-width:0;overflow:hidden;text-overflow:ellipsis}.inspector-command-row__separator,.inspector-command-row__activity{flex:0 0 auto}.inspector-command-row.is-active .inspector-command-row__meta{color:#c2c3cc}.inspector-command-row__actions,.inspector-command-row__confirm-actions{display:flex;align-items:center;gap:1px}.inspector-command-row__actions{opacity:0;pointer-events:none}.inspector-command-row:hover .inspector-command-row__actions,.inspector-command-row:focus-within .inspector-command-row__actions{opacity:1;pointer-events:auto}.inspector-command-row button{display:inline-grid;width:22px;min-height:22px;padding:0;place-items:center;border:0;border-radius:4px;background:transparent;color:var(--command-muted);cursor:pointer;font-family:inherit;font-size:10px;font-weight:550;line-height:1.2}.inspector-command-row button svg{width:11px;height:11px;fill:currentColor}.inspector-command-row button:hover{background:#ffffff12;color:var(--command-text)}.inspector-command-row button.is-danger{width:auto;padding:0 7px;color:var(--command-danger);font-size:11px}.inspector-command-row button.is-danger:hover{background:#ef66611f}.inspector-command-row__confirm-actions button:not(.is-danger){width:auto;padding:0 7px;font-size:11px}.inspector-command-row button:focus-visible,.inspector-command-row__rename:focus-visible{outline:1px solid var(--command-accent);outline-offset:1px}.inspector-command-row__confirm{grid-column:1;color:var(--command-text);font-size:12px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.inspector-command-row__rename{grid-column:1 / -1;min-height:26px;padding-inline:6px;border:1px solid oklch(72% .13 255 / .4);border-radius:4px;background:#191a21;font-size:12px;font-weight:500}.inspector-command__message{margin:0;padding:16px 10px;color:var(--command-faint);font-size:12px;line-height:1.4;text-align:center}.inspector-command__message--error{padding:6px 10px;border-bottom:1px solid oklch(55% .08 25 / .3);background:#39191780;color:#f7cbc7;text-align:left;font-size:11px}.inspector-command__actions{display:flex;gap:2px;padding:4px;border-top:1px solid var(--command-edge)}.inspector-command-action{display:flex;flex:1 1 0;min-width:0;min-height:28px;align-items:center;justify-content:center;gap:4px;padding:0 4px;overflow:hidden;border:0;border-radius:5px;background:transparent;color:var(--command-muted);cursor:pointer;font:inherit;font-size:10px;font-weight:500;line-height:1;text-align:left}.inspector-command-action svg{width:11px;height:11px;flex:0 0 auto;fill:currentColor}.inspector-command-action span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.inspector-command-action:hover:not(:disabled){background:#ffffff0f;color:var(--command-text)}.inspector-command-action.is-active{background:#6aa7f421;color:#c2daf9}.inspector-command-action.is-selected,.inspector-command-action.is-selected:hover:not(:disabled){background:var(--command-surface-active);color:var(--command-text);box-shadow:inset 0 0 0 1px #6aa7f49e}.inspector-command-action--danger:hover:not(:disabled){background:#ef66611a;color:#f5b9b4}.inspector-command-action:disabled{cursor:wait;opacity:.45}.inspector-command-action:focus-visible{outline:1px solid var(--command-accent);outline-offset:-1px}.inspector-visually-hidden{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.inspector-checkpoint-toast{position:fixed;top:10px;left:50%;z-index:500;margin:0;padding:5px 10px;border:1px solid oklch(74% .12 150 / .25);border-radius:999px;background:#0e1f12f0;color:#cce6d0;box-shadow:var(--inspector-shadow);font-size:11px;font-weight:520;line-height:1.25;pointer-events:none;transform:translate(-50%)}.inspector-checkpoint-toast--error{border-color:#e2726b4d;background:#351311f0;color:#fed2cd}@media (prefers-reduced-motion: reduce){.inspector-command-dialog{transition-duration:.01ms!important}.inspector-command-dialog,.inspector-command-dialog[open]{transform:none}.inspector-command__pet-switcher{transition:none}.inspector-command__pet-sprite{animation:none;transform:translate(0)}}.inspector-box{position:fixed;box-sizing:border-box;pointer-events:none;border:1px solid var(--inspector-accent, var(--inspector-blue));background:color-mix(in srgb,var(--inspector-accent, var(--inspector-blue)) 8%,transparent)}.inspector-box--hover{opacity:.55}.inspector-box--selected{border-width:1.5px}.inspector-box--margin{border-color:#f0a646d1;background:#f0a64614}.inspector-box--padding{border-color:#5ac576d1;background:#5ac57614}.inspector-box--gap{border-color:#bb8aefb8;background:#bb8aef0d}.inspector-box--distance{border-style:dashed;border-color:#539af2b3;background:transparent}.inspector-label,.inspector-box-tag,.inspector-text-chip,.inspector-distance-tag{font-variant-numeric:tabular-nums}.inspector-label{position:absolute;left:0;top:0;transform:translateY(calc(-100% - 6px));max-width:min(380px,calc(100vw - 20px));padding:4px 7px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:var(--inspector-panel);color:var(--inspector-text);box-shadow:var(--inspector-shadow);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);font-size:10px;font-weight:500;line-height:1.2;white-space:nowrap}.inspector-box-tag{position:fixed;transform:translateY(-100%);padding:3px 5px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#0e0f15f0;color:var(--inspector-text);font-size:9px;font-weight:520;line-height:1;pointer-events:none}.inspector-box-tag--margin{color:#f5c076}.inspector-box-tag--padding{color:#95dfa4;transform:translateY(0)}.inspector-box-tag--gap{color:oklch(86% .09 305)}.inspector-text-chip{position:fixed;transform:translateY(-100%);display:inline-flex;gap:5px;align-items:center;padding:3px 6px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#0e0f15f0;color:#e4e4e9;font-size:9px;font-weight:500;line-height:1;white-space:nowrap;pointer-events:none}.inspector-text-chip__swatch{width:7px;height:7px;border-radius:999px;border:1px solid oklch(100% 0 0 / .16);flex:0 0 auto}.inspector-connector{position:fixed;border-color:#539af2b8;border-style:dashed;pointer-events:none}.inspector-connector--vertical{border-left-width:1px;width:0}.inspector-connector--horizontal{border-top-width:1px;height:0}.inspector-distance-line{position:fixed;background:var(--inspector-blue);pointer-events:none}.inspector-distance-line--horizontal{height:1px}.inspector-distance-line--vertical{width:1px}.inspector-distance-tag{position:fixed;transform:translate(-50%);padding:3px 6px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#0e0f15f2;color:var(--inspector-text);font-size:9px;font-weight:520;line-height:1;pointer-events:none}.inspector-distance-tag--vertical{transform:translateY(-50%)}.inspector-guide{position:fixed;margin:0;padding:0;border:0;background:transparent;pointer-events:auto;cursor:grab}.inspector-guide--vertical{top:0;width:14px;height:100vh;transform:translate(-50%)}.inspector-guide--horizontal{left:0;width:100vw;height:14px;transform:translateY(-50%)}.inspector-guide--preview{opacity:.55;pointer-events:none;cursor:default}.inspector-guide--preview .inspector-guide-line{background:color-mix(in srgb,var(--inspector-guide, #ff7a00) 72%,transparent)}.inspector-guide-line{position:absolute;inset:0;pointer-events:none}.inspector-guide--vertical .inspector-guide-line{left:calc(50% - .5px);width:1px;height:100%;background:var(--inspector-guide, #ff7a00)}.inspector-guide--horizontal .inspector-guide-line{top:calc(50% - .5px);width:100%;height:1px;background:var(--inspector-guide, #ff7a00)}.inspector-guide--selected .inspector-guide-line{box-shadow:0 0 0 1px #ffffff80}@media (min-width: 769px) and (min-height: 769px){:host{--inspector-radius: 14px;--inspector-shadow: 0 21px 56px oklch(6% .02 280 / .5)}.inspector-command-dialog{inset-block-start:max(10vh,84px);width:min(735px,calc(100vw - 42px));max-height:min(630px,calc(100vh - 112px))}.inspector-command{max-height:min(630px,calc(100vh - 112px))}.inspector-command__search{gap:14px;min-height:70px;padding:0 19.25px}.inspector-command__pet-switcher{width:42px;height:42px}.inspector-command__search input{height:68.25px;font-size:22.75px}.inspector-command__results{max-height:455px;padding:8.75px}.inspector-command-row{gap:10.5px;min-height:59.5px;padding:0 12.25px 0 15.75px;border-radius:8.75px}.inspector-command-row__content{gap:14px}.inspector-command-row__name,.inspector-command-row__confirm{font-size:21px}.inspector-command-row__meta{gap:7px;font-size:19.25px}.inspector-command-row__actions,.inspector-command-row__confirm-actions{gap:1.75px}.inspector-command-row button{width:38.5px;min-height:38.5px;border-radius:7px;font-size:17.5px}.inspector-command-row button svg{width:19.25px;height:19.25px}.inspector-command-row button.is-danger,.inspector-command-row__confirm-actions button:not(.is-danger){padding:0 12.25px;font-size:19.25px}.inspector-command-row__rename{min-height:45.5px;padding-inline:10.5px;border-radius:7px;font-size:21px}.inspector-command__message{padding:28px 17.5px;font-size:21px}.inspector-command__message--error{padding:10.5px 17.5px;font-size:19.25px}.inspector-command__actions{gap:3.5px;padding:7px}.inspector-command-action{min-height:49px;gap:7px;padding:0 7px;border-radius:8.75px;font-size:17.5px}.inspector-command-action svg{width:19.25px;height:19.25px}.inspector-checkpoint-toast{top:17.5px;padding:8.75px 17.5px;font-size:19.25px}.inspector-label{transform:translateY(calc(-100% - 10.5px));max-width:min(665px,calc(100vw - 35px));padding:7px 12.25px;font-size:17.5px}.inspector-box-tag{padding:5.25px 8.75px;font-size:15.75px}.inspector-box-tag--padding{transform:translateY(0)}.inspector-text-chip{gap:8.75px;padding:5.25px 10.5px;font-size:15.75px}.inspector-text-chip__swatch{width:12.25px;height:12.25px}.inspector-distance-tag{padding:5.25px 10.5px;font-size:15.75px}.inspector-guide--vertical{width:24.5px}.inspector-guide--horizontal{height:24.5px}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1960
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: inspectorComponent, isStandalone: true, selector: "inspector-overlay", inputs: { highlightColor: "highlightColor", guideColor: "guideColor", hoverHighlightEnabled: "hoverHighlightEnabled" }, host: { listeners: { "window:keydown": "handleKeydown($event)", "window:keyup": "handleKeyup($event)", "window:pointermove": "handlePointerMove($event)", "window:pointerup": "handlePointerUp()", "window:click": "handleClick($event)", "window:resize": "handleViewportChange()", "window:scroll": "handleViewportChange()" } }, viewQueries: [{ propertyName: "overlayRoot", first: true, predicate: ["overlayRoot"], descendants: true, isSignal: true }, { propertyName: "checkpointDialog", first: true, predicate: ["checkpointDialog"], descendants: true, isSignal: true }, { propertyName: "checkpointSearch", first: true, predicate: ["checkpointSearch"], descendants: true, isSignal: true }, { propertyName: "checkpointRename", first: true, predicate: ["checkpointRename"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"inspector-root\" #overlayRoot>\n @if (checkpointService) {\n <dialog\n #checkpointDialog\n class=\"inspector-command-dialog\"\n aria-labelledby=\"inspector-command-title\"\n (cancel)=\"$event.preventDefault(); closeCheckpointCommandBar()\"\n (click)=\"handleCheckpointDialogClick($event)\"\n >\n <section class=\"inspector-command\" (click)=\"$event.stopPropagation()\">\n <header class=\"inspector-command__search\">\n <label\n id=\"inspector-command-title\"\n class=\"inspector-visually-hidden\"\n for=\"inspector-checkpoint-search\"\n >\n inspector-ng command palette\n </label>\n <button\n type=\"button\"\n class=\"inspector-command__pet-switcher\"\n [attr.aria-label]=\"'Change pet. Current pet: ' + activePet().name\"\n [title]=\"'Change pet: ' + activePet().name\"\n (click)=\"cyclePet($event)\"\n >\n <img\n class=\"inspector-command__pet-sprite\"\n [src]=\"activePet().spriteSrc\"\n alt=\"\"\n aria-hidden=\"true\"\n draggable=\"false\"\n />\n </button>\n <input\n #checkpointSearch\n id=\"inspector-checkpoint-search\"\n type=\"search\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n placeholder=\"inspector-ng\u2026\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"commandBarOpen()\"\n [value]=\"checkpointQuery()\"\n [attr.aria-controls]=\"'inspector-checkpoint-results inspector-command-actions'\"\n [attr.aria-activedescendant]=\"activeCommandResultId()\"\n (input)=\"updateCheckpointQuery($event)\"\n />\n </header>\n\n @if (checkpointService.error(); as error) {\n <p\n class=\"inspector-command__message inspector-command__message--error\"\n role=\"alert\"\n >\n {{ error }}\n </p>\n }\n\n <div\n id=\"inspector-checkpoint-results\"\n class=\"inspector-command__results\"\n role=\"listbox\"\n aria-label=\"Saved checkpoints\"\n >\n @if (checkpointService.loading()) {\n <p class=\"inspector-command__message\" role=\"status\">Loading\u2026</p>\n } @else if (\n !checkpointService.checkpoints().length && !checkpointQuery().trim()\n ) {\n <p class=\"inspector-command__message\" role=\"status\">\n No checkpoints yet\n </p>\n } @else if (\n !filteredCheckpoints().length &&\n !filteredInspectorActions().length &&\n !navigateTarget()\n ) {\n <p class=\"inspector-command__message\" role=\"status\">No matches</p>\n } @else {\n @for (\n checkpoint of filteredCheckpoints();\n track checkpoint.id;\n let index = $index\n ) {\n <div\n class=\"inspector-command-row\"\n role=\"option\"\n [id]=\"'inspector-checkpoint-' + checkpoint.id\"\n [attr.data-command-index]=\"index\"\n [attr.aria-selected]=\"activeCommandIndex() === index\"\n [class.is-active]=\"activeCommandIndex() === index\"\n [class.is-busy]=\"\n checkpointService.busy() && activeCommandIndex() === index\n \"\n (mouseenter)=\"setActiveCheckpoint(index)\"\n (click)=\"activateCheckpoint(checkpoint, $event)\"\n >\n @if (deletingCheckpointId() === checkpoint.id) {\n <span class=\"inspector-command-row__confirm\"\n >Delete \u201C{{ checkpoint.name }}\u201D?</span\n >\n <span class=\"inspector-command-row__confirm-actions\">\n <button\n type=\"button\"\n class=\"is-danger\"\n (click)=\"confirmDelete(checkpoint, $event)\"\n >\n Delete\n </button>\n <button type=\"button\" (click)=\"cancelDelete($event)\">\n Keep\n </button>\n </span>\n } @else if (editingCheckpointId() === checkpoint.id) {\n <input\n #checkpointRename\n class=\"inspector-command-row__rename\"\n aria-label=\"Checkpoint name\"\n [value]=\"renameDraft()\"\n (input)=\"updateRenameDraft($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n } @else {\n <span class=\"inspector-command-row__content\">\n <span\n class=\"inspector-command-row__name\"\n [title]=\"checkpoint.name\"\n >\n <bdi dir=\"ltr\">\n @if (\n checkpointService.busy() &&\n activeCommandIndex() === index\n ) {\n Restoring\u2026\n } @else {\n {{ checkpoint.name }}\n }\n </bdi>\n </span>\n <span class=\"inspector-command-row__activity\">\n {{ checkpoint.lastUsedAt ? \"Used\" : \"Saved\" }}\n {{\n formatRelativeTime(checkpointActivityAt(checkpoint))\n }}\n </span>\n </span>\n <span class=\"inspector-command-row__actions\">\n <button\n type=\"button\"\n (click)=\"beginRename(checkpoint, $event)\"\n [attr.aria-label]=\"'Rename ' + checkpoint.name\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"m11.8 1.8 2.4 2.4-8.3 8.3-3.1.7.7-3.1zm-8 10.4 1.5-.3-1.2-1.2z\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n (click)=\"downloadCheckpoint(checkpoint, $event)\"\n [attr.aria-label]=\"'Export ' + checkpoint.name\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M7.25 2h1.5v5.44l1.72-1.72L11.53 6.78 8 10.31 4.47 6.78l1.06-1.06 1.72 1.72zM2.5 12h11v1.5h-11z\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n (click)=\"beginDelete(checkpoint, $event)\"\n [attr.aria-label]=\"'Delete ' + checkpoint.name\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M5.5 2h5l.5 1H14v1.25H2V3h3zm-2 3.25h9L12 14H4z\"\n />\n </svg>\n </button>\n </span>\n }\n </div>\n }\n @if (navigateTarget(); as target) {\n <div\n class=\"inspector-command-row inspector-command-row--navigate\"\n role=\"option\"\n id=\"inspector-navigate\"\n [attr.data-command-index]=\"filteredCheckpoints().length\"\n [attr.aria-selected]=\"\n activeCommandIndex() === filteredCheckpoints().length\n \"\n [class.is-active]=\"\n activeCommandIndex() === filteredCheckpoints().length\n \"\n [class.is-busy]=\"\n checkpointService.busy() &&\n activeCommandIndex() === filteredCheckpoints().length\n \"\n (mouseenter)=\"setActiveCheckpoint(filteredCheckpoints().length)\"\n (click)=\"navigateToQueryRoute()\"\n >\n <span class=\"inspector-command-row__content\">\n <span\n class=\"inspector-command-row__name\"\n [title]=\"'Navigate to ' + target\"\n >\n <bdi dir=\"ltr\">\n @if (\n checkpointService.busy() &&\n activeCommandIndex() === filteredCheckpoints().length\n ) {\n Navigating\u2026\n } @else {\n Go to {{ target }}\n }\n </bdi>\n </span>\n <span class=\"inspector-command-row__activity\">\n navigate \u00B7 keeps state\n </span>\n </span>\n </div>\n }\n }\n </div>\n\n @if (filteredInspectorActions().length) {\n <footer\n id=\"inspector-command-actions\"\n class=\"inspector-command__actions\"\n role=\"listbox\"\n aria-label=\"Inspector actions\"\n aria-orientation=\"horizontal\"\n >\n @for (\n action of filteredInspectorActions();\n track action.id;\n let index = $index\n ) {\n <button\n type=\"button\"\n role=\"option\"\n class=\"inspector-command-action\"\n [id]=\"'inspector-action-' + action.id\"\n [attr.data-command-index]=\"actionIndexOffset() + index\"\n [attr.aria-label]=\"action.ariaLabel\"\n [attr.aria-selected]=\"\n activeCommandIndex() === actionIndexOffset() + index\n \"\n [attr.aria-disabled]=\"checkpointService.busy()\"\n [class.is-selected]=\"\n activeCommandIndex() === actionIndexOffset() + index\n \"\n [class.is-active]=\"\n (action.id === 'select' && toolMode() === 'select') ||\n (action.id === 'type' && showTypography()) ||\n (action.id === 'vertical' &&\n toolMode() === 'guides' &&\n guideOrientation() === 'vertical') ||\n (action.id === 'horizontal' &&\n toolMode() === 'guides' &&\n guideOrientation() === 'horizontal')\n \"\n [disabled]=\"checkpointService.busy()\"\n (mouseenter)=\"setActiveInspectorAction(index)\"\n (click)=\"executeInspectorAction(action)\"\n >\n @switch (action.id) {\n @case (\"select\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 2l8 8-3 .7L6.7 13 6 10 3 2z\" />\n </svg>\n }\n @case (\"type\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 4V2h10v2h-4v10H7V4z\" />\n </svg>\n }\n @case (\"save\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M2.5 2h9.6l1.4 1.4V14h-11zm2 1.5v3h6v-3zm.5 6V12h6V9.5z\"\n />\n </svg>\n }\n @case (\"import\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M8 2l3.53 3.53-1.06 1.06L8.75 4.87V9.5h-1.5V4.87L5.53 6.59 4.47 5.53zM2.5 11h11v1.5h-11z\"\n />\n </svg>\n }\n @case (\"vertical\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M7.25 2h1.5v12h-1.5z\" />\n </svg>\n }\n @case (\"horizontal\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M2 7.25h12v1.5H2z\" />\n </svg>\n }\n }\n <span>{{ action.label }}</span>\n </button>\n }\n </footer>\n }\n </section>\n </dialog>\n }\n\n @if (checkpointToast(); as toast) {\n <p\n class=\"inspector-checkpoint-toast\"\n [class.inspector-checkpoint-toast--error]=\"checkpointToastIsError()\"\n [attr.role]=\"checkpointToastIsError() ? 'alert' : 'status'\"\n >\n {{ toast }}\n </p>\n }\n\n @if (enabled() && toolMode() === \"select\") {\n @if (hoverRect() && hoverHighlightEnabled) {\n <div\n class=\"inspector-box inspector-box--hover\"\n [style.left.px]=\"hoverRect()!.left\"\n [style.top.px]=\"hoverRect()!.top\"\n [style.width.px]=\"hoverRect()!.width\"\n [style.height.px]=\"hoverRect()!.height\"\n [style.--inspector-accent]=\"highlightColor\"\n ></div>\n }\n\n @if (selectedMeasurement(); as selected) {\n @if (selected.gap.active && selected.parentRect) {\n <div\n class=\"inspector-box inspector-box--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top\"\n [style.width.px]=\"selected.parentRect.width\"\n [style.height.px]=\"selected.parentRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top - 8\"\n >\n G {{ formatGap(selected) }}\n </div>\n }\n\n <div\n class=\"inspector-box inspector-box--margin\"\n [style.left.px]=\"selected.marginRect.left\"\n [style.top.px]=\"selected.marginRect.top\"\n [style.width.px]=\"selected.marginRect.width\"\n [style.height.px]=\"selected.marginRect.height\"\n ></div>\n\n <div\n class=\"inspector-box inspector-box--selected\"\n [style.left.px]=\"selected.rect.left\"\n [style.top.px]=\"selected.rect.top\"\n [style.width.px]=\"selected.rect.width\"\n [style.height.px]=\"selected.rect.height\"\n [style.--inspector-accent]=\"highlightColor\"\n >\n <div class=\"inspector-label\">{{ selectedMetaLine() }}</div>\n </div>\n\n <div\n class=\"inspector-box inspector-box--padding\"\n [style.left.px]=\"selected.paddingRect.left\"\n [style.top.px]=\"selected.paddingRect.top\"\n [style.width.px]=\"selected.paddingRect.width\"\n [style.height.px]=\"selected.paddingRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--spacing\"\n [style.left.px]=\"selected.rect.left\"\n [style.top.px]=\"selected.rect.top + selected.rect.height + 8\"\n >\n <span class=\"inspector-box-tag__margin\">M</span>\n <span>{{ formatEdges(selected.margin) }}</span>\n <span class=\"inspector-box-tag__separator\">\u00B7</span>\n <span class=\"inspector-box-tag__padding\">P</span>\n <span>{{ formatEdges(selected.padding) }}</span>\n </div>\n }\n }\n\n @if (enabled() && showTypography()) {\n @for (block of textBlocks(); track block.id) {\n <div\n class=\"inspector-text-chip\"\n [style.left.px]=\"block.rect.left\"\n [style.top.px]=\"block.rect.top - 8\"\n >\n <span\n class=\"inspector-text-chip__swatch\"\n [style.background]=\"block.styles.color\"\n ></span>\n <span>{{ block.styles.fontSize }}</span>\n <span>{{ block.styles.lineHeight }}</span>\n <span>{{ block.styles.color }}</span>\n </div>\n }\n }\n\n @if (enabled() && altPressed() && distanceOverlay(); as distance) {\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectA.left\"\n [style.top.px]=\"distance.rectA.top\"\n [style.width.px]=\"distance.rectA.width\"\n [style.height.px]=\"distance.rectA.height\"\n ></div>\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectB.left\"\n [style.top.px]=\"distance.rectB.top\"\n [style.width.px]=\"distance.rectB.width\"\n [style.height.px]=\"distance.rectB.height\"\n ></div>\n\n @for (\n connector of distance.connectors;\n track trackConnector($index, connector)\n ) {\n <div\n class=\"inspector-connector\"\n [class.inspector-connector--vertical]=\"connector.x1 === connector.x2\"\n [class.inspector-connector--horizontal]=\"connector.y1 === connector.y2\"\n [style.left.px]=\"Math.min(connector.x1, connector.x2)\"\n [style.top.px]=\"Math.min(connector.y1, connector.y2)\"\n [style.width.px]=\"Math.max(1, Math.abs(connector.x2 - connector.x1))\"\n [style.height.px]=\"Math.max(1, Math.abs(connector.y2 - connector.y1))\"\n ></div>\n }\n\n @for (horizontal of distance.horizontalDistances; track $index) {\n @if (horizontal.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--horizontal\"\n [style.left.px]=\"Math.min(horizontal.x1!, horizontal.x2!)\"\n [style.top.px]=\"horizontal.y!\"\n [style.width.px]=\"Math.abs(horizontal.x2! - horizontal.x1!)\"\n ></div>\n <div\n class=\"inspector-distance-tag\"\n [style.left.px]=\"(horizontal.x1! + horizontal.x2!) / 2\"\n [style.top.px]=\"horizontal.y!\"\n >\n {{ formatValue(horizontal.value) }}\n </div>\n }\n }\n\n @for (vertical of distance.verticalDistances; track $index) {\n @if (vertical.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--vertical\"\n [style.left.px]=\"vertical.x!\"\n [style.top.px]=\"Math.min(vertical.y1!, vertical.y2!)\"\n [style.height.px]=\"Math.abs(vertical.y2! - vertical.y1!)\"\n ></div>\n <div\n class=\"inspector-distance-tag inspector-distance-tag--vertical\"\n [style.left.px]=\"vertical.x!\"\n [style.top.px]=\"(vertical.y1! + vertical.y2!) / 2\"\n >\n {{ formatValue(vertical.value) }}\n </div>\n }\n }\n }\n\n @if (enabled()) {\n @if (toolMode() === \"guides\") {\n @if (guidePreview(); as preview) {\n <div\n class=\"inspector-guide inspector-guide--preview\"\n [class.inspector-guide--vertical]=\"preview.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"\n preview.orientation === 'horizontal'\n \"\n [style.left.px]=\"\n preview.orientation === 'vertical' ? preview.position : null\n \"\n [style.top.px]=\"\n preview.orientation === 'horizontal' ? preview.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n >\n <span class=\"inspector-guide-line\"></span>\n </div>\n }\n }\n\n @for (guide of guides(); track guide.id) {\n <button\n type=\"button\"\n class=\"inspector-guide\"\n [class.inspector-guide--vertical]=\"guide.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"guide.orientation === 'horizontal'\"\n [class.inspector-guide--selected]=\"selectedGuideId() === guide.id\"\n [style.left.px]=\"\n guide.orientation === 'vertical' ? guide.position : null\n \"\n [style.top.px]=\"\n guide.orientation === 'horizontal' ? guide.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n [attr.aria-label]=\"\n (guide.orientation === 'vertical' ? 'Vertical' : 'Horizontal') +\n ' guide at ' +\n formatValue(guide.position) +\n ' pixels'\n \"\n (pointerdown)=\"startGuideDrag($event, guide)\"\n >\n <span class=\"inspector-guide-line\"></span>\n </button>\n }\n\n @for (distance of guideDistances(); track distance.orientation + \"-\" + distance.start + \"-\" + distance.end) {\n <div\n class=\"inspector-guide-distance\"\n [class.inspector-guide-distance--vertical]=\"distance.orientation === 'vertical'\"\n [class.inspector-guide-distance--horizontal]=\"distance.orientation === 'horizontal'\"\n [style.left.px]=\"distance.orientation === 'vertical' ? distance.start : null\"\n [style.top.px]=\"distance.orientation === 'horizontal' ? distance.start : null\"\n [style.width.px]=\"distance.orientation === 'vertical' ? distance.value : null\"\n [style.height.px]=\"distance.orientation === 'horizontal' ? distance.value : null\"\n [style.--inspector-guide]=\"guideColor\"\n aria-hidden=\"true\"\n >\n <span class=\"inspector-guide-distance__line\"></span>\n <span class=\"inspector-guide-distance__tag\">\n {{ formatValue(distance.value) }} px\n </span>\n </div>\n }\n }\n</div>\n", styles: [":host{--inspector-panel: oklch(20% .012 280 / .92);--inspector-panel-edge: oklch(100% 0 0 / .08);--inspector-text: oklch(96% .005 280);--inspector-muted: oklch(70% .014 280);--inspector-faint: oklch(56% .012 280);--inspector-blue: oklch(68% .15 255);--inspector-blue-soft: oklch(68% .15 255 / .14);--inspector-orange: oklch(78% .14 70);--inspector-green: oklch(74% .15 150);--inspector-violet: oklch(72% .15 305);--inspector-radius: 8px;--inspector-shadow: 0 12px 32px oklch(6% .02 280 / .5);--inspector-font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--inspector-ease: cubic-bezier(.16, 1, .3, 1);position:fixed;inset:0;z-index:2147;pointer-events:none;font-family:var(--inspector-font);color:var(--inspector-text);-webkit-font-smoothing:antialiased}.inspector-root{position:fixed;inset:0;pointer-events:none}.inspector-command-dialog{--command-surface: oklch(17.5% .012 280);--command-surface-active: oklch(25% .012 280);--command-edge: oklch(100% 0 0 / .08);--command-text: oklch(96% .005 280);--command-muted: oklch(68% .014 280);--command-faint: oklch(52% .012 280);--command-accent: oklch(72% .13 255);--command-danger: oklch(68% .17 25);box-sizing:border-box;inset-block-start:max(10vh,48px);width:min(420px,calc(100vw - 24px));max-width:none;max-height:min(360px,calc(100vh - 64px));margin:0 auto;padding:0;overflow:hidden;border:1px solid var(--command-edge);border-radius:var(--inspector-radius);background:var(--command-surface);color:var(--command-text);box-shadow:var(--inspector-shadow);opacity:0;pointer-events:auto;transform:translateY(-4px);transition:opacity .1s ease,transform .1s ease,overlay .1s allow-discrete,display .1s allow-discrete;font-family:var(--inspector-font);-webkit-font-smoothing:antialiased}.inspector-command-dialog[open]{opacity:1;transform:none;transition-duration:.14s;transition-timing-function:var(--inspector-ease)}@starting-style{.inspector-command-dialog[open]{opacity:0;transform:translateY(-4px)}}.inspector-command-dialog::backdrop{background:#01010266}.inspector-command{display:grid;grid-template-rows:auto auto 1fr auto;min-width:0;min-height:0;max-height:min(360px,calc(100vh - 64px))}.inspector-command__search{display:flex;align-items:center;gap:8px;min-height:40px;padding:0 11px;border-bottom:1px solid var(--command-edge)}.inspector-command__pet-switcher{display:block;width:28px;height:28px;flex:0 0 auto;padding:0;overflow:hidden;border:0;border-radius:4px;background:transparent;cursor:pointer;opacity:.72;transition:opacity .14s var(--inspector-ease),transform .1s var(--inspector-ease)}.inspector-command__pet-sprite{display:block;width:500%;height:100%;max-width:none;image-rendering:pixelated;-webkit-user-select:none;user-select:none;transform:translate(0)}.inspector-command__search:focus-within .inspector-command__pet-switcher,.inspector-command__pet-switcher:hover,.inspector-command__pet-switcher:focus-visible{opacity:1}.inspector-command__pet-switcher:hover,.inspector-command__pet-switcher:focus-visible{background:#6aa7f41f}.inspector-command__pet-switcher:active{transform:scale(.94)}.inspector-command__pet-switcher:focus-visible{outline:1px solid var(--command-accent);outline-offset:1px}@media (prefers-reduced-motion: no-preference){.inspector-command__pet-sprite{animation:inspector-pet-cycle 1s steps(1,end) infinite}}@keyframes inspector-pet-cycle{0%,19.99%{transform:translate(0)}20%,39.99%{transform:translate(-20%)}40%,59.99%{transform:translate(-40%)}60%,79.99%{transform:translate(-60%)}80%,to{transform:translate(-80%)}}.inspector-command__search input,.inspector-command-row__rename{min-width:0;border:0;outline:0;background:transparent;color:var(--command-text);font:inherit}.inspector-command__search input{flex:1 1 auto;width:100%;height:39px;padding:0;font-size:13px;font-weight:450;line-height:1.3}.inspector-command__search input::placeholder{color:var(--command-faint);opacity:1}.inspector-command__search input::-webkit-search-cancel-button{display:none}.inspector-command__results{min-height:0;max-height:260px;overflow:auto;padding:5px;scrollbar-width:thin;scrollbar-color:oklch(100% 0 0 / .1) transparent}.inspector-command-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:6px;min-height:34px;padding:0 7px 0 9px;border-radius:5px;cursor:pointer;-webkit-user-select:none;user-select:none}.inspector-command-row.is-active{background:color-mix(in oklch,var(--command-surface-active) 92%,var(--command-accent));box-shadow:inset 0 0 0 1px #6aa7f452}.inspector-command-row.is-busy{cursor:wait;pointer-events:none;opacity:.7}.inspector-command-row__content{display:flex;align-items:baseline;gap:6px;min-width:0;overflow:hidden}.inspector-command-row__name{flex:0 1 auto;min-width:3ch;overflow:hidden;color:var(--command-text);font-size:12px;font-weight:500;line-height:1.25;text-overflow:ellipsis;white-space:nowrap;direction:rtl;text-align:left}.inspector-command-row__name bdi{direction:ltr;unicode-bidi:isolate}.inspector-command-row__activity{flex:0 0 auto;color:var(--command-faint);font-size:9px;font-weight:450;line-height:1;white-space:nowrap}.inspector-command-row.is-active .inspector-command-row__activity{color:#c2c3cc}.inspector-command-row--navigate{margin-top:4px;padding-top:5px;border-top:1px dashed var(--command-edge)}.inspector-command-row--navigate .inspector-command-row__name{color:color-mix(in oklch,var(--command-text) 78%,var(--command-accent))}.inspector-command-row--navigate .inspector-command-row__name:before{content:\"\\2192 \";color:var(--command-accent)}.inspector-command-row__actions,.inspector-command-row__confirm-actions{display:flex;align-items:center;gap:1px}.inspector-command-row__actions{opacity:0;pointer-events:none}.inspector-command-row.is-active .inspector-command-row__actions,.inspector-command-row:hover .inspector-command-row__actions,.inspector-command-row:focus-within .inspector-command-row__actions{opacity:1;pointer-events:auto}.inspector-command-row button{display:inline-grid;width:22px;min-height:22px;padding:0;place-items:center;border:0;border-radius:4px;background:transparent;color:var(--command-muted);cursor:pointer;font-family:inherit;font-size:10px;font-weight:550;line-height:1.2}.inspector-command-row button svg{width:11px;height:11px;fill:currentColor}.inspector-command-row button:hover{background:#ffffff12;color:var(--command-text)}.inspector-command-row button.is-danger{width:auto;padding:0 7px;color:var(--command-danger);font-size:11px}.inspector-command-row button.is-danger:hover{background:#ef66611f}.inspector-command-row__confirm-actions button:not(.is-danger){width:auto;padding:0 7px;font-size:11px}.inspector-command-row button:focus-visible,.inspector-command-row__rename:focus-visible{outline:1px solid var(--command-accent);outline-offset:1px}.inspector-command-row__confirm{grid-column:1;color:var(--command-text);font-size:12px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.inspector-command-row__rename{grid-column:1 / -1;min-height:26px;padding-inline:6px;border:1px solid oklch(72% .13 255 / .4);border-radius:4px;background:#191a21;font-size:12px;font-weight:500}.inspector-command__message{margin:0;padding:16px 10px;color:var(--command-faint);font-size:12px;line-height:1.4;text-align:center}.inspector-command__message--error{padding:6px 10px;border-bottom:1px solid oklch(55% .08 25 / .3);background:#39191780;color:#f7cbc7;text-align:left;font-size:11px}.inspector-command__actions{display:flex;gap:2px;padding:4px;border-top:1px solid var(--command-edge)}.inspector-command-action{display:flex;flex:1 1 0;min-width:0;min-height:28px;align-items:center;justify-content:center;gap:4px;padding:0 4px;overflow:hidden;border:0;border-radius:5px;background:transparent;color:var(--command-muted);cursor:pointer;font:inherit;font-size:10px;font-weight:500;line-height:1;text-align:left}.inspector-command-action svg{width:11px;height:11px;flex:0 0 auto;fill:currentColor}.inspector-command-action span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.inspector-command-action:hover:not(:disabled){background:#ffffff0f;color:var(--command-text)}.inspector-command-action.is-active{background:#6aa7f421;color:#c2daf9}.inspector-command-action.is-selected,.inspector-command-action.is-selected:hover:not(:disabled){background:var(--command-surface-active);color:var(--command-text);box-shadow:inset 0 0 0 1px #6aa7f49e}.inspector-command-action:disabled{cursor:wait;opacity:.45}.inspector-command-action:focus-visible{outline:1px solid var(--command-accent);outline-offset:-1px}.inspector-visually-hidden{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.inspector-checkpoint-toast{position:fixed;top:10px;left:50%;z-index:500;margin:0;display:flex;align-items:center;gap:6px;padding:6px 9px;border:1px solid var(--inspector-panel-edge);border-radius:6px;background:#0f1016f5;color:var(--inspector-text);box-shadow:0 8px 24px #01000352;font-size:11px;font-weight:500;line-height:1.3;pointer-events:none;transform:translate(-50%);animation:inspector-toast-in .16s var(--inspector-ease) both}.inspector-checkpoint-toast:before{width:5px;height:5px;flex:0 0 auto;border-radius:50%;background:var(--inspector-blue);content:\"\"}.inspector-checkpoint-toast--error{border-color:#e2726b4d;background:#351311f0;color:#fed2cd}.inspector-checkpoint-toast--error:before{background:var(--command-danger, oklch(68% .17 25))}@keyframes inspector-toast-in{0%{opacity:0;transform:translate(-50%,-4px)}to{opacity:1;transform:translate(-50%)}}@media (prefers-reduced-motion: reduce){.inspector-command-dialog{transition-duration:.01ms!important}.inspector-command-dialog,.inspector-command-dialog[open]{transform:none}.inspector-command__pet-switcher{transition:none}.inspector-command__pet-sprite{animation:none;transform:translate(0)}.inspector-checkpoint-toast{animation:none}}.inspector-box{position:fixed;box-sizing:border-box;pointer-events:none;border:1px solid var(--inspector-accent, var(--inspector-blue));background:color-mix(in srgb,var(--inspector-accent, var(--inspector-blue)) 8%,transparent)}.inspector-box--hover{opacity:.55}.inspector-box--selected{border-width:1.5px}.inspector-box--margin{border-color:#f0a646d1;background:#f0a64614}.inspector-box--padding{border-color:#5ac576d1;background:#5ac57614}.inspector-box--gap{border-color:#bb8aefb8;background:#bb8aef0d}.inspector-box--distance{border-style:dashed;border-color:#539af2b3;background:transparent}.inspector-label,.inspector-box-tag,.inspector-text-chip,.inspector-distance-tag,.inspector-guide-distance__tag{border:1px solid var(--inspector-panel-edge);border-radius:4px;background:#0e0f15c2;font-variant-numeric:tabular-nums;text-shadow:none}.inspector-label{position:absolute;left:0;top:0;transform:translateY(calc(-100% - 6px));max-width:min(380px,calc(100vw - 20px));padding:1px 3px;color:var(--inspector-text);box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none;font-size:9px;font-weight:500;line-height:1.2;white-space:nowrap}.inspector-box-tag{position:fixed;transform:translateY(-100%);padding:2px 4px;color:var(--inspector-text);font-size:9px;font-weight:520;line-height:1;pointer-events:none}.inspector-box-tag__margin{color:#f5c076}.inspector-box-tag__padding{color:#95dfa4}.inspector-box-tag--gap{color:oklch(86% .09 305)}.inspector-box-tag--spacing{display:inline-flex;align-items:center;gap:3px;transform:translateY(0);white-space:nowrap}.inspector-box-tag__separator{color:var(--inspector-faint)}.inspector-text-chip{position:fixed;transform:translateY(-100%);display:inline-flex;gap:5px;align-items:center;padding:2px 4px;color:#e4e4e9;font-size:9px;font-weight:500;line-height:1;white-space:nowrap;pointer-events:none}.inspector-text-chip__swatch{width:7px;height:7px;border-radius:999px;border:1px solid oklch(100% 0 0 / .16);flex:0 0 auto}.inspector-connector{position:fixed;border-color:#539af2b8;border-style:dashed;pointer-events:none}.inspector-connector--vertical{border-left-width:1px;width:0}.inspector-connector--horizontal{border-top-width:1px;height:0}.inspector-distance-line{position:fixed;background:var(--inspector-blue);pointer-events:none}.inspector-distance-line--horizontal{height:1px}.inspector-distance-line--vertical{width:1px}.inspector-distance-tag{position:fixed;transform:translate(-50%,-50%);padding:2px 4px;border-color:#539af247;background:#0e0f15b8;color:var(--inspector-text);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);font-size:9px;font-weight:520;line-height:1;pointer-events:none}.inspector-guide{position:fixed;margin:0;padding:0;border:0;background:transparent;pointer-events:auto;cursor:grab}.inspector-guide--vertical{top:0;width:14px;height:100vh;transform:translate(-50%)}.inspector-guide--horizontal{left:0;width:100vw;height:14px;transform:translateY(-50%)}.inspector-guide--preview{opacity:.55;pointer-events:none;cursor:default}.inspector-guide--preview .inspector-guide-line{background:color-mix(in srgb,var(--inspector-guide, #ff7a00) 72%,transparent)}.inspector-guide-line{position:absolute;inset:0;pointer-events:none}.inspector-guide--vertical .inspector-guide-line{left:calc(50% - .5px);width:1px;height:100%;background:var(--inspector-guide, #ff7a00)}.inspector-guide--horizontal .inspector-guide-line{top:calc(50% - .5px);width:100%;height:1px;background:var(--inspector-guide, #ff7a00)}.inspector-guide--selected .inspector-guide-line{box-shadow:0 0 0 1px #ffffff80}.inspector-guide-distance{position:fixed;z-index:2;pointer-events:none}.inspector-guide-distance--vertical{top:50%;height:1px}.inspector-guide-distance--horizontal{left:50%;width:1px}.inspector-guide-distance__line{position:absolute;background:color-mix(in srgb,var(--inspector-guide, #ff7a00) 72%,transparent)}.inspector-guide-distance--vertical .inspector-guide-distance__line{inset:0;height:1px}.inspector-guide-distance--horizontal .inspector-guide-distance__line{inset:0;width:1px}.inspector-guide-distance__line:before,.inspector-guide-distance__line:after{position:absolute;content:\"\";background:var(--inspector-guide, #ff7a00)}.inspector-guide-distance--vertical .inspector-guide-distance__line:before,.inspector-guide-distance--vertical .inspector-guide-distance__line:after{top:-2px;width:1px;height:5px}.inspector-guide-distance--vertical .inspector-guide-distance__line:before{left:0}.inspector-guide-distance--vertical .inspector-guide-distance__line:after{right:0}.inspector-guide-distance--horizontal .inspector-guide-distance__line:before,.inspector-guide-distance--horizontal .inspector-guide-distance__line:after{left:-2px;width:5px;height:1px}.inspector-guide-distance--horizontal .inspector-guide-distance__line:before{top:0}.inspector-guide-distance--horizontal .inspector-guide-distance__line:after{bottom:0}.inspector-guide-distance__tag{position:absolute;padding:2px 4px;border-color:color-mix(in srgb,var(--inspector-guide, #ff7a00) 48%,transparent);background:#0e0f15eb;color:var(--inspector-text);box-shadow:0 1px 4px #01000357;font-size:9px;font-weight:520;line-height:1;white-space:nowrap}.inspector-guide-distance--vertical .inspector-guide-distance__tag{left:50%;top:0;transform:translate(-50%,-50%)}.inspector-guide-distance--horizontal .inspector-guide-distance__tag{left:0;top:50%;transform:translate(-50%,-50%)}@media (min-width: 769px) and (min-height: 769px){:host{--inspector-radius: 14px;--inspector-shadow: 0 21px 56px oklch(6% .02 280 / .5)}.inspector-command-dialog{inset-block-start:max(10vh,84px);width:min(735px,calc(100vw - 42px));max-height:min(630px,calc(100vh - 112px))}.inspector-command{max-height:min(630px,calc(100vh - 112px))}.inspector-command__search{gap:14px;min-height:70px;padding:0 19.25px}.inspector-command__pet-switcher{width:42px;height:42px}.inspector-command__search input{height:68.25px;font-size:22.75px}.inspector-command__results{max-height:455px;padding:8.75px}.inspector-command-row{gap:10.5px;min-height:59.5px;padding:0 12.25px 0 15.75px;border-radius:8.75px}.inspector-command-row__content{gap:10.5px}.inspector-command-row__name,.inspector-command-row__confirm{font-size:21px}.inspector-command-row__activity{font-size:15.75px}.inspector-command-row__actions,.inspector-command-row__confirm-actions{gap:1.75px}.inspector-command-row button{width:38.5px;min-height:38.5px;border-radius:7px;font-size:17.5px}.inspector-command-row button svg{width:19.25px;height:19.25px}.inspector-command-row button.is-danger,.inspector-command-row__confirm-actions button:not(.is-danger){padding:0 12.25px;font-size:19.25px}.inspector-command-row__rename{min-height:45.5px;padding-inline:10.5px;border-radius:7px;font-size:21px}.inspector-command__message{padding:28px 17.5px;font-size:21px}.inspector-command__message--error{padding:10.5px 17.5px;font-size:19.25px}.inspector-command__actions{gap:3.5px;padding:7px}.inspector-command-action{min-height:49px;gap:7px;padding:0 7px;border-radius:8.75px;font-size:17.5px}.inspector-command-action svg{width:19.25px;height:19.25px}.inspector-checkpoint-toast{top:14px;padding:7px 10px;font-size:13px}.inspector-label{transform:translateY(calc(-100% - 10.5px));max-width:min(665px,calc(100vw - 35px));padding:2px 4px;font-size:13px}.inspector-box-tag{padding:3px 5px;font-size:15.75px}.inspector-box-tag--spacing{gap:5px;transform:translateY(0)}.inspector-text-chip{gap:8.75px;padding:3px 5px;font-size:15.75px}.inspector-text-chip__swatch{width:12.25px;height:12.25px}.inspector-distance-tag,.inspector-guide-distance__tag{padding:3px 5px;font-size:15.75px}.inspector-guide--vertical{width:24.5px}.inspector-guide--horizontal{height:24.5px}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1596
1961
|
}
|
|
1597
1962
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: inspectorComponent, decorators: [{
|
|
1598
1963
|
type: Component,
|
|
1599
|
-
args: [{ selector: 'inspector-overlay', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"inspector-root\" #overlayRoot>\n @if (checkpointService) {\n <dialog\n #checkpointDialog\n class=\"inspector-command-dialog\"\n aria-labelledby=\"inspector-command-title\"\n (cancel)=\"$event.preventDefault(); closeCheckpointCommandBar()\"\n (click)=\"handleCheckpointDialogClick($event)\"\n >\n <section class=\"inspector-command\" (click)=\"$event.stopPropagation()\">\n <header class=\"inspector-command__search\">\n <label\n id=\"inspector-command-title\"\n class=\"inspector-visually-hidden\"\n for=\"inspector-checkpoint-search\"\n >\n inspector-ng command palette\n </label>\n <button\n type=\"button\"\n class=\"inspector-command__pet-switcher\"\n [attr.aria-label]=\"'Change pet. Current pet: ' + activePet().name\"\n [title]=\"'Change pet: ' + activePet().name\"\n (click)=\"cyclePet($event)\"\n >\n <img\n class=\"inspector-command__pet-sprite\"\n [src]=\"activePet().spriteSrc\"\n alt=\"\"\n aria-hidden=\"true\"\n draggable=\"false\"\n />\n </button>\n <input\n #checkpointSearch\n id=\"inspector-checkpoint-search\"\n type=\"search\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n placeholder=\"inspector-ng\u2026\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"commandBarOpen()\"\n [value]=\"checkpointQuery()\"\n [attr.aria-controls]=\"'inspector-checkpoint-results inspector-command-actions'\"\n [attr.aria-activedescendant]=\"activeCommandResultId()\"\n (input)=\"updateCheckpointQuery($event)\"\n />\n </header>\n\n @if (checkpointService.error(); as error) {\n <p\n class=\"inspector-command__message inspector-command__message--error\"\n role=\"alert\"\n >\n {{ error }}\n </p>\n }\n\n <div\n id=\"inspector-checkpoint-results\"\n class=\"inspector-command__results\"\n role=\"listbox\"\n aria-label=\"Saved checkpoints\"\n >\n @if (checkpointService.loading()) {\n <p class=\"inspector-command__message\" role=\"status\">Loading\u2026</p>\n } @else if (\n !checkpointService.checkpoints().length && !checkpointQuery().trim()\n ) {\n <p class=\"inspector-command__message\" role=\"status\">\n No checkpoints yet\n </p>\n } @else if (\n !filteredCheckpoints().length && !filteredInspectorActions().length\n ) {\n <p class=\"inspector-command__message\" role=\"status\">No matches</p>\n } @else {\n @for (\n checkpoint of filteredCheckpoints();\n track checkpoint.id;\n let index = $index\n ) {\n <div\n class=\"inspector-command-row\"\n role=\"option\"\n [id]=\"'inspector-checkpoint-' + checkpoint.id\"\n [attr.data-command-index]=\"index\"\n [attr.aria-selected]=\"activeCommandIndex() === index\"\n [class.is-active]=\"activeCommandIndex() === index\"\n [class.is-busy]=\"\n checkpointService.busy() && activeCommandIndex() === index\n \"\n (mouseenter)=\"setActiveCheckpoint(index)\"\n (click)=\"\n deletingCheckpointId() === checkpoint.id ||\n editingCheckpointId() === checkpoint.id\n ? null\n : restoreCheckpoint(checkpoint)\n \"\n >\n @if (deletingCheckpointId() === checkpoint.id) {\n <span class=\"inspector-command-row__confirm\"\n >Delete \u201C{{ checkpoint.name }}\u201D?</span\n >\n <span class=\"inspector-command-row__confirm-actions\">\n <button\n type=\"button\"\n class=\"is-danger\"\n (click)=\"confirmDelete(checkpoint, $event)\"\n >\n Delete\n </button>\n <button type=\"button\" (click)=\"cancelDelete($event)\">\n Keep\n </button>\n </span>\n } @else if (editingCheckpointId() === checkpoint.id) {\n <input\n class=\"inspector-command-row__rename\"\n aria-label=\"Checkpoint name\"\n [value]=\"renameDraft()\"\n (input)=\"updateRenameDraft($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n } @else {\n <span class=\"inspector-command-row__content\">\n <span class=\"inspector-command-row__name\">\n @if (\n checkpointService.busy() &&\n activeCommandIndex() === index\n ) {\n Restoring\u2026\n } @else {\n {{ checkpoint.name }}\n }\n </span>\n <span class=\"inspector-command-row__meta\">\n @if (shouldShowCheckpointRoute(checkpoint)) {\n <span class=\"inspector-command-row__route\">{{\n checkpoint.route\n }}</span>\n <span\n class=\"inspector-command-row__separator\"\n aria-hidden=\"true\"\n >\u00B7</span\n >\n }\n <span class=\"inspector-command-row__activity\">\n {{ checkpoint.lastUsedAt ? \"Used\" : \"Saved\" }}\n {{\n formatRelativeTime(checkpointActivityAt(checkpoint))\n }}\n </span>\n </span>\n </span>\n <span class=\"inspector-command-row__actions\">\n <button\n type=\"button\"\n (click)=\"beginRename(checkpoint, $event)\"\n [attr.aria-label]=\"'Rename ' + checkpoint.name\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"m11.8 1.8 2.4 2.4-8.3 8.3-3.1.7.7-3.1zm-8 10.4 1.5-.3-1.2-1.2z\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n (click)=\"beginDelete(checkpoint, $event)\"\n [attr.aria-label]=\"'Delete ' + checkpoint.name\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M5.5 2h5l.5 1H14v1.25H2V3h3zm-2 3.25h9L12 14H4z\"\n />\n </svg>\n </button>\n </span>\n }\n </div>\n }\n }\n </div>\n\n @if (filteredInspectorActions().length) {\n <footer\n id=\"inspector-command-actions\"\n class=\"inspector-command__actions\"\n role=\"listbox\"\n aria-label=\"Inspector actions\"\n aria-orientation=\"horizontal\"\n >\n @for (\n action of filteredInspectorActions();\n track action.id;\n let index = $index\n ) {\n <button\n type=\"button\"\n role=\"option\"\n class=\"inspector-command-action\"\n [id]=\"'inspector-action-' + action.id\"\n [attr.data-command-index]=\"filteredCheckpoints().length + index\"\n [attr.aria-label]=\"action.ariaLabel\"\n [attr.aria-selected]=\"\n activeCommandIndex() === filteredCheckpoints().length + index\n \"\n [attr.aria-disabled]=\"checkpointService.busy()\"\n [class.is-selected]=\"\n activeCommandIndex() === filteredCheckpoints().length + index\n \"\n [class.is-active]=\"\n (action.id === 'select' && toolMode() === 'select') ||\n (action.id === 'type' && showTypography()) ||\n (action.id === 'vertical' &&\n toolMode() === 'guides' &&\n guideOrientation() === 'vertical') ||\n (action.id === 'horizontal' &&\n toolMode() === 'guides' &&\n guideOrientation() === 'horizontal')\n \"\n [class.inspector-command-action--danger]=\"action.id === 'off'\"\n [disabled]=\"checkpointService.busy()\"\n (mouseenter)=\"setActiveInspectorAction(index)\"\n (click)=\"executeInspectorAction(action)\"\n >\n @switch (action.id) {\n @case (\"select\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 2l8 8-3 .7L6.7 13 6 10 3 2z\" />\n </svg>\n }\n @case (\"type\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 4V2h10v2h-4v10H7V4z\" />\n </svg>\n }\n @case (\"save\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M2.5 2h9.6l1.4 1.4V14h-11zm2 1.5v3h6v-3zm.5 6V12h6V9.5z\"\n />\n </svg>\n }\n @case (\"vertical\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M7.25 2h1.5v12h-1.5z\" />\n </svg>\n }\n @case (\"horizontal\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M2 7.25h12v1.5H2z\" />\n </svg>\n }\n @case (\"off\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M7.25 1.5h1.5v6h-1.5zM4.1 3.35l.96 1.15A4.25 4.25 0 1 0 10.94 4.5l.96-1.15A5.75 5.75 0 1 1 4.1 3.35z\"\n />\n </svg>\n }\n }\n <span>{{ action.label }}</span>\n </button>\n }\n </footer>\n }\n </section>\n </dialog>\n }\n\n @if (checkpointToast(); as toast) {\n <p\n class=\"inspector-checkpoint-toast\"\n [class.inspector-checkpoint-toast--error]=\"checkpointToastIsError()\"\n [attr.role]=\"checkpointToastIsError() ? 'alert' : 'status'\"\n >\n {{ toast }}\n </p>\n }\n\n @if (enabled() && toolMode() === \"select\") {\n @if (hoverRect() && hoverHighlightEnabled) {\n <div\n class=\"inspector-box inspector-box--hover\"\n [style.left.px]=\"hoverRect()!.left\"\n [style.top.px]=\"hoverRect()!.top\"\n [style.width.px]=\"hoverRect()!.width\"\n [style.height.px]=\"hoverRect()!.height\"\n [style.--inspector-accent]=\"highlightColor\"\n ></div>\n }\n\n @if (selectedMeasurement(); as selected) {\n @if (selected.gap.active && selected.parentRect) {\n <div\n class=\"inspector-box inspector-box--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top\"\n [style.width.px]=\"selected.parentRect.width\"\n [style.height.px]=\"selected.parentRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top - 8\"\n >\n G {{ formatGap(selected) }}\n </div>\n }\n\n <div\n class=\"inspector-box inspector-box--margin\"\n [style.left.px]=\"selected.marginRect.left\"\n [style.top.px]=\"selected.marginRect.top\"\n [style.width.px]=\"selected.marginRect.width\"\n [style.height.px]=\"selected.marginRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--margin\"\n [style.left.px]=\"selected.marginRect.left\"\n [style.top.px]=\"selected.marginRect.top - 8\"\n >\n M {{ formatEdges(selected.margin) }}\n </div>\n\n <div\n class=\"inspector-box inspector-box--selected\"\n [style.left.px]=\"selected.rect.left\"\n [style.top.px]=\"selected.rect.top\"\n [style.width.px]=\"selected.rect.width\"\n [style.height.px]=\"selected.rect.height\"\n [style.--inspector-accent]=\"highlightColor\"\n >\n <div class=\"inspector-label\">{{ selectedMetaLine() }}</div>\n </div>\n\n <div\n class=\"inspector-box inspector-box--padding\"\n [style.left.px]=\"selected.paddingRect.left\"\n [style.top.px]=\"selected.paddingRect.top\"\n [style.width.px]=\"selected.paddingRect.width\"\n [style.height.px]=\"selected.paddingRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--padding\"\n [style.left.px]=\"selected.paddingRect.left\"\n [style.top.px]=\"\n selected.paddingRect.top + selected.paddingRect.height + 8\n \"\n >\n P {{ formatEdges(selected.padding) }}\n </div>\n }\n }\n\n @if (enabled() && showTypography()) {\n @for (block of textBlocks(); track block.id) {\n <div\n class=\"inspector-text-chip\"\n [style.left.px]=\"block.rect.left\"\n [style.top.px]=\"block.rect.top - 8\"\n >\n <span\n class=\"inspector-text-chip__swatch\"\n [style.background]=\"block.styles.color\"\n ></span>\n <span>{{ block.styles.fontSize }}</span>\n <span>{{ block.styles.lineHeight }}</span>\n <span>{{ block.styles.color }}</span>\n </div>\n }\n }\n\n @if (enabled() && altPressed() && distanceOverlay(); as distance) {\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectA.left\"\n [style.top.px]=\"distance.rectA.top\"\n [style.width.px]=\"distance.rectA.width\"\n [style.height.px]=\"distance.rectA.height\"\n ></div>\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectB.left\"\n [style.top.px]=\"distance.rectB.top\"\n [style.width.px]=\"distance.rectB.width\"\n [style.height.px]=\"distance.rectB.height\"\n ></div>\n\n @for (\n connector of distance.connectors;\n track trackConnector($index, connector)\n ) {\n <div\n class=\"inspector-connector\"\n [class.inspector-connector--vertical]=\"connector.x1 === connector.x2\"\n [class.inspector-connector--horizontal]=\"connector.y1 === connector.y2\"\n [style.left.px]=\"Math.min(connector.x1, connector.x2)\"\n [style.top.px]=\"Math.min(connector.y1, connector.y2)\"\n [style.width.px]=\"Math.max(1, Math.abs(connector.x2 - connector.x1))\"\n [style.height.px]=\"Math.max(1, Math.abs(connector.y2 - connector.y1))\"\n ></div>\n }\n\n @if (distance.horizontal && distance.horizontal.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--horizontal\"\n [style.left.px]=\"\n Math.min(distance.horizontal.x1!, distance.horizontal.x2!)\n \"\n [style.top.px]=\"distance.horizontal.y!\"\n [style.width.px]=\"\n Math.abs(distance.horizontal.x2! - distance.horizontal.x1!)\n \"\n ></div>\n <div\n class=\"inspector-distance-tag\"\n [style.left.px]=\"\n (distance.horizontal.x1! + distance.horizontal.x2!) / 2\n \"\n [style.top.px]=\"distance.horizontal.y! + 10\"\n >\n {{ formatValue(distance.horizontal.value) }}\n </div>\n }\n\n @if (distance.vertical && distance.vertical.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--vertical\"\n [style.left.px]=\"distance.vertical.x!\"\n [style.top.px]=\"Math.min(distance.vertical.y1!, distance.vertical.y2!)\"\n [style.height.px]=\"\n Math.abs(distance.vertical.y2! - distance.vertical.y1!)\n \"\n ></div>\n <div\n class=\"inspector-distance-tag inspector-distance-tag--vertical\"\n [style.left.px]=\"distance.vertical.x! + 10\"\n [style.top.px]=\"(distance.vertical.y1! + distance.vertical.y2!) / 2\"\n >\n {{ formatValue(distance.vertical.value) }}\n </div>\n }\n }\n\n @if (enabled()) {\n @if (toolMode() === \"guides\") {\n @if (guidePreview(); as preview) {\n <div\n class=\"inspector-guide inspector-guide--preview\"\n [class.inspector-guide--vertical]=\"preview.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"\n preview.orientation === 'horizontal'\n \"\n [style.left.px]=\"\n preview.orientation === 'vertical' ? preview.position : null\n \"\n [style.top.px]=\"\n preview.orientation === 'horizontal' ? preview.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n >\n <span class=\"inspector-guide-line\"></span>\n </div>\n }\n }\n\n @for (guide of guides(); track guide.id) {\n <button\n type=\"button\"\n class=\"inspector-guide\"\n [class.inspector-guide--vertical]=\"guide.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"guide.orientation === 'horizontal'\"\n [class.inspector-guide--selected]=\"selectedGuideId() === guide.id\"\n [style.left.px]=\"\n guide.orientation === 'vertical' ? guide.position : null\n \"\n [style.top.px]=\"\n guide.orientation === 'horizontal' ? guide.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n [attr.aria-label]=\"\n (guide.orientation === 'vertical' ? 'Vertical' : 'Horizontal') +\n ' guide at ' +\n formatValue(guide.position) +\n ' pixels'\n \"\n (pointerdown)=\"startGuideDrag($event, guide)\"\n >\n <span class=\"inspector-guide-line\"></span>\n </button>\n }\n }\n</div>\n", styles: [":host{--inspector-panel: oklch(20% .012 280 / .92);--inspector-panel-edge: oklch(100% 0 0 / .08);--inspector-text: oklch(96% .005 280);--inspector-muted: oklch(70% .014 280);--inspector-faint: oklch(56% .012 280);--inspector-blue: oklch(68% .15 255);--inspector-blue-soft: oklch(68% .15 255 / .14);--inspector-orange: oklch(78% .14 70);--inspector-green: oklch(74% .15 150);--inspector-violet: oklch(72% .15 305);--inspector-radius: 8px;--inspector-shadow: 0 12px 32px oklch(6% .02 280 / .5);--inspector-font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--inspector-ease: cubic-bezier(.16, 1, .3, 1);position:fixed;inset:0;z-index:2147;pointer-events:none;font-family:var(--inspector-font);color:var(--inspector-text);-webkit-font-smoothing:antialiased}.inspector-root{position:fixed;inset:0;pointer-events:none}.inspector-command-dialog{--command-surface: oklch(17.5% .012 280);--command-surface-active: oklch(25% .012 280);--command-edge: oklch(100% 0 0 / .08);--command-text: oklch(96% .005 280);--command-muted: oklch(68% .014 280);--command-faint: oklch(52% .012 280);--command-accent: oklch(72% .13 255);--command-danger: oklch(68% .17 25);box-sizing:border-box;inset-block-start:max(10vh,48px);width:min(420px,calc(100vw - 24px));max-width:none;max-height:min(360px,calc(100vh - 64px));margin:0 auto;padding:0;overflow:hidden;border:1px solid var(--command-edge);border-radius:var(--inspector-radius);background:var(--command-surface);color:var(--command-text);box-shadow:var(--inspector-shadow);opacity:0;pointer-events:auto;transform:translateY(-4px);transition:opacity .1s ease,transform .1s ease,overlay .1s allow-discrete,display .1s allow-discrete;font-family:var(--inspector-font);-webkit-font-smoothing:antialiased}.inspector-command-dialog[open]{opacity:1;transform:none;transition-duration:.14s;transition-timing-function:var(--inspector-ease)}@starting-style{.inspector-command-dialog[open]{opacity:0;transform:translateY(-4px)}}.inspector-command-dialog::backdrop{background:#01010266}.inspector-command{display:grid;grid-template-rows:auto auto 1fr auto;min-width:0;min-height:0;max-height:min(360px,calc(100vh - 64px))}.inspector-command__search{display:flex;align-items:center;gap:8px;min-height:40px;padding:0 11px;border-bottom:1px solid var(--command-edge)}.inspector-command__pet-switcher{display:block;width:28px;height:28px;flex:0 0 auto;padding:0;overflow:hidden;border:0;border-radius:4px;background:transparent;cursor:pointer;opacity:.72;transition:opacity .14s var(--inspector-ease),transform .1s var(--inspector-ease)}.inspector-command__pet-sprite{display:block;width:500%;height:100%;max-width:none;image-rendering:pixelated;-webkit-user-select:none;user-select:none;transform:translate(0)}.inspector-command__search:focus-within .inspector-command__pet-switcher,.inspector-command__pet-switcher:hover,.inspector-command__pet-switcher:focus-visible{opacity:1}.inspector-command__pet-switcher:hover,.inspector-command__pet-switcher:focus-visible{background:#6aa7f41f}.inspector-command__pet-switcher:active{transform:scale(.94)}.inspector-command__pet-switcher:focus-visible{outline:1px solid var(--command-accent);outline-offset:1px}@media (prefers-reduced-motion: no-preference){.inspector-command__search:focus-within .inspector-command__pet-sprite{animation:inspector-pet-cycle 1s steps(1,end) infinite}}@keyframes inspector-pet-cycle{0%,19.99%{transform:translate(0)}20%,39.99%{transform:translate(-20%)}40%,59.99%{transform:translate(-40%)}60%,79.99%{transform:translate(-60%)}80%,to{transform:translate(-80%)}}.inspector-command__search input,.inspector-command-row__rename{min-width:0;border:0;outline:0;background:transparent;color:var(--command-text);font:inherit}.inspector-command__search input{flex:1 1 auto;width:100%;height:39px;padding:0;font-size:13px;font-weight:450;line-height:1.3}.inspector-command__search input::placeholder{color:var(--command-faint);opacity:1}.inspector-command__search input::-webkit-search-cancel-button{display:none}.inspector-command__results{min-height:0;max-height:260px;overflow:auto;padding:5px;scrollbar-width:thin;scrollbar-color:oklch(100% 0 0 / .1) transparent}.inspector-command-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:6px;min-height:34px;padding:0 7px 0 9px;border-radius:5px;cursor:pointer;-webkit-user-select:none;user-select:none}.inspector-command-row.is-active{background:var(--command-surface-active);box-shadow:inset 0 0 0 1px #6aa7f49e}.inspector-command-row.is-busy{cursor:wait;pointer-events:none;opacity:.7}.inspector-command-row__content{display:flex;align-items:baseline;gap:8px;min-width:0;overflow:hidden}.inspector-command-row__name{flex:0 1 auto;min-width:3ch;overflow:hidden;color:var(--command-text);font-size:12px;font-weight:500;line-height:1.25;text-overflow:ellipsis;white-space:nowrap}.inspector-command-row__meta{display:inline-flex;flex:0 1 auto;align-items:baseline;gap:4px;min-width:0;overflow:hidden;color:var(--command-faint);font-size:11px;font-weight:400;line-height:1.25;text-overflow:ellipsis;white-space:nowrap}.inspector-command-row__route{min-width:0;overflow:hidden;text-overflow:ellipsis}.inspector-command-row__separator,.inspector-command-row__activity{flex:0 0 auto}.inspector-command-row.is-active .inspector-command-row__meta{color:#c2c3cc}.inspector-command-row__actions,.inspector-command-row__confirm-actions{display:flex;align-items:center;gap:1px}.inspector-command-row__actions{opacity:0;pointer-events:none}.inspector-command-row:hover .inspector-command-row__actions,.inspector-command-row:focus-within .inspector-command-row__actions{opacity:1;pointer-events:auto}.inspector-command-row button{display:inline-grid;width:22px;min-height:22px;padding:0;place-items:center;border:0;border-radius:4px;background:transparent;color:var(--command-muted);cursor:pointer;font-family:inherit;font-size:10px;font-weight:550;line-height:1.2}.inspector-command-row button svg{width:11px;height:11px;fill:currentColor}.inspector-command-row button:hover{background:#ffffff12;color:var(--command-text)}.inspector-command-row button.is-danger{width:auto;padding:0 7px;color:var(--command-danger);font-size:11px}.inspector-command-row button.is-danger:hover{background:#ef66611f}.inspector-command-row__confirm-actions button:not(.is-danger){width:auto;padding:0 7px;font-size:11px}.inspector-command-row button:focus-visible,.inspector-command-row__rename:focus-visible{outline:1px solid var(--command-accent);outline-offset:1px}.inspector-command-row__confirm{grid-column:1;color:var(--command-text);font-size:12px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.inspector-command-row__rename{grid-column:1 / -1;min-height:26px;padding-inline:6px;border:1px solid oklch(72% .13 255 / .4);border-radius:4px;background:#191a21;font-size:12px;font-weight:500}.inspector-command__message{margin:0;padding:16px 10px;color:var(--command-faint);font-size:12px;line-height:1.4;text-align:center}.inspector-command__message--error{padding:6px 10px;border-bottom:1px solid oklch(55% .08 25 / .3);background:#39191780;color:#f7cbc7;text-align:left;font-size:11px}.inspector-command__actions{display:flex;gap:2px;padding:4px;border-top:1px solid var(--command-edge)}.inspector-command-action{display:flex;flex:1 1 0;min-width:0;min-height:28px;align-items:center;justify-content:center;gap:4px;padding:0 4px;overflow:hidden;border:0;border-radius:5px;background:transparent;color:var(--command-muted);cursor:pointer;font:inherit;font-size:10px;font-weight:500;line-height:1;text-align:left}.inspector-command-action svg{width:11px;height:11px;flex:0 0 auto;fill:currentColor}.inspector-command-action span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.inspector-command-action:hover:not(:disabled){background:#ffffff0f;color:var(--command-text)}.inspector-command-action.is-active{background:#6aa7f421;color:#c2daf9}.inspector-command-action.is-selected,.inspector-command-action.is-selected:hover:not(:disabled){background:var(--command-surface-active);color:var(--command-text);box-shadow:inset 0 0 0 1px #6aa7f49e}.inspector-command-action--danger:hover:not(:disabled){background:#ef66611a;color:#f5b9b4}.inspector-command-action:disabled{cursor:wait;opacity:.45}.inspector-command-action:focus-visible{outline:1px solid var(--command-accent);outline-offset:-1px}.inspector-visually-hidden{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.inspector-checkpoint-toast{position:fixed;top:10px;left:50%;z-index:500;margin:0;padding:5px 10px;border:1px solid oklch(74% .12 150 / .25);border-radius:999px;background:#0e1f12f0;color:#cce6d0;box-shadow:var(--inspector-shadow);font-size:11px;font-weight:520;line-height:1.25;pointer-events:none;transform:translate(-50%)}.inspector-checkpoint-toast--error{border-color:#e2726b4d;background:#351311f0;color:#fed2cd}@media (prefers-reduced-motion: reduce){.inspector-command-dialog{transition-duration:.01ms!important}.inspector-command-dialog,.inspector-command-dialog[open]{transform:none}.inspector-command__pet-switcher{transition:none}.inspector-command__pet-sprite{animation:none;transform:translate(0)}}.inspector-box{position:fixed;box-sizing:border-box;pointer-events:none;border:1px solid var(--inspector-accent, var(--inspector-blue));background:color-mix(in srgb,var(--inspector-accent, var(--inspector-blue)) 8%,transparent)}.inspector-box--hover{opacity:.55}.inspector-box--selected{border-width:1.5px}.inspector-box--margin{border-color:#f0a646d1;background:#f0a64614}.inspector-box--padding{border-color:#5ac576d1;background:#5ac57614}.inspector-box--gap{border-color:#bb8aefb8;background:#bb8aef0d}.inspector-box--distance{border-style:dashed;border-color:#539af2b3;background:transparent}.inspector-label,.inspector-box-tag,.inspector-text-chip,.inspector-distance-tag{font-variant-numeric:tabular-nums}.inspector-label{position:absolute;left:0;top:0;transform:translateY(calc(-100% - 6px));max-width:min(380px,calc(100vw - 20px));padding:4px 7px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:var(--inspector-panel);color:var(--inspector-text);box-shadow:var(--inspector-shadow);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);font-size:10px;font-weight:500;line-height:1.2;white-space:nowrap}.inspector-box-tag{position:fixed;transform:translateY(-100%);padding:3px 5px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#0e0f15f0;color:var(--inspector-text);font-size:9px;font-weight:520;line-height:1;pointer-events:none}.inspector-box-tag--margin{color:#f5c076}.inspector-box-tag--padding{color:#95dfa4;transform:translateY(0)}.inspector-box-tag--gap{color:oklch(86% .09 305)}.inspector-text-chip{position:fixed;transform:translateY(-100%);display:inline-flex;gap:5px;align-items:center;padding:3px 6px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#0e0f15f0;color:#e4e4e9;font-size:9px;font-weight:500;line-height:1;white-space:nowrap;pointer-events:none}.inspector-text-chip__swatch{width:7px;height:7px;border-radius:999px;border:1px solid oklch(100% 0 0 / .16);flex:0 0 auto}.inspector-connector{position:fixed;border-color:#539af2b8;border-style:dashed;pointer-events:none}.inspector-connector--vertical{border-left-width:1px;width:0}.inspector-connector--horizontal{border-top-width:1px;height:0}.inspector-distance-line{position:fixed;background:var(--inspector-blue);pointer-events:none}.inspector-distance-line--horizontal{height:1px}.inspector-distance-line--vertical{width:1px}.inspector-distance-tag{position:fixed;transform:translate(-50%);padding:3px 6px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#0e0f15f2;color:var(--inspector-text);font-size:9px;font-weight:520;line-height:1;pointer-events:none}.inspector-distance-tag--vertical{transform:translateY(-50%)}.inspector-guide{position:fixed;margin:0;padding:0;border:0;background:transparent;pointer-events:auto;cursor:grab}.inspector-guide--vertical{top:0;width:14px;height:100vh;transform:translate(-50%)}.inspector-guide--horizontal{left:0;width:100vw;height:14px;transform:translateY(-50%)}.inspector-guide--preview{opacity:.55;pointer-events:none;cursor:default}.inspector-guide--preview .inspector-guide-line{background:color-mix(in srgb,var(--inspector-guide, #ff7a00) 72%,transparent)}.inspector-guide-line{position:absolute;inset:0;pointer-events:none}.inspector-guide--vertical .inspector-guide-line{left:calc(50% - .5px);width:1px;height:100%;background:var(--inspector-guide, #ff7a00)}.inspector-guide--horizontal .inspector-guide-line{top:calc(50% - .5px);width:100%;height:1px;background:var(--inspector-guide, #ff7a00)}.inspector-guide--selected .inspector-guide-line{box-shadow:0 0 0 1px #ffffff80}@media (min-width: 769px) and (min-height: 769px){:host{--inspector-radius: 14px;--inspector-shadow: 0 21px 56px oklch(6% .02 280 / .5)}.inspector-command-dialog{inset-block-start:max(10vh,84px);width:min(735px,calc(100vw - 42px));max-height:min(630px,calc(100vh - 112px))}.inspector-command{max-height:min(630px,calc(100vh - 112px))}.inspector-command__search{gap:14px;min-height:70px;padding:0 19.25px}.inspector-command__pet-switcher{width:42px;height:42px}.inspector-command__search input{height:68.25px;font-size:22.75px}.inspector-command__results{max-height:455px;padding:8.75px}.inspector-command-row{gap:10.5px;min-height:59.5px;padding:0 12.25px 0 15.75px;border-radius:8.75px}.inspector-command-row__content{gap:14px}.inspector-command-row__name,.inspector-command-row__confirm{font-size:21px}.inspector-command-row__meta{gap:7px;font-size:19.25px}.inspector-command-row__actions,.inspector-command-row__confirm-actions{gap:1.75px}.inspector-command-row button{width:38.5px;min-height:38.5px;border-radius:7px;font-size:17.5px}.inspector-command-row button svg{width:19.25px;height:19.25px}.inspector-command-row button.is-danger,.inspector-command-row__confirm-actions button:not(.is-danger){padding:0 12.25px;font-size:19.25px}.inspector-command-row__rename{min-height:45.5px;padding-inline:10.5px;border-radius:7px;font-size:21px}.inspector-command__message{padding:28px 17.5px;font-size:21px}.inspector-command__message--error{padding:10.5px 17.5px;font-size:19.25px}.inspector-command__actions{gap:3.5px;padding:7px}.inspector-command-action{min-height:49px;gap:7px;padding:0 7px;border-radius:8.75px;font-size:17.5px}.inspector-command-action svg{width:19.25px;height:19.25px}.inspector-checkpoint-toast{top:17.5px;padding:8.75px 17.5px;font-size:19.25px}.inspector-label{transform:translateY(calc(-100% - 10.5px));max-width:min(665px,calc(100vw - 35px));padding:7px 12.25px;font-size:17.5px}.inspector-box-tag{padding:5.25px 8.75px;font-size:15.75px}.inspector-box-tag--padding{transform:translateY(0)}.inspector-text-chip{gap:8.75px;padding:5.25px 10.5px;font-size:15.75px}.inspector-text-chip__swatch{width:12.25px;height:12.25px}.inspector-distance-tag{padding:5.25px 10.5px;font-size:15.75px}.inspector-guide--vertical{width:24.5px}.inspector-guide--horizontal{height:24.5px}}\n"] }]
|
|
1964
|
+
args: [{ selector: 'inspector-overlay', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"inspector-root\" #overlayRoot>\n @if (checkpointService) {\n <dialog\n #checkpointDialog\n class=\"inspector-command-dialog\"\n aria-labelledby=\"inspector-command-title\"\n (cancel)=\"$event.preventDefault(); closeCheckpointCommandBar()\"\n (click)=\"handleCheckpointDialogClick($event)\"\n >\n <section class=\"inspector-command\" (click)=\"$event.stopPropagation()\">\n <header class=\"inspector-command__search\">\n <label\n id=\"inspector-command-title\"\n class=\"inspector-visually-hidden\"\n for=\"inspector-checkpoint-search\"\n >\n inspector-ng command palette\n </label>\n <button\n type=\"button\"\n class=\"inspector-command__pet-switcher\"\n [attr.aria-label]=\"'Change pet. Current pet: ' + activePet().name\"\n [title]=\"'Change pet: ' + activePet().name\"\n (click)=\"cyclePet($event)\"\n >\n <img\n class=\"inspector-command__pet-sprite\"\n [src]=\"activePet().spriteSrc\"\n alt=\"\"\n aria-hidden=\"true\"\n draggable=\"false\"\n />\n </button>\n <input\n #checkpointSearch\n id=\"inspector-checkpoint-search\"\n type=\"search\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n placeholder=\"inspector-ng\u2026\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"commandBarOpen()\"\n [value]=\"checkpointQuery()\"\n [attr.aria-controls]=\"'inspector-checkpoint-results inspector-command-actions'\"\n [attr.aria-activedescendant]=\"activeCommandResultId()\"\n (input)=\"updateCheckpointQuery($event)\"\n />\n </header>\n\n @if (checkpointService.error(); as error) {\n <p\n class=\"inspector-command__message inspector-command__message--error\"\n role=\"alert\"\n >\n {{ error }}\n </p>\n }\n\n <div\n id=\"inspector-checkpoint-results\"\n class=\"inspector-command__results\"\n role=\"listbox\"\n aria-label=\"Saved checkpoints\"\n >\n @if (checkpointService.loading()) {\n <p class=\"inspector-command__message\" role=\"status\">Loading\u2026</p>\n } @else if (\n !checkpointService.checkpoints().length && !checkpointQuery().trim()\n ) {\n <p class=\"inspector-command__message\" role=\"status\">\n No checkpoints yet\n </p>\n } @else if (\n !filteredCheckpoints().length &&\n !filteredInspectorActions().length &&\n !navigateTarget()\n ) {\n <p class=\"inspector-command__message\" role=\"status\">No matches</p>\n } @else {\n @for (\n checkpoint of filteredCheckpoints();\n track checkpoint.id;\n let index = $index\n ) {\n <div\n class=\"inspector-command-row\"\n role=\"option\"\n [id]=\"'inspector-checkpoint-' + checkpoint.id\"\n [attr.data-command-index]=\"index\"\n [attr.aria-selected]=\"activeCommandIndex() === index\"\n [class.is-active]=\"activeCommandIndex() === index\"\n [class.is-busy]=\"\n checkpointService.busy() && activeCommandIndex() === index\n \"\n (mouseenter)=\"setActiveCheckpoint(index)\"\n (click)=\"activateCheckpoint(checkpoint, $event)\"\n >\n @if (deletingCheckpointId() === checkpoint.id) {\n <span class=\"inspector-command-row__confirm\"\n >Delete \u201C{{ checkpoint.name }}\u201D?</span\n >\n <span class=\"inspector-command-row__confirm-actions\">\n <button\n type=\"button\"\n class=\"is-danger\"\n (click)=\"confirmDelete(checkpoint, $event)\"\n >\n Delete\n </button>\n <button type=\"button\" (click)=\"cancelDelete($event)\">\n Keep\n </button>\n </span>\n } @else if (editingCheckpointId() === checkpoint.id) {\n <input\n #checkpointRename\n class=\"inspector-command-row__rename\"\n aria-label=\"Checkpoint name\"\n [value]=\"renameDraft()\"\n (input)=\"updateRenameDraft($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n } @else {\n <span class=\"inspector-command-row__content\">\n <span\n class=\"inspector-command-row__name\"\n [title]=\"checkpoint.name\"\n >\n <bdi dir=\"ltr\">\n @if (\n checkpointService.busy() &&\n activeCommandIndex() === index\n ) {\n Restoring\u2026\n } @else {\n {{ checkpoint.name }}\n }\n </bdi>\n </span>\n <span class=\"inspector-command-row__activity\">\n {{ checkpoint.lastUsedAt ? \"Used\" : \"Saved\" }}\n {{\n formatRelativeTime(checkpointActivityAt(checkpoint))\n }}\n </span>\n </span>\n <span class=\"inspector-command-row__actions\">\n <button\n type=\"button\"\n (click)=\"beginRename(checkpoint, $event)\"\n [attr.aria-label]=\"'Rename ' + checkpoint.name\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"m11.8 1.8 2.4 2.4-8.3 8.3-3.1.7.7-3.1zm-8 10.4 1.5-.3-1.2-1.2z\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n (click)=\"downloadCheckpoint(checkpoint, $event)\"\n [attr.aria-label]=\"'Export ' + checkpoint.name\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M7.25 2h1.5v5.44l1.72-1.72L11.53 6.78 8 10.31 4.47 6.78l1.06-1.06 1.72 1.72zM2.5 12h11v1.5h-11z\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n (click)=\"beginDelete(checkpoint, $event)\"\n [attr.aria-label]=\"'Delete ' + checkpoint.name\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M5.5 2h5l.5 1H14v1.25H2V3h3zm-2 3.25h9L12 14H4z\"\n />\n </svg>\n </button>\n </span>\n }\n </div>\n }\n @if (navigateTarget(); as target) {\n <div\n class=\"inspector-command-row inspector-command-row--navigate\"\n role=\"option\"\n id=\"inspector-navigate\"\n [attr.data-command-index]=\"filteredCheckpoints().length\"\n [attr.aria-selected]=\"\n activeCommandIndex() === filteredCheckpoints().length\n \"\n [class.is-active]=\"\n activeCommandIndex() === filteredCheckpoints().length\n \"\n [class.is-busy]=\"\n checkpointService.busy() &&\n activeCommandIndex() === filteredCheckpoints().length\n \"\n (mouseenter)=\"setActiveCheckpoint(filteredCheckpoints().length)\"\n (click)=\"navigateToQueryRoute()\"\n >\n <span class=\"inspector-command-row__content\">\n <span\n class=\"inspector-command-row__name\"\n [title]=\"'Navigate to ' + target\"\n >\n <bdi dir=\"ltr\">\n @if (\n checkpointService.busy() &&\n activeCommandIndex() === filteredCheckpoints().length\n ) {\n Navigating\u2026\n } @else {\n Go to {{ target }}\n }\n </bdi>\n </span>\n <span class=\"inspector-command-row__activity\">\n navigate \u00B7 keeps state\n </span>\n </span>\n </div>\n }\n }\n </div>\n\n @if (filteredInspectorActions().length) {\n <footer\n id=\"inspector-command-actions\"\n class=\"inspector-command__actions\"\n role=\"listbox\"\n aria-label=\"Inspector actions\"\n aria-orientation=\"horizontal\"\n >\n @for (\n action of filteredInspectorActions();\n track action.id;\n let index = $index\n ) {\n <button\n type=\"button\"\n role=\"option\"\n class=\"inspector-command-action\"\n [id]=\"'inspector-action-' + action.id\"\n [attr.data-command-index]=\"actionIndexOffset() + index\"\n [attr.aria-label]=\"action.ariaLabel\"\n [attr.aria-selected]=\"\n activeCommandIndex() === actionIndexOffset() + index\n \"\n [attr.aria-disabled]=\"checkpointService.busy()\"\n [class.is-selected]=\"\n activeCommandIndex() === actionIndexOffset() + index\n \"\n [class.is-active]=\"\n (action.id === 'select' && toolMode() === 'select') ||\n (action.id === 'type' && showTypography()) ||\n (action.id === 'vertical' &&\n toolMode() === 'guides' &&\n guideOrientation() === 'vertical') ||\n (action.id === 'horizontal' &&\n toolMode() === 'guides' &&\n guideOrientation() === 'horizontal')\n \"\n [disabled]=\"checkpointService.busy()\"\n (mouseenter)=\"setActiveInspectorAction(index)\"\n (click)=\"executeInspectorAction(action)\"\n >\n @switch (action.id) {\n @case (\"select\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 2l8 8-3 .7L6.7 13 6 10 3 2z\" />\n </svg>\n }\n @case (\"type\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 4V2h10v2h-4v10H7V4z\" />\n </svg>\n }\n @case (\"save\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M2.5 2h9.6l1.4 1.4V14h-11zm2 1.5v3h6v-3zm.5 6V12h6V9.5z\"\n />\n </svg>\n }\n @case (\"import\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M8 2l3.53 3.53-1.06 1.06L8.75 4.87V9.5h-1.5V4.87L5.53 6.59 4.47 5.53zM2.5 11h11v1.5h-11z\"\n />\n </svg>\n }\n @case (\"vertical\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M7.25 2h1.5v12h-1.5z\" />\n </svg>\n }\n @case (\"horizontal\") {\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M2 7.25h12v1.5H2z\" />\n </svg>\n }\n }\n <span>{{ action.label }}</span>\n </button>\n }\n </footer>\n }\n </section>\n </dialog>\n }\n\n @if (checkpointToast(); as toast) {\n <p\n class=\"inspector-checkpoint-toast\"\n [class.inspector-checkpoint-toast--error]=\"checkpointToastIsError()\"\n [attr.role]=\"checkpointToastIsError() ? 'alert' : 'status'\"\n >\n {{ toast }}\n </p>\n }\n\n @if (enabled() && toolMode() === \"select\") {\n @if (hoverRect() && hoverHighlightEnabled) {\n <div\n class=\"inspector-box inspector-box--hover\"\n [style.left.px]=\"hoverRect()!.left\"\n [style.top.px]=\"hoverRect()!.top\"\n [style.width.px]=\"hoverRect()!.width\"\n [style.height.px]=\"hoverRect()!.height\"\n [style.--inspector-accent]=\"highlightColor\"\n ></div>\n }\n\n @if (selectedMeasurement(); as selected) {\n @if (selected.gap.active && selected.parentRect) {\n <div\n class=\"inspector-box inspector-box--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top\"\n [style.width.px]=\"selected.parentRect.width\"\n [style.height.px]=\"selected.parentRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top - 8\"\n >\n G {{ formatGap(selected) }}\n </div>\n }\n\n <div\n class=\"inspector-box inspector-box--margin\"\n [style.left.px]=\"selected.marginRect.left\"\n [style.top.px]=\"selected.marginRect.top\"\n [style.width.px]=\"selected.marginRect.width\"\n [style.height.px]=\"selected.marginRect.height\"\n ></div>\n\n <div\n class=\"inspector-box inspector-box--selected\"\n [style.left.px]=\"selected.rect.left\"\n [style.top.px]=\"selected.rect.top\"\n [style.width.px]=\"selected.rect.width\"\n [style.height.px]=\"selected.rect.height\"\n [style.--inspector-accent]=\"highlightColor\"\n >\n <div class=\"inspector-label\">{{ selectedMetaLine() }}</div>\n </div>\n\n <div\n class=\"inspector-box inspector-box--padding\"\n [style.left.px]=\"selected.paddingRect.left\"\n [style.top.px]=\"selected.paddingRect.top\"\n [style.width.px]=\"selected.paddingRect.width\"\n [style.height.px]=\"selected.paddingRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--spacing\"\n [style.left.px]=\"selected.rect.left\"\n [style.top.px]=\"selected.rect.top + selected.rect.height + 8\"\n >\n <span class=\"inspector-box-tag__margin\">M</span>\n <span>{{ formatEdges(selected.margin) }}</span>\n <span class=\"inspector-box-tag__separator\">\u00B7</span>\n <span class=\"inspector-box-tag__padding\">P</span>\n <span>{{ formatEdges(selected.padding) }}</span>\n </div>\n }\n }\n\n @if (enabled() && showTypography()) {\n @for (block of textBlocks(); track block.id) {\n <div\n class=\"inspector-text-chip\"\n [style.left.px]=\"block.rect.left\"\n [style.top.px]=\"block.rect.top - 8\"\n >\n <span\n class=\"inspector-text-chip__swatch\"\n [style.background]=\"block.styles.color\"\n ></span>\n <span>{{ block.styles.fontSize }}</span>\n <span>{{ block.styles.lineHeight }}</span>\n <span>{{ block.styles.color }}</span>\n </div>\n }\n }\n\n @if (enabled() && altPressed() && distanceOverlay(); as distance) {\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectA.left\"\n [style.top.px]=\"distance.rectA.top\"\n [style.width.px]=\"distance.rectA.width\"\n [style.height.px]=\"distance.rectA.height\"\n ></div>\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectB.left\"\n [style.top.px]=\"distance.rectB.top\"\n [style.width.px]=\"distance.rectB.width\"\n [style.height.px]=\"distance.rectB.height\"\n ></div>\n\n @for (\n connector of distance.connectors;\n track trackConnector($index, connector)\n ) {\n <div\n class=\"inspector-connector\"\n [class.inspector-connector--vertical]=\"connector.x1 === connector.x2\"\n [class.inspector-connector--horizontal]=\"connector.y1 === connector.y2\"\n [style.left.px]=\"Math.min(connector.x1, connector.x2)\"\n [style.top.px]=\"Math.min(connector.y1, connector.y2)\"\n [style.width.px]=\"Math.max(1, Math.abs(connector.x2 - connector.x1))\"\n [style.height.px]=\"Math.max(1, Math.abs(connector.y2 - connector.y1))\"\n ></div>\n }\n\n @for (horizontal of distance.horizontalDistances; track $index) {\n @if (horizontal.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--horizontal\"\n [style.left.px]=\"Math.min(horizontal.x1!, horizontal.x2!)\"\n [style.top.px]=\"horizontal.y!\"\n [style.width.px]=\"Math.abs(horizontal.x2! - horizontal.x1!)\"\n ></div>\n <div\n class=\"inspector-distance-tag\"\n [style.left.px]=\"(horizontal.x1! + horizontal.x2!) / 2\"\n [style.top.px]=\"horizontal.y!\"\n >\n {{ formatValue(horizontal.value) }}\n </div>\n }\n }\n\n @for (vertical of distance.verticalDistances; track $index) {\n @if (vertical.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--vertical\"\n [style.left.px]=\"vertical.x!\"\n [style.top.px]=\"Math.min(vertical.y1!, vertical.y2!)\"\n [style.height.px]=\"Math.abs(vertical.y2! - vertical.y1!)\"\n ></div>\n <div\n class=\"inspector-distance-tag inspector-distance-tag--vertical\"\n [style.left.px]=\"vertical.x!\"\n [style.top.px]=\"(vertical.y1! + vertical.y2!) / 2\"\n >\n {{ formatValue(vertical.value) }}\n </div>\n }\n }\n }\n\n @if (enabled()) {\n @if (toolMode() === \"guides\") {\n @if (guidePreview(); as preview) {\n <div\n class=\"inspector-guide inspector-guide--preview\"\n [class.inspector-guide--vertical]=\"preview.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"\n preview.orientation === 'horizontal'\n \"\n [style.left.px]=\"\n preview.orientation === 'vertical' ? preview.position : null\n \"\n [style.top.px]=\"\n preview.orientation === 'horizontal' ? preview.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n >\n <span class=\"inspector-guide-line\"></span>\n </div>\n }\n }\n\n @for (guide of guides(); track guide.id) {\n <button\n type=\"button\"\n class=\"inspector-guide\"\n [class.inspector-guide--vertical]=\"guide.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"guide.orientation === 'horizontal'\"\n [class.inspector-guide--selected]=\"selectedGuideId() === guide.id\"\n [style.left.px]=\"\n guide.orientation === 'vertical' ? guide.position : null\n \"\n [style.top.px]=\"\n guide.orientation === 'horizontal' ? guide.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n [attr.aria-label]=\"\n (guide.orientation === 'vertical' ? 'Vertical' : 'Horizontal') +\n ' guide at ' +\n formatValue(guide.position) +\n ' pixels'\n \"\n (pointerdown)=\"startGuideDrag($event, guide)\"\n >\n <span class=\"inspector-guide-line\"></span>\n </button>\n }\n\n @for (distance of guideDistances(); track distance.orientation + \"-\" + distance.start + \"-\" + distance.end) {\n <div\n class=\"inspector-guide-distance\"\n [class.inspector-guide-distance--vertical]=\"distance.orientation === 'vertical'\"\n [class.inspector-guide-distance--horizontal]=\"distance.orientation === 'horizontal'\"\n [style.left.px]=\"distance.orientation === 'vertical' ? distance.start : null\"\n [style.top.px]=\"distance.orientation === 'horizontal' ? distance.start : null\"\n [style.width.px]=\"distance.orientation === 'vertical' ? distance.value : null\"\n [style.height.px]=\"distance.orientation === 'horizontal' ? distance.value : null\"\n [style.--inspector-guide]=\"guideColor\"\n aria-hidden=\"true\"\n >\n <span class=\"inspector-guide-distance__line\"></span>\n <span class=\"inspector-guide-distance__tag\">\n {{ formatValue(distance.value) }} px\n </span>\n </div>\n }\n }\n</div>\n", styles: [":host{--inspector-panel: oklch(20% .012 280 / .92);--inspector-panel-edge: oklch(100% 0 0 / .08);--inspector-text: oklch(96% .005 280);--inspector-muted: oklch(70% .014 280);--inspector-faint: oklch(56% .012 280);--inspector-blue: oklch(68% .15 255);--inspector-blue-soft: oklch(68% .15 255 / .14);--inspector-orange: oklch(78% .14 70);--inspector-green: oklch(74% .15 150);--inspector-violet: oklch(72% .15 305);--inspector-radius: 8px;--inspector-shadow: 0 12px 32px oklch(6% .02 280 / .5);--inspector-font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--inspector-ease: cubic-bezier(.16, 1, .3, 1);position:fixed;inset:0;z-index:2147;pointer-events:none;font-family:var(--inspector-font);color:var(--inspector-text);-webkit-font-smoothing:antialiased}.inspector-root{position:fixed;inset:0;pointer-events:none}.inspector-command-dialog{--command-surface: oklch(17.5% .012 280);--command-surface-active: oklch(25% .012 280);--command-edge: oklch(100% 0 0 / .08);--command-text: oklch(96% .005 280);--command-muted: oklch(68% .014 280);--command-faint: oklch(52% .012 280);--command-accent: oklch(72% .13 255);--command-danger: oklch(68% .17 25);box-sizing:border-box;inset-block-start:max(10vh,48px);width:min(420px,calc(100vw - 24px));max-width:none;max-height:min(360px,calc(100vh - 64px));margin:0 auto;padding:0;overflow:hidden;border:1px solid var(--command-edge);border-radius:var(--inspector-radius);background:var(--command-surface);color:var(--command-text);box-shadow:var(--inspector-shadow);opacity:0;pointer-events:auto;transform:translateY(-4px);transition:opacity .1s ease,transform .1s ease,overlay .1s allow-discrete,display .1s allow-discrete;font-family:var(--inspector-font);-webkit-font-smoothing:antialiased}.inspector-command-dialog[open]{opacity:1;transform:none;transition-duration:.14s;transition-timing-function:var(--inspector-ease)}@starting-style{.inspector-command-dialog[open]{opacity:0;transform:translateY(-4px)}}.inspector-command-dialog::backdrop{background:#01010266}.inspector-command{display:grid;grid-template-rows:auto auto 1fr auto;min-width:0;min-height:0;max-height:min(360px,calc(100vh - 64px))}.inspector-command__search{display:flex;align-items:center;gap:8px;min-height:40px;padding:0 11px;border-bottom:1px solid var(--command-edge)}.inspector-command__pet-switcher{display:block;width:28px;height:28px;flex:0 0 auto;padding:0;overflow:hidden;border:0;border-radius:4px;background:transparent;cursor:pointer;opacity:.72;transition:opacity .14s var(--inspector-ease),transform .1s var(--inspector-ease)}.inspector-command__pet-sprite{display:block;width:500%;height:100%;max-width:none;image-rendering:pixelated;-webkit-user-select:none;user-select:none;transform:translate(0)}.inspector-command__search:focus-within .inspector-command__pet-switcher,.inspector-command__pet-switcher:hover,.inspector-command__pet-switcher:focus-visible{opacity:1}.inspector-command__pet-switcher:hover,.inspector-command__pet-switcher:focus-visible{background:#6aa7f41f}.inspector-command__pet-switcher:active{transform:scale(.94)}.inspector-command__pet-switcher:focus-visible{outline:1px solid var(--command-accent);outline-offset:1px}@media (prefers-reduced-motion: no-preference){.inspector-command__pet-sprite{animation:inspector-pet-cycle 1s steps(1,end) infinite}}@keyframes inspector-pet-cycle{0%,19.99%{transform:translate(0)}20%,39.99%{transform:translate(-20%)}40%,59.99%{transform:translate(-40%)}60%,79.99%{transform:translate(-60%)}80%,to{transform:translate(-80%)}}.inspector-command__search input,.inspector-command-row__rename{min-width:0;border:0;outline:0;background:transparent;color:var(--command-text);font:inherit}.inspector-command__search input{flex:1 1 auto;width:100%;height:39px;padding:0;font-size:13px;font-weight:450;line-height:1.3}.inspector-command__search input::placeholder{color:var(--command-faint);opacity:1}.inspector-command__search input::-webkit-search-cancel-button{display:none}.inspector-command__results{min-height:0;max-height:260px;overflow:auto;padding:5px;scrollbar-width:thin;scrollbar-color:oklch(100% 0 0 / .1) transparent}.inspector-command-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:6px;min-height:34px;padding:0 7px 0 9px;border-radius:5px;cursor:pointer;-webkit-user-select:none;user-select:none}.inspector-command-row.is-active{background:color-mix(in oklch,var(--command-surface-active) 92%,var(--command-accent));box-shadow:inset 0 0 0 1px #6aa7f452}.inspector-command-row.is-busy{cursor:wait;pointer-events:none;opacity:.7}.inspector-command-row__content{display:flex;align-items:baseline;gap:6px;min-width:0;overflow:hidden}.inspector-command-row__name{flex:0 1 auto;min-width:3ch;overflow:hidden;color:var(--command-text);font-size:12px;font-weight:500;line-height:1.25;text-overflow:ellipsis;white-space:nowrap;direction:rtl;text-align:left}.inspector-command-row__name bdi{direction:ltr;unicode-bidi:isolate}.inspector-command-row__activity{flex:0 0 auto;color:var(--command-faint);font-size:9px;font-weight:450;line-height:1;white-space:nowrap}.inspector-command-row.is-active .inspector-command-row__activity{color:#c2c3cc}.inspector-command-row--navigate{margin-top:4px;padding-top:5px;border-top:1px dashed var(--command-edge)}.inspector-command-row--navigate .inspector-command-row__name{color:color-mix(in oklch,var(--command-text) 78%,var(--command-accent))}.inspector-command-row--navigate .inspector-command-row__name:before{content:\"\\2192 \";color:var(--command-accent)}.inspector-command-row__actions,.inspector-command-row__confirm-actions{display:flex;align-items:center;gap:1px}.inspector-command-row__actions{opacity:0;pointer-events:none}.inspector-command-row.is-active .inspector-command-row__actions,.inspector-command-row:hover .inspector-command-row__actions,.inspector-command-row:focus-within .inspector-command-row__actions{opacity:1;pointer-events:auto}.inspector-command-row button{display:inline-grid;width:22px;min-height:22px;padding:0;place-items:center;border:0;border-radius:4px;background:transparent;color:var(--command-muted);cursor:pointer;font-family:inherit;font-size:10px;font-weight:550;line-height:1.2}.inspector-command-row button svg{width:11px;height:11px;fill:currentColor}.inspector-command-row button:hover{background:#ffffff12;color:var(--command-text)}.inspector-command-row button.is-danger{width:auto;padding:0 7px;color:var(--command-danger);font-size:11px}.inspector-command-row button.is-danger:hover{background:#ef66611f}.inspector-command-row__confirm-actions button:not(.is-danger){width:auto;padding:0 7px;font-size:11px}.inspector-command-row button:focus-visible,.inspector-command-row__rename:focus-visible{outline:1px solid var(--command-accent);outline-offset:1px}.inspector-command-row__confirm{grid-column:1;color:var(--command-text);font-size:12px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.inspector-command-row__rename{grid-column:1 / -1;min-height:26px;padding-inline:6px;border:1px solid oklch(72% .13 255 / .4);border-radius:4px;background:#191a21;font-size:12px;font-weight:500}.inspector-command__message{margin:0;padding:16px 10px;color:var(--command-faint);font-size:12px;line-height:1.4;text-align:center}.inspector-command__message--error{padding:6px 10px;border-bottom:1px solid oklch(55% .08 25 / .3);background:#39191780;color:#f7cbc7;text-align:left;font-size:11px}.inspector-command__actions{display:flex;gap:2px;padding:4px;border-top:1px solid var(--command-edge)}.inspector-command-action{display:flex;flex:1 1 0;min-width:0;min-height:28px;align-items:center;justify-content:center;gap:4px;padding:0 4px;overflow:hidden;border:0;border-radius:5px;background:transparent;color:var(--command-muted);cursor:pointer;font:inherit;font-size:10px;font-weight:500;line-height:1;text-align:left}.inspector-command-action svg{width:11px;height:11px;flex:0 0 auto;fill:currentColor}.inspector-command-action span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.inspector-command-action:hover:not(:disabled){background:#ffffff0f;color:var(--command-text)}.inspector-command-action.is-active{background:#6aa7f421;color:#c2daf9}.inspector-command-action.is-selected,.inspector-command-action.is-selected:hover:not(:disabled){background:var(--command-surface-active);color:var(--command-text);box-shadow:inset 0 0 0 1px #6aa7f49e}.inspector-command-action:disabled{cursor:wait;opacity:.45}.inspector-command-action:focus-visible{outline:1px solid var(--command-accent);outline-offset:-1px}.inspector-visually-hidden{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.inspector-checkpoint-toast{position:fixed;top:10px;left:50%;z-index:500;margin:0;display:flex;align-items:center;gap:6px;padding:6px 9px;border:1px solid var(--inspector-panel-edge);border-radius:6px;background:#0f1016f5;color:var(--inspector-text);box-shadow:0 8px 24px #01000352;font-size:11px;font-weight:500;line-height:1.3;pointer-events:none;transform:translate(-50%);animation:inspector-toast-in .16s var(--inspector-ease) both}.inspector-checkpoint-toast:before{width:5px;height:5px;flex:0 0 auto;border-radius:50%;background:var(--inspector-blue);content:\"\"}.inspector-checkpoint-toast--error{border-color:#e2726b4d;background:#351311f0;color:#fed2cd}.inspector-checkpoint-toast--error:before{background:var(--command-danger, oklch(68% .17 25))}@keyframes inspector-toast-in{0%{opacity:0;transform:translate(-50%,-4px)}to{opacity:1;transform:translate(-50%)}}@media (prefers-reduced-motion: reduce){.inspector-command-dialog{transition-duration:.01ms!important}.inspector-command-dialog,.inspector-command-dialog[open]{transform:none}.inspector-command__pet-switcher{transition:none}.inspector-command__pet-sprite{animation:none;transform:translate(0)}.inspector-checkpoint-toast{animation:none}}.inspector-box{position:fixed;box-sizing:border-box;pointer-events:none;border:1px solid var(--inspector-accent, var(--inspector-blue));background:color-mix(in srgb,var(--inspector-accent, var(--inspector-blue)) 8%,transparent)}.inspector-box--hover{opacity:.55}.inspector-box--selected{border-width:1.5px}.inspector-box--margin{border-color:#f0a646d1;background:#f0a64614}.inspector-box--padding{border-color:#5ac576d1;background:#5ac57614}.inspector-box--gap{border-color:#bb8aefb8;background:#bb8aef0d}.inspector-box--distance{border-style:dashed;border-color:#539af2b3;background:transparent}.inspector-label,.inspector-box-tag,.inspector-text-chip,.inspector-distance-tag,.inspector-guide-distance__tag{border:1px solid var(--inspector-panel-edge);border-radius:4px;background:#0e0f15c2;font-variant-numeric:tabular-nums;text-shadow:none}.inspector-label{position:absolute;left:0;top:0;transform:translateY(calc(-100% - 6px));max-width:min(380px,calc(100vw - 20px));padding:1px 3px;color:var(--inspector-text);box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none;font-size:9px;font-weight:500;line-height:1.2;white-space:nowrap}.inspector-box-tag{position:fixed;transform:translateY(-100%);padding:2px 4px;color:var(--inspector-text);font-size:9px;font-weight:520;line-height:1;pointer-events:none}.inspector-box-tag__margin{color:#f5c076}.inspector-box-tag__padding{color:#95dfa4}.inspector-box-tag--gap{color:oklch(86% .09 305)}.inspector-box-tag--spacing{display:inline-flex;align-items:center;gap:3px;transform:translateY(0);white-space:nowrap}.inspector-box-tag__separator{color:var(--inspector-faint)}.inspector-text-chip{position:fixed;transform:translateY(-100%);display:inline-flex;gap:5px;align-items:center;padding:2px 4px;color:#e4e4e9;font-size:9px;font-weight:500;line-height:1;white-space:nowrap;pointer-events:none}.inspector-text-chip__swatch{width:7px;height:7px;border-radius:999px;border:1px solid oklch(100% 0 0 / .16);flex:0 0 auto}.inspector-connector{position:fixed;border-color:#539af2b8;border-style:dashed;pointer-events:none}.inspector-connector--vertical{border-left-width:1px;width:0}.inspector-connector--horizontal{border-top-width:1px;height:0}.inspector-distance-line{position:fixed;background:var(--inspector-blue);pointer-events:none}.inspector-distance-line--horizontal{height:1px}.inspector-distance-line--vertical{width:1px}.inspector-distance-tag{position:fixed;transform:translate(-50%,-50%);padding:2px 4px;border-color:#539af247;background:#0e0f15b8;color:var(--inspector-text);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);font-size:9px;font-weight:520;line-height:1;pointer-events:none}.inspector-guide{position:fixed;margin:0;padding:0;border:0;background:transparent;pointer-events:auto;cursor:grab}.inspector-guide--vertical{top:0;width:14px;height:100vh;transform:translate(-50%)}.inspector-guide--horizontal{left:0;width:100vw;height:14px;transform:translateY(-50%)}.inspector-guide--preview{opacity:.55;pointer-events:none;cursor:default}.inspector-guide--preview .inspector-guide-line{background:color-mix(in srgb,var(--inspector-guide, #ff7a00) 72%,transparent)}.inspector-guide-line{position:absolute;inset:0;pointer-events:none}.inspector-guide--vertical .inspector-guide-line{left:calc(50% - .5px);width:1px;height:100%;background:var(--inspector-guide, #ff7a00)}.inspector-guide--horizontal .inspector-guide-line{top:calc(50% - .5px);width:100%;height:1px;background:var(--inspector-guide, #ff7a00)}.inspector-guide--selected .inspector-guide-line{box-shadow:0 0 0 1px #ffffff80}.inspector-guide-distance{position:fixed;z-index:2;pointer-events:none}.inspector-guide-distance--vertical{top:50%;height:1px}.inspector-guide-distance--horizontal{left:50%;width:1px}.inspector-guide-distance__line{position:absolute;background:color-mix(in srgb,var(--inspector-guide, #ff7a00) 72%,transparent)}.inspector-guide-distance--vertical .inspector-guide-distance__line{inset:0;height:1px}.inspector-guide-distance--horizontal .inspector-guide-distance__line{inset:0;width:1px}.inspector-guide-distance__line:before,.inspector-guide-distance__line:after{position:absolute;content:\"\";background:var(--inspector-guide, #ff7a00)}.inspector-guide-distance--vertical .inspector-guide-distance__line:before,.inspector-guide-distance--vertical .inspector-guide-distance__line:after{top:-2px;width:1px;height:5px}.inspector-guide-distance--vertical .inspector-guide-distance__line:before{left:0}.inspector-guide-distance--vertical .inspector-guide-distance__line:after{right:0}.inspector-guide-distance--horizontal .inspector-guide-distance__line:before,.inspector-guide-distance--horizontal .inspector-guide-distance__line:after{left:-2px;width:5px;height:1px}.inspector-guide-distance--horizontal .inspector-guide-distance__line:before{top:0}.inspector-guide-distance--horizontal .inspector-guide-distance__line:after{bottom:0}.inspector-guide-distance__tag{position:absolute;padding:2px 4px;border-color:color-mix(in srgb,var(--inspector-guide, #ff7a00) 48%,transparent);background:#0e0f15eb;color:var(--inspector-text);box-shadow:0 1px 4px #01000357;font-size:9px;font-weight:520;line-height:1;white-space:nowrap}.inspector-guide-distance--vertical .inspector-guide-distance__tag{left:50%;top:0;transform:translate(-50%,-50%)}.inspector-guide-distance--horizontal .inspector-guide-distance__tag{left:0;top:50%;transform:translate(-50%,-50%)}@media (min-width: 769px) and (min-height: 769px){:host{--inspector-radius: 14px;--inspector-shadow: 0 21px 56px oklch(6% .02 280 / .5)}.inspector-command-dialog{inset-block-start:max(10vh,84px);width:min(735px,calc(100vw - 42px));max-height:min(630px,calc(100vh - 112px))}.inspector-command{max-height:min(630px,calc(100vh - 112px))}.inspector-command__search{gap:14px;min-height:70px;padding:0 19.25px}.inspector-command__pet-switcher{width:42px;height:42px}.inspector-command__search input{height:68.25px;font-size:22.75px}.inspector-command__results{max-height:455px;padding:8.75px}.inspector-command-row{gap:10.5px;min-height:59.5px;padding:0 12.25px 0 15.75px;border-radius:8.75px}.inspector-command-row__content{gap:10.5px}.inspector-command-row__name,.inspector-command-row__confirm{font-size:21px}.inspector-command-row__activity{font-size:15.75px}.inspector-command-row__actions,.inspector-command-row__confirm-actions{gap:1.75px}.inspector-command-row button{width:38.5px;min-height:38.5px;border-radius:7px;font-size:17.5px}.inspector-command-row button svg{width:19.25px;height:19.25px}.inspector-command-row button.is-danger,.inspector-command-row__confirm-actions button:not(.is-danger){padding:0 12.25px;font-size:19.25px}.inspector-command-row__rename{min-height:45.5px;padding-inline:10.5px;border-radius:7px;font-size:21px}.inspector-command__message{padding:28px 17.5px;font-size:21px}.inspector-command__message--error{padding:10.5px 17.5px;font-size:19.25px}.inspector-command__actions{gap:3.5px;padding:7px}.inspector-command-action{min-height:49px;gap:7px;padding:0 7px;border-radius:8.75px;font-size:17.5px}.inspector-command-action svg{width:19.25px;height:19.25px}.inspector-checkpoint-toast{top:14px;padding:7px 10px;font-size:13px}.inspector-label{transform:translateY(calc(-100% - 10.5px));max-width:min(665px,calc(100vw - 35px));padding:2px 4px;font-size:13px}.inspector-box-tag{padding:3px 5px;font-size:15.75px}.inspector-box-tag--spacing{gap:5px;transform:translateY(0)}.inspector-text-chip{gap:8.75px;padding:3px 5px;font-size:15.75px}.inspector-text-chip__swatch{width:12.25px;height:12.25px}.inspector-distance-tag,.inspector-guide-distance__tag{padding:3px 5px;font-size:15.75px}.inspector-guide--vertical{width:24.5px}.inspector-guide--horizontal{height:24.5px}}\n"] }]
|
|
1600
1965
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1601
1966
|
type: Inject,
|
|
1602
1967
|
args: [PLATFORM_ID]
|