Replace loading dots with animated spinner icons

Replaces the small dot indicators with animated Loader2 icons that
appear in place of the favicon while tabs are loading. Provides
clearer, more prominent visual feedback during navigation.
This commit is contained in:
Jinjing
2026-09-05 21:18:54 -07:00
parent fe81ca49db
commit bc01091270
3 changed files with 16 additions and 11 deletions
@@ -1,5 +1,5 @@
import { useState } from 'react'
import { Globe } from 'lucide-react'
import { Globe, Loader2 } from 'lucide-react'
import { cn } from '@/lib/utils'
import { displayableFaviconUrl } from './browser-pane/describe-page/browser-favicon-url'
@@ -32,6 +32,15 @@ export function BrowserFavicon({
setFailedUrl(null)
}
if (loading) {
return (
<Loader2
className={cn('shrink-0 motion-safe:animate-spin', className, fallbackClassName)}
aria-hidden="true"
/>
)
}
if (displayUrl && failedUrl !== displayUrl) {
return (
<img
@@ -191,15 +191,12 @@ export default function BrowserTab({
muted-foreground made the icon read as "disabled" in practice. */}
<BrowserFavicon
faviconUrl={tab.faviconUrl}
loading={tab.loading}
loading={tab.loading && !tab.loadError && !isBlankBrowserTab(tab)}
className="size-3 mr-1"
fallbackClassName="text-blue-500"
/>
{isPinned && <Pin className="mr-1 size-3 shrink-0 text-muted-foreground" aria-hidden />}
<span className={`${TAB_LABEL_WIDTH_CLASSES} mr-1`}>{tabLabel}</span>
{tab.loading && !tab.loadError && !isBlankBrowserTab(tab) && (
<span className="mr-1 size-1.5 rounded-full bg-sky-500/80 shrink-0" />
)}
{!isPinned && (
<button
className={`flex items-center justify-center w-4 h-4 rounded-sm shrink-0 ${
@@ -1,4 +1,4 @@
import { Laptop, X } from 'lucide-react'
import { Laptop, Loader2, X } from 'lucide-react'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { translate } from '@/i18n/i18n'
import type { ClientHostedBrowserRow } from '../../../../shared/client-hosted-browser-rows'
@@ -36,6 +36,8 @@ export default function ClientHostedBrowserTab({
onClose: () => void
includeTopTabBorder?: boolean
}): React.JSX.Element {
const loading = row.loading && !row.hostAbsent
const PageIcon = loading ? Loader2 : Laptop
const label = getClientHostedBrowserRowLabel(row)
const hostDescription = describeClientHostedBrowserRowHost(row)
@@ -62,8 +64,8 @@ export default function ClientHostedBrowserTab({
}}
>
{isActive && <span className={ACTIVE_TAB_INDICATOR_CLASSES} aria-hidden />}
<Laptop
className={`mr-1 size-3 shrink-0 ${row.hostAbsent ? 'text-muted-foreground' : 'text-blue-500'}`}
<PageIcon
className={`mr-1 size-3 shrink-0 ${loading ? 'motion-safe:animate-spin' : ''} ${row.hostAbsent ? 'text-muted-foreground' : 'text-blue-500'}`}
aria-hidden
/>
<span
@@ -71,9 +73,6 @@ export default function ClientHostedBrowserTab({
>
{label}
</span>
{row.loading && (
<span className="mr-1 size-1.5 shrink-0 rounded-full bg-sky-500/80" aria-hidden />
)}
<button
type="button"
aria-label={translate('browser.clientHosted.hostRowClose', 'Close hosted page')}