feat: Added tooltips for navbar buttons to clear meaning of each one (#1636)

* feat: Added tooltips for navbar buttons to clear meaning of each one.

* update tooltips and fix linter errors

---------

Co-authored-by: henrygd <hank@henrygd.me>
This commit is contained in:
Fahleen Arif
2026-01-28 23:39:15 +05:00
committed by GitHub
parent 42da1e5a52
commit 425c8d2bdf
6 changed files with 156 additions and 125 deletions

View File

@@ -1,21 +1,29 @@
import { useLingui } from "@lingui/react/macro" import { Trans, useLingui } from "@lingui/react/macro"
import { LanguagesIcon } from "lucide-react" import { LanguagesIcon } from "lucide-react"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import { dynamicActivate } from "@/lib/i18n" import { dynamicActivate } from "@/lib/i18n"
import languages from "@/lib/languages" import languages from "@/lib/languages"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"
export function LangToggle() { export function LangToggle() {
const { i18n } = useLingui() const { i18n } = useLingui()
const LangTrans = <Trans>Language</Trans>
return ( return (
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger>
<Tooltip>
<TooltipTrigger asChild>
<Button variant={"ghost"} size="icon" className="hidden sm:flex"> <Button variant={"ghost"} size="icon" className="hidden sm:flex">
<LanguagesIcon className="absolute h-[1.2rem] w-[1.2rem] light:opacity-85" /> <LanguagesIcon className="absolute h-[1.2rem] w-[1.2rem] light:opacity-85" />
<span className="sr-only">Language</span> <span className="sr-only">{LangTrans}</span>
</Button> </Button>
</TooltipTrigger>
<TooltipContent>{LangTrans}</TooltipContent>
</Tooltip>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="grid grid-cols-3"> <DropdownMenuContent className="grid grid-cols-3">
{languages.map(([lang, label, e]) => ( {languages.map(([lang, label, e]) => (

View File

@@ -2,11 +2,15 @@ import { t } from "@lingui/core/macro"
import { MoonStarIcon, SunIcon } from "lucide-react" import { MoonStarIcon, SunIcon } from "lucide-react"
import { useTheme } from "@/components/theme-provider" import { useTheme } from "@/components/theme-provider"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"
import { Trans } from "@lingui/react/macro"
export function ModeToggle() { export function ModeToggle() {
const { theme, setTheme } = useTheme() const { theme, setTheme } = useTheme()
return ( return (
<Tooltip>
<TooltipTrigger>
<Button <Button
variant={"ghost"} variant={"ghost"}
size="icon" size="icon"
@@ -16,5 +20,10 @@ export function ModeToggle() {
<SunIcon className="h-[1.2rem] w-[1.2rem] transition-all -rotate-90 dark:opacity-0 dark:rotate-0" /> <SunIcon className="h-[1.2rem] w-[1.2rem] transition-all -rotate-90 dark:opacity-0 dark:rotate-0" />
<MoonStarIcon className="absolute h-[1.2rem] w-[1.2rem] transition-all opacity-0 -rotate-90 dark:opacity-100 dark:rotate-0" /> <MoonStarIcon className="absolute h-[1.2rem] w-[1.2rem] transition-all opacity-0 -rotate-90 dark:opacity-100 dark:rotate-0" />
</Button> </Button>
</TooltipTrigger>
<TooltipContent>
<Trans>Toggle theme</Trans>
</TooltipContent>
</Tooltip>
) )
} }

View File

@@ -30,7 +30,7 @@ import { LangToggle } from "./lang-toggle"
import { Logo } from "./logo" import { Logo } from "./logo"
import { ModeToggle } from "./mode-toggle" import { ModeToggle } from "./mode-toggle"
import { $router, basePath, Link, prependBasePath } from "./router" import { $router, basePath, Link, prependBasePath } from "./router"
import { t } from "@lingui/core/macro" import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"
const CommandPalette = lazy(() => import("./command-palette")) const CommandPalette = lazy(() => import("./command-palette"))
@@ -49,7 +49,10 @@ export default function Navbar() {
</Link> </Link>
<SearchButton /> <SearchButton />
{/** biome-ignore lint/a11y/noStaticElementInteractions: ignore */}
<div className="flex items-center ms-auto" onMouseEnter={() => import("@/components/routes/settings/general")}> <div className="flex items-center ms-auto" onMouseEnter={() => import("@/components/routes/settings/general")}>
<Tooltip>
<TooltipTrigger asChild>
<Link <Link
href={getPagePath($router, "containers")} href={getPagePath($router, "containers")}
className={cn(buttonVariants({ variant: "ghost", size: "icon" }))} className={cn(buttonVariants({ variant: "ghost", size: "icon" }))}
@@ -57,6 +60,13 @@ export default function Navbar() {
> >
<ContainerIcon className="h-[1.2rem] w-[1.2rem]" strokeWidth={1.5} /> <ContainerIcon className="h-[1.2rem] w-[1.2rem]" strokeWidth={1.5} />
</Link> </Link>
</TooltipTrigger>
<TooltipContent>
<Trans>All Containers</Trans>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Link <Link
href={getPagePath($router, "smart")} href={getPagePath($router, "smart")}
className={cn("hidden md:grid", buttonVariants({ variant: "ghost", size: "icon" }))} className={cn("hidden md:grid", buttonVariants({ variant: "ghost", size: "icon" }))}
@@ -64,8 +74,15 @@ export default function Navbar() {
> >
<HardDriveIcon className="h-[1.2rem] w-[1.2rem]" strokeWidth={1.5} /> <HardDriveIcon className="h-[1.2rem] w-[1.2rem]" strokeWidth={1.5} />
</Link> </Link>
</TooltipTrigger>
<TooltipContent>
<Trans>S.M.A.R.T.</Trans>
</TooltipContent>
</Tooltip>
<LangToggle /> <LangToggle />
<ModeToggle /> <ModeToggle />
<Tooltip>
<TooltipTrigger asChild>
<Link <Link
href={getPagePath($router, "settings", { name: "general" })} href={getPagePath($router, "settings", { name: "general" })}
aria-label="Settings" aria-label="Settings"
@@ -73,6 +90,11 @@ export default function Navbar() {
> >
<SettingsIcon className="h-[1.2rem] w-[1.2rem]" /> <SettingsIcon className="h-[1.2rem] w-[1.2rem]" />
</Link> </Link>
</TooltipTrigger>
<TooltipContent>
<Trans>Settings</Trans>
</TooltipContent>
</Tooltip>
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<button aria-label="User Actions" className={cn(buttonVariants({ variant: "ghost", size: "icon" }))}> <button aria-label="User Actions" className={cn(buttonVariants({ variant: "ghost", size: "icon" }))}>
@@ -135,14 +157,14 @@ export default function Navbar() {
) )
} }
function SearchButton() { const Kbd = ({ children }: { children: React.ReactNode }) => (
const [open, setOpen] = useState(false)
const Kbd = ({ children }: { children: React.ReactNode }) => (
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100"> <kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">
{children} {children}
</kbd> </kbd>
) )
function SearchButton() {
const [open, setOpen] = useState(false)
return ( return (
<> <>

View File

@@ -17,7 +17,7 @@ import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card" import { Card } from "@/components/ui/card"
import { FreeBsdIcon, TuxIcon, WebSocketIcon, WindowsIcon } from "@/components/ui/icons" import { FreeBsdIcon, TuxIcon, WebSocketIcon, WindowsIcon } from "@/components/ui/icons"
import { Separator } from "@/components/ui/separator" import { Separator } from "@/components/ui/separator"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
import { ConnectionType, connectionTypeLabels, Os, SystemStatus } from "@/lib/enums" import { ConnectionType, connectionTypeLabels, Os, SystemStatus } from "@/lib/enums"
import { cn, formatBytes, getHostDisplayValue, secondsToString, toFixedFloat } from "@/lib/utils" import { cn, formatBytes, getHostDisplayValue, secondsToString, toFixedFloat } from "@/lib/utils"
import type { ChartData, SystemDetailsRecord, SystemRecord } from "@/types" import type { ChartData, SystemDetailsRecord, SystemRecord } from "@/types"
@@ -135,7 +135,6 @@ export default function InfoBar({
<div> <div>
<h1 className="text-[1.6rem] font-semibold mb-1.5">{system.name}</h1> <h1 className="text-[1.6rem] font-semibold mb-1.5">{system.name}</h1>
<div className="flex flex-wrap items-center gap-3 gap-y-2 text-sm opacity-90"> <div className="flex flex-wrap items-center gap-3 gap-y-2 text-sm opacity-90">
<TooltipProvider>
<Tooltip> <Tooltip>
<TooltipTrigger asChild> <TooltipTrigger asChild>
<div className="capitalize flex gap-2 items-center"> <div className="capitalize flex gap-2 items-center">
@@ -171,7 +170,6 @@ export default function InfoBar({
</TooltipContent> </TooltipContent>
)} )}
</Tooltip> </Tooltip>
</TooltipProvider>
{systemInfo.map(({ value, label, Icon, hide }) => { {systemInfo.map(({ value, label, Icon, hide }) => {
if (hide || !value) { if (hide || !value) {
@@ -186,12 +184,10 @@ export default function InfoBar({
<div key={value} className="contents"> <div key={value} className="contents">
<Separator orientation="vertical" className="h-4 bg-primary/30" /> <Separator orientation="vertical" className="h-4 bg-primary/30" />
{label ? ( {label ? (
<TooltipProvider> <Tooltip delayDuration={100}>
<Tooltip delayDuration={150}>
<TooltipTrigger asChild>{content}</TooltipTrigger> <TooltipTrigger asChild>{content}</TooltipTrigger>
<TooltipContent>{label}</TooltipContent> <TooltipContent>{label}</TooltipContent>
</Tooltip> </Tooltip>
</TooltipProvider>
) : ( ) : (
content content
)} )}
@@ -202,7 +198,6 @@ export default function InfoBar({
</div> </div>
<div className="xl:ms-auto flex items-center gap-2 max-sm:-mb-1"> <div className="xl:ms-auto flex items-center gap-2 max-sm:-mb-1">
<ChartTimeSelect className="w-full xl:w-40" agentVersion={chartData.agentVersion} /> <ChartTimeSelect className="w-full xl:w-40" agentVersion={chartData.agentVersion} />
<TooltipProvider delayDuration={100}>
<Tooltip> <Tooltip>
<TooltipTrigger asChild> <TooltipTrigger asChild>
<Button <Button
@@ -221,7 +216,6 @@ export default function InfoBar({
</TooltipTrigger> </TooltipTrigger>
<TooltipContent>{t`Toggle grid`}</TooltipContent> <TooltipContent>{t`Toggle grid`}</TooltipContent>
</Tooltip> </Tooltip>
</TooltipProvider>
</div> </div>
</div> </div>
</Card> </Card>

View File

@@ -3,7 +3,7 @@ import { CopyIcon } from "lucide-react"
import { copyToClipboard } from "@/lib/utils" import { copyToClipboard } from "@/lib/utils"
import { Button } from "./button" import { Button } from "./button"
import { Input } from "./input" import { Input } from "./input"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./tooltip" import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip"
export function InputCopy({ value, id, name }: { value: string; id: string; name: string }) { export function InputCopy({ value, id, name }: { value: string; id: string; name: string }) {
return ( return (
@@ -14,7 +14,6 @@ export function InputCopy({ value, id, name }: { value: string; id: string; name
"h-6 w-24 bg-linear-to-r rtl:bg-linear-to-l from-transparent to-background to-65% absolute top-2 end-1 pointer-events-none" "h-6 w-24 bg-linear-to-r rtl:bg-linear-to-l from-transparent to-background to-65% absolute top-2 end-1 pointer-events-none"
} }
></div> ></div>
<TooltipProvider delayDuration={100} disableHoverableContent>
<Tooltip disableHoverableContent={true}> <Tooltip disableHoverableContent={true}>
<TooltipTrigger asChild> <TooltipTrigger asChild>
<Button <Button
@@ -32,7 +31,6 @@ export function InputCopy({ value, id, name }: { value: string; id: string; name
</p> </p>
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
</TooltipProvider>
</div> </div>
) )
} }

View File

@@ -3,7 +3,7 @@ import type * as React from "react"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
function TooltipProvider({ delayDuration = 0, ...props }: React.ComponentProps<typeof TooltipPrimitive.Provider>) { function TooltipProvider({ delayDuration = 50, ...props }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
return <TooltipPrimitive.Provider data-slot="tooltip-provider" delayDuration={delayDuration} {...props} /> return <TooltipPrimitive.Provider data-slot="tooltip-provider" delayDuration={delayDuration} {...props} />
} }