From ebf9a9f4a820866a0ec937f0bb3b6b67256a0fd4 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Thu, 4 Jun 2026 17:04:29 +0200 Subject: [PATCH] feat: replace CSS bar charts with recharts, fix label readability --- spa/src/aero-theme.css | 5 +++ spa/src/components/profile-view.tsx | 25 ++++++----- spa/src/components/rating-histogram.tsx | 32 +++++++------- spa/src/routes/_app/wrapup.$id.tsx | 56 ++++++++++++------------- 4 files changed, 60 insertions(+), 58 deletions(-) diff --git a/spa/src/aero-theme.css b/spa/src/aero-theme.css index 79eedd7..1070ffe 100644 --- a/spa/src/aero-theme.css +++ b/spa/src/aero-theme.css @@ -298,6 +298,11 @@ body > #root { color: oklch(0.985 0 0); } +/* Chart label readability */ +[data-slot="chart"] .recharts-cartesian-axis-tick text { + fill: rgba(255, 255, 255, 0.85) !important; +} + /* Star glow for filled amber stars */ .aero-star-filled { filter: drop-shadow(0 0 4px var(--aero-primary-glow)) drop-shadow(0 0 1px var(--aero-primary)); diff --git a/spa/src/components/profile-view.tsx b/spa/src/components/profile-view.tsx index 9682850..de9405a 100644 --- a/spa/src/components/profile-view.tsx +++ b/spa/src/components/profile-view.tsx @@ -1,7 +1,9 @@ import { Link } from "@tanstack/react-router" import { useCallback } from "react" import { useTranslation } from "react-i18next" +import { Bar, BarChart, XAxis, YAxis } from "recharts" import { User } from "lucide-react" +import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from "@/components/ui/chart" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Skeleton } from "@/components/ui/skeleton" @@ -136,6 +138,10 @@ function DiaryTab({ sortBy }: { sortBy: string; userId?: string }) { ) } +const trendChartConfig = { + count: { label: "Movies", color: "var(--primary)" }, +} satisfies ChartConfig + function TrendsView({ data, }: { @@ -183,17 +189,14 @@ function TrendsView({ {t("profile.monthlyActivity")} - {data.trends.monthly_ratings.map((m) => ( -
- {m.month_label} - - {t("common.filmsAvg", { count: m.count, avg: m.avg_rating.toFixed(1) })} - -
- ))} + + + v.slice(0, 3)} tick={{ fontSize: 10, fill: "rgba(255,255,255,0.85)" }} tickLine={false} axisLine={false} /> + + } /> + + +
)} diff --git a/spa/src/components/rating-histogram.tsx b/spa/src/components/rating-histogram.tsx index 5de426b..e0ef250 100644 --- a/spa/src/components/rating-histogram.tsx +++ b/spa/src/components/rating-histogram.tsx @@ -1,26 +1,24 @@ +import { Bar, BarChart, XAxis } from "recharts" +import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from "@/components/ui/chart" + +const chartConfig = { + count: { label: "Reviews", color: "var(--primary)" }, +} satisfies ChartConfig + type RatingHistogramProps = { histogram: number[] } export function RatingHistogram({ histogram }: RatingHistogramProps) { - const max = Math.max(...histogram, 1) + const data = histogram.map((count, i) => ({ rating: `${i + 1}★`, count })) return ( -
-
- {histogram.map((count, i) => ( -
0 ? 2 : 0 }} - /> - ))} -
-
- {[1, 2, 3, 4, 5].map((n) => ( -
{n}
- ))} -
-
+ + + + } /> + + + ) } diff --git a/spa/src/routes/_app/wrapup.$id.tsx b/spa/src/routes/_app/wrapup.$id.tsx index 7bb930a..3bde4ce 100644 --- a/spa/src/routes/_app/wrapup.$id.tsx +++ b/spa/src/routes/_app/wrapup.$id.tsx @@ -1,10 +1,20 @@ import { createFileRoute, Link } from "@tanstack/react-router" import { lazy, Suspense, useState } from "react" import { useTranslation } from "react-i18next" +import { Bar, BarChart, XAxis, YAxis } from "recharts" import { BarChart3, DollarSign, Globe, Hash, Share2, Star, Users } from "lucide-react" +import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from "@/components/ui/chart" import { BackButton } from "@/components/back-button" import { Button } from "@/components/ui/button" +const monthlyChartConfig = { + count: { label: "Movies", color: "var(--primary)" }, +} satisfies ChartConfig + +const genreChartConfig = { + count: { label: "Movies", color: "var(--primary)" }, +} satisfies ChartConfig + const WrapUpShareCard = lazy(() => import("@/components/wrapup-share-card").then((m) => ({ default: m.WrapUpShareCard }))) import { Badge } from "@/components/ui/badge" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" @@ -111,18 +121,14 @@ function WrapUpReportPage() { {t("wrapup.genresExplored", { count: report.genre_diversity })} - {report.top_genres.slice(0, 8).map((g) => { - const max = report.top_genres[0]?.count ?? 1 - return ( -
- {g.genre} -
-
-
- {g.count} -
- ) - })} + + + + + } /> + + +
{report.highest_rated_genre && ( {t("wrapup.highestRated", { genre: report.highest_rated_genre })} @@ -144,24 +150,14 @@ function WrapUpReportPage() { - {(() => { - const max = Math.max(...report.movies_per_month.map((x) => x.count)) - const barHeight = 96 - return ( -
- {report.movies_per_month.map((m) => { - const h = max > 0 ? Math.max((m.count / max) * barHeight, 4) : 4 - return ( -
- {m.count} -
- {m.year_month.slice(5)} -
- ) - })} -
- ) - })()} + + + v.slice(5)} tick={{ fontSize: 10, fill: "rgba(255,255,255,0.85)" }} tickLine={false} axisLine={false} /> + + report.movies_per_month.find((m) => m.year_month === String(v))?.label ?? String(v)} />} /> + + + )}