feat: 화면 관리 및 대시보드 뷰어 레이아웃 전체 너비 활용 개선
- 화면 관리 페이지에서 position.x === 0인 컴포넌트가 100% 너비로 표시되도록 수정 - 대시보드 뷰어에서 부모 컨테이너의 maxWidth 제한 제거하여 화면 전체 너비 활용 - AppLayout의 main 영역에 16px 내부 패딩 적용 - RealtimePreview 및 RealtimePreviewDynamic 컴포넌트에서 좌측 정렬 컴포넌트 너비 자동 조정 - 모바일 환경에서 화면 스케일링 비활성화 (반응형만 작동) - table-mobile-fixed CSS 클래스 추가로 모바일 테이블 레이아웃 개선 - useResponsive 훅 추가로 반응형 감지 기능 구현
This commit is contained in:
@@ -91,8 +91,8 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
||||
key={column.columnName}
|
||||
className={cn(
|
||||
column.columnName === "__checkbox__"
|
||||
? "h-12 border-0 px-6 py-3 text-center align-middle"
|
||||
: "h-12 cursor-pointer border-0 px-6 py-3 text-left align-middle font-semibold whitespace-nowrap text-foreground transition-all duration-200 select-none hover:text-foreground",
|
||||
? "h-10 border-0 px-3 py-2 text-center align-middle sm:h-12 sm:px-6 sm:py-3"
|
||||
: "h-10 cursor-pointer border-0 px-3 py-2 text-left align-middle font-semibold whitespace-nowrap text-xs text-foreground transition-all duration-200 select-none hover:text-foreground sm:h-12 sm:px-6 sm:py-3 sm:text-sm",
|
||||
`text-${column.align}`,
|
||||
column.sortable && "hover:bg-primary/10",
|
||||
// 고정 컬럼 스타일
|
||||
@@ -133,11 +133,11 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
||||
{columnLabels[column.columnName] || column.displayName || column.columnName}
|
||||
</span>
|
||||
{column.sortable && sortColumn === column.columnName && (
|
||||
<span className="ml-2 flex h-5 w-5 items-center justify-center rounded-md bg-background/50 shadow-sm">
|
||||
<span className="ml-1 flex h-4 w-4 items-center justify-center rounded-md bg-background/50 shadow-sm sm:ml-2 sm:h-5 sm:w-5">
|
||||
{sortDirection === "asc" ? (
|
||||
<ArrowUp className="h-3.5 w-3.5 text-primary" />
|
||||
<ArrowUp className="h-2.5 w-2.5 text-primary sm:h-3.5 sm:w-3.5" />
|
||||
) : (
|
||||
<ArrowDown className="h-3.5 w-3.5 text-primary" />
|
||||
<ArrowDown className="h-2.5 w-2.5 text-primary sm:h-3.5 sm:w-3.5" />
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
@@ -177,7 +177,7 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
||||
<TableRow
|
||||
key={`row-${index}`}
|
||||
className={cn(
|
||||
"h-16 cursor-pointer border-b transition-colors bg-background",
|
||||
"h-14 cursor-pointer border-b transition-colors bg-background sm:h-16",
|
||||
tableConfig.tableStyle?.hoverEffect && "hover:bg-muted/50",
|
||||
)}
|
||||
onClick={() => handleRowClick(row)}
|
||||
@@ -201,7 +201,7 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
||||
<TableCell
|
||||
key={`cell-${column.columnName}`}
|
||||
className={cn(
|
||||
"h-16 px-6 py-3 align-middle text-sm whitespace-nowrap text-foreground transition-colors",
|
||||
"h-14 px-3 py-2 align-middle text-xs whitespace-nowrap text-foreground transition-colors sm:h-16 sm:px-6 sm:py-3 sm:text-sm",
|
||||
`text-${column.align}`,
|
||||
// 고정 컬럼 스타일
|
||||
column.fixed === "left" &&
|
||||
|
||||
@@ -772,45 +772,32 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "60px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
position: "relative",
|
||||
borderTop: "2px solid #e5e7eb",
|
||||
backgroundColor: "#ffffff",
|
||||
padding: "0 24px",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
className="w-full h-14 flex items-center justify-center relative border-t-2 border-border bg-background px-4 flex-shrink-0 sm:h-[60px] sm:px-6"
|
||||
>
|
||||
{/* 중앙 페이지네이션 컨트롤 */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "16px",
|
||||
}}
|
||||
className="flex items-center gap-2 sm:gap-4"
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handlePageChange(1)}
|
||||
disabled={currentPage === 1 || loading}
|
||||
className="h-8 w-8 p-0 sm:h-9 sm:w-auto sm:px-3"
|
||||
>
|
||||
<ChevronsLeft className="h-4 w-4" />
|
||||
<ChevronsLeft className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handlePageChange(currentPage - 1)}
|
||||
disabled={currentPage === 1 || loading}
|
||||
className="h-8 w-8 p-0 sm:h-9 sm:w-auto sm:px-3"
|
||||
>
|
||||
<ChevronLeft className="h-4 w-4" />
|
||||
<ChevronLeft className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||
</Button>
|
||||
|
||||
<span className="text-sm font-medium text-foreground min-w-[80px] text-center">
|
||||
<span className="text-xs font-medium text-foreground min-w-[60px] text-center sm:text-sm sm:min-w-[80px]">
|
||||
{currentPage} / {totalPages || 1}
|
||||
</span>
|
||||
|
||||
@@ -819,19 +806,21 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
||||
size="sm"
|
||||
onClick={() => handlePageChange(currentPage + 1)}
|
||||
disabled={currentPage >= totalPages || loading}
|
||||
className="h-8 w-8 p-0 sm:h-9 sm:w-auto sm:px-3"
|
||||
>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
<ChevronRight className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handlePageChange(totalPages)}
|
||||
disabled={currentPage >= totalPages || loading}
|
||||
className="h-8 w-8 p-0 sm:h-9 sm:w-auto sm:px-3"
|
||||
>
|
||||
<ChevronsRight className="h-4 w-4" />
|
||||
<ChevronsRight className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||
</Button>
|
||||
|
||||
<span className="text-xs text-muted-foreground ml-4">
|
||||
<span className="text-[10px] text-muted-foreground ml-2 sm:text-xs sm:ml-4">
|
||||
전체 {totalItems.toLocaleString()}개
|
||||
</span>
|
||||
</div>
|
||||
@@ -842,9 +831,9 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
||||
size="sm"
|
||||
onClick={handleRefresh}
|
||||
disabled={loading}
|
||||
style={{ position: "absolute", right: "24px" }}
|
||||
className="absolute right-2 h-8 w-8 p-0 sm:right-6 sm:h-9 sm:w-auto sm:px-3"
|
||||
>
|
||||
<RefreshCw className={cn("h-4 w-4", loading && "animate-spin")} />
|
||||
<RefreshCw className={cn("h-3 w-3", loading && "animate-spin")} />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
@@ -884,14 +873,14 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
||||
return (
|
||||
<div {...domProps}>
|
||||
{tableConfig.showHeader && (
|
||||
<div className="px-6 py-4 border-b border-border">
|
||||
<h2 className="text-lg font-semibold text-foreground">{tableConfig.title || tableLabel}</h2>
|
||||
<div className="px-4 py-3 border-b border-border sm:px-6 sm:py-4">
|
||||
<h2 className="text-base font-semibold text-foreground sm:text-lg">{tableConfig.title || tableLabel}</h2>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tableConfig.filter?.enabled && (
|
||||
<div className="px-6 py-4 border-b border-border">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="px-4 py-3 border-b border-border sm:px-6 sm:py-4">
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:gap-4">
|
||||
<div className="flex-1">
|
||||
<AdvancedSearchFilters
|
||||
filters={activeFilters}
|
||||
@@ -905,7 +894,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setIsFilterSettingOpen(true)}
|
||||
className="flex-shrink-0 mt-1"
|
||||
className="flex-shrink-0 w-full sm:w-auto sm:mt-1"
|
||||
>
|
||||
<Settings className="mr-2 h-4 w-4" />
|
||||
필터 설정
|
||||
@@ -946,16 +935,16 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
||||
<div {...domProps}>
|
||||
{/* 헤더 */}
|
||||
{tableConfig.showHeader && (
|
||||
<div style={{ padding: "16px 24px", borderBottom: "1px solid #e5e7eb", flexShrink: 0 }}>
|
||||
<h2 style={{ fontSize: "18px", fontWeight: 600, color: "#111827" }}>{tableConfig.title || tableLabel}</h2>
|
||||
<div className="px-4 py-3 border-b border-border flex-shrink-0 sm:px-6 sm:py-4">
|
||||
<h2 className="text-base font-semibold text-foreground sm:text-lg">{tableConfig.title || tableLabel}</h2>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 필터 */}
|
||||
{tableConfig.filter?.enabled && (
|
||||
<div style={{ padding: "16px 24px", borderBottom: "1px solid #e5e7eb", flexShrink: 0 }}>
|
||||
<div style={{ display: "flex", alignItems: "flex-start", gap: "16px" }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div className="px-4 py-3 border-b border-border flex-shrink-0 sm:px-6 sm:py-4">
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:gap-4">
|
||||
<div className="flex-1">
|
||||
<AdvancedSearchFilters
|
||||
filters={activeFilters}
|
||||
searchValues={searchValues}
|
||||
@@ -968,7 +957,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setIsFilterSettingOpen(true)}
|
||||
style={{ flexShrink: 0, marginTop: "4px" }}
|
||||
className="flex-shrink-0 w-full sm:w-auto sm:mt-1"
|
||||
>
|
||||
<Settings className="mr-2 h-4 w-4" />
|
||||
필터 설정
|
||||
@@ -978,33 +967,34 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
||||
)}
|
||||
|
||||
{/* 테이블 컨테이너 */}
|
||||
<div className="flex-1 flex flex-col overflow-hidden">
|
||||
<div className="flex-1 flex flex-col overflow-hidden w-full max-w-full">
|
||||
{/* 스크롤 영역 */}
|
||||
<div
|
||||
className="w-full h-[500px] overflow-y-scroll overflow-x-auto bg-background"
|
||||
className="w-full max-w-full h-[400px] overflow-y-scroll overflow-x-auto bg-background sm:h-[500px]"
|
||||
>
|
||||
{/* 테이블 */}
|
||||
<table
|
||||
className="w-full max-w-full table-mobile-fixed"
|
||||
style={{
|
||||
width: "100%",
|
||||
borderCollapse: "collapse",
|
||||
tableLayout: "auto",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{/* 헤더 (sticky) */}
|
||||
<thead
|
||||
className="sticky top-0 z-10 bg-background"
|
||||
>
|
||||
<tr className="h-12 border-b border-border">
|
||||
<tr className="h-10 border-b border-border sm:h-12">
|
||||
{visibleColumns.map((column) => (
|
||||
<th
|
||||
key={column.columnName}
|
||||
className={cn(
|
||||
"h-12 px-6 py-3 text-sm font-semibold text-foreground whitespace-nowrap bg-background",
|
||||
"h-10 px-2 py-2 text-xs font-semibold text-foreground overflow-hidden text-ellipsis bg-background sm:h-12 sm:px-6 sm:py-3 sm:text-sm sm:whitespace-nowrap",
|
||||
column.sortable && "cursor-pointer"
|
||||
)}
|
||||
style={{
|
||||
textAlign: column.align || "left",
|
||||
width: `${100 / visibleColumns.length}%`, // 컬럼 수에 따라 균등 분배
|
||||
}}
|
||||
onClick={() => column.sortable && handleSort(column.columnName)}
|
||||
>
|
||||
@@ -1063,7 +1053,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
||||
onDragStart={(e) => handleRowDragStart(e, row, index)}
|
||||
onDragEnd={handleRowDragEnd}
|
||||
className={cn(
|
||||
"h-16 border-b transition-colors bg-background hover:bg-muted/50 cursor-pointer"
|
||||
"h-14 border-b transition-colors bg-background hover:bg-muted/50 cursor-pointer sm:h-16"
|
||||
)}
|
||||
onClick={() => handleRowClick(row)}
|
||||
>
|
||||
@@ -1075,10 +1065,11 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
||||
<td
|
||||
key={column.columnName}
|
||||
className={cn(
|
||||
"h-16 px-6 py-3 text-sm text-foreground whitespace-nowrap overflow-hidden text-ellipsis"
|
||||
"h-14 px-2 py-2 text-xs text-foreground overflow-hidden text-ellipsis sm:h-16 sm:px-6 sm:py-3 sm:text-sm sm:whitespace-nowrap"
|
||||
)}
|
||||
style={{
|
||||
textAlign: column.align || "left",
|
||||
width: `${100 / visibleColumns.length}%`, // 컬럼 수에 따라 균등 분배
|
||||
}}
|
||||
>
|
||||
{column.columnName === "__checkbox__"
|
||||
|
||||
Reference in New Issue
Block a user