authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-10-04 08:58:25-03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-04 08:58:25-03:00
logd3bec62ec167e783412effbc929da77167f08c4d
tree72970f2d5c4bf92afbdba26544e398b8216d2a80
parentc346fb679bac106c4c162ab145c27e3c8b9640bd
signature Signed by PGP key B5690EEEBB952194

fix(web): reveal sidebar actions for secondary hovering pointers (#15536)


2 files changed, 18 insertions(+), 9 deletions(-)

apps/web/src/components/Sidebar.tsx+9-9
...@@ -1807,7 +1807,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1807,7 +1807,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1807 <span1807 <span
1808 className={cn(1808 className={cn(
1809 "inline-flex justify-end tabular-nums text-secondary-label transition-opacity",1809 "inline-flex justify-end tabular-nums text-secondary-label transition-opacity",
1810 !isWoke && "group-hover/sidebar-row:opacity-0",1810 !isWoke && "group-any-hover/sidebar-row:opacity-0",
1811 )}1811 )}
1812 >1812 >
1813 {variantAction === "unsnooze" && props.snoozeWakeLabelText !== null ? (1813 {variantAction === "unsnooze" && props.snoozeWakeLabelText !== null ? (
...@@ -1851,8 +1851,8 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1851,8 +1851,8 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1851 onClick={handleUnsnoozeClick}1851 onClick={handleUnsnoozeClick}
1852 onPointerDown={handleActionPointerDown}1852 onPointerDown={handleActionPointerDown}
1853 className={cn(1853 className={cn(
1854 "pointer-events-none absolute inset-y-0 right-0 -mr-1 inline-flex cursor-pointer items-center gap-1 rounded-md bg-transparent px-1.5 text-xs text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:pointer-events-auto focus-visible:opacity-100 group-hover/sidebar-row:pointer-events-auto group-hover/sidebar-row:opacity-100",1854 "pointer-events-none absolute inset-y-0 right-0 -mr-1 inline-flex cursor-pointer items-center gap-1 rounded-md bg-transparent px-1.5 text-xs text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:pointer-events-auto focus-visible:opacity-100 group-any-hover/sidebar-row:pointer-events-auto group-any-hover/sidebar-row:opacity-100",
1855 isWoke && "group-hover/sidebar-row:static",1855 isWoke && "group-any-hover/sidebar-row:static",
1856 )}1856 )}
1857 >1857 >
1858 <AlarmClockOffIcon className="mb-px size-3" />1858 <AlarmClockOffIcon className="mb-px size-3" />
...@@ -1868,8 +1868,8 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1868,8 +1868,8 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1868 onClick={handleUnsettleClick}1868 onClick={handleUnsettleClick}
1869 onPointerDown={handleActionPointerDown}1869 onPointerDown={handleActionPointerDown}
1870 className={cn(1870 className={cn(
1871 "pointer-events-none absolute inset-y-0 right-0 -mr-1 inline-flex cursor-pointer items-center gap-1 rounded-md bg-transparent px-1.5 text-xs text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:pointer-events-auto focus-visible:opacity-100 group-hover/sidebar-row:pointer-events-auto group-hover/sidebar-row:opacity-100",1871 "pointer-events-none absolute inset-y-0 right-0 -mr-1 inline-flex cursor-pointer items-center gap-1 rounded-md bg-transparent px-1.5 text-xs text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:pointer-events-auto focus-visible:opacity-100 group-any-hover/sidebar-row:pointer-events-auto group-any-hover/sidebar-row:opacity-100",
1872 isWoke && "group-hover/sidebar-row:static",1872 isWoke && "group-any-hover/sidebar-row:static",
1873 )}1873 )}
1874 />1874 />
1875 }1875 }
...@@ -1885,8 +1885,8 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1885,8 +1885,8 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1885 onClick={handleSettleClick}1885 onClick={handleSettleClick}
1886 onPointerDown={handleActionPointerDown}1886 onPointerDown={handleActionPointerDown}
1887 className={cn(1887 className={cn(
1888 "pointer-events-none absolute inset-y-0 right-0 inline-flex cursor-pointer items-center gap-1 rounded-md bg-transparent px-2 text-xs text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:pointer-events-auto focus-visible:opacity-100 group-hover/sidebar-row:pointer-events-auto group-hover/sidebar-row:opacity-100",1888 "pointer-events-none absolute inset-y-0 right-0 inline-flex cursor-pointer items-center gap-1 rounded-md bg-transparent px-2 text-xs text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:pointer-events-auto focus-visible:opacity-100 group-any-hover/sidebar-row:pointer-events-auto group-any-hover/sidebar-row:opacity-100",
1889 isWoke && "group-hover/sidebar-row:static",1889 isWoke && "group-any-hover/sidebar-row:static",
1890 )}1890 )}
1891 >1891 >
1892 <CheckIcon className="size-3" />1892 <CheckIcon className="size-3" />
...@@ -1975,7 +1975,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1975,7 +1975,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1975 className={cn(1975 className={cn(
1976 isWokeStatus1976 isWokeStatus
1977 ? "pointer-events-auto"1977 ? "pointer-events-auto"
1978 : "pointer-events-none group-has-[:focus-visible]/sidebar-status-slot:absolute group-has-[:focus-visible]/sidebar-status-slot:right-0 group-has-[:focus-visible]/sidebar-status-slot:opacity-0 group-hover/sidebar-row:absolute group-hover/sidebar-row:right-0 group-hover/sidebar-row:opacity-0",1978 : "pointer-events-none group-has-[:focus-visible]/sidebar-status-slot:absolute group-has-[:focus-visible]/sidebar-status-slot:right-0 group-has-[:focus-visible]/sidebar-status-slot:opacity-0 group-any-hover/sidebar-row:absolute group-any-hover/sidebar-row:right-0 group-any-hover/sidebar-row:opacity-0",
1979 "flex items-center self-center justify-self-end tabular-nums text-secondary-label transition-opacity",1979 "flex items-center self-center justify-self-end tabular-nums text-secondary-label transition-opacity",
1980 snoozeMenuOpen && "pointer-events-none absolute right-0 opacity-0",1980 snoozeMenuOpen && "pointer-events-none absolute right-0 opacity-0",
1981 )}1981 )}
...@@ -2042,7 +2042,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -2042,7 +2042,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
2042 // would keep the controls pinned over the status label2042 // would keep the controls pinned over the status label
2043 // once the pointer moves away (e.g. after a failed2043 // once the pointer moves away (e.g. after a failed
2044 // settle) instead of cross-fading back.2044 // settle) instead of cross-fading back.
2045 "pointer-events-none absolute inset-y-0 right-0 flex items-stretch opacity-0 transition-opacity has-[:focus-visible]:pointer-events-auto has-[:focus-visible]:static has-[:focus-visible]:opacity-100 group-hover/sidebar-row:pointer-events-auto group-hover/sidebar-row:static group-hover/sidebar-row:opacity-100",2045 "pointer-events-none absolute inset-y-0 right-0 flex items-stretch opacity-0 transition-opacity has-[:focus-visible]:pointer-events-auto has-[:focus-visible]:static has-[:focus-visible]:opacity-100 group-any-hover/sidebar-row:pointer-events-auto group-any-hover/sidebar-row:static group-any-hover/sidebar-row:opacity-100",
2046 snoozeMenuOpen && "pointer-events-auto static opacity-100",2046 snoozeMenuOpen && "pointer-events-auto static opacity-100",
2047 )}2047 )}
2048 >2048 >
apps/web/src/index.css+9
...@@ -5,6 +5,15 @@...@@ -5,6 +5,15 @@
5/* Window Controls Overlay: active when Electron exposes native titlebar control geometry. */5/* Window Controls Overlay: active when Electron exposes native titlebar control geometry. */
6@custom-variant wco (&:is(.wco, .wco *));6@custom-variant wco (&:is(.wco, .wco *));
77
8/* Secondary hovering pointers reveal sidebar actions on touch-primary devices. */
9@custom-variant any-hover {
10 @media (any-hover: hover) {
11 &:hover {
12 @slot;
13 }
14 }
15}
16
8/* On mobile, morph the expanded hero composer into the compact docked17/* On mobile, morph the expanded hero composer into the compact docked
9 composer while it moves; the rest of the app remains visually stationary. */18 composer while it moves; the rest of the app remains visually stationary. */
10html[data-mobile-composer-route-transition="true"]::view-transition-old(root),19html[data-mobile-composer-route-transition="true"]::view-transition-old(root),