테이블 틀고정기능
This commit is contained in:
@@ -13,7 +13,7 @@ import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { GripVertical, Eye, EyeOff } from "lucide-react";
|
||||
import { GripVertical, Eye, EyeOff, Lock } from "lucide-react";
|
||||
import { ColumnVisibility } from "@/types/table-options";
|
||||
|
||||
interface Props {
|
||||
@@ -30,6 +30,7 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
||||
|
||||
const [localColumns, setLocalColumns] = useState<ColumnVisibility[]>([]);
|
||||
const [draggedIndex, setDraggedIndex] = useState<number | null>(null);
|
||||
const [frozenColumnCount, setFrozenColumnCount] = useState<number>(0);
|
||||
|
||||
// 테이블 정보 로드
|
||||
useEffect(() => {
|
||||
@@ -42,6 +43,8 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
||||
order: 0,
|
||||
}))
|
||||
);
|
||||
// 현재 틀고정 컬럼 수 로드
|
||||
setFrozenColumnCount(table.frozenColumnCount ?? 0);
|
||||
}
|
||||
}, [table]);
|
||||
|
||||
@@ -94,6 +97,11 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
||||
table.onColumnOrderChange(newOrder);
|
||||
}
|
||||
|
||||
// 틀고정 컬럼 수 변경 콜백 호출
|
||||
if (table?.onFrozenColumnCountChange) {
|
||||
table.onFrozenColumnCountChange(frozenColumnCount);
|
||||
}
|
||||
|
||||
onClose();
|
||||
};
|
||||
|
||||
@@ -107,9 +115,18 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
||||
order: 0,
|
||||
}))
|
||||
);
|
||||
setFrozenColumnCount(0);
|
||||
}
|
||||
};
|
||||
|
||||
// 틀고정 컬럼 수 변경 핸들러
|
||||
const handleFrozenColumnCountChange = (value: string) => {
|
||||
const count = parseInt(value) || 0;
|
||||
// 최대값은 표시 가능한 컬럼 수
|
||||
const maxCount = localColumns.filter((col) => col.visible).length;
|
||||
setFrozenColumnCount(Math.min(Math.max(0, count), maxCount));
|
||||
};
|
||||
|
||||
const visibleCount = localColumns.filter((col) => col.visible).length;
|
||||
|
||||
return (
|
||||
@@ -126,11 +143,34 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-3 sm:space-y-4">
|
||||
{/* 상태 표시 */}
|
||||
<div className="flex items-center justify-between rounded-lg border bg-muted/50 p-3">
|
||||
<div className="text-xs text-muted-foreground sm:text-sm">
|
||||
{visibleCount}/{localColumns.length}개 컬럼 표시 중
|
||||
{/* 상태 표시 및 틀고정 설정 */}
|
||||
<div className="flex flex-col gap-3 rounded-lg border bg-muted/50 p-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="text-xs text-muted-foreground sm:text-sm">
|
||||
{visibleCount}/{localColumns.length}개 컬럼 표시 중
|
||||
</div>
|
||||
|
||||
{/* 틀고정 설정 */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Lock className="h-4 w-4 text-muted-foreground" />
|
||||
<Label className="text-xs text-muted-foreground whitespace-nowrap">
|
||||
틀고정:
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={frozenColumnCount}
|
||||
onChange={(e) => handleFrozenColumnCountChange(e.target.value)}
|
||||
className="h-7 w-16 text-xs sm:h-8 sm:w-20 sm:text-sm"
|
||||
min={0}
|
||||
max={visibleCount}
|
||||
placeholder="0"
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground whitespace-nowrap">
|
||||
개 컬럼
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
@@ -148,6 +188,12 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
||||
const columnMeta = table?.columns.find(
|
||||
(c) => c.columnName === col.columnName
|
||||
);
|
||||
// 표시 가능한 컬럼 중 몇 번째인지 계산 (틀고정 표시용)
|
||||
const visibleIndex = localColumns
|
||||
.slice(0, index + 1)
|
||||
.filter((c) => c.visible).length;
|
||||
const isFrozen = col.visible && visibleIndex <= frozenColumnCount;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={col.columnName}
|
||||
@@ -155,7 +201,11 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
||||
onDragStart={() => handleDragStart(index)}
|
||||
onDragOver={(e) => handleDragOver(e, index)}
|
||||
onDragEnd={handleDragEnd}
|
||||
className="flex items-center gap-3 rounded-lg border bg-background p-3 transition-colors hover:bg-muted/50 cursor-move"
|
||||
className={`flex items-center gap-3 rounded-lg border p-3 transition-colors cursor-move ${
|
||||
isFrozen
|
||||
? "bg-blue-50 border-blue-200 dark:bg-blue-950/30 dark:border-blue-800"
|
||||
: "bg-background hover:bg-muted/50"
|
||||
}`}
|
||||
>
|
||||
{/* 드래그 핸들 */}
|
||||
<GripVertical className="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
@@ -171,8 +221,10 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
||||
}
|
||||
/>
|
||||
|
||||
{/* 가시성 아이콘 */}
|
||||
{col.visible ? (
|
||||
{/* 가시성/틀고정 아이콘 */}
|
||||
{isFrozen ? (
|
||||
<Lock className="h-4 w-4 shrink-0 text-blue-500" />
|
||||
) : col.visible ? (
|
||||
<Eye className="h-4 w-4 shrink-0 text-primary" />
|
||||
) : (
|
||||
<EyeOff className="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
@@ -180,8 +232,15 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
||||
|
||||
{/* 컬럼명 */}
|
||||
<div className="flex-1">
|
||||
<div className="text-xs font-medium sm:text-sm">
|
||||
{columnMeta?.columnLabel}
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs font-medium sm:text-sm">
|
||||
{columnMeta?.columnLabel}
|
||||
</span>
|
||||
{isFrozen && (
|
||||
<span className="text-[10px] text-blue-600 dark:text-blue-400 font-medium">
|
||||
(고정)
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-[10px] text-muted-foreground sm:text-xs">
|
||||
{col.columnName}
|
||||
@@ -217,7 +276,7 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
||||
<DialogFooter className="gap-2 sm:gap-0">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => onOpenChange(false)}
|
||||
onClick={onClose}
|
||||
className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
|
||||
>
|
||||
취소
|
||||
|
||||
Reference in New Issue
Block a user