Files
3x-ui/docs/components/home/features.tsx
T
MHSanaei 9b91f0f42e docs: vendor the documentation site into the monorepo
Fold the standalone 3x-ui-docs project (Next.js 16 + Fumadocs, deployed to
docs.sanaei.dev) into docs/ so the panel and its documentation share a single
source of truth, the way sing-box keeps its docs in-tree. The old repo becomes
redundant and can be retired.

- Import the full site under docs/ (app, components, content, lib, public,
  scripts, config). The self-contained pnpm project sits alongside the existing
  engineering notes with no filename collisions.
- Re-point "Edit on GitHub" links from MHSanaei/3x-ui-docs to this repo's
  docs/content/docs path (docs/lib/shared.ts, docs/app/.../page.tsx).
- Add docs-ci.yml and docs-deploy.yml under .github/workflows/, scoped to
  docs/** and run with working-directory: docs, since GitHub only runs
  workflows from the repo-root .github/. deploy-static.yml's GitHub Pages
  publish (CNAME docs.sanaei.dev) carries over unchanged.

Follow-up (outside this commit): attach the docs.sanaei.dev custom domain to
this repository's Pages (or set the Vercel project's root directory to docs),
confirm the site is live from the monorepo, then delete MHSanaei/3x-ui-docs.
2026-07-07 23:07:14 +02:00

50 lines
1.6 KiB
TypeScript

import {
Boxes,
Network,
Send,
ShieldCheck,
TerminalSquare,
Users,
type LucideIcon,
} from 'lucide-react';
// Icons map by position to the localized feature items in lib/site-i18n.ts
// (Every major protocol, REALITY, Clients, Multi-node, Telegram, Self-hosted).
const ICONS: LucideIcon[] = [Boxes, ShieldCheck, Users, Network, Send, TerminalSquare];
export function Features({
heading,
subtitle,
items,
}: {
heading: string;
subtitle: string;
items: { title: string; description: string }[];
}) {
return (
<section className="mx-auto w-full max-w-6xl px-4 py-16 sm:py-24">
<div className="mx-auto max-w-2xl text-center">
<h2 className="text-2xl font-bold tracking-tight sm:text-3xl">{heading}</h2>
<p className="mt-3 text-fd-muted-foreground">{subtitle}</p>
</div>
<div className="mt-12 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{items.map(({ title, description }, i) => {
const Icon = ICONS[i] ?? Boxes;
return (
<div
key={title}
className="rounded-2xl border bg-fd-card p-6 transition-colors hover:border-fd-primary/40"
>
<div className="inline-flex size-11 items-center justify-center rounded-xl bg-brand/10 text-brand">
<Icon className="size-6" aria-hidden />
</div>
<h3 className="mt-4 font-semibold">{title}</h3>
<p className="mt-2 text-sm text-fd-muted-foreground">{description}</p>
</div>
);
})}
</div>
</section>
);
}