jskim-node #416

Merged
kjs merged 7 commits from jskim-node into main 2026-03-16 09:29:43 +09:00
11 changed files with 61 additions and 25 deletions
Showing only changes of commit ba39ebf341 - Show all commits

1
.gitignore vendored
View File

@ -153,6 +153,7 @@ backend-node/uploads/
uploads/
*.jpg
*.jpeg
*.png
*.gif
*.pdf
*.doc

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View File

@ -402,18 +402,9 @@ select {
/* 필요시 특정 컴포넌트에 대한 스타일 오버라이드를 여기에 추가 */
/* 예: Calendar, Table 등의 미세 조정 */
/* 모바일에서 테이블 레이아웃 고정 (화면 밖으로 넘어가지 않도록) */
@media (max-width: 639px) {
.table-mobile-fixed {
table-layout: fixed;
}
}
/* 데스크톱에서 테이블 레이아웃 자동 (기본값이지만 명시적으로 설정) */
@media (min-width: 640px) {
.table-mobile-fixed {
table-layout: auto;
}
/* 테이블 레이아웃 고정 (셀 내용이 영역을 벗어나지 않도록) */
.table-mobile-fixed {
table-layout: fixed;
}
/* 그리드선 숨기기 */

View File

@ -583,7 +583,7 @@ const RealtimePreviewDynamicComponent: React.FC<RealtimePreviewProps> = ({
const needsStripBorder = isV2HorizLabel || isButtonComponent;
const safeComponentStyle = needsStripBorder
? (() => {
const { borderWidth, borderColor, borderStyle, border, borderRadius, ...rest } = componentStyle as any;
const { borderWidth, borderColor, borderStyle, border, ...rest } = componentStyle as any;
return rest;
})()
: componentStyle;

View File

@ -2670,7 +2670,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
<td
key={colIdx}
className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
style={{ textAlign: col.align || "left" }}
style={{ textAlign: col.align || "left", overflow: "hidden", textOverflow: "ellipsis" }}
>
{formatCellValue(
col.name,
@ -2732,7 +2732,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
<td
key={colIdx}
className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
style={{ textAlign: col.align || "left" }}
style={{ textAlign: col.align || "left", overflow: "hidden", textOverflow: "ellipsis" }}
>
{formatCellValue(
col.name,
@ -3415,7 +3415,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
<td
key={colIdx}
className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
style={{ textAlign: col.align || "left" }}
style={{ textAlign: col.align || "left", overflow: "hidden", textOverflow: "ellipsis" }}
>
{formatCellValue(
col.name,

View File

@ -379,12 +379,33 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
}
}, [tableConfig.selectedTable, currentUserId]);
// columnVisibility 변경 시 컬럼 순서 및 가시성 적용
// columnVisibility 변경 시 컬럼 순서, 가시성, 너비 적용
useEffect(() => {
if (columnVisibility.length > 0) {
const newOrder = columnVisibility.map((cv) => cv.columnName).filter((name) => name !== "__checkbox__"); // 체크박스 제외
setColumnOrder(newOrder);
// 너비 적용
const newWidths: Record<string, number> = {};
columnVisibility.forEach((cv) => {
if (cv.width) {
newWidths[cv.columnName] = cv.width;
}
});
if (Object.keys(newWidths).length > 0) {
setColumnWidths((prev) => ({ ...prev, ...newWidths }));
// table_column_widths_* localStorage도 동기화 (초기 너비 로드 시 올바른 값 사용)
if (tableConfig.selectedTable && userId) {
const widthsKey = `table_column_widths_${tableConfig.selectedTable}_${userId}`;
try {
const existing = localStorage.getItem(widthsKey);
const merged = existing ? { ...JSON.parse(existing), ...newWidths } : newWidths;
localStorage.setItem(widthsKey, JSON.stringify(merged));
} catch { /* ignore */ }
}
}
// localStorage에 저장 (사용자별)
if (tableConfig.selectedTable && currentUserId) {
const storageKey = `table_column_visibility_${tableConfig.selectedTable}_${currentUserId}`;

View File

@ -570,6 +570,8 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
...restComponentStyle,
width: "100%",
height: "100%",
borderRadius: _br || "0.5rem",
overflow: "hidden",
};
// 디자인 모드 스타일

View File

@ -3607,7 +3607,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
<td
key={colIdx}
className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
style={{ textAlign: col.align || "left" }}
style={{ textAlign: col.align || "left", overflow: "hidden", textOverflow: "ellipsis" }}
>
{formatCellValue(
col.name,
@ -3704,7 +3704,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
<td
key={colIdx}
className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
style={{ textAlign: col.align || "left" }}
style={{ textAlign: col.align || "left", overflow: "hidden", textOverflow: "ellipsis" }}
>
{formatCellValue(
col.name,
@ -4201,7 +4201,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
onClick={() => toggleRightItemExpansion(`tab_${activeTabIndex}_${tabItemId}`)}
>
{tabSummaryColumns.map((col: any) => (
<td key={col.name} className="px-3 py-2 text-xs">
<td key={col.name} className="px-3 py-2 text-xs" style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
{col.type === "progress"
? renderProgressCell(col, item, selectedLeftItem)
: formatCellValue(
@ -4317,7 +4317,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
onClick={() => toggleRightItemExpansion(`tab_${activeTabIndex}_${tabItemId}`)}
>
{listSummaryColumns.map((col: any) => (
<td key={col.name} className="px-3 py-2 text-xs">
<td key={col.name} className="px-3 py-2 text-xs" style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
{col.type === "progress"
? renderProgressCell(col, item, selectedLeftItem)
: formatCellValue(
@ -4709,8 +4709,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
{columnsToShow.map((col, colIdx) => (
<td
key={colIdx}
className="px-3 py-2 text-xs whitespace-nowrap"
style={{ textAlign: col.align || "left" }}
className="px-3 py-2 text-xs"
style={{ textAlign: col.align || "left", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}
>
{col.type === "progress"
? renderProgressCell(col, item, selectedLeftItem)
@ -4856,7 +4856,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
onClick={() => toggleRightItemExpansion(itemId)}
>
{columnsToDisplay.map((col) => (
<td key={col.name} className="px-3 py-2 text-xs">
<td key={col.name} className="px-3 py-2 text-xs" style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
{formatCellValue(
col.name,
getEntityJoinValue(item, col.name),

View File

@ -521,12 +521,33 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
}
}, [tableConfig.selectedTable, currentUserId]);
// columnVisibility 변경 시 컬럼 순서 및 가시성 적용
// columnVisibility 변경 시 컬럼 순서, 가시성, 너비 적용
useEffect(() => {
if (columnVisibility.length > 0) {
const newOrder = columnVisibility.map((cv) => cv.columnName).filter((name) => name !== "__checkbox__"); // 체크박스 제외
setColumnOrder(newOrder);
// 너비 적용
const newWidths: Record<string, number> = {};
columnVisibility.forEach((cv) => {
if (cv.width) {
newWidths[cv.columnName] = cv.width;
}
});
if (Object.keys(newWidths).length > 0) {
setColumnWidths((prev) => ({ ...prev, ...newWidths }));
// table_column_widths_* localStorage도 동기화 (초기 너비 로드 시 올바른 값 사용)
if (tableConfig.selectedTable && userId) {
const widthsKey = `table_column_widths_${tableConfig.selectedTable}_${userId}`;
try {
const existing = localStorage.getItem(widthsKey);
const merged = existing ? { ...JSON.parse(existing), ...newWidths } : newWidths;
localStorage.setItem(widthsKey, JSON.stringify(merged));
} catch { /* ignore */ }
}
}
// localStorage에 저장 (사용자별)
if (tableConfig.selectedTable && currentUserId) {
const storageKey = `table_column_visibility_${tableConfig.selectedTable}_${currentUserId}`;