Files
small-packages/luci-theme-aurora/.dev/src/media/components/_float-button.css
T
2026-09-20 01:22:33 +08:00

84 lines
3.3 KiB
CSS

.floating-toolbar {
/* Detached-bubble speed dial: every shortcut is its own floating circle
(elevation only, no border), collapsing drops the bubbles into the
toggle one after another and the toggle's X rotates into a +.
All motion is translate/scale/opacity/rotate — compositor-only (R1).
The stagger math runs on custom properties set by header.ut:
--fab-n (on .toolbar-list) item count
--fab-i (on each .toolbar-btn) index, 0 = top bubble
--fab-icon (on each .toolbar-btn) configured icon URL, drawn via
mask + bg-current so it follows the theme text color in both
modes (replaces the old <img> + dark:invert).
Travel per step = bubble 44px + 10px gap = 3.375rem (40px + 8px =
3rem below md). Expanding pops bottom-first ("jump up"), collapsing
drops top-first; --fab-d only ever delays the motion properties, so
hover color feedback stays instant. */
/* The stack keeps its layout height when collapsed (the bubbles must
travel a real distance into the toggle), so the container itself must
not catch clicks — only the buttons do. */
@apply pointer-events-none fixed right-4 bottom-4 z-40 flex flex-col items-center max-md:right-3 max-md:bottom-3;
.toolbar-list {
@apply mb-2.5 flex flex-col items-center gap-2.5 max-md:mb-2 max-md:gap-2;
}
.toolbar-btn {
@apply text-text-muted bg-surface-overlay pointer-events-auto grid size-11 cursor-pointer place-items-center rounded-full shadow-md max-md:size-10;
/* `visibility` rides the same transition so collapsed bubbles leave the
tab order, but only after the drop finishes (it flips at the end of
its transition window, so the motion itself is never clipped). */
@apply [transition:translate_320ms_cubic-bezier(0.34,1.25,0.5,1),scale_320ms_cubic-bezier(0.34,1.25,0.5,1),opacity_220ms_ease,visibility_320ms_ease,background-color_150ms_ease,color_150ms_ease];
@apply [transition-delay:var(--fab-d,0s),var(--fab-d,0s),var(--fab-d,0s),var(--fab-d,0s),0s,0s];
&:hover {
@apply text-text bg-hover-faint;
}
&:active {
@apply scale-[0.92];
}
&:not(.toggle) {
@apply [--fab-d:calc((var(--fab-n,1)-1-var(--fab-i,0))*60ms)] no-underline;
/* The stagger delay must not defer press feedback: `scale` shares the
delayed transition channel, so without this a press on the top
bubble would acknowledge (n-1)*60ms late. Nested (not merged into
the base `:active`) so it outranks the delay set just above. */
&:active {
@apply [--fab-d:0s];
}
.icon {
@apply size-5 shrink-0 bg-current [mask:var(--fab-icon)_center/contain_no-repeat] max-md:size-4.5;
}
}
&.toggle {
@apply text-text-subtle hover:text-text border-0;
.icon {
@apply grid size-5 place-items-center transition-[rotate] duration-[250ms] ease-out max-md:size-4.5;
svg {
@apply size-full;
}
}
}
}
&.collapsed {
.toolbar-btn {
&:not(.toggle) {
@apply pointer-events-none invisible scale-[0.35] opacity-0;
@apply [--fab-d:calc(var(--fab-i,0)*60ms)] translate-y-[calc((var(--fab-n,1)-var(--fab-i,0))*3.375rem)] max-md:translate-y-[calc((var(--fab-n,1)-var(--fab-i,0))*3rem)];
}
&.toggle .icon {
@apply rotate-45;
}
}
}
}