From 713ce06aeae7934c7e77450be249f1a072b2dc61 Mon Sep 17 00:00:00 2001
From: t8y2 <1156263951@qq.com>
Date: Tue, 22 Sep 2026 11:36:14 +0800
Subject: [PATCH] feat(docs): float RainYun sponsor card on doc pages
---
docs/app/[lang]/docs/layout.tsx | 2 +
docs/app/global.css | 17 ++++++
docs/components/FloatingSponsorCard.tsx | 77 +++++++++++++++++++++++++
3 files changed, 96 insertions(+)
create mode 100644 docs/components/FloatingSponsorCard.tsx
diff --git a/docs/app/[lang]/docs/layout.tsx b/docs/app/[lang]/docs/layout.tsx
index 845bcb9b5f..c3afca3c17 100644
--- a/docs/app/[lang]/docs/layout.tsx
+++ b/docs/app/[lang]/docs/layout.tsx
@@ -2,6 +2,7 @@ import type { ReactNode } from "react";
import { DocsLayout } from "fumadocs-ui/layouts/docs";
import { RootProvider } from "fumadocs-ui/provider/next";
import { DocsSidebarFooter, DocsSidebarLanguageButton } from "@/components/DocsSidebarFooter";
+import { FloatingSponsorCard } from "@/components/FloatingSponsorCard";
import { StaticSearchDialog } from "@/components/StaticSearchDialog";
import { i18nUI, resolveLang } from "@/lib/i18n";
import { source } from "@/lib/source";
@@ -37,6 +38,7 @@ export default async function Layout({ params, children }: { params: Promise<{ l
}}
>
{children}
+
);
diff --git a/docs/app/global.css b/docs/app/global.css
index a024d85391..59e251e198 100644
--- a/docs/app/global.css
+++ b/docs/app/global.css
@@ -22,6 +22,23 @@
opacity 0.22s ease;
}
+/* 文档页右下角赞助悬浮卡片入场动画 */
+
+@keyframes sponsor-card-in {
+ from {
+ opacity: 0;
+ transform: translateY(8px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.sponsor-card-in {
+ animation: sponsor-card-in 0.3s ease-out both;
+}
+
@theme {
--color-landing-bg: #161616;
--color-landing-ink: #ededf0;
diff --git a/docs/components/FloatingSponsorCard.tsx b/docs/components/FloatingSponsorCard.tsx
new file mode 100644
index 0000000000..d548f660df
--- /dev/null
+++ b/docs/components/FloatingSponsorCard.tsx
@@ -0,0 +1,77 @@
+"use client";
+
+import { X } from "lucide-react";
+import { useEffect, useState } from "react";
+
+const DISMISS_STORAGE_KEY = "dbx.docs.sponsorCard.dismissedAt";
+// 关闭 7 天后重新出现
+const RESURFACE_MS = 7 * 24 * 60 * 60 * 1000;
+
+const RAINYUN_URL = "https://www.rainyun.com/MTE5Mjc4Ng==_";
+
+const COPY = {
+ cn: {
+ badge: "赞助商",
+ tagline: "云服务器 · 游戏云 · 物理服务器",
+ closeLabel: "关闭赞助卡片",
+ },
+ en: {
+ badge: "Sponsor",
+ tagline: "Cloud servers, game hosting & bare metal",
+ closeLabel: "Dismiss sponsor card",
+ },
+} as const;
+
+export function FloatingSponsorCard({ lang }: { lang: string }) {
+ const [visible, setVisible] = useState(false);
+
+ useEffect(() => {
+ try {
+ const dismissedAt = Number(window.localStorage.getItem(DISMISS_STORAGE_KEY));
+ if (!Number.isFinite(dismissedAt) || Date.now() - dismissedAt > RESURFACE_MS) {
+ setVisible(true);
+ }
+ } catch {
+ setVisible(true);
+ }
+ }, []);
+
+ if (!visible) return null;
+
+ const dismiss = () => {
+ setVisible(false);
+ try {
+ window.localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now()));
+ } catch {
+ // localStorage 不可用时按本次会话关闭处理
+ }
+ };
+
+ const t = lang === "cn" ? COPY.cn : COPY.en;
+
+ return (
+
+ );
+}