Files
KisStock/components/CommonUI.tsx
2026-02-02 22:20:08 +09:00

128 lines
4.5 KiB
TypeScript

import React from 'react';
// --- StatCard: 대시보드 및 자산 요약용 ---
interface StatCardProps {
title: string;
value: string;
change?: string;
isUp?: boolean;
icon: React.ReactNode;
}
export const StatCard: React.FC<StatCardProps> = ({ title, value, change, isUp, icon }) => (
<div className="bg-white p-4 rounded-2xl shadow-sm border border-slate-100 flex items-center justify-between group hover:border-blue-100 transition-all">
<div className="min-w-0 flex-1">
<p className="text-[10px] font-black text-slate-400 mb-1 uppercase tracking-widest truncate">{title}</p>
<h4 className="text-[18px] font-black text-slate-900 leading-none truncate">{value}</h4>
{change && (
<p className={`text-[10px] font-black mt-2 flex items-center gap-1.5 ${isUp ? 'text-emerald-500' : 'text-rose-500'}`}>
{change}
</p>
)}
</div>
<div className="bg-slate-50 p-3 rounded-xl group-hover:bg-blue-50 transition-colors shrink-0 ml-3">
{React.cloneElement(icon as React.ReactElement, { size: 18 })}
</div>
</div>
);
// --- FilterChip: 시장/정렬/카테고리 필터용 ---
interface FilterChipProps {
active: boolean;
onClick: () => void;
label: string;
}
export const FilterChip: React.FC<FilterChipProps> = ({ active, onClick, label }) => (
<button
onClick={onClick}
className={`px-5 py-2 rounded-full text-[12px] font-black transition-all ${active ? 'bg-slate-900 text-white shadow-lg' : 'bg-slate-100 text-slate-500 hover:bg-slate-200'}`}
>
{label}
</button>
);
// --- TabButton: 대분류 섹션 전환용 ---
interface TabButtonProps {
active: boolean;
onClick: () => void;
icon: React.ReactNode;
label: string;
}
export const TabButton: React.FC<TabButtonProps> = ({ active, onClick, icon, label }) => (
<button
onClick={onClick}
className={`flex items-center gap-3 pb-4 whitespace-nowrap transition-all border-b-2 ${active ? 'border-blue-600 text-blue-600 font-black' : 'border-transparent text-slate-400 font-bold hover:text-slate-600'}`}
>
{icon}
<span className="text-base tracking-tight">{label}</span>
</button>
);
// --- InputGroup: 설정창 및 폼 입력용 ---
interface InputGroupProps {
label: string;
value: string;
onChange: (v: string) => void;
placeholder: string;
type?: string;
icon?: React.ReactNode;
}
export const InputGroup: React.FC<InputGroupProps> = ({ label, value, onChange, placeholder, type = "text", icon }) => (
<div className="space-y-2">
<label className="text-[11px] font-black text-slate-400 uppercase tracking-widest block pl-1 flex items-center gap-2">
{icon} {label}
</label>
<input
type={type}
value={value}
onChange={(e) => onChange(e.target.value)}
className="w-full p-3 bg-slate-50 border border-slate-200 rounded-xl focus:border-blue-500 focus:bg-white outline-none transition-all font-bold text-slate-800 placeholder:text-slate-300 text-[13px] shadow-sm"
placeholder={placeholder}
/>
</div>
);
// --- SelectGroup: 일관된 디자인의 셀렉트 박스 ---
interface SelectGroupProps {
label: string;
value: string;
onChange: (v: string) => void;
options: { value: string, label: string }[];
icon?: React.ReactNode;
}
export const SelectGroup: React.FC<SelectGroupProps> = ({ label, value, onChange, options, icon }) => (
<div className="space-y-2">
<label className="text-[11px] font-black text-slate-400 uppercase tracking-widest block pl-1 flex items-center gap-2">
{icon} {label}
</label>
<select
value={value}
onChange={(e) => onChange(e.target.value)}
className="w-full p-3 bg-slate-50 border border-slate-200 rounded-xl focus:border-blue-500 focus:bg-white outline-none transition-all font-bold text-slate-800 text-[13px] shadow-sm appearance-none"
>
{options.map(opt => <option key={opt.value} value={opt.value}>{opt.label}</option>)}
</select>
</div>
);
// --- ToggleButton: 활성화/비활성 스위치 ---
interface ToggleButtonProps {
active: boolean;
onClick: () => void;
}
export const ToggleButton: React.FC<ToggleButtonProps> = ({ active, onClick }) => (
<button
type="button"
onClick={onClick}
className={`relative inline-flex h-8 w-14 items-center rounded-full transition-all focus:outline-none ${active ? 'bg-emerald-500' : 'bg-slate-300'}`}
>
<span className={`inline-block h-5 w-5 transform rounded-full bg-white transition-transform ${active ? 'translate-x-7' : 'translate-x-2'}`} />
</button>
);