design: apply Termius theme across all pages (light+dark)
Docker Build / Build and Push Docker Image (push) Successful in 4m8s
Docker Build / Build and Push Docker Image (push) Successful in 4m8s
This commit is contained in:
+31
-89
@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
For commercial licensing, please contact admin@modelstoken.com
|
||||
*/
|
||||
import { Fragment, useMemo } from 'react'
|
||||
import { Fragment } from 'react'
|
||||
import { Link } from '@tanstack/react-router'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { cn } from '@/lib/utils'
|
||||
@@ -55,20 +55,20 @@ function FooterLinkItem(props: { link: FooterLink }) {
|
||||
if (isExternal) {
|
||||
return (
|
||||
<a
|
||||
href={props.link.href}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-muted-foreground hover:text-foreground text-sm transition-colors duration-200'
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
href={props.link.href}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[#8B8D97] hover:text-[#00D2FF] text-sm transition-colors duration-200'
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
to={props.link.href}
|
||||
className='text-muted-foreground hover:text-foreground text-sm transition-colors duration-200'
|
||||
className='text-[#8B8D97] hover:text-[#00D2FF] text-sm transition-colors duration-200'
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
@@ -104,13 +104,13 @@ function LegalLinks(props: { leadingSeparator?: boolean }) {
|
||||
{items.map((item, index) => (
|
||||
<Fragment key={item.key}>
|
||||
{(props.leadingSeparator || index > 0) && (
|
||||
<span aria-hidden='true' className='text-muted-foreground/30'>
|
||||
<span aria-hidden='true' className='text-[#5C5D66]'>
|
||||
·
|
||||
</span>
|
||||
)}
|
||||
<Link
|
||||
to={item.href}
|
||||
className='hover:text-foreground transition-colors duration-200'
|
||||
className='text-[#8B8D97] hover:text-[#00D2FF] transition-colors duration-200'
|
||||
>
|
||||
{item.label}
|
||||
</Link>
|
||||
@@ -125,13 +125,13 @@ function LegalLinks(props: { leadingSeparator?: boolean }) {
|
||||
function ProjectAttribution(props: { currentYear: number; inline?: boolean }) {
|
||||
const { t } = useTranslation()
|
||||
const content = (
|
||||
<span className='text-muted-foreground/45'>
|
||||
<span className='text-[#5C5D66]'>
|
||||
© {props.currentYear}{' '}
|
||||
<a
|
||||
href='https://git.viaeon.com/admin/new-api'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-foreground/70 hover:text-foreground font-medium transition-colors'
|
||||
className='text-[#8B8D97] hover:text-[#00D2FF] font-medium transition-colors'
|
||||
>
|
||||
{t('ModelsToken')}
|
||||
</a>
|
||||
@@ -142,7 +142,7 @@ function ProjectAttribution(props: { currentYear: number; inline?: boolean }) {
|
||||
return content
|
||||
}
|
||||
return (
|
||||
<div className='text-muted-foreground/45 text-center text-xs sm:text-right'>
|
||||
<div className='text-[#5C5D66] text-center text-xs sm:text-right'>
|
||||
{content}
|
||||
</div>
|
||||
)
|
||||
@@ -162,80 +162,23 @@ export function Footer(props: FooterProps) {
|
||||
const isDemoSiteMode = Boolean(demoSiteEnabled)
|
||||
const currentYear = new Date().getFullYear()
|
||||
|
||||
const fallbackColumns = useMemo<FooterColumnProps[]>(
|
||||
() => [
|
||||
{
|
||||
title: t('footer.columns.about.title'),
|
||||
links: [
|
||||
{
|
||||
text: t('footer.columns.about.links.aboutProject'),
|
||||
href: 'https://docs.newapi.pro/wiki/project-introduction/',
|
||||
},
|
||||
{
|
||||
text: t('footer.columns.about.links.contact'),
|
||||
href: 'https://docs.newapi.pro/support/community-interaction/',
|
||||
},
|
||||
{
|
||||
text: t('footer.columns.about.links.features'),
|
||||
href: 'https://docs.newapi.pro/wiki/features-introduction/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t('footer.columns.docs.title'),
|
||||
links: [
|
||||
{
|
||||
text: t('footer.columns.docs.links.quickStart'),
|
||||
href: 'https://docs.newapi.pro/getting-started/',
|
||||
},
|
||||
{
|
||||
text: t('footer.columns.docs.links.installation'),
|
||||
href: 'https://docs.newapi.pro/installation/',
|
||||
},
|
||||
{
|
||||
text: t('footer.columns.docs.links.apiDocs'),
|
||||
href: 'https://docs.newapi.pro/api/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t('footer.columns.related.title'),
|
||||
links: [
|
||||
{
|
||||
text: t('footer.columns.related.links.oneApi'),
|
||||
href: 'https://github.com/songquanpeng/one-api',
|
||||
},
|
||||
{
|
||||
text: t('footer.columns.related.links.midjourney'),
|
||||
href: 'https://github.com/novicezk/midjourney-proxy',
|
||||
},
|
||||
{
|
||||
text: t('footer.columns.related.links.newApiKeyTool'),
|
||||
href: 'https://github.com/Calcium-Ion/new-api-key-tool',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
[t]
|
||||
)
|
||||
|
||||
const displayColumns = props.columns ?? fallbackColumns
|
||||
const displayColumns = props.columns ?? []
|
||||
|
||||
if (footerHtml) {
|
||||
return (
|
||||
<footer
|
||||
className={cn(
|
||||
'border-border/40 relative z-10 border-t',
|
||||
'border-[#2A2B33] bg-[#0C0D10] border-t',
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
<div className='mx-auto w-full max-w-6xl px-6 py-5'>
|
||||
<div className='bg-muted/20 border-border/50 flex flex-col items-center justify-between gap-4 rounded-2xl border px-4 py-4 backdrop-blur-sm sm:flex-row sm:px-5'>
|
||||
<div className='border-[#2A2B33] bg-[#13141A] flex flex-col items-center justify-between gap-4 rounded-lg border px-4 py-4 sm:flex-row sm:px-5'>
|
||||
<div
|
||||
className='custom-footer text-muted-foreground min-w-0 text-center text-sm sm:text-left'
|
||||
className='text-[#8B8D97] min-w-0 text-center text-sm sm:text-left'
|
||||
dangerouslySetInnerHTML={{ __html: footerHtml }}
|
||||
/>
|
||||
<div className='border-border/60 text-muted-foreground/45 flex w-full flex-wrap items-center justify-center gap-x-3 gap-y-1 border-t pt-4 text-xs sm:w-auto sm:justify-end sm:border-t-0 sm:border-l sm:pt-0 sm:pl-5'>
|
||||
<div className='border-[#2A2B33] text-[#5C5D66] flex w-full flex-wrap items-center justify-center gap-x-3 gap-y-1 border-t pt-4 text-xs sm:w-auto sm:justify-end sm:border-t-0 sm:border-l sm:pt-0 sm:pl-5'>
|
||||
<LegalLinks />
|
||||
<ProjectAttribution currentYear={currentYear} inline />
|
||||
</div>
|
||||
@@ -247,36 +190,36 @@ export function Footer(props: FooterProps) {
|
||||
|
||||
return (
|
||||
<footer
|
||||
className={cn('border-border/40 relative z-10 border-t', props.className)}
|
||||
className={cn('border-[#2A2B33] bg-[#0C0D10] border-t', props.className)}
|
||||
>
|
||||
<div className='mx-auto max-w-6xl px-6 py-12 md:py-16'>
|
||||
<div className='flex flex-col justify-between gap-10 md:flex-row md:gap-16'>
|
||||
<div className='mx-auto max-w-6xl px-6 py-10'>
|
||||
<div className='flex flex-col justify-between gap-8 md:flex-row md:gap-16'>
|
||||
{/* Brand column */}
|
||||
<div className='shrink-0'>
|
||||
<Link to='/' className='group flex items-center gap-2.5'>
|
||||
<img
|
||||
src={displayLogo}
|
||||
alt={displayName}
|
||||
className='size-7 rounded-lg object-contain'
|
||||
className='size-6 rounded object-contain'
|
||||
/>
|
||||
<span className='text-sm font-semibold tracking-tight'>
|
||||
<span className='text-sm font-semibold tracking-tight text-[#C5C6D0]'>
|
||||
{displayName}
|
||||
</span>
|
||||
</Link>
|
||||
<p className='text-muted-foreground/60 mt-3 max-w-[200px] text-xs leading-relaxed'>
|
||||
<p className='mt-2.5 max-w-[200px] text-xs leading-relaxed text-[#5C5D66]'>
|
||||
{t('Powerful API Management Platform')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Links columns */}
|
||||
{isDemoSiteMode && (
|
||||
{isDemoSiteMode && displayColumns.length > 0 && (
|
||||
<div className='grid grid-cols-3 gap-8 md:gap-16'>
|
||||
{displayColumns.map((column, index) => (
|
||||
<div key={index}>
|
||||
<p className='text-muted-foreground/50 mb-3 text-xs font-medium tracking-wider uppercase'>
|
||||
<p className='mb-2.5 text-[10px] font-medium tracking-widest uppercase text-[#5C5D66]'>
|
||||
{t(column.title)}
|
||||
</p>
|
||||
<ul className='space-y-2.5'>
|
||||
<ul className='space-y-2'>
|
||||
{column.links.map((link, linkIndex) => (
|
||||
<li key={linkIndex}>
|
||||
<FooterLinkItem link={link} />
|
||||
@@ -289,10 +232,9 @@ export function Footer(props: FooterProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Copyright + optional legal links inline on the left, project
|
||||
attribution on the right; wraps on narrow screens. */}
|
||||
<div className='border-border/30 mt-12 flex flex-col items-center justify-between gap-x-3 gap-y-2 border-t pt-6 sm:flex-row'>
|
||||
<div className='text-muted-foreground/40 flex flex-wrap items-center justify-center gap-x-2 gap-y-1 text-xs sm:justify-start'>
|
||||
{/* Copyright row */}
|
||||
<div className='border-[#2A2B33] mt-8 flex flex-col items-center justify-between gap-x-3 gap-y-2 border-t pt-5 sm:flex-row'>
|
||||
<div className='text-[#5C5D66] flex flex-wrap items-center justify-center gap-x-2 gap-y-1 text-xs sm:justify-start'>
|
||||
<span>
|
||||
© {currentYear} {displayName}.{' '}
|
||||
{props.copyright ?? t('footer.defaultCopyright')}
|
||||
|
||||
@@ -184,7 +184,7 @@ export function PublicHeader(props: PublicHeaderProps) {
|
||||
className={cn(
|
||||
'flex items-center justify-between transition-all duration-700 ease-[cubic-bezier(0.16,1,0.3,1)]',
|
||||
scrolled
|
||||
? 'bg-background/60 ring-border/50 h-12 rounded-2xl pr-1.5 pl-4 shadow-[0_2px_16px_-6px_rgba(0,0,0,0.08),0_0_0_0.5px_rgba(0,0,0,0.02)] ring-[0.5px] backdrop-blur-2xl dark:shadow-[0_2px_16px_-6px_rgba(0,0,0,0.4)]'
|
||||
? 'bg-[#0C0D10]/80 ring-[#2A2B33]/80 h-12 rounded-2xl pr-1.5 pl-4 shadow-[0_2px_16px_-6px_rgba(0,0,0,0.5)] ring-[0.5px] backdrop-blur-2xl'
|
||||
: 'h-16 px-2'
|
||||
)}
|
||||
>
|
||||
@@ -285,7 +285,7 @@ export function PublicHeader(props: PublicHeaderProps) {
|
||||
) : (
|
||||
<Button
|
||||
size='sm'
|
||||
className='h-8 rounded-lg px-3.5 text-xs font-medium'
|
||||
className='h-8 rounded-lg bg-[#00D2FF] px-3.5 text-xs font-semibold text-[#0C0D10] hover:bg-[#00B8E6]'
|
||||
render={<Link to='/sign-in' />}
|
||||
>
|
||||
{t('Sign in')}
|
||||
@@ -338,7 +338,7 @@ export function PublicHeader(props: PublicHeaderProps) {
|
||||
{/* Mobile full-screen overlay */}
|
||||
<div
|
||||
className={cn(
|
||||
'bg-background/98 fixed inset-0 z-40 backdrop-blur-2xl transition-all duration-500 ease-[cubic-bezier(0.16,1,0.3,1)] sm:pointer-events-none sm:hidden',
|
||||
'bg-[#0C0D10]/98 fixed inset-0 z-40 backdrop-blur-2xl transition-all duration-500 ease-[cubic-bezier(0.16,1,0.3,1)] sm:pointer-events-none sm:hidden',
|
||||
mobileOpen
|
||||
? 'pointer-events-auto opacity-100'
|
||||
: 'pointer-events-none opacity-0'
|
||||
@@ -404,7 +404,7 @@ export function PublicHeader(props: PublicHeaderProps) {
|
||||
<Link
|
||||
to={isAuthenticated ? '/dashboard' : '/sign-in'}
|
||||
onClick={() => setMobileOpen(false)}
|
||||
className='bg-foreground text-background inline-flex h-10 items-center justify-center rounded-lg text-sm font-medium transition-opacity hover:opacity-90 active:opacity-80'
|
||||
className='bg-[#00D2FF] text-[#0C0D10] inline-flex h-10 items-center justify-center rounded-lg text-sm font-semibold transition-opacity hover:opacity-90 active:opacity-80'
|
||||
>
|
||||
{isAuthenticated ? t('Go to Dashboard') : t('Sign in')}
|
||||
</Link>
|
||||
|
||||
+8
-10
@@ -17,7 +17,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
For commercial licensing, please contact admin@modelstoken.com
|
||||
*/
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Construction } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Markdown } from '@/components/ui/markdown'
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
@@ -43,19 +42,18 @@ function EmptyAboutState() {
|
||||
|
||||
return (
|
||||
<div className='flex min-h-[60vh] items-center justify-center p-8'>
|
||||
<div className='max-w-2xl space-y-6 text-center'>
|
||||
<div className='flex justify-center'>
|
||||
<Construction className='text-muted-foreground h-24 w-24' />
|
||||
</div>
|
||||
<div className='max-w-lg space-y-5 text-center'>
|
||||
<div className='space-y-2'>
|
||||
<h2 className='text-2xl font-bold'>{t('No About Content Set')}</h2>
|
||||
<p className='text-muted-foreground'>
|
||||
<h2 className='text-2xl font-bold text-foreground'>
|
||||
{t('No About Content Set')}
|
||||
</h2>
|
||||
<p className='text-muted-foreground text-sm'>
|
||||
{t(
|
||||
'The administrator has not configured any about content yet. You can set it in the settings page, supporting HTML or URL.'
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className='space-y-4 text-sm'>
|
||||
<div className='space-y-3 text-sm'>
|
||||
<p>
|
||||
{t('ModelsToken Project Repository:')}{' '}
|
||||
<a
|
||||
@@ -76,7 +74,7 @@ function EmptyAboutState() {
|
||||
>
|
||||
{t('ModelsToken')}
|
||||
</a>{' '}
|
||||
© {currentYear}{' '}
|
||||
© {currentYear}{' '}
|
||||
<a
|
||||
href='https://git.viaeon.com/admin/new-api'
|
||||
target='_blank'
|
||||
@@ -94,7 +92,7 @@ function EmptyAboutState() {
|
||||
>
|
||||
{t('One API')}
|
||||
</a>{' '}
|
||||
© 2023{' '}
|
||||
© 2023{' '}
|
||||
<a
|
||||
href='https://github.com/songquanpeng'
|
||||
target='_blank'
|
||||
|
||||
+6
-6
@@ -30,30 +30,30 @@ export function AuthLayout({ children }: AuthLayoutProps) {
|
||||
const { systemName, logo, loading } = useSystemConfig()
|
||||
|
||||
return (
|
||||
<div className='relative grid h-svh max-w-none'>
|
||||
<div className='relative grid h-svh max-w-none bg-[#0C0D10]'>
|
||||
<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'
|
||||
>
|
||||
<div className='relative h-8 w-8'>
|
||||
{loading ? (
|
||||
<Skeleton className='absolute inset-0 rounded-full' />
|
||||
<Skeleton className='absolute inset-0 rounded-lg' />
|
||||
) : (
|
||||
<img
|
||||
src={logo}
|
||||
alt={t('Logo')}
|
||||
className='h-8 w-8 rounded-full object-cover'
|
||||
className='h-8 w-8 rounded-lg object-cover'
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{loading ? (
|
||||
<Skeleton className='h-6 w-24' />
|
||||
<Skeleton className='h-5 w-20' />
|
||||
) : (
|
||||
<h1 className='text-xl font-medium'>{systemName}</h1>
|
||||
<h1 className='text-base font-semibold text-white'>{systemName}</h1>
|
||||
)}
|
||||
</Link>
|
||||
<div className='container flex items-center pt-16 sm:pt-0'>
|
||||
<div className='mx-auto flex w-full flex-col justify-center space-y-2 px-4 py-8 sm:w-[480px] sm:p-8'>
|
||||
<div className='mx-auto flex w-full flex-col justify-center space-y-2 px-4 py-8 sm:w-[420px] sm:p-8'>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+11
-7
@@ -25,15 +25,19 @@ export function ForbiddenError() {
|
||||
const navigate = useNavigate()
|
||||
const { history } = useRouter()
|
||||
return (
|
||||
<div className='h-svh'>
|
||||
<div className='m-auto flex h-full w-full flex-col items-center justify-center gap-2'>
|
||||
<h1 className='text-[7rem] leading-tight font-bold'>403</h1>
|
||||
<span className='font-medium'>{t('Access Forbidden')}</span>
|
||||
<p className='text-muted-foreground text-center'>
|
||||
{t("You don't have necessary permission")} <br />
|
||||
<div className='bg-background flex h-svh'>
|
||||
<div className='m-auto flex w-full flex-col items-center justify-center gap-3 px-6'>
|
||||
<h1 className='text-[7rem] leading-none font-bold text-primary/80'>
|
||||
403
|
||||
</h1>
|
||||
<span className='text-lg font-medium text-foreground'>
|
||||
{t('Access Forbidden')}
|
||||
</span>
|
||||
<p className='text-muted-foreground max-w-sm text-center text-sm'>
|
||||
{t("You don't have necessary permission")}{' '}
|
||||
{t('to view this resource.')}
|
||||
</p>
|
||||
<div className='mt-6 flex gap-4'>
|
||||
<div className='mt-6 flex gap-3'>
|
||||
<Button variant='outline' onClick={() => history.go(-1)}>
|
||||
{t('Go Back')}
|
||||
</Button>
|
||||
|
||||
+8
-8
@@ -54,24 +54,24 @@ export function GeneralError({
|
||||
: t('Please try again later.')
|
||||
|
||||
return (
|
||||
<div className={cn('h-svh w-full', className)}>
|
||||
<div className='m-auto flex h-full w-full flex-col items-center justify-center gap-2'>
|
||||
<div className={cn('bg-background flex h-svh w-full', className)}>
|
||||
<div className='m-auto flex w-full flex-col items-center justify-center gap-3 px-6'>
|
||||
{!minimal && (
|
||||
<h1 className='text-[7rem] leading-tight font-bold'>
|
||||
<h1 className='text-[7rem] leading-none font-bold text-primary/80'>
|
||||
{status ?? 500}
|
||||
</h1>
|
||||
)}
|
||||
<span className='font-medium'>{title}</span>
|
||||
<p className='text-muted-foreground text-center'>
|
||||
{t('We apologize for the inconvenience.')} <br /> {description}
|
||||
<span className='text-lg font-medium text-foreground'>{title}</span>
|
||||
<p className='text-muted-foreground max-w-sm text-center text-sm'>
|
||||
{t('We apologize for the inconvenience.')} {description}
|
||||
</p>
|
||||
{!minimal && (
|
||||
<p className='text-muted-foreground text-center text-sm'>
|
||||
<p className='text-muted-foreground/60 text-center text-xs'>
|
||||
{t('If this keeps happening, please report it on GitHub Issues.')}
|
||||
</p>
|
||||
)}
|
||||
{!minimal && (
|
||||
<div className='mt-6 flex flex-wrap justify-center gap-4'>
|
||||
<div className='mt-6 flex flex-wrap justify-center gap-3'>
|
||||
<Button variant='outline' onClick={() => history.go(-1)}>
|
||||
{t('Go Back')}
|
||||
</Button>
|
||||
|
||||
+9
-7
@@ -22,17 +22,19 @@ import { Button } from '@/components/ui/button'
|
||||
export function MaintenanceError() {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className='h-svh'>
|
||||
<div className='m-auto flex h-full w-full flex-col items-center justify-center gap-2'>
|
||||
<h1 className='text-[7rem] leading-tight font-bold'>503</h1>
|
||||
<span className='font-medium'>
|
||||
<div className='bg-background flex h-svh'>
|
||||
<div className='m-auto flex w-full flex-col items-center justify-center gap-3 px-6'>
|
||||
<h1 className='text-[7rem] leading-none font-bold text-primary/80'>
|
||||
503
|
||||
</h1>
|
||||
<span className='text-lg font-medium text-foreground'>
|
||||
{t('Website is under maintenance!')}
|
||||
</span>
|
||||
<p className='text-muted-foreground text-center'>
|
||||
{t('The site is not available at the moment.')} <br />
|
||||
<p className='text-muted-foreground max-w-sm text-center text-sm'>
|
||||
{t('The site is not available at the moment.')}{' '}
|
||||
{t("We'll be back online shortly.")}
|
||||
</p>
|
||||
<div className='mt-6 flex gap-4'>
|
||||
<div className='mt-6'>
|
||||
<Button variant='outline'>{t('Learn more')}</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+11
-7
@@ -25,15 +25,19 @@ export function NotFoundError() {
|
||||
const navigate = useNavigate()
|
||||
const { history } = useRouter()
|
||||
return (
|
||||
<div className='h-svh'>
|
||||
<div className='m-auto flex h-full w-full flex-col items-center justify-center gap-2'>
|
||||
<h1 className='text-[7rem] leading-tight font-bold'>404</h1>
|
||||
<span className='font-medium'>{t('Oops! Page Not Found!')}</span>
|
||||
<p className='text-muted-foreground text-center'>
|
||||
{t("It seems like the page you're looking for")} <br />
|
||||
<div className='bg-background flex h-svh'>
|
||||
<div className='m-auto flex w-full flex-col items-center justify-center gap-3 px-6'>
|
||||
<h1 className='text-[7rem] leading-none font-bold text-primary/80'>
|
||||
404
|
||||
</h1>
|
||||
<span className='text-lg font-medium text-foreground'>
|
||||
{t('Oops! Page Not Found!')}
|
||||
</span>
|
||||
<p className='text-muted-foreground max-w-sm text-center text-sm'>
|
||||
{t("It seems like the page you're looking for")}{' '}
|
||||
{t('does not exist or might have been removed.')}
|
||||
</p>
|
||||
<div className='mt-6 flex gap-4'>
|
||||
<div className='mt-6 flex gap-3'>
|
||||
<Button variant='outline' onClick={() => history.go(-1)}>
|
||||
{t('Go Back')}
|
||||
</Button>
|
||||
|
||||
+11
-7
@@ -25,15 +25,19 @@ export function UnauthorisedError() {
|
||||
const navigate = useNavigate()
|
||||
const { history } = useRouter()
|
||||
return (
|
||||
<div className='h-svh'>
|
||||
<div className='m-auto flex h-full w-full flex-col items-center justify-center gap-2'>
|
||||
<h1 className='text-[7rem] leading-tight font-bold'>401</h1>
|
||||
<span className='font-medium'>{t('Unauthorized Access')}</span>
|
||||
<p className='text-muted-foreground text-center'>
|
||||
{t('Please log in with the appropriate credentials')} <br />{' '}
|
||||
<div className='bg-background flex h-svh'>
|
||||
<div className='m-auto flex w-full flex-col items-center justify-center gap-3 px-6'>
|
||||
<h1 className='text-[7rem] leading-none font-bold text-primary/80'>
|
||||
401
|
||||
</h1>
|
||||
<span className='text-lg font-medium text-foreground'>
|
||||
{t('Unauthorized Access')}
|
||||
</span>
|
||||
<p className='text-muted-foreground max-w-sm text-center text-sm'>
|
||||
{t('Please log in with the appropriate credentials')}{' '}
|
||||
{t('to access this resource.')}
|
||||
</p>
|
||||
<div className='mt-6 flex gap-4'>
|
||||
<div className='mt-6 flex gap-3'>
|
||||
<Button variant='outline' onClick={() => history.go(-1)}>
|
||||
{t('Go Back')}
|
||||
</Button>
|
||||
|
||||
+86
-128
@@ -19,6 +19,7 @@ For commercial licensing, please contact admin@modelstoken.com
|
||||
import { Link } from '@tanstack/react-router'
|
||||
import { ArrowRight } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useStatus } from '@/hooks/use-status'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
interface HeroProps {
|
||||
@@ -28,145 +29,102 @@ interface HeroProps {
|
||||
|
||||
export function Hero(props: HeroProps) {
|
||||
const { t } = useTranslation()
|
||||
const { status } = useStatus()
|
||||
const serverAddress =
|
||||
(status?.server_address as string | undefined) ||
|
||||
`${window.location.origin}`
|
||||
|
||||
return (
|
||||
<section className='relative bg-[#0C0D10] dark:bg-[#0C0D10]'>
|
||||
<div className='mx-auto max-w-6xl px-6 pt-20 pb-16 md:pt-28 md:pb-24'>
|
||||
<div className='flex flex-col items-center text-center'>
|
||||
{/* Headline */}
|
||||
<h1
|
||||
className='landing-animate-fade-up max-w-3xl text-[clamp(1.75rem,4.5vw,3.25rem)] leading-[1.15] font-bold tracking-tight text-white'
|
||||
style={{ animationDelay: '0ms' }}
|
||||
>
|
||||
{t('Unified LLM Gateway')}
|
||||
</h1>
|
||||
<section className='bg-[#0C0D10]'>
|
||||
<div className='mx-auto flex min-h-[calc(100svh-3rem)] max-w-6xl flex-col items-center justify-center px-6 py-20 text-center'>
|
||||
{/* Headline */}
|
||||
<h1 className='max-w-2xl text-[clamp(1.75rem,4.5vw,3rem)] leading-[1.15] font-bold tracking-tight text-white'>
|
||||
{t('Unified LLM Gateway')}
|
||||
</h1>
|
||||
|
||||
{/* Subtitle */}
|
||||
<p
|
||||
className='landing-animate-fade-up mt-4 max-w-xl text-base leading-relaxed text-[#8B8D97] md:text-lg'
|
||||
style={{ animationDelay: '60ms' }}
|
||||
>
|
||||
{t(
|
||||
'One endpoint for all models. OpenAI-compatible, switch and go.'
|
||||
)}
|
||||
</p>
|
||||
{/* Subtitle */}
|
||||
<p className='mt-4 max-w-md text-base leading-relaxed text-[#8B8D97]'>
|
||||
{t(
|
||||
'One endpoint for all models. OpenAI-compatible, switch and go.'
|
||||
)}
|
||||
</p>
|
||||
|
||||
{/* CTA */}
|
||||
<div
|
||||
className='landing-animate-fade-up mt-8 flex flex-wrap items-center justify-center gap-3'
|
||||
style={{ animationDelay: '120ms' }}
|
||||
>
|
||||
{props.isAuthenticated ? (
|
||||
{/* CTA */}
|
||||
<div className='mt-8 flex flex-wrap items-center justify-center gap-3'>
|
||||
{props.isAuthenticated ? (
|
||||
<Button
|
||||
className='group h-11 rounded-lg bg-[#00D2FF] px-6 text-sm font-semibold text-[#0C0D10] hover:bg-[#00B8E6]'
|
||||
render={<Link to='/dashboard' />}
|
||||
>
|
||||
{t('Go to Dashboard')}
|
||||
<ArrowRight className='ml-1.5 size-4 transition-transform duration-200 group-hover:translate-x-0.5' />
|
||||
</Button>
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
className='group h-11 rounded-lg bg-[#00D2FF] px-6 text-sm font-semibold text-[#0C0D10] hover:bg-[#00B8E6]'
|
||||
render={<Link to='/dashboard' />}
|
||||
render={<Link to='/sign-up' />}
|
||||
>
|
||||
{t('Go to Dashboard')}
|
||||
{t('Get Started')}
|
||||
<ArrowRight className='ml-1.5 size-4 transition-transform duration-200 group-hover:translate-x-0.5' />
|
||||
</Button>
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
className='group h-11 rounded-lg bg-[#00D2FF] px-6 text-sm font-semibold text-[#0C0D10] hover:bg-[#00B8E6]'
|
||||
render={<Link to='/sign-up' />}
|
||||
>
|
||||
{t('Get Started')}
|
||||
<ArrowRight className='ml-1.5 size-4 transition-transform duration-200 group-hover:translate-x-0.5' />
|
||||
</Button>
|
||||
<Button
|
||||
variant='outline'
|
||||
className='h-11 rounded-lg border-[#2A2B33] bg-transparent px-6 text-sm font-medium text-[#C5C6D0] hover:border-[#3A3B45] hover:bg-[#1A1B20] hover:text-white'
|
||||
render={<Link to='/pricing' />}
|
||||
>
|
||||
{t('View Pricing')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
variant='outline'
|
||||
className='h-11 rounded-lg border-[#2A2B33] bg-transparent px-6 text-sm font-medium text-[#C5C6D0] hover:border-[#3A3B45] hover:bg-[#1A1B20] hover:text-white'
|
||||
render={<Link to='/pricing' />}
|
||||
>
|
||||
{t('View Pricing')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Platform badges */}
|
||||
<div
|
||||
className='landing-animate-fade-up mt-6 flex items-center gap-4 text-xs text-[#5C5D66]'
|
||||
style={{ animationDelay: '180ms' }}
|
||||
>
|
||||
<span>{t('Compatible with')}</span>
|
||||
<div className='flex items-center gap-3'>
|
||||
{['OpenAI', 'Claude', 'Gemini', 'DeepSeek', 'Qwen'].map(
|
||||
(name) => (
|
||||
<span key={name} className='text-[#8B8D97]'>
|
||||
{name}
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Product screenshot - terminal demo */}
|
||||
<div
|
||||
className='landing-animate-fade-up mt-14 w-full max-w-4xl'
|
||||
style={{ animationDelay: '240ms' }}
|
||||
>
|
||||
<div className='overflow-hidden rounded-xl border border-[#2A2B33] bg-[#13141A] shadow-2xl shadow-black/40'>
|
||||
{/* Terminal header */}
|
||||
<div className='flex items-center gap-2 border-b border-[#2A2B33] px-4 py-3'>
|
||||
<div className='flex gap-1.5'>
|
||||
<div className='size-3 rounded-full bg-[#FF5F57]' />
|
||||
<div className='size-3 rounded-full bg-[#FEBC2E]' />
|
||||
<div className='size-3 rounded-full bg-[#28C840]' />
|
||||
</div>
|
||||
<span className='ml-3 text-xs text-[#5C5D66]'>
|
||||
ModelsToken Gateway
|
||||
</span>
|
||||
{/* Terminal demo */}
|
||||
<div className='mt-16 w-full max-w-3xl'>
|
||||
<div className='overflow-hidden rounded-xl border border-[#2A2B33] bg-[#13141A] shadow-2xl shadow-black/50'>
|
||||
{/* Terminal header */}
|
||||
<div className='flex items-center border-b border-[#2A2B33] px-4 py-2.5'>
|
||||
<div className='flex gap-1.5'>
|
||||
<div className='size-2.5 rounded-full bg-[#FF5F57]' />
|
||||
<div className='size-2.5 rounded-full bg-[#FEBC2E]' />
|
||||
<div className='size-2.5 rounded-full bg-[#28C840]' />
|
||||
</div>
|
||||
{/* Terminal content */}
|
||||
<div className='p-5 font-mono text-sm leading-7'>
|
||||
<div>
|
||||
<span className='text-[#28C840]'>$</span>{' '}
|
||||
<span className='text-[#C5C6D0]'>curl</span>{' '}
|
||||
<span className='text-[#00D2FF]'>https://api.modelstoken.com/v1/chat/completions</span>
|
||||
</div>
|
||||
<div className='mt-1'>
|
||||
<span className='text-[#5C5D66]'>-H</span>{' '}
|
||||
<span className='text-[#FEBC2E]'>"Authorization: Bearer sk-..."</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className='text-[#5C5D66]'>-H</span>{' '}
|
||||
<span className='text-[#FEBC2E]'>"Content-Type: application/json"</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className='text-[#5C5D66]'>-d</span>{' '}
|
||||
<span className='text-[#FEBC2E]'>{'\'{ "model": "gpt-4o", "messages": [...] }\' '}</span>
|
||||
</div>
|
||||
<div className='mt-3'>
|
||||
<span className='text-[#5C5D66]'># Response</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className='text-[#5C5D66]'>{'{'}</span>
|
||||
</div>
|
||||
<div className='pl-4'>
|
||||
<span className='text-[#00D2FF]'>"id"</span>
|
||||
<span className='text-[#5C5D66]'>:</span>{' '}
|
||||
<span className='text-[#FEBC2E]'>"chatcmpl-..."</span>
|
||||
<span className='text-[#5C5D66]'>,</span>
|
||||
</div>
|
||||
<div className='pl-4'>
|
||||
<span className='text-[#00D2FF]'>"model"</span>
|
||||
<span className='text-[#5C5D66]'>:</span>{' '}
|
||||
<span className='text-[#FEBC2E]'>"gpt-4o"</span>
|
||||
<span className='text-[#5C5D66]'>,</span>
|
||||
</div>
|
||||
<div className='pl-4'>
|
||||
<span className='text-[#00D2FF]'>"choices"</span>
|
||||
<span className='text-[#5C5D66]'>:</span>{' '}
|
||||
<span className='text-[#5C5D66]'>[{'{'}...{'}'}]</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className='text-[#5C5D66]'>{'}'}</span>
|
||||
</div>
|
||||
<div className='mt-2'>
|
||||
<span className='text-[#28C840]'>$</span>
|
||||
<span className='animate-pulse text-[#C5C6D0]'> _</span>
|
||||
</div>
|
||||
<span className='ml-3 text-[11px] text-[#5C5D66]'>
|
||||
ModelsToken Gateway
|
||||
</span>
|
||||
</div>
|
||||
{/* Terminal content */}
|
||||
<div className='p-5 font-mono text-[13px] leading-6'>
|
||||
<div>
|
||||
<span className='text-[#28C840]'>$</span>{' '}
|
||||
<span className='text-[#C5C6D0]'>curl</span>{' '}
|
||||
<span className='text-[#00D2FF]'>{serverAddress}/v1/chat/completions</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className='text-[#5C5D66]'>-H</span>{' '}
|
||||
<span className='text-[#FEBC2E]'>"Authorization: Bearer sk-..."</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className='text-[#5C5D66]'>-d</span>{' '}
|
||||
<span className='text-[#FEBC2E]'>{'\'{ "model": "gpt-4o", "messages": [...] }\' '}</span>
|
||||
</div>
|
||||
<div className='mt-3 border-t border-[#2A2B33] pt-3'>
|
||||
<span className='text-[#5C5D66]'># 200 OK</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className='text-[#5C5D66]'>{'{'}</span>{' '}
|
||||
<span className='text-[#00D2FF]'>"model"</span>
|
||||
<span className='text-[#5C5D66]'>:</span>{' '}
|
||||
<span className='text-[#FEBC2E]'>"gpt-4o"</span>
|
||||
<span className='text-[#5C5D66]'>,</span>{' '}
|
||||
<span className='text-[#00D2FF]'>"usage"</span>
|
||||
<span className='text-[#5C5D66]'>:</span>{' '}
|
||||
<span className='text-[#5C5D66]'>{'{'}...{'}'}</span>{' '}
|
||||
<span className='text-[#5C5D66]'>{'}'}</span>
|
||||
</div>
|
||||
<div className='mt-2'>
|
||||
<span className='text-[#28C840]'>$</span>
|
||||
<span className='animate-pulse text-[#8B8D97]'> _</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+4
-8
@@ -21,7 +21,7 @@ import { useAuthStore } from '@/stores/auth-store'
|
||||
import { Markdown } from '@/components/ui/markdown'
|
||||
import { PublicLayout } from '@/components/layout'
|
||||
import { Footer } from '@/components/layout/components/footer'
|
||||
import { CTA, Features, Hero, HowItWorks, Stats } from './components'
|
||||
import { Hero } from './components'
|
||||
import { useHomePageContent } from './hooks'
|
||||
|
||||
export function Home() {
|
||||
@@ -33,8 +33,8 @@ export function Home() {
|
||||
if (!isLoaded) {
|
||||
return (
|
||||
<PublicLayout showMainContainer={false}>
|
||||
<main className='flex min-h-screen items-center justify-center'>
|
||||
<div className='text-muted-foreground'>{t('Loading...')}</div>
|
||||
<main className='flex min-h-screen items-center justify-center bg-[#0C0D10]'>
|
||||
<div className='text-[#5C5D66]'>{t('Loading...')}</div>
|
||||
</main>
|
||||
</PublicLayout>
|
||||
)
|
||||
@@ -43,7 +43,7 @@ export function Home() {
|
||||
if (content) {
|
||||
return (
|
||||
<PublicLayout showMainContainer={false}>
|
||||
<main className='overflow-x-hidden'>
|
||||
<main className='overflow-x-hidden bg-[#0C0D10]'>
|
||||
{isUrl ? (
|
||||
<iframe
|
||||
src={content}
|
||||
@@ -63,10 +63,6 @@ export function Home() {
|
||||
return (
|
||||
<PublicLayout showMainContainer={false}>
|
||||
<Hero isAuthenticated={isAuthenticated} />
|
||||
<Stats />
|
||||
<Features />
|
||||
<HowItWorks />
|
||||
<CTA isAuthenticated={isAuthenticated} />
|
||||
<Footer />
|
||||
</PublicLayout>
|
||||
)
|
||||
|
||||
Vendored
+69
-68
@@ -91,7 +91,7 @@ For commercial licensing, please contact admin@modelstoken.com
|
||||
}
|
||||
|
||||
:root {
|
||||
--radius: 1rem;
|
||||
--radius: 0.625rem;
|
||||
--app-header-height: 3rem;
|
||||
/* Static build-channel fallback consumed when JS hasn't booted yet. */
|
||||
--app-rev: '2k6e8r7p';
|
||||
@@ -100,92 +100,93 @@ For commercial licensing, please contact admin@modelstoken.com
|
||||
* in theme-presets.css. Default mirrors `--font-sans` so behavior is
|
||||
* identical when no font preference is set. */
|
||||
--font-body: var(--font-sans);
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
/* Termius-inspired light mode: clean whites, subtle borders, cyan accent */
|
||||
--background: oklch(0.985 0.001 270);
|
||||
--foreground: oklch(0.15 0.005 270);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--card-foreground: oklch(0.15 0.005 270);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.13 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.95 0 0);
|
||||
--secondary-foreground: oklch(0.145 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.49 0 0);
|
||||
--accent: oklch(0.95 0 0);
|
||||
--accent-foreground: oklch(0.145 0 0);
|
||||
--popover-foreground: oklch(0.15 0.005 270);
|
||||
--primary: oklch(0.65 0.17 210);
|
||||
--primary-foreground: oklch(1 0 0);
|
||||
--secondary: oklch(0.955 0.003 270);
|
||||
--secondary-foreground: oklch(0.20 0.005 270);
|
||||
--muted: oklch(0.955 0.003 270);
|
||||
--muted-foreground: oklch(0.50 0.01 270);
|
||||
--accent: oklch(0.955 0.003 270);
|
||||
--accent-foreground: oklch(0.15 0.005 270);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--destructive-foreground: oklch(0.985 0 0);
|
||||
--success: oklch(0.596 0.145 163.225);
|
||||
--success-foreground: oklch(0.985 0 0);
|
||||
--warning: oklch(0.681 0.162 75.834);
|
||||
--warning-foreground: oklch(0.145 0 0);
|
||||
--warning-foreground: oklch(0.15 0.005 270);
|
||||
--info: oklch(0.588 0.158 241.966);
|
||||
--info-foreground: oklch(0.985 0 0);
|
||||
--neutral: oklch(0.708 0 0);
|
||||
--neutral-foreground: oklch(0.145 0 0);
|
||||
--border: oklch(0.93 0 0);
|
||||
--input: oklch(0.93 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.975 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.13 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.92 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.145 0 0);
|
||||
--sidebar-border: oklch(0.93 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
--skeleton-base: oklch(0.97 0 0);
|
||||
--skeleton-highlight: oklch(0.985 0 0);
|
||||
--neutral: oklch(0.55 0.01 270);
|
||||
--neutral-foreground: oklch(0.985 0 0);
|
||||
--border: oklch(0.91 0.003 270);
|
||||
--input: oklch(0.91 0.003 270);
|
||||
--ring: oklch(0.65 0.17 210);
|
||||
--chart-1: oklch(0.65 0.17 210);
|
||||
--chart-2: oklch(0.596 0.145 163.225);
|
||||
--chart-3: oklch(0.681 0.162 75.834);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.975 0.002 270);
|
||||
--sidebar-foreground: oklch(0.15 0.005 270);
|
||||
--sidebar-primary: oklch(0.65 0.17 210);
|
||||
--sidebar-primary-foreground: oklch(1 0 0);
|
||||
--sidebar-accent: oklch(0.935 0.003 270);
|
||||
--sidebar-accent-foreground: oklch(0.15 0.005 270);
|
||||
--sidebar-border: oklch(0.91 0.003 270);
|
||||
--sidebar-ring: oklch(0.65 0.17 210);
|
||||
--skeleton-base: oklch(0.955 0.003 270);
|
||||
--skeleton-highlight: oklch(0.985 0.001 270);
|
||||
}
|
||||
|
||||
.dark {
|
||||
/* OpenAI-like dark mode: nearly black chrome, readable raised surfaces. */
|
||||
--background: oklch(0.185 0 0);
|
||||
--foreground: oklch(0.965 0 0);
|
||||
--card: oklch(0.235 0 0);
|
||||
--card-foreground: oklch(0.965 0 0);
|
||||
--popover: oklch(0.255 0 0);
|
||||
--popover-foreground: oklch(0.965 0 0);
|
||||
--primary: oklch(0.965 0 0);
|
||||
--primary-foreground: oklch(0.145 0 0);
|
||||
--secondary: oklch(0.285 0 0);
|
||||
--secondary-foreground: oklch(0.965 0 0);
|
||||
--muted: oklch(0.255 0 0);
|
||||
--muted-foreground: oklch(0.76 0 0);
|
||||
--accent: oklch(0.325 0 0);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
/* Termius-inspired dark mode: deep charcoal, cyan accent */
|
||||
--background: oklch(0.13 0.005 270);
|
||||
--foreground: oklch(0.93 0.005 270);
|
||||
--card: oklch(0.17 0.005 270);
|
||||
--card-foreground: oklch(0.93 0.005 270);
|
||||
--popover: oklch(0.17 0.005 270);
|
||||
--popover-foreground: oklch(0.93 0.005 270);
|
||||
--primary: oklch(0.78 0.15 210);
|
||||
--primary-foreground: oklch(0.13 0.005 270);
|
||||
--secondary: oklch(0.22 0.005 270);
|
||||
--secondary-foreground: oklch(0.88 0.005 270);
|
||||
--muted: oklch(0.20 0.005 270);
|
||||
--muted-foreground: oklch(0.62 0.01 270);
|
||||
--accent: oklch(0.25 0.005 270);
|
||||
--accent-foreground: oklch(0.93 0.005 270);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--destructive-foreground: oklch(0.985 0 0);
|
||||
--success: oklch(0.696 0.17 162.48);
|
||||
--success-foreground: oklch(0.145 0 0);
|
||||
--success-foreground: oklch(0.13 0.005 270);
|
||||
--warning: oklch(0.769 0.188 70.08);
|
||||
--warning-foreground: oklch(0.145 0 0);
|
||||
--warning-foreground: oklch(0.13 0.005 270);
|
||||
--info: oklch(0.68 0.17 237.323);
|
||||
--info-foreground: oklch(0.145 0 0);
|
||||
--neutral: oklch(0.76 0 0);
|
||||
--neutral-foreground: oklch(0.145 0 0);
|
||||
--border: oklch(1 0 0 / 9%);
|
||||
--input: oklch(1 0 0 / 16%);
|
||||
--ring: oklch(0.68 0 0);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--info-foreground: oklch(0.13 0.005 270);
|
||||
--neutral: oklch(0.62 0.01 270);
|
||||
--neutral-foreground: oklch(0.13 0.005 270);
|
||||
--border: oklch(0.25 0.005 270);
|
||||
--input: oklch(0.25 0.005 270);
|
||||
--ring: oklch(0.78 0.15 210);
|
||||
--chart-1: oklch(0.78 0.15 210);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.115 0 0);
|
||||
--sidebar-foreground: oklch(0.95 0 0);
|
||||
--sidebar-primary: oklch(0.965 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.145 0 0);
|
||||
--sidebar-accent: oklch(0.31 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.68 0 0);
|
||||
--skeleton-base: oklch(0.285 0 0);
|
||||
--skeleton-highlight: oklch(0.39 0 0);
|
||||
--sidebar: oklch(0.11 0.005 270);
|
||||
--sidebar-foreground: oklch(0.88 0.005 270);
|
||||
--sidebar-primary: oklch(0.78 0.15 210);
|
||||
--sidebar-primary-foreground: oklch(0.13 0.005 270);
|
||||
--sidebar-accent: oklch(0.20 0.005 270);
|
||||
--sidebar-accent-foreground: oklch(0.88 0.005 270);
|
||||
--sidebar-border: oklch(0.25 0.005 270);
|
||||
--sidebar-ring: oklch(0.78 0.15 210);
|
||||
--skeleton-base: oklch(0.20 0.005 270);
|
||||
--skeleton-highlight: oklch(0.28 0.005 270);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user