Commit 288d456c authored by timel's avatar timel

feat: match page

parent 294d0f81
Pipeline #22887 failed with stages
in 12 minutes and 29 seconds
...@@ -34,7 +34,10 @@ const theme: ThemeConfig = { ...@@ -34,7 +34,10 @@ const theme: ThemeConfig = {
export const Component: React.FC = () => { export const Component: React.FC = () => {
return ( return (
<ConfigProvider theme={theme}> <ConfigProvider theme={theme}>
<Background /> <Background
style={{ backgroundImage: "initial" }}
innerStyle={{ background: "rgba(72, 0, 255, 0.6)" }}
/>
<div className={styles.layout} style={{ width: "100%" }}> <div className={styles.layout} style={{ width: "100%" }}>
<div className={styles.sider}> <div className={styles.sider}>
<div className={styles["deck-select-container"]}> <div className={styles["deck-select-container"]}>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 75px; gap: 60px;
} }
} }
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
border-right: none; border-right: none;
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
background-color: rgba(255, 255, 255, 0.08); background-color: rgba(255, 255, 255, 0.04);
} }
.select :global(.ant-select-selector) { .select :global(.ant-select-selector) {
border-top-left-radius: 0; border-top-left-radius: 0;
...@@ -45,33 +45,57 @@ ...@@ -45,33 +45,57 @@
.mode-select { .mode-select {
display: grid; display: grid;
grid-template-columns: 1fr 1fr 1.75fr; /* 三列 */ grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto; /* 自动调整行高 */ grid-template-rows: repeat(2, 1fr); /* 自动调整行高 */
gap: 40px 34px; /* 行和列的间隔 */ width: 800px;
width: 1000px; height: 500px;
height: 414px; gap: 16px;
.rank { .mode {
grid-column: 1 / 2; height: 100%;
grid-row: 1 / 3; background: hsla(0, 0%, 100%, 0.05);
backdrop-filter: blur(10px);
padding: 32px;
border-radius: 12px;
transition: 0.2s;
cursor: pointer;
&:hover {
box-shadow: 0 0 0 4px rgb(56, 27, 143);
background: hsla(0, 0%, 100%, 0.07);
filter: brightness(1.1);
}
.icon {
&::before {
content: "";
width: 100%;
height: 100%;
position: absolute;
background: linear-gradient(#514f5780, #2a283277);
}
overflow: hidden;
position: relative;
--length: 48px;
width: var(--length);
height: var(--length);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
color: white;
transition: 0.2s;
} }
.fun { &:hover .icon {
grid-column: 2 / 3; filter: brightness(1.3);
grid-row: 1 / 3;
} }
.solo { .title {
grid-column: 3 / 4; margin-top: 24px;
margin-bottom: 12px;
font-size: 16px;
} }
.custom { .desc {
grid-column: 3 / 4; font-size: 14px;
line-height: 24px;
color: hsla(0, 0%, 100%, 0.6);
} }
.mode {
height: -webkit-fill-available;
border-radius: 20px;
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.05) 100%
);
border: 1px solid rgba(255, 255, 255, 0.2);
} }
} }
...@@ -4,10 +4,14 @@ import { type LoaderFunction } from "react-router-dom"; ...@@ -4,10 +4,14 @@ import { type LoaderFunction } from "react-router-dom";
import { CookieKeys, setCookie } from "@/api"; import { CookieKeys, setCookie } from "@/api";
import { accountStore, type User } from "@/stores"; import { accountStore, type User } from "@/stores";
import { Background } from "@/ui/Shared"; import { Background, IconFont } from "@/ui/Shared";
import { useConfig } from "@/config";
import { SettingFilled, EditFilled } from "@ant-design/icons";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
const NeosConfig = useConfig();
export const loader: LoaderFunction = () => { export const loader: LoaderFunction = () => {
const sso = new URLSearchParams(location.search).get("sso"); const sso = new URLSearchParams(location.search).get("sso");
const user = sso ? getSSOUser(new URLSearchParams(atob(sso))) : undefined; const user = sso ? getSSOUser(new URLSearchParams(atob(sso))) : undefined;
...@@ -28,7 +32,7 @@ export const Component: React.FC = () => { ...@@ -28,7 +32,7 @@ export const Component: React.FC = () => {
<CustomSelect <CustomSelect
title="服务器" title="服务器"
defaultValue="lucy" defaultValue="lucy"
style={{ width: 370 }} style={{ width: 200 }}
options={[ options={[
{ value: "jack", label: "Jack" }, { value: "jack", label: "Jack" },
{ value: "lucy", label: "Lucy" }, { value: "lucy", label: "Lucy" },
...@@ -40,7 +44,7 @@ export const Component: React.FC = () => { ...@@ -40,7 +44,7 @@ export const Component: React.FC = () => {
title="卡组" title="卡组"
showSearch showSearch
defaultValue="lucy" defaultValue="lucy"
style={{ width: 370 }} style={{ width: 200 }}
options={[ options={[
{ value: "jack", label: "Jack" }, { value: "jack", label: "Jack" },
{ value: "lucy", label: "Lucy" }, { value: "lucy", label: "Lucy" },
...@@ -50,12 +54,36 @@ export const Component: React.FC = () => { ...@@ -50,12 +54,36 @@ export const Component: React.FC = () => {
/> />
</Space> </Space>
<div className={styles["mode-select"]}> <div className={styles["mode-select"]}>
<div className={classNames(styles.mode, styles.rank)}>竞技匹配</div> <Mode
<div className={classNames(styles.mode, styles.fun)}>娱乐匹配</div> title="竞技匹配"
<div className={classNames(styles.mode, styles.solo)}>单人模式</div> desc="与世界上其他玩家在线匹配,您的排名将实时显示在排行榜上。"
<div className={classNames(styles.mode, styles.custom)}> icon={<IconFont type="icon-battle" size={32} />}
自定义房间 />
</div> <Mode
title="休闲匹配"
desc="使用任意卡组进行对战,将胜负暂且搁置,尽情享受决斗的乐趣。"
icon={<IconFont type="icon-coffee" size={28} />}
/>
<Mode
title="单人模式"
desc="开启与AI的决斗,验证自己的卡组,或者只是打发时间。"
icon={<IconFont type="icon-chip" size={26} />}
/>
<Mode
title="自定义房间"
desc="创建一个自定义的对战房间,便捷地与好友进行对战,甚至是举办一场竞技比赛。"
icon={<SettingFilled />}
/>
<Mode
title="录像回放"
desc="自由查看进行过的决斗,回味那些精彩的逆转瞬间。"
icon={<IconFont type="icon-record" size={24} />}
/>
<Mode
title="卡组编辑"
desc="创建和编辑卡组,在上万种卡片中选择,组建独一无二的构筑。"
icon={<EditFilled />}
/>
</div> </div>
</div> </div>
</main> </main>
...@@ -64,6 +92,18 @@ export const Component: React.FC = () => { ...@@ -64,6 +92,18 @@ export const Component: React.FC = () => {
}; };
Component.displayName = "Match"; Component.displayName = "Match";
const Mode: React.FC<{
title: string;
desc: string;
icon: React.ReactNode;
}> = ({ title, desc, icon }) => (
<div className={styles.mode}>
<div className={styles.icon}>{icon}</div>
<div className={styles.title}>{title}</div>
<div className={styles.desc}>{desc}</div>
</div>
);
/** 从SSO跳转回的URL之中,解析用户信息 */ /** 从SSO跳转回的URL之中,解析用户信息 */
function getSSOUser(searchParams: URLSearchParams): User { function getSSOUser(searchParams: URLSearchParams): User {
return Object.fromEntries(searchParams) as unknown as User; return Object.fromEntries(searchParams) as unknown as User;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
background-color: #010514; background-color: #010514;
background-image: url("/neos-assets/background-grid.webp");
z-index: -1; z-index: -1;
display: flex; display: flex;
justify-content: center; justify-content: center;
...@@ -16,6 +17,6 @@ ...@@ -16,6 +17,6 @@
.inner { .inner {
width: 90vw; width: 90vw;
height: 50vh; height: 50vh;
background: rgba(72, 0, 255, 0.6); background: rgba(72, 0, 255, 0.8);
filter: blur(582px); filter: blur(582px);
} }
import { createFromIconfontCN } from "@ant-design/icons"; import { createFromIconfontCN } from "@ant-design/icons";
const _IconFont = createFromIconfontCN({ const _IconFont = createFromIconfontCN({
scriptUrl: ["//at.alicdn.com/t/c/font_4188978_14gvq0ry2bk.js"], scriptUrl: ["//at.alicdn.com/t/c/font_4188978_evr8efp70uk.js"],
}); });
export const IconFont: React.FC<{ export const IconFont: React.FC<{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment