refactor(components): 重构 playground组件

- 移除 Data、Scene 和 IodRelevant 组件中的 Drawer
- 优化 Data、Scene 和 IodRelevant 组件的结构
- 添加 Header 组件用于展示标题和关闭按钮
- 使用 Main 组件替代原来的 ShowCard 组件
- 调整样式和布局,提高组件的可复用性和可维护性
This commit is contained in:
zhaoweijie
2025-08-23 17:03:14 +08:00
parent 6fb71b01f0
commit e640b1254d
17 changed files with 664 additions and 410 deletions

View File

@@ -1,25 +1,121 @@
import React from "react"
import React, { createContext, useContext, useState } from "react"
import { AnimatePresence, motion } from "framer-motion"
import { PlaygroundIodRelevant } from "@/components/Common/Playground/IodRelevant.tsx"
import { PlaygroundData } from "@/components/Common/Playground/Data.tsx"
import { PlaygroundScene } from "@/components/Common/Playground/Scene.tsx"
import { PlaygroundTeam } from "@/components/Common/Playground/Team.tsx"
import { Card } from "antd"
import { CloseOutlined } from "@ant-design/icons"
// 定义 Context 类型
interface IodPlaygroundContextType {
showPlayground: boolean
setShowPlayground: React.Dispatch<React.SetStateAction<boolean>>
detailHeader: React.ReactNode
setDetailHeader: React.Dispatch<React.SetStateAction<React.ReactNode>>
detailMain: React.ReactNode
setDetailMain: React.Dispatch<React.SetStateAction<React.ReactNode>>
}
// 创建 Context
const PlaygroundContext = createContext<IodPlaygroundContextType | undefined>(
undefined
)
// 创建自定义 hook 以便子组件使用
export const useIodPlaygroundContext = () => {
const context = useContext(PlaygroundContext)
if (context === undefined) {
throw new Error(
"usePlaygroundContext must be used within a PlaygroundProvider"
)
}
return context
}
export const PlaygroundIod = () => {
const [showPlayground, setShowPlayground] = useState<boolean>(true)
const [detailHeader, setDetailHeader] = useState(<></>)
const [detailMain, setDetailMain] = useState(<></>)
return (
<div
className="w-[36%] h-full grid grid-rows-12 gap-3 pt-16 pr-5 pb-0"
style={{ paddingTop: "4rem" }}>
<div className="w-full row-span-5">
<PlaygroundIodRelevant />
<PlaygroundContext.Provider
value={{
showPlayground,
setShowPlayground,
detailMain,
setDetailMain,
detailHeader,
setDetailHeader
}}>
<div className="w-[36%] h-full pt-16 pr-5 pb-0">
<PlaygroundContent />
</div>
<div className="w-full row-span-4 grid grid-cols-2 gap-3 custom-scrollbar">
<PlaygroundData />
<PlaygroundScene />
</div>
<div className="w-full row-span-3 pb-3">
<PlaygroundTeam />
</div>
</div>
</PlaygroundContext.Provider>
)
}
// 子组件使用修改card的默认样式
const classNames =
"h-full [&_.ant-card-body]:h-full [&_.ant-card-body]:!p-[20px] overflow-y-hidden !bg-[rgba(240,245,255,0.3)] backdrop-blur-sm border border-white/30 shadow-xl rounded-2xl"
// 将原来的返回内容移到这个组件中
const PlaygroundContent = () => {
const { showPlayground, detailMain, detailHeader, setShowPlayground } =
useIodPlaygroundContext()
return (
<AnimatePresence mode="popLayout">
{showPlayground ? (
<motion.div
key="playground"
initial={{ x: "100%" }}
animate={{ x: 0 }}
exit={{ x: "100%" }}
transition={{
duration: 0.6,
ease: "easeInOut"
}}
className="h-full grid grid-rows-12 gap-3">
<div className="w-full row-span-5">
<PlaygroundIodRelevant className={classNames.replace('!bg-[rgba(240,245,255,0.3)]', '')} />
</div>
<div className="w-full row-span-4 grid grid-cols-2 gap-3 custom-scrollbar">
<PlaygroundData className={classNames} />
<PlaygroundScene className={classNames} />
</div>
<div className="w-full row-span-3 pb-3">
<PlaygroundTeam className={classNames} />
</div>
</motion.div>
) : (
<motion.div
key="alternative"
initial={{ x: "100%" }}
animate={{ x: 0 }}
exit={{ x: "100%" }}
transition={{
duration: 0.6,
ease: "easeInOut"
}}
className="h-full pb-5">
<Card className="h-full shadow-xl shadow-gray-500/20 [&_.ant-card-body]:h-full">
<div className="flex flex-col h-full">
<div className="pb-6 flex items-center justify-between">
<div>{detailHeader}</div>
<CloseOutlined
size={30}
className="hover:text-red-500 cursor-pointer transition-colors duration-200 text-xl"
onClick={() => setShowPlayground(true)}
/>
</div>
{detailMain}
</div>
</Card>
</motion.div>
)}
</AnimatePresence>
)
}