mirror of
https://github.com/devonthesofa/obsidian-note-status.git
synced 2026-07-22 12:30:24 +00:00
94 lines
2.5 KiB
TypeScript
94 lines
2.5 KiB
TypeScript
import { useMemo } from "react";
|
|
import { StatusDisplay } from "@/components/atoms/StatusDisplay";
|
|
import { VaultStats } from "./useVaultStats";
|
|
import { NoteStatus } from "@/types/noteStatus";
|
|
|
|
interface StatusDistributionChartProps {
|
|
vaultStats: VaultStats;
|
|
availableStatuses: NoteStatus[];
|
|
onStatusClick?: (statusName: string) => void;
|
|
}
|
|
|
|
export const StatusDistributionChart = ({
|
|
vaultStats,
|
|
availableStatuses,
|
|
onStatusClick,
|
|
}: StatusDistributionChartProps) => {
|
|
const statusChart = useMemo(() => {
|
|
const total = Object.values(vaultStats.statusDistribution).reduce(
|
|
(sum, count) => sum + count,
|
|
0,
|
|
);
|
|
if (total === 0) return [];
|
|
|
|
return Object.entries(vaultStats.statusDistribution)
|
|
.filter(([_, count]) => count > 0)
|
|
.map(([statusName, count]) => ({
|
|
name: statusName,
|
|
count,
|
|
percentage: Math.round((count / total) * 100),
|
|
}))
|
|
.sort((a, b) => b.count - a.count);
|
|
}, [vaultStats.statusDistribution]);
|
|
|
|
const statusMap = useMemo(
|
|
() => new Map(availableStatuses.map((s) => [s.name, s])),
|
|
[availableStatuses],
|
|
);
|
|
|
|
return (
|
|
<div className="status-dashboard-section">
|
|
<div className="status-dashboard-section-header">
|
|
<h3>Status Distribution</h3>
|
|
</div>
|
|
<div className="status-distribution">
|
|
{statusChart.length > 0 ? (
|
|
<div className="status-chart">
|
|
{statusChart.map(({ name, count, percentage }) => {
|
|
const status = statusMap.get(name);
|
|
return (
|
|
<div
|
|
key={name}
|
|
className={`status-chart-item ${onStatusClick ? "status-chart-item--clickable" : ""}`}
|
|
onClick={() => onStatusClick?.(name)}
|
|
title={
|
|
onStatusClick
|
|
? `Click to search for notes with status: ${name}`
|
|
: undefined
|
|
}
|
|
>
|
|
<div className="status-chart-info">
|
|
{status && (
|
|
<StatusDisplay
|
|
status={status}
|
|
variant="badge"
|
|
/>
|
|
)}
|
|
<span className="status-chart-count">
|
|
{count} notes ({percentage}%)
|
|
</span>
|
|
</div>
|
|
<div className="status-chart-bar">
|
|
<div
|
|
className="status-chart-fill"
|
|
style={{
|
|
width: `${percentage}%`,
|
|
backgroundColor:
|
|
status?.color ||
|
|
"var(--interactive-accent)",
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
) : (
|
|
<div className="status-distribution-empty">
|
|
No status data available
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|