[agent-pipeline] pipe-20260317084014-ydap round-1
This commit is contained in:
parent
9409f1308f
commit
d3acf391a4
|
|
@ -217,10 +217,16 @@ export default function TableManagementPage() {
|
||||||
// 메모이제이션된 입력타입 옵션
|
// 메모이제이션된 입력타입 옵션
|
||||||
const memoizedInputTypeOptions = useMemo(() => inputTypeOptions, []);
|
const memoizedInputTypeOptions = useMemo(() => inputTypeOptions, []);
|
||||||
|
|
||||||
// 참조 테이블 옵션 (실제 테이블 목록에서 가져옴)
|
// 참조 테이블 옵션 (한글라벨 (영어명) 동시 표시)
|
||||||
const referenceTableOptions = [
|
const referenceTableOptions = [
|
||||||
{ value: "none", label: getTextFromUI(TABLE_MANAGEMENT_KEYS.LABEL_NONE, "선택 안함") },
|
{ value: "none", label: getTextFromUI(TABLE_MANAGEMENT_KEYS.LABEL_NONE, "선택 안함") },
|
||||||
...tables.map((table) => ({ value: table.tableName, label: table.displayName || table.tableName })),
|
...tables.map((table) => ({
|
||||||
|
value: table.tableName,
|
||||||
|
label:
|
||||||
|
table.displayName && table.displayName !== table.tableName
|
||||||
|
? `${table.displayName} (${table.tableName})`
|
||||||
|
: table.tableName,
|
||||||
|
})),
|
||||||
];
|
];
|
||||||
|
|
||||||
// 공통 코드 카테고리 목록 상태
|
// 공통 코드 카테고리 목록 상태
|
||||||
|
|
@ -1596,6 +1602,8 @@ export default function TableManagementPage() {
|
||||||
onIndexToggle={(columnName, checked) =>
|
onIndexToggle={(columnName, checked) =>
|
||||||
handleIndexToggle(columnName, "index", checked)
|
handleIndexToggle(columnName, "index", checked)
|
||||||
}
|
}
|
||||||
|
tables={tables}
|
||||||
|
referenceTableColumns={referenceTableColumns}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
@ -1795,11 +1803,16 @@ export default function TableManagementPage() {
|
||||||
<p className="text-sm font-medium">변경될 PK 컬럼:</p>
|
<p className="text-sm font-medium">변경될 PK 컬럼:</p>
|
||||||
{pendingPkColumns.length > 0 ? (
|
{pendingPkColumns.length > 0 ? (
|
||||||
<div className="mt-2 flex flex-wrap gap-2">
|
<div className="mt-2 flex flex-wrap gap-2">
|
||||||
{pendingPkColumns.map((col) => (
|
{pendingPkColumns.map((col) => {
|
||||||
<Badge key={col} variant="secondary" className="font-mono text-xs">
|
const colInfo = columns.find((c) => c.columnName === col);
|
||||||
{col}
|
return (
|
||||||
|
<Badge key={col} variant="secondary" className="text-xs">
|
||||||
|
{colInfo?.displayName && colInfo.displayName !== col
|
||||||
|
? `${colInfo.displayName} (${col})`
|
||||||
|
: col}
|
||||||
</Badge>
|
</Badge>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-destructive mt-2 text-sm">PK가 모두 제거됩니다</p>
|
<p className="text-destructive mt-2 text-sm">PK가 모두 제거됩니다</p>
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,16 @@ export function ColumnDetailPanel({
|
||||||
|
|
||||||
const refTableOpts = referenceTableOptions.length
|
const refTableOpts = referenceTableOptions.length
|
||||||
? referenceTableOptions
|
? referenceTableOptions
|
||||||
: [{ value: "none", label: "선택 안함" }, ...tables.map((t) => ({ value: t.tableName, label: t.displayName || t.tableName }))];
|
: [
|
||||||
|
{ value: "none", label: "선택 안함" },
|
||||||
|
...tables.map((t) => ({
|
||||||
|
value: t.tableName,
|
||||||
|
label:
|
||||||
|
t.displayName && t.displayName !== t.tableName
|
||||||
|
? `${t.displayName} (${t.tableName})`
|
||||||
|
: t.tableName,
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full flex-col border-l bg-card">
|
<div className="flex h-full w-full flex-col border-l bg-card">
|
||||||
|
|
@ -90,7 +99,11 @@ export function ColumnDetailPanel({
|
||||||
{typeConf.label}
|
{typeConf.label}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span className="truncate font-mono text-sm font-medium">{column.columnName}</span>
|
<span className="truncate text-sm font-medium">
|
||||||
|
{column.displayName && column.displayName !== column.columnName
|
||||||
|
? `${column.displayName} (${column.columnName})`
|
||||||
|
: column.columnName}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Button type="button" variant="ghost" size="icon" className="h-8 w-8 shrink-0" onClick={onClose} aria-label="닫기">
|
<Button type="button" variant="ghost" size="icon" className="h-8 w-8 shrink-0" onClick={onClose} aria-label="닫기">
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
|
|
@ -207,7 +220,12 @@ export function ColumnDetailPanel({
|
||||||
className="h-9 w-full justify-between text-xs"
|
className="h-9 w-full justify-between text-xs"
|
||||||
>
|
>
|
||||||
{column.referenceColumn && column.referenceColumn !== "none"
|
{column.referenceColumn && column.referenceColumn !== "none"
|
||||||
? column.referenceColumn
|
? (() => {
|
||||||
|
const matched = refColumns.find((c) => c.columnName === column.referenceColumn);
|
||||||
|
return matched?.displayName && matched.displayName !== column.referenceColumn
|
||||||
|
? `${matched.displayName} (${column.referenceColumn})`
|
||||||
|
: column.referenceColumn;
|
||||||
|
})()
|
||||||
: "컬럼 선택..."}
|
: "컬럼 선택..."}
|
||||||
<ChevronsUpDown className="ml-2 h-3 w-3 opacity-50" />
|
<ChevronsUpDown className="ml-2 h-3 w-3 opacity-50" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -245,7 +263,13 @@ export function ColumnDetailPanel({
|
||||||
column.referenceColumn === refCol.columnName ? "opacity-100" : "opacity-0",
|
column.referenceColumn === refCol.columnName ? "opacity-100" : "opacity-0",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{refCol.columnName}
|
<div className="flex flex-col">
|
||||||
|
<span className="font-medium">
|
||||||
|
{refCol.displayName && refCol.displayName !== refCol.columnName
|
||||||
|
? `${refCol.displayName} (${refCol.columnName})`
|
||||||
|
: refCol.columnName}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</CommandItem>
|
</CommandItem>
|
||||||
))}
|
))}
|
||||||
</CommandGroup>
|
</CommandGroup>
|
||||||
|
|
@ -259,12 +283,20 @@ export function ColumnDetailPanel({
|
||||||
{/* 참조 요약 미니맵 */}
|
{/* 참조 요약 미니맵 */}
|
||||||
{column.referenceTable && column.referenceTable !== "none" && column.referenceColumn && (
|
{column.referenceTable && column.referenceTable !== "none" && column.referenceColumn && (
|
||||||
<div className="flex items-center gap-2 rounded-md bg-violet-50 px-3 py-2">
|
<div className="flex items-center gap-2 rounded-md bg-violet-50 px-3 py-2">
|
||||||
<span className="font-mono text-[11px] font-semibold text-violet-600">
|
<span className="text-[11px] font-semibold text-violet-600">
|
||||||
{column.referenceTable}
|
{(() => {
|
||||||
|
const tbl = refTableOpts.find((o) => o.value === column.referenceTable);
|
||||||
|
return tbl?.label ?? column.referenceTable;
|
||||||
|
})()}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-muted-foreground text-[10px]">→</span>
|
<span className="text-muted-foreground text-[10px]">→</span>
|
||||||
<span className="font-mono text-[11px] font-semibold text-violet-600">
|
<span className="text-[11px] font-semibold text-violet-600">
|
||||||
{column.referenceColumn}
|
{(() => {
|
||||||
|
const col = refColumns.find((c) => c.columnName === column.referenceColumn);
|
||||||
|
return col?.displayName && col.displayName !== column.referenceColumn
|
||||||
|
? `${col.displayName} (${column.referenceColumn})`
|
||||||
|
: column.referenceColumn;
|
||||||
|
})()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@ import { MoreHorizontal, Database, Layers, FileStack } from "lucide-react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import type { ColumnTypeInfo } from "./types";
|
import type { ColumnTypeInfo, TableInfo } from "./types";
|
||||||
import { INPUT_TYPE_COLORS, getColumnGroup } from "./types";
|
import { INPUT_TYPE_COLORS, getColumnGroup } from "./types";
|
||||||
|
import type { ReferenceTableColumn } from "@/lib/api/entityJoin";
|
||||||
|
|
||||||
export interface ColumnGridConstraints {
|
export interface ColumnGridConstraints {
|
||||||
primaryKey: { columns: string[] };
|
primaryKey: { columns: string[] };
|
||||||
|
|
@ -23,6 +24,9 @@ export interface ColumnGridProps {
|
||||||
getColumnIndexState?: (columnName: string) => { isPk: boolean; hasIndex: boolean };
|
getColumnIndexState?: (columnName: string) => { isPk: boolean; hasIndex: boolean };
|
||||||
onPkToggle?: (columnName: string, checked: boolean) => void;
|
onPkToggle?: (columnName: string, checked: boolean) => void;
|
||||||
onIndexToggle?: (columnName: string, checked: boolean) => void;
|
onIndexToggle?: (columnName: string, checked: boolean) => void;
|
||||||
|
/** 호버 시 한글 라벨 표시용 (Badge title) */
|
||||||
|
tables?: TableInfo[];
|
||||||
|
referenceTableColumns?: Record<string, ReferenceTableColumn[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIndexState(
|
function getIndexState(
|
||||||
|
|
@ -53,6 +57,8 @@ export function ColumnGrid({
|
||||||
getColumnIndexState: externalGetIndexState,
|
getColumnIndexState: externalGetIndexState,
|
||||||
onPkToggle,
|
onPkToggle,
|
||||||
onIndexToggle,
|
onIndexToggle,
|
||||||
|
tables,
|
||||||
|
referenceTableColumns,
|
||||||
}: ColumnGridProps) {
|
}: ColumnGridProps) {
|
||||||
const getIdxState = useMemo(
|
const getIdxState = useMemo(
|
||||||
() => externalGetIndexState ?? ((name: string) => getIndexState(name, constraints)),
|
() => externalGetIndexState ?? ((name: string) => getIndexState(name, constraints)),
|
||||||
|
|
@ -136,13 +142,12 @@ export function ColumnGrid({
|
||||||
{/* 4px 색상바 (타입별 진한 색) */}
|
{/* 4px 색상바 (타입별 진한 색) */}
|
||||||
<div className={cn("h-full min-h-8 w-1 rounded-full", typeConf.barColor)} />
|
<div className={cn("h-full min-h-8 w-1 rounded-full", typeConf.barColor)} />
|
||||||
|
|
||||||
{/* 라벨 + 컬럼명 */}
|
{/* 라벨 + 컬럼명 (한글라벨 (영어명) 동시 표시) */}
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="truncate text-sm font-medium">
|
<div className="truncate text-sm font-medium">
|
||||||
{column.displayName || column.columnName}
|
{column.displayName && column.displayName !== column.columnName
|
||||||
</div>
|
? `${column.displayName} (${column.columnName})`
|
||||||
<div className="truncate font-mono text-xs text-muted-foreground">
|
: column.columnName}
|
||||||
{column.columnName}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -150,11 +155,38 @@ export function ColumnGrid({
|
||||||
<div className="flex min-w-0 flex-wrap gap-1">
|
<div className="flex min-w-0 flex-wrap gap-1">
|
||||||
{column.inputType === "entity" && column.referenceTable && column.referenceTable !== "none" && (
|
{column.inputType === "entity" && column.referenceTable && column.referenceTable !== "none" && (
|
||||||
<>
|
<>
|
||||||
<Badge variant="outline" className="text-xs font-normal">
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="text-xs font-normal"
|
||||||
|
title={
|
||||||
|
tables
|
||||||
|
? (() => {
|
||||||
|
const t = tables.find((tb) => tb.tableName === column.referenceTable);
|
||||||
|
return t?.displayName && t.displayName !== t.tableName
|
||||||
|
? `${t.displayName} (${column.referenceTable})`
|
||||||
|
: column.referenceTable;
|
||||||
|
})()
|
||||||
|
: column.referenceTable
|
||||||
|
}
|
||||||
|
>
|
||||||
{column.referenceTable}
|
{column.referenceTable}
|
||||||
</Badge>
|
</Badge>
|
||||||
<span className="text-muted-foreground text-xs">→</span>
|
<span className="text-muted-foreground text-xs">→</span>
|
||||||
<Badge variant="outline" className="text-xs font-normal">
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="text-xs font-normal"
|
||||||
|
title={
|
||||||
|
referenceTableColumns?.[column.referenceTable]
|
||||||
|
? (() => {
|
||||||
|
const refCols = referenceTableColumns[column.referenceTable];
|
||||||
|
const c = refCols.find((rc) => rc.columnName === (column.referenceColumn ?? ""));
|
||||||
|
return c?.displayName && c.displayName !== c.columnName
|
||||||
|
? `${c.displayName} (${column.referenceColumn})`
|
||||||
|
: column.referenceColumn ?? "—";
|
||||||
|
})()
|
||||||
|
: column.referenceColumn ?? "—"
|
||||||
|
}
|
||||||
|
>
|
||||||
{column.referenceColumn || "—"}
|
{column.referenceColumn || "—"}
|
||||||
</Badge>
|
</Badge>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, Suspense, useEffect } from "react";
|
import { useState, Suspense, useEffect, useCallback } from "react";
|
||||||
import { useRouter, usePathname, useSearchParams } from "next/navigation";
|
import { useRouter, usePathname, useSearchParams } from "next/navigation";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
|
|
@ -341,6 +341,10 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
||||||
|
|
||||||
const currentMenus = isAdminMode ? adminMenus : userMenus;
|
const currentMenus = isAdminMode ? adminMenus : userMenus;
|
||||||
|
|
||||||
|
const currentTabs = useTabStore((s) => s[s.mode].tabs);
|
||||||
|
const currentActiveTabId = useTabStore((s) => s[s.mode].activeTabId);
|
||||||
|
const activeTab = currentTabs.find((t) => t.id === currentActiveTabId);
|
||||||
|
|
||||||
const toggleMenu = (menuId: string) => {
|
const toggleMenu = (menuId: string) => {
|
||||||
const newExpanded = new Set(expandedMenus);
|
const newExpanded = new Set(expandedMenus);
|
||||||
if (newExpanded.has(menuId)) {
|
if (newExpanded.has(menuId)) {
|
||||||
|
|
@ -478,6 +482,26 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// pathname + 활성 탭 기반 활성 메뉴 판별 (탭 네비게이션에서도 사이드바 활성 표시)
|
||||||
|
const isMenuActive = useCallback(
|
||||||
|
(menu: any): boolean => {
|
||||||
|
if (pathname === menu.url) return true;
|
||||||
|
if (!activeTab) return false;
|
||||||
|
|
||||||
|
const menuObjid = parseInt((menu.objid || menu.id)?.toString() || "0");
|
||||||
|
|
||||||
|
if (activeTab.type === "admin" && activeTab.adminUrl) {
|
||||||
|
return menu.url === activeTab.adminUrl;
|
||||||
|
}
|
||||||
|
if (activeTab.type === "screen") {
|
||||||
|
if (activeTab.menuObjid != null && menuObjid === activeTab.menuObjid) return true;
|
||||||
|
if (activeTab.screenId != null && menu.screenId === activeTab.screenId) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
[pathname, activeTab],
|
||||||
|
);
|
||||||
|
|
||||||
// 메뉴 트리 렌더링 (기존 MainLayout 스타일 적용)
|
// 메뉴 트리 렌더링 (기존 MainLayout 스타일 적용)
|
||||||
const renderMenu = (menu: any, level: number = 0) => {
|
const renderMenu = (menu: any, level: number = 0) => {
|
||||||
const isExpanded = expandedMenus.has(menu.id);
|
const isExpanded = expandedMenus.has(menu.id);
|
||||||
|
|
@ -489,8 +513,8 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
||||||
draggable={isLeaf}
|
draggable={isLeaf}
|
||||||
onDragStart={(e) => handleMenuDragStart(e, menu)}
|
onDragStart={(e) => handleMenuDragStart(e, menu)}
|
||||||
className={`group flex min-h-[44px] cursor-pointer items-center justify-between rounded-md px-3 py-2 text-sm font-medium transition-colors duration-150 ease-in-out sm:min-h-[40px] ${
|
className={`group flex min-h-[44px] cursor-pointer items-center justify-between rounded-md px-3 py-2 text-sm font-medium transition-colors duration-150 ease-in-out sm:min-h-[40px] ${
|
||||||
pathname === menu.url
|
isMenuActive(menu)
|
||||||
? "border-primary bg-primary/8 text-primary border-l-3 font-semibold"
|
? "border-l-[3px] border-l-primary bg-primary/10 dark:bg-primary/15 text-primary font-semibold"
|
||||||
: isExpanded
|
: isExpanded
|
||||||
? "bg-accent/60 text-foreground"
|
? "bg-accent/60 text-foreground"
|
||||||
: "text-muted-foreground hover:bg-accent hover:text-foreground"
|
: "text-muted-foreground hover:bg-accent hover:text-foreground"
|
||||||
|
|
@ -518,8 +542,8 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
||||||
draggable={!child.hasChildren}
|
draggable={!child.hasChildren}
|
||||||
onDragStart={(e) => handleMenuDragStart(e, child)}
|
onDragStart={(e) => handleMenuDragStart(e, child)}
|
||||||
className={`flex min-h-[44px] cursor-pointer items-center rounded-md px-3 py-2 text-sm transition-colors duration-150 hover:cursor-pointer sm:min-h-[40px] ${
|
className={`flex min-h-[44px] cursor-pointer items-center rounded-md px-3 py-2 text-sm transition-colors duration-150 hover:cursor-pointer sm:min-h-[40px] ${
|
||||||
pathname === child.url
|
isMenuActive(child)
|
||||||
? "border-primary bg-primary/8 text-primary border-l-3 font-semibold"
|
? "border-l-[3px] border-l-primary bg-primary/10 dark:bg-primary/15 text-primary font-semibold"
|
||||||
: "text-muted-foreground hover:bg-accent hover:text-foreground"
|
: "text-muted-foreground hover:bg-accent hover:text-foreground"
|
||||||
}`}
|
}`}
|
||||||
onClick={() => handleMenuClick(child)}
|
onClick={() => handleMenuClick(child)}
|
||||||
|
|
@ -557,6 +581,28 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
||||||
|
|
||||||
const uiMenus = convertMenuToUI(currentMenus, user as ExtendedUserInfo);
|
const uiMenus = convertMenuToUI(currentMenus, user as ExtendedUserInfo);
|
||||||
|
|
||||||
|
// 활성 탭에 해당하는 메뉴가 속한 부모 메뉴 자동 확장
|
||||||
|
useEffect(() => {
|
||||||
|
if (!activeTab || uiMenus.length === 0) return;
|
||||||
|
|
||||||
|
const toExpand: string[] = [];
|
||||||
|
for (const menu of uiMenus) {
|
||||||
|
if (menu.hasChildren && menu.children) {
|
||||||
|
const hasActiveChild = menu.children.some((child: any) => isMenuActive(child));
|
||||||
|
if (hasActiveChild && !expandedMenus.has(menu.id)) {
|
||||||
|
toExpand.push(menu.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toExpand.length > 0) {
|
||||||
|
setExpandedMenus((prev) => {
|
||||||
|
const next = new Set(prev);
|
||||||
|
toExpand.forEach((id) => next.add(id));
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [activeTab, uiMenus, isMenuActive, expandedMenus]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-background flex h-screen flex-col">
|
<div className="bg-background flex h-screen flex-col">
|
||||||
{/* 모바일 헤더 */}
|
{/* 모바일 헤더 */}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { apiClient } from "@/lib/api/client";
|
||||||
import { getCategoryValues } from "@/lib/api/tableCategoryValue";
|
import { getCategoryValues } from "@/lib/api/tableCategoryValue";
|
||||||
import { ChevronRight, FolderTree, Loader2, Search, X } from "lucide-react";
|
import { ChevronRight, FolderTree, Loader2, Search, X } from "lucide-react";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export interface CategoryColumn {
|
export interface CategoryColumn {
|
||||||
tableName: string;
|
tableName: string;
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ function TabsList({
|
||||||
<TabsPrimitive.List
|
<TabsPrimitive.List
|
||||||
data-slot="tabs-list"
|
data-slot="tabs-list"
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-muted/30 text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
|
"bg-muted/50 text-muted-foreground inline-flex h-10 w-fit items-center justify-center rounded-lg border border-border/50 p-1",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -42,7 +42,7 @@ function TabsTrigger({
|
||||||
<TabsPrimitive.Trigger
|
<TabsPrimitive.Trigger
|
||||||
data-slot="tabs-trigger"
|
data-slot="tabs-trigger"
|
||||||
className={cn(
|
className={cn(
|
||||||
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"data-[state=active]:bg-background data-[state=active]:font-semibold dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-foreground/70 inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
||||||
|
|
@ -3981,8 +3981,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
className={cn(
|
className={cn(
|
||||||
"px-3 py-1 text-sm font-medium transition-colors",
|
"px-3 py-1 text-sm font-medium transition-colors",
|
||||||
activeTabIndex === 0
|
activeTabIndex === 0
|
||||||
? "text-foreground border-b-2 border-primary"
|
? "text-primary border-b-2 border-primary font-semibold bg-primary/5"
|
||||||
: "text-muted-foreground hover:text-foreground"
|
: "text-foreground/70 hover:text-foreground hover:bg-muted/30"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{componentConfig.rightPanel?.title || "기본"}
|
{componentConfig.rightPanel?.title || "기본"}
|
||||||
|
|
@ -3994,8 +3994,8 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||||
className={cn(
|
className={cn(
|
||||||
"px-3 py-1 text-sm font-medium transition-colors",
|
"px-3 py-1 text-sm font-medium transition-colors",
|
||||||
activeTabIndex === index + 1
|
activeTabIndex === index + 1
|
||||||
? "text-foreground border-b-2 border-primary"
|
? "text-primary border-b-2 border-primary font-semibold bg-primary/5"
|
||||||
: "text-muted-foreground hover:text-foreground"
|
: "text-foreground/70 hover:text-foreground hover:bg-muted/30"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{tab.label || `탭 ${index + 1}`}
|
{tab.label || `탭 ${index + 1}`}
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,8 @@ const TabsDesignEditor: React.FC<{
|
||||||
return cn(
|
return cn(
|
||||||
"px-4 py-2 text-sm font-medium cursor-pointer transition-colors",
|
"px-4 py-2 text-sm font-medium cursor-pointer transition-colors",
|
||||||
isActive
|
isActive
|
||||||
? "bg-background border-b-2 border-primary text-primary"
|
? "bg-primary/10 border-b-2 border-primary text-primary font-semibold"
|
||||||
: "text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
: "text-foreground/70 hover:text-foreground hover:bg-muted/50"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -283,7 +283,7 @@ const TabsDesignEditor: React.FC<{
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full flex-col overflow-hidden rounded-lg border bg-background">
|
<div className="flex h-full w-full flex-col overflow-hidden rounded-lg border bg-background">
|
||||||
{/* 탭 헤더 */}
|
{/* 탭 헤더 */}
|
||||||
<div className="flex items-center border-b bg-muted/30">
|
<div className="flex items-center border-b bg-muted/50">
|
||||||
{tabs.length > 0 ? (
|
{tabs.length > 0 ? (
|
||||||
tabs.map((tab) => (
|
tabs.map((tab) => (
|
||||||
<div
|
<div
|
||||||
|
|
@ -649,8 +649,8 @@ ComponentRegistry.registerComponent({
|
||||||
return cn(
|
return cn(
|
||||||
"px-4 py-2 text-sm font-medium cursor-pointer transition-colors",
|
"px-4 py-2 text-sm font-medium cursor-pointer transition-colors",
|
||||||
isActive
|
isActive
|
||||||
? "bg-background border-b-2 border-primary text-primary"
|
? "bg-primary/10 border-b-2 border-primary text-primary font-semibold"
|
||||||
: "text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
: "text-foreground/70 hover:text-foreground hover:bg-muted/50"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -662,7 +662,7 @@ ComponentRegistry.registerComponent({
|
||||||
onDragEnd={onDragEnd}
|
onDragEnd={onDragEnd}
|
||||||
>
|
>
|
||||||
{/* 탭 헤더 */}
|
{/* 탭 헤더 */}
|
||||||
<div className="flex items-center border-b bg-muted/30">
|
<div className="flex items-center border-b bg-muted/50">
|
||||||
{tabs.length > 0 ? (
|
{tabs.length > 0 ? (
|
||||||
tabs.map((tab) => (
|
tabs.map((tab) => (
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue