@1agh/maude 0.19.0 → 0.19.1
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/package.json +8 -8
- package/plugins/design/dev-server/annotations-context-toolbar.tsx +14 -6
- package/plugins/design/dev-server/annotations-layer.tsx +144 -22
- package/plugins/design/dev-server/api.ts +70 -17
- package/plugins/design/dev-server/artboard-marquee.tsx +170 -0
- package/plugins/design/dev-server/canvas-lib.tsx +190 -94
- package/plugins/design/dev-server/canvas-shell.tsx +478 -34
- package/plugins/design/dev-server/client/app.jsx +173 -52
- package/plugins/design/dev-server/client/styles/1-tokens.css +15 -8
- package/plugins/design/dev-server/client/styles/4-components.css +32 -2
- package/plugins/design/dev-server/config.schema.json +31 -5
- package/plugins/design/dev-server/context-menu.tsx +3 -3
- package/plugins/design/dev-server/context.ts +37 -3
- package/plugins/design/dev-server/dist/client.bundle.js +212 -103
- package/plugins/design/dev-server/dist/styles.css +38 -2
- package/plugins/design/dev-server/export-dialog.tsx +3 -3
- package/plugins/design/dev-server/http.ts +14 -2
- package/plugins/design/dev-server/input-router.tsx +22 -8
- package/plugins/design/dev-server/server.mjs +84 -18
- package/plugins/design/dev-server/test/context-resolve-tokens.test.ts +97 -0
- package/plugins/design/dev-server/test/snap-distance-pill.test.ts +68 -0
- package/plugins/design/dev-server/test/system-endpoint.test.ts +144 -0
- package/plugins/design/dev-server/tool-palette.tsx +71 -15
- package/plugins/design/dev-server/use-annotation-resize.tsx +295 -0
- package/plugins/design/dev-server/use-snap-guides.tsx +25 -1
- package/plugins/design/dev-server/use-tool-mode.tsx +31 -2
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
|
|
67
67
|
import {
|
|
68
68
|
type CSSProperties,
|
|
69
|
+
Fragment,
|
|
69
70
|
type ReactNode,
|
|
70
71
|
type PointerEvent as ReactPointerEvent,
|
|
71
72
|
type RefObject,
|
|
@@ -108,12 +109,63 @@ const ENGINE_CSS = `
|
|
|
108
109
|
inset: 0;
|
|
109
110
|
overflow: hidden;
|
|
110
111
|
outline: none;
|
|
112
|
+
/* DDR-046 — snap-layer magenta is distinct from --accent so the snap chrome
|
|
113
|
+
never visually melts into the selection halo during a drag-snap gesture.
|
|
114
|
+
OKLCH default approximates FigJam magenta in the project's color space. */
|
|
115
|
+
--guide-magenta: oklch(62% 0.28 350);
|
|
111
116
|
background-color: var(--bg-1, #f4f1ea);
|
|
112
117
|
background-image:
|
|
113
118
|
linear-gradient(var(--border-subtle, rgba(0,0,0,0.08)) 1px, transparent 1px),
|
|
114
119
|
linear-gradient(90deg, var(--border-subtle, rgba(0,0,0,0.08)) 1px, transparent 1px);
|
|
115
120
|
background-size: 24px 24px;
|
|
116
121
|
}
|
|
122
|
+
/* DDR-046 — Snap guides. Sibling kind = confident magenta + glow + distance
|
|
123
|
+
pill. Grid kind = lighter gray fallback, no pill. Width 2 px (up from 1 px)
|
|
124
|
+
so the line stays readable at zoom < 0.8. */
|
|
125
|
+
.dc-snap-guide {
|
|
126
|
+
position: fixed;
|
|
127
|
+
pointer-events: none;
|
|
128
|
+
z-index: 6;
|
|
129
|
+
animation: dc-snap-spawn 80ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
130
|
+
transform-origin: center;
|
|
131
|
+
}
|
|
132
|
+
.dc-snap-guide--sibling {
|
|
133
|
+
background: var(--guide-magenta, oklch(62% 0.28 350));
|
|
134
|
+
box-shadow: 0 0 4px color-mix(in oklab, var(--guide-magenta, oklch(62% 0.28 350)) 35%, transparent);
|
|
135
|
+
}
|
|
136
|
+
.dc-snap-guide--grid {
|
|
137
|
+
background: color-mix(in oklab, var(--fg-3, var(--fg-1, #4a3f30)) 40%, transparent);
|
|
138
|
+
}
|
|
139
|
+
.dc-snap-pill {
|
|
140
|
+
position: fixed;
|
|
141
|
+
pointer-events: none;
|
|
142
|
+
z-index: 7;
|
|
143
|
+
font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
144
|
+
font-size: 11px;
|
|
145
|
+
font-weight: 600;
|
|
146
|
+
line-height: 1;
|
|
147
|
+
color: #fff;
|
|
148
|
+
background: var(--guide-magenta, oklch(62% 0.28 350));
|
|
149
|
+
padding: 3px 6px;
|
|
150
|
+
border-radius: 3px;
|
|
151
|
+
white-space: nowrap;
|
|
152
|
+
font-variant-numeric: tabular-nums;
|
|
153
|
+
animation: dc-snap-pill-spawn 80ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
154
|
+
}
|
|
155
|
+
@keyframes dc-snap-spawn {
|
|
156
|
+
from { opacity: 0; transform: scaleY(0.92); }
|
|
157
|
+
to { opacity: 1; transform: scaleY(1); }
|
|
158
|
+
}
|
|
159
|
+
@keyframes dc-snap-pill-spawn {
|
|
160
|
+
from { opacity: 0; transform: translate(-50%, -50%) scale(0.88); }
|
|
161
|
+
to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
|
|
162
|
+
}
|
|
163
|
+
@media (prefers-reduced-motion: reduce) {
|
|
164
|
+
.dc-snap-guide,
|
|
165
|
+
.dc-snap-pill {
|
|
166
|
+
animation: none !important;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
117
169
|
.dc-canvas:focus { outline: none; }
|
|
118
170
|
.dc-world {
|
|
119
171
|
position: absolute;
|
|
@@ -129,8 +181,11 @@ const ENGINE_CSS = `
|
|
|
129
181
|
.dc-canvas .dc-artboard {
|
|
130
182
|
background: var(--bg-0, #ffffff);
|
|
131
183
|
color: var(--fg-0, #2a2520);
|
|
132
|
-
|
|
133
|
-
|
|
184
|
+
/* Quiet frame chrome — FigJam Section / Figma Frame canonical. The Memphis
|
|
185
|
+
hard-shadow is the Maude brand on USER CONTENT inside artboards; the frame
|
|
186
|
+
itself stays calm so user content reads as loud. */
|
|
187
|
+
border: 1px solid color-mix(in oklab, var(--fg-0, #2a2520) 22%, transparent);
|
|
188
|
+
border-radius: 2px;
|
|
134
189
|
display: flex;
|
|
135
190
|
flex-direction: column;
|
|
136
191
|
overflow: hidden;
|
|
@@ -166,25 +221,15 @@ button.dc-artboard-label:focus-visible { outline: 2px solid var(--accent, #d63b1
|
|
|
166
221
|
/* Phase 4.2 — drag chrome. */
|
|
167
222
|
.dc-canvas[data-active-tool="move"] .dc-artboard-label { cursor: grab; }
|
|
168
223
|
.dc-canvas[data-active-tool="move"] .dc-artboard-label:active { cursor: grabbing; }
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
.dc-canvas .dc-artboard-ghost-label {
|
|
180
|
-
background: var(--bg-2, #e8e3d8);
|
|
181
|
-
border-bottom: 1px solid var(--fg-0, #2a2520);
|
|
182
|
-
padding: 6px 14px;
|
|
183
|
-
font-size: 10px;
|
|
184
|
-
letter-spacing: 0.06em;
|
|
185
|
-
text-transform: uppercase;
|
|
186
|
-
color: var(--fg-1, #4a3f30);
|
|
187
|
-
font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
224
|
+
/* Post-Wave-2 — direct artboard drag. The article itself updates its
|
|
225
|
+
inline left/top during drag (no ghost placeholder, no opacity fade on
|
|
226
|
+
the original). Compositor handles the pixel movement; halo + group
|
|
227
|
+
bbox naturally follow via getBoundingClientRect on the article. */
|
|
228
|
+
.dc-canvas .dc-artboard.dc-dragging {
|
|
229
|
+
z-index: 5;
|
|
230
|
+
/* Keep the cursor consistent with the label's grabbing affordance even
|
|
231
|
+
when the pointer drifts off the label strip during the drag. */
|
|
232
|
+
cursor: grabbing;
|
|
188
233
|
}
|
|
189
234
|
`.trim();
|
|
190
235
|
|
|
@@ -237,6 +282,12 @@ function useWorldContext(): WorldContextValue | null {
|
|
|
237
282
|
return useContext(WorldContext);
|
|
238
283
|
}
|
|
239
284
|
|
|
285
|
+
/** Read-only access to the artboard list + viewport state. Used by overlays
|
|
286
|
+
* that need to operate on artboards directly (distribute, marquee, etc.). */
|
|
287
|
+
export function useArtboardsContext(): WorldContextValue | null {
|
|
288
|
+
return useContext(WorldContext);
|
|
289
|
+
}
|
|
290
|
+
|
|
240
291
|
// Phase 5.1: annotations-layer needs the world `<div>` to portal a stroke SVG
|
|
241
292
|
// inside it (so CSS zoom + translate apply natively, no per-frame projection
|
|
242
293
|
// math). Expose only the ref — the rest of WorldContextValue stays internal.
|
|
@@ -1355,50 +1406,41 @@ export function DCArtboard({
|
|
|
1355
1406
|
const isFollower = !!followerOffset;
|
|
1356
1407
|
const isInDrag = isLeader || isFollower;
|
|
1357
1408
|
|
|
1358
|
-
//
|
|
1359
|
-
|
|
1360
|
-
|
|
1409
|
+
// Live drag position (world coords). The article's own `left/top` updates
|
|
1410
|
+
// each frame while the drag is in flight — no ghost placeholder, no faded
|
|
1411
|
+
// original. commitFromState then persists the final position on settle.
|
|
1412
|
+
let liveX = rect.x;
|
|
1413
|
+
let liveY = rect.y;
|
|
1361
1414
|
if (busDrag?.kind === 'dragging') {
|
|
1362
1415
|
if (isLeader) {
|
|
1363
|
-
|
|
1364
|
-
|
|
1416
|
+
liveX = busDrag.leaderRect.x;
|
|
1417
|
+
liveY = busDrag.leaderRect.y;
|
|
1365
1418
|
} else if (isFollower && followerOffset) {
|
|
1366
|
-
|
|
1367
|
-
|
|
1419
|
+
liveX = busDrag.leaderRect.x + followerOffset.offsetX;
|
|
1420
|
+
liveY = busDrag.leaderRect.y + followerOffset.offsetY;
|
|
1368
1421
|
}
|
|
1369
1422
|
}
|
|
1370
1423
|
|
|
1371
1424
|
const handleProps = dragHook.bindHandle();
|
|
1372
1425
|
|
|
1373
1426
|
return (
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1427
|
+
<article
|
|
1428
|
+
className={`dc-artboard dc-positioned${isInDrag ? ' dc-dragging' : ''}`}
|
|
1429
|
+
data-dc-screen={id}
|
|
1430
|
+
aria-current={isActive ? 'true' : undefined}
|
|
1431
|
+
style={{ left: liveX, top: liveY, width: rect.w, height: rect.h }}
|
|
1432
|
+
{...handleProps}
|
|
1433
|
+
>
|
|
1434
|
+
<button
|
|
1435
|
+
type="button"
|
|
1436
|
+
className="dc-artboard-label sku"
|
|
1437
|
+
onClick={onFocus}
|
|
1438
|
+
aria-label={`Focus artboard ${label}`}
|
|
1381
1439
|
>
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
aria-label={`Focus artboard ${label}`}
|
|
1387
|
-
>
|
|
1388
|
-
{label}
|
|
1389
|
-
</button>
|
|
1390
|
-
<div className="dc-artboard-body">{children}</div>
|
|
1391
|
-
</article>
|
|
1392
|
-
{isInDrag ? (
|
|
1393
|
-
<div
|
|
1394
|
-
className="dc-artboard-ghost"
|
|
1395
|
-
aria-hidden="true"
|
|
1396
|
-
style={{ left: ghostX, top: ghostY, width: rect.w, height: rect.h }}
|
|
1397
|
-
>
|
|
1398
|
-
<div className="dc-artboard-ghost-label">{label}</div>
|
|
1399
|
-
</div>
|
|
1400
|
-
) : null}
|
|
1401
|
-
</>
|
|
1440
|
+
{label}
|
|
1441
|
+
</button>
|
|
1442
|
+
<div className="dc-artboard-body">{children}</div>
|
|
1443
|
+
</article>
|
|
1402
1444
|
);
|
|
1403
1445
|
}
|
|
1404
1446
|
DCArtboard.displayName = 'DCArtboard';
|
|
@@ -1410,6 +1452,15 @@ DCArtboard.displayName = 'DCArtboard';
|
|
|
1410
1452
|
// come from `dragBus.current.snap.guides`; world→screen projection uses the
|
|
1411
1453
|
// live viewport (`v.x + worldCoord * v.zoom` — same convention as `writeTransform`).
|
|
1412
1454
|
|
|
1455
|
+
// DDR-046 — render kind-aware snap guides + distance pills. `kind === 'sibling'`
|
|
1456
|
+
// gets the confident magenta + glow; `kind === 'grid'` gets a lighter gray (the
|
|
1457
|
+
// grid is fallback when no sibling fires). Pre-DDR-046 guides emit no `kind`
|
|
1458
|
+
// field — treat as sibling for back-compat. The `Δ{Math.round(delta)}` pill
|
|
1459
|
+
// renders mid-span when |delta| > 0 and screen-span exceeds 60 px (smaller
|
|
1460
|
+
// spans hide the pill so it never overlaps the line itself).
|
|
1461
|
+
const MIN_PILL_SPAN_PX = 60;
|
|
1462
|
+
const GUIDE_THICKNESS_PX = 2;
|
|
1463
|
+
|
|
1413
1464
|
export function SnapGuideOverlay() {
|
|
1414
1465
|
const dragBus = useDragStateContext();
|
|
1415
1466
|
const world = useWorldContext();
|
|
@@ -1421,49 +1472,78 @@ export function SnapGuideOverlay() {
|
|
|
1421
1472
|
return (
|
|
1422
1473
|
<>
|
|
1423
1474
|
{s.snap.guides.map((g, i) => {
|
|
1475
|
+
const kindClass = g.kind === 'grid' ? 'dc-snap-guide--grid' : 'dc-snap-guide--sibling';
|
|
1476
|
+
const delta = g.delta ?? 0;
|
|
1477
|
+
const showPill = g.kind !== 'grid' && Math.abs(delta) > 0;
|
|
1424
1478
|
if (g.axis === 'x') {
|
|
1425
1479
|
const sx = vp.x + g.pos * vp.zoom;
|
|
1426
1480
|
const sFrom = vp.y + g.from * vp.zoom;
|
|
1427
1481
|
const sTo = vp.y + g.to * vp.zoom;
|
|
1482
|
+
const screenSpan = sTo - sFrom;
|
|
1428
1483
|
return (
|
|
1429
|
-
<
|
|
1484
|
+
<Fragment
|
|
1430
1485
|
// biome-ignore lint/suspicious/noArrayIndexKey: guides are positional
|
|
1431
1486
|
key={`x-${i}`}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1487
|
+
>
|
|
1488
|
+
<div
|
|
1489
|
+
className={`dc-snap-guide ${kindClass}`}
|
|
1490
|
+
style={{
|
|
1491
|
+
left: sx - GUIDE_THICKNESS_PX / 2,
|
|
1492
|
+
top: sFrom,
|
|
1493
|
+
width: GUIDE_THICKNESS_PX,
|
|
1494
|
+
height: Math.max(GUIDE_THICKNESS_PX, screenSpan),
|
|
1495
|
+
}}
|
|
1496
|
+
aria-hidden="true"
|
|
1497
|
+
/>
|
|
1498
|
+
{showPill && screenSpan >= MIN_PILL_SPAN_PX && (
|
|
1499
|
+
<div
|
|
1500
|
+
className="dc-snap-pill"
|
|
1501
|
+
style={{
|
|
1502
|
+
left: sx,
|
|
1503
|
+
top: sFrom + screenSpan / 2,
|
|
1504
|
+
transform: 'translate(-50%, -50%)',
|
|
1505
|
+
}}
|
|
1506
|
+
aria-hidden="true"
|
|
1507
|
+
>
|
|
1508
|
+
Δ{Math.round(Math.abs(delta))}
|
|
1509
|
+
</div>
|
|
1510
|
+
)}
|
|
1511
|
+
</Fragment>
|
|
1445
1512
|
);
|
|
1446
1513
|
}
|
|
1447
1514
|
const sy = vp.y + g.pos * vp.zoom;
|
|
1448
1515
|
const sFrom = vp.x + g.from * vp.zoom;
|
|
1449
1516
|
const sTo = vp.x + g.to * vp.zoom;
|
|
1517
|
+
const screenSpan = sTo - sFrom;
|
|
1450
1518
|
return (
|
|
1451
|
-
<
|
|
1519
|
+
<Fragment
|
|
1452
1520
|
// biome-ignore lint/suspicious/noArrayIndexKey: guides are positional
|
|
1453
1521
|
key={`y-${i}`}
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1522
|
+
>
|
|
1523
|
+
<div
|
|
1524
|
+
className={`dc-snap-guide ${kindClass}`}
|
|
1525
|
+
style={{
|
|
1526
|
+
left: sFrom,
|
|
1527
|
+
top: sy - GUIDE_THICKNESS_PX / 2,
|
|
1528
|
+
width: Math.max(GUIDE_THICKNESS_PX, screenSpan),
|
|
1529
|
+
height: GUIDE_THICKNESS_PX,
|
|
1530
|
+
}}
|
|
1531
|
+
aria-hidden="true"
|
|
1532
|
+
/>
|
|
1533
|
+
{showPill && screenSpan >= MIN_PILL_SPAN_PX && (
|
|
1534
|
+
<div
|
|
1535
|
+
className="dc-snap-pill"
|
|
1536
|
+
style={{
|
|
1537
|
+
left: sFrom + screenSpan / 2,
|
|
1538
|
+
top: sy,
|
|
1539
|
+
transform: 'translate(-50%, -50%)',
|
|
1540
|
+
}}
|
|
1541
|
+
aria-hidden="true"
|
|
1542
|
+
>
|
|
1543
|
+
Δ{Math.round(Math.abs(delta))}
|
|
1544
|
+
</div>
|
|
1545
|
+
)}
|
|
1546
|
+
</Fragment>
|
|
1467
1547
|
);
|
|
1468
1548
|
})}
|
|
1469
1549
|
</>
|
|
@@ -1484,6 +1564,14 @@ export function DCPostIt({ children }: { children: ReactNode }) {
|
|
|
1484
1564
|
// same vocabulary; if a DS wants to restyle, it can target `.dc-mm` /
|
|
1485
1565
|
// `.dc-zoom-tb` directly.
|
|
1486
1566
|
|
|
1567
|
+
// DDR-046 — Floating chrome (mini-map, zoom HUD, tool palette, popovers, comment
|
|
1568
|
+
// composer, export dialog) drops the brutalist 4 × 4 × 0 hard offset shadow in
|
|
1569
|
+
// favor of a soft ambient. The hard offset stays on app-shell chrome only
|
|
1570
|
+
// (menubar, header, tab strip) — that's the project's intentional brutalist
|
|
1571
|
+
// identity. Floating layer = soft. App frame = hard.
|
|
1572
|
+
const FLOATING_SHADOW = '0 6px 24px color-mix(in oklab, var(--fg-0, #1c1917) 10%, transparent)';
|
|
1573
|
+
const FLOATING_RADIUS = '8px';
|
|
1574
|
+
|
|
1487
1575
|
const OVERLAY_CSS = `
|
|
1488
1576
|
.dc-mm {
|
|
1489
1577
|
position: absolute;
|
|
@@ -1491,15 +1579,15 @@ const OVERLAY_CSS = `
|
|
|
1491
1579
|
bottom: 16px;
|
|
1492
1580
|
width: 196px;
|
|
1493
1581
|
height: 132px;
|
|
1494
|
-
background: var(--bg-
|
|
1582
|
+
background: var(--bg-0, #ffffff);
|
|
1495
1583
|
border: 1px solid var(--fg-0, #1c1917);
|
|
1496
|
-
border-radius:
|
|
1584
|
+
border-radius: ${FLOATING_RADIUS};
|
|
1497
1585
|
font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
1498
1586
|
font-size: 10px;
|
|
1499
1587
|
color: var(--fg-1, rgba(40,30,20,0.7));
|
|
1500
1588
|
z-index: 6;
|
|
1501
1589
|
user-select: none;
|
|
1502
|
-
box-shadow:
|
|
1590
|
+
box-shadow: ${FLOATING_SHADOW};
|
|
1503
1591
|
overflow: hidden;
|
|
1504
1592
|
}
|
|
1505
1593
|
.dc-mm-hd {
|
|
@@ -1508,6 +1596,7 @@ const OVERLAY_CSS = `
|
|
|
1508
1596
|
letter-spacing: 0.05em;
|
|
1509
1597
|
text-transform: uppercase;
|
|
1510
1598
|
font-size: 9px;
|
|
1599
|
+
background: var(--bg-1, #f4f1ea);
|
|
1511
1600
|
}
|
|
1512
1601
|
.dc-mm-body {
|
|
1513
1602
|
position: relative;
|
|
@@ -1515,15 +1604,21 @@ const OVERLAY_CSS = `
|
|
|
1515
1604
|
height: calc(100% - 22px);
|
|
1516
1605
|
overflow: hidden;
|
|
1517
1606
|
cursor: pointer;
|
|
1607
|
+
background: var(--bg-1, #f4f1ea);
|
|
1518
1608
|
}
|
|
1519
1609
|
.dc-mm-rect {
|
|
1520
1610
|
position: absolute;
|
|
1521
|
-
background:
|
|
1522
|
-
border: 1px solid
|
|
1611
|
+
background: color-mix(in oklab, var(--fg-0, #1c1917) 14%, transparent);
|
|
1612
|
+
border: 1px solid color-mix(in oklab, var(--fg-0, #1c1917) 28%, transparent);
|
|
1613
|
+
border-radius: 1px;
|
|
1523
1614
|
}
|
|
1615
|
+
/* Filled viewport indicator — FigJam / Figma both ship a tinted fill, not
|
|
1616
|
+
outline-only. Reads from a glance as "what slice of the world you're on". */
|
|
1524
1617
|
.dc-mm-vp {
|
|
1525
1618
|
position: absolute;
|
|
1526
|
-
|
|
1619
|
+
background: color-mix(in oklab, var(--accent, #d63b1f) 12%, transparent);
|
|
1620
|
+
border: 1.5px solid var(--accent, #d63b1f);
|
|
1621
|
+
border-radius: 1px;
|
|
1527
1622
|
pointer-events: none;
|
|
1528
1623
|
}
|
|
1529
1624
|
.dc-zoom-tb {
|
|
@@ -1533,15 +1628,15 @@ const OVERLAY_CSS = `
|
|
|
1533
1628
|
transform: translateX(-50%);
|
|
1534
1629
|
display: flex;
|
|
1535
1630
|
align-items: stretch;
|
|
1536
|
-
background: var(--bg-
|
|
1631
|
+
background: var(--bg-0, #ffffff);
|
|
1537
1632
|
border: 1px solid var(--fg-0, #1c1917);
|
|
1538
|
-
border-radius:
|
|
1633
|
+
border-radius: ${FLOATING_RADIUS};
|
|
1539
1634
|
overflow: hidden;
|
|
1540
1635
|
font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
1541
1636
|
font-size: 11px;
|
|
1542
1637
|
color: var(--fg-1, rgba(40,30,20,0.85));
|
|
1543
1638
|
z-index: 6;
|
|
1544
|
-
box-shadow:
|
|
1639
|
+
box-shadow: ${FLOATING_SHADOW};
|
|
1545
1640
|
}
|
|
1546
1641
|
.dc-zoom-tb button {
|
|
1547
1642
|
appearance: none;
|
|
@@ -1554,10 +1649,11 @@ const OVERLAY_CSS = `
|
|
|
1554
1649
|
cursor: pointer;
|
|
1555
1650
|
min-width: 36px;
|
|
1556
1651
|
text-align: center;
|
|
1652
|
+
transition: background 80ms linear;
|
|
1557
1653
|
}
|
|
1558
1654
|
.dc-zoom-tb button:last-child { border-right: 0; }
|
|
1559
|
-
.dc-zoom-tb button:hover { background:
|
|
1560
|
-
.dc-zoom-tb button:focus-visible { outline: 2px solid #d63b1f; outline-offset: -2px; }
|
|
1655
|
+
.dc-zoom-tb button:hover { background: color-mix(in oklab, var(--fg-0, #1c1917) 5%, transparent); }
|
|
1656
|
+
.dc-zoom-tb button:focus-visible { outline: 2px solid var(--accent, #d63b1f); outline-offset: -2px; }
|
|
1561
1657
|
.dc-zoom-tb-pct { font-variant-numeric: tabular-nums; min-width: 52px; }
|
|
1562
1658
|
`.trim();
|
|
1563
1659
|
|