fix(desktop): replace native title tooltips with styled Tip component

This commit is contained in:
wnuuee1 2026-06-23 11:04:32 +03:00 committed by Teknium
parent a0471e2464
commit 9fd2b2cb9f
4 changed files with 111 additions and 99 deletions

View file

@ -13,6 +13,7 @@ import {
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu'
import { Kbd } from '@/components/ui/kbd'
import { Tip } from '@/components/ui/tooltip'
import { useI18n } from '@/i18n'
import { Clipboard, FileText, FolderOpen, type IconComponent, ImageIcon, Link, MessageSquareText } from '@/lib/icons'
import { cn } from '@/lib/utils'
@ -42,22 +43,23 @@ export function ContextMenu({
return (
<>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
aria-label={state.tools.label}
className={cn(
GHOST_ICON_BTN,
'data-[state=open]:bg-(--chrome-action-hover) data-[state=open]:text-foreground'
)}
disabled={!state.tools.enabled}
size="icon"
title={state.tools.label}
type="button"
variant="ghost"
>
<Codicon name="add" size="0.875rem" />
</Button>
</DropdownMenuTrigger>
<Tip label={state.tools.label} side="top">
<DropdownMenuTrigger asChild>
<Button
aria-label={state.tools.label}
className={cn(
GHOST_ICON_BTN,
'data-[state=open]:bg-(--chrome-action-hover) data-[state=open]:text-foreground'
)}
disabled={!state.tools.enabled}
size="icon"
type="button"
variant="ghost"
>
<Codicon name="add" size="0.875rem" />
</Button>
</DropdownMenuTrigger>
</Tip>
<DropdownMenuContent align="start" className={cn('w-60', composerPanelCard)} side="top" sideOffset={6}>
<DropdownMenuLabel className="px-2 pb-0.5 pt-0.5 text-[0.625rem] font-semibold uppercase tracking-wider text-(--ui-text-tertiary)">
{c.attachLabel}

View file

@ -5,6 +5,7 @@ import { ModelMenuCloseContext } from '@/app/shell/model-menu-panel'
import { Button } from '@/components/ui/button'
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
import { GlyphSpinner } from '@/components/ui/glyph-spinner'
import { Tip } from '@/components/ui/tooltip'
import { useI18n } from '@/i18n'
import { ChevronDown } from '@/lib/icons'
import { formatModelStatusLabel } from '@/lib/model-status-label'
@ -74,34 +75,36 @@ export function ModelPill({
if (!model.modelMenuContent) {
return (
<Button
aria-label={copy.openModelPicker}
className={pillClass}
disabled={disabled}
onClick={() => setModelPickerOpen(true)}
title={copy.openModelPicker}
type="button"
variant="ghost"
>
{label}
</Button>
)
}
return (
<DropdownMenu onOpenChange={setOpen} open={open}>
<DropdownMenuTrigger asChild>
<Tip label={copy.openModelPicker} side="top">
<Button
aria-label={title}
aria-label={copy.openModelPicker}
className={pillClass}
disabled={disabled}
title={title}
onClick={() => setModelPickerOpen(true)}
type="button"
variant="ghost"
>
{label}
</Button>
</DropdownMenuTrigger>
</Tip>
)
}
return (
<DropdownMenu onOpenChange={setOpen} open={open}>
<Tip label={title} side="top">
<DropdownMenuTrigger asChild>
<Button
aria-label={title}
className={pillClass}
disabled={disabled}
type="button"
variant="ghost"
>
{label}
</Button>
</DropdownMenuTrigger>
</Tip>
<DropdownMenuContent align="end" className="w-64 p-0" side="top" sideOffset={8}>
<ModelMenuCloseContext.Provider value={() => setOpen(false)}>
{model.modelMenuContent}

View file

@ -5,6 +5,7 @@ import { ErrorBoundary } from '@/components/error-boundary'
import { Button } from '@/components/ui/button'
import { Codicon } from '@/components/ui/codicon'
import { Loader } from '@/components/ui/loader'
import { Tip } from '@/components/ui/tooltip'
import { useI18n } from '@/i18n'
import { selectDesktopPaths } from '@/lib/desktop-fs'
import { normalizeOrLocalPreviewTarget } from '@/lib/local-preview'
@ -167,38 +168,41 @@ function FilesystemTab({
<SidebarPanelLabel>{cwdName}</SidebarPanelLabel>
</button>
</div>
<Button
aria-label={r.refreshTree}
className={HEADER_ACTION_LABEL_REVEAL}
disabled={!hasCwd || loading}
onClick={onRefresh}
size="icon-xs"
title={r.refreshTree}
variant="ghost"
>
<Codicon name="refresh" size="0.8125rem" spinning={loading} />
</Button>
<Button
aria-label={r.openFolder}
className={HEADER_ACTION_CLASS}
onClick={() => void onChangeFolder()}
size="icon-xs"
title={r.openFolder}
variant="ghost"
>
<Codicon name="folder-opened" size="0.8125rem" />
</Button>
<Button
aria-label={r.collapseAll}
className={cn(HEADER_ACTION_CLASS, !canCollapse && 'pointer-events-none opacity-0')}
disabled={!hasCwd || !canCollapse}
onClick={onCollapseAll}
size="icon-xs"
title={r.collapseAll}
variant="ghost"
>
<Codicon name="collapse-all" size="0.8125rem" />
</Button>
<Tip label={r.refreshTree} side="left">
<Button
aria-label={r.refreshTree}
className={HEADER_ACTION_LABEL_REVEAL}
disabled={!hasCwd || loading}
onClick={onRefresh}
size="icon-xs"
variant="ghost"
>
<Codicon name="refresh" size="0.8125rem" spinning={loading} />
</Button>
</Tip>
<Tip label={r.openFolder} side="left">
<Button
aria-label={r.openFolder}
className={HEADER_ACTION_CLASS}
onClick={() => void onChangeFolder()}
size="icon-xs"
variant="ghost"
>
<Codicon name="folder-opened" size="0.8125rem" />
</Button>
</Tip>
<Tip label={r.collapseAll} side="left">
<Button
aria-label={r.collapseAll}
className={cn(HEADER_ACTION_CLASS, !canCollapse && 'pointer-events-none opacity-0')}
disabled={!hasCwd || !canCollapse}
onClick={onCollapseAll}
size="icon-xs"
variant="ghost"
>
<Codicon name="collapse-all" size="0.8125rem" />
</Button>
</Tip>
</RightSidebarSectionHeader>
<FileTreeBody
collapseNonce={collapseNonce}

View file

@ -4,6 +4,7 @@ import { useLocation, useNavigate } from 'react-router-dom'
import { Button } from '@/components/ui/button'
import { Codicon } from '@/components/ui/codicon'
import { Tip } from '@/components/ui/tooltip'
import { useI18n } from '@/i18n'
import { triggerHaptic } from '@/lib/haptics'
import { cn } from '@/lib/utils'
@ -204,41 +205,43 @@ function TitlebarToolButton({ navigate, tool }: { navigate: ReturnType<typeof us
if (tool.href) {
return (
<Button asChild className={className} size="icon-titlebar" variant="ghost">
<a
aria-label={tool.label}
href={tool.href}
onPointerDown={event => event.stopPropagation()}
rel="noreferrer"
target="_blank"
title={tool.title ?? tool.label}
>
{tool.icon}
</a>
</Button>
<Tip label={tool.title ?? tool.label}>
<Button asChild className={className} size="icon-titlebar" variant="ghost">
<a
aria-label={tool.label}
href={tool.href}
onPointerDown={event => event.stopPropagation()}
rel="noreferrer"
target="_blank"
>
{tool.icon}
</a>
</Button>
</Tip>
)
}
return (
<Button
aria-label={tool.label}
aria-pressed={tool.active ?? undefined}
className={className}
disabled={tool.disabled}
onClick={() => {
if (tool.to) {
navigate(tool.to)
}
<Tip label={tool.title ?? tool.label}>
<Button
aria-label={tool.label}
aria-pressed={tool.active ?? undefined}
className={className}
disabled={tool.disabled}
onClick={() => {
if (tool.to) {
navigate(tool.to)
}
tool.onSelect?.()
}}
onPointerDown={event => event.stopPropagation()}
size="icon-titlebar"
title={tool.title ?? tool.label}
type="button"
variant="ghost"
>
{tool.icon}
</Button>
tool.onSelect?.()
}}
onPointerDown={event => event.stopPropagation()}
size="icon-titlebar"
type="button"
variant="ghost"
>
{tool.icon}
</Button>
</Tip>
)
}