fix: force dark mode on auth/home, add grid texture and glow to homepage
Docker Build / Build and Push Docker Image (push) Successful in 4m3s
Docker Build / Build and Push Docker Image (push) Successful in 4m3s
This commit is contained in:
+1
-1
@@ -30,7 +30,7 @@ export function AuthLayout({ children }: AuthLayoutProps) {
|
||||
const { systemName, logo, loading } = useSystemConfig()
|
||||
|
||||
return (
|
||||
<div className='relative grid h-svh max-w-none bg-[#0A0E14]'>
|
||||
<div className='dark relative grid h-svh max-w-none bg-[#0A0E14]'>
|
||||
<Link
|
||||
to='/'
|
||||
className='absolute top-4 left-4 z-10 flex items-center gap-2 transition-opacity hover:opacity-80 sm:top-8 sm:left-8'
|
||||
|
||||
+93
-26
@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
For commercial licensing, please contact admin@modelstoken.com
|
||||
*/
|
||||
import { Link } from '@tanstack/react-router'
|
||||
import { ArrowRight } from 'lucide-react'
|
||||
import { ArrowRight, Zap, Shield, Layers, BarChart3, Key, GitBranch } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useStatus } from '@/hooks/use-status'
|
||||
import { Button } from '@/components/ui/button'
|
||||
@@ -32,6 +32,7 @@ const T = {
|
||||
surface: '#0F1419',
|
||||
border: '#1A1F29',
|
||||
accent: '#00D2FF',
|
||||
accentDim: '#0099BB',
|
||||
green: '#28C840',
|
||||
yellow: '#FEBC2E',
|
||||
gray: '#5C6370',
|
||||
@@ -40,6 +41,15 @@ const T = {
|
||||
red: '#FF5F57',
|
||||
}
|
||||
|
||||
const features = [
|
||||
{ icon: Zap, title: 'Multi-model Routing', desc: 'Intelligent routing with automatic failover and load balancing' },
|
||||
{ icon: Key, title: 'Key Management', desc: 'Centralized API key lifecycle management with usage tracking' },
|
||||
{ icon: Shield, title: 'Access Control', desc: 'Fine-grained permissions, rate limiting, and token policies' },
|
||||
{ icon: BarChart3, title: 'Real-time Monitoring', desc: 'Live dashboards with request latency and cost analytics' },
|
||||
{ icon: Layers, title: 'OpenAI Compatible', desc: 'Drop-in replacement for OpenAI API with zero code changes' },
|
||||
{ icon: GitBranch, title: 'Model Mapping', desc: 'Map model names and customize per-channel behavior' },
|
||||
]
|
||||
|
||||
export function Hero(props: HeroProps) {
|
||||
const { t } = useTranslation()
|
||||
const { status } = useStatus()
|
||||
@@ -49,22 +59,33 @@ export function Hero(props: HeroProps) {
|
||||
|
||||
return (
|
||||
<section className='relative overflow-hidden' style={{ backgroundColor: T.bg }}>
|
||||
{/* Subtle top glow */}
|
||||
{/* Grid background texture */}
|
||||
<div
|
||||
aria-hidden
|
||||
className='pointer-events-none absolute inset-0 opacity-[0.03]'
|
||||
style={{
|
||||
backgroundImage:
|
||||
'linear-gradient(rgba(0,210,255,0.5) 1px, transparent 1px), linear-gradient(90deg, rgba(0,210,255,0.5) 1px, transparent 1px)',
|
||||
backgroundSize: '64px 64px',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Top glow */}
|
||||
<div
|
||||
aria-hidden
|
||||
className='pointer-events-none absolute inset-0'
|
||||
style={{
|
||||
background:
|
||||
'radial-gradient(ellipse 40% 25% at 50% 0%, rgba(0,210,255,0.06) 0%, transparent 70%)',
|
||||
'radial-gradient(ellipse 50% 40% at 50% 0%, rgba(0,210,255,0.08) 0%, transparent 70%)',
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className='relative mx-auto max-w-4xl px-6'>
|
||||
<div className='relative mx-auto max-w-5xl px-6'>
|
||||
{/* ── Hero ── */}
|
||||
<div className='flex min-h-[calc(100svh-3rem)] flex-col items-center justify-center py-20 text-center'>
|
||||
{/* Headline */}
|
||||
<h1
|
||||
className='max-w-xl text-[clamp(2.4rem,7vw,4.5rem)] leading-[1] font-bold tracking-[-0.04em]'
|
||||
className='max-w-2xl text-[clamp(2.2rem,6vw,4.2rem)] leading-[1.05] font-bold tracking-[-0.03em]'
|
||||
style={{ color: T.white }}
|
||||
>
|
||||
{t('Unified LLM')}{' '}
|
||||
@@ -72,12 +93,12 @@ export function Hero(props: HeroProps) {
|
||||
</h1>
|
||||
|
||||
{/* Subtitle */}
|
||||
<p className='mt-6 max-w-sm text-[15px] leading-relaxed' style={{ color: T.grayLight }}>
|
||||
<p className='mt-5 max-w-md text-[15px] leading-relaxed' style={{ color: T.grayLight }}>
|
||||
{t('One endpoint for all models. OpenAI-compatible, switch and go.')}
|
||||
</p>
|
||||
|
||||
{/* CTA */}
|
||||
<div className='mt-10 flex items-center gap-4'>
|
||||
<div className='mt-9 flex items-center gap-4'>
|
||||
{props.isAuthenticated ? (
|
||||
<Button
|
||||
className='group h-11 rounded-lg px-7 text-sm font-semibold hover:opacity-90'
|
||||
@@ -112,43 +133,43 @@ export function Hero(props: HeroProps) {
|
||||
</div>
|
||||
|
||||
{/* ── Terminal demo ── */}
|
||||
<div className='-mt-4 pb-28'>
|
||||
<div className='-mt-6 pb-24'>
|
||||
<div
|
||||
className='mx-auto w-full max-w-xl overflow-hidden rounded-xl border'
|
||||
style={{ borderColor: T.border, backgroundColor: T.surface }}
|
||||
className='mx-auto w-full max-w-2xl overflow-hidden rounded-xl border'
|
||||
style={{ borderColor: T.border, backgroundColor: T.surface, boxShadow: '0 0 80px -20px rgba(0,210,255,0.1)' }}
|
||||
>
|
||||
{/* Terminal header */}
|
||||
<div className='flex items-center gap-2 border-b px-4 py-2' style={{ borderColor: T.border }}>
|
||||
<div className='flex items-center gap-2 border-b px-4 py-2.5' style={{ borderColor: T.border }}>
|
||||
<div className='flex gap-1.5'>
|
||||
<div className='size-2 rounded-full' style={{ backgroundColor: T.red }} />
|
||||
<div className='size-2 rounded-full' style={{ backgroundColor: T.yellow }} />
|
||||
<div className='size-2 rounded-full' style={{ backgroundColor: T.green }} />
|
||||
<div className='size-2.5 rounded-full' style={{ backgroundColor: T.red }} />
|
||||
<div className='size-2.5 rounded-full' style={{ backgroundColor: T.yellow }} />
|
||||
<div className='size-2.5 rounded-full' style={{ backgroundColor: T.green }} />
|
||||
</div>
|
||||
<span className='ml-2 text-[10px]' style={{ color: T.gray }}>bash</span>
|
||||
<span className='ml-2 text-[11px]' style={{ color: T.gray }}>bash — api</span>
|
||||
</div>
|
||||
{/* Terminal content */}
|
||||
<div className='p-4 font-mono text-[12px] leading-[2]'>
|
||||
<div className='p-5 font-mono text-[13px] leading-[1.85]'>
|
||||
<div>
|
||||
<span style={{ color: T.accent }}>$</span>{' '}
|
||||
<span style={{ color: T.white }}>curl</span>{' '}
|
||||
<span style={{ color: T.accent }}>{serverAddress}/v1/chat/completions</span>{' '}
|
||||
<span style={{ color: T.gray }}>\</span>
|
||||
</div>
|
||||
<div className='pl-4'>
|
||||
<div className='pl-5'>
|
||||
<span style={{ color: T.gray }}>-H</span>{' '}
|
||||
<span style={{ color: T.yellow }}>"Authorization: Bearer sk-..."</span>{' '}
|
||||
<span style={{ color: T.gray }}>\</span>
|
||||
</div>
|
||||
<div className='pl-4'>
|
||||
<div className='pl-5'>
|
||||
<span style={{ color: T.gray }}>-d</span>{' '}
|
||||
<span style={{ color: T.yellow }}>{"'{ \"model\": \"gpt-4o\" }'"}</span>
|
||||
<span style={{ color: T.yellow }}>{"'{ \"model\": \"gpt-4o\", \"messages\": [...] }'"}</span>
|
||||
</div>
|
||||
|
||||
<div className='mt-4 border-t pt-3' style={{ borderColor: T.border }}>
|
||||
<div className='flex items-center gap-2 mb-2'>
|
||||
<div className='mt-5 border-t pt-4' style={{ borderColor: T.border }}>
|
||||
<div className='flex items-center gap-2 mb-3'>
|
||||
<span className='inline-block size-1.5 rounded-full' style={{ backgroundColor: T.green }} />
|
||||
<span className='text-[10px] font-medium' style={{ color: T.gray }}>200</span>
|
||||
<span className='text-[10px]' style={{ color: T.gray }}>312ms</span>
|
||||
<span className='text-[11px] font-medium' style={{ color: T.gray }}>200 OK</span>
|
||||
<span className='text-[11px]' style={{ color: T.gray }}>312ms</span>
|
||||
</div>
|
||||
<div>
|
||||
<span style={{ color: T.gray }}>{"{"}</span>
|
||||
@@ -158,17 +179,63 @@ export function Hero(props: HeroProps) {
|
||||
<span style={{ color: T.gray }}>,</span>
|
||||
<span style={{ color: T.accent }}> "usage"</span>
|
||||
<span style={{ color: T.gray }}>:</span>
|
||||
<span style={{ color: T.gray }}> {"{...}"} </span>
|
||||
<span style={{ color: T.gray }}> {"{ \"prompt_tokens\": 12, \"completion_tokens\": 47 }"}</span>
|
||||
<span style={{ color: T.gray }}>{"}"}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-2'>
|
||||
<div className='mt-3'>
|
||||
<span style={{ color: T.accent }}>$</span>
|
||||
<span className='ml-1 inline-block h-3 w-[6px] animate-pulse align-middle' style={{ backgroundColor: T.accent }} />
|
||||
<span className='ml-1 inline-block h-3.5 w-[7px] animate-pulse align-middle' style={{ backgroundColor: T.accent }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Features ── */}
|
||||
<div className='pb-28'>
|
||||
<div className='mb-14 text-center'>
|
||||
<h2 className='text-xl font-semibold tracking-tight' style={{ color: T.white }}>
|
||||
{t('Full-featured gateway')}
|
||||
</h2>
|
||||
<p className='mt-2 text-sm' style={{ color: T.grayLight }}>
|
||||
{t('Everything you need to manage, route, and monitor LLM API traffic')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='grid gap-4 sm:grid-cols-2 lg:grid-cols-3'>
|
||||
{features.map((feature) => (
|
||||
<div
|
||||
key={feature.title}
|
||||
className='group rounded-lg border p-5 transition-all duration-200'
|
||||
style={{
|
||||
borderColor: T.border,
|
||||
backgroundColor: T.surface,
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.borderColor = T.accentDim
|
||||
e.currentTarget.style.boxShadow = '0 0 24px -8px rgba(0,210,255,0.15)'
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.borderColor = T.border
|
||||
e.currentTarget.style.boxShadow = 'none'
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className='mb-3 flex size-9 items-center justify-center rounded-md'
|
||||
style={{ backgroundColor: `${T.accent}10` }}
|
||||
>
|
||||
<feature.icon className='size-4' style={{ color: T.accent }} />
|
||||
</div>
|
||||
<h3 className='text-sm font-semibold' style={{ color: T.white }}>
|
||||
{t(feature.title)}
|
||||
</h3>
|
||||
<p className='mt-1.5 text-[13px] leading-relaxed' style={{ color: T.gray }}>
|
||||
{t(feature.desc)}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
|
||||
+5
-3
@@ -62,8 +62,10 @@ export function Home() {
|
||||
|
||||
return (
|
||||
<PublicLayout showMainContainer={false}>
|
||||
<Hero isAuthenticated={isAuthenticated} />
|
||||
<Footer />
|
||||
</PublicLayout>
|
||||
<div className='dark'>
|
||||
<Hero isAuthenticated={isAuthenticated} />
|
||||
<Footer />
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user