fix: compact filter popover; feat: i18n (de/en)
Build & Push Docker Image / build (push) Successful in 2m31s
Build & Push Docker Image / build (push) Successful in 2m31s
This commit is contained in:
@@ -15,12 +15,14 @@ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/com
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||
import { ShieldAlert, Trophy, Scale } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
function fmt(v: number | null | undefined): string {
|
||||
return v != null ? v.toFixed(1) : "–";
|
||||
}
|
||||
|
||||
export default function Compare() {
|
||||
const { t } = useTranslation();
|
||||
const { hasFeature, isLoading: authLoading } = useAuth();
|
||||
const search = useSearch();
|
||||
|
||||
@@ -50,10 +52,10 @@ export default function Compare() {
|
||||
<Layout>
|
||||
<div className="flex flex-col items-center justify-center py-20 gap-4">
|
||||
<ShieldAlert className="w-12 h-12 text-muted-foreground" />
|
||||
<h2 className="text-2xl font-bold">Compare requires a higher tier</h2>
|
||||
<p className="text-muted-foreground">Compare tools side-by-side is available to Premium and Enterprise users.</p>
|
||||
<h2 className="text-2xl font-bold">{t("compare.requiresPremium")}</h2>
|
||||
<p className="text-muted-foreground">{t("compare.requiresPremiumSub")}</p>
|
||||
<Button variant="outline" asChild>
|
||||
<a href="/tools">Back to tools</a>
|
||||
<a href="/tools">{t("common.backToTools")}</a>
|
||||
</Button>
|
||||
</div>
|
||||
</Layout>
|
||||
@@ -77,10 +79,10 @@ export default function Compare() {
|
||||
<Layout>
|
||||
<div className="flex flex-col items-center justify-center py-20 gap-4">
|
||||
<Scale className="w-12 h-12 text-muted-foreground" />
|
||||
<h2 className="text-2xl font-bold">Nothing to compare</h2>
|
||||
<p className="text-muted-foreground">Select at least one tool to compare and come back here.</p>
|
||||
<h2 className="text-2xl font-bold">{t("compare.nothingToCompare")}</h2>
|
||||
<p className="text-muted-foreground">{t("compare.nothingToCompareSub")}</p>
|
||||
<Button variant="outline" asChild>
|
||||
<a href="/tools">Browse tools</a>
|
||||
<a href="/tools">{t("common.browseTools")}</a>
|
||||
</Button>
|
||||
</div>
|
||||
</Layout>
|
||||
@@ -99,20 +101,20 @@ export default function Compare() {
|
||||
<Layout>
|
||||
<div className="space-y-6 pb-10">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight mb-2">Compare Tools</h1>
|
||||
<p className="text-muted-foreground">Comparing {list.length} tool(s) side-by-side.</p>
|
||||
<h1 className="text-3xl font-bold tracking-tight mb-2">{t("compare.title")}</h1>
|
||||
<p className="text-muted-foreground">{t("compare.subtitle", { count: list.length })}</p>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Side-by-side comparison</CardTitle>
|
||||
<CardDescription>Best value in each row is highlighted.</CardDescription>
|
||||
<CardTitle>{t("compare.sideBySide")}</CardTitle>
|
||||
<CardDescription>{t("compare.bestValue")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-44">Attribute</TableHead>
|
||||
<TableHead className="w-44">{t("compare.attribute")}</TableHead>
|
||||
{list.map((t) => (
|
||||
<TableHead key={t.id} className="min-w-[12rem]">
|
||||
<div className="flex flex-col gap-1">
|
||||
@@ -127,7 +129,7 @@ export default function Compare() {
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Rating</TableCell>
|
||||
<TableCell className="font-medium">{t("compare.rating")}</TableCell>
|
||||
{list.map((t) => (
|
||||
<TableCell key={t.id} className={cn(isBest(t.avgCombined, bestRating) && "bg-primary/5")}>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -155,7 +157,7 @@ export default function Compare() {
|
||||
))}
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Reviews</TableCell>
|
||||
<TableCell className="font-medium">{t("compare.reviews")}</TableCell>
|
||||
{list.map((t) => (
|
||||
<TableCell key={t.id} className={cn(isBest(t.ratingCount, bestReviews) && "bg-primary/5")}>
|
||||
<span className="tabular-nums">{t.ratingCount}</span>
|
||||
@@ -163,7 +165,7 @@ export default function Compare() {
|
||||
))}
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Description</TableCell>
|
||||
<TableCell className="font-medium">{t("compare.description")}</TableCell>
|
||||
{list.map((t) => (
|
||||
<TableCell key={t.id} className="text-sm text-muted-foreground align-top">
|
||||
{t.description}
|
||||
@@ -197,7 +199,7 @@ export default function Compare() {
|
||||
))}
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Last updated</TableCell>
|
||||
<TableCell className="font-medium">{t("compare.lastUpdated")}</TableCell>
|
||||
{list.map((t) => (
|
||||
<TableCell key={t.id} className="text-sm text-muted-foreground">
|
||||
{new Date(t.updatedAt).toLocaleDateString()}
|
||||
@@ -210,7 +212,7 @@ export default function Compare() {
|
||||
</Card>
|
||||
|
||||
<Button variant="outline" asChild>
|
||||
<Link to="/tools">Back to browse</Link>
|
||||
<Link to="/tools">{t("compare.backToBrowse")}</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
Reference in New Issue
Block a user