Merge branch 'iipbs/common/main' into iipbs/sn/dev

This commit is contained in:
truthwing
2025-03-11 14:43:13 +09:00
13 changed files with 252 additions and 79 deletions
+3 -1
View File
@@ -5,4 +5,6 @@
node_modules
# misc
.DS_Store
.DS_Store
apps/wr/.next/**/*
apps/fo/.next/**/*
+14 -3
View File
@@ -1,6 +1,6 @@
## business_components 패키지
### 원앤올에서 제공받는 컴포넌트 외에 업무 파트에서 사용할 수 있는 별도 components 패키지지
  1) 설정
  1) 환경설정
    (1) tsconfig.json 'path'에 '@common/business_components' 변수를 추가
```json
@@ -8,7 +8,7 @@
"@/*": ["./*"],
"@common/components/*": ["../../packages/common/components/src/*"],
"@common/components": ["../../packages/common/components/src/index"],
// 작성구문문
//아래에 해당하는 부분을 추가해줘야함.
"@common/business_components/*": ["../../packages/common/business_components/src/*"],
"@common/business_components": ["../../packages/common/business_components/src/index"]
}
@@ -19,4 +19,15 @@
"@common/business_components": "workspace:*",
"next": "15.1.7"
},
```
```
    (3) tailwind.config.ts 추가
``` json
content: [
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"../../packages/common/components/src/ui/**/*.{js,ts,jsx,tsx,mdx}",
//아래에 해당하는 부분을 추가해줘야함.
"../../packages/common/business_components/src/ui/**/*.{js,ts,jsx,tsx,mdx}",
],
```
@@ -28,6 +28,7 @@
"@common/components": "workspace:*",
"@hookform/resolvers": "^4.1.3",
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-scroll-area": "^1.2.3",
"@radix-ui/react-select": "^2.1.6",
"@radix-ui/react-slot": "^1.1.2",
"class-variance-authority": "^0.7.1",
@@ -0,0 +1,7 @@
@tailwind components;
@layer components {
.date-picker-trigger {
@apply h-[3rem] w-[12rem] justify-between border-input !bg-background px-4 py-2 text-left text-[1.3rem] font-normal leading-none text-muted-foreground hover:!bg-accent;
}
}
@@ -0,0 +1,46 @@
"use client";
import "./date-picker.css";
import { format } from "date-fns";
import { CalendarIcon } from "lucide-react";
import type { DayPickerSingleProps } from "react-day-picker";
import { Button, Calendar, Popover, PopoverContent, PopoverTrigger } from "@common/components/ui";
import { cn } from "../../lib/utils";
import { FormControl } from "../form";
type DatePickerProps = DayPickerSingleProps & { field: { value: Date; onChange: (date: Date | undefined) => void } };
export function DatePicker({ field }: DatePickerProps) {
return (
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
variant={"outline"}
className={cn(
"w-[240px] pl-3 text-left font-normal",
!field?.value && "text-muted-foreground"
)}
>
{field?.value ? (
format(field?.value, "PPP")
) : (
<span>Pick a date</span>
)}
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
mode="single"
selected={field?.value}
onSelect={field?.onChange}
initialFocus
/>
</PopoverContent>
</Popover>
);
}
@@ -0,0 +1,19 @@
import React from "react";
import { FormControl, FormItem, FormLabel, FormMessage } from "../form";
const FormUi = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & {label:string|undefined}
>(({children, label},ref)=>{
return (
<FormItem ref={ref}>
{label?<FormLabel className="text-xl">{label}</FormLabel>:<></>}
<FormControl>
{children}
</FormControl>
<FormMessage />
</FormItem>
)
})
FormUi.displayName = 'FormUi';
export { FormUi };
@@ -1,6 +1,12 @@
export * from "./chart";
export * from "./date_picker";
export * from "./file-upload";
export * from "./form";
export * from "./form_ui";
export * from "./scroll";
export * from "./search_form";
export * from "./search_input";
export * from "./search_input_select";
export * from "./select";
export * from "./table";
@@ -0,0 +1,46 @@
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
import * as React from "react"
import { cn } from "../../lib/utils"
const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<ScrollAreaPrimitive.Root
ref={ref}
className={cn("relative overflow-hidden", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
))
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
const ScrollBar = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
>(({ className, orientation = "vertical", ...props }, ref) => (
<ScrollAreaPrimitive.ScrollAreaScrollbar
ref={ref}
orientation={orientation}
className={cn(
"flex touch-none select-none transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
className
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
</ScrollAreaPrimitive.ScrollAreaScrollbar>
))
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
export { ScrollArea, ScrollBar }
@@ -1,21 +1,9 @@
/**
* 검색영역 스타일
*/
const styles = {
divStyle : {
border: '1px solid black',
margin: '1rem',
display: 'flex',
borderRadius: '1rem'
} as React.CSSProperties
}
function SearchDiv ({children}:{ children: React.ReactNode; }) {
return (
<div style={styles.divStyle}>
<div className="flex border border-black m-4 rounded-lg min-h-[80px]">
{children}
</div>
)
}
export { SearchDiv };
export { SearchDiv };
@@ -0,0 +1,16 @@
import { Input, Label } from "@common/components";
import React from "react";
const SearchInput = React.forwardRef<
HTMLDivElement& HTMLInputElement,
React.HTMLAttributes<HTMLDivElement> & {className:string, label:string}>
(({className, label}, ref) => {
console.log(ref);
return (
<div className={className+" flex"} >
{label && <Label className="m-4 text-2xl w-1/4">{label}</Label>}
<Input className="ml-8 w-3/4 text-lg" ref={ref}></Input>
</div>
)
});
export { SearchInput };
@@ -0,0 +1,38 @@
import { Input, Label } from "@common/components";
import React from "react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../select/lib/selectBox";
export type SelectDataType = {
text: string;
val: string;
}
/**
* 검색 입력 및 선택 컴포넌트
* @param className - string tailwindcss class
* @param label - string label
* @param selectData - SelectDataType[] 선택 데이터
* @param onSelectValue - (val:string)=>void 선택 값 콜백
* @param refs - React.forwardRef<HTMLInputElement> | null 입력값 ref
* @returns React.FC
*/
const SearchInputSelect = React.forwardRef<HTMLInputElement, {className:string, label:string, selectData: SelectDataType[], onSelectValue:(val:string)=>void}>(({className, label, selectData, onSelectValue}, refs) => {
return (
<div className={className+" flex items-center"} >
{label && <Label className="m-4 text-2xl w-1/4">{label}</Label>}
<div className="flex w-full items-center">
<Input className="w-2/3 text-lg" ref={refs}/>
<Select onValueChange={onSelectValue}>
<SelectTrigger className="ml-2 w-1/3 text-lg" >
<SelectValue placeholder={selectData?.[0]?.text ?? ""} />
</SelectTrigger>
{/* <SelectContent ref={refs ? (refs as unknown as RefType)?.selectValue : null}> */}
<SelectContent >
{selectData.map((selectArray) => (
<SelectItem key={selectArray.val} value={selectArray.val}>{selectArray.text}</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
)
});
export { SearchInputSelect };
@@ -1,45 +1,35 @@
import { Label } from "@common/components";
import React from "react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./lib/selectBox";
/** 차트 기본 스타일 */
const styles = {
selectBoxDiv : {
marginLeft : '2rem',
display : 'flex'
} as React.CSSProperties,
selectStyle : {
marginLeft: '1rem',
width:'8rem'
} as React.CSSProperties,
labelStyle : {
margin:'0.8rem 0.8rem 0.8rem 0.8rem',
fontSize: '10px',
} as React.CSSProperties
}
interface SelectBox1 {
text:string,
val:string
}
function SelectBox(props: {label : string, selectArray: SelectBox1[]}){
const placeHolder = props.selectArray.length > 0 ? props.selectArray[0].text : "";
const SelectBox = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & {label:string, className:string, selectArray:SelectBox1[], onSelectValue:(val:string)=>void}
>(({ label, className, selectArray, onSelectValue }, ref)=>{
const placeHolder = selectArray?.[0]?.text ?? "";
return (
<div style={styles.selectBoxDiv}>
{props.label && <Label style={styles.labelStyle}>{props.label}</Label>}
<Select style={styles.selectStyle}>
<SelectTrigger style={styles.selectStyle} className="w-[180px]">
<div className={className+" flex items-center"} ref={ref}>
{label && <Label className="m-4 text-2xl w-1/4">{label}</Label>}
<Select onValueChange={onSelectValue}>
<SelectTrigger className="ml-8 w-3/4 text-2xl">
<SelectValue placeholder={placeHolder} />
</SelectTrigger>
<SelectContent>
{props.selectArray.map((selectArray) => (
{selectArray.map((selectArray) => (
<SelectItem key={selectArray.val} value={selectArray.val}>{selectArray.text}</SelectItem>
))}
</SelectContent>
</Select>
</div>
)
}
})
export { SelectBox };
export { SelectBox };
@@ -1,46 +1,49 @@
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components";
import UiPageNations from "./uiPageNations";
interface UiTableProps {
headName: string;
publicReuseFacility: any[];
headlist: { id: string; title: string; }[];
type UiTableProps = {
headName: React.ReactNode | undefined;
tableData: { [key: string]: string | number | boolean }[];
headlist: UiHeadProps[];
pageSize: number;
total: number;
children: React.ReactNode|undefined;
children: React.ReactNode | undefined;
}
export function UiTable(UiTableProps: UiTableProps) {
const { publicReuseFacility, headlist,pageSize , total, children,headName} = UiTableProps;
type UiHeadProps = {
id: string;
title: string;
}
export function UiTable({ tableData, headlist, pageSize, total, children, headName }: UiTableProps) {
const cur = 1;
return (
<>
<p>{headName}</p>
<Table>
<TableHeader>
{children? <>{children}</>:<TableRow>
{headlist.map((head) => (
<TableHead key={head.id}>{head.title}</TableHead>
))}
</TableRow>}
</TableHeader>
<TableBody>
{publicReuseFacility.map((el: any,index) => (
<TableRow key={index+"row"} >
{headlist.map((head) => (
<TableCell key={head.id+index}>{el[head.id]}</TableCell>
))}
</TableRow>
return (
<>
{headName ? headName : <></>}
<Table>
<TableHeader>
{children ? <>{children}</> : <TableRow>
{headlist?.map((head) => (
<TableHead key={head.id}>{head.title}</TableHead>
))}
</TableBody>
</Table>
<UiPageNations total={total} cur={cur} pageSize={pageSize} />
</>
);
}
</TableRow>}
</TableHeader>
<TableBody className='text-center'>
{tableData?.map((el: { [key: string]: string | number | boolean }, index) => (
<TableRow key={index + "row"} >
{headlist.map((head) => (
<TableCell key={head.id + index}>{el[head.id]}</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
{total <= 0 ? <></> : <UiPageNations total={total} cur={cur} pageSize={pageSize} />}
</>
);
}