refactor_#2 #13

Merged
Saeed0920 merged 2 commits from refactor_#2 into main 2025-09-18 10:57:56 +03:30
7 changed files with 230 additions and 233 deletions
Showing only changes of commit 380c0f43aa - Show all commits

View File

@ -37,6 +37,7 @@
--color-pr-green : #3AEA83;
--color-pr-blue : #69C8EA;
--color-pr-red : #F76276;
--color-pr-gray : #3F415A;
}
html,

View File

@ -16,7 +16,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
import toast from "react-hot-toast";
import { Badge } from "~/components/ui/badge";
import { Button } from "~/components/ui/button";
import { Card, CardContent } from "~/components/ui/card";
import { BaseCard } from "~/components/ui/base-card";
import { Checkbox } from "~/components/ui/checkbox";
import { CustomBarChart } from "~/components/ui/custom-bar-chart";
import {
@ -36,6 +36,7 @@ import {
import apiService from "~/lib/api";
import { formatNumber } from "~/lib/utils";
import { DashboardLayout } from "../layout";
import { Card , CardContent} from "~/components/ui/card";
moment.loadPersian({ usePersianDigits: true });
interface ProcessInnovationData {
@ -49,6 +50,11 @@ interface ProcessInnovationData {
amount_currency_reduction: string;
Reduce_rate_failure: string;
observer: string;
// optional detailed fields returned by API
project_description?: string;
start_date?: string;
done_date?: string;
approved_budget?: string;
}
interface ProjectStats {
@ -152,7 +158,7 @@ export function ProcessInnovationPage() {
stats.productionStopsPreventionSum
),
description: "تن افزایش یافته",
icon: <CirclePause />,
icon: CirclePause,
color: "text-emerald-400",
},
bottleneckremoval: {
@ -160,7 +166,7 @@ export function ProcessInnovationPage() {
title: "رفع گلوگاه",
value: formatNumber(stats.bottleneckRemovalCount),
description: "تعداد رفع گلوگاه",
icon: <Funnel />,
icon: Funnel,
color: "text-emerald-400",
},
currencyreduction: {
@ -170,7 +176,7 @@ export function ProcessInnovationPage() {
stats.currencyReductionSum.toFixed?.(0) ?? stats.currencyReductionSum
),
description: "دلار کاهش یافته",
icon: <DollarSign />,
icon: DollarSign ,
color: "text-emerald-400",
},
frequentfailuresreduction: {
@ -181,7 +187,7 @@ export function ProcessInnovationPage() {
stats.frequentFailuresReductionSum
),
description: "مجموع درصد کاهش خرابی",
icon: <Wrench />,
icon: Wrench,
color: "text-emerald-400",
},
});
@ -528,7 +534,7 @@ export function ProcessInnovationPage() {
variant="ghost"
size="sm"
onClick={() => handleProjectDetails(item)}
className="text-emerald-400 hover:text-emerald-300 hover:bg-emerald-500/20 p-2 h-auto"
className="text-pr-green hover:text-emerald-300 underline-offset-4 underline font-normal hover:bg-emerald-500/20 p-2 h-auto"
>
جزئیات بیشتر
</Button>
@ -541,18 +547,18 @@ export function ProcessInnovationPage() {
);
case "project_no":
return (
<Badge variant="outline" className="font-mono">
<Badge variant="outline" className="font-normal text-sm">
{String(value)}
</Badge>
);
case "title":
return <span className="font-medium text-white">{String(value)}</span>;
return <span className="font-normal text-sm text-white">{String(value)}</span>;
case "project_status":
return (
<div className="flex items-center gap-1">
<Badge
variant={statusColor(value)}
className="font-medium border-2 p-0 block w-2 h-2 rounded-full"
variant={statusColor(value as projectStatus)}
className="font-normal text-base border-2 p-0 block w-2 h-2 rounded-full"
style={{
border: "none",
}}
@ -562,7 +568,7 @@ export function ProcessInnovationPage() {
);
case "project_rating":
return (
<Badge variant="outline" className="text-lg text-center border-none">
<Badge variant="outline" className="text-base font-semibold text-center border-none">
{formatNumber(String(value))}
</Badge>
);
@ -590,106 +596,96 @@ export function ProcessInnovationPage() {
{loading || statsLoading
? // Loading skeleton for stats cards - matching new design
Array.from({ length: 4 }).map((_, index) => (
<Card
key={`skeleton-${index}`}
className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm rounded-2xl overflow-hidden"
>
<CardContent className="p-2">
<div className="flex flex-col justify-between gap-2">
<div className="flex justify-between items-center border-b-2 mx-4 border-gray-500/20">
<div
className="h-6 bg-gray-600 rounded animate-pulse"
style={{ width: "60%" }}
/>
<div className="p-3 bg-emerald-500/20 rounded-full w-fit">
<div className="w-6 h-6 bg-gray-600 rounded animate-pulse" />
</div>
</div>
<div className="flex items-center justify-center flex-col p-1">
<div
className="h-8 bg-gray-600 rounded mb-1 animate-pulse"
style={{ width: "40%" }}
/>
<div
className="h-4 bg-gray-600 rounded animate-pulse"
style={{ width: "80%" }}
/>
<BaseCard key={`skeleton-${index}`} className="rounded-2xl overflow-hidden">
<div className="flex flex-col justify-between gap-2">
<div className="flex justify-between items-center border-b-2 mx-4 border-gray-500/20">
<div
className="h-6 bg-gray-600 rounded animate-pulse"
style={{ width: "60%" }}
/>
<div className="p-3 bg-emerald-500/20 rounded-full w-fit">
<div className="w-6 h-6 bg-gray-600 rounded animate-pulse" />
</div>
</div>
</CardContent>
</Card>
<div className="flex items-center justify-center flex-col p-1">
<div
className="h-8 bg-gray-600 rounded mb-1 animate-pulse"
style={{ width: "40%" }}
/>
<div
className="h-4 bg-gray-600 rounded animate-pulse"
style={{ width: "80%" }}
/>
</div>
</div>
</BaseCard>
))
: Object.entries(stateCard).map(([key, card]) => (
<Card
key={card.id}
className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm border-gray-700/50"
>
<CardContent className="p-2">
<div className="flex flex-col justify-between gap-2">
<div className="flex justify-between items-center border-b-2 mx-4 border-gray-500/20">
<h3 className="text-lg font-bold text-white font-persian">
{card.title}
</h3>
<div
className={`p-3 gird placeitems-center rounded-full w-fit `}
>
{card.icon}
: Object.entries(stateCard).map(([key, card]) => {
// map percent values for each card key
const percentMap: Record<string, number | string | undefined> = {
productionstopsprevention: stats.percentProductionStops,
bottleneckremoval: stats.percentBottleneckRemoval,
currencyreduction: stats.percentCurrencyReduction,
frequentfailuresreduction: stats.percentFailuresReduction,
};
const percentValue = percentMap[key];
return (
<BaseCard
key={card.id}
title={card.title}
className="border-gray-700/50"
icon={card.icon}
>
<div className="flex items-center justify-center flex-col">
<div className="flex items-center gap-4">
<div className="text-center">
<p className="text-3xl text-pr-green font-bold mb-1">
{(card.value)}
</p>
<div className="text-[11px] text-[#ACACAC] font-light font-persian">
{card.description}
</div>
</div>
</div>
<div className="flex items-center justify-center flex-col p-1">
<p
className={`text-3xl font-bold ${card.color} mb-1`}
>
{card.value}
</p>
<p className="text-sm text-gray-300 font-persian">
{card.description}
</p>
</div>
</div>
</CardContent>
</Card>
))}
</BaseCard>
);
})}
</div>
</div>
{/* Process Impacts Chart */}
<Card className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] backdrop-blur-sm rounded-2xl w-full overflow-hidden">
<CardContent>
<CustomBarChart
title="تاثیرات فرآیندی به صورت درصد مقایسه ای"
loading={statsLoading}
data={[
{
label: "کاهش توقفات تولید",
value: stats.percentProductionStops || 0,
color: "bg-emerald-400",
labelColor: "text-white",
},
{
label: "رفع گلوگاه تولید",
value: stats.percentBottleneckRemoval || 0,
color: "bg-emerald-400",
labelColor: "text-white",
},
{
label: "کاهش ارز بری",
value: stats.percentCurrencyReduction || 0,
color: "bg-emerald-400",
labelColor: "text-white",
},
{
label: "کاهش خرابی پر تکرار",
value: stats.percentFailuresReduction || 0,
color: "bg-emerald-400",
labelColor: "text-white",
},
]}
barHeight="h-5"
showAxisLabels={true}
/>
</CardContent>
</Card>
<BaseCard className="rounded-2xl w-full overflow-hidden">
<CustomBarChart
title="تاثیرات فرآیندی به صورت درصد مقایسه ای"
loading={statsLoading}
data={[
{
label: "کاهش توقفات تولید",
value: Number(stats.percentProductionStops) || 0,
labelColor: "text-white",
},
{
label: "رفع گلوگاه تولید",
value: Number(stats.percentBottleneckRemoval) || 0,
labelColor: "text-white",
},
{
label: "کاهش ارز بری",
value: Number(stats.percentCurrencyReduction) || 0,
labelColor: "text-white",
},
{
label: "کاهش خرابی پر تکرار",
value: Number(stats.percentFailuresReduction) || 0,
labelColor: "text-white",
},
]}
barHeight="h-6"
showAxisLabels={true}
/>
</BaseCard>
</div>
{/* Data Table */}
@ -810,7 +806,7 @@ export function ProcessInnovationPage() {
{/* Footer */}
<div className="p-2 px-4 bg-gray-700/50">
<div className="p-2 px-4 bg-[#3F415A]">
<div className="flex gap-4 text-sm text-gray-300 font-persian justify-between sm:flex-col xl:flex-row">
<div className="text-center gap-2 items-center xl:w-1/3 pr-36 sm:w-full">
<div className="text-base text-gray-401 mb-1">
@ -841,15 +837,15 @@ export function ProcessInnovationPage() {
<Dialog open={detailsDialogOpen} onOpenChange={setDetailsDialogOpen}>
<DialogContent className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] max-w-4xl max-h-[80vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="text-white mr-4 border-b-2 border-gray-600 pb-4 font-persian text-right">
<DialogTitle className="text-white mr-4 border-b-2 border-gray-600 pb-4 font-persian font-semibold text-sm text-right">
شرح پروژه
</DialogTitle>
</DialogHeader>
<div className="space-y-4 flex justify-between text-right px-6">
{/* Project Description */}
<div className="flex-[4] border-l-2 border-gray-600">
<h2 className="font-bold">{selectedProjectDetails?.title}</h2>
<p className="text-gray-300 font-persian px-2 mt-2">
<h2 className="font-bold text-base">{selectedProjectDetails?.title}</h2>
<p className="text-white font-normal text-base font-persian px-2 mt-2">
{selectedProjectDetails?.project_description || "-"}
</p>
</div>
@ -859,11 +855,11 @@ export function ProcessInnovationPage() {
<div className="font-bold text-right ">جزئیات پروژه</div>
<div className="flex items-center justify-between">
<h4 className="font-medium text-gray-300 font-persian mb-2 flex items-center gap-1">
<Building2 className="h-4 text-green-500" />
<h4 className="font-light text-sm text-white font-persian mb-2 flex items-center gap-1">
<Building2 className="h-4 text-green-500 text-sm font-light" />
زمان شروع:
</h4>
<span className="text-white font-bold font-persian">
<span className="text-white font-normal text-base font-persian">
{selectedProjectDetails?.start_date
? moment(
selectedProjectDetails?.start_date,
@ -874,11 +870,11 @@ export function ProcessInnovationPage() {
</div>
<div className="flex items-center justify-between">
<h4 className="font-medium text-gray-300 font-persian mb-2 flex items-center gap-1">
<PickaxeIcon className="h-4 text-green-500" />
<h4 className="font-light text-sm text-white font-persian mb-2 flex items-center gap-1">
<PickaxeIcon className="h-4 text-green-500 text-sm font-light" />
زمان پایان:
</h4>
<span className="text-white font-bold font-persian">
<span className="text-white font-normal text-base font-persian">
{selectedProjectDetails?.done_date
? moment(
selectedProjectDetails?.done_date,
@ -889,27 +885,29 @@ export function ProcessInnovationPage() {
</div>
<div className="flex items-center justify-between">
<h4 className="font-medium text-gray-300 font-persian mb-2 flex items-center gap-1">
<UsersIcon className="h-4 text-green-500" />
<h4 className="font-light text-sm text-white font-persian mb-2 flex items-center gap-1">
<UsersIcon className="h-4 text-green-500 text-sm font-light" />
هزینه برآورد شده:
</h4>
<span className="text-white font-bold font-persian">
{formatNumber(
Number(
selectedProjectDetails?.approved_budget.replaceAll(
",",
""
<span className="text-white font-normal text-base font-persian">
{selectedProjectDetails?.approved_budget
? formatNumber(
Number(
selectedProjectDetails.approved_budget.replaceAll(
",",
""
)
)
)
)
) || "-"}
: "-"}
</span>
</div>
<div className="flex items-center justify-between">
<h4 className="font-medium text-gray-300 font-persian mb-2 flex items-center gap-1">
<UserIcon className="h-4 text-green-500" />
<h4 className="font-light text-sm text-white font-persian mb-2 flex items-center gap-1">
<UserIcon className="h-4 text-green-500 text-sm font-light" />
نفر مرتبط:
</h4>
<span className="text-white font-bold font-persian">
<span className="text-white font-normal text-base font-persian">
{selectedProjectDetails?.observer || "-"}
</span>
</div>

View File

@ -401,21 +401,13 @@ export function InfoPanel({ selectedCompany }: InfoPanelProps) {
<div className="space-y-4">
<Card className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)]">
<CardHeader className="text-center pt-4 pb-3 border-b-2 border-[#3F415A]">
<CardTitle className="font-persian text-xl text-white">
<CardTitle className="font-persian text-base font-semibold text-white">
وضعیت زیستبوم فناوری و نوآوری
</CardTitle>
</CardHeader>
{/* Footer - MOU Count */}
{/* <CardContent className="py-3">
<div className="flex font-bold text-xl px-6 justify-between text-gray-300 font-persian mb-1">
تعداد تفاهم نامه ها
<span className="text-2xl">{formatNumber(counts.mou_count)}</span>
</div>
</CardContent> */}
<CardHeader className="text-center pb-2 border-b-2 border-[#3F415A]">
<CardTitle className="font-persian text-xl text-white flex justify-between px-4">
<CardTitle className="font-persian text-sm text-white flex justify-between px-4">
تعداد تفاهم نامه ها
<span className="font-bold text-3xl">
{formatNumber(counts.mou_count)}
@ -424,7 +416,7 @@ export function InfoPanel({ selectedCompany }: InfoPanelProps) {
</CardHeader>
<CardHeader className="text-center pb-2 border-b-2 border-[#3F415A]">
<CardTitle className="font-persian text-xl text-white flex justify-between px-4">
<CardTitle className="font-persian text-sm text-white flex justify-between px-4">
تعداد بازیگران
<span className="font-bold text-3xl">
{formatNumber(counts.actor_count)}
@ -433,7 +425,7 @@ export function InfoPanel({ selectedCompany }: InfoPanelProps) {
</CardHeader>
{/* Actor Count Display */}
<CardHeader className="text-right text-xl py-2 pb-4 font-bold w-full">
<CardHeader className="text-right pt-4 mt-2 pb-2 text-sm font-semibold w-full">
تنوع بازیگران
</CardHeader>
{/* Middle - Bar Chart */}
@ -454,58 +446,78 @@ export function InfoPanel({ selectedCompany }: InfoPanelProps) {
</CardContent>
{/* Area Chart Section */}
<CardContent className="px-2 pb-4 border-b-2 border-[#3F415A] py-4">
<div className="mb-4">
<CardTitle className="font-persian text-lg text-white mb-2">
<CardContent className="p-2">
<div className="px-4">
<CardTitle className="font-persian text-sm font-semibold text-white mb-2">
روند ایجاد بازیگران در طول سالها
</CardTitle>
</div>
<div className="h-48">
<div className="h-42">
{processData.length > 0 ? (
<ResponsiveContainer width="100%" height="100%">
<AreaChart
data={processData}
margin={{ top: 10, right: 30, left: 0, bottom: 0 }}
>
<CartesianGrid
strokeDasharray="3 3"
stroke="rgba(255,255,255,0.1)"
/>
<XAxis
dataKey="year"
stroke="#9ca3af"
fontSize={12}
tickFormatter={formatPersianYear}
/>
<YAxis
stroke="#9ca3af"
fontSize={12}
tickFormatter={(value) => formatNumber(value)}
/>
<Tooltip
contentStyle={{
backgroundColor: "#374151",
border: "1px solid #6b7280",
borderRadius: "6px",
color: "#f3f4f6",
}}
labelFormatter={(value) =>
`سال ${formatPersianYear(value.toString())}`
}
formatter={(value) => [
formatNumber(value),
"تعداد بازیگران",
]}
/>
<Area
type="monotone"
dataKey="value"
stroke="#34d399"
fill="rgba(52, 211, 153, 0.25)"
strokeWidth={2}
/>
</AreaChart>
</ResponsiveContainer>
<ResponsiveContainer width="100%" height="100%">
<AreaChart
accessibilityLayer
data={processData}
margin={{ top: 25, right: 30, left: 0, bottom: 0 }}
>
<defs>
<linearGradient id="fillDesktop" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#3AEA83" stopOpacity={1} />
<stop offset="100%" stopColor="#3AEA83" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid
vertical={false}
stroke="rgba(255,255,255,0.1)"
/>
<XAxis
dataKey="year"
stroke="#9ca3af"
fontSize={12}
tickLine={false}
tickMargin={8}
axisLine={false}
tickFormatter={formatPersianYear}
/>
<YAxis
stroke="#9ca3af"
fontSize={12}
tickMargin={12}
tickLine={false}
axisLine={false}
tickFormatter={(value) => formatNumber(value)}
/>
<Tooltip cursor={false} content={<></>} />
{/* ✅ Use gradient for fill */}
<Area
type="monotone"
dataKey="value"
stroke="#3AEA83"
fill="url(#fillDesktop)"
strokeWidth={2}
activeDot={({ cx, cy, payload }) => (
<g>
{/* Small circle */}
<circle cx={cx} cy={cy} r={5} fill="#3AEA83" stroke="#fff" strokeWidth={2} />
{/* Year label above point */}
<text
x={cx}
y={cy - 10}
textAnchor="middle"
fontSize={12}
fontWeight="bold"
fill="#3AEA83"
>
{formatPersianYear(payload.year)}
</text>
</g>
)}
/>
</AreaChart>
</ResponsiveContainer>
) : (
<div className="flex items-center justify-center h-full text-gray-400 font-persian">
دادهای برای نمایش وجود ندارد

View File

@ -508,7 +508,7 @@ export function NetworkGraph({ onNodeClick }: NetworkGraphProps) {
// Don't render on server side
if (!isMounted) {
return (
<div className="w-full h-full flex items-center justify-center bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)]">
<div className="w-full h-full flex items-center justify-center bg-transparent">
<div className="text-white font-persian text-sm">
در حال بارگذاری...
</div>
@ -518,7 +518,7 @@ export function NetworkGraph({ onNodeClick }: NetworkGraphProps) {
if (isLoading) {
return (
<div className="w-full h-full relative bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)]">
<div className="w-full h-full relative bg-transparent">
{/* Skeleton Graph Container */}
<div className="w-full h-full flex items-center justify-center relative">
{/* Center Node Skeleton */}
@ -579,7 +579,7 @@ export function NetworkGraph({ onNodeClick }: NetworkGraphProps) {
}
return (
<div className="w-full h-full relative bg-[linear-gradient(to_bottom_left,#464861,10%,#111628)] overflow-hidden">
<div className="w-full h-full relative bg-transparent overflow-hidden">
<svg ref={svgRef} className="w-full h-full" style={{ minHeight: 500 }} />
</div>
);

View File

@ -7,6 +7,7 @@ interface BaseCardProps {
headerClassName?: string;
contentClassName?: string;
children: React.ReactNode;
icon ?: React.ComponentType<{ className?: string }>;
withHeader?: boolean;
}
@ -17,6 +18,7 @@ export function BaseCard({
contentClassName,
children,
withHeader = false,
icon : Icon,
}: BaseCardProps) {
return (
<Card
@ -25,7 +27,12 @@ export function BaseCard({
className
)}
>
{withHeader && title ? (
{Icon && title ? (
<CardHeader className={cn("border-b-2 border-gray-500/20 py-2 px-0 pb-4", headerClassName)}>
<CardTitle className="text-white text-sm text-right font-persian px-4 my-auto items-center flex w-full justify-between">{title} {<Icon />} </CardTitle>
</CardHeader>
) :
withHeader && title ? (
<CardHeader className={cn("pb-2 border-b-2 border-gray-500/20", headerClassName)}>
<CardTitle className="text-white text-sm text-right font-persian px-4">{title}</CardTitle>
</CardHeader>

View File

@ -67,76 +67,56 @@ export function CustomBarChart({
return (
<div className={`space-y-6 ${className}`} style={{ height }}>
<div className="border-b">
{title && (
<h3 className="text-xl font-bold text-white font-persian text-right p-4">
{title && <div className="border-b-[#3F415A] border-b-2">
<h3 className="text-sm font-semibold text-white font-persian text-right p-4">
{title}
</h3>
)}
</div>
</div>}
<div className="space-y-4 px-4 pb-4">
{data.map((item, index) => {
const percentage =
globalMaxValue > 0 ? (item.value / globalMaxValue) * 100 : 0;
const displayValue: any = item.value;
return (
<div key={index} className="flex items-center gap-3">
{/* Label */}
<span
className={`font-persian text-sm min-w-[160px] text-right ${
className={`font-persian text-sm font-normal min-w-[120px] text-right ${
item.labelColor || "text-white"
}`}
>
{item.label}
</span>
{/* Bar Container */}
<div
className={`flex-1 flex items-center bg-gray-700 rounded-full relative overflow-hidden ${barHeight}`}
className={`${showAxisLabels && "bg-pr-gray"} flex-1 flex items-center gap-1 justify-start rounded-full overflow-hidden ${barHeight}`}
>
<div
className={`${barHeight} rounded-full transition-all duration-700 ease-out relative ${
item.color || "bg-emerald-400"
className={`${barHeight} rounded-full transition-all duration-700 ease-out ${
item.color || "bg-pr-green"
}`}
style={{
width: `${Math.min(percentage, 100)}%`,
}}
>
{/* Add a subtle gradient effect for better visual appeal */}
<div className="absolute inset-0 bg-gradient-to-r from-transparent to-white/10 rounded-full"></div>
<div className="inset-0 bg-gradient-to-r from-transparent to-white/10 rounded-full"></div>
</div>
</div>
{/* Value Label */}
<span
className={`font-bold text-sm min-w-[60px] text-left ${
item.color?.includes("emerald")
? "text-emerald-400"
: item.color?.includes("blue")
? "text-blue-400"
: item.color?.includes("purple")
? "text-purple-400"
: item.color?.includes("red")
? "text-red-400"
: item.color?.includes("yellow")
? "text-yellow-400"
: "text-emerald-400"
}`}
className={`text-base font-normal text-left text-white`}
>
{item.valuePrefix || ""}
{formatNumber(parseFloat(displayValue))}%
{formatNumber(parseFloat(displayValue))}
{item.valueSuffix || ""}
</span>
</div>
</div>
);
})}
{/* Axis Labels */}
{showAxisLabels && globalMaxValue > 0 && (
<div className="flex items-center gap-3 mt-6">
<span className="min-w-[160px]"></span>
<div className="flex w-full items-center gap-3 mt-6">
<span className="min-w-[120px]"></span>
<div className="flex-1 flex justify-between pt-2 border-t border-gray-700">
<span className="text-gray-400 text-xs">{formatNumber(0)}</span>
<span className="text-gray-400 text-xs">
@ -152,7 +132,7 @@ export function CustomBarChart({
{formatNumber(Math.round(globalMaxValue))}
</span>
</div>
<span className="min-w-[60px]"></span>
<span className="min-w-[0px]"></span>
</div>
)}
</div>

View File

@ -76,8 +76,8 @@ export default function EcosystemPage() {
</div>
<div className="lg:col-span-8 h-full">
<Card className="h-full overflow-hidden">
<CardContent className="p-0 h-full">
<Card className="h-full overflow-hidden bg-transparent border-[#3F415A]">
<CardContent className="p-0 h-full bg-transparent">
<NetworkGraph onNodeClick={setSelectedCompany} />
</CardContent>
</Card>
@ -92,11 +92,10 @@ export default function EcosystemPage() {
>
<DialogContent className="font-persian max-w-6xl max-h-[75vh] overflow-y-auto bg-[linear-gradient(to_bottom_left,#464861,20%,#111628)]">
<DialogHeader>
<DialogTitle className="text-right border-b-2 border-gray-600 py-2 mr-4 text-xl">
<DialogTitle className="text-right border-b-2 border-gray-600 pt-2 pb-4 mr-4 text-sm font-semibold">
معرفی
<span> {selectedCompany?.category}</span>
</DialogTitle>
<DialogDescription className="text-center text-green-400"></DialogDescription>
</DialogHeader>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
@ -109,7 +108,7 @@ export default function EcosystemPage() {
<img
src={getImageUrl(selectedCompany.stageid)}
alt={selectedCompany?.label || ""}
className="w-14 h-14 object-cover rounded-2xl"
className="w-12 h-12 object-cover rounded-2xl"
onError={(e) => {
// Hide image and show fallback on error
e.currentTarget.style.display = "none";
@ -147,7 +146,7 @@ export default function EcosystemPage() {
</div>
{selectedCompany?.description ? (
<div className="p-4 rounded-lg">
<p className="font-persian leading-relaxed">
<p className="font-persian text-sm font-normal leading-relaxed">
{selectedCompany.description}
</p>
</div>
@ -159,22 +158,22 @@ export default function EcosystemPage() {
</div>
{/* Left Column - Company Fields */}
<div className="space-y-2">
<h3 className="font-persian gap-1 flex text-lg font-bold">
<h3 className="font-persian gap-1 flex text-sm font-semibold">
اطلاعات
<span>{selectedCompany?.category}</span>
</h3>
{selectedCompany?.fields &&
selectedCompany.fields.length > 0 ? (
<div className="space-y-3">
<div className="space-y-3 px-4">
{selectedCompany.fields.map((field, index) => (
<div
key={index}
className="flex justify-between items-center rounded-lg"
>
<span className="font-persian font-light">
<span className="font-persian text-sm font-light">
{field.N}:
</span>
<span className="font-persian font-light text-right">
<span className="font-persian text-sm font-light text-right">
{handleValue(field.V)}
{field.U && <span className="mr-1">({field.U})</span>}
</span>