Compare commits

...

1 Commits

Author SHA1 Message Date
YoVinchen
5b5b3efad4 refactor(ui): simplify UpdateBadge to minimal dot indicator 2026-01-15 01:08:42 +08:00
2 changed files with 41 additions and 57 deletions

View File

@@ -619,8 +619,8 @@ function App() {
</h1>
</div>
) : (
<>
<div className="flex items-center gap-2">
<div className="flex items-center gap-2">
<div className="relative inline-flex items-center">
<a
href="https://github.com/farion1231/cc-switch"
target="_blank"
@@ -634,26 +634,27 @@ function App() {
>
CC Switch
</a>
<Button
variant="ghost"
size="icon"
<UpdateBadge
onClick={() => {
setSettingsDefaultTab("general");
setSettingsDefaultTab("about");
setCurrentView("settings");
}}
title={t("common.settings")}
className="hover:bg-black/5 dark:hover:bg-white/5"
>
<Settings className="w-4 h-4" />
</Button>
className="absolute -top-4 -right-4"
/>
</div>
<UpdateBadge
<Button
variant="ghost"
size="icon"
onClick={() => {
setSettingsDefaultTab("about");
setSettingsDefaultTab("general");
setCurrentView("settings");
}}
/>
</>
title={t("common.settings")}
className="hover:bg-black/5 dark:hover:bg-white/5"
>
<Settings className="w-4 h-4" />
</Button>
</div>
)}
</div>

View File

@@ -1,6 +1,6 @@
import { X, Download } from "lucide-react";
import { useUpdate } from "@/contexts/UpdateContext";
import { useTranslation } from "react-i18next";
import { Button } from "@/components/ui/button";
interface UpdateBadgeProps {
className?: string;
@@ -8,56 +8,39 @@ interface UpdateBadgeProps {
}
export function UpdateBadge({ className = "", onClick }: UpdateBadgeProps) {
const { hasUpdate, updateInfo, isDismissed, dismissUpdate } = useUpdate();
const { hasUpdate, updateInfo } = useUpdate();
const { t } = useTranslation();
const isActive = hasUpdate && updateInfo;
const title = isActive
? t("settings.updateAvailable", {
version: updateInfo?.availableVersion ?? "",
})
: t("settings.checkForUpdates");
// 如果没有更新或已关闭,不显示
if (!hasUpdate || isDismissed || !updateInfo) {
if (!isActive) {
return null;
}
return (
<div
<Button
type="button"
variant="ghost"
size="icon"
title={title}
aria-label={title}
onClick={onClick}
className={`
flex items-center gap-1.5 px-2.5 py-1
bg-white dark:bg-gray-800
border border-border-default
rounded-lg text-xs
shadow-sm
transition-all duration-200
${onClick ? "cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-750" : ""}
relative h-6 w-6 rounded-full
${isActive ? "text-blue-600 dark:text-blue-300 hover:bg-blue-50 dark:hover:bg-blue-500/10" : "text-muted-foreground hover:bg-muted/60"}
${className}
`}
role={onClick ? "button" : undefined}
tabIndex={onClick ? 0 : -1}
onClick={onClick}
onKeyDown={(e) => {
if (!onClick) return;
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
onClick();
}
}}
>
<Download className="w-3 h-3 text-blue-500 dark:text-blue-400" />
<span className="text-gray-700 dark:text-gray-300 font-medium">
{t("settings.updateBadge")}
</span>
<button
onClick={(e) => {
e.stopPropagation();
dismissUpdate();
}}
className="
ml-1 -mr-0.5 p-0.5 rounded
hover:bg-gray-100 dark:hover:bg-gray-700
transition-colors
focus:outline-none focus:ring-2 focus:ring-blue-500/20
"
aria-label={t("common.close")}
>
<X className="w-3 h-3 text-muted-foreground" />
</button>
</div>
<span
className={`
absolute inset-0 m-auto h-2 w-2 rounded-full ring-1 ring-background
${isActive ? "bg-blue-500 dark:bg-blue-400" : "bg-blue-300/70 dark:bg-blue-300/60"}
`}
/>
</Button>
);
}