authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-02 15:57:50-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-02 15:57:50-07:00
log064392ffc7fc58fcc3018fd2ba2df33fbb21f1de
treee7f75f36425fee59c10157f7911aecdfb649d0f3
parentb59b7d0af9536a2d61ddfcf8d33420b890b2faca
signature Signed by PGP key B5690EEEBB952194

fix(web): offer browser profiles from the empty-panel launcher (#9279)


1 files changed, 69 insertions(+), 17 deletions(-)

apps/web/src/components/RightPanelTabs.tsx+69-17
......@@ -8,6 +8,7 @@ import type {
88import { getTerminalLabel } from "@t3tools/shared/terminalLabels";
99import {
1010 Bot,
11 ChevronDown,
1112 FileDiff,
1213 Files,
1314 GitPullRequest,
......@@ -283,6 +284,8 @@ function SurfaceMenuItem(props: {
283284 */
284285function RightPanelEmptyState(props: {
285286 onAddBrowser: () => void;
287 onAddBrowserInProfile: (profileId: string) => void;
288 browserProfiles: ReadonlyArray<{ readonly id: string; readonly name: string }>;
286289 onAddTerminal: () => void;
287290 onAddDiff: () => void;
288291 onAddFiles: () => void;
......@@ -473,31 +476,78 @@ function RightPanelEmptyState(props: {
473476 <div className="grid grid-cols-2 gap-2">
474477 {actions.map((action) =>
475478 action.available ? (
476 <button
479 // The card is itself a button, so the profile chooser sits beside
480 // it in a wrapper rather than inside it. Hover lives on the
481 // wrapper: the chooser overlays the card, and a pointer moving
482 // onto it must not read as leaving the card.
483 <div
477484 key={action.label}
478 type="button"
479 onClick={action.onClick}
485 className="group relative"
480486 onMouseEnter={() => setHighlight(availableActions.indexOf(action))}
481487 onMouseLeave={() =>
482488 setHighlight((current) =>
483489 current === availableActions.indexOf(action) ? -1 : current,
484490 )
485491 }
486 className={cn(
487 "relative flex w-full cursor-pointer flex-col items-start p-4 text-left transition hover:border-border hover:bg-accent/60",
488 cardShellClass,
489 isHighlighted(action) && highlightedCardClass,
490 )}
491492 >
492 <Kbd className="absolute top-3 right-3">{action.shortcut}</Kbd>
493 <span className="flex items-center gap-2 pe-8">
494 {actionIcon(action)}
495 <span className="font-medium text-sm">{action.label}</span>
496 </span>
497 <span className="mt-1.5 text-muted-foreground text-xs leading-relaxed">
498 {action.description}
499 </span>
500 </button>
493 <button
494 type="button"
495 onClick={action.onClick}
496 className={cn(
497 // Full height: the wrapper is the grid item that stretches
498 // to the row, so the button must fill it to stay level with
499 // its neighbour and keep the chooser anchored inside.
500 "relative flex h-full w-full cursor-pointer flex-col items-start p-4 text-left transition group-hover:border-border group-hover:bg-accent/60",
501 cardShellClass,
502 isHighlighted(action) && highlightedCardClass,
503 )}
504 >
505 <Kbd className="absolute top-3 right-3">{action.shortcut}</Kbd>
506 <span className="flex items-center gap-2 pe-8">
507 {actionIcon(action)}
508 <span className="font-medium text-sm">{action.label}</span>
509 </span>
510 <span className="mt-1.5 text-muted-foreground text-xs leading-relaxed">
511 {action.description}
512 </span>
513 </button>
514 {/*
515 Same choice the tab bar's "+" menu offers: the card opens the
516 default profile, the chevron picks another. Only worth showing
517 once there is something to choose between.
518 */}
519 {action.label === "Browser" && props.browserProfiles.length > 1 ? (
520 <Menu>
521 <MenuTrigger
522 render={
523 <Button
524 aria-label="Open browser in a profile"
525 className="absolute right-3 bottom-3 [--control-icon-color:currentColor]"
526 size="icon-xs"
527 variant="ghost-muted"
528 />
529 }
530 >
531 <ChevronDown className="size-3.5" />
532 </MenuTrigger>
533 <MenuPopup
534 align="end"
535 side="bottom"
536 sideOffset={6}
537 className="min-w-40 max-w-56"
538 >
539 {props.browserProfiles.map((profile) => (
540 <MenuItem
541 key={profile.id}
542 onClick={() => props.onAddBrowserInProfile(profile.id)}
543 >
544 <span className="min-w-0 truncate">{profile.name}</span>
545 </MenuItem>
546 ))}
547 </MenuPopup>
548 </Menu>
549 ) : null}
550 </div>
501551 ) : (
502552 <div
503553 key={action.label}
......@@ -1053,6 +1103,8 @@ export function RightPanelTabs(props: RightPanelTabsProps) {
10531103 {props.activeSurfaceId === null ? (
10541104 <RightPanelEmptyState
10551105 onAddBrowser={props.onAddBrowser}
1106 onAddBrowserInProfile={props.onAddBrowserInProfile}
1107 browserProfiles={browserProfiles}
10561108 onAddTerminal={props.onAddTerminal}
10571109 onAddDiff={props.onAddDiff}
10581110 onAddFiles={props.onAddFiles}