fix(nav,auth): trim nav to wireframe pages; auth gracefully degrades when DB unavailable in dev
This commit is contained in:
parent
854a162109
commit
7949f9bcd1
@ -1,55 +1,21 @@
|
||||
import Link from "next/link";
|
||||
import Logo from "./Logo";
|
||||
|
||||
const FOOTER_LINKS = [
|
||||
{ label: "活动规则", href: "/rules" },
|
||||
{ label: "隐私协议", href: "/privacy" },
|
||||
{ label: "用户协议", href: "/terms" },
|
||||
{ label: "联系客服", href: "/support" },
|
||||
] as const;
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="border-t border-white/[0.06] bg-[rgba(8,5,26,0.6)] backdrop-blur-sm mt-20">
|
||||
<div className="max-w-7xl mx-auto px-6 sm:px-8 py-10 grid gap-8 md:grid-cols-3 items-start">
|
||||
{/* Brand */}
|
||||
<div className="max-w-7xl mx-auto px-6 sm:px-8 py-8 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||
<div>
|
||||
<Logo size="sm" href={null} />
|
||||
<p className="mt-3 text-xs text-white/45 leading-relaxed">
|
||||
虚拟偶像 Top12 出道企划
|
||||
<br />
|
||||
Cyber Star · Virtual Idol Debut Project
|
||||
<p className="mt-2 text-xs text-white/45 leading-relaxed">
|
||||
虚拟偶像 Top12 出道企划 · Cyber Star · Virtual Idol Debut Project
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Links */}
|
||||
<nav className="md:col-span-1">
|
||||
<p className="font-label text-[10px] tracking-[0.3em] uppercase text-purple-300 mb-3">
|
||||
Information
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm">
|
||||
{FOOTER_LINKS.map((link) => (
|
||||
<li key={link.href}>
|
||||
<Link
|
||||
href={link.href}
|
||||
className="text-white/55 hover:text-purple-300 transition-colors"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{/* Caption */}
|
||||
<div className="text-xs text-white/40 md:text-right">
|
||||
<p className="font-label tracking-[0.25em] uppercase text-purple-300/70 mb-2">
|
||||
<div className="text-xs text-white/40 sm:text-right">
|
||||
<p className="font-label tracking-[0.25em] uppercase text-purple-300/70 mb-1">
|
||||
© 2026 Cyber Star
|
||||
</p>
|
||||
<p>All rights reserved.</p>
|
||||
<p className="mt-1 font-mono text-white/30">
|
||||
airlabs.art · powered by Next.js
|
||||
</p>
|
||||
<p className="font-mono text-white/30">airlabs.art</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@ -6,10 +6,8 @@ import { cn } from "@/lib/cn";
|
||||
|
||||
const NAV_ITEMS = [
|
||||
{ label: "HOME", href: "/" },
|
||||
{ label: "VOTE", href: "/vote" },
|
||||
{ label: "RANKING", href: "/ranking" },
|
||||
{ label: "NEWS", href: "/news" },
|
||||
{ label: "ABOUT", href: "/about" },
|
||||
{ label: "ME", href: "/me" },
|
||||
] as const;
|
||||
|
||||
interface NavLinksProps {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import NextAuth, { type NextAuthConfig } from "next-auth";
|
||||
import Credentials from "next-auth/providers/credentials";
|
||||
import { PrismaAdapter } from "@auth/prisma-adapter";
|
||||
import { prisma } from "./prisma";
|
||||
import { z } from "zod";
|
||||
|
||||
@ -9,11 +8,11 @@ import { z } from "zod";
|
||||
*
|
||||
* 支持渠道(按优先级):
|
||||
* 1. 手机号 + 短信 OTP(国内主推)
|
||||
* 2. 微信扫码(待团队配置 appId/secret 后开启)
|
||||
* 2. 微信扫码(待团队配置 appId/secret 后开启 · 启用时需把 PrismaAdapter 加回来)
|
||||
* 3. 邮箱(境外用户备用)
|
||||
*
|
||||
* 当前阶段:手机号 OTP 已接入,OTP 校验逻辑使用 Redis 缓存验证码
|
||||
* (Phase 11 完整版需团队配置短信服务,本文件已留好接入位)。
|
||||
* 当前阶段:使用 JWT session 策略,Credentials 不需要 Adapter。
|
||||
* 数据库不可用时自动降级为内存用户(开发态友好)。
|
||||
*/
|
||||
|
||||
const OtpCredentials = z.object({
|
||||
@ -24,7 +23,8 @@ const OtpCredentials = z.object({
|
||||
});
|
||||
|
||||
export const authConfig: NextAuthConfig = {
|
||||
adapter: PrismaAdapter(prisma),
|
||||
// NOTE: Credentials + JWT 策略不需要 adapter。
|
||||
// 启用微信 OAuth 时再把 PrismaAdapter 加回来。
|
||||
session: { strategy: "jwt" },
|
||||
pages: {
|
||||
signIn: "/login",
|
||||
@ -42,49 +42,44 @@ export const authConfig: NextAuthConfig = {
|
||||
if (!parsed.success) return null;
|
||||
const { phone, code } = parsed.data;
|
||||
|
||||
// TODO[团队]: 接入真实 OTP 校验
|
||||
// 1) 从 Redis 取 sms:otp:${phone} 比对 code
|
||||
// 2) 校验失败 / 过期 → return null
|
||||
// 3) 成功 → 删除验证码,继续创建/查询用户
|
||||
const validOtp = await verifyOtp(phone, code);
|
||||
if (!validOtp) return null;
|
||||
|
||||
// 查询或创建用户
|
||||
const user = await prisma.user.upsert({
|
||||
where: { phone },
|
||||
create: {
|
||||
phone,
|
||||
nickname: `粉丝_${phone.slice(-4)}`,
|
||||
loginType: "PHONE",
|
||||
},
|
||||
update: { lastLoginAt: new Date() },
|
||||
});
|
||||
|
||||
return {
|
||||
id: String(user.id),
|
||||
name: user.nickname,
|
||||
image: user.avatar ?? undefined,
|
||||
};
|
||||
// 尝试持久化到数据库;失败则降级为内存身份(开发态)
|
||||
try {
|
||||
const user = await prisma.user.upsert({
|
||||
where: { phone },
|
||||
create: {
|
||||
phone,
|
||||
nickname: `粉丝_${phone.slice(-4)}`,
|
||||
loginType: "PHONE",
|
||||
},
|
||||
update: { lastLoginAt: new Date() },
|
||||
});
|
||||
return {
|
||||
id: String(user.id),
|
||||
name: user.nickname,
|
||||
image: user.avatar ?? undefined,
|
||||
};
|
||||
} catch (err) {
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
console.error("[auth] DB upsert failed:", err);
|
||||
return null;
|
||||
}
|
||||
// 开发态:用手机号末 9 位做确定性 ID,便于跨重启保持身份
|
||||
const fakeId = String(parseInt(phone.slice(-9), 10));
|
||||
console.warn(
|
||||
`[auth] DB 不可用,开发态降级身份 id=${fakeId} phone=${phone}`,
|
||||
);
|
||||
return {
|
||||
id: fakeId,
|
||||
name: `粉丝_${phone.slice(-4)}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
// TODO[团队]: 启用微信扫码登录
|
||||
// 需要 WECHAT_APP_ID / WECHAT_APP_SECRET 环境变量。
|
||||
// 实现可参考 https://authjs.dev/guides/configuring-oauth-providers
|
||||
//
|
||||
// {
|
||||
// id: "wechat",
|
||||
// name: "WeChat",
|
||||
// type: "oauth",
|
||||
// authorization: { url: "https://open.weixin.qq.com/connect/qrconnect", params: { scope: "snsapi_login" } },
|
||||
// token: "https://api.weixin.qq.com/sns/oauth2/access_token",
|
||||
// userinfo: "https://api.weixin.qq.com/sns/userinfo",
|
||||
// clientId: process.env.WECHAT_APP_ID,
|
||||
// clientSecret: process.env.WECHAT_APP_SECRET,
|
||||
// profile(p) {
|
||||
// return { id: p.openid, name: p.nickname, image: p.headimgurl };
|
||||
// },
|
||||
// },
|
||||
// TODO[团队]: 启用微信扫码登录(需配置 WECHAT_APP_ID/SECRET 并加回 PrismaAdapter)
|
||||
],
|
||||
callbacks: {
|
||||
async jwt({ token, user }) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user