feat(ui): unify overlay animations and trim tooltip delays

Use base-ui's transition-status pattern (data-starting-style /
data-ending-style) for Dialog, DropdownMenu, Select, Tooltip and Popover
so open/close animate consistently at 150ms ease-out without flicker.
Wrap dialog popups in a centered flex container so the scale animation
no longer fights with translate-based positioning, and switch
PendingChangesBar to a real Popover so it actually animates closed.

Convert ScheduledTaskEditorDialog from raw Radix to the shared Dialog
wrapper, give ScheduledTasksDialog a stable min-height to prevent layout
shift mid-animation, and reset NewWorktreeDialog form state on open
instead of close so fields don't empty during the close transition.

Drop tooltip delay from 700ms to 300ms globally and remove all
per-component overrides except the model/variant/agent selectors in the
chat input (600ms).
This commit is contained in:
Bohdan Triapitsyn
2026-04-30 22:41:33 +03:00
parent 24533dfe32
commit 63da6e6292
57 changed files with 305 additions and 314 deletions
+4 -4
View File
@@ -828,7 +828,7 @@ function App({ apis }: AppProps) {
<ErrorBoundary>
<SyncProvider sdk={opencodeClient.getSdkClient()} directory={currentDirectory || ''}>
<RuntimeAPIProvider apis={apis}>
<TooltipProvider delayDuration={700} skipDelayDuration={150}>
<TooltipProvider delayDuration={300} skipDelayDuration={150}>
<div className="h-full text-foreground bg-background">
<EmbeddedSessionSelectionGate embeddedSessionChat={embeddedSessionChat} isVSCodeRuntime={isVSCodeRuntime} />
<SyncAppEffects embeddedBackgroundWorkEnabled={embeddedBackgroundWorkEnabled} />
@@ -873,7 +873,7 @@ function App({ apis }: AppProps) {
<ErrorBoundary>
<SyncProvider sdk={opencodeClient.getSdkClient()} directory={currentDirectory || ''}>
<RuntimeAPIProvider apis={apis}>
<TooltipProvider delayDuration={700} skipDelayDuration={150}>
<TooltipProvider delayDuration={300} skipDelayDuration={150}>
<div className="h-full text-foreground bg-background">
<SyncAppEffects embeddedBackgroundWorkEnabled={embeddedBackgroundWorkEnabled} />
<AgentManagerView />
@@ -891,7 +891,7 @@ function App({ apis }: AppProps) {
<SyncProvider sdk={opencodeClient.getSdkClient()} directory={currentDirectory || ''}>
<RuntimeAPIProvider apis={apis}>
<FireworksProvider>
<TooltipProvider delayDuration={700} skipDelayDuration={150}>
<TooltipProvider delayDuration={300} skipDelayDuration={150}>
<div className="h-full text-foreground bg-background">
<SyncAppEffects embeddedBackgroundWorkEnabled={embeddedBackgroundWorkEnabled} />
<VSCodeLayout />
@@ -916,7 +916,7 @@ function App({ apis }: AppProps) {
<RuntimeAPIProvider apis={apis}>
<FireworksProvider>
<VoiceProvider>
<TooltipProvider delayDuration={700} skipDelayDuration={150}>
<TooltipProvider delayDuration={300} skipDelayDuration={150}>
<div className={isDesktopRuntime ? 'h-full text-foreground bg-transparent' : 'h-full text-foreground bg-background'}>
<SyncAppEffects embeddedBackgroundWorkEnabled={embeddedBackgroundWorkEnabled} />
<MainLayout />
@@ -431,7 +431,7 @@ const PermissionAutoAcceptButton = React.memo(function PermissionAutoAcceptButto
}
return (
<Tooltip delayDuration={600}>
<Tooltip>
<TooltipTrigger asChild>
{button}
</TooltipTrigger>
@@ -454,7 +454,7 @@ const FocusModeButton = React.memo(function FocusModeButton(props: FocusModeButt
const { t } = useI18n();
return (
<Tooltip delayDuration={600}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -468,7 +468,7 @@ export const MessageFilesDisplay = memo(({ files, onShowPopup, compact = false }
const filename = resolveDisplayName(file) || 'Image';
return (
<Tooltip key={`img-${file.url || file.filename || index}`} delayDuration={1000}>
<Tooltip key={`img-${file.url || file.filename || index}`}>
<TooltipTrigger asChild>
<button
type="button"
@@ -2654,7 +2654,7 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
let currentFlatIndex = 0;
return (
<Tooltip delayDuration={1000}>
<Tooltip delayDuration={600}>
{!isCompact ? (
<DropdownMenu open={isReady && agentMenuOpen} onOpenChange={isReady ? handleModelMenuOpenChange : undefined}>
<TooltipTrigger asChild>
@@ -3119,7 +3119,7 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
}
return (
<Tooltip delayDuration={800}>
<Tooltip delayDuration={600}>
<DropdownMenu>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
@@ -3182,7 +3182,7 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
if (!isCompact) {
return (
<div className="flex items-center gap-2 min-w-0">
<Tooltip delayDuration={1000}>
<Tooltip delayDuration={600}>
<DropdownMenu open={isReady && isAgentSelectorOpen} onOpenChange={isReady ? setIsAgentSelectorOpen : undefined}>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
@@ -1,4 +1,5 @@
import React from 'react';
import { Popover } from '@base-ui/react/popover';
import { RiFileEditLine, RiArrowDownSLine, RiArrowUpSLine } from '@remixicon/react';
import { useDirectoryStore } from '@/stores/useDirectoryStore';
import { useGitStore, useIsGitRepo } from '@/stores/useGitStore';
@@ -27,7 +28,6 @@ export const PendingChangesBar: React.FC = React.memo(() => {
);
const ensureStatus = useGitStore((s) => s.ensureStatus);
const fetchStatus = useGitStore((s) => s.fetchStatus);
const popoverRef = React.useRef<HTMLDivElement>(null);
// Seed git store for currentDirectory so the bar can render independently of
// DiffView/GitView/right-sidebar mounting. ensureStatus has a 5s staleness
@@ -64,19 +64,6 @@ export const PendingChangesBar: React.FC = React.memo(() => {
return { totalAdded: added, totalRemoved: removed };
}, [gitChangedFiles]);
React.useEffect(() => {
if (!isExpanded) return;
const handleClickOutside = (event: MouseEvent) => {
if (popoverRef.current && !popoverRef.current.contains(event.target as Node)) {
setIsExpanded(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, [isExpanded]);
if (isGitRepo !== true) return null;
if (gitChangedFiles.length === 0) return null;
@@ -109,41 +96,45 @@ export const PendingChangesBar: React.FC = React.memo(() => {
: t('chat.pendingChanges.fileCountPlural', { count: fileCount });
return (
<div className="relative flex min-w-0 items-center" ref={popoverRef}>
<button
type="button"
onClick={() => setIsExpanded((prev) => !prev)}
className="flex min-w-0 max-w-full items-center gap-1 text-left text-muted-foreground"
>
<RiFileEditLine className="h-3.5 w-3.5 flex-shrink-0 text-[var(--status-warning)]" />
<span className="min-w-0 typography-ui-label text-foreground flex-shrink-0">{labelHead}</span>
<span className="status-row__changed-label min-w-0 typography-ui-label text-foreground truncate">
{t('chat.pendingChanges.changedInWorkspace')}
</span>
<span className="text-[0.75rem] tabular-nums inline-flex items-baseline gap-1 flex-shrink-0">
{totalAdded > 0 ? <span style={{ color: 'var(--status-success)' }}>+{totalAdded}</span> : null}
{totalRemoved > 0 ? <span style={{ color: 'var(--status-error)' }}>-{totalRemoved}</span> : null}
</span>
{isExpanded ? (
<RiArrowUpSLine className="h-3.5 w-3.5 flex-shrink-0" />
) : (
<RiArrowDownSLine className="h-3.5 w-3.5 flex-shrink-0" />
)}
</button>
{isExpanded ? (
<div
style={changedFilesPopoverStyle}
className={`${changedFilesPopoverClassName} absolute z-50 left-0 bottom-full mb-1 slide-in-from-bottom-2`}
>
<ChangedFilesList
files={gitChangedFiles}
currentDirectory={currentDirectory}
onOpenFile={handleOpenFile}
/>
</div>
) : null}
</div>
<Popover.Root open={isExpanded} onOpenChange={setIsExpanded}>
<Popover.Trigger
render={
<button
type="button"
className="flex min-w-0 max-w-full items-center gap-1 text-left text-muted-foreground"
>
<RiFileEditLine className="h-3.5 w-3.5 flex-shrink-0 text-[var(--status-warning)]" />
<span className="min-w-0 typography-ui-label text-foreground flex-shrink-0">{labelHead}</span>
<span className="status-row__changed-label min-w-0 typography-ui-label text-foreground truncate">
{t('chat.pendingChanges.changedInWorkspace')}
</span>
<span className="text-[0.75rem] tabular-nums inline-flex items-baseline gap-1 flex-shrink-0">
{totalAdded > 0 ? <span style={{ color: 'var(--status-success)' }}>+{totalAdded}</span> : null}
{totalRemoved > 0 ? <span style={{ color: 'var(--status-error)' }}>-{totalRemoved}</span> : null}
</span>
{isExpanded ? (
<RiArrowUpSLine className="h-3.5 w-3.5 flex-shrink-0" />
) : (
<RiArrowDownSLine className="h-3.5 w-3.5 flex-shrink-0" />
)}
</button>
}
/>
<Popover.Portal>
<Popover.Positioner side="top" align="start" sideOffset={4} collisionPadding={8}>
<Popover.Popup
style={changedFilesPopoverStyle}
className={`${changedFilesPopoverClassName} transition-all duration-150 ease-out data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95`}
>
<ChangedFilesList
files={gitChangedFiles}
currentDirectory={currentDirectory}
onOpenFile={handleOpenFile}
/>
</Popover.Popup>
</Popover.Positioner>
</Popover.Portal>
</Popover.Root>
);
});
@@ -87,7 +87,7 @@ const TodoItemRow: React.FC<TodoItemRowProps> = ({ todo }) => {
return (
<div className="flex items-center min-w-0 py-0.5 gap-2">
<Tooltip delayDuration={200}>
<Tooltip>
<TooltipTrigger asChild>
<span className="flex-shrink-0">{statusIcon}</span>
</TooltipTrigger>
@@ -103,7 +103,7 @@ const TodoItemRow: React.FC<TodoItemRowProps> = ({ todo }) => {
>
{todo.content}
</span>
<Tooltip delayDuration={200}>
<Tooltip>
<TooltipTrigger asChild>
<span
className={cn(
@@ -145,7 +145,7 @@ export const TimelineDialog: React.FC<TimelineDialogProps> = ({
</span>
<div className="hidden group-hover:flex gap-1">
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -162,7 +162,7 @@ export const TimelineDialog: React.FC<TimelineDialogProps> = ({
<TooltipContent sideOffset={6}>{t('chat.timeline.actions.revertFromHere')}</TooltipContent>
</Tooltip>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -84,7 +84,7 @@ export const TurnChangedFilesDropdown: React.FC<TurnChangedFilesDropdownProps> =
return (
<Popover.Root open={isExpanded} onOpenChange={setIsExpanded}>
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Popover.Trigger
render={
@@ -113,7 +113,7 @@ export const TurnChangedFilesDropdown: React.FC<TurnChangedFilesDropdownProps> =
<Popover.Positioner side="top" align="start" sideOffset={4} collisionPadding={8}>
<Popover.Popup
style={changedFilesPopoverStyle}
className={changedFilesPopoverClassName}
className={`${changedFilesPopoverClassName} transition-all duration-150 ease-out data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95`}
>
<ChangedFilesList
files={changedFiles}
@@ -1,7 +1,7 @@
import type { CSSProperties } from 'react';
export const changedFilesPopoverClassName =
"w-max min-w-[280px] max-w-full rounded-xl p-1 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)] animate-in fade-in-0 zoom-in-95 duration-150";
"w-max min-w-[280px] max-w-full rounded-xl p-1 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)] origin-[var(--transform-origin)]";
export const changedFilesPopoverStyle: CSSProperties = {
maxWidth: 'calc(100cqw - 4ch)',
@@ -444,7 +444,7 @@ const UserMessageBody = React.memo(({ messageId, parts, isMobile, hasTouchInput,
)}
>
{onRevert && (
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
@@ -465,7 +465,7 @@ const UserMessageBody = React.memo(({ messageId, parts, isMobile, hasTouchInput,
</Tooltip>
)}
{onFork && (
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
@@ -486,7 +486,7 @@ const UserMessageBody = React.memo(({ messageId, parts, isMobile, hasTouchInput,
</Tooltip>
)}
{canCopyMessage && hasCopyableText && (
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
@@ -734,7 +734,7 @@ const AssistantMessageActionButtons = React.memo(({
return (
<>
{onCopyMessage && (
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
@@ -773,7 +773,7 @@ const AssistantMessageActionButtons = React.memo(({
<TooltipContent sideOffset={6}>{t('chat.messageBody.actions.copyAnswer')}</TooltipContent>
</Tooltip>
)}
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
@@ -799,7 +799,7 @@ const AssistantMessageActionButtons = React.memo(({
<TooltipContent sideOffset={6}>{isSharing ? t('chat.messageBody.actions.savingImage') : t('chat.messageBody.actions.saveAsImage')}</TooltipContent>
</Tooltip>
{showMessageTTSButtons && hasCopyableText && (
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
@@ -1698,7 +1698,7 @@ const AssistantMessageBody = React.memo(({
const finalTurnActionButtons = (
<>
{canOpenMessagePreview && messagePreviewUrl ? (
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
@@ -1723,7 +1723,7 @@ const AssistantMessageBody = React.memo(({
</Tooltip>
) : null}
{!isVSCode ? (
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
@@ -1743,7 +1743,7 @@ const AssistantMessageBody = React.memo(({
<TooltipContent sideOffset={6}>{t('chat.messageBody.actions.saveAsPlan')}</TooltipContent>
</Tooltip>
) : null}
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
@@ -1759,7 +1759,7 @@ const AssistantMessageBody = React.memo(({
<TooltipContent sideOffset={6}>{t('chat.messageBody.actions.startNewSession')}</TooltipContent>
</Tooltip>
{!isVSCode ? (
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
@@ -1846,7 +1846,7 @@ const AssistantMessageBody = React.memo(({
</div>
<div className="flex items-center gap-1.5">
{turnDurationText ? (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<span className="text-sm text-muted-foreground/60 tabular-nums flex items-center gap-1">
<RiHourglassLine className="h-3.5 w-3.5" />
@@ -1857,7 +1857,7 @@ const AssistantMessageBody = React.memo(({
</Tooltip>
) : null}
{footerTimestamp ? (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<span
className={footerTimestampClassName}
@@ -928,7 +928,7 @@ export function DesktopHostSwitcherDialog({
)
)}
<Tooltip delayDuration={700}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -950,7 +950,7 @@ export function DesktopHostSwitcherDialog({
</TooltipContent>
</Tooltip>
<Tooltip delayDuration={700}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -1328,7 +1328,7 @@ export function DesktopHostSwitcherButton({ headerIconButtonClass }: DesktopHost
return (
<>
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
+7 -7
View File
@@ -98,7 +98,7 @@ const HeaderIconActionButton = React.memo(function HeaderIconActionButton({
}
return (
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -308,7 +308,7 @@ const DesktopServicesMenu = React.memo(function DesktopServicesMenu({
}
}}
>
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<button
@@ -1726,7 +1726,7 @@ export const Header: React.FC<HeaderProps> = ({
const desktopSidebarActions = (
<>
{showPlanTab && (
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -1820,7 +1820,7 @@ export const Header: React.FC<HeaderProps> = ({
<div className={cn('flex min-w-0 flex-1 items-center', !isSidebarOpen && 'pl-3')}>
{!isLeftSidebarOpen ? (
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -1970,7 +1970,7 @@ export const Header: React.FC<HeaderProps> = ({
const isDiffTab = tab.icon === 'diff';
const Icon = isDiffTab ? null : (tab.icon as RemixiconComponentType);
return (
<Tooltip key={tab.id} delayDuration={500}>
<Tooltip key={tab.id}>
<TooltipTrigger asChild>
<button
type="button"
@@ -2039,7 +2039,7 @@ export const Header: React.FC<HeaderProps> = ({
}
}}
>
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<button
@@ -2293,7 +2293,7 @@ export const Header: React.FC<HeaderProps> = ({
</DropdownMenu>
{onToggleRightDrawer ? (
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -784,7 +784,7 @@ export const ProjectActionsButton = ({
: <SelectedIcon className="h-5 w-5" />}
</button>
{showSelectedPreviewButton ? (
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -882,7 +882,7 @@ export const ProjectActionsButton = ({
</button>
{showSelectedPreviewButton ? (
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -152,7 +152,7 @@ export const McpDropdownContent: React.FC<McpDropdownContentProps> = ({ active,
>
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2 min-w-0">
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<span
className={cn(
@@ -305,7 +305,7 @@ export const McpDropdown: React.FC<McpDropdownProps> = ({ headerIconButtonClass
aria-label={tooltip}
/>
) : (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<span
className={cn(
@@ -427,7 +427,7 @@ export const McpDropdown: React.FC<McpDropdownProps> = ({ headerIconButtonClass
// Desktop: use DropdownMenu
return (
<DropdownMenu open={open} onOpenChange={handleDropdownOpenChange}>
<Tooltip delayDuration={1000} open={open ? false : tooltipOpen} onOpenChange={handleTooltipOpenChange}>
<Tooltip open={open ? false : tooltipOpen} onOpenChange={handleTooltipOpenChange}>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
{triggerButton}
@@ -56,7 +56,7 @@ interface MultiRunLauncherProps {
/** Info tooltip - small icon that shows helper text on hover */
const InfoTip: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<Tooltip delayDuration={200}>
<Tooltip>
<TooltipTrigger asChild>
<button type="button" tabIndex={-1} className="inline-flex items-center justify-center text-muted-foreground/50 hover:text-muted-foreground transition-colors">
<RiInformationLine className="h-3.5 w-3.5" />
@@ -605,7 +605,7 @@ export const MultiRunLauncher: React.FC<MultiRunLauncherProps> = ({
<h1 className="typography-ui-label font-medium">{t('multirun.launcher.title')}</h1>
{onCancel && (
<div className="absolute right-0 flex items-center pr-3">
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -845,7 +845,7 @@ export const MultiRunLauncher: React.FC<MultiRunLauncherProps> = ({
onChange={handleFileSelect}
accept="*/*"
/>
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -701,7 +701,7 @@ export const AgentsPage: React.FC = () => {
<div className="flex min-w-0 flex-col gap-1.5">
<div className="flex items-center gap-1.5">
<span className="typography-ui-label text-foreground">{t('settings.agents.page.field.mode')}</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -778,7 +778,7 @@ export const AgentsPage: React.FC = () => {
<div className={cn("flex min-w-0 flex-col", isMobile ? "w-full" : "sm:w-56 shrink-0")}>
<div className="flex items-center gap-1.5">
<span className="typography-ui-label text-foreground">{t('settings.agents.page.field.temperature')}</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -822,7 +822,7 @@ export const AgentsPage: React.FC = () => {
<div className={cn("flex min-w-0 flex-col", isMobile ? "w-full" : "sm:w-56 shrink-0")}>
<div className="flex items-center gap-1.5">
<span className="typography-ui-label text-foreground">{t('settings.agents.page.field.topP')}</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -296,7 +296,7 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
<div className="flex items-center gap-1.5 mb-1.5">
<label className="typography-ui-label text-foreground">{t('settings.gitIdentities.editor.field.userName')}</label>
{!isGlobalProfile && <span className="text-[var(--status-error)] text-xs">*</span>}
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -320,7 +320,7 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
<div className="flex items-center gap-1.5 mb-1.5">
<label className="typography-ui-label text-foreground">{t('settings.gitIdentities.editor.field.emailAddress')}</label>
{!isGlobalProfile && <span className="text-[var(--status-error)] text-xs">*</span>}
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -373,7 +373,7 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
<div>
<div className="flex items-center gap-1.5 mb-1.5">
<label className="typography-ui-label text-foreground">{t('settings.gitIdentities.editor.field.sshKeyPath')}</label>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -396,7 +396,7 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
<div className="flex items-center gap-1.5 mb-1.5">
<label className="typography-ui-label text-foreground">{t('settings.gitIdentities.editor.field.host')}</label>
<span className="text-[var(--status-error)] text-xs">*</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -267,7 +267,7 @@ export const MagicPromptsPage: React.FC = () => {
<div className="space-y-1">
<div className="flex items-center gap-2">
<h2 className="typography-ui-header font-semibold text-foreground">{tUnsafe(pageConfig.titleKey)}</h2>
<Tooltip delayDuration={700}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -304,7 +304,7 @@ export const MagicPromptsPage: React.FC = () => {
<div className="space-y-1">
<div className="flex flex-wrap items-center gap-2">
<h3 className="typography-ui-label text-foreground">{tUnsafe(block.titleKey)}</h3>
<Tooltip delayDuration={700}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -244,7 +244,7 @@ export const GitHubSettings: React.FC = () => {
<div className="mb-3 px-1 flex items-start justify-between gap-4">
<div className="flex items-center gap-2">
<h3 className="typography-ui-header font-semibold text-foreground">GitHub</h3>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -153,7 +153,7 @@ export const KeyboardShortcutsSettings: React.FC = () => {
>
{t('settings.openchamber.keyboardShortcuts.actions.resetAll')}
</Button>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -804,7 +804,7 @@ export const NotificationSettings: React.FC = () => {
<div className="flex min-w-0 flex-col sm:w-56 shrink-0">
<div className="flex items-center gap-2">
<span className="typography-ui-label text-foreground">{t('settings.notifications.page.summary.modelLabel')}</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -689,7 +689,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
>
{themesReloading ? t('settings.openchamber.visual.actions.reloadingThemes') : t('settings.openchamber.visual.actions.reloadThemes')}
</button>
<Tooltip delayDuration={700}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -1029,7 +1029,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
<div className={cn("flex min-w-0 flex-col", isMobile ? "w-full" : "w-56 shrink-0")}>
<div className="flex items-center gap-1.5">
<span className="typography-ui-label text-foreground">{t('settings.openchamber.visual.field.inputBarOffset')}</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -1095,7 +1095,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
/>
<div className="flex min-w-0 items-center gap-1.5">
<span className="typography-ui-label text-foreground">{t('settings.openchamber.visual.field.terminalQuickKeys')}</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -1551,7 +1551,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
/>
<div className="flex min-w-0 items-center gap-1.5">
<span className="typography-ui-label text-foreground">{t('settings.openchamber.visual.field.showSplitAssistantMessageActions')}</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 cursor-help text-muted-foreground/60" />
</TooltipTrigger>
@@ -1653,7 +1653,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
/>
<div className="flex min-w-0 items-center gap-1.5">
<span className="typography-ui-label text-foreground">{t('settings.openchamber.visual.field.queueMessagesByDefault')}</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -93,7 +93,7 @@ export const OpenCodeCliSettings: React.FC = () => {
<h3 className="typography-ui-header font-medium text-foreground">
{t('settings.openchamber.opencodeCli.title')}
</h3>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -63,7 +63,7 @@ export const SessionRetentionSettings: React.FC = () => {
<h3 className="typography-ui-header font-medium text-foreground">
{t('settings.openchamber.sessionRetention.title')}
</h3>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -1210,7 +1210,7 @@ export const TunnelSettings: React.FC = () => {
<p className="typography-ui-label text-foreground">{t('settings.openchamber.tunnel.field.tunnelType')}</p>
<div className="flex flex-wrap items-center gap-1">
{TUNNEL_MODE_OPTIONS.map((option) => (
<Tooltip key={option.value} delayDuration={700}>
<Tooltip key={option.value}>
<TooltipTrigger asChild>
<Button
variant="chip"
@@ -1481,7 +1481,7 @@ export const TunnelSettings: React.FC = () => {
<div className="flex items-center gap-1.5">
<p className="typography-meta text-muted-foreground/80">{t('settings.openchamber.tunnel.note.tokensSavedPerTunnel')}</p>
<Tooltip delayDuration={700}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -443,7 +443,7 @@ export const VoiceSettings: React.FC = () => {
<div className="flex min-w-0 flex-col gap-1.5">
<div className="flex items-center gap-1.5">
<span className="typography-ui-label text-foreground">{t('settings.voice.page.field.provider')}</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -732,7 +732,7 @@ export const VoiceSettings: React.FC = () => {
<div className="flex min-w-0 flex-col gap-1.5">
<div className="flex items-center gap-1.5">
<span className="typography-ui-label text-foreground">{t('settings.voice.page.field.provider')}</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -273,7 +273,7 @@ export const WorktreeSectionContent: React.FC<WorktreeSectionContentProps> = ({
<div className="mb-1 px-1">
<div className="flex items-center gap-2">
<h3 className="typography-ui-header font-normal text-foreground">{t('settings.openchamber.worktrees.setup.title')}</h3>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -332,7 +332,7 @@ export const WorktreeSectionContent: React.FC<WorktreeSectionContentProps> = ({
<div className="mb-1 px-1">
<div className="flex items-center gap-2">
<h3 className="typography-ui-header font-normal text-foreground">{t('settings.openchamber.worktrees.list.title')}</h3>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -362,7 +362,7 @@ export const ProjectActionsSection: React.FC<ProjectActionsSectionProps> = ({ pr
placeholder={t('settings.projects.actions.field.overrideUrlPlaceholder')}
className="h-7 w-full max-w-[24rem]"
/>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 shrink-0 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -634,7 +634,7 @@ export const ProvidersPage: React.FC = () => {
<div className="py-1.5">
<label className="typography-ui-label text-foreground flex items-center gap-1.5">
{t('settings.providers.page.auth.apiKeyLabel')}
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -837,7 +837,7 @@ export const ProvidersPage: React.FC = () => {
<div className="py-1.5">
<label className="typography-ui-label text-foreground flex items-center gap-1.5">
{t('settings.providers.page.auth.apiKeyLabel')}
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -150,7 +150,7 @@ const HintLabel: React.FC<{ label: string; hint: React.ReactNode }> = ({ label,
return (
<span className="inline-flex items-center gap-1 typography-meta text-muted-foreground">
<span>{label}</span>
<Tooltip delayDuration={700}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -192,7 +192,7 @@ export const UsagePage: React.FC = () => {
/>
<div className="flex min-w-0 items-center gap-1.5">
<span className="typography-ui-label text-foreground">{t('settings.usage.page.options.showInHeader')}</span>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<RiInformationLine className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
</TooltipTrigger>
@@ -85,7 +85,7 @@ export const UsageSidebar: React.FC<UsageSidebarProps> = ({ onItemSelect }) => {
<div className="flex items-center justify-between gap-2">
<span className="typography-meta text-muted-foreground">{t('settings.usage.sidebar.total', { count: QUOTA_PROVIDERS.length })}</span>
<div className="flex items-center gap-2">
<Tooltip delayDuration={700}>
<Tooltip>
<TooltipTrigger asChild>
<span className="inline-flex">
<Checkbox
@@ -435,7 +435,7 @@ export function BranchPickerDialog({ open, onOpenChange, project }: BranchPicker
{!isEditing && !isConfirming ? (
<div className="flex items-center gap-1 flex-shrink-0">
<Tooltip delayDuration={700}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -456,7 +456,7 @@ export function BranchPickerDialog({ open, onOpenChange, project }: BranchPicker
</TooltipContent>
</Tooltip>
<Tooltip delayDuration={700}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -473,7 +473,7 @@ export function BranchPickerDialog({ open, onOpenChange, project }: BranchPicker
</TooltipContent>
</Tooltip>
<Tooltip delayDuration={700}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -657,46 +657,39 @@ export function NewWorktreeDialog({
void loadDefaultSourceBranch();
}, [branches, projectDirectory, newBranchState.sourceBranch]);
// Reset state when dialog opens/closes
// Reset state on each open. Resetting on close would empty the form during
// the close animation, causing visible flicker.
React.useEffect(() => {
if (!open) {
setMode('new-branch');
setNewBranchState({
branchName: '',
worktreeName: '',
isSyncingWorktreeName: true,
sourceBranch: '',
linkedIssue: null,
linkedPr: null,
includePrDiff: false,
});
setExistingBranchState({
selectedBranch: '',
worktreeName: '',
});
setExistingBranchDropdownOpen(false);
setSourceBranchDropdownOpen(false);
setExistingBranchPickerOpen(false);
setSourceBranchPickerOpen(false);
setExistingBranchQuery('');
setSourceBranchQuery('');
setValidation({
isValidating: false,
branchError: null,
worktreeError: null,
touched: false,
});
return;
}
// Generate unique slug when dialog opens
if (!open) return;
setMode('new-branch');
setExistingBranchState({
selectedBranch: '',
worktreeName: '',
});
setExistingBranchDropdownOpen(false);
setSourceBranchDropdownOpen(false);
setExistingBranchPickerOpen(false);
setSourceBranchPickerOpen(false);
setExistingBranchQuery('');
setSourceBranchQuery('');
setValidation({
isValidating: false,
branchError: null,
worktreeError: null,
touched: false,
});
const uniqueSlug = generateUniqueSlug();
setNewBranchState(prev => ({
...prev,
setNewBranchState({
branchName: uniqueSlug,
worktreeName: uniqueSlug,
isSyncingWorktreeName: true,
}));
sourceBranch: '',
linkedIssue: null,
linkedPr: null,
includePrDiff: false,
});
}, [open, generateUniqueSlug]);
// Sync worktree name with branch name for new-branch mode
@@ -1,5 +1,5 @@
import * as React from 'react';
import * as DialogPrimitive from '@radix-ui/react-dialog';
import { Dialog, DialogContent, DialogTitle, DialogDescription } from '@/components/ui/dialog';
import { cn } from '@/lib/utils';
import { ScrollShadow } from '@/components/ui/ScrollShadow';
import { Input } from '@/components/ui/input';
@@ -1456,7 +1456,7 @@ export function ScheduledTaskEditorDialog(props: {
}
return (
<DialogPrimitive.Root
<Dialog
open={open}
onOpenChange={(next) => {
if (!next && hasOpenFloatingMenu()) {
@@ -1465,55 +1465,35 @@ export function ScheduledTaskEditorDialog(props: {
onOpenChange(next);
}}
>
<DialogPrimitive.Portal>
<DialogPrimitive.Overlay className="fixed inset-0 z-50 bg-black/50 dark:bg-black/75" />
<DialogPrimitive.Content
aria-describedby={descriptionId}
className={cn(
'fixed z-50 top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%]',
'w-[90vw] max-w-[720px] h-[680px] max-h-[85vh]',
'flex flex-col rounded-xl border shadow-none overflow-hidden',
'bg-background'
)}
<DialogContent
aria-describedby={descriptionId}
className="!max-w-[720px] w-[90vw] h-[680px] max-h-[85vh] gap-0 p-0 overflow-hidden"
>
<DialogDescription id={descriptionId} className="sr-only">
{description}
</DialogDescription>
<header className="shrink-0 px-4 sm:px-6 pt-5 pb-3">
<div className="mx-auto w-full max-w-2xl">
<DialogTitle className="typography-ui-label font-medium text-foreground">
{title}
</DialogTitle>
<p className="typography-meta mt-0.5 text-muted-foreground">{description}</p>
</div>
</header>
<ScrollShadow
className="flex-1 min-h-0 overflow-auto [scrollbar-gutter:stable_both-edges]"
size={64}
hideTopShadow
>
<div className="absolute right-0.5 top-0.5 z-50">
<button
type="button"
onClick={() => onOpenChange(false)}
aria-label={t('sessions.scheduledTasks.editor.actions.closeAria')}
className="inline-flex h-7 w-7 items-center justify-center rounded-md p-0.5 text-muted-foreground hover:bg-interactive-hover/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary"
>
<RiCloseLine className="h-5 w-5" />
</button>
</div>
<DialogPrimitive.Description id={descriptionId} className="sr-only">
{description}
</DialogPrimitive.Description>
<div className="mx-auto w-full max-w-2xl px-4 sm:px-6 pb-5">{formBody}</div>
</ScrollShadow>
<header className="shrink-0 px-4 sm:px-6 pt-5 pb-3">
<div className="mx-auto w-full max-w-2xl">
<DialogPrimitive.Title className="typography-ui-label font-medium text-foreground">
{title}
</DialogPrimitive.Title>
<p className="typography-meta mt-0.5 text-muted-foreground">
{description}
</p>
</div>
</header>
<ScrollShadow className="flex-1 min-h-0 overflow-auto [scrollbar-gutter:stable_both-edges]" size={64} hideTopShadow>
<div className="mx-auto w-full max-w-2xl px-4 sm:px-6 pb-5">
{formBody}
</div>
</ScrollShadow>
<div className="shrink-0 px-4 sm:px-6 py-3">
<div className="mx-auto w-full max-w-2xl">
{footerRow}
</div>
</div>
</DialogPrimitive.Content>
</DialogPrimitive.Portal>
</DialogPrimitive.Root>
<div className="shrink-0 px-4 sm:px-6 py-3">
<div className="mx-auto w-full max-w-2xl">{footerRow}</div>
</div>
</DialogContent>
</Dialog>
);
}
@@ -192,7 +192,9 @@ export function ScheduledTasksDialog() {
const [selectedProjectID, setSelectedProjectID] = React.useState<string>('');
const [tasks, setTasks] = React.useState<ScheduledTask[]>([]);
const [loading, setLoading] = React.useState(false);
// Start in loading state so the first frame after open shows the spinner,
// not an empty/select-project flash before the fetch effect runs.
const [loading, setLoading] = React.useState(true);
const [editorOpen, setEditorOpen] = React.useState(false);
const [editorTask, setEditorTask] = React.useState<ScheduledTask | null>(null);
const [mutatingTaskID, setMutatingTaskID] = React.useState<string | null>(null);
@@ -276,6 +278,7 @@ export function ScheduledTasksDialog() {
void reloadTasks(preferredProjectID);
} else {
setTasks([]);
setLoading(false);
}
}, [open, activeProject, projects, reloadTasks]);
@@ -427,6 +430,7 @@ export function ScheduledTasksDialog() {
projectSelector
)}
<div className="min-h-[280px]">
{loading ? (
<div className="flex items-center gap-2 typography-meta text-muted-foreground">
<RiLoader4Line className="h-4 w-4 animate-spin" /> {t('sessions.scheduledTasks.dialog.loading')}
@@ -579,6 +583,7 @@ export function ScheduledTasksDialog() {
})}
</div>
)}
</div>
</div>
);
@@ -166,7 +166,7 @@ export const SortableProjectItem: React.FC<SortableProjectItemProps> = ({
style={{ backgroundColor: isDesktopShell && isStuck ? 'transparent' : undefined }}
>
<div className="relative flex items-center gap-1 px-0.5 py-0.5" {...attributes}>
<Tooltip delayDuration={1500}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -108,8 +108,10 @@ export const CommandPalette: React.FC = () => {
const trimmedQuery = debouncedQuery.trim();
const liveTrimmed = query.trim();
// Clear query on open (not close) so content stays visible through the
// close animation instead of emptying mid-flight.
React.useEffect(() => {
if (!isCommandPaletteOpen) setQuery('');
if (isCommandPaletteOpen) setQuery('');
}, [isCommandPaletteOpen]);
// Lazy-load git status for every session directory we plan to display so that
@@ -418,10 +420,7 @@ export const CommandPalette: React.FC = () => {
<DialogTitle>{t('commandPalette.title')}</DialogTitle>
<DialogDescription>{t('commandPalette.description')}</DialogDescription>
</DialogHeader>
<DialogContent
className="overflow-hidden p-0 transform-gpu will-change-transform"
showCloseButton
>
<DialogContent className="overflow-hidden p-0" showCloseButton>
<Command
shouldFilter={false}
className="[&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-4 [&_[cmdk-input-wrapper]_svg]:w-4 [&_[cmdk-input]]:h-8 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-1.5 [&_[cmdk-item]_svg]:h-4 [&_[cmdk-item]_svg]:w-4 [&_[cmdk-item]]:typography-meta"
@@ -158,7 +158,7 @@ export const ContextUsageDisplay: React.FC<ContextUsageDisplayProps> = ({
}
return (
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>{contextElement}</TooltipTrigger>
<TooltipContent>
<div className="space-y-0.5">
@@ -307,7 +307,7 @@ export const DebugPanel: React.FC<DebugPanelProps> = ({ onClose }) => {
</div>
<div className="flex gap-2 border-t border-[var(--interactive-border)] pt-2">
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="sm"
+17 -10
View File
@@ -71,6 +71,8 @@ const DialogOverlay = React.forwardRef<
data-slot="dialog-overlay"
className={cn(
"fixed inset-0 z-50 bg-black/50 dark:bg-black/75",
"transition-opacity duration-150 ease-out",
"data-[starting-style]:opacity-0 data-[ending-style]:opacity-0",
className
)}
{...props}
@@ -101,15 +103,19 @@ function DialogContent({
return (
<DialogPortal>
<DialogOverlay className="rounded-none" />
<BaseDialog.Popup
data-slot="dialog-content"
data-state-slot="dialog"
className={cn(
"bg-background text-foreground fixed top-[50%] left-[50%] z-50 flex flex-col w-full max-w-lg max-h-[calc(100dvh-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-xl border p-6 shadow-none overflow-y-auto pwa-dialog-content",
className
)}
{...props}
>
<div className="fixed inset-0 z-50 flex items-center justify-center pointer-events-none p-4">
<BaseDialog.Popup
data-slot="dialog-content"
data-state-slot="dialog"
className={cn(
"relative pointer-events-auto bg-background text-foreground flex flex-col w-full max-w-lg max-h-full gap-4 rounded-xl border p-6 shadow-none overflow-y-auto pwa-dialog-content origin-center",
"transition-all duration-150 ease-out",
"data-[starting-style]:opacity-0 data-[starting-style]:scale-[0.98]",
"data-[ending-style]:opacity-0 data-[ending-style]:scale-[0.98]",
className
)}
{...props}
>
{children}
{showCloseButton && (
<BaseDialog.Close
@@ -120,7 +126,8 @@ function DialogContent({
<span className="sr-only">{t('dialog.common.actions.close')}</span>
</BaseDialog.Close>
)}
</BaseDialog.Popup>
</BaseDialog.Popup>
</div>
</DialogPortal>
)
}
@@ -132,7 +132,7 @@ function DropdownMenuContent({
...style,
}}
className={cn(
"data-[open]:animate-in data-[closed]:animate-out data-[closed]:fade-out-0 data-[open]:fade-in-0 data-[closed]:zoom-out-95 data-[open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-[var(--available-height)] min-w-[8rem] origin-[var(--transform-origin)] overflow-visible rounded-xl p-1 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)]",
"transition-all duration-150 ease-out data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95 z-50 max-h-[var(--available-height)] min-w-[8rem] origin-[var(--transform-origin)] overflow-visible rounded-xl p-1 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)]",
className
)}
{...props}
@@ -336,7 +336,7 @@ function DropdownMenuSubContent({
color: 'var(--surface-elevated-foreground)',
}}
className={cn(
"data-[open]:animate-in data-[closed]:animate-out data-[closed]:fade-out-0 data-[open]:fade-in-0 data-[closed]:zoom-out-95 data-[open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-[var(--transform-origin)] overflow-visible rounded-xl p-1 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)]",
"transition-all duration-150 ease-out data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95 z-50 min-w-[8rem] origin-[var(--transform-origin)] overflow-visible rounded-xl p-1 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)]",
className
)}
{...props}
+1 -1
View File
@@ -190,7 +190,7 @@ function SelectContent({
color: 'var(--surface-elevated-foreground)',
}}
className={cn(
"pointer-events-auto data-[open]:animate-in data-[closed]:animate-out data-[closed]:fade-out-0 data-[open]:fade-in-0 data-[closed]:zoom-out-95 data-[open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-[120] max-h-[var(--available-height)] min-w-[8rem] origin-[var(--transform-origin)] overflow-x-hidden rounded-xl transform-gpu will-change-transform shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)]",
"pointer-events-auto transition-all duration-150 ease-out data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95 relative z-[120] max-h-[var(--available-height)] min-w-[8rem] origin-[var(--transform-origin)] overflow-x-hidden rounded-xl shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)]",
!alignItemWithTrigger &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
fitContent && "w-max min-w-0",
+1 -1
View File
@@ -78,7 +78,7 @@ function TooltipContent({
<BaseTooltip.Popup
data-slot="tooltip-content"
className={cn(
"bg-muted text-muted-foreground border border-border/60 animate-in fade-in-0 zoom-in-95 data-[closed]:animate-out data-[closed]:fade-out-0 data-[closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-[var(--transform-origin)] rounded-xl px-3 py-1.5 typography-meta text-balance overflow-hidden transform-gpu will-change-transform",
"bg-muted text-muted-foreground border border-border/60 transition-all duration-150 ease-out data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95 z-50 w-fit origin-[var(--transform-origin)] rounded-xl px-3 py-1.5 typography-meta text-balance overflow-hidden",
className
)}
style={{ ...style }}
@@ -38,36 +38,47 @@ export const MultiRunWindow: React.FC<MultiRunWindowProps> = ({
}}
>
<Dialog.Portal>
<Dialog.Backdrop className="fixed inset-0 z-50 bg-black/50 dark:bg-black/75" />
<Dialog.Popup
aria-describedby={descriptionId}
<Dialog.Backdrop
className={cn(
'fixed z-50 top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%]',
'w-[90vw] max-w-[720px] h-[680px] max-h-[85vh]',
'flex flex-col rounded-xl border shadow-none overflow-hidden',
'bg-background'
'fixed inset-0 z-50 bg-black/50 dark:bg-black/75',
'transition-opacity duration-150 ease-out',
'data-[starting-style]:opacity-0 data-[ending-style]:opacity-0',
)}
>
<div className="absolute right-0.5 top-0.5 z-50">
<button
type="button"
onClick={() => onOpenChange(false)}
aria-label={t('multiRun.window.actions.closeAria')}
className="inline-flex h-7 w-7 items-center justify-center rounded-md p-0.5 text-muted-foreground hover:text-foreground hover:bg-interactive-hover/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary"
>
<RiCloseLine className="h-5 w-5" />
</button>
</div>
<Dialog.Description id={descriptionId} className="sr-only">
{t('multiRun.window.description')}
</Dialog.Description>
<MultiRunLauncher
initialPrompt={initialPrompt}
onCreated={() => onOpenChange(false)}
onCancel={() => onOpenChange(false)}
isWindowed
/>
</Dialog.Popup>
/>
<div className="fixed inset-0 z-50 flex items-center justify-center pointer-events-none">
<Dialog.Popup
aria-describedby={descriptionId}
className={cn(
'relative pointer-events-auto',
'w-[90vw] max-w-[720px] h-[680px] max-h-[85vh]',
'flex flex-col rounded-xl border shadow-none overflow-hidden origin-center',
'bg-background',
'transition-all duration-150 ease-out',
'data-[starting-style]:opacity-0 data-[starting-style]:scale-[0.98]',
'data-[ending-style]:opacity-0 data-[ending-style]:scale-[0.98]',
)}
>
<div className="absolute right-0.5 top-0.5 z-50">
<button
type="button"
onClick={() => onOpenChange(false)}
aria-label={t('multiRun.window.actions.closeAria')}
className="inline-flex h-7 w-7 items-center justify-center rounded-md p-0.5 text-muted-foreground hover:text-foreground hover:bg-interactive-hover/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary"
>
<RiCloseLine className="h-5 w-5" />
</button>
</div>
<Dialog.Description id={descriptionId} className="sr-only">
{t('multiRun.window.description')}
</Dialog.Description>
<MultiRunLauncher
initialPrompt={initialPrompt}
onCreated={() => onOpenChange(false)}
onCancel={() => onOpenChange(false)}
isWindowed
/>
</Dialog.Popup>
</div>
</Dialog.Portal>
</Dialog.Root>
);
@@ -628,7 +628,7 @@ export const PlanView: React.FC<PlanViewProps> = ({ targetPath = null }) => {
{resolvedPath ? (
<div className="flex items-center gap-1">
<DropdownMenu>
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button
@@ -657,7 +657,7 @@ export const PlanView: React.FC<PlanViewProps> = ({ targetPath = null }) => {
</DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button
@@ -27,7 +27,7 @@ export const PreviewToggleButton: React.FC<PreviewToggleButtonProps> = ({
const tooltipText = isPreview ? 'Edit' : 'Preview';
return (
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
@@ -554,7 +554,7 @@ export const SettingsView: React.FC<SettingsViewProps> = ({ onClose, forceMobile
if (!Icon) return null;
return (
<Tooltip key={page.slug} delayDuration={600}>
<Tooltip key={page.slug}>
<TooltipTrigger asChild>
<button
type="button"
@@ -587,7 +587,7 @@ export const SettingsView: React.FC<SettingsViewProps> = ({ onClose, forceMobile
<div className="overflow-hidden transition-opacity duration-150 opacity-100">
<div className="border-t border-border bg-sidebar px-2 py-1 space-y-0.5">
{!runtimeCtx.isVSCode && (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -36,21 +36,32 @@ export const SettingsWindow: React.FC<SettingsWindowProps> = ({ open, onOpenChan
}}
>
<Dialog.Portal>
<Dialog.Backdrop className="fixed inset-0 z-50 bg-black/50 dark:bg-black/75" />
<Dialog.Popup
aria-describedby={descriptionId}
<Dialog.Backdrop
className={cn(
'fixed z-50 top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%]',
'w-[90vw] max-w-[1200px] h-[85vh] max-h-[900px]',
'rounded-xl border shadow-none overflow-hidden',
'bg-background'
'fixed inset-0 z-50 bg-black/50 dark:bg-black/75',
'transition-opacity duration-150 ease-out',
'data-[starting-style]:opacity-0 data-[ending-style]:opacity-0',
)}
>
<Dialog.Description id={descriptionId} className="sr-only">
{t('settings.window.description')}
</Dialog.Description>
<SettingsView onClose={() => onOpenChange(false)} isWindowed />
</Dialog.Popup>
/>
<div className="fixed inset-0 z-50 flex items-center justify-center pointer-events-none">
<Dialog.Popup
aria-describedby={descriptionId}
className={cn(
'relative pointer-events-auto',
'w-[90vw] max-w-[1200px] h-[85vh] max-h-[900px]',
'rounded-xl border shadow-none overflow-hidden origin-center',
'bg-background',
'transition-all duration-150 ease-out',
'data-[starting-style]:opacity-0 data-[starting-style]:scale-[0.98]',
'data-[ending-style]:opacity-0 data-[ending-style]:scale-[0.98]',
)}
>
<Dialog.Description id={descriptionId} className="sr-only">
{t('settings.window.description')}
</Dialog.Description>
<SettingsView onClose={() => onOpenChange(false)} isWindowed />
</Dialog.Popup>
</div>
</Dialog.Portal>
</Dialog.Root>
);
@@ -26,7 +26,7 @@ export const AIHighlightsBox: React.FC<AIHighlightsBoxProps> = ({
<div className="space-y-2 rounded-xl border border-border/60 bg-transparent px-3 py-2">
<div className="flex items-center justify-between gap-2">
<p className="typography-micro text-muted-foreground">{t('gitView.commit.aiHighlights.title')}</p>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
@@ -414,7 +414,7 @@ export const BranchIntegrationSection: React.FC<BranchIntegrationSectionProps> =
return (
<>
<Tooltip delayDuration={1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -40,7 +40,6 @@ interface BranchSelectorProps {
onCreate: (name: string, remote?: GitRemote) => Promise<void>;
remotes?: GitRemote[];
disabled?: boolean;
tooltipDelayMs?: number;
}
const sanitizeBranchNameInput = (value: string): string => {
@@ -65,7 +64,6 @@ export const BranchSelector: React.FC<BranchSelectorProps> = ({
onCreate,
remotes = [],
disabled = false,
tooltipDelayMs = 1000,
}) => {
const { t } = useI18n();
const [isOpen, setIsOpen] = React.useState(false);
@@ -170,7 +168,7 @@ export const BranchSelector: React.FC<BranchSelectorProps> = ({
return (
<DropdownMenu open={isOpen} onOpenChange={setIsOpen}>
<Tooltip delayDuration={tooltipDelayMs}>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button
@@ -150,7 +150,7 @@ export const ChangeRow = React.memo<ChangeRowProps>(function ChangeRow({
<span className="text-muted-foreground mx-0.5">/</span>
<span style={{ color: 'var(--status-error)' }}>-{deletions}</span>
</span>
<Tooltip delayDuration={200}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -104,7 +104,6 @@ interface IdentityDropdownProps {
identities: GitIdentityProfile[];
onSelect: (profile: GitIdentityProfile) => void;
isApplying: boolean;
tooltipDelayMs?: number;
iconOnly?: boolean;
}
@@ -113,7 +112,6 @@ const IdentityDropdown: React.FC<IdentityDropdownProps> = ({
identities,
onSelect,
isApplying,
tooltipDelayMs = 1000,
iconOnly = false,
}) => {
const { t } = useI18n();
@@ -121,7 +119,7 @@ const IdentityDropdown: React.FC<IdentityDropdownProps> = ({
return (
<DropdownMenu>
<Tooltip delayDuration={tooltipDelayMs}>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button
@@ -224,7 +222,7 @@ export const GitHeader: React.FC<GitHeaderProps> = ({
const managementButtons = (
<div className="flex items-center gap-1 shrink-0">
{onOpenHistory ? (
<Tooltip delayDuration={useTwoRowHeader ? 300 : 1000}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
@@ -252,7 +250,7 @@ export const GitHeader: React.FC<GitHeaderProps> = ({
removingRemoteName={removingRemoteName}
disabled={!status}
iconOnly={true}
tooltipDelayMs={useTwoRowHeader ? 300 : 1000}
aheadCount={status.ahead}
behindCount={status.behind}
/>
@@ -264,7 +262,7 @@ export const GitHeader: React.FC<GitHeaderProps> = ({
identities={availableIdentities}
onSelect={onSelectIdentity}
isApplying={isApplyingIdentity}
tooltipDelayMs={useTwoRowHeader ? 300 : 1000}
iconOnly={false}
/>
);
@@ -287,7 +285,7 @@ export const GitHeader: React.FC<GitHeaderProps> = ({
onCheckout={onCheckoutBranch}
onCreate={onCreateBranch}
remotes={remotes}
tooltipDelayMs={useTwoRowHeader ? 300 : 1000}
/>
)}
</div>
@@ -88,7 +88,7 @@ export const HistoryCommitRow = React.memo(({
<code className="shrink-0 font-mono">
{entry.hash.slice(0, 8)}
</code>
<Tooltip delayDuration={500}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
@@ -1408,7 +1408,7 @@ export const PullRequestSection: React.FC<{
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2 min-w-0">
{pr ? (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -1431,7 +1431,7 @@ export const PullRequestSection: React.FC<{
</div>
<div className="flex items-center gap-2">
{isLoading ? <RiLoader4Line className="size-4 animate-spin text-muted-foreground" /> : null}
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
@@ -1612,7 +1612,7 @@ export const PullRequestSection: React.FC<{
{pr.state === 'open' ? (
isEditingPr ? (
<>
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1631,7 +1631,7 @@ export const PullRequestSection: React.FC<{
</TooltipTrigger>
<TooltipContent><p>{t('gitView.pr.actions.cancelEditing')}</p></TooltipContent>
</Tooltip>
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="sm"
@@ -1647,7 +1647,7 @@ export const PullRequestSection: React.FC<{
</Tooltip>
</>
) : (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1665,7 +1665,7 @@ export const PullRequestSection: React.FC<{
) : null}
{checks ? (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1683,7 +1683,7 @@ export const PullRequestSection: React.FC<{
) : null}
{checks?.failure ? (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1699,7 +1699,7 @@ export const PullRequestSection: React.FC<{
</Tooltip>
) : null}
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1714,7 +1714,7 @@ export const PullRequestSection: React.FC<{
<TooltipContent><p>{t('gitView.pr.actions.openComments')}</p></TooltipContent>
</Tooltip>
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1730,7 +1730,7 @@ export const PullRequestSection: React.FC<{
</Tooltip>
{canMerge && pr.draft && pr.state === 'open' ? (
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
@@ -1765,7 +1765,7 @@ export const PullRequestSection: React.FC<{
<SelectItem value="rebase">{t('gitView.pr.mergeMethod.rebase')}</SelectItem>
</SelectContent>
</Select>
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="sm"
@@ -2064,7 +2064,7 @@ export const PullRequestSection: React.FC<{
{comment.authorLogin && comment.authorLogin !== comment.authorName ? ` · @${comment.authorLogin}` : ''}
</span>
{comment.createdAt ? <span className="whitespace-nowrap">{formatTimestamp(comment.createdAt)}</span> : null}
<Tooltip delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
@@ -29,7 +29,6 @@ interface SyncActionsProps {
disabled: boolean;
removingRemoteName?: string | null;
iconOnly?: boolean;
tooltipDelayMs?: number;
aheadCount?: number;
behindCount?: number;
}
@@ -44,7 +43,6 @@ export const SyncActions: React.FC<SyncActionsProps> = ({
disabled,
removingRemoteName = null,
iconOnly = false,
tooltipDelayMs = 1000,
aheadCount = 0,
behindCount = 0,
}) => {
@@ -108,7 +106,7 @@ export const SyncActions: React.FC<SyncActionsProps> = ({
);
return (
<Tooltip delayDuration={tooltipDelayMs}>
<Tooltip>
<TooltipTrigger asChild>{button}</TooltipTrigger>
<TooltipContent sideOffset={8}>{tooltipText}</TooltipContent>
</Tooltip>
@@ -126,7 +124,7 @@ export const SyncActions: React.FC<SyncActionsProps> = ({
) => {
return (
<DropdownMenu>
<Tooltip delayDuration={tooltipDelayMs}>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button