Merge commit '63cc81cd3ffe7ef5c5bce7c7b8f208b72b3072a9'

This commit is contained in:
2025-02-27 14:39:52 +09:00
8 changed files with 141 additions and 164 deletions
+3 -3
View File
@@ -10,12 +10,12 @@
},
"dependencies": {
"@common/components": "workspace:*",
"@toast-ui/react-grid": "^4.21.22",
"next": "15.1.7",
"tui-grid": "^4.21.22"
"@tanstack/react-table": "^8.21.2",
"next": "15.1.7"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@faker-js/faker": "^9.5.0",
"@types/node": "^22.13.1",
"eslint": "^9",
"eslint-config-next": "15.1.7",
+6
View File
@@ -7,4 +7,10 @@
.card-border {
@apply shadow-blur border border-[#dbe2e6] bg-[rgba(255,255,255,0.6)];
}
.card-header {
@apply -mx-[0.6rem] flex items-center justify-between border-b border-b-[#e1e7eb] p-4;
}
.card-footer {
@apply -mx-[0.6rem] mt-2 flex items-center justify-center border-t border-t-[#e1e7eb] py-4;
}
}
-90
View File
@@ -1,90 +0,0 @@
"use client";
import { createRoot } from "react-dom/client";
import type { AlignType } from "tui-grid/types/store/column";
import type { CellRendererProps } from "tui-grid/types/renderer";
import { Switch } from "@common/components";
class SwitchComponent {
private el: HTMLDivElement;
constructor(props: CellRendererProps) {
this.el = document.createElement("div");
const { value } = props;
createRoot(this.el).render(
<Switch
defaultChecked={value as boolean}
className="!h-[1.8rem] !w-[4.2rem] !bg-[length:2.4rem] !bg-[center_right_.1rem] data-[state=checked]:!bg-[center_left_.2rem] [&>span]:!size-[1.6rem] [&>span]:data-[state=checked]:!translate-x-[2.6rem]"
/>,
);
}
getElement() {
return this.el;
}
}
const data = [
{
id: 1,
siteCode: "WR",
siteName: "물재이용",
siteUrl: "https://www.hasudoon.kr/wr/",
enabled: true,
active: true,
registrant: "홍길동",
createdAt: "2025-01-01",
},
{
id: 2,
siteCode: "SN",
siteName: "하수관로",
siteUrl: "https://www.hasudoon.kr/sn/",
enabled: false,
active: true,
registrant: "홍길동",
createdAt: "2025-01-01",
},
{
id: 3,
siteCode: "CS",
siteName: "통합관리시스템",
siteUrl: "https://www.hasudoon.kr/cs/",
enabled: false,
active: true,
registrant: "홍길동",
createdAt: "2025-01-01",
},
];
const columns = [
{ name: "id", header: "NO", align: "center" as AlignType },
{ name: "siteCode", header: "사이트코드", align: "center" as AlignType },
{ name: "siteName", header: "사이트명", align: "center" as AlignType },
{ name: "siteUrl", header: "대표 URL", align: "center" as AlignType },
{
name: "enabled",
header: "기본 사이트 여부",
align: "center" as AlignType,
renderer: {
type: SwitchComponent,
},
},
{
name: "active",
header: "사용 여부",
align: "center" as AlignType,
renderer: {
type: SwitchComponent,
},
},
{ name: "registrant", header: "등록자", align: "center" as AlignType },
{ name: "createdAt", header: "등록일", align: "center" as AlignType },
];
const header = {
align: "center" as AlignType,
};
export { data, columns, header };
@@ -0,0 +1,59 @@
import { createColumnHelper } from "@tanstack/react-table";
import { fakerKO as faker } from "@faker-js/faker";
type Site = {
id: number;
사이트코드: string;
사이트명: string;
대표_URL: string;
기본_사이트_여부: boolean;
사용_여부: boolean;
등록자: string;
등록일: string;
};
faker.seed(123);
const data: Site[] = Array.from({ length: 100 }, (_, i) => ({
id: i + 1,
사이트코드: faker.string.alpha(2).toUpperCase(),
사이트명: faker.lorem.word(),
대표_URL: faker.internet.url(),
기본_사이트_여부: faker.datatype.boolean(),
사용_여부: faker.datatype.boolean(),
등록자: faker.person.fullName(),
등록일: faker.date.recent().toISOString().split("T")[0] as string,
}));
const columnHelper = createColumnHelper<Site>();
const columns = [
columnHelper.accessor("id", {
header: "NO",
}),
columnHelper.accessor("사이트코드", {
header: "사이트코드",
}),
columnHelper.accessor("사이트명", {
header: "사이트명",
}),
columnHelper.accessor("대표_URL", {
header: "대표_URL",
}),
columnHelper.accessor("기본_사이트_여부", {
header: "기본 사이트 여부",
cell: (info) => (info.getValue() ? "Y" : "N"),
}),
columnHelper.accessor("사용_여부", {
header: "사용 여부",
cell: (info) => (info.getValue() ? "Y" : "N"),
}),
columnHelper.accessor("등록자", {
header: "등록자",
}),
columnHelper.accessor("등록일", {
header: "등록일",
}),
];
export { data, columns };
+12 -38
View File
@@ -2,31 +2,13 @@
import "@common/assets/styles/grid.css";
import TuiGrid from "tui-grid";
import Grid from "@toast-ui/react-grid";
import { BaseLayout, Button, Input } from "@common/components";
import { data, columns, header } from "../model/__mock__";
TuiGrid.applyTheme("clean", {
row: {
hover: {
background: "#f5f5f5",
},
},
cell: {
normal: {
background: "#fff",
border: "#e0e6ea",
text: "#666",
showHorizontalBorder: true,
},
header: {
background: "#c6ccd1",
text: "#fff",
showVerticalBorder: false,
},
},
});
import {
BaseLayout,
Button,
Input,
BasicTable as Table,
} from "@common/components";
import { data, columns } from "../model/__mocks__";
const SitePage = () => {
return (
@@ -35,7 +17,7 @@ const SitePage = () => {
<h2 className="px-[1.8rem] pt-[2rem] text-[2.4rem] font-semibold text-[#4c5e6f]">
사이트 관리
</h2>
<div className="card">
<div className="card card-border">
<div className="card card-border !border-[#dbe2e6] !bg-[#eef7ff]">
<div className="flex items-center gap-2 p-2">
<label htmlFor="" className="mr-2 text-[#657481]">
@@ -46,20 +28,12 @@ const SitePage = () => {
</div>
</div>
<div className="card card-border">
<div className="flex items-center justify-between p-2">
<h3>사이트 목록</h3>
<div className="card-header">
<h3 className="text-2xl font-medium text-[#666]">사이트 목록</h3>
<Button className="">등록</Button>
</div>
<div className="card">
<Grid
data={data}
columns={columns}
header={header}
rowHeight={25}
bodyHeight={100}
heightResizable={true}
usageStatistics={false}
/>
<div className="card !m-[1.2rem] h-[44.5rem] overflow-auto !p-0">
<Table data={data} columns={columns} />
</div>
</div>
</div>
@@ -15,4 +15,5 @@ export * from "./popover";
export * from "./radio-group";
export * from "./slider";
export * from "./switch";
export * from "./table";
export * from "./tabs";
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import "./table.css";
import {
@@ -6,14 +5,45 @@ import {
getCoreRowModel,
useReactTable,
type ColumnDef,
type RowData,
type Table,
} from "@tanstack/react-table";
declare module "@tanstack/react-table" {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface ColumnMeta<TData extends RowData, TValue> {
align: "left" | "center" | "right";
}
}
function TableHead<T>({ table }: { table: Table<T> }) {
return (
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id} className="sticky top-0">
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</th>
))}
</tr>
))}
</thead>
);
}
interface TableProps<T> {
data: T[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
columns: ColumnDef<T, any>[];
}
function Table<T>({ data, columns }: TableProps<T>) {
function BasicTable<T>({ data, columns }: TableProps<T>) {
const table = useReactTable({
data,
columns,
@@ -21,36 +51,23 @@ function Table<T>({ data, columns }: TableProps<T>) {
});
return (
<div className="p-2">
<table>
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{row.getVisibleCells().map((cell) => (
<td key={cell.id}>
<table className="w-full">
<TableHead table={table} />
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{row.getVisibleCells().map((cell) => {
const { meta } = cell.column.columnDef;
return (
<td key={cell.id} align="center" {...meta}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
{/* <tfoot>
);
})}
</tr>
))}
</tbody>
{/* <tfoot>
{table.getFooterGroups().map((footerGroup) => (
<tr key={footerGroup.id}>
{footerGroup.headers.map((header) => (
@@ -66,9 +83,8 @@ function Table<T>({ data, columns }: TableProps<T>) {
</tr>
))}
</tfoot> */}
</table>
</div>
</table>
);
}
export { Table };
export { BasicTable };
+11
View File
@@ -36,6 +36,9 @@ importers:
'@common/components':
specifier: workspace:*
version: link:../../packages/common/components
'@tanstack/react-table':
specifier: ^8.21.2
version: 8.21.2(react-dom@18.3.1)(react@18.3.1)
next:
specifier: 15.1.7
version: 15.1.7(react-dom@18.3.1)(react@18.3.1)
@@ -43,6 +46,9 @@ importers:
'@eslint/eslintrc':
specifier: ^3
version: 3.3.0
'@faker-js/faker':
specifier: ^9.5.0
version: 9.5.0
'@types/node':
specifier: ^22.13.1
version: 22.13.5
@@ -976,6 +982,11 @@ packages:
levn: 0.4.1
dev: true
/@faker-js/faker@9.5.0:
resolution: {integrity: sha512-3qbjLv+fzuuCg3umxc9/7YjrEXNaKwHgmig949nfyaTx8eL4FAsvFbu+1JcFUj1YAXofhaDn6JdEUBTYuk0Ssw==}
engines: {node: '>=18.0.0', npm: '>=9.0.0'}
dev: true
/@feature-sliced/filesystem@2.4.0:
resolution: {integrity: sha512-aOFdPACNvkFXYb+gNHId8UCRD5fm7Z9/RV6JgBPlgEvm1QtLS4idg2XeHMDGnHrNRCS4ki+0RauxVZxm+g9pvw==}
dependencies: