달력과 투두리스트 합침, 배경색변경가능, 위젯끼리 밀어내는 기능과 세밀한 그리드 추가, 범용위젯 복구

This commit is contained in:
leeheejin
2025-10-17 09:49:02 +09:00
parent 7097775343
commit fa08a26079
13 changed files with 992 additions and 113 deletions

View File

@@ -3,6 +3,7 @@
import React, { useState, useEffect, useCallback } from "react";
import { DashboardElement, QueryResult } from "@/components/admin/dashboard/types";
import { ChartRenderer } from "@/components/admin/dashboard/charts/ChartRenderer";
import { DashboardProvider } from "@/contexts/DashboardContext";
import dynamic from "next/dynamic";
// 위젯 동적 import - 모든 위젯
@@ -231,28 +232,30 @@ export function DashboardViewer({ elements, dashboardId, refreshInterval, backgr
}
return (
<div className="relative h-full w-full overflow-auto" style={{ backgroundColor }}>
{/* 새로고침 상태 표시 */}
<div className="text-muted-foreground absolute top-4 right-4 z-10 rounded-lg bg-white px-3 py-2 text-xs shadow-sm">
: {lastRefresh.toLocaleTimeString()}
{Array.from(loadingElements).length > 0 && (
<span className="text-primary ml-2">({Array.from(loadingElements).length} ...)</span>
)}
</div>
<DashboardProvider>
<div className="relative h-full w-full overflow-auto" style={{ backgroundColor }}>
{/* 새로고침 상태 표시 */}
<div className="text-muted-foreground absolute top-4 right-4 z-10 rounded-lg bg-white px-3 py-2 text-xs shadow-sm">
: {lastRefresh.toLocaleTimeString()}
{Array.from(loadingElements).length > 0 && (
<span className="text-primary ml-2">({Array.from(loadingElements).length} ...)</span>
)}
</div>
{/* 대시보드 요소들 */}
<div className="relative" style={{ minHeight: "100%" }}>
{elements.map((element) => (
<ViewerElement
key={element.id}
element={element}
data={elementData[element.id]}
isLoading={loadingElements.has(element.id)}
onRefresh={() => loadElementData(element)}
/>
))}
{/* 대시보드 요소들 */}
<div className="relative" style={{ minHeight: "100%" }}>
{elements.map((element) => (
<ViewerElement
key={element.id}
element={element}
data={elementData[element.id]}
isLoading={loadingElements.has(element.id)}
onRefresh={() => loadElementData(element)}
/>
))}
</div>
</div>
</div>
</DashboardProvider>
);
}
@@ -286,21 +289,21 @@ function ViewerElement({ element, data, isLoading, onRefresh }: ViewerElementPro
<div className="flex items-center justify-between border-b border-gray-200 bg-gray-50 px-4 py-3">
<h3 className="text-sm font-semibold text-gray-800">{element.customTitle || element.title}</h3>
{/* 새로고침 버튼 (호버 시에만 표시) */}
{isHovered && (
<button
onClick={onRefresh}
disabled={isLoading}
className="hover:text-muted-foreground text-gray-400 disabled:opacity-50"
title="새로고침"
>
{isLoading ? (
<div className="h-4 w-4 animate-spin rounded-full border border-gray-400 border-t-transparent" />
) : (
"🔄"
)}
</button>
)}
{/* 새로고침 버튼 (항상 렌더링하되 opacity로 제어) */}
<button
onClick={onRefresh}
disabled={isLoading}
className={`hover:text-muted-foreground text-gray-400 transition-opacity disabled:opacity-50 ${
isHovered ? "opacity-100" : "opacity-0"
}`}
title="새로고침"
>
{isLoading ? (
<div className="h-4 w-4 animate-spin rounded-full border border-gray-400 border-t-transparent" />
) : (
"🔄"
)}
</button>
</div>
)}