fix: polish chart legends
All checks were successful
CI / Lint, test, typecheck and build (push) Successful in 9m58s
All checks were successful
CI / Lint, test, typecheck and build (push) Successful in 9m58s
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Bar, CartesianGrid, ComposedChart, Legend, Line, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
|
import { Bar, CartesianGrid, ComposedChart, Line, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { ChartTooltip } from "@/components/charts/chart-tooltip";
|
import { ChartTooltip } from "@/components/charts/chart-tooltip";
|
||||||
import { CHART_COLORS } from "@/lib/chart-theme";
|
import { CHART_COLORS } from "@/lib/chart-theme";
|
||||||
@@ -12,10 +12,37 @@ import type { HourlyForecast } from "@/types/forecast";
|
|||||||
|
|
||||||
const INITIAL_CHART_DIMENSION = { width: 1, height: 1 };
|
const INITIAL_CHART_DIMENSION = { width: 1, height: 1 };
|
||||||
|
|
||||||
|
interface ChartLegendItem {
|
||||||
|
color: string;
|
||||||
|
label: string;
|
||||||
|
marker: "bar" | "line" | "dashed-line";
|
||||||
|
}
|
||||||
|
|
||||||
function formatHour(value: string) {
|
function formatHour(value: string) {
|
||||||
return value.slice(11, 16);
|
return value.slice(11, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ChartLegend({ items }: { items: ChartLegendItem[] }) {
|
||||||
|
return (
|
||||||
|
<div className="mt-2 flex flex-wrap items-center gap-x-4 gap-y-2 text-[0.72rem] font-medium text-muted">
|
||||||
|
{items.map((item) => (
|
||||||
|
<span className="inline-flex items-center gap-1.5" key={item.label}>
|
||||||
|
{item.marker === "bar" ? (
|
||||||
|
<span className="h-2.5 w-3 rounded-t-[5px]" style={{ backgroundColor: item.color }} aria-hidden="true" />
|
||||||
|
) : (
|
||||||
|
<span
|
||||||
|
className={`h-0 w-5 border-t-2 ${item.marker === "dashed-line" ? "border-dashed" : "border-solid"}`}
|
||||||
|
style={{ borderColor: item.color }}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function DayForecastCharts({ hours }: { hours: HourlyForecast[] }) {
|
export function DayForecastCharts({ hours }: { hours: HourlyForecast[] }) {
|
||||||
const { language, t } = useI18n();
|
const { language, t } = useI18n();
|
||||||
const temperatureUnit = useWeatherStore((state) => state.temperatureUnit);
|
const temperatureUnit = useWeatherStore((state) => state.temperatureUnit);
|
||||||
@@ -27,6 +54,14 @@ export function DayForecastCharts({ hours }: { hours: HourlyForecast[] }) {
|
|||||||
precipitationProbability: hour.precipitationProbability,
|
precipitationProbability: hour.precipitationProbability,
|
||||||
}));
|
}));
|
||||||
const temperatureUnitLabel = getTemperatureUnitLabel(temperatureUnit);
|
const temperatureUnitLabel = getTemperatureUnitLabel(temperatureUnit);
|
||||||
|
const temperatureLegendItems: ChartLegendItem[] = [
|
||||||
|
{ color: CHART_COLORS.temperature, label: t("forecast.temperature"), marker: "line" },
|
||||||
|
{ color: CHART_COLORS.feelsLike, label: t("forecast.apparentTemperature"), marker: "dashed-line" },
|
||||||
|
];
|
||||||
|
const rainfallLegendItems: ChartLegendItem[] = [
|
||||||
|
{ color: CHART_COLORS.rainfall, label: t("forecast.precipitation"), marker: "bar" },
|
||||||
|
{ color: CHART_COLORS.probability, label: t("forecast.precipitationProbability"), marker: "line" },
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid gap-3 lg:grid-cols-2">
|
<div className="grid gap-3 lg:grid-cols-2">
|
||||||
@@ -68,7 +103,6 @@ export function DayForecastCharts({ hours }: { hours: HourlyForecast[] }) {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Legend wrapperStyle={{ fontSize: "0.72rem" }} />
|
|
||||||
<Line
|
<Line
|
||||||
type="monotone"
|
type="monotone"
|
||||||
dataKey="temperature"
|
dataKey="temperature"
|
||||||
@@ -91,6 +125,7 @@ export function DayForecastCharts({ hours }: { hours: HourlyForecast[] }) {
|
|||||||
</ComposedChart>
|
</ComposedChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
</div>
|
</div>
|
||||||
|
<ChartLegend items={temperatureLegendItems} />
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="p-4 sm:p-5">
|
<Card className="p-4 sm:p-5">
|
||||||
@@ -141,7 +176,6 @@ export function DayForecastCharts({ hours }: { hours: HourlyForecast[] }) {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Legend wrapperStyle={{ fontSize: "0.72rem" }} />
|
|
||||||
<Bar
|
<Bar
|
||||||
yAxisId="rainfall"
|
yAxisId="rainfall"
|
||||||
dataKey="precipitation"
|
dataKey="precipitation"
|
||||||
@@ -162,6 +196,7 @@ export function DayForecastCharts({ hours }: { hours: HourlyForecast[] }) {
|
|||||||
</ComposedChart>
|
</ComposedChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
</div>
|
</div>
|
||||||
|
<ChartLegend items={rainfallLegendItems} />
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user