Update environment configuration and enhance Docker setup for production deployment
- Changed NODE_ENV from development to production in .env.example for production readiness. - Updated WEBUI_URL to point to the new public URL behind Traefik. - Added internal and external networks in docker-compose.yml for improved service isolation and routing. - Removed direct port exposure for the WebUI, ensuring it is only accessible through Traefik. - Refactored landing and login pages in the WebUI to streamline navigation and error handling, redirecting users appropriately based on session status.
This commit is contained in:
117
apps/webui/src/archived/landing-page.tsx
Normal file
117
apps/webui/src/archived/landing-page.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Archived marketing landing page (Phase 8).
|
||||
* Replaced by the login screen at `/` for the dashboard.nexumi.de deploy.
|
||||
* A separate public landing will live on nexumi.de later.
|
||||
* This file is not an App Router page and is not served.
|
||||
*/
|
||||
import { DASHBOARD_MODULES, type DashboardModuleGroup } from '@nexumi/shared';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { SiteShell } from '@/components/site/site-shell';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { buildBotInviteUrl, env } from '@/lib/env';
|
||||
import { getLocale, t } from '@/lib/i18n';
|
||||
import { getPublicStats } from '@/lib/public-stats';
|
||||
import { getSession } from '@/lib/session';
|
||||
|
||||
const GROUP_ORDER: DashboardModuleGroup[] = [
|
||||
'moderation',
|
||||
'engagement',
|
||||
'community',
|
||||
'utility',
|
||||
'integrations'
|
||||
];
|
||||
|
||||
export default async function ArchivedLandingPage() {
|
||||
const [locale, stats, session] = await Promise.all([getLocale(), getPublicStats(), getSession()]);
|
||||
const inviteUrl = buildBotInviteUrl();
|
||||
const isLoggedIn = Boolean(session);
|
||||
|
||||
return (
|
||||
<SiteShell>
|
||||
<section className="border-b border-border">
|
||||
<div className="mx-auto flex w-full max-w-[1200px] flex-col gap-8 px-6 py-16 sm:py-20">
|
||||
<div className="flex items-center gap-3">
|
||||
<Image src="/nexumi-logo.svg" alt="" width={48} height={48} priority />
|
||||
<h1 className="text-4xl font-semibold tracking-tight sm:text-5xl">Nexumi</h1>
|
||||
</div>
|
||||
<p className="max-w-2xl text-lg text-muted-foreground">{t(locale, 'landing.hero.subtitle')}</p>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<Button asChild size="lg">
|
||||
<a href={inviteUrl} target="_blank" rel="noreferrer">
|
||||
{t(locale, 'landing.hero.invite')}
|
||||
</a>
|
||||
</Button>
|
||||
<Button asChild size="lg" variant="secondary">
|
||||
<Link href={isLoggedIn ? '/dashboard' : '/login'}>
|
||||
{isLoggedIn ? t(locale, 'landing.hero.dashboard') : t(locale, 'landing.hero.login')}
|
||||
</Link>
|
||||
</Button>
|
||||
{env.SUPPORT_SERVER_URL ? (
|
||||
<Button asChild size="lg" variant="outline">
|
||||
<a href={env.SUPPORT_SERVER_URL} target="_blank" rel="noreferrer">
|
||||
{t(locale, 'landing.hero.support')}
|
||||
</a>
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="border-b border-border">
|
||||
<div className="mx-auto grid w-full max-w-[1200px] gap-4 px-6 py-12 sm:grid-cols-2">
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">
|
||||
{t(locale, 'landing.stats.guilds')}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="text-3xl font-semibold">{stats.guildCount.toLocaleString(locale)}</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">
|
||||
{t(locale, 'landing.stats.users')}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="text-3xl font-semibold">
|
||||
{stats.approximateUserCount.toLocaleString(locale)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div className="mx-auto w-full max-w-[1200px] space-y-8 px-6 py-12">
|
||||
<div>
|
||||
<h2 className="text-2xl font-semibold">{t(locale, 'landing.features.title')}</h2>
|
||||
<p className="mt-2 text-muted-foreground">{t(locale, 'landing.features.subtitle')}</p>
|
||||
</div>
|
||||
{GROUP_ORDER.map((group) => {
|
||||
const modules = DASHBOARD_MODULES.filter((module) => module.group === group);
|
||||
return (
|
||||
<div key={group} className="space-y-3">
|
||||
<h3 className="text-sm font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
{t(locale, `moduleGroups.${group}`)}
|
||||
</h3>
|
||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{modules.map((module) => (
|
||||
<Card key={module.id}>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-base">{t(locale, `modules.${module.id}.label`)}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="text-sm text-muted-foreground">
|
||||
{t(locale, `modules.${module.id}.description`)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
</SiteShell>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user