Files
new-api-analytics/components/TimeRangeSelector.tsx
shangzy b719b358f8 feat: API analytics dashboard with i18n and theme support
Next.js full-stack analytics dashboard for new-api.
- Direct PostgreSQL readonly queries on logs table
- 5 pages: Dashboard, Rankings, Aggregation, Logs, Detail
- Dark/Light/System theme with CSS variables
- Chinese/English i18n (default Chinese)
- Recharts with dual Y-axis for input/output tokens
- Lucide icons + Motion animations
- Docker + docker-compose with external sinobridge network, port 8019
2026-04-02 12:47:50 +08:00

42 lines
1.4 KiB
TypeScript

"use client";
import { type TimeRange } from "@/lib/utils";
import { useI18n } from "@/lib/i18n";
import { motion } from "motion/react";
export function TimeRangeSelector({
value,
onChange,
}: {
value: TimeRange;
onChange: (v: TimeRange) => void;
}) {
const { t } = useI18n();
const ranges: { label: string; value: TimeRange }[] = [
{ label: t("time.today"), value: "today" },
{ label: t("time.7d"), value: "7d" },
{ label: t("time.30d"), value: "30d" },
{ label: t("time.all"), value: "all" },
];
return (
<div className="flex gap-1 rounded-lg p-1" style={{ background: "var(--row-hover)", border: "1px solid var(--surface-border)" }}>
{ranges.map((r) => (
<button key={r.value} onClick={() => onChange(r.value)}
className="relative px-3 py-1.5 text-xs font-medium rounded-md transition-colors"
style={{ color: value === r.value ? "var(--text-accent)" : "var(--text-muted)" }}
>
{value === r.value && (
<motion.div layoutId="time-range-bg"
className="absolute inset-0 rounded-md"
style={{ background: "var(--btn-active-bg)", border: "1px solid var(--surface-border)" }}
transition={{ type: "spring", stiffness: 400, damping: 30 }}
/>
)}
<span className="relative z-10">{r.label}</span>
</button>
))}
</div>
);
}