69 lines
2.0 KiB
TypeScript
69 lines
2.0 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { ComponentData } from "@/types/screen";
|
|
import { componentRegistry, ComponentRenderer } from "../DynamicComponentRenderer";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { TrendingUp, TrendingDown, Minus } from "lucide-react";
|
|
|
|
// 통계 카드 컴포넌트 렌더러
|
|
const StatsCardRenderer: ComponentRenderer = ({ component, ...props }) => {
|
|
const config = component.componentConfig || {};
|
|
const {
|
|
title = "통계 제목",
|
|
value = "1,234",
|
|
change = "+12.5%",
|
|
trend = "up", // up, down, neutral
|
|
description = "전월 대비",
|
|
style = {},
|
|
} = config;
|
|
|
|
const getTrendIcon = () => {
|
|
switch (trend) {
|
|
case "up":
|
|
return <TrendingUp className="h-4 w-4 text-green-600" />;
|
|
case "down":
|
|
return <TrendingDown className="h-4 w-4 text-red-600" />;
|
|
default:
|
|
return <Minus className="h-4 w-4 text-gray-600" />;
|
|
}
|
|
};
|
|
|
|
const getTrendColor = () => {
|
|
switch (trend) {
|
|
case "up":
|
|
return "text-green-600";
|
|
case "down":
|
|
return "text-red-600";
|
|
default:
|
|
return "text-gray-600";
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Card className="h-full w-full" style={style}>
|
|
<CardHeader className="pb-2">
|
|
<CardTitle className="text-sm font-medium text-gray-600">{title}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<div className="text-2xl font-bold">{value}</div>
|
|
<div className={`flex items-center gap-1 text-sm ${getTrendColor()}`}>
|
|
{getTrendIcon()}
|
|
<span>{change}</span>
|
|
<span className="text-gray-500">{description}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
// 레지스트리에 등록
|
|
componentRegistry.register("stats", StatsCardRenderer);
|
|
componentRegistry.register("stats-card", StatsCardRenderer);
|
|
|
|
export { StatsCardRenderer };
|