mirror of
https://github.com/better-auth/better-hub
synced 2026-08-09 12:26:04 +00:00
chore: improve dashboard stat btn ui (#30)
Added a highlight state to the UI of the stat buttons: <img width="1588" height="876" alt="CleanShot 2026-02-23 at 18 40 38@2x" src="https://github.com/user-attachments/assets/9ad17c3e-df3b-4cf0-8ba2-cddee6d97dcc" />
This commit is contained in:
@@ -112,9 +112,10 @@ export function DashboardContent({
|
|||||||
<div className="shrink-0 grid grid-cols-2 sm:grid-cols-4 gap-2 sm:gap-3">
|
<div className="shrink-0 grid grid-cols-2 sm:grid-cols-4 gap-2 sm:gap-3">
|
||||||
<Stat
|
<Stat
|
||||||
icon={<Eye className="w-3.5 h-3.5" />}
|
icon={<Eye className="w-3.5 h-3.5" />}
|
||||||
label="Reviews"
|
label="Needs review"
|
||||||
value={reviewRequests.total_count}
|
value={reviewRequests.total_count}
|
||||||
accent={reviewRequests.total_count > 0}
|
accent={reviewRequests.total_count > 0}
|
||||||
|
active={activeTab === "reviews"}
|
||||||
onClick={() => handleStatClick("reviews")}
|
onClick={() => handleStatClick("reviews")}
|
||||||
/>
|
/>
|
||||||
<Stat
|
<Stat
|
||||||
@@ -124,6 +125,7 @@ export function DashboardContent({
|
|||||||
label="Open PRs"
|
label="Open PRs"
|
||||||
value={myOpenPRs.total_count}
|
value={myOpenPRs.total_count}
|
||||||
accent={myOpenPRs.total_count > 0}
|
accent={myOpenPRs.total_count > 0}
|
||||||
|
active={activeTab === "prs"}
|
||||||
onClick={() => handleStatClick("prs")}
|
onClick={() => handleStatClick("prs")}
|
||||||
/>
|
/>
|
||||||
<Stat
|
<Stat
|
||||||
@@ -131,6 +133,7 @@ export function DashboardContent({
|
|||||||
label="Assigned Issues"
|
label="Assigned Issues"
|
||||||
value={myIssues.total_count}
|
value={myIssues.total_count}
|
||||||
accent={myIssues.total_count > 0}
|
accent={myIssues.total_count > 0}
|
||||||
|
active={activeTab === "issues"}
|
||||||
onClick={() => handleStatClick("issues")}
|
onClick={() => handleStatClick("issues")}
|
||||||
/>
|
/>
|
||||||
<Stat
|
<Stat
|
||||||
@@ -141,6 +144,7 @@ export function DashboardContent({
|
|||||||
(n) => n.unread,
|
(n) => n.unread,
|
||||||
).length
|
).length
|
||||||
}
|
}
|
||||||
|
active={activeTab === "notifs"}
|
||||||
onClick={() => handleStatClick("notifs")}
|
onClick={() => handleStatClick("notifs")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -449,6 +453,7 @@ function Stat({
|
|||||||
label,
|
label,
|
||||||
value,
|
value,
|
||||||
accent,
|
accent,
|
||||||
|
active,
|
||||||
onClick,
|
onClick,
|
||||||
href,
|
href,
|
||||||
}: {
|
}: {
|
||||||
@@ -456,6 +461,7 @@ function Stat({
|
|||||||
label: string;
|
label: string;
|
||||||
value: number;
|
value: number;
|
||||||
accent?: boolean;
|
accent?: boolean;
|
||||||
|
active?: boolean;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
href?: string;
|
href?: string;
|
||||||
}) {
|
}) {
|
||||||
@@ -476,7 +482,14 @@ function Stat({
|
|||||||
>
|
>
|
||||||
{icon}
|
{icon}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-[10px] font-mono uppercase tracking-wider text-muted-foreground/60">
|
<span
|
||||||
|
className={cn(
|
||||||
|
"text-[10px] font-mono uppercase tracking-wider",
|
||||||
|
active
|
||||||
|
? "text-foreground"
|
||||||
|
: "text-muted-foreground/60",
|
||||||
|
)}
|
||||||
|
>
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -501,12 +514,12 @@ function Stat({
|
|||||||
|
|
||||||
const className = cn(
|
const className = cn(
|
||||||
"stat-card relative overflow-hidden rounded-lg px-3 py-3 text-left w-full",
|
"stat-card relative overflow-hidden rounded-lg px-3 py-3 text-left w-full",
|
||||||
"border border-black/[0.04] dark:border-white/[0.06]",
|
|
||||||
"bg-gradient-to-br from-black/[0.02] via-black/[0.01] to-transparent dark:from-white/[0.04] dark:via-white/[0.02] dark:to-transparent",
|
"bg-gradient-to-br from-black/[0.02] via-black/[0.01] to-transparent dark:from-white/[0.04] dark:via-white/[0.02] dark:to-transparent",
|
||||||
"transition-all duration-150 cursor-pointer",
|
"transition-all duration-150 cursor-pointer",
|
||||||
"hover:border-black/[0.08] dark:hover:border-white/[0.12]",
|
"hover:border-black/[0.08] dark:hover:border-white/[0.12]",
|
||||||
"hover:bg-gradient-to-br hover:from-black/[0.04] hover:via-black/[0.02] dark:hover:from-white/[0.06] dark:hover:via-white/[0.03]",
|
"hover:bg-gradient-to-br hover:from-black/[0.04] hover:via-black/[0.02] dark:hover:from-white/[0.06] dark:hover:via-white/[0.03]",
|
||||||
"dark:active:from-white/[0.03] dark:active:via-white/[0.02] transition-all duration-150",
|
"dark:active:from-white/[0.03] dark:active:via-white/[0.02]",
|
||||||
|
active ? "border border-primary/20!" : "border border-border/50!",
|
||||||
);
|
);
|
||||||
|
|
||||||
if (href) {
|
if (href) {
|
||||||
@@ -524,34 +537,6 @@ function Stat({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Panel ─────────────────────────────────────────────────────────── */
|
|
||||||
|
|
||||||
function Panel({
|
|
||||||
title,
|
|
||||||
count,
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
title: string;
|
|
||||||
count?: number;
|
|
||||||
children: React.ReactNode;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<section className="border border-border">
|
|
||||||
<div className="flex items-center gap-2 px-4 py-2 border-b border-border">
|
|
||||||
<h2 className="text-[11px] font-mono uppercase tracking-wider text-muted-foreground">
|
|
||||||
{title}
|
|
||||||
</h2>
|
|
||||||
{count !== undefined && (
|
|
||||||
<span className="text-[10px] font-mono text-muted-foreground/50 tabular-nums ml-auto">
|
|
||||||
{count}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div>{children}</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ItemRow({ item, type }: { item: IssueItem; type: "pr" | "issue" }) {
|
function ItemRow({ item, type }: { item: IssueItem; type: "pr" | "issue" }) {
|
||||||
const repo = extractRepoName(item.repository_url);
|
const repo = extractRepoName(item.repository_url);
|
||||||
const isMerged = type === "pr" && item.pull_request?.merged_at;
|
const isMerged = type === "pr" && item.pull_request?.merged_at;
|
||||||
|
|||||||
Reference in New Issue
Block a user