Files
olivv-cs-ComfyUI-FunPack/app/composer/elements/wheel.css
T
digital-garbage c3df8b2d45 composer: pin the edge panel properly
Three bugs in wheel.half, all found by looking at it:

The hub was centred on the edge, so the edge sliced it in half -- half a cancel
target is not a target. It is pushed inward by its own radius now, and the
wedges start beyond it. The ring is an inset shadow rather than a border,
because a border pushes every absolutely positioned child inward by its own
width, which put the hub a pixel past the screen edge.

Highlighting fired anywhere the pointer went, including well outside the wheel,
promising a pick that release would not deliver. The hit test is bounded by the
same rIn/rOut the wedges are drawn from, so the lit shape is the region.

An edge panel did not follow its edge: it kept the pixel position it opened at
and drifted inward when the window grew. It re-derives its anchor on resize,
and on visualViewport resize for pinch-zoom and mobile chrome.

One GEOMETRY object per variant now drives the wedges, the labels, the hub and
the hit test together, so they cannot disagree.
2026-08-28 19:29:57 +03:00

63 lines
2.8 KiB
CSS

/* The ring is an INSET shadow, not a border. A border pushes every absolutely
* positioned child inward by its own width, which put the hub a pixel past the
* screen edge on an edge panel -- the one place a pixel shows. */
.cx-wheel {
position: fixed; pointer-events: auto; border-radius: var(--r-pill);
background: color-mix(in srgb, var(--elev-3) 92%, transparent);
box-shadow: var(--shadow-3), inset 0 0 0 var(--bw) var(--line);
backdrop-filter: blur(6px);
animation: cx-wheel-in var(--dur-1) var(--ease-standard);
}
@keyframes cx-wheel-in { from { opacity: 0; transform: scale(.9); } }
/* The lit shape IS the region that picks the item, so the target is legible
* instead of implied by a box around a label. */
.cx-wheel-canvas { position: absolute; inset: 0; pointer-events: none; }
.cx-wheel-wedge {
fill: transparent;
stroke: color-mix(in srgb, var(--line) 70%, transparent);
stroke-width: 1;
transition: fill var(--dur-1) var(--ease-standard), stroke var(--dur-1) var(--ease-standard);
}
.cx-wheel-wedge.cx-on { fill: var(--accent-soft); stroke: var(--accent); }
.cx-wheel-item {
position: absolute; transform: translate(-50%, -50%);
display: flex; flex-direction: column; align-items: center; gap: 2px;
min-width: 52px; padding: var(--sp-1) var(--sp-2);
background: transparent; border: 0; color: var(--muted);
font-size: var(--fs-7); cursor: pointer; text-align: center;
transition: color var(--dur-1) var(--ease-standard),
transform var(--dur-1) var(--ease-standard);
}
.cx-wheel-item .cx-wheel-icon { font-size: var(--fs-2); line-height: 1; }
.cx-wheel-item.cx-on {
color: var(--accent-hi);
transform: translate(-50%, -50%) scale(1.06);
}
/* Sized to the dead zone exactly (radius 42), so the cancel target you can see
* is the cancel target you can hit. */
/* left/top/size come from the geometry so the drawn hub and the cancel region
* are the same circle. */
.cx-wheel-hub {
position: absolute; transform: translate(-50%, -50%);
border-radius: var(--r-pill);
border: var(--bw) dashed var(--line);
display: flex; align-items: center; justify-content: center;
color: var(--faint);
transition: border-color var(--dur-1) var(--ease-standard),
color var(--dur-1) var(--ease-standard),
background var(--dur-1) var(--ease-standard);
}
.cx-wheel-hub-glyph { font-size: var(--fs-2); line-height: 1; }
.cx-wheel-hub.cx-on {
border-color: var(--danger); color: var(--danger);
background: color-mix(in srgb, var(--danger) 12%, transparent);
}
/* Half wheels sit ON the edge: the off-screen half is simply clipped by the
* viewport, which is what gives the edge-panel silhouette. The flat side gets a
* straight edge so it reads as pinned rather than cropped by accident. */
.cx-wheel-half { backdrop-filter: blur(8px); }