71 lines
2.9 KiB
TypeScript
71 lines
2.9 KiB
TypeScript
"use client";
|
||
|
||
import { ChevronRight } from "lucide-react";
|
||
import { normalizeBrowserReachableHttpUrl } from "@/lib/panelUrls";
|
||
|
||
export type PortalNavTarget =
|
||
| "network"
|
||
| "services"
|
||
| "live_youtube"
|
||
| "live_tiktok"
|
||
| "android";
|
||
|
||
type TFn = (zh: string, en: string) => string;
|
||
|
||
export type PipelineStep = {
|
||
label: string;
|
||
sub?: string;
|
||
gradient: string;
|
||
target?: PortalNavTarget;
|
||
/** 若设置,点击时在新标签打开(优先于 target) */
|
||
openUrl?: string;
|
||
};
|
||
|
||
type Props = {
|
||
t: TFn;
|
||
title: string;
|
||
subtitle: string;
|
||
steps: PipelineStep[];
|
||
onNavigate?: (target: PortalNavTarget) => void;
|
||
};
|
||
|
||
export function LivePipelineStrip({ t, title, subtitle, steps, onNavigate }: Props) {
|
||
return (
|
||
<div className="rounded-2xl border border-violet-500/25 bg-gradient-to-br from-violet-500/10 via-zinc-950/40 to-fuchsia-500/5 p-6 shadow-lg shadow-violet-900/10">
|
||
<h3 className="flex items-center gap-2 text-sm font-semibold text-white">{title}</h3>
|
||
<p className="mt-2 text-xs text-zinc-400">{subtitle}</p>
|
||
<div className="mt-6 flex flex-col items-center gap-4 sm:flex-row sm:flex-wrap sm:justify-center">
|
||
{steps.map((step, i) => (
|
||
<div key={step.label} className="flex items-center gap-4">
|
||
{step.openUrl || (step.target && onNavigate) ? (
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
if (step.openUrl) {
|
||
window.open(normalizeBrowserReachableHttpUrl(step.openUrl), "_blank", "noopener,noreferrer");
|
||
return;
|
||
}
|
||
if (step.target && onNavigate) onNavigate(step.target);
|
||
}}
|
||
className={`flex min-h-[4rem] min-w-[7rem] flex-col items-center justify-center rounded-2xl bg-gradient-to-br px-4 py-2 text-center text-xs font-bold text-white shadow-lg ring-2 ring-white/10 transition hover:ring-violet-400/50 hover:brightness-110 ${step.gradient}`}
|
||
>
|
||
<span>{step.label}</span>
|
||
{step.sub ? <span className="mt-1 text-[10px] font-normal text-white/80">{step.sub}</span> : null}
|
||
</button>
|
||
) : (
|
||
<div
|
||
className={`flex min-h-[4rem] min-w-[7rem] flex-col items-center justify-center rounded-2xl bg-gradient-to-br px-4 py-2 text-center text-xs font-bold text-white shadow-lg ${step.gradient}`}
|
||
>
|
||
<span>{step.label}</span>
|
||
{step.sub ? <span className="mt-1 text-[10px] font-normal text-white/80">{step.sub}</span> : null}
|
||
</div>
|
||
)}
|
||
{i < steps.length - 1 ? <ChevronRight className="hidden h-5 w-5 text-zinc-600 sm:block" aria-hidden /> : null}
|
||
</div>
|
||
))}
|
||
</div>
|
||
<p className="mt-4 text-center text-[10px] text-zinc-600">{t("点击高亮块可跳转到对应功能页", "Tap a highlighted step to open its page")}</p>
|
||
</div>
|
||
);
|
||
}
|