feat: 사이트 상세(수정) 페이지 데이터 바인딩 작업
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
import { RegisterPage as ViewRegisterPage } from "@/pages/site";
|
||||||
|
|
||||||
|
export default async function RegisterPage({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ id: string }>;
|
||||||
|
}) {
|
||||||
|
const { id } = await params;
|
||||||
|
return <ViewRegisterPage siteId={id} />;
|
||||||
|
}
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
import { RegisterPage } from "@/pages/site";
|
|
||||||
export default RegisterPage;
|
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
"@tanstack/react-table": "^8.21.2",
|
"@tanstack/react-table": "^8.21.2",
|
||||||
"axios": "^1.8.1",
|
"axios": "^1.8.1",
|
||||||
"chart.js": "^4.4.8",
|
"chart.js": "^4.4.8",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"next": "15.1.7",
|
"next": "15.1.7",
|
||||||
"react-chartjs-2": "^5.3.0",
|
"react-chartjs-2": "^5.3.0",
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { client } from "@/shared/api/client";
|
||||||
|
import { ENDPOINT } from "@/shared/config/api";
|
||||||
|
import type { CodeService, ICode } from "../model/code-interface";
|
||||||
|
|
||||||
|
export class CodeApiService implements CodeService {
|
||||||
|
public async getCode(upCd: string): Promise<ICode[]> {
|
||||||
|
const response = await client.get<ICode[]>(
|
||||||
|
`${ENDPOINT.CMS_SERVICE.CODE}/${upCd}`,
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CodeApi = new CodeApiService();
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { CodeSelect } from "./ui/code-select";
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export interface ICode {
|
||||||
|
lwpoCd: string;
|
||||||
|
upCd: string;
|
||||||
|
lwpoCdNm: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CodeService {
|
||||||
|
getCode(upCd: string): Promise<ICode[]>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@common/components";
|
||||||
|
import { ENDPOINT } from "@/shared/config/api";
|
||||||
|
import { CodeApi } from "../api/code-service";
|
||||||
|
|
||||||
|
type CodeSelectProps = {
|
||||||
|
upCd: string;
|
||||||
|
value?: string;
|
||||||
|
defaultValue?: string;
|
||||||
|
onValueChange?: (value: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function CodeSelect({ upCd, defaultValue, ...props }: CodeSelectProps) {
|
||||||
|
const { data: code } = useQuery({
|
||||||
|
queryKey: [ENDPOINT.CMS_SERVICE.CODE, upCd],
|
||||||
|
queryFn: () => CodeApi.getCode(upCd),
|
||||||
|
enabled: !!upCd,
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultValueText =
|
||||||
|
code?.find((item) => item.lwpoCd === defaultValue)?.lwpoCdNm ?? "선택";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select {...props}>
|
||||||
|
<SelectTrigger className="w-[12rem] text-[1.3rem] text-label">
|
||||||
|
<SelectValue placeholder={defaultValueText} />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{code?.map((item) => (
|
||||||
|
<SelectItem key={item.lwpoCd} value={item.lwpoCd}>
|
||||||
|
{item.lwpoCdNm}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CodeSelect };
|
||||||
@@ -4,6 +4,7 @@ import type {
|
|||||||
ISiteQuery,
|
ISiteQuery,
|
||||||
ISiteInfo,
|
ISiteInfo,
|
||||||
SiteService,
|
SiteService,
|
||||||
|
ISiteDetail,
|
||||||
} from "../model/site-interface";
|
} from "../model/site-interface";
|
||||||
|
|
||||||
export class SiteApiService implements SiteService {
|
export class SiteApiService implements SiteService {
|
||||||
@@ -12,7 +13,13 @@ export class SiteApiService implements SiteService {
|
|||||||
`${ENDPOINT.CMS_SERVICE.SITES}`,
|
`${ENDPOINT.CMS_SERVICE.SITES}`,
|
||||||
{ params: query },
|
{ params: query },
|
||||||
);
|
);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async siteDetail(siteId: string): Promise<ISiteDetail> {
|
||||||
|
const response = await client.get<ISiteDetail>(
|
||||||
|
`${ENDPOINT.CMS_SERVICE.SITES}/${siteId}`,
|
||||||
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ export interface ISite {
|
|||||||
siteNm: string;
|
siteNm: string;
|
||||||
siteKindCode: string;
|
siteKindCode: string;
|
||||||
bscSiteYn: string;
|
bscSiteYn: string;
|
||||||
|
siteAddr: string;
|
||||||
useYn: string;
|
useYn: string;
|
||||||
|
regDt: string;
|
||||||
|
rgTrNm: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISiteInfo {
|
export interface ISiteInfo {
|
||||||
@@ -44,6 +47,29 @@ export interface ISiteInfo {
|
|||||||
empty: boolean;
|
empty: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ISiteDetail {
|
||||||
|
siteId: string;
|
||||||
|
siteNm: string;
|
||||||
|
siteExpln: string;
|
||||||
|
siteKndCd: string;
|
||||||
|
siteKindNm: string;
|
||||||
|
siteAddr: string;
|
||||||
|
faxNumber: string;
|
||||||
|
telNo: string;
|
||||||
|
lwndCn: string;
|
||||||
|
basicSiteYn: string;
|
||||||
|
bkmkIcon: string;
|
||||||
|
useYn: string;
|
||||||
|
siteSkn: string;
|
||||||
|
regDt: string;
|
||||||
|
rgTr: string;
|
||||||
|
mdfcnDt: string;
|
||||||
|
mdFr: string;
|
||||||
|
rgTrNm: string;
|
||||||
|
mdFrNm: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SiteService {
|
export interface SiteService {
|
||||||
siteInfo(query: ISiteQuery): Promise<ISiteInfo>;
|
siteInfo(query: ISiteQuery): Promise<ISiteInfo>;
|
||||||
|
siteDetail(siteId: string): Promise<ISiteDetail>;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-6
@@ -1,3 +1,4 @@
|
|||||||
|
import dayjs from "dayjs";
|
||||||
import { createColumnHelper } from "@tanstack/react-table";
|
import { createColumnHelper } from "@tanstack/react-table";
|
||||||
import type { ISite } from "@/entities/site/model/site-interface";
|
import type { ISite } from "@/entities/site/model/site-interface";
|
||||||
|
|
||||||
@@ -16,8 +17,8 @@ const columns = [
|
|||||||
id: "siteNm",
|
id: "siteNm",
|
||||||
header: "사이트명",
|
header: "사이트명",
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("siteKindCode", {
|
columnHelper.accessor("siteAddr", {
|
||||||
id: "unknown1",
|
id: "siteAddr",
|
||||||
header: "대표 URL",
|
header: "대표 URL",
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("bscSiteYn", {
|
columnHelper.accessor("bscSiteYn", {
|
||||||
@@ -30,13 +31,17 @@ const columns = [
|
|||||||
header: "사용 여부",
|
header: "사용 여부",
|
||||||
cell: (info) => (info.getValue() ? "Y" : "N"),
|
cell: (info) => (info.getValue() ? "Y" : "N"),
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("siteId", {
|
columnHelper.accessor("rgTrNm", {
|
||||||
id: "unknown2",
|
id: "rgTrNm",
|
||||||
header: "등록자",
|
header: "등록자",
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("siteId", {
|
columnHelper.accessor("regDt", {
|
||||||
id: "ununknown3",
|
id: "regDt",
|
||||||
header: "등록일",
|
header: "등록일",
|
||||||
|
cell: (info) => {
|
||||||
|
const date = dayjs(info.getValue());
|
||||||
|
return date.format("YYYY-MM-DD");
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -26,7 +26,11 @@ type IP = {
|
|||||||
allowed: boolean;
|
allowed: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function IPManagementDialog() {
|
type IPManagementDialogProps = {
|
||||||
|
triggerDisabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
function IPManagementDialog({ triggerDisabled }: IPManagementDialogProps) {
|
||||||
const [rows, setRows] = useState<IP[]>([]);
|
const [rows, setRows] = useState<IP[]>([]);
|
||||||
const [rowSelection, setRowSelection] = useState<IP["id"][]>([]);
|
const [rowSelection, setRowSelection] = useState<IP["id"][]>([]);
|
||||||
|
|
||||||
@@ -72,7 +76,7 @@ function IPManagementDialog() {
|
|||||||
return (
|
return (
|
||||||
<Dialog>
|
<Dialog>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button>IP 관리</Button>
|
<Button disabled={triggerDisabled}>IP 관리</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className="sm:max-w-[600px]">
|
<DialogContent className="sm:max-w-[600px]">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { SiteApi } from "@/entities/site";
|
||||||
|
import { ENDPOINT } from "@/shared/config/api";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
DropdownMenu,
|
|
||||||
DropdownMenuContent,
|
|
||||||
DropdownMenuItem,
|
|
||||||
DropdownMenuTrigger,
|
|
||||||
Input,
|
Input,
|
||||||
Label,
|
Label,
|
||||||
RadioGroup,
|
RadioGroup,
|
||||||
@@ -16,10 +15,24 @@ import {
|
|||||||
TableHead,
|
TableHead,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { CodeSelect } from "@/entities/code";
|
||||||
import { SitePageLayout } from "./layout";
|
import { SitePageLayout } from "./layout";
|
||||||
import { IPManagementDialog } from "./ip-management-dialog";
|
import { IPManagementDialog } from "./ip-management-dialog";
|
||||||
|
|
||||||
function RegisterPage() {
|
function RegisterPage({ siteId }: { siteId: string }) {
|
||||||
|
const { data: siteDetail } = useQuery({
|
||||||
|
queryKey: [ENDPOINT.CMS_SERVICE.SITES, siteId],
|
||||||
|
queryFn: () => SiteApi.siteDetail(siteId),
|
||||||
|
select: (data) => {
|
||||||
|
setSiteKndCd(data.siteKndCd);
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
enabled: !!siteId,
|
||||||
|
});
|
||||||
|
const [siteKndCd, setSiteKndCd] = useState<string>("");
|
||||||
|
const [, setSiteSkinCd] = useState<string>("");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SitePageLayout>
|
<SitePageLayout>
|
||||||
<div className="card card-border !mt-6">
|
<div className="card card-border !mt-6">
|
||||||
@@ -36,54 +49,38 @@ function RegisterPage() {
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>사이트 코드</TableHead>
|
<TableHead>사이트 코드</TableHead>
|
||||||
<TableCell className="border">
|
<TableCell className="border">
|
||||||
<Input className="w-[12rem] !text-[1.3rem]" />
|
<Input
|
||||||
|
className="w-[12rem] !text-[1.3rem]"
|
||||||
|
defaultValue={siteDetail?.siteId}
|
||||||
|
disabled={!!siteId}
|
||||||
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>사이트 구분</TableHead>
|
<TableHead>사이트 구분</TableHead>
|
||||||
<TableCell className="border">
|
<TableCell className="border">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<DropdownMenu>
|
<CodeSelect
|
||||||
<DropdownMenu>
|
upCd="SITEKNDCD"
|
||||||
<DropdownMenuTrigger asChild>
|
defaultValue={siteDetail?.siteKndCd}
|
||||||
<Button
|
onValueChange={(value) => {
|
||||||
color="white"
|
setSiteKndCd(value);
|
||||||
className="group w-[12rem] justify-between px-4"
|
}}
|
||||||
>
|
/>
|
||||||
선택
|
<IPManagementDialog triggerDisabled={siteKndCd === "O"} />
|
||||||
<i className="diveicon di-chevron-down translate-y-0.5 transition-transform group-data-[state=open]:translate-y-0 group-data-[state=open]:rotate-180" />
|
|
||||||
</Button>
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
<DropdownMenuContent className="w-[12rem]">
|
|
||||||
<DropdownMenuItem>내부</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem>외부</DropdownMenuItem>
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
</DropdownMenu>
|
|
||||||
<IPManagementDialog />
|
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>사이트 디자인</TableHead>
|
<TableHead>사이트 디자인</TableHead>
|
||||||
<TableCell className="border">
|
<TableCell className="border">
|
||||||
<DropdownMenu>
|
<CodeSelect
|
||||||
<DropdownMenu>
|
upCd="SITESKINCD"
|
||||||
<DropdownMenuTrigger asChild>
|
defaultValue={siteDetail?.siteSkn}
|
||||||
<Button
|
onValueChange={(value) => {
|
||||||
color="white"
|
setSiteSkinCd(value);
|
||||||
className="group w-[12rem] justify-between px-4"
|
}}
|
||||||
>
|
/>
|
||||||
선택
|
|
||||||
<i className="diveicon di-chevron-down translate-y-0.5 transition-transform group-data-[state=open]:translate-y-0 group-data-[state=open]:rotate-180" />
|
|
||||||
</Button>
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
<DropdownMenuContent className="w-[12rem]">
|
|
||||||
<DropdownMenuItem>라이트</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem>다크</DropdownMenuItem>
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
</DropdownMenu>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
@@ -92,6 +89,7 @@ function RegisterPage() {
|
|||||||
<Input
|
<Input
|
||||||
className="!text-[1.3rem]"
|
className="!text-[1.3rem]"
|
||||||
placeholder="사이트명을 입력하십시오."
|
placeholder="사이트명을 입력하십시오."
|
||||||
|
defaultValue={siteDetail?.siteNm}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -101,6 +99,7 @@ function RegisterPage() {
|
|||||||
<Input
|
<Input
|
||||||
className="!text-[1.3rem]"
|
className="!text-[1.3rem]"
|
||||||
placeholder="사이트 설명을 입력하십시오."
|
placeholder="사이트 설명을 입력하십시오."
|
||||||
|
defaultValue={siteDetail?.siteExpln}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -110,6 +109,7 @@ function RegisterPage() {
|
|||||||
<Input
|
<Input
|
||||||
className="!text-[1.3rem]"
|
className="!text-[1.3rem]"
|
||||||
placeholder="사이트 하단 주소를 입력하십시오."
|
placeholder="사이트 하단 주소를 입력하십시오."
|
||||||
|
defaultValue={siteDetail?.siteAddr}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -119,6 +119,7 @@ function RegisterPage() {
|
|||||||
<Input
|
<Input
|
||||||
className="!text-[1.3rem]"
|
className="!text-[1.3rem]"
|
||||||
placeholder="사이트 하단 전화번호를 입력하십시오."
|
placeholder="사이트 하단 전화번호를 입력하십시오."
|
||||||
|
defaultValue={siteDetail?.telNo}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -128,6 +129,7 @@ function RegisterPage() {
|
|||||||
<Input
|
<Input
|
||||||
className="!text-[1.3rem]"
|
className="!text-[1.3rem]"
|
||||||
placeholder="사이트 하단 팩스번호를 입력하십시오."
|
placeholder="사이트 하단 팩스번호를 입력하십시오."
|
||||||
|
defaultValue={siteDetail?.faxNumber}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -137,6 +139,7 @@ function RegisterPage() {
|
|||||||
<Input
|
<Input
|
||||||
className="!text-[1.3rem]"
|
className="!text-[1.3rem]"
|
||||||
placeholder="사이트 표기 내용을 입력하십시오. (ex. COPYRIGHT c 2013 KECO. ALL RIGHTS RESERVED.)"
|
placeholder="사이트 표기 내용을 입력하십시오. (ex. COPYRIGHT c 2013 KECO. ALL RIGHTS RESERVED.)"
|
||||||
|
defaultValue={siteDetail?.lwndCn}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -146,13 +149,19 @@ function RegisterPage() {
|
|||||||
<Input
|
<Input
|
||||||
className="!text-[1.3rem]"
|
className="!text-[1.3rem]"
|
||||||
placeholder="아이콘 파일 경로 및 파일명을 입력하여 주십시오."
|
placeholder="아이콘 파일 경로 및 파일명을 입력하여 주십시오."
|
||||||
|
defaultValue={siteDetail?.bkmkIcon}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>기본 사이트 여부</TableHead>
|
<TableHead>기본 사이트 여부</TableHead>
|
||||||
<TableCell className="border">
|
<TableCell className="border">
|
||||||
<RadioGroup defaultValue="comfortable">
|
<RadioGroup
|
||||||
|
defaultValue={siteDetail?.basicSiteYn}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
console.log(value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<RadioGroupItem value="default" id="r1" />
|
<RadioGroupItem value="default" id="r1" />
|
||||||
<Label htmlFor="r1">예</Label>
|
<Label htmlFor="r1">예</Label>
|
||||||
@@ -167,7 +176,12 @@ function RegisterPage() {
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>사용 여부</TableHead>
|
<TableHead>사용 여부</TableHead>
|
||||||
<TableCell className="border">
|
<TableCell className="border">
|
||||||
<RadioGroup defaultValue="comfortable">
|
<RadioGroup
|
||||||
|
defaultValue={siteDetail?.useYn}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
console.log(value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<RadioGroupItem value="default" id="r1" />
|
<RadioGroupItem value="default" id="r1" />
|
||||||
<Label htmlFor="r1">사용</Label>
|
<Label htmlFor="r1">사용</Label>
|
||||||
|
|||||||
@@ -8,12 +8,19 @@ import { useQuery } from "@tanstack/react-query";
|
|||||||
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||||
import { Button, Input, DataTable } from "@common/components";
|
import { Button, Input, DataTable } from "@common/components";
|
||||||
import { SiteApi } from "@/entities/site/api/site-service";
|
import { SiteApi } from "@/entities/site/api/site-service";
|
||||||
|
import type { ISite, ISiteQuery } from "@/entities/site/model/site-interface";
|
||||||
import { ENDPOINT } from "@/shared/config/api";
|
import { ENDPOINT } from "@/shared/config/api";
|
||||||
import { columns } from "../model/__mocks__";
|
import { columns } from "../model/table-columns";
|
||||||
import { SitePageLayout } from "./layout";
|
import { SitePageLayout } from "./layout";
|
||||||
import type { ISiteQuery } from "@/entities/site/model/site-interface";
|
|
||||||
|
|
||||||
function SitePage() {
|
function SitePage() {
|
||||||
|
const router = useRouter();
|
||||||
|
const { data: siteInfo, refetch } = useQuery({
|
||||||
|
queryKey: [ENDPOINT.CMS_SERVICE.SITES],
|
||||||
|
queryFn: () => SiteApi.siteInfo(siteQuery),
|
||||||
|
enabled: false,
|
||||||
|
});
|
||||||
|
|
||||||
const [siteQuery, setSiteQuery] = useState<ISiteQuery>({
|
const [siteQuery, setSiteQuery] = useState<ISiteQuery>({
|
||||||
siteNm: "",
|
siteNm: "",
|
||||||
siteKndCd: "",
|
siteKndCd: "",
|
||||||
@@ -23,10 +30,10 @@ function SitePage() {
|
|||||||
sort: [],
|
sort: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: siteInfo, refetch } = useQuery({
|
const table = useReactTable({
|
||||||
queryKey: [ENDPOINT.CMS_SERVICE.SITES],
|
data: siteInfo?.content ?? [],
|
||||||
queryFn: () => SiteApi.siteInfo(siteQuery),
|
columns,
|
||||||
enabled: false,
|
getCoreRowModel: getCoreRowModel(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
@@ -34,15 +41,13 @@ function SitePage() {
|
|||||||
refetch();
|
refetch();
|
||||||
};
|
};
|
||||||
|
|
||||||
const router = useRouter();
|
const handleRowClick = (row: ISite) => {
|
||||||
const table = useReactTable({
|
router.push(`/site/register/${row.siteId}`);
|
||||||
data: siteInfo?.content ?? [],
|
};
|
||||||
columns,
|
|
||||||
getCoreRowModel: getCoreRowModel(),
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refetch();
|
refetch();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -71,7 +76,7 @@ function SitePage() {
|
|||||||
<Button onClick={() => router.push("/site/register")}>등록</Button>
|
<Button onClick={() => router.push("/site/register")}>등록</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="card !m-[1.2rem] h-[49rem] overflow-auto !p-0">
|
<div className="card !m-[1.2rem] h-[49rem] overflow-auto !p-0">
|
||||||
<DataTable table={table} />
|
<DataTable table={table} onRowClick={handleRowClick} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export const ENDPOINT = {
|
|||||||
},
|
},
|
||||||
CMS_SERVICE: {
|
CMS_SERVICE: {
|
||||||
SITES: "/cms-service/api/v1/sites",
|
SITES: "/cms-service/api/v1/sites",
|
||||||
|
CODE: "/cms-service/api/v1/code/cache",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
--border: #e5e5e5;
|
--border: #e5e5e5;
|
||||||
--input: #e5e5e5;
|
--input: #e5e5e5;
|
||||||
--label: #666666;
|
--label: #666666;
|
||||||
|
--placeholder: #a2a2a2;
|
||||||
--ring: #0a0a0a;
|
--ring: #0a0a0a;
|
||||||
--chart-1: #2094fa;
|
--chart-1: #2094fa;
|
||||||
--chart-2: #00dfe5;
|
--chart-2: #00dfe5;
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
--border: #262626;
|
--border: #262626;
|
||||||
--input: #262626;
|
--input: #262626;
|
||||||
--label: #f1f1f1;
|
--label: #f1f1f1;
|
||||||
|
--placeholder: #737373;
|
||||||
--ring: #d4d4d4;
|
--ring: #d4d4d4;
|
||||||
--chart-1: #66b3ff;
|
--chart-1: #66b3ff;
|
||||||
--chart-2: #66f0f2;
|
--chart-2: #66f0f2;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
"@radix-ui/react-label": "^2.1.2",
|
"@radix-ui/react-label": "^2.1.2",
|
||||||
"@radix-ui/react-popover": "^1.1.6",
|
"@radix-ui/react-popover": "^1.1.6",
|
||||||
"@radix-ui/react-radio-group": "^1.2.2",
|
"@radix-ui/react-radio-group": "^1.2.2",
|
||||||
|
"@radix-ui/react-select": "^2.1.6",
|
||||||
"@radix-ui/react-slider": "^1.2.3",
|
"@radix-ui/react-slider": "^1.2.3",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
"@radix-ui/react-switch": "^1.1.3",
|
"@radix-ui/react-switch": "^1.1.3",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const meta: Meta<typeof Bar> = {
|
|||||||
description: {
|
description: {
|
||||||
component: `
|
component: `
|
||||||
- [Docs](https://react-chartjs-2.js.org/)
|
- [Docs](https://react-chartjs-2.js.org/)
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
source: {
|
source: {
|
||||||
code: `
|
code: `
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const meta: Meta<typeof DataTable> = {
|
|||||||
description: {
|
description: {
|
||||||
component: `
|
component: `
|
||||||
- [Docs](https://tanstack.com/table/v8/docs/introduction)
|
- [Docs](https://tanstack.com/table/v8/docs/introduction)
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
source: {
|
source: {
|
||||||
code: `
|
code: `
|
||||||
|
|||||||
@@ -36,15 +36,22 @@ function THead<T>({ table }: { table: TableType<T> }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type TableProps<T> = { table: TableType<T> };
|
type TableProps<T> = {
|
||||||
|
table: TableType<T>;
|
||||||
|
onRowClick?: (row: T) => void;
|
||||||
|
};
|
||||||
|
|
||||||
function DataTable<T>({ table }: TableProps<T>) {
|
function DataTable<T>({ table, onRowClick }: TableProps<T>) {
|
||||||
return (
|
return (
|
||||||
<Table className="w-full">
|
<Table className="w-full">
|
||||||
<THead table={table} />
|
<THead table={table} />
|
||||||
<tbody>
|
<tbody>
|
||||||
{table.getRowModel().rows.map((row) => (
|
{table.getRowModel().rows.map((row) => (
|
||||||
<TableRow key={row.id}>
|
<TableRow
|
||||||
|
key={row.id}
|
||||||
|
onClick={() => onRowClick?.(row.original)}
|
||||||
|
className={onRowClick ? "cursor-pointer hover:bg-muted" : ""}
|
||||||
|
>
|
||||||
{row.getVisibleCells().map((cell) => {
|
{row.getVisibleCells().map((cell) => {
|
||||||
const { meta } = cell.column.columnDef;
|
const { meta } = cell.column.columnDef;
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export * from "./layout";
|
|||||||
export * from "./loading";
|
export * from "./loading";
|
||||||
export * from "./popover";
|
export * from "./popover";
|
||||||
export * from "./radio-group";
|
export * from "./radio-group";
|
||||||
|
export * from "./select";
|
||||||
export * from "./slider";
|
export * from "./slider";
|
||||||
export * from "./switch";
|
export * from "./switch";
|
||||||
export * from "./table";
|
export * from "./table";
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
|||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-[3.2rem] w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
"placeholder:text-placeholder flex h-[3.2rem] w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
} from "chart.js";
|
} from "chart.js";
|
||||||
import { Line } from "react-chartjs-2";
|
import { Line } from "react-chartjs-2";
|
||||||
import { fakerKO as faker } from "@faker-js/faker";
|
import { fakerKO as faker } from "@faker-js/faker";
|
||||||
import { getCssVariableValue } from "../../lib/utils";
|
|
||||||
|
|
||||||
const meta: Meta<typeof Line> = {
|
const meta: Meta<typeof Line> = {
|
||||||
title: "Chart/Line",
|
title: "Chart/Line",
|
||||||
@@ -23,7 +22,7 @@ const meta: Meta<typeof Line> = {
|
|||||||
description: {
|
description: {
|
||||||
component: `
|
component: `
|
||||||
- [Docs](https://react-chartjs-2.js.org/)
|
- [Docs](https://react-chartjs-2.js.org/)
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
source: {
|
source: {
|
||||||
code: `
|
code: `
|
||||||
@@ -107,7 +106,7 @@ export const Default: Story = {
|
|||||||
LineElement,
|
LineElement,
|
||||||
Title,
|
Title,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Legend
|
Legend,
|
||||||
);
|
);
|
||||||
|
|
||||||
const options: ChartOptions<"line"> = {
|
const options: ChartOptions<"line"> = {
|
||||||
@@ -124,29 +123,29 @@ export const Default: Story = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const labels = [
|
const labels = [
|
||||||
'January',
|
"January",
|
||||||
'February',
|
"February",
|
||||||
'March',
|
"March",
|
||||||
'April',
|
"April",
|
||||||
'May',
|
"May",
|
||||||
'June',
|
"June",
|
||||||
'July'
|
"July",
|
||||||
];
|
];
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
labels,
|
labels,
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: 'Dataset 1',
|
label: "Dataset 1",
|
||||||
data: labels.map(() => faker.number.int({ min: -1000, max: 1000 })),
|
data: labels.map(() => faker.number.int({ min: -1000, max: 1000 })),
|
||||||
borderColor: 'rgb(255, 99, 132)',
|
borderColor: "rgb(255, 99, 132)",
|
||||||
backgroundColor: 'rgba(255, 99, 132, 0.5)',
|
backgroundColor: "rgba(255, 99, 132, 0.5)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Dataset 2',
|
label: "Dataset 2",
|
||||||
data: labels.map(() => faker.number.int({ min: -1000, max: 1000 })),
|
data: labels.map(() => faker.number.int({ min: -1000, max: 1000 })),
|
||||||
borderColor: 'rgb(53, 162, 235)',
|
borderColor: "rgb(53, 162, 235)",
|
||||||
backgroundColor: 'rgba(53, 162, 235, 0.5)',
|
backgroundColor: "rgba(53, 162, 235, 0.5)",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,15 +1,7 @@
|
|||||||
import type { Meta, StoryObj } from "@storybook/react";
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
|
|
||||||
import {
|
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
|
||||||
Chart as ChartJS,
|
|
||||||
ArcElement,
|
|
||||||
Tooltip,
|
|
||||||
Legend,
|
|
||||||
type ChartOptions,
|
|
||||||
} from "chart.js";
|
|
||||||
import { Pie } from "react-chartjs-2";
|
import { Pie } from "react-chartjs-2";
|
||||||
import { fakerKO as faker } from "@faker-js/faker";
|
|
||||||
import { getCssVariableValue } from "../../lib/utils";
|
|
||||||
|
|
||||||
const meta: Meta<typeof Pie> = {
|
const meta: Meta<typeof Pie> = {
|
||||||
title: "Chart/Pie",
|
title: "Chart/Pie",
|
||||||
@@ -19,7 +11,7 @@ const meta: Meta<typeof Pie> = {
|
|||||||
description: {
|
description: {
|
||||||
component: `
|
component: `
|
||||||
- [Docs](https://react-chartjs-2.js.org/)
|
- [Docs](https://react-chartjs-2.js.org/)
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
source: {
|
source: {
|
||||||
code: `
|
code: `
|
||||||
@@ -83,42 +75,31 @@ type Story = StoryObj<typeof Pie>;
|
|||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
render: () => {
|
render: () => {
|
||||||
ChartJS.register(
|
ChartJS.register(ArcElement, Tooltip, Legend);
|
||||||
ArcElement,
|
|
||||||
Tooltip,
|
|
||||||
Legend,
|
|
||||||
);
|
|
||||||
|
|
||||||
const labels = [
|
const labels = ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"];
|
||||||
'Red',
|
|
||||||
'Blue',
|
|
||||||
'Yellow',
|
|
||||||
'Green',
|
|
||||||
'Purple',
|
|
||||||
'Orange'
|
|
||||||
];
|
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
labels,
|
labels,
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: '# of Votes',
|
label: "# of Votes",
|
||||||
data: [12, 19, 3, 5, 2, 3],
|
data: [12, 19, 3, 5, 2, 3],
|
||||||
backgroundColor: [
|
backgroundColor: [
|
||||||
'rgba(255, 99, 132, 0.2)',
|
"rgba(255, 99, 132, 0.2)",
|
||||||
'rgba(54, 162, 235, 0.2)',
|
"rgba(54, 162, 235, 0.2)",
|
||||||
'rgba(255, 206, 86, 0.2)',
|
"rgba(255, 206, 86, 0.2)",
|
||||||
'rgba(75, 192, 192, 0.2)',
|
"rgba(75, 192, 192, 0.2)",
|
||||||
'rgba(153, 102, 255, 0.2)',
|
"rgba(153, 102, 255, 0.2)",
|
||||||
'rgba(255, 159, 64, 0.2)',
|
"rgba(255, 159, 64, 0.2)",
|
||||||
],
|
],
|
||||||
borderColor: [
|
borderColor: [
|
||||||
'rgba(255, 99, 132, 1)',
|
"rgba(255, 99, 132, 1)",
|
||||||
'rgba(54, 162, 235, 1)',
|
"rgba(54, 162, 235, 1)",
|
||||||
'rgba(255, 206, 86, 1)',
|
"rgba(255, 206, 86, 1)",
|
||||||
'rgba(75, 192, 192, 1)',
|
"rgba(75, 192, 192, 1)",
|
||||||
'rgba(153, 102, 255, 1)',
|
"rgba(153, 102, 255, 1)",
|
||||||
'rgba(255, 159, 64, 1)',
|
"rgba(255, 159, 64, 1)",
|
||||||
],
|
],
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
||||||
|
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
||||||
|
|
||||||
|
import { cn } from "../../lib/utils";
|
||||||
|
|
||||||
|
const Select = SelectPrimitive.Root;
|
||||||
|
|
||||||
|
const SelectGroup = SelectPrimitive.Group;
|
||||||
|
|
||||||
|
const SelectValue = SelectPrimitive.Value;
|
||||||
|
|
||||||
|
const SelectTrigger = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Trigger
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex h-[3.2rem] w-full items-center justify-between whitespace-nowrap rounded-sm border border-input bg-transparent px-4 py-2 text-sm ring-offset-background focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground [&>span]:line-clamp-1",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<SelectPrimitive.Icon asChild>
|
||||||
|
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||||
|
</SelectPrimitive.Icon>
|
||||||
|
</SelectPrimitive.Trigger>
|
||||||
|
));
|
||||||
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
|
const SelectScrollUpButton = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.ScrollUpButton
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-default items-center justify-center py-1",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChevronUp className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ScrollUpButton>
|
||||||
|
));
|
||||||
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
||||||
|
|
||||||
|
const SelectScrollDownButton = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.ScrollDownButton
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-default items-center justify-center py-1",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChevronDown className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ScrollDownButton>
|
||||||
|
));
|
||||||
|
SelectScrollDownButton.displayName =
|
||||||
|
SelectPrimitive.ScrollDownButton.displayName;
|
||||||
|
|
||||||
|
const SelectContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||||
|
>(({ className, children, position = "popper", ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Portal>
|
||||||
|
<SelectPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
|
position === "popper" &&
|
||||||
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
position={position}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<SelectScrollUpButton />
|
||||||
|
<SelectPrimitive.Viewport
|
||||||
|
className={cn(
|
||||||
|
"p-1",
|
||||||
|
position === "popper" &&
|
||||||
|
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SelectPrimitive.Viewport>
|
||||||
|
<SelectScrollDownButton />
|
||||||
|
</SelectPrimitive.Content>
|
||||||
|
</SelectPrimitive.Portal>
|
||||||
|
));
|
||||||
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
||||||
|
|
||||||
|
const SelectLabel = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Label
|
||||||
|
ref={ref}
|
||||||
|
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
||||||
|
|
||||||
|
const SelectItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative flex w-full cursor-default select-none items-center rounded-sm py-3 pl-4 pr-8 text-[1.2rem] outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<SelectPrimitive.ItemIndicator>
|
||||||
|
<Check className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ItemIndicator>
|
||||||
|
</span>
|
||||||
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||||
|
</SelectPrimitive.Item>
|
||||||
|
));
|
||||||
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
||||||
|
|
||||||
|
const SelectSeparator = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Separator
|
||||||
|
ref={ref}
|
||||||
|
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Select,
|
||||||
|
SelectGroup,
|
||||||
|
SelectValue,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectContent,
|
||||||
|
SelectLabel,
|
||||||
|
SelectItem,
|
||||||
|
SelectSeparator,
|
||||||
|
SelectScrollUpButton,
|
||||||
|
SelectScrollDownButton,
|
||||||
|
};
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from ".";
|
||||||
|
|
||||||
|
const meta: Meta<typeof Select> = {
|
||||||
|
title: "Elements/Select",
|
||||||
|
component: Select,
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
component: `
|
||||||
|
- [Docs](https://ui.shadcn.com/docs/components/select)
|
||||||
|
- [API Reference](https://www.radix-ui.com/primitives/docs/components/select#api-reference)
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof Select>;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
render: () => (
|
||||||
|
<Select>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
<SelectValue placeholder="선택하세요" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="option1">옵션 1</SelectItem>
|
||||||
|
<SelectItem value="option2">옵션 2</SelectItem>
|
||||||
|
<SelectItem value="option3">옵션 3</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
),
|
||||||
|
};
|
||||||
@@ -63,7 +63,7 @@ const TableRow = React.forwardRef<
|
|||||||
<tr
|
<tr
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"hover:bg-muted/50 border-b transition-colors data-[state=selected]:bg-muted",
|
"border-b bg-white transition-colors data-[state=selected]:bg-muted",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ th {
|
|||||||
@apply bg-[#5987bf] px-4 py-[1.2rem] text-[1.3rem] font-medium leading-[1.2] text-[#fff];
|
@apply bg-[#5987bf] px-4 py-[1.2rem] text-[1.3rem] font-medium leading-[1.2] text-[#fff];
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
@apply border-b border-b-[#e0e6ea] bg-[#fff] px-2 py-[1.2rem] text-[1.3rem] font-normal leading-[1.2] text-[#666];
|
@apply border-b border-b-[#e0e6ea] px-2 py-[1.2rem] text-[1.3rem] font-normal leading-[1.2] text-[#666];
|
||||||
}
|
}
|
||||||
|
|
||||||
.secondary th {
|
.secondary th {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const meta: Meta<typeof Tree> = {
|
|||||||
description: {
|
description: {
|
||||||
component: `
|
component: `
|
||||||
- [Docs](https://github.com/minop1205/react-dnd-treeview/blob/next/README.md)
|
- [Docs](https://github.com/minop1205/react-dnd-treeview/blob/next/README.md)
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+70
@@ -54,6 +54,9 @@ importers:
|
|||||||
chart.js:
|
chart.js:
|
||||||
specifier: ^4.4.8
|
specifier: ^4.4.8
|
||||||
version: 4.4.8
|
version: 4.4.8
|
||||||
|
dayjs:
|
||||||
|
specifier: ^1.11.13
|
||||||
|
version: 1.11.13
|
||||||
js-cookie:
|
js-cookie:
|
||||||
specifier: ^3.0.5
|
specifier: ^3.0.5
|
||||||
version: 3.0.5
|
version: 3.0.5
|
||||||
@@ -148,6 +151,9 @@ importers:
|
|||||||
'@radix-ui/react-radio-group':
|
'@radix-ui/react-radio-group':
|
||||||
specifier: ^1.2.2
|
specifier: ^1.2.2
|
||||||
version: 1.2.3(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
version: 1.2.3(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
'@radix-ui/react-select':
|
||||||
|
specifier: ^2.1.6
|
||||||
|
version: 2.1.6(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
||||||
'@radix-ui/react-slider':
|
'@radix-ui/react-slider':
|
||||||
specifier: ^1.2.3
|
specifier: ^1.2.3
|
||||||
version: 1.2.3(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
version: 1.2.3(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
||||||
@@ -2077,6 +2083,46 @@ packages:
|
|||||||
react-dom: 18.3.1(react@18.3.1)
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-select@2.1.6(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1):
|
||||||
|
resolution: {integrity: sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^18.3.18
|
||||||
|
'@types/react-dom': ^18.3.5
|
||||||
|
react: ^18.3.1
|
||||||
|
react-dom: ^18.3.1
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@radix-ui/number': 1.1.0
|
||||||
|
'@radix-ui/primitive': 1.1.1
|
||||||
|
'@radix-ui/react-collection': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
'@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1)
|
||||||
|
'@radix-ui/react-context': 1.1.1(@types/react@18.3.18)(react@18.3.1)
|
||||||
|
'@radix-ui/react-direction': 1.1.0(@types/react@18.3.18)(react@18.3.1)
|
||||||
|
'@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
'@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.18)(react@18.3.1)
|
||||||
|
'@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
'@radix-ui/react-id': 1.1.0(@types/react@18.3.18)(react@18.3.1)
|
||||||
|
'@radix-ui/react-popper': 1.2.2(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
'@radix-ui/react-portal': 1.1.4(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
'@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
'@radix-ui/react-slot': 1.1.2(@types/react@18.3.18)(react@18.3.1)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.18)(react@18.3.1)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.18)(react@18.3.1)
|
||||||
|
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.18)(react@18.3.1)
|
||||||
|
'@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.18)(react@18.3.1)
|
||||||
|
'@radix-ui/react-visually-hidden': 1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
'@types/react': 18.3.18
|
||||||
|
'@types/react-dom': 18.3.5(@types/react@18.3.18)
|
||||||
|
aria-hidden: 1.2.4
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
react-remove-scroll: 2.6.3(@types/react@18.3.18)(react@18.3.1)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-slider@1.2.3(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1):
|
/@radix-ui/react-slider@1.2.3(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1):
|
||||||
resolution: {integrity: sha512-nNrLAWLjGESnhqBqcCNW4w2nn7LxudyMzeB6VgdyAnFLC6kfQgnAjSL2v6UkQTnDctJBlxrmxfplWS4iYjdUTw==}
|
resolution: {integrity: sha512-nNrLAWLjGESnhqBqcCNW4w2nn7LxudyMzeB6VgdyAnFLC6kfQgnAjSL2v6UkQTnDctJBlxrmxfplWS4iYjdUTw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2269,6 +2315,26 @@ packages:
|
|||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-visually-hidden@1.1.2(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1):
|
||||||
|
resolution: {integrity: sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^18.3.18
|
||||||
|
'@types/react-dom': ^18.3.5
|
||||||
|
react: ^18.3.1
|
||||||
|
react-dom: ^18.3.1
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
'@types/react': 18.3.18
|
||||||
|
'@types/react-dom': 18.3.5(@types/react@18.3.18)
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/rect@1.1.0:
|
/@radix-ui/rect@1.1.0:
|
||||||
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
|
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -3984,6 +4050,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
|
resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/dayjs@1.11.13:
|
||||||
|
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/debug@3.2.7:
|
/debug@3.2.7:
|
||||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export default {
|
|||||||
border: "var(--border)",
|
border: "var(--border)",
|
||||||
input: "var(--input)",
|
input: "var(--input)",
|
||||||
label: "var(--label)",
|
label: "var(--label)",
|
||||||
|
placeholder: "var(--placeholder)",
|
||||||
ring: "var(--ring)",
|
ring: "var(--ring)",
|
||||||
chart: {
|
chart: {
|
||||||
1: "var(--chart-1)",
|
1: "var(--chart-1)",
|
||||||
|
|||||||
Reference in New Issue
Block a user