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