feat(website): SEO 升级 — BrowserRouter + 每页独立 meta

- HashRouter → BrowserRouter(basename /KimiSwitch),GitHub Pages 用 404.html SPA 回退,/features /download /changelog 变为可收录的独立 URL
- 每页独立 title / description / OG / canonical(RouteMeta 随语言切换)
- og:image 改为绝对地址;sitemap 更新为干净路径
This commit is contained in:
KimiSwitch Dev committed 2026-08-01 19:56:54 +08:00
1 parent 5788624d12
commit 1b5cd0f416
8 files changed
+139 -21

No files matched your search

+46
View File
@@ -8,6 +8,10 @@ import Download from "./sections/Download";
import Privacy from "./sections/Privacy";
import CTA from "./sections/CTA";
import Footer from "./components/Footer";
import { useLang, type Dict } from "./i18n";
const SITE_URL = "https://billowliu2.github.io/KimiSwitch";
type SeoKey = keyof Dict["seo"];
function ScrollToTop() {
const { pathname } = useLocation();
@@ -17,6 +21,47 @@ function ScrollToTop() {
return null;
}
/** Update per-page title / description / OG / canonical for SEO. */
function RouteMeta() {
const { pathname } = useLocation();
const { t } = useLang();
useEffect(() => {
const page = pathname.replace(/\/+$/, "");
const seoKey: SeoKey =
page === "/features" || page === "/changelog" || page === "/download"
? (page.slice(1) as SeoKey)
: "home";
const m = t.seo[seoKey];
const url = `${SITE_URL}${page === "" ? "/" : page}`;
document.title = m.title;
setMeta("name", "description", m.description);
setMeta("property", "og:title", m.title);
setMeta("property", "og:description", m.description);
setMeta("property", "og:url", url);
setMeta("name", "twitter:title", m.title);
setMeta("name", "twitter:description", m.description);
const canon = document.querySelector('link[rel="canonical"]');
if (canon) canon.setAttribute("href", url);
}, [pathname, t]);
return null;
}
function setMeta(attr: "name" | "property", key: string, content: string) {
let el = document.head.querySelector<HTMLMetaElement>(
`meta[${attr}="${key}"]`,
);
if (!el) {
el = document.createElement("meta");
el.setAttribute(attr, key);
document.head.appendChild(el);
}
el.setAttribute("content", content);
}
const homePage = (
<>
<Hero />
@@ -30,6 +75,7 @@ export default function App() {
<Nav />
<main className="flex-1">
<ScrollToTop />
<RouteMeta />
<Routes>
<Route path="/" element={homePage} />
<Route
+44
View File
@@ -252,6 +252,28 @@ const zh = {
download: "免费下载",
source: "GitHub 源码",
},
seo: {
home: {
title: "Kimi Switch — 多 LLM 供应商统一管理 · 用量监控 · 账单一目了然",
description:
"Kimi Switch / KimiCodeSwitch — Windows 桌面端多 LLM 供应商统一管理器,一键切换 Kimi / 智谱 GLM / MiniMax / DeepSeek / OpenRouter / 基元律动,用量账单实时监控,开源 MIT。",
},
features: {
title: "核心功能 - Kimi Switch",
description:
"Kimi Switch 核心功能:多供应商管理、用量与账单监控、Kimi 一键授权登录、智能模型发现与自动更新,22 个预设开箱即用。",
},
changelog: {
title: "更新日志 - Kimi Switch",
description:
"Kimi Switch 更新日志:每个版本的重要变更记录,同步自 GitHub Releases。",
},
download: {
title: "下载 - Kimi Switch",
description:
"下载 Kimi Switch:Windows .msi、macOS .dmg、Linux .deb / .AppImage / .rpm,免费开源 MIT。",
},
},
footer: {
recommend: "推荐供应商",
mirror: "国内镜像",
@@ -516,6 +538,28 @@ const en: Dict = {
download: "Free Download",
source: "GitHub Source",
},
seo: {
home: {
title: "Kimi Switch — Unified Management for AI Providers · Usage & Billing",
description:
"Kimi Switch / KimiCodeSwitch — a Windows desktop manager for multiple LLM providers. Switch between Kimi, Zhipu GLM, MiniMax, DeepSeek, OpenRouter and TokenRhythm in one click, with usage and billing at a glance. Open source MIT.",
},
features: {
title: "Core Features - Kimi Switch",
description:
"Kimi Switch core features: multi-provider management, usage & billing, one-click Kimi login, smart model discovery and auto updates. 22 presets out of the box.",
},
changelog: {
title: "Changelog - Kimi Switch",
description:
"Kimi Switch changelog: notable changes in every release, synced from GitHub Releases.",
},
download: {
title: "Download - Kimi Switch",
description:
"Download Kimi Switch: Windows .msi, macOS .dmg, Linux .deb / .AppImage / .rpm. Free and open source under MIT.",
},
},
footer: {
recommend: "Recommended Providers",
mirror: "China mirror",
+3 -3
View File
@@ -1,16 +1,16 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { HashRouter } from "react-router-dom";
import { BrowserRouter } from "react-router-dom";
import { LangProvider } from "./i18n";
import App from "./App";
import "./index.css";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<HashRouter>
<BrowserRouter basename="/KimiSwitch">
<LangProvider>
<App />
</LangProvider>
</HashRouter>
</BrowserRouter>
</StrictMode>,
);