Files
tool-evaluator/artifacts/toolrate/src/components/tool-preview-card.tsx
T
opencode 3de59ccaaf
Build & Push Docker Image / build (push) Successful in 2m33s
feat(i18n): full app + docs localization (de/en)
- translate remaining pages/components (admin, analytics, redundancy,
  trash, compare, browse, watchlist, admin tools tab, category combobox,
  theme toggle, tool preview card, tool-new/edit) to t() calls
- locales: 453 keys each, parity verified
- docs: bilingual handbook + release notes via *.en.md variants,
  language-aware docs.tsx (markdown paths, nav titles, search index),
  LanguageSwitcher in docs header
- generate-docs: emit per-locale handbook/release/search output,
  localized index.json fields (fileEn/titleEn), en-aware snapshots
2026-08-04 08:35:05 +02:00

56 lines
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Link } from "wouter";
import { useTranslation } from "react-i18next";
import type { ToolWithStats } from "@workspace/api-client-react";
import { Badge } from "@/components/ui/badge";
import { RatingStars } from "@/components/rating-stars";
import { MiniBars } from "@/components/mini-bars";
export function ToolPreviewCard({ tool }: { tool: ToolWithStats }) {
const { t } = useTranslation();
return (
<div className="space-y-3">
<div>
<div className="flex items-start justify-between gap-2">
<div className="min-w-0">
<div className="font-semibold leading-tight truncate">{tool.name}</div>
<div className="text-xs text-muted-foreground">{tool.category}</div>
</div>
<RatingStars value={tool.avgCombined ?? 0} size="sm" />
</div>
</div>
<p className="text-xs text-muted-foreground line-clamp-3">{tool.description}</p>
<div className="space-y-1.5">
<div className="flex items-center justify-between text-xs">
<span className="text-muted-foreground">{t("browse.reviewCount", { count: tool.ratingCount })}</span>
<span className="font-semibold tabular-nums">
{tool.avgCombined != null ? tool.avgCombined.toFixed(1) : ""}/5
</span>
</div>
<MiniBars usefulness={tool.avgUsefulness} usability={tool.avgUsability} />
</div>
{tool.tags && tool.tags.length > 0 && (
<div className="flex flex-wrap gap-1">
{tool.tags.slice(0, 4).map((tag) => (
<Badge key={tag} variant="secondary" className="text-[10px]">
{tag}
</Badge>
))}
{tool.tags.length > 4 && (
<span className="text-[10px] text-muted-foreground">+{tool.tags.length - 4}</span>
)}
</div>
)}
<Link
href={`/tools/${tool.id}`}
className="block w-full rounded-md border border-primary/40 bg-primary/5 px-3 py-1.5 text-center text-xs font-medium text-primary hover:bg-primary/10"
>
{t("common.viewDetails")}
</Link> </div>
);
}