Skip to content

feat(drag): a dragged dock element lifts off the row and the dock holds its width - #69

Open
priard wants to merge 1 commit into
thepathless:experimentalfrom
priard:feat/drag-lift
Open

priard wants to merge 1 commit into
thepathless:experimentalfrom
priard:feat/drag-lift

Conversation

@priard

@priard priard commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

What and why

A drag inside the dock left the element in its slot at a third of its opacity and opened a narrow gap with an accent line where it would land. So:

  • the dock grew while dragging;
  • on the drop the element popped out of one place and into the other;
  • a running app pinned in the run left with its exit animation and came back with its entrance, and the card widened and narrowed as the two raced;
  • a centred card that changes width also moves every tile under a pointer that stands still, so the drop target flickered and the faded tile lagged behind the hand.

Now the element is picked up: a copy follows the pointer, the row parts where it would land, and the dock keeps its width.

A pinned app lifted: its copy over the row, the place it left closed, the row parted where it lands

How

  • components/DockLift.qml (new, in the card, reached as root.dockCard.liftRef since Dock.qml is at its cap) holds the dragged element. Its copy is a ShaderEffectSource with hideSource, label and plate included, at full opacity (0.4 while letting go would unpin it), live while held and frozen once dropped.
  • The drop gap opens as wide as the element, without the accent line (DropGap).
  • The held slot gives up exactly the room the open gaps take. Each DropGap reports what it takes (DockLift.noteGap, a spacer's row spacing included); the held RowSlot shrinks by that sum, down to nothing with the spacing after it (a negative width in the Row). The neighbours slide to fill the place it left while the row parts where it lands, and the card keeps its width. Where no gap opens (over another app, over the running apps, pulled off the dock) the place simply stays empty.
  • The drop lands in one step. DockLift.snapping turns off the gaps' easing for the drop. A slot entering the pinned run stands open from its first frame (at least the width the gap held, as its label settles a frame later). Names and side marks do not ease while a drag holds or settles (DockLabel). A held slot leaving its run (into a group, off the dock) eases shut from the room it had left.
  • The copy settles into the element's new place before the element shows there, or fades into a group or off the dock. A drag that ends without a drop goes home: the gap closes, the place reopens by the same amount, and the copy returns.
  • Apps, app groups and folders lift. The old 0.35 drag opacity and the icon's press scale during a drag are gone. Motion Off does all of it at once.

Verification

  • node --check of the model files and node --test tests/unit/*.test.mjs tests/unit/*.test.js (252 pass)
  • python3 -m unittest discover -s tests/unit -p 'test_*.py'
  • qmllint (no new error kinds)
  • security-grep.py, structure-check.py, shaders-in-sync.sh
  • ./tests/manifest-check.sh . and omarchy plugin validate .
  • ./tests/smoke-test.sh against a running dock
  • Live, with a temporary IPC that drives the drag handlers and samples the card's width every ~16 ms: the width stays constant (to 0.1 px) while lifting, moving, over an app's middle, over the running apps, cancelling, reordering, pinning a running app in the run, and moving a folder. Unpinning closes the hole smoothly.

…ds its width

A drag inside the dock used to leave the element in its slot at a third
of its opacity and open a narrow gap with an accent line where it would
land, so the dock grew while dragging; on the drop the element popped
out of one place and into the other, a running app pinned in the run
left with its exit animation and came back with its entrance, and the
card widened and narrowed as the two raced. A centred card that changes
width also moves every tile under a pointer that stands still, so the
drop target flickered and the faded tile lagged behind the hand.

Now the element is picked up: a copy of it (a ShaderEffectSource with
hideSource, label and plate included) follows the pointer at full
opacity, and the drop gap opens as wide as the element, without the
line. The held element's slot gives up exactly the room the open drop
gaps take (DockLift.gapSum, which each DropGap reports, a spacer's row
spacing included), down to nothing with the spacing after it (a
negative width in the Row). The neighbours slide to fill the place it
left while the row parts where it would land, and the card keeps its
width throughout: over another app (to group), over the running apps or
pulled off the dock no gap opens and the place stays empty.

On the drop the row takes its final shape in one step (DockLift.snapping
turns off the gaps' easing): a slot entering the pinned run stands open
from its first frame (at least the width the gap held, as its label
settles a frame later) and names and side marks do not ease while a
drag holds or settles; a held slot leaving its run (into the pinned
run, a group or off the dock) eases shut from the room it had left. The
copy settles into the element's new place before the element shows
there, or fades into a group or off the dock. A drag that ends without
a drop eases back: the gap closes, the place reopens by the same
amount, and the copy returns home. Motion Off does all of it at once.

Apps, app groups and folders lift; drags out of a group popup keep the
narrow gap, as nothing in the row stands in for them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant