样式调整

This commit is contained in:
海龙 2025-08-30 22:59:25 +08:00
parent 596e695a1d
commit c9735fe15a
4 changed files with 166 additions and 100 deletions

View File

@ -102,9 +102,6 @@ function HomeModule5() {
}, [plans, billingType]); }, [plans, billingType]);
const handleSubscribe = async (planName: string) => { const handleSubscribe = async (planName: string) => {
if (planName === "Kickoff") {
return;
}
try { try {
// 使用新的Checkout Session方案更简单 // 使用新的Checkout Session方案更简单

View File

@ -0,0 +1,90 @@
import React from 'react';
interface UserCardProps {
/** 用户计划名称 */
plan_name?: string;
/** 子组件内容 */
children: React.ReactNode;
}
/**
*
*
*/
export default function UserCard({
plan_name = "none",
children
}: UserCardProps) {
// 根据计划名称获取对应的样式
const getCardStyles = () => {
switch (plan_name) {
case "Kickoff":
return {
outerBg: "bg-[#3d3c3d]",
glowColor: "bg-[#c0c0c0]",
glowShadow: "shadow-[0_0_50px_rgba(192,192,192,0.3)]"
};
case "Pro":
return {
outerBg: "bg-gradient-to-br from-[#1a1a2e] via-[#16213e] to-[#0f3460]",
glowColor: "bg-[#4facfe]",
glowShadow: "shadow-[0_0_50px_rgba(79,172,254,0.4)]"
};
case "Ultra":
return {
outerBg: "bg-gradient-to-br from-[#0a4a4a] via-[#2a1f4a] to-[#4a0a4a]",
glowColor: "bg-gradient-to-r from-[rgb(106,244,249)] to-[rgb(199,59,255)]",
glowShadow: "shadow-[0_0_50px_rgba(106,244,249,0.5)]"
};
default: // none
return {
outerBg: "bg-[#1a1a1a]",
glowColor: "bg-[#333]",
glowShadow: "shadow-[0_0_50px_rgba(51,51,51,0.3)]"
};
}
};
const styles = getCardStyles();
return (
<div
data-alt="user-card-outer"
className={`relative w-[18.75rem] h-[11.5rem] overflow-hidden rounded-xl ${styles.outerBg} ${styles.glowShadow}`}
>
{/* 发光背景 */}
<div
className={`absolute w-56 h-48 ${styles.glowColor} blur-[50px] -left-1/2 -top-1/2 opacity-40`}
/>
{/* 卡片内容区域 */}
<div
data-alt="user-card"
className={`relative z-[1] w-full h-full flex items-center justify-center text-white rounded-xl overflow-hidden `}
style={{ margin: '2px' }}
>
{/* 计划名称背景文字 - 非 none 时显示 */}
{plan_name !== "none" && (
<div
data-alt="plan-name-background"
className="absolute inset-0 flex items-center justify-center z-[1] text-white/10 font-bold text-6xl tracking-wider"
style={{
transform: 'rotate(-15deg) scale(1.2)',
textShadow: '0 0 20px rgba(255,255,255,0.1)'
}}
>
{plan_name}
</div>
)}
{/* 内容区域 */}
<div
data-alt="user-card-content"
className="relative z-[2] w-full h-full flex flex-col items-center justify-center rounded-xl"
>
{children}
</div>
</div>
</div>
);
};

View File

@ -2,6 +2,7 @@
import "../pages/style/top-bar.css"; import "../pages/style/top-bar.css";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { GradientText } from "@/components/ui/gradient-text"; import { GradientText } from "@/components/ui/gradient-text";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import { import {
@ -23,6 +24,7 @@ import {
redirectToPortal, redirectToPortal,
getUserSubscriptionInfo, getUserSubscriptionInfo,
} from "@/lib/stripe"; } from "@/lib/stripe";
import UserCard from "@/components/common/userCard";
interface User { interface User {
id: string; id: string;
@ -33,11 +35,7 @@ interface User {
plan_name?: string; plan_name?: string;
} }
export function TopBar({ export function TopBar({ collapsed }: { collapsed: boolean }) {
collapsed,
}: {
collapsed: boolean;
}) {
const router = useRouter(); const router = useRouter();
const [isOpen, setIsOpen] = React.useState(false); const [isOpen, setIsOpen] = React.useState(false);
const menuRef = useRef<HTMLDivElement>(null); const menuRef = useRef<HTMLDivElement>(null);
@ -68,7 +66,7 @@ export function TopBar({
// 更新 currentUser 的 plan_name // 更新 currentUser 的 plan_name
setCurrentUser((prev) => ({ setCurrentUser((prev) => ({
...prev, ...prev,
plan_name: response.data.plan_name, plan_name: response.data.plan_name, // HACK
})); }));
} }
} catch (error) { } catch (error) {
@ -169,7 +167,7 @@ export function TopBar({
return ( return (
<div <div
className="fixed right-0 top-0 h-16 header z-[999]" className="fixed right-0 top-0 h-16 header z-[999]"
style={{ isolation: "isolate", left: collapsed ? '3rem' : '16rem' }} style={{ isolation: "isolate", left: collapsed ? "3rem" : "16rem" }}
> >
<div className="h-full flex items-center justify-between pr-6 pl-4"> <div className="h-full flex items-center justify-between pr-6 pl-4">
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
@ -264,11 +262,11 @@ export function TopBar({
}} }}
data-alt="user-menu-trigger" data-alt="user-menu-trigger"
style={{ style={{
background: 'unset !important' background: "unset !important",
}} }}
> >
<div className="h-10 w-10 rounded-full bg-[#C73BFF] flex items-center justify-center text-white font-semibold"> <div className="h-10 w-10 rounded-full bg-[#C73BFF] flex items-center justify-center text-white font-semibold">
{currentUser.username ? currentUser.username.charAt(0) : 'MF'} {currentUser.username ? currentUser.username.charAt(0) : "MF"}
</div> </div>
</Button> </Button>
@ -284,89 +282,73 @@ export function TopBar({
position: "fixed", position: "fixed",
top: "4rem", top: "4rem",
right: "1rem", right: "1rem",
width: "18rem",
zIndex: 9999, zIndex: 9999,
}} }}
className="bg-[#1E1E1E] rounded-lg shadow-lg overflow-hidden" className="overflow-hidden rounded-xl"
data-alt="user-menu-dropdown" data-alt="user-menu-dropdown"
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
{/* User Info */} <UserCard plan_name={currentUser.plan_name}>
<div className="p-4"> <div className="relative z-[2] w-full h-full flex flex-col text-white p-3">
<div className="flex items-center space-x-3"> {/* 顶部用户信息 */}
<div className="h-10 w-10 rounded-full bg-[#C73BFF] flex items-center justify-center text-white font-semibold"> <div className="flex items-center space-x-3 mb-3">
{currentUser.username ? currentUser.username.charAt(0) : 'MF'} <div className="h-10 w-10 rounded-full bg-[#C73BFF] flex items-center justify-center text-white font-bold text-sm flex-shrink-0">
</div> {currentUser.username
<div className="flex-1"> ? currentUser.username.charAt(0)
<div className="flex items-center gap-2"> : "MF"}
<p className="text-sm font-medium"> </div>
{currentUser.name || currentUser.username} <div className="flex-1 min-w-0">
</p> <h3 className="text-sm font-semibold text-white truncate">
{currentUser.plan_name && {currentUser.name || currentUser.username}
currentUser.plan_name !== "none" && ( </h3>
<span <p className="text-xs text-gray-300 truncate">
className={`inline-flex items-center px-2 py-1 text-xs font-medium rounded-full ${ {currentUser.email}
currentUser.plan_name === "Kickoff" </p>
? "bg-blue-100 text-blue-800" </div>
: currentUser.plan_name === "Pro" </div>
? "bg-purple-100 text-purple-800"
: currentUser.plan_name === "Ultra"
? "bg-orange-100 text-orange-800"
: ""
}`}
>
{currentUser.plan_name}
</span>
)}
</div>
<p className="text-xs text-gray-500">
{currentUser.email}
</p>
</div>
<div
className="cursor-pointer hover:text-red-400 transition-colors duration-200"
onClick={() => {
logoutUser();
}}
title="退出登录"
>
<LogOut className="h-4 w-4" />
</div>
</div>
</div>
{/* AI Points */} {/* AI 积分 */}
<div className="px-4 py-3 flex items-center justify-between"> <div className="flex items-center justify-center space-x-3 mb-4">
<div className="flex items-center space-x-2"> <div className="p-2 rounded-full bg-white/10 backdrop-blur-sm">
<Sparkles className="h-4 w-4" /> <Sparkles className="h-5 w-5 text-white" />
<span className="text-white underline text-sm"> </div>
{isLoadingSubscription <span className="text-white text-base font-semibold">
? "..." {isLoadingSubscription
: `${credits} credits`} ? "Loading..."
</span> : `${credits} credits`}
</div> </span>
<Button </div>
variant="outline"
size="sm" {/* 操作按钮区域 */}
className="text-white border-white hover:bg-white/10 rounded-full px-3 py-1 text-[10px]" <div className="flex-1 flex flex-row justify-center items-end space-x-2 pb-2">
onClick={() => { <button
window.open("/pricing", "_blank"); className="flex-1 bg-transparent border border-white/30 text-white text-xs py-0.5 h-6 rounded hover:bg-white/10 transition-colors"
}} onClick={() => {
> window.open("/pricing", "_blank");
Upgrade }}
</Button> >
{subscriptionStatus === "ACTIVE" && ( Upgrade
<Button </button>
variant="outline"
size="sm" {currentUser.plan_name !== "none" && (
className="text-white border-white hover:bg-white/10 rounded-full px-3 py-1 text-[10px]" <button
onClick={handleManageSubscription} className="flex-1 bg-transparent border border-gray-400/30 text-gray-300 text-xs py-0.5 h-6 rounded hover:bg-gray-400/10 transition-colors disabled:opacity-50"
disabled={isManagingSubscription} onClick={handleManageSubscription}
> disabled={isManagingSubscription}
Manage >
</Button> Manage
)} </button>
</div> )}
<button
className="flex-1 bg-transparent border border-red-400/50 text-red-300 text-xs py-0.5 h-6 rounded hover:bg-red-400/10 transition-colors"
onClick={() => logoutUser()}
>
Logout
</button>
</div>
</div>
</UserCard>
</motion.div>, </motion.div>,
document.body document.body
) )

View File

@ -254,21 +254,21 @@ function HomeModule2() {
const videoList = [ const videoList = [
{ {
title: "Text to Movie", title: "Text to Movie",
video: "https://cdn.qikongjian.com/videos/module2 (1).mp4", video: "https://cdn.qikongjian.com/1756559467841_kn9fr9.mp4",
}, },
{ {
title: "Image to Movie", title: "Image to Movie",
video: "https://cdn.qikongjian.com/videos/module2 (2).mp4", video: "https://cdn.qikongjian.com/1756559467840_m4ijd7.mp4",
}, },
{ {
title: "Template to Movie", title: "Template to Movie",
video: "https://cdn.qikongjian.com/videos/module2 (3).mp4", video: "https://cdn.qikongjian.com/1756559467836_ij9y54.mp4",
}, },
]; ];
return ( return (
<div <div
data-alt="core-value-section" data-alt="core-value-section"
className="home-module2 relative flex flex-col items-center justify-center w-full h-[1300px] bg-black snap-start" className="home-module2 relative flex flex-col items-center justify-center w-full h-[1000px] bg-black snap-start"
> >
<div <div
data-alt="core-value-content" data-alt="core-value-content"
@ -277,7 +277,7 @@ function HomeModule2() {
<h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[3rem]"> <h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[3rem]">
Just Drop A Thought Just Drop A Thought
</h2> </h2>
<p className="text-white text-[1.125rem] leading-[140%] font-normal text-center"> <p className="text-white text-[1.7rem] leading-[140%] font-normal text-center">
Say your idea in a single line,and MovieFlow will bring it to life. Say your idea in a single line,and MovieFlow will bring it to life.
</p> </p>
</div> </div>
@ -355,7 +355,7 @@ function HomeModule3() {
<h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[3rem]"> <h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[3rem]">
Ideas Made Real Ideas Made Real
</h2> </h2>
<p className="text-white text-[1.125rem] leading-[140%] font-normal text-center"> <p className="text-white text-[1.7rem] leading-[140%] font-normal text-center">
High-quality films, any style, made with MovieFlow. High-quality films, any style, made with MovieFlow.
</p> </p>
</div> </div>
@ -479,11 +479,11 @@ function HomeModule4() {
return ( return (
<div <div
data-alt="core-value-section" data-alt="core-value-section"
className="home-module4 h-[1280px] relative flex flex-col items-center justify-center w-full bg-black snap-start" className="home-module4 h-[1000px] relative flex flex-col items-center justify-center w-full bg-black snap-start"
> >
<div <div
data-alt="core-value-content" data-alt="core-value-content"
className="center z-10 flex flex-col items-center mb-[14rem]" className="center z-10 flex flex-col items-center mb-[10rem]"
> >
<h2 className="text-white text-[3.375rem] leading-[100%] font-normal "> <h2 className="text-white text-[3.375rem] leading-[100%] font-normal ">
Create Your Way Create Your Way
@ -588,9 +588,6 @@ function HomeModule5() {
}, [plans, billingType]); }, [plans, billingType]);
const handleSubscribe = async (planName: string) => { const handleSubscribe = async (planName: string) => {
if (planName === "hobby") {
return;
}
localStorage.setItem("callBackUrl", pathname); localStorage.setItem("callBackUrl", pathname);
try { try {
// 使用新的Checkout Session方案更简单 // 使用新的Checkout Session方案更简单