Commit 28af313d authored by timel's avatar timel

feat: card build

parent f7a5a096
......@@ -25,7 +25,6 @@ table {
#root {
margin: 0 auto;
text-align: center;
width: 100%;
}
......@@ -114,5 +113,5 @@ nav {
body {
--theme-font: "Electrolize", sans-serif;
--nav-height: 48px;
--nav-height: 56px;
}
@mixin scrollbar {
overflow-y: overlay;
&::-webkit-scrollbar {
background: transparent;
width: 5px;
}
&::-webkit-scrollbar-track {
background: transparent;
width: 5px;
}
&::-webkit-scrollbar-thumb {
background: rgba(136, 136, 136, 0.417);
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(136, 136, 136, 0.6);
}
&::-webkit-scrollbar-thumb:active {
background: rgba(136, 136, 136, 0.8);
}
}
export const Component = () => <>build</>;
Component.displayName = "Build";
@use "/src/styles/utils.scss";
.layout {
position: fixed;
left: 0;
top: var(--nav-height);
height: calc(100% - var(--nav-height));
}
.sider {
max-height: 100%;
min-height: 100%;
overflow-x: hidden;
overflow-y: overlay;
background: transparent !important;
@include utils.scrollbar;
.menu {
min-height: 100%;
}
.btn-add {
position: absolute;
bottom: 40px;
left: 50%;
transform: translate(-50%);
background-color: rgb(59, 0, 169);
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.5);
&:hover {
background-color: rgb(78, 0, 223);
transform: translate(-50%) scale(1.3);
}
}
}
.content {
display: flex;
padding-bottom: 0;
padding-right: 1rem;
.deck {
width: 620px;
}
.select {
flex: 1;
.select-btns {
padding: 5px;
display: flex;
}
}
}
.container {
height: calc(100% - 20px);
border: 1px solid rgba(255, 255, 255, 0.2);
display: flex;
flex-direction: column;
& > *:not(:last-of-type) {
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
.title {
height: 44px;
flex: 0 0 44px;
}
.deck-zone {
@include utils.scrollbar;
display: flex;
flex-direction: column;
height: 100%;
}
.main,
.extra,
.side {
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
padding: 0.75rem;
}
.main {
flex: 3;
}
.extra {
flex: 1;
}
.side {
flex: 1;
}
.card-continer {
display: grid;
grid-template-columns: repeat(10, 1fr);
gap: 5px;
}
}
.select .container {
border-left: none;
}
.card {
width: 100%;
background-color: rgb(32, 36, 71);
aspect-ratio: var(--card-ratio);
}
.search-cards-container {
overflow-y: scroll;
@include utils.scrollbar;
.search-cards {
--card-width: 80px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--card-width), 1fr));
padding: 0.75rem;
gap: 10px;
}
}
import {
Menu,
Layout,
type MenuProps,
ConfigProvider,
type ThemeConfig,
Input,
Button,
Space,
} from "antd";
import { Background } from "../Shared";
import styles from "./index.module.scss";
import classNames from "classnames";
import {
SearchOutlined,
DeleteOutlined,
UndoOutlined,
CheckOutlined,
FilterOutlined,
SortAscendingOutlined,
EditOutlined,
PlusOutlined,
} from "@ant-design/icons";
const { Content, Sider } = Layout;
type MenuItem = Required<MenuProps>["items"][number];
// 生成伪菜单栏
function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[],
type?: "group"
): MenuItem {
return {
key,
icon,
children,
label,
type,
} as MenuItem;
}
const items: MenuProps["items"] = Array.from({ length: 15 }).map((_, i) =>
getItem(`卡组 ${i}`, i.toString())
);
const theme: ThemeConfig = {
components: {
Menu: {
colorItemBg: "#ffffff00",
colorItemBgSelected: "#ffffff33",
colorItemTextSelected: "#ffffff",
colorActiveBarBorderSize: 0,
fontSize: 12,
fontSizeLG: 12,
},
Layout: {
colorBgBody: "transparent",
},
},
};
export const Component: React.FC = () => {
return (
<ConfigProvider theme={theme}>
<Background />
<Layout className={styles.layout} style={{ width: "100%" }}>
<Sider width={220} className={styles.sider}>
<Menu
className={styles.menu}
defaultSelectedKeys={["1"]}
defaultOpenKeys={["sub1"]}
items={items}
/>
<Button
className={styles["btn-add"]}
icon={<PlusOutlined />}
shape="circle"
type="text"
></Button>
</Sider>
<Content className={styles.content}>
<Deck />
<Select />
</Content>
</Layout>
</ConfigProvider>
);
};
Component.displayName = "Build";
const Deck: React.FC = () => {
return (
<div className={styles.deck}>
<div className={styles.container}>
<Space
className={styles.title}
style={{ justifyContent: "space-between" }}
>
<Input
placeholder="我的卡组"
bordered={false}
prefix={<EditOutlined />}
/>
<Space style={{ marginRight: 6 }}>
<Button type="text" size="small" icon={<DeleteOutlined />}>
清空
</Button>
<Button type="text" size="small" icon={<UndoOutlined />}>
重置
</Button>
<Button type="text" size="small" icon={<CheckOutlined />}>
保存
</Button>
</Space>
</Space>
<div className={styles["deck-zone"]}>
<div className={styles.main}>
<div className={styles["card-continer"]}>
{Array.from({ length: 60 }).map((_, i) => (
<div className={styles.card} key={i} />
))}
</div>
</div>
<div className={styles.extra}>
<div className={styles["card-continer"]}>
{Array.from({ length: 15 }).map((_, i) => (
<div className={styles.card} key={i} />
))}
</div>
</div>
<div className={styles.side}>
<div className={styles["card-continer"]}>
{Array.from({ length: 15 }).map((_, i) => (
<div className={styles.card} key={i} />
))}
</div>
</div>
</div>
</div>
</div>
);
};
const Select: React.FC = () => {
return (
<div className={styles.select}>
<div className={styles.container}>
<div className={styles.title}>
<Input
placeholder="搜索卡片"
bordered={false}
suffix={<Button type="text" icon={<SearchOutlined />} />}
/>
</div>
<div className={styles["select-btns"]}>
<Button block type="text" icon={<FilterOutlined />}>
筛选
</Button>
<Button block type="text" icon={<SortAscendingOutlined />}>
排列
</Button>
<Button block type="text" icon={<DeleteOutlined />}>
重置
</Button>
</div>
<div className={styles["search-cards-container"]}>
<div className={styles["search-cards"]}>
{Array.from({ length: 60 }).map((_, i) => (
<div className={styles.card} key={i} />
))}
</div>
</div>
</div>
</div>
);
};
......@@ -24,7 +24,7 @@
padding: 1rem;
padding-bottom: 0.6rem;
border-radius: 8px;
text-align: left;
// text-align: left;
display: flex;
flex-direction: column;
gap: 8px;
......
......@@ -20,10 +20,10 @@
line-height: var(--nav-height);
transition: 0.3s;
&:hover {
opacity: 0.8;
box-shadow: 0px 2px 0 0 white inset;
}
&:global(.active) {
box-shadow: 0px -2px 0 0 white inset;
box-shadow: 0px 2px 0 0 white inset;
}
}
}
......
......@@ -27,7 +27,7 @@ const _router = createBrowserRouter([
},
{
path: "/build",
lazy: () => import("./Build"),
lazy: () => import("./BuildDeck"),
},
{
path: "/profile",
......
import { Select, Space } from "antd";
import { Select, Space, ConfigProvider } from "antd";
import classNames from "classnames";
import { type LoaderFunction } from "react-router-dom";
......@@ -72,13 +72,24 @@ const CustomSelect: React.FC<
React.ComponentProps<typeof Select> & { title: string }
> = ({ title, className, ...rest }) => {
return (
<div className={styles["custom-select"]}>
<span className={styles.prefix}>{title}</span>
<Select
className={classNames(styles.select, className)}
size="large"
{...rest}
/>
</div>
<ConfigProvider
theme={{
components: {
Select: {
colorBgElevated: "#00132Dff",
controlItemBgActive: "#00286055",
},
},
}}
>
<div className={styles["custom-select"]}>
<span className={styles.prefix}>{title}</span>
<Select
className={classNames(styles.select, className)}
size="large"
{...rest}
/>
</div>
</ConfigProvider>
);
};
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