import { ChevronDown, ChevronUp } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { sortBy } from "remeda"; import { Area, AreaChart, CartesianGrid, Tooltip, XAxis, YAxis, } from "recharts"; import type { MonthlySearch } from "@/types/keywords"; import { formatCompactNumber } from "../utils"; import { FloatingTooltip, useFloatingTooltip } from "./FloatingTooltip"; export type SortField = | "keyword" | "searchVolume" | "cpc" | "competition" | "keywordDifficulty"; export type SortDir = "asc" | "desc"; export function HeaderHelpLabel({ label, helpText, delayMs = 150, }: { label: string; helpText: string; delayMs?: number; }) { const tooltip = useFloatingTooltip({ delayMs }); return ( { if (e.key === "Escape") tooltip.close(); }} aria-describedby={tooltip.isOpen ? tooltip.tooltipId : undefined} > {label} {tooltip.isOpen && typeof document !== "undefined" ? createPortal( {helpText} , document.body, ) : null} ); } export function AreaTrendChart({ trend }: { trend: MonthlySearch[] }) { const sorted = sortBy(trend, (item) => item.year * 100 + item.month); const last12 = sorted.slice(-12); const containerRef = useRef(null); const [chartWidth, setChartWidth] = useState(0); if (last12.length === 0) return null; useEffect(() => { const container = containerRef.current; if (!container) return; const update = () => { setChartWidth(container.clientWidth); }; update(); const observer = new ResizeObserver(update); observer.observe(container); return () => { observer.disconnect(); }; }, []); const monthLabels = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ]; const data = last12.map((m) => ({ month: monthLabels[m.month - 1], year: m.year, searchVolume: m.searchVolume, label: `${monthLabels[m.month - 1]} ${m.year}`, })); return (
{chartWidth > 0 ? ( formatCompactNumber(Number(value)) } tick={{ fill: "var(--trend-axis-color)", fontSize: 11 }} width={44} axisLine={false} tickLine={false} /> ) : null}
); } export function SortHeader({ label, helpText, field, current, dir, onToggle, className, }: { label: string; helpText?: string; field: SortField; current: SortField; dir: SortDir; onToggle: (f: SortField) => void; className?: string; }) { const isActive = field === current; const tooltip = useFloatingTooltip({ enabled: !!helpText, }); return ( ); }