feat(astal-menu): bouncy slide-in on open, springy pop on quad expand

- Main open: enable Hyprland's `layers` animation with the bouncy myBezier curve and
  a slide style, so the layer-shell control centre slides in from the top edge with a
  little overshoot instead of just appearing. (Also gives notifications/bar the same
  springy slide, which suits the DE.) A per-namespace layerrule was tried first but
  this hyprlua build doesn't honour its animation timing.
- Quad expand: a CSS @keyframes scale-bounce (scale 0.82 -> 1.05 -> 1.0) added to the
  expanded card on expand and cleared on collapse so it replays every time. Verified
  GTK4 CSS transforms/keyframes render on this build, and that the card scales during
  the animation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
feat/astal-menu
Amir Alexander Abdelbaki 2026-07-06 00:00:14 +02:00
parent 3aafd2cc17
commit 6a5a5bce97
3 changed files with 22 additions and 1 deletions

View File

@ -42,6 +42,15 @@ drawingarea {
opacity: 0.15;
}
/* bouncy pop when a quad expands (added in ui/quadgrid.py on expand) */
@keyframes quad-pop {
0% { transform: scale(0.82); opacity: 0.4; }
55% { transform: scale(1.05); opacity: 1; }
78% { transform: scale(0.985); }
100% { transform: scale(1.0); }
}
.quad-pop { animation: quad-pop 300ms ease-out; }
.quad-card { min-height: 100px; }
.section-title { color: @text; font-weight: bold; opacity: 0.85; }

View File

@ -52,7 +52,8 @@ class QuadGrid(Gtk.Overlay):
self._expand_reveal.set_valign(Gtk.Align.FILL)
self._expand_holder = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self._expand_holder.add_css_class("quad-expanded")
self._expand_reveal.set_child(bordered(self._expand_holder, radius=16, fill_bg=True))
self._expand_card = bordered(self._expand_holder, radius=16, fill_bg=True)
self._expand_reveal.set_child(self._expand_card)
self.add_overlay(self._expand_reveal)
# The overlay's holder is opaque; keep the whole overlay hidden unless a quad
# is actually expanded, otherwise it paints over the 2x2 grid.
@ -82,12 +83,16 @@ class QuadGrid(Gtk.Overlay):
self._expand_holder.append(content)
self._expanded_id = module_id
self._expand_reveal.set_reveal_child(True)
# bouncy scale pop (CSS @keyframes); the class was cleared on collapse so
# re-adding it here replays the animation on every expand.
self._expand_card.add_css_class("quad-pop")
self.grid.add_css_class("dimmed")
card.on_show()
def request_collapse(self) -> None:
self._expand_reveal.set_reveal_child(False)
self._expand_reveal.set_visible(False)
self._expand_card.remove_css_class("quad-pop") # reset so the pop replays
self._expanded_id = None
self.grid.remove_css_class("dimmed")
# Drop the reference to the reparented widget so the card can reuse it.

View File

@ -207,6 +207,13 @@ hl.animation({ leaf = "fade", enabled = true, speed = 7, bezier = "
-- from regular workspace transitions which use horizontal slides by default.
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 10, bezier = "default", style = "slidevert" })
-- Layer-shell surfaces (the astal-menu control centre, notifications, the bar) slide
-- in from their anchored edge with the bouncy myBezier curve, so opening the menu
-- reads as a springy slide-down rather than a plain fade. (A per-namespace layerrule
-- was tried but this hyprlua build doesn't honour its animation timing; the global
-- `layers` leaf does.)
hl.animation({ leaf = "layers", enabled = true, speed = 5, bezier = "myBezier", style = "slide" })
--------------
---- DEVICE ---
--------------