Files
Sankofa/portal/src/components/preview/FeaturePreviewPage.tsx
defiQUG 456cc613b7
Some checks failed
API CI / API Lint (push) Successful in 53s
API CI / API Type Check (push) Failing after 51s
API CI / API Test (push) Successful in 1m32s
API CI / API Build (push) Failing after 1m0s
API CI / Build Docker Image (push) Has been skipped
CD Pipeline / Deploy to Staging (push) Failing after 32s
CI Pipeline / Lint and Type Check (push) Failing after 33s
CI Pipeline / Build (push) Has been skipped
CI Pipeline / Test Backend (push) Failing after 2m1s
CI Pipeline / Test Frontend (push) Failing after 35s
CI Pipeline / Security Scan (push) Failing after 1m12s
Deploy to Staging / Deploy to Staging (push) Failing after 28s
Portal CI / Portal Lint (push) Failing after 19s
Portal CI / Portal Type Check (push) Failing after 18s
Portal CI / Portal Test (push) Failing after 19s
Portal CI / Portal Build (push) Failing after 18s
Test Suite / frontend-tests (push) Failing after 30s
Test Suite / api-tests (push) Failing after 44s
Test Suite / blockchain-tests (push) Failing after 27s
Type Check / type-check (map[directory:. name:root]) (push) Failing after 18s
Type Check / type-check (map[directory:api name:api]) (push) Failing after 19s
Type Check / type-check (map[directory:portal name:portal]) (push) Failing after 18s
CD Pipeline / Deploy to Production (push) Has been skipped
fix(portal): corporate landing SEO, favicon, and public home UX
Add sankofa.nexus marketing site with institutional grade scorecards,
server-side metadata/title, dynamic icons, favicon rewrite, and instant
landing render without session-loading flash; split authenticated AppShell
from unauthenticated corporate chrome.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-11 01:27:05 -07:00

82 lines
2.7 KiB
TypeScript

'use client';
import Link from 'next/link';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/Card';
import { cn } from '@/lib/utils';
interface PreviewAction {
href: string;
label: string;
}
interface FeaturePreviewPageProps {
eyebrow: string;
title: string;
description: string;
status?: 'preview' | 'request-only' | 'active';
bullets: readonly string[];
primaryAction?: PreviewAction;
secondaryAction?: PreviewAction;
}
export function FeaturePreviewPage({
eyebrow,
title,
description,
status = 'preview',
bullets,
primaryAction,
secondaryAction,
}: FeaturePreviewPageProps) {
const primaryActionClassName =
'inline-flex h-10 items-center justify-center rounded-md bg-gray-700 px-4 text-base font-medium text-white transition-colors hover:bg-gray-600';
const secondaryActionClassName =
'inline-flex h-10 items-center justify-center rounded-md border border-gray-600 bg-transparent px-4 text-base font-medium text-white transition-colors hover:bg-gray-800';
return (
<div className="mx-auto max-w-4xl px-4 py-10">
<div className="mb-8">
<p className="mb-2 text-sm font-medium uppercase tracking-wide text-orange-400">{eyebrow}</p>
<div className="mb-3 flex items-center gap-3">
<h1 className="text-3xl font-bold text-white">{title}</h1>
<Badge variant={status === 'active' ? 'default' : 'secondary'}>
{status === 'request-only' ? 'Request Only' : status === 'active' ? 'Active' : 'Preview'}
</Badge>
</div>
<p className="max-w-3xl text-gray-400">{description}</p>
</div>
<Card className="border-gray-800 bg-gray-900/70">
<CardHeader>
<CardTitle className="text-white">Current Scope</CardTitle>
<CardDescription>
This route is now real and intentionally describes the supported boundary for this workspace area.
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<ul className="space-y-2 text-sm text-gray-300">
{bullets.map((bullet) => (
<li key={bullet}> {bullet}</li>
))}
</ul>
<div className="flex flex-col gap-3 pt-2 sm:flex-row">
{primaryAction ? (
<Link href={primaryAction.href} className={cn(primaryActionClassName)}>
{primaryAction.label}
</Link>
) : null}
{secondaryAction ? (
<Link href={secondaryAction.href} className={cn(secondaryActionClassName)}>
{secondaryAction.label}
</Link>
) : null}
</div>
</CardContent>
</Card>
</div>
);
}