fix: 修复4小时负载图表数据渲染和下拉菜单动画

This commit is contained in:
Montia37
2025-09-07 15:54:58 +08:00
parent bed0de67dc
commit 657c02a49f
4 changed files with 86 additions and 36 deletions

View File

@@ -70,43 +70,49 @@ export const Header = ({
<>
{isMobile ? (
<>
<div
className={`absolute top-full left-0 w-full purcarte-blur p-2 border-b border-border shadow-sm z-10 transform transition-all duration-300 ease-in-out ${
isSearchOpen
? "opacity-100 translate-y-0"
: "opacity-0 -translate-y-4 pointer-events-none"
}`}>
{enableSearchButton && (
<DropdownMenu modal={false}>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
className="relative group">
<Search className="size-5 text-primary" />
{searchTerm && (
<span className="absolute top-0 right-0 w-1.5 h-1.5 rounded-full bg-primary transform -translate-x-1/2"></span>
)}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
className="purcarte-blur border-border rounded-xl w-48">
<div className="p-2">
<Input
type="search"
placeholder="搜索服务器..."
className="w-full"
value={searchTerm}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setSearchTerm(e.target.value)
}
onChange={(
e: React.ChangeEvent<HTMLInputElement>
) => setSearchTerm(e.target.value)}
/>
</div>
{enableSearchButton && (
<Button
variant="ghost"
size="icon"
onClick={() => setIsSearchOpen(!isSearchOpen)}>
<Search className="size-5 text-primary" />
</Button>
</DropdownMenuContent>
</DropdownMenu>
)}
<DropdownMenu>
<DropdownMenu modal={false}>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
className="relative group">
<Menu className="size-5 text-primary transition-transform duration-300 group-data-[state=open]:rotate-180" />
<span className="absolute -bottom-1 left-1/2 w-1.5 h-1.5 rounded-full bg-primary transform -translate-x-1/2 scale-0 transition-transform duration-300 group-data-[state=open]:scale-100"></span>
<span className="absolute top-0 right-0 w-1.5 h-1.5 rounded-full bg-primary transform -translate-x-1/2 scale-0 transition-transform duration-300 group-data-[state=open]:scale-100"></span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
className="animate-in slide-in-from-top-5 duration-300 purcarte-blur border-border rounded-xl">
className="purcarte-blur border-border rounded-xl">
<DropdownMenuItem
onClick={() =>
setViewMode(viewMode === "grid" ? "table" : "grid")
@@ -167,8 +173,12 @@ export const Header = ({
<Button
variant="ghost"
size="icon"
className="relative group"
onClick={() => setIsSearchOpen(!isSearchOpen)}>
<Search className="size-5 text-primary" />
{searchTerm && (
<span className="absolute top-0 right-0 w-1.5 h-1.5 rounded-full bg-primary transform -translate-x-1/2"></span>
)}
</Button>
)}
<Button

View File

@@ -0,0 +1,29 @@
@keyframes slideDownAndFade {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideUpAndFade {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(-10px);
}
}
[role="menu"][data-state="open"] {
animation: slideDownAndFade 300ms cubic-bezier(0.16, 1, 0.3, 1);
}
[role="menu"][data-state="closed"] {
animation: slideUpAndFade 300ms cubic-bezier(0.16, 1, 0.3, 1);
}

View File

@@ -1,5 +1,7 @@
import * as React from "react";
import "./dropdown-menu.css";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { Theme } from "@radix-ui/themes";
import { DotFilledIcon } from "@radix-ui/react-icons";
import { cn } from "@/utils";
@@ -43,7 +45,7 @@ const DropdownMenuSubContent = React.forwardRef<
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] purcarte-blur overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
"z-50 min-w-[8rem] purcarte-blur overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md",
className
)}
{...props}
@@ -57,15 +59,17 @@ const DropdownMenuContent = React.forwardRef<
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<DropdownMenuPrimitive.Portal>
<Theme>
<DropdownMenuPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[8rem] purcarte-blur overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
"z-50 min-w-[8rem] purcarte-blur overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md",
className
)}
{...props}
/>
</Theme>
</DropdownMenuPrimitive.Portal>
));
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;

View File

@@ -118,13 +118,20 @@ export const useLoadCharts = (node: NodeData | null, hours: number) => {
}));
let filledData;
if (hours <= 4) {
if (hours === 1) {
filledData = fillMissingTimePoints(
stringifiedData,
minute,
hour,
minute * 2
);
} else if (hours === 4) {
filledData = fillMissingTimePoints(
stringifiedData,
minute,
hour * 4,
minute * 2
);
} else {
const interval = hours > 120 ? hour : minute * 15;
const maxGap = interval * 2;