import { Switch } from "@/components/ui/switch"
import { Download, Star, Zap } from "lucide-react"
import { navigate } from "vike/client/router"
function getGitHubStarsBadgeUrl(repoUrl?: string): string | null {
if (!repoUrl) return null
try {
const url = new URL(repoUrl)
if (url.hostname === "github.com" || url.hostname === "www.github.com") {
const pathParts = url.pathname.split("/").filter(Boolean)
if (pathParts.length >= 2) {
const owner = pathParts[0]
const repo = pathParts[1]
return `https://img.shields.io/github/stars/${owner}/${repo}?style=flat&logo=github&logoColor=white&labelColor=rgb(0,0,0,0)&color=rgb(30,30,30)&label=★`
}
}
} catch {
// Invalid URL, return null
}
return null
}
interface PluginCardBaseProps {
id: string
name: string
description: string
imageUrl?: string
featured?: boolean
repo?: string
homepage?: string
version?: string
downloads?: number
stars?: number
flashCount?: number
incompatibleReason?: string
prominent?: boolean
}
interface PluginCardToggleProps extends PluginCardBaseProps {
variant: "toggle"
isEnabled: boolean
onToggle: (enabled: boolean) => void
disabled?: boolean
enabledLabel?: string
}
interface PluginCardLinkProps extends PluginCardBaseProps {
variant: "link"
href?: string
}
interface PluginCardLinkToggleProps extends PluginCardBaseProps {
variant: "link-toggle"
isEnabled: boolean
onToggle: (enabled: boolean) => void
disabled?: boolean
enabledLabel?: string
}
type PluginCardProps = PluginCardToggleProps | PluginCardLinkProps | PluginCardLinkToggleProps
export function PluginCard(props: PluginCardProps) {
const {
id,
name,
description,
imageUrl,
featured = false,
repo,
homepage,
version,
downloads,
stars,
flashCount,
incompatibleReason,
prominent = false,
} = props
const starsBadgeUrl = getGitHubStarsBadgeUrl(repo)
const isIncompatible = !!incompatibleReason
const isToggle = props.variant === "toggle"
const isLink = props.variant === "link"
const isLinkToggle = props.variant === "link-toggle"
const cardContent = (
<>
{isToggle ? (
<>
{/* Toggle layout: horizontal with switch on right */}
{name}
{featured && }
{description}
{isIncompatible && incompatibleReason && (
{incompatibleReason}
)}
{/* Metadata in bottom right for toggle */}
{version &&
v{version}}
{flashCount !== undefined && (
)}
>
) : (
<>
{/* Link/link-toggle layout: vertical with image */}
{imageUrl && (

)}
{name}
{featured &&
(isLinkToggle ? (
) : (
Featured
))}
{description}
{isIncompatible && incompatibleReason && (
{incompatibleReason}
)}
{/* Metadata row */}
{version &&
v{version}}
{isLinkToggle && flashCount !== undefined && (
)}
{isLink && downloads !== undefined && (
{downloads.toLocaleString()}
)}
{homepage &&
homepage !== repo &&
(isLink || isLinkToggle) &&
(isLink ? (
) : (
e.stopPropagation()}
className="hover:opacity-80 transition-opacity"
>
))}
{starsBadgeUrl &&
repo &&
(isLink ? (
) : (
e.stopPropagation()}
className="hover:opacity-80 transition-opacity"
>
))}
{/* Build Now button - absolutely positioned in lower right */}
{isLink && (
)}
{/* Toggle switch - absolutely positioned in lower right */}
{isLinkToggle && (
)}
>
)}
>
)
const baseClassName = `relative flex ${isToggle ? "items-start gap-4" : "flex-col gap-3"} p-4 rounded-lg border-2 transition-colors h-full ${
isIncompatible
? "border-slate-800 bg-slate-900/30 opacity-60 cursor-not-allowed"
: prominent
? "border-cyan-400 bg-gradient-to-br from-cyan-500/30 via-cyan-600/20 to-blue-600/30 hover:from-cyan-500/40 hover:via-cyan-600/30 hover:to-blue-600/40 hover:border-cyan-300 shadow-xl shadow-cyan-500/30"
: "border-slate-700 bg-slate-900/50 hover:border-slate-600"
} ${isLink ? "group" : ""}`
if (isLink) {
const href = props.href || `/builds?plugin=${id}`
return (
{cardContent}
)
}
return {cardContent}
}
// Export convenience wrappers for backward compatibility
export function PluginToggle(props: Omit) {
return
}