Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion libs/code/deepagents_code/widgets/welcome.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from textual.widgets import Static

if TYPE_CHECKING:
from textual.events import Click
from textual.events import Click, MouseMove
from textual.timer import Timer

from deepagents_code import theme
Expand Down Expand Up @@ -341,6 +341,18 @@ def on_click(self, event: Click) -> None: # noqa: PLR6301 # Textual event hand
"""Open style-embedded hyperlinks on single click."""
open_style_link(event)

def on_mouse_move(self, event: MouseMove) -> None:
"""Show a hand pointer over link spans and reset it elsewhere.

`auto_links` is disabled to avoid a hover-refresh flicker, so the
pointer shape is updated manually from the style under the cursor.
"""
self.styles.pointer = "pointer" if event.style.link else "default"

def on_leave(self) -> None:
"""Reset the pointer shape when the mouse leaves the banner."""
self.styles.pointer = "default"

def _build_banner(self, project_url: str | None = None) -> Content:
"""Build the banner content.

Expand Down
34 changes: 34 additions & 0 deletions libs/code/tests/unit_tests/test_welcome.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,40 @@ def test_click_with_browser_error_is_graceful(self) -> None:
event.stop.assert_not_called()


class TestPointerShapeOnHover:
"""Tests for the hand pointer shown when hovering link spans."""

def test_mouse_move_over_link_sets_pointer(self) -> None:
"""Hovering a link span should show the hand pointer."""
widget = _make_banner(thread_id="abc")
event = MagicMock()
event.style = Style(link="https://example.com")

widget.on_mouse_move(event)

assert widget.styles.pointer == "pointer"

def test_mouse_move_off_link_resets_pointer(self) -> None:
"""Hovering non-link text should reset to the default pointer."""
widget = _make_banner(thread_id="abc")
widget.styles.pointer = "pointer"
event = MagicMock()
event.style = Style()

widget.on_mouse_move(event)

assert widget.styles.pointer == "default"

def test_leave_resets_pointer(self) -> None:
"""Leaving the banner should reset to the default pointer."""
widget = _make_banner(thread_id="abc")
widget.styles.pointer = "pointer"

widget.on_leave()

assert widget.styles.pointer == "default"


class TestBuildWelcomeFooter:
"""Tests for the `build_welcome_footer` standalone function."""

Expand Down
Loading