Marketing site (bargevasat.ir) + admin-editable store links + subdomain split
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 4m40s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m7s
CI/CD / Deploy - local stack (db + server + web) (push) Failing after 41s

- New standalone Next.js marketing site under site/ (static export, SEO):
  landing, download/install guide (Bazaar/Myket/iOS-PWA/web), FAQ (JSON-LD),
  privacy, terms, support, /admin link editor. fa RTL, sitemap/robots/manifest.
- Backend: SiteLinksService (JSON-file persisted) + GET /api/site/links (public)
  + POST /api/admin/site/links (X-Admin-Token). ADMIN_TOKEN + Site__DataDir via env.
- compose: hokm-site service (:1520) + hokm_data volume for links JSON.
- CI deploy job builds + deploys the site container.
- deploy/SUBDOMAIN_SPLIT.md: nginx blocks, cert reissue, DNS, ENV split.
- Exclude site/ from root tsc + web docker context.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-08 07:19:43 +03:30
parent 8d0d4dc991
commit 5d38312ef0
39 changed files with 8207 additions and 2 deletions
+72
View File
@@ -0,0 +1,72 @@
"use client";
import { useState } from "react";
import Link from "next/link";
import { Menu, X, Play } from "lucide-react";
import { Logo } from "./Logo";
import { APP_URL, BRAND } from "@/lib/site";
const NAV = [
{ href: "/#features", label: "ویژگی‌ها" },
{ href: "/download", label: "دانلود و نصب" },
{ href: "/faq", label: "سوال‌ها" },
{ href: "/support", label: "پشتیبانی" },
];
export function Nav() {
const [open, setOpen] = useState(false);
return (
<header className="sticky top-0 z-50 glass">
<nav className="mx-auto flex max-w-6xl items-center justify-between gap-4 px-4 py-3">
<Link href="/" className="flex items-center gap-2">
<Logo size={34} />
<span className="text-lg font-extrabold gold-text">{BRAND.nameFa}</span>
</Link>
<div className="hidden items-center gap-6 md:flex">
{NAV.map((n) => (
<Link key={n.href} href={n.href} className="text-sm text-cream/80 hover:text-cream">
{n.label}
</Link>
))}
</div>
<div className="flex items-center gap-2">
<a
href={APP_URL}
className="hidden items-center gap-1.5 rounded-xl btn-gold px-4 py-2 text-sm sm:flex"
>
<Play size={16} /> بازی در مرورگر
</a>
<button
className="rounded-lg p-2 text-cream md:hidden"
onClick={() => setOpen((v) => !v)}
aria-label="منو"
>
{open ? <X size={22} /> : <Menu size={22} />}
</button>
</div>
</nav>
{open && (
<div className="border-t border-gold/10 px-4 pb-4 md:hidden">
<div className="flex flex-col gap-1 pt-2">
{NAV.map((n) => (
<Link
key={n.href}
href={n.href}
onClick={() => setOpen(false)}
className="rounded-lg px-3 py-2 text-cream/85 hover:bg-navy-800"
>
{n.label}
</Link>
))}
<a href={APP_URL} className="mt-2 flex items-center justify-center gap-1.5 rounded-xl btn-gold px-4 py-2.5">
<Play size={16} /> بازی در مرورگر
</a>
</div>
</div>
)}
</header>
);
}