feat(settings): give the About card's star prompt its own dismissible strip

The star prompt sat at the end of the link row with ms-auto, so it
wrapped onto a line of its own and read like a stray underlined caption.

- Move it into a tinted strip at the bottom of the card with a slowly
  spinning star (stops under prefers-reduced-motion) and a "Star on
  GitHub" button that opens the repo
- Drop the separate GitHub button while the strip is shown, since the
  star button goes to the same place
- Add a close button; dismissal is remembered per device in
  localStorage, and the plain GitHub button returns to the link row
- Add settings.starOnGithub to all four locales
This commit is contained in:
Jason committed 2026-10-07 09:16:14 +08:00
1 parent f61dc5f520
commit e09fdf046c
5 files changed
+77 -19

No files matched your search

+73 -19
View File
@@ -8,6 +8,8 @@ import {
Loader2,
RefreshCw,
Sparkles,
Star,
X,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { useTranslation } from "react-i18next";
@@ -28,6 +30,17 @@ interface AboutSectionProps {
// 应用自身版本(getVersion,本地毫秒级、无网络)也缓存一份,纯为重挂时免去 loading 闪烁。
let appVersionCache: string | null = null;
// 邀 Star 条关掉后记在本机(纯界面偏好,不进库、不随云同步)
const STAR_PROMPT_DISMISSED_KEY = "ccswitch:about:starPromptDismissed";
function readStarPromptDismissed(): boolean {
try {
return localStorage.getItem(STAR_PROMPT_DISMISSED_KEY) === "1";
} catch {
return false;
}
}
/**
* 设置 → 关于:版本、便携模式、检查更新 / 安装并重启、项目链接。
* 命令行应用的安装与升级在侧栏「应用」页。
@@ -42,6 +55,9 @@ export function AboutSection({ isPortable }: AboutSectionProps) {
);
const [isDownloading, setIsDownloading] = useState(false);
const [whatsNewOpen, setWhatsNewOpen] = useState(false);
const [starPromptDismissed, setStarPromptDismissed] = useState(
readStarPromptDismissed,
);
const recentEntries = useMemo(
() => (version ? entriesUpTo(WHATS_NEW_ENTRIES, version) : []),
[version],
@@ -106,6 +122,15 @@ export function AboutSection({ isPortable }: AboutSectionProps) {
void settingsApi.openExternal("https://github.com/farion1231/cc-switch");
}, []);
const handleDismissStarPrompt = useCallback(() => {
setStarPromptDismissed(true);
try {
localStorage.setItem(STAR_PROMPT_DISMISSED_KEY, "1");
} catch {
// 存不下就只在本次会话里隐藏
}
}, []);
const handleCheckUpdate = useCallback(async () => {
if (hasUpdate) {
if (isPortable) {
@@ -230,15 +255,17 @@ export function AboutSection({ isPortable }: AboutSectionProps) {
)}
<div className="flex flex-wrap items-center gap-2 px-5 py-4">
<Button
type="button"
variant="neutral"
size="compact"
onClick={handleOpenGithub}
>
<Github className="h-3.5 w-3.5" />
{t("settings.github")}
</Button>
{starPromptDismissed && (
<Button
type="button"
variant="neutral"
size="compact"
onClick={handleOpenGithub}
>
<Github className="h-3.5 w-3.5" />
{t("settings.github")}
</Button>
)}
<Button
type="button"
variant="neutral"
@@ -268,18 +295,45 @@ export function AboutSection({ isPortable }: AboutSectionProps) {
{t("whatsNew.recentTitle")}
</Button>
)}
<a
href="https://github.com/farion1231/cc-switch"
onClick={(event) => {
event.preventDefault();
handleOpenGithub();
}}
className="ms-auto text-caption text-fg-2 underline decoration-border-strong underline-offset-[3px] hover:text-fg-1"
>
{t("settings.starPrompt")}
</a>
</div>
{/* 下载与更新都走 ccswitch.io,用户不再经过仓库页,邀 Star 单独占一行;按钮即 GitHub 入口。
关掉后链接行补回 GitHub 按钮 */}
{!starPromptDismissed && (
<div className="flex flex-wrap items-center gap-x-4 gap-y-3 bg-action-soft py-3.5 ps-5 pe-3">
<div className="flex min-w-0 flex-1 items-center gap-3">
<Star
aria-hidden="true"
className="h-5 w-5 shrink-0 animate-[spin_6s_linear_infinite] fill-amber-500 text-amber-500 motion-reduce:animate-none"
/>
<p className="min-w-0 text-body text-fg-1">
{t("settings.starPrompt")}
</p>
</div>
<div className="flex shrink-0 items-center gap-1">
<Button
type="button"
variant="neutral"
size="compact"
onClick={handleOpenGithub}
>
<Github className="h-3.5 w-3.5" />
{t("settings.starOnGithub")}
</Button>
<Button
type="button"
variant="quiet"
size="icon-compact"
onClick={handleDismissStarPrompt}
aria-label={t("common.close")}
title={t("common.close")}
>
<X className="h-3.5 w-3.5" />
</Button>
</div>
</div>
)}
<WhatsNewDialog
open={whatsNewOpen}
onClose={() => setWhatsNewOpen(false)}
+1
View File
@@ -905,6 +905,7 @@
"officialWebsite": "Official Website",
"github": "GitHub",
"starPrompt": "If CC Switch has helped you, please star us on GitHub — it means a lot to us",
"starOnGithub": "Star on GitHub",
"manualInstallCommands": "Manual Install Commands",
"oneClickInstallHint": "Install or upgrade Claude Code / Codex / Gemini CLI / Grok Build / OpenCode / OpenClaw / Hermes / Pi / MiniMax Code",
"localEnvCheck": "Local environment check",
+1
View File
@@ -905,6 +905,7 @@
"officialWebsite": "公式サイト",
"github": "GitHub",
"starPrompt": "CC Switch がお役に立てたなら、GitHub でスターをお願いします。私たちにとって大きな励みになります",
"starOnGithub": "GitHub でスター",
"manualInstallCommands": "手動インストールコマンド",
"oneClickInstallHint": "Claude Code / Codex / Gemini CLI / Grok Build / OpenCode / OpenClaw / Hermes / Pi / MiniMax Code をインストールまたは更新",
"localEnvCheck": "ローカル環境チェック",
+1
View File
@@ -905,6 +905,7 @@
"officialWebsite": "官方網站",
"github": "GitHub",
"starPrompt": "如果 CC Switch 幫到了你,請在 GitHub 點個 Star,這對我們意義重大",
"starOnGithub": "去點 Star",
"manualInstallCommands": "手動安裝指令",
"oneClickInstall": "一鍵安裝",
"oneClickInstallHint": "安裝或更新 Claude Code / Codex / Gemini CLI / Grok Build / OpenCode / OpenClaw / Hermes / Pi / MiniMax Code",
+1
View File
@@ -905,6 +905,7 @@
"officialWebsite": "官方网站",
"github": "GitHub",
"starPrompt": "如果 CC Switch 帮到了你,请在 GitHub 点个 Star,这对我们意义重大",
"starOnGithub": "去点 Star",
"manualInstallCommands": "手动安装命令",
"oneClickInstallHint": "安装或升级 Claude Code / Codex / Gemini CLI / Grok Build / OpenCode / OpenClaw / Hermes / Pi / MiniMax Code",
"localEnvCheck": "本地环境检查",