www_site/components/ui.tsx

45 lines
3.2 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 Link from "next/link";
import { ArrowRight, ArrowUpRight, CheckIcon } from "@/components/icons";
export function DevPlaceholder({ children = "开发占位" }: { children?: React.ReactNode }) {
return <span className="inline-flex items-center rounded-full border border-warning/30 bg-warning/10 px-2.5 py-1 text-[0.68rem] font-semibold tracking-wide text-warning">{children}</span>;
}
export function SectionHeading({ eyebrow, title, description, tone = "orange" }: { eyebrow: string; title: string; description?: string; tone?: "orange" | "blue" | "cyan" }) {
return (
<div className="max-w-2xl">
<p className={`eyebrow ${tone === "blue" ? "eyebrow-blue" : tone === "cyan" ? "eyebrow-cyan" : ""}`}>{eyebrow}</p>
<h2 className="text-balance mt-5 text-3xl font-semibold tracking-[-0.04em] text-copy sm:text-5xl">{title}</h2>
{description ? <p className="body-copy mt-5 max-w-xl text-base">{description}</p> : null}
</div>
);
}
export function ArrowLink({ href, children, external = false }: { href: string; children: React.ReactNode; external?: boolean }) {
return <Link className="inline-flex items-center gap-2 text-sm font-semibold text-cyan transition-colors hover:text-copy" href={href}>{children}{external ? <ArrowUpRight /> : <ArrowRight />}</Link>;
}
export function ProductVisual({ accent = "orange", label = "PRODUCT CONCEPT" }: { accent?: "orange" | "blue"; label?: string }) {
return (
<div aria-label="开发占位产品视觉,不代表真实产品" className="product-visual">
<div className={`absolute left-8 top-8 h-24 w-44 rounded-[2rem] border ${accent === "orange" ? "border-orange/70 shadow-[0_0_60px_rgba(255,106,0,0.14)]" : "border-blue/70 shadow-[0_0_60px_rgba(22,119,255,0.18)]"} bg-ink/80 sm:h-32 sm:w-60`} />
<div className={`absolute left-20 top-20 h-16 w-24 rounded-full border ${accent === "orange" ? "border-orange/60" : "border-blue/60"} bg-panel/80 sm:left-32 sm:top-28 sm:h-20 sm:w-36`} />
<span className="absolute bottom-5 left-6 text-[0.62rem] font-semibold tracking-[0.24em] text-subtle">{label}</span>
<DevPlaceholder />
</div>
);
}
export function PreviewNotice({ children = "当前为 Phase 1 界面预览,真实业务将在后续阶段接入。" }: { children?: React.ReactNode }) {
return <div className="rounded-xl border border-warning/25 bg-warning/8 px-4 py-3 text-sm leading-6 text-warning" role="status"><span className="font-semibold"></span>{children}</div>;
}
export function StatusCard({ title, description, tone = "neutral" }: { title: string; description: string; tone?: "neutral" | "info" | "warning" | "success" }) {
const styles = { neutral: "border-line bg-panel", info: "border-blue/25 bg-blue/8", warning: "border-warning/25 bg-warning/8", success: "border-success/25 bg-success/8" };
return <div className={`rounded-xl border p-4 ${styles[tone]}`}><p className="font-semibold text-copy">{title}</p><p className="mt-2 text-sm leading-6 text-muted">{description}</p></div>;
}
export function FeatureList({ items }: { items: string[] }) {
return <ul className="space-y-3">{items.map((item) => <li className="flex gap-3 text-sm leading-6 text-muted" key={item}><span className="mt-1 text-cyan"><CheckIcon /></span><span>{item}</span></li>)}</ul>;
}