Skip to content

Annie/UI fixes#11

Open
anchen9 wants to merge 5 commits into
mainfrom
annie/ui-fixes
Open

Annie/UI fixes#11
anchen9 wants to merge 5 commits into
mainfrom
annie/ui-fixes

Conversation

@anchen9
Copy link
Copy Markdown
Contributor

@anchen9 anchen9 commented May 3, 2026

Summary

This PR implements some UI changes suggested by May:

  • Making the icon 80% of its previous size
  • Making the icon clamp to the sides better
  • Making the icon draggable (right now it only drags and locks to either the left or the right sides
  • Allowing for the icon to be x-ed out so that people can fully close the extension and reopen through clicking the toolbar.
Screenshot 2026-05-03 at 4 11 10 PM Screenshot 2026-05-03 at 4 11 40 PM Screenshot 2026-05-03 at 4 11 32 PM

Remaining TODOs:

  • Making panel itself draggable (buggy right now)

Test Plan

  • Tested through dragging

Notes

Breaking Changes

Copy link
Copy Markdown
Contributor

@benkoppe benkoppe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this! I like the drag functionality. I had a few issues with the panel drag scope and accessibility, etc.

[beginDrag],
);

const handlePanelPointerDown = useCallback(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This starts a drag with surface: "panel", but the shared drag logic only updates iconPos. Since the panel itself has fixed top/height and only docks based on dockRight, dragging the panel/header can move the hidden launcher position and make the panel jump sides instead of actually dragging the panel.

const dockRight = iconPos.x + ICON_W / 2 >= window.innerWidth / 2;

useEffect(() => {
const handler = () => setIsDismissed(false);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only restores the floating launcher after dismissal, but it does not reopen the panel. The PR description says users can close the extension and reopen it through the toolbar, so I’d expect toolbar click to show the panel UI directly. Should this also call setIsOpen(true)?

"absolute top-0 left-[3px] -translate-y-1/2",
"flex h-[18px] w-[18px] items-center justify-center",
"rounded-full bg-white shadow-[0_1px_4px_rgba(0,0,0,0.22)]",
"opacity-0 transition-opacity duration-150 group-hover:opacity-100",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dismiss button is invisible until hover, but it remains keyboard-focusable. A keyboard user can tab to a button they cannot see. Can we add a focus-visible state like focus-visible:opacity-100, or otherwise avoid making the hidden control tabbable?

onClick={() => setIsOpen(true)}
{/* ── Floating tab ───────────────────────────────────────────────────── */}
<div
role="button"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is implementing button keyboard behavior manually, Space should call e.preventDefault() before opening the panel. Otherwise pressing Space while focused can also scroll the host page.


const handleIconPointerDown = useCallback(
(e: React.PointerEvent) => {
if ((e.target as HTMLElement).closest("[data-dismiss-btn]")) return;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid this cast by checking e.target instanceof Element first? That would be safer and match the helper functions above.

}}
onPointerDown={(e) => e.stopPropagation()}
className={[
"absolute top-0 left-[3px] -translate-y-1/2",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The icon is mirrored when docked left, but the dismiss button is always positioned with left-[3px]. Should this flip based on dockRight so the close button stays in the expected outside/top corner on both sides?

anchen9 and others added 2 commits May 19, 2026 23:21
- Panel drag now uses panelDragLeft state so the panel visually follows
  the cursor; iconPos is only updated at snap time, eliminating the
  side-flicker described in review comment #1.
- LOOP_SHOW_PANEL handler now calls setIsOpen(true) in addition to
  clearing isDismissed, so toolbar clicks re-open the panel directly.
- Dismiss button gains focus-visible:opacity-100 so keyboard users can
  see the control they are focused on.
- Space key on the launcher div now calls e.preventDefault() to prevent
  the host page from scrolling.
- Replaced (e.target as HTMLElement) cast with an instanceof Element
  guard in handleIconPointerDown.
- Dismiss button position flips based on dockRight so the X always
  appears at the outer/viewport-edge top corner on both sides.
- Add grab/grabbing cursor affordance to the panel header drag zone
  via content.css.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

2 participants