diff --git a/app/[locale]/login/page.tsx b/app/[locale]/login/page.tsx
index 920eee4..67a9a04 100644
--- a/app/[locale]/login/page.tsx
+++ b/app/[locale]/login/page.tsx
@@ -1,8 +1,10 @@
import type { Metadata } from "next";
+import { Suspense } from "react";
import { setRequestLocale, getTranslations } from "next-intl/server";
import { hasLocale } from "next-intl";
import { notFound } from "next/navigation";
import { SignInButton } from "@/app/components/SignInButton";
+import { LoginErrorNotice } from "@/app/components/LoginErrorNotice";
import { routing } from "@/i18n/routing";
// SEO: 登录页不参与 index(搜索引擎不需要收录登录入口)
@@ -30,11 +32,20 @@ export default async function LoginPage({ params }: Props) {
{t("heading")}
{t("subheading")}
+
+
+
- {/* Discord 登录暂时下线:后端 provider 已就绪,但新用户"验证邮箱→建号"
- 流程(OTP wiring)还没做完,先不对外暴露以免分叉账号。做完后取消注释即可。 */}
- {/* */}
+ {/* Discord 登录灰度中:后端按 Discord id 白名单放行(auth.discord.allowlist),
+ 名单外的人点了会被回调弹回 /login?error=discord_canary。GA(OTP wiring 完成、
+ 清空白名单)后此按钮即对所有人开放。 */}
+
diff --git a/app/components/LoginErrorNotice.tsx b/app/components/LoginErrorNotice.tsx
new file mode 100644
index 0000000..bc3d3d0
--- /dev/null
+++ b/app/components/LoginErrorNotice.tsx
@@ -0,0 +1,25 @@
+"use client";
+
+import { useSearchParams } from "next/navigation";
+
+// 登录页顶端的错误提示。后端 OAuth 回调失败会 302 到 /login?error=xxx。
+// 用 useSearchParams(客户端读 query)而非 server 读 searchParams,避免整页退回
+// 动态渲染(登录页要保持 SSG,见 CLAUDE.md 路由分类约束)。父级用 包裹。
+// 文案由 server 端 getTranslations 取好后作为 prop 传入,省一套 client i18n provider。
+export function LoginErrorNotice({
+ messages,
+}: {
+ messages: Record;
+}) {
+ const error = useSearchParams().get("error");
+ if (!error) return null;
+ const msg = messages[error] ?? messages.generic;
+ return (
+
+ {msg}
+
+ );
+}
diff --git a/generated/doc-contributors.json b/generated/doc-contributors.json
index 822d731..af4a834 100644
--- a/generated/doc-contributors.json
+++ b/generated/doc-contributors.json
@@ -1,6 +1,6 @@
{
"repo": "InvolutionHell/involutionhell",
- "generatedAt": "2026-05-24T18:19:10.363Z",
+ "generatedAt": "2026-07-24T13:55:10.610Z",
"docsDir": "content/docs",
"totalDocs": 144,
"results": [
@@ -2196,9 +2196,9 @@
"githubId": "123258594",
"contributions": 2,
"lastContributedAt": "2025-09-29T10:32:11.000Z",
- "login": "PenghaoJiang",
+ "login": "OvOhao",
"avatarUrl": "https://avatars.githubusercontent.com/u/123258594?v=4",
- "htmlUrl": "https://github.com/PenghaoJiang"
+ "htmlUrl": "https://github.com/OvOhao"
},
{
"githubId": "41898282",
@@ -2816,9 +2816,9 @@
"githubId": "76551253",
"contributions": 1,
"lastContributedAt": "2025-10-06T00:30:18.000Z",
- "login": "840691168",
+ "login": "YangLiu-Lewis",
"avatarUrl": "https://avatars.githubusercontent.com/u/76551253?v=4",
- "htmlUrl": "https://github.com/840691168"
+ "htmlUrl": "https://github.com/YangLiu-Lewis"
}
]
},
diff --git a/messages/en.json b/messages/en.json
index 2d7148b..484d1d1 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -70,7 +70,9 @@
"heading": "Sign In",
"subheading": "Sign in to access protected pages",
"github": "Sign in with GitHub",
- "discord": "Sign in with Discord"
+ "discord": "Sign in with Discord",
+ "errorDiscordCanary": "Discord sign-in is in limited testing and not open yet — stay tuned!",
+ "errorGeneric": "Sign-in didn't complete. Please try again."
},
"settings": {
"theme": {
diff --git a/messages/zh.json b/messages/zh.json
index 7b935f7..7355d94 100644
--- a/messages/zh.json
+++ b/messages/zh.json
@@ -70,7 +70,9 @@
"heading": "登录",
"subheading": "请登录以访问受保护的页面",
"github": "用 GitHub 登录",
- "discord": "用 Discord 登录"
+ "discord": "用 Discord 登录",
+ "errorDiscordCanary": "Discord 登录正在灰度测试中,暂未对外开放,敬请期待~",
+ "errorGeneric": "登录未完成,请重试。"
},
"settings": {
"theme": {