mirror of
https://github.com/usememos/memos.git
synced 2025-10-24 05:07:13 +08:00
chore: update StatCard component for improved icon and count rendering in StatisticsView
This commit is contained in:
parent
56758f107c
commit
228cc6105d
2 changed files with 46 additions and 34 deletions
|
|
@ -1,37 +1,55 @@
|
||||||
|
import { cloneElement, isValidElement } from "react";
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import type { StatCardProps } from "@/types/statistics";
|
import type { StatCardProps } from "@/types/statistics";
|
||||||
|
|
||||||
export const StatCard = ({ icon, label, count, onClick, tooltip, className }: StatCardProps) => {
|
export const StatCard = ({ icon, label, count, onClick, tooltip, className }: StatCardProps) => {
|
||||||
const content = (
|
const iconNode = isValidElement(icon)
|
||||||
<div
|
? cloneElement(icon, {
|
||||||
|
className: cn("h-3.5 w-3.5", icon.props.className),
|
||||||
|
})
|
||||||
|
: icon;
|
||||||
|
|
||||||
|
const countNode = (() => {
|
||||||
|
if (typeof count === "number" || typeof count === "string") {
|
||||||
|
return <span className="text-foreground/80">{count}</span>;
|
||||||
|
}
|
||||||
|
if (isValidElement(count)) {
|
||||||
|
return cloneElement(count, {
|
||||||
|
className: cn("text-foreground/80", count.props.className),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return <span className="text-foreground/80">{count}</span>;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const button = (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onClick}
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-auto border pl-1.5 pr-2 py-0.5 rounded-md flex justify-between items-center",
|
"inline-flex items-center gap-1 rounded-md border border-border/40 bg-background/80 px-1 pr-2 py-0.5 text-sm leading-none text-muted-foreground transition-colors",
|
||||||
"cursor-pointer hover:bg-muted transition-colors",
|
"hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring/70 focus-visible:ring-offset-1 focus-visible:ring-offset-background",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
onClick={onClick}
|
|
||||||
>
|
>
|
||||||
<div className="w-auto flex justify-start items-center mr-1">
|
<span className="flex h-5 w-5 items-center justify-center text-muted-foreground/80">{iconNode}</span>
|
||||||
{icon}
|
<span className="truncate text-sm text-foreground/70">{label}</span>
|
||||||
<span className="block text-sm opacity-80">{label}</span>
|
<span className="ml-1 flex items-center text-sm">{countNode}</span>
|
||||||
</div>
|
</button>
|
||||||
<span className="text-sm truncate opacity-80">{count}</span>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (tooltip) {
|
if (!tooltip) {
|
||||||
return (
|
return button;
|
||||||
<TooltipProvider>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>{content}</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p>{tooltip}</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return content;
|
return (
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>{tooltip}</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,10 @@ const StatisticsView = observer(() => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="pt-1 w-full flex flex-row justify-start items-center gap-1 flex-wrap">
|
<div className="pt-2 w-full flex flex-wrap items-center gap-2">
|
||||||
{isRootPath && hasPinnedMemos && (
|
{isRootPath && hasPinnedMemos && (
|
||||||
<StatCard
|
<StatCard
|
||||||
icon={<BookmarkIcon className="w-4 h-auto mr-1 opacity-70" />}
|
icon={<BookmarkIcon className="opacity-70" />}
|
||||||
label={t("common.pinned")}
|
label={t("common.pinned")}
|
||||||
count={userStore.state.currentUserStats!.pinnedMemos.length}
|
count={userStore.state.currentUserStats!.pinnedMemos.length}
|
||||||
onClick={() => handleFilterClick("pinned")}
|
onClick={() => handleFilterClick("pinned")}
|
||||||
|
|
@ -57,20 +57,14 @@ const StatisticsView = observer(() => {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<StatCard
|
<StatCard
|
||||||
icon={<LinkIcon className="w-4 h-auto mr-1 opacity-70" />}
|
icon={<LinkIcon className="opacity-70" />}
|
||||||
label={t("memo.links")}
|
label={t("memo.links")}
|
||||||
count={memoTypeStats.linkCount}
|
count={memoTypeStats.linkCount}
|
||||||
onClick={() => handleFilterClick("property.hasLink")}
|
onClick={() => handleFilterClick("property.hasLink")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<StatCard
|
<StatCard
|
||||||
icon={
|
icon={memoTypeStats.undoCount > 0 ? <ListTodoIcon className="opacity-70" /> : <CheckCircleIcon className="opacity-70" />}
|
||||||
memoTypeStats.undoCount > 0 ? (
|
|
||||||
<ListTodoIcon className="w-4 h-auto mr-1 opacity-70" />
|
|
||||||
) : (
|
|
||||||
<CheckCircleIcon className="w-4 h-auto mr-1 opacity-70" />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
label={t("memo.to-do")}
|
label={t("memo.to-do")}
|
||||||
count={
|
count={
|
||||||
memoTypeStats.undoCount > 0 ? (
|
memoTypeStats.undoCount > 0 ? (
|
||||||
|
|
@ -88,7 +82,7 @@ const StatisticsView = observer(() => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<StatCard
|
<StatCard
|
||||||
icon={<Code2Icon className="w-4 h-auto mr-1 opacity-70" />}
|
icon={<Code2Icon className="opacity-70" />}
|
||||||
label={t("memo.code")}
|
label={t("memo.code")}
|
||||||
count={memoTypeStats.codeCount}
|
count={memoTypeStats.codeCount}
|
||||||
onClick={() => handleFilterClick("property.hasCode")}
|
onClick={() => handleFilterClick("property.hasCode")}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue