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:
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user