Files
juip-web/src/components/productDropdown.tsx

185 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useNavigate } from "react-router-dom"
import { cn } from "@/lib/utils"
const SIZE_STYLES = {
lg: {
wrap: "space-y-4",
grid: "grid-cols-3 gap-4",
card: "gap-3 p-3",
title: "text-sm",
titleGap: "gap-2",
desc: "text-xs mt-1",
tag: "px-2 py-0.5",
footer: "gap-3 pt-3",
footerLink: "text-sm",
},
sm: {
wrap: "space-y-3",
grid: "grid-cols-3 gap-3",
card: "gap-2 p-2",
title: "text-xs",
titleGap: "gap-1.5",
desc: "text-[11px] mt-0.5",
tag: "px-1.5 py-0.5",
footer: "gap-2 pt-2",
footerLink: "text-xs",
},
} as const
export default function ProductDropdown({
size = "lg",
onNavigate,
}: {
size?: keyof typeof SIZE_STYLES
onNavigate?: () => void
}) {
const navigate = useNavigate()
const s = SIZE_STYLES[size]
const handleClick = (path: string) => {
navigate(path)
onNavigate?.()
}
return (
<div className={s.wrap}>
<div className={cn("grid", s.grid)}>
<ProductCard
size={s}
title="动静态IP"
desc="千万级动态短效IP,自动去重,高并发采集"
tag="热门"
onClick={() => handleClick("/product")}
/>
<ProductCard
size={s}
title="新HTTP/S5"
desc="IP可用时长从数小时到365天全覆盖"
tag="稳定"
onClick={() => window.open("https://lanhuip.com", "_blank")}
/>
<ProductCard
size={s}
title="HTTP/S5"
desc="海量全球住宅优质IP,4G/5G真实手机IP"
tag="全球"
onClick={() => handleClick("/product/http")}
/>
<ProductCard
size={s}
title="软路由成本价"
desc="云端自动切换IP,更易于调用与开发"
onClick={() => handleClick("/product/routeros")}
/>
<ProductCard
size={s}
title="动态Vps"
desc="IP独享,高带宽,灵活控制存活周期"
onClick={() => window.open("http://vps.juip.com", "_blank")}
/>
</div>
<div
className={cn(
"flex items-center flex-wrap border-t border-gray-100",
s.footer,
)}
>
<span className="text-xs font-medium text-gray-400">热门推荐:</span>
<button
onClick={() => handleClick("/product")}
className={cn(
"text-blue-600 hover:underline whitespace-nowrap",
s.footerLink,
)}
>
短效代理
</button>
<button
onClick={() => handleClick("/product?tab=global")}
className={cn(
"text-blue-600 hover:underline whitespace-nowrap",
s.footerLink,
)}
>
海外代理
</button>
<button
onClick={() => handleClick("/product?tab=tunnel")}
className={cn(
"text-blue-600 hover:underline whitespace-nowrap",
s.footerLink,
)}
>
隧道代理
</button>
<span className="text-xs text-gray-300">|</span>
<button
onClick={() => handleClick("/product")}
className={cn(
"text-orange-500 hover:underline font-medium whitespace-nowrap",
s.footerLink,
)}
>
业务定制 →
</button>
</div>
</div>
)
}
function ProductCard({
size,
title,
desc,
tag,
onClick,
}: {
size: (typeof SIZE_STYLES)[keyof typeof SIZE_STYLES]
title: string
desc: string
tag?: string
onClick: () => void
}) {
return (
<button
onClick={onClick}
className={cn(
"group flex items-start rounded-lg hover:bg-gray-50 transition-all cursor-pointer border border-transparent hover:border-blue-200 text-left w-full",
size.card,
)}
>
<div className="flex-1 min-w-0">
<div className={cn("flex items-center flex-wrap", size.titleGap)}>
<span
className={cn(
"font-medium text-gray-800 group-hover:text-blue-600 transition-colors whitespace-nowrap",
size.title,
)}
>
{title}
</span>
{tag && (
<span
className={cn(
"text-[10px] bg-blue-100 text-blue-600 rounded-full shrink-0",
size.tag,
)}
>
{tag}
</span>
)}
</div>
<p
className={cn(
"text-gray-500 leading-relaxed line-clamp-2",
size.desc,
)}
>
{desc}
</p>
</div>
</button>
)
}