ci: dev version includes UTC time (dev-YYYYMMDD-HHmm)
Build & Push Docker Image / build (push) Successful in 2m36s
Build & Push Docker Image / build (push) Successful in 2m36s
Phase 1: browse power-up - faceted filters: tags + features (array containment) and min rating on listTools; new ?tags=?features=?minRating= URL params with chips - global Cmd+K command palette (cmdk) with tool search + navigation - mini usefulness/usability bars on grid cards, wide cards and table rows
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function pct(v: number | null | undefined): number {
|
||||
if (v == null) return 0;
|
||||
return Math.max(0, Math.min(5, v)) / 5 * 100;
|
||||
}
|
||||
|
||||
export function MiniBars({
|
||||
usefulness,
|
||||
usability,
|
||||
className,
|
||||
}: {
|
||||
usefulness: number | null | undefined;
|
||||
usability: number | null | undefined;
|
||||
className?: string;
|
||||
}) {
|
||||
const rows = [
|
||||
{ label: "Usefulness", value: usefulness },
|
||||
{ label: "Usability", value: usability },
|
||||
];
|
||||
return (
|
||||
<div className={cn("space-y-1 w-full", className)}>
|
||||
{rows.map(({ label, value }) => (
|
||||
<div
|
||||
key={label}
|
||||
className="flex items-center gap-2"
|
||||
title={`${label}: ${value != null ? value.toFixed(1) : "N/A"} / 5`}
|
||||
>
|
||||
<span className="text-[10px] uppercase tracking-wide text-muted-foreground w-[3.5rem] shrink-0">
|
||||
{label}
|
||||
</span>
|
||||
<div className="flex-1 h-1.5 rounded-full bg-muted overflow-hidden">
|
||||
<div
|
||||
className="h-full rounded-full bg-primary/70"
|
||||
style={{ width: `${pct(value)}%` }}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-[10px] text-muted-foreground tabular-nums w-7 text-right shrink-0">
|
||||
{value != null ? value.toFixed(1) : "–"}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function MiniBarStack({
|
||||
usefulness,
|
||||
usability,
|
||||
className,
|
||||
}: {
|
||||
usefulness: number | null | undefined;
|
||||
usability: number | null | undefined;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={cn("h-1.5 w-16 rounded-full bg-muted overflow-hidden flex", className)}
|
||||
title={`Usefulness ${usefulness != null ? usefulness.toFixed(1) : "N/A"} / Usability ${
|
||||
usability != null ? usability.toFixed(1) : "N/A"
|
||||
} (of 5)`}
|
||||
>
|
||||
<div
|
||||
className="h-full bg-primary/80"
|
||||
style={{ width: `${pct(usefulness)}%` }}
|
||||
/>
|
||||
<div
|
||||
className="h-full bg-primary/40"
|
||||
style={{ width: `${pct(usability)}%` }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user