mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
fix: emcn component library design engineering polish (#3672)
* chore: fix conflicts * chore: fix conflicts * chore: pause marquee * chore: fix conflicts * chore: fix conflicts * chore: address review comments * chore: fix conflicts * chore: other bug fixes * chore: fix conflicts * chore: fix radius * chore: fix review changes * chore: fix conflicts * chore: revert other * chore: fix conflicts * chore: fix review changes * chore: fix conflicts * chore: fix review changes * chore: fix button state * chore: fix button state * chore: fix review changes * chore: fix lint * chore: fix conflicts * chore: add metadata * chore: fix things * chore: fix overwritten states * chore: fix warnings * chore: fix button state * chore: fix review changes * chore: fix review changes * chore: fix hover state * chore: fix popover * chore: fix review changes * chore: fix review changes
This commit is contained in:
@@ -8,8 +8,6 @@ export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
export const viewport: Viewport = {
|
||||
width: 'device-width',
|
||||
initialScale: 1,
|
||||
maximumScale: 1,
|
||||
userScalable: false,
|
||||
themeColor: [
|
||||
{ media: '(prefers-color-scheme: light)', color: '#ffffff' },
|
||||
{ media: '(prefers-color-scheme: dark)', color: '#0c0c0c' },
|
||||
|
||||
@@ -14,8 +14,8 @@ export default function AuthLayoutClient({ children }: { children: React.ReactNo
|
||||
|
||||
return (
|
||||
<AuthBackground className='dark font-[430] font-season'>
|
||||
<main className='relative flex min-h-full flex-col text-[#ECECEC]'>
|
||||
<header className='shrink-0 bg-[#1C1C1C]'>
|
||||
<main className='relative flex min-h-full flex-col text-[var(--landing-text)]'>
|
||||
<header className='shrink-0 bg-[var(--landing-bg)]'>
|
||||
<Navbar logoOnly />
|
||||
</header>
|
||||
<div className='relative z-30 flex flex-1 items-center justify-center px-4 pb-24'>
|
||||
|
||||
@@ -9,7 +9,7 @@ type AuthBackgroundProps = {
|
||||
export default function AuthBackground({ className, children }: AuthBackgroundProps) {
|
||||
return (
|
||||
<div className={cn('fixed inset-0 overflow-hidden', className)}>
|
||||
<div className='-z-50 pointer-events-none absolute inset-0 bg-[#1C1C1C]' />
|
||||
<div className='-z-50 pointer-events-none absolute inset-0 bg-[var(--landing-bg)]' />
|
||||
<AuthBackgroundSVG />
|
||||
<div className='relative z-20 h-full overflow-auto'>{children}</div>
|
||||
</div>
|
||||
|
||||
@@ -55,9 +55,9 @@ export const BrandedButton = forwardRef<HTMLButtonElement, BrandedButtonProps>(
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
className={cn(
|
||||
'group inline-flex h-[32px] items-center justify-center gap-[8px] rounded-[5px] border px-[10px] font-[430] font-season text-[14px] transition-colors disabled:cursor-not-allowed disabled:opacity-50',
|
||||
'group inline-flex h-[32px] items-center justify-center gap-2 rounded-[5px] border px-2.5 font-[430] font-season text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50',
|
||||
!hasCustomColor &&
|
||||
'border-[#FFFFFF] bg-[#FFFFFF] text-black hover:border-[#E0E0E0] hover:bg-[#E0E0E0]',
|
||||
'border-[var(--white)] bg-[var(--white)] text-black hover:border-[#E0E0E0] hover:bg-[#E0E0E0]',
|
||||
fullWidth && 'w-full',
|
||||
className
|
||||
)}
|
||||
|
||||
@@ -35,7 +35,7 @@ export function SSOLoginButton({
|
||||
|
||||
const primaryBtnClasses = cn(
|
||||
primaryClassName || 'branded-button-gradient',
|
||||
'flex w-full items-center justify-center gap-2 rounded-[10px] border font-medium text-[15px] text-white transition-all duration-200'
|
||||
'flex w-full items-center justify-center gap-2 rounded-[10px] border font-medium text-base text-white transition-all duration-200'
|
||||
)
|
||||
|
||||
const outlineBtnClasses = cn('w-full rounded-[10px]')
|
||||
|
||||
@@ -18,18 +18,18 @@ export function StatusPageLayout({
|
||||
}: StatusPageLayoutProps) {
|
||||
return (
|
||||
<AuthBackground className='dark font-[430] font-season'>
|
||||
<main className='relative flex min-h-full flex-col text-[#ECECEC]'>
|
||||
<header className='shrink-0 bg-[#1C1C1C]'>
|
||||
<main className='relative flex min-h-full flex-col text-[var(--landing-text)]'>
|
||||
<header className='shrink-0 bg-[var(--landing-bg)]'>
|
||||
<Navbar logoOnly />
|
||||
</header>
|
||||
<div className='relative z-30 flex flex-1 items-center justify-center px-4 pb-24'>
|
||||
<div className='w-full max-w-lg px-4'>
|
||||
<div className='flex flex-col items-center justify-center'>
|
||||
<div className='space-y-1 text-center'>
|
||||
<h1 className='font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
<h1 className='text-balance font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
{title}
|
||||
</h1>
|
||||
<p className='font-[430] font-season text-[#F6F6F6]/60 text-[18px] leading-[125%] tracking-[0.02em]'>
|
||||
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)] text-lg leading-[125%] tracking-[0.02em]'>
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -11,12 +11,12 @@ export function SupportFooter({ position = 'fixed' }: SupportFooterProps) {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`right-0 bottom-0 left-0 z-50 pb-8 text-center font-[340] text-[#999] text-[13px] leading-relaxed ${position}`}
|
||||
className={`right-0 bottom-0 left-0 z-50 pb-8 text-center font-[340] text-[var(--landing-text-muted)] text-small leading-relaxed ${position}`}
|
||||
>
|
||||
Need help?{' '}
|
||||
<a
|
||||
href={`mailto:${brandConfig.supportEmail}`}
|
||||
className='text-[#999] underline-offset-4 transition hover:text-[#ECECEC] hover:underline'
|
||||
className='text-[var(--landing-text-muted)] underline-offset-4 transition hover:text-[var(--landing-text)] hover:underline'
|
||||
>
|
||||
Contact support
|
||||
</a>
|
||||
|
||||
@@ -4,21 +4,21 @@ export default function LoginLoading() {
|
||||
return (
|
||||
<div className='flex flex-col items-center'>
|
||||
<Skeleton className='h-[38px] w-[80px] rounded-[4px]' />
|
||||
<div className='mt-[32px] w-full space-y-[8px]'>
|
||||
<div className='mt-8 w-full space-y-2'>
|
||||
<Skeleton className='h-[14px] w-[40px] rounded-[4px]' />
|
||||
<Skeleton className='h-[44px] w-full rounded-[10px]' />
|
||||
</div>
|
||||
<div className='mt-[16px] w-full space-y-[8px]'>
|
||||
<div className='mt-4 w-full space-y-2'>
|
||||
<Skeleton className='h-[14px] w-[64px] rounded-[4px]' />
|
||||
<Skeleton className='h-[44px] w-full rounded-[10px]' />
|
||||
</div>
|
||||
<Skeleton className='mt-[24px] h-[44px] w-full rounded-[10px]' />
|
||||
<Skeleton className='mt-[24px] h-[1px] w-full rounded-[1px]' />
|
||||
<div className='mt-[24px] flex w-full gap-[12px]'>
|
||||
<Skeleton className='mt-6 h-[44px] w-full rounded-[10px]' />
|
||||
<Skeleton className='mt-6 h-[1px] w-full rounded-[1px]' />
|
||||
<div className='mt-6 flex w-full gap-3'>
|
||||
<Skeleton className='h-[44px] flex-1 rounded-[10px]' />
|
||||
<Skeleton className='h-[44px] flex-1 rounded-[10px]' />
|
||||
</div>
|
||||
<Skeleton className='mt-[24px] h-[14px] w-[200px] rounded-[4px]' />
|
||||
<Skeleton className='mt-6 h-[14px] w-[200px] rounded-[4px]' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ export default function LoginPage({
|
||||
callbackURL: safeCallbackUrl,
|
||||
},
|
||||
{
|
||||
onError: (ctx) => {
|
||||
onError: (ctx: any) => {
|
||||
logger.error('Login error:', ctx.error)
|
||||
|
||||
if (ctx.error.code?.includes('EMAIL_NOT_VERIFIED')) {
|
||||
@@ -342,10 +342,10 @@ export default function LoginPage({
|
||||
return (
|
||||
<>
|
||||
<div className='space-y-1 text-center'>
|
||||
<h1 className='font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
<h1 className='text-balance font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
Sign in
|
||||
</h1>
|
||||
<p className='font-[430] font-season text-[#F6F6F6]/60 text-[18px] leading-[125%] tracking-[0.02em]'>
|
||||
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)] text-lg leading-[125%] tracking-[0.02em]'>
|
||||
Enter your details
|
||||
</p>
|
||||
</div>
|
||||
@@ -399,7 +399,7 @@ export default function LoginPage({
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setForgotPasswordOpen(true)}
|
||||
className='font-medium text-[#999] text-xs transition hover:text-[#ECECEC]'
|
||||
className='font-medium text-[var(--landing-text-muted)] text-xs transition hover:text-[var(--landing-text)]'
|
||||
>
|
||||
Forgot password?
|
||||
</button>
|
||||
@@ -426,7 +426,7 @@ export default function LoginPage({
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[#999] transition hover:text-[#ECECEC]'
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[var(--landing-text-muted)] transition hover:text-[var(--landing-text)]'
|
||||
aria-label={showPassword ? 'Hide password' : 'Show password'}
|
||||
>
|
||||
{showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
|
||||
@@ -469,10 +469,12 @@ export default function LoginPage({
|
||||
{showDivider && (
|
||||
<div className='relative my-6 font-light'>
|
||||
<div className='absolute inset-0 flex items-center'>
|
||||
<div className='w-full border-[#2A2A2A] border-t' />
|
||||
<div className='w-full border-[var(--landing-bg-elevated)] border-t' />
|
||||
</div>
|
||||
<div className='relative flex justify-center text-sm'>
|
||||
<span className='bg-[#1C1C1C] px-4 font-[340] text-[#999]'>Or continue with</span>
|
||||
<span className='bg-[var(--landing-bg)] px-4 font-[340] text-[var(--landing-text-muted)]'>
|
||||
Or continue with
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -502,20 +504,20 @@ export default function LoginPage({
|
||||
<span className='font-normal'>Don't have an account? </span>
|
||||
<Link
|
||||
href={isInviteFlow ? `/signup?invite_flow=true&callbackUrl=${callbackUrl}` : '/signup'}
|
||||
className='font-medium text-[#ECECEC] underline-offset-4 transition hover:text-white hover:underline'
|
||||
className='font-medium text-[var(--landing-text)] underline-offset-4 transition hover:text-white hover:underline'
|
||||
>
|
||||
Sign up
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='absolute right-0 bottom-0 left-0 px-8 pb-8 text-center font-[340] text-[#999] text-[13px] leading-relaxed sm:px-8 md:px-[44px]'>
|
||||
<div className='absolute right-0 bottom-0 left-0 px-8 pb-8 text-center font-[340] text-[13px] text-[var(--landing-text-muted)] leading-relaxed sm:px-8 md:px-11'>
|
||||
By signing in, you agree to our{' '}
|
||||
<Link
|
||||
href='/terms'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[#999] underline-offset-4 transition hover:text-[#ECECEC] hover:underline'
|
||||
className='text-[var(--landing-text-muted)] underline-offset-4 transition hover:text-[var(--landing-text)] hover:underline'
|
||||
>
|
||||
Terms of Service
|
||||
</Link>{' '}
|
||||
@@ -524,7 +526,7 @@ export default function LoginPage({
|
||||
href='/privacy'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[#999] underline-offset-4 transition hover:text-[#ECECEC] hover:underline'
|
||||
className='text-[var(--landing-text-muted)] underline-offset-4 transition hover:text-[var(--landing-text)] hover:underline'
|
||||
>
|
||||
Privacy Policy
|
||||
</Link>
|
||||
|
||||
@@ -3,16 +3,16 @@ import { Skeleton } from '@/components/emcn'
|
||||
export default function OAuthConsentLoading() {
|
||||
return (
|
||||
<div className='flex flex-col items-center'>
|
||||
<div className='flex items-center gap-[16px]'>
|
||||
<div className='flex items-center gap-4'>
|
||||
<Skeleton className='h-[48px] w-[48px] rounded-[12px]' />
|
||||
<Skeleton className='h-[20px] w-[20px] rounded-[4px]' />
|
||||
<Skeleton className='h-[48px] w-[48px] rounded-[12px]' />
|
||||
</div>
|
||||
<Skeleton className='mt-[24px] h-[38px] w-[220px] rounded-[4px]' />
|
||||
<Skeleton className='mt-[8px] h-[14px] w-[280px] rounded-[4px]' />
|
||||
<Skeleton className='mt-[24px] h-[56px] w-full rounded-[8px]' />
|
||||
<Skeleton className='mt-[16px] h-[120px] w-full rounded-[8px]' />
|
||||
<div className='mt-[24px] flex w-full max-w-[410px] gap-[12px]'>
|
||||
<Skeleton className='mt-6 h-[38px] w-[220px] rounded-[4px]' />
|
||||
<Skeleton className='mt-2 h-[14px] w-[280px] rounded-[4px]' />
|
||||
<Skeleton className='mt-6 h-[56px] w-full rounded-[8px]' />
|
||||
<Skeleton className='mt-4 h-[120px] w-full rounded-[8px]' />
|
||||
<div className='mt-6 flex w-full max-w-[410px] gap-3'>
|
||||
<Skeleton className='h-[44px] flex-1 rounded-[10px]' />
|
||||
<Skeleton className='h-[44px] flex-1 rounded-[10px]' />
|
||||
</div>
|
||||
|
||||
@@ -127,10 +127,10 @@ export default function OAuthConsentPage() {
|
||||
return (
|
||||
<div className='flex flex-col items-center justify-center'>
|
||||
<div className='space-y-1 text-center'>
|
||||
<h1 className='font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
<h1 className='text-balance font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
Authorize Application
|
||||
</h1>
|
||||
<p className='font-[430] font-season text-[#F6F6F6]/60 text-[18px] leading-[125%] tracking-[0.02em]'>
|
||||
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)] text-lg leading-[125%] tracking-[0.02em]'>
|
||||
Loading application details...
|
||||
</p>
|
||||
</div>
|
||||
@@ -142,10 +142,10 @@ export default function OAuthConsentPage() {
|
||||
return (
|
||||
<div className='flex flex-col items-center justify-center'>
|
||||
<div className='space-y-1 text-center'>
|
||||
<h1 className='font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
<h1 className='text-balance font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
Authorization Error
|
||||
</h1>
|
||||
<p className='font-[430] font-season text-[#F6F6F6]/60 text-[18px] leading-[125%] tracking-[0.02em]'>
|
||||
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)] text-lg leading-[125%] tracking-[0.02em]'>
|
||||
{error}
|
||||
</p>
|
||||
</div>
|
||||
@@ -170,11 +170,11 @@ export default function OAuthConsentPage() {
|
||||
className='rounded-[10px]'
|
||||
/>
|
||||
) : (
|
||||
<div className='flex h-12 w-12 items-center justify-center rounded-[10px] bg-[#2A2A2A] font-medium text-[#999] text-[18px]'>
|
||||
<div className='flex h-12 w-12 items-center justify-center rounded-[10px] bg-[var(--landing-bg-elevated)] font-medium text-[var(--landing-text-muted)] text-lg'>
|
||||
{(clientName ?? '?').charAt(0).toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
<ArrowLeftRight className='h-5 w-5 text-[#999]' />
|
||||
<ArrowLeftRight className='h-5 w-5 text-[var(--landing-text-muted)]' />
|
||||
<Image
|
||||
src='/new/logo/colorized-bg.svg'
|
||||
alt='Sim'
|
||||
@@ -185,17 +185,17 @@ export default function OAuthConsentPage() {
|
||||
</div>
|
||||
|
||||
<div className='space-y-1 text-center'>
|
||||
<h1 className='font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
<h1 className='text-balance font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
Authorize Application
|
||||
</h1>
|
||||
<p className='font-[430] font-season text-[#F6F6F6]/60 text-[18px] leading-[125%] tracking-[0.02em]'>
|
||||
<span className='font-medium text-[#ECECEC]'>{clientName}</span> is requesting access to
|
||||
your account
|
||||
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)] text-lg leading-[125%] tracking-[0.02em]'>
|
||||
<span className='font-medium text-[var(--landing-text)]'>{clientName}</span> is requesting
|
||||
access to your account
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{session?.user && (
|
||||
<div className='mt-5 flex items-center gap-3 rounded-lg border border-[#2A2A2A] px-4 py-3'>
|
||||
<div className='mt-5 flex items-center gap-3 rounded-lg border border-[var(--landing-bg-elevated)] px-4 py-3'>
|
||||
{session.user.image ? (
|
||||
<Image
|
||||
src={session.user.image}
|
||||
@@ -206,20 +206,22 @@ export default function OAuthConsentPage() {
|
||||
unoptimized
|
||||
/>
|
||||
) : (
|
||||
<div className='flex h-8 w-8 items-center justify-center rounded-full bg-[#2A2A2A] font-medium text-[#999] text-[13px]'>
|
||||
<div className='flex h-8 w-8 items-center justify-center rounded-full bg-[var(--landing-bg-elevated)] font-medium text-[var(--landing-text-muted)] text-small'>
|
||||
{(session.user.name ?? session.user.email ?? '?').charAt(0).toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
<div className='min-w-0'>
|
||||
{session.user.name && (
|
||||
<p className='truncate font-medium text-[14px]'>{session.user.name}</p>
|
||||
<p className='truncate font-medium text-sm'>{session.user.name}</p>
|
||||
)}
|
||||
<p className='truncate text-[#999] text-[13px]'>{session.user.email}</p>
|
||||
<p className='truncate text-[var(--landing-text-muted)] text-small'>
|
||||
{session.user.email}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type='button'
|
||||
onClick={handleSwitchAccount}
|
||||
className='ml-auto text-[#999] text-[13px] underline-offset-2 transition-colors hover:text-[#ECECEC] hover:underline'
|
||||
className='ml-auto text-[var(--landing-text-muted)] text-small underline-offset-2 transition-colors hover:text-[var(--landing-text)] hover:underline'
|
||||
>
|
||||
Switch
|
||||
</button>
|
||||
@@ -229,10 +231,13 @@ export default function OAuthConsentPage() {
|
||||
{scopes.length > 0 && (
|
||||
<div className='mt-5 w-full max-w-[410px]'>
|
||||
<div className='rounded-lg border p-4'>
|
||||
<p className='mb-3 font-medium text-[14px]'>This will allow the application to:</p>
|
||||
<p className='mb-3 font-medium text-sm'>This will allow the application to:</p>
|
||||
<ul className='space-y-2'>
|
||||
{scopes.map((s) => (
|
||||
<li key={s} className='flex items-start gap-2 font-normal text-[#999] text-[13px]'>
|
||||
<li
|
||||
key={s}
|
||||
className='flex items-start gap-2 font-normal text-[var(--landing-text-muted)] text-small'
|
||||
>
|
||||
<span className='mt-0.5 text-green-500'>✓</span>
|
||||
<span>{SCOPE_DESCRIPTIONS[s] ?? s}</span>
|
||||
</li>
|
||||
|
||||
@@ -4,13 +4,13 @@ export default function ResetPasswordLoading() {
|
||||
return (
|
||||
<div className='flex flex-col items-center'>
|
||||
<Skeleton className='h-[38px] w-[160px] rounded-[4px]' />
|
||||
<Skeleton className='mt-[12px] h-[14px] w-[280px] rounded-[4px]' />
|
||||
<div className='mt-[32px] w-full space-y-[8px]'>
|
||||
<Skeleton className='mt-3 h-[14px] w-[280px] rounded-[4px]' />
|
||||
<div className='mt-8 w-full space-y-2'>
|
||||
<Skeleton className='h-[14px] w-[40px] rounded-[4px]' />
|
||||
<Skeleton className='h-[44px] w-full rounded-[10px]' />
|
||||
</div>
|
||||
<Skeleton className='mt-[24px] h-[44px] w-full rounded-[10px]' />
|
||||
<Skeleton className='mt-[24px] h-[14px] w-[120px] rounded-[4px]' />
|
||||
<Skeleton className='mt-6 h-[44px] w-full rounded-[10px]' />
|
||||
<Skeleton className='mt-6 h-[14px] w-[120px] rounded-[4px]' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -69,10 +69,10 @@ function ResetPasswordContent() {
|
||||
return (
|
||||
<>
|
||||
<div className='space-y-1 text-center'>
|
||||
<h1 className='font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
<h1 className='text-balance font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
Reset your password
|
||||
</h1>
|
||||
<p className='font-[430] font-season text-[#F6F6F6]/60 text-[18px] leading-[125%] tracking-[0.02em]'>
|
||||
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)] text-lg leading-[125%] tracking-[0.02em]'>
|
||||
Enter a new password for your account
|
||||
</p>
|
||||
</div>
|
||||
@@ -87,10 +87,10 @@ function ResetPasswordContent() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='pt-6 text-center font-light text-[14px]'>
|
||||
<div className='pt-6 text-center font-light text-sm'>
|
||||
<Link
|
||||
href='/login'
|
||||
className='font-medium text-[#ECECEC] underline-offset-4 transition hover:text-white hover:underline'
|
||||
className='font-medium text-[var(--landing-text)] underline-offset-4 transition hover:text-white hover:underline'
|
||||
>
|
||||
Back to login
|
||||
</Link>
|
||||
|
||||
@@ -46,7 +46,7 @@ export function RequestResetForm({
|
||||
disabled={isSubmitting}
|
||||
required
|
||||
/>
|
||||
<p className='text-[#999] text-sm'>
|
||||
<p className='text-[var(--landing-text-muted)] text-sm'>
|
||||
We'll send a password reset link to this email address.
|
||||
</p>
|
||||
</div>
|
||||
@@ -54,7 +54,10 @@ export function RequestResetForm({
|
||||
{/* Status message display */}
|
||||
{statusType && statusMessage && (
|
||||
<div
|
||||
className={cn('text-xs', statusType === 'success' ? 'text-[#4CAF50]' : 'text-red-400')}
|
||||
className={cn(
|
||||
'text-xs',
|
||||
statusType === 'success' ? 'text-[var(--success)]' : 'text-red-400'
|
||||
)}
|
||||
>
|
||||
<p>{statusMessage}</p>
|
||||
</div>
|
||||
@@ -162,7 +165,7 @@ export function SetNewPasswordForm({
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[#999] transition hover:text-[#ECECEC]'
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[var(--landing-text-muted)] transition hover:text-[var(--landing-text)]'
|
||||
aria-label={showPassword ? 'Hide password' : 'Show password'}
|
||||
>
|
||||
{showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
|
||||
@@ -190,7 +193,7 @@ export function SetNewPasswordForm({
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[#999] transition hover:text-[#ECECEC]'
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[var(--landing-text-muted)] transition hover:text-[var(--landing-text)]'
|
||||
aria-label={showConfirmPassword ? 'Hide password' : 'Show password'}
|
||||
>
|
||||
{showConfirmPassword ? <EyeOff size={18} /> : <Eye size={18} />}
|
||||
@@ -208,7 +211,7 @@ export function SetNewPasswordForm({
|
||||
<div
|
||||
className={cn(
|
||||
'mt-1 space-y-1 text-xs',
|
||||
statusType === 'success' ? 'text-[#4CAF50]' : 'text-red-400'
|
||||
statusType === 'success' ? 'text-[var(--success)]' : 'text-red-400'
|
||||
)}
|
||||
>
|
||||
<p>{statusMessage}</p>
|
||||
|
||||
@@ -4,25 +4,25 @@ export default function SignupLoading() {
|
||||
return (
|
||||
<div className='flex flex-col items-center'>
|
||||
<Skeleton className='h-[38px] w-[100px] rounded-[4px]' />
|
||||
<div className='mt-[32px] w-full space-y-[8px]'>
|
||||
<div className='mt-8 w-full space-y-2'>
|
||||
<Skeleton className='h-[14px] w-[40px] rounded-[4px]' />
|
||||
<Skeleton className='h-[44px] w-full rounded-[10px]' />
|
||||
</div>
|
||||
<div className='mt-[16px] w-full space-y-[8px]'>
|
||||
<div className='mt-4 w-full space-y-2'>
|
||||
<Skeleton className='h-[14px] w-[40px] rounded-[4px]' />
|
||||
<Skeleton className='h-[44px] w-full rounded-[10px]' />
|
||||
</div>
|
||||
<div className='mt-[16px] w-full space-y-[8px]'>
|
||||
<div className='mt-4 w-full space-y-2'>
|
||||
<Skeleton className='h-[14px] w-[64px] rounded-[4px]' />
|
||||
<Skeleton className='h-[44px] w-full rounded-[10px]' />
|
||||
</div>
|
||||
<Skeleton className='mt-[24px] h-[44px] w-full rounded-[10px]' />
|
||||
<Skeleton className='mt-[24px] h-[1px] w-full rounded-[1px]' />
|
||||
<div className='mt-[24px] flex w-full gap-[12px]'>
|
||||
<Skeleton className='mt-6 h-[44px] w-full rounded-[10px]' />
|
||||
<Skeleton className='mt-6 h-[1px] w-full rounded-[1px]' />
|
||||
<div className='mt-6 flex w-full gap-3'>
|
||||
<Skeleton className='h-[44px] flex-1 rounded-[10px]' />
|
||||
<Skeleton className='h-[44px] flex-1 rounded-[10px]' />
|
||||
</div>
|
||||
<Skeleton className='mt-[24px] h-[14px] w-[220px] rounded-[4px]' />
|
||||
<Skeleton className='mt-6 h-[14px] w-[220px] rounded-[4px]' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -363,10 +363,10 @@ function SignupFormContent({
|
||||
return (
|
||||
<>
|
||||
<div className='space-y-1 text-center'>
|
||||
<h1 className='font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
<h1 className='text-balance font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
Create an account
|
||||
</h1>
|
||||
<p className='font-[430] font-season text-[#F6F6F6]/60 text-[18px] leading-[125%] tracking-[0.02em]'>
|
||||
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)] text-lg leading-[125%] tracking-[0.02em]'>
|
||||
Create an account or log in
|
||||
</p>
|
||||
</div>
|
||||
@@ -390,105 +390,144 @@ function SignupFormContent({
|
||||
|
||||
{/* Email/Password Form - show unless explicitly disabled */}
|
||||
{!isFalsy(getEnv('NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED')) && (
|
||||
<form onSubmit={onSubmit} className='mt-8 space-y-8'>
|
||||
<form onSubmit={onSubmit} className='mt-8 space-y-10'>
|
||||
<div className='space-y-6'>
|
||||
<div className='space-y-2'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label htmlFor='name'>Full name</Label>
|
||||
</div>
|
||||
<Input
|
||||
id='name'
|
||||
name='name'
|
||||
placeholder='Enter your name'
|
||||
type='text'
|
||||
autoCapitalize='words'
|
||||
autoComplete='name'
|
||||
title='Name can only contain letters, spaces, hyphens, and apostrophes'
|
||||
value={name}
|
||||
onChange={handleNameChange}
|
||||
className={cn(
|
||||
showNameValidationError &&
|
||||
nameErrors.length > 0 &&
|
||||
'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
/>
|
||||
{showNameValidationError && nameErrors.length > 0 && (
|
||||
<div className='mt-1 space-y-1 text-red-400 text-xs'>
|
||||
{nameErrors.map((error, index) => (
|
||||
<p key={index}>{error}</p>
|
||||
))}
|
||||
<div className='relative'>
|
||||
<Input
|
||||
id='name'
|
||||
name='name'
|
||||
placeholder='Enter your name'
|
||||
type='text'
|
||||
autoCapitalize='words'
|
||||
autoComplete='name'
|
||||
title='Name can only contain letters, spaces, hyphens, and apostrophes'
|
||||
value={name}
|
||||
onChange={handleNameChange}
|
||||
className={cn(
|
||||
showNameValidationError &&
|
||||
nameErrors.length > 0 &&
|
||||
'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
'absolute right-0 left-0 z-10 grid transition-[grid-template-rows] duration-200 ease-out',
|
||||
showNameValidationError && nameErrors.length > 0
|
||||
? 'grid-rows-[1fr]'
|
||||
: 'grid-rows-[0fr]'
|
||||
)}
|
||||
aria-live={showNameValidationError && nameErrors.length > 0 ? 'polite' : 'off'}
|
||||
>
|
||||
<div className='overflow-hidden'>
|
||||
<div className='mt-1 space-y-1 text-red-400 text-xs'>
|
||||
{nameErrors.map((error, index) => (
|
||||
<p key={index}>{error}</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='space-y-2'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label htmlFor='email'>Email</Label>
|
||||
</div>
|
||||
<Input
|
||||
id='email'
|
||||
name='email'
|
||||
placeholder='Enter your email'
|
||||
autoCapitalize='none'
|
||||
autoComplete='email'
|
||||
autoCorrect='off'
|
||||
value={email}
|
||||
onChange={handleEmailChange}
|
||||
className={cn(
|
||||
(emailError || (showEmailValidationError && emailErrors.length > 0)) &&
|
||||
'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
/>
|
||||
{showEmailValidationError && emailErrors.length > 0 && (
|
||||
<div className='mt-1 space-y-1 text-red-400 text-xs'>
|
||||
{emailErrors.map((error, index) => (
|
||||
<p key={index}>{error}</p>
|
||||
))}
|
||||
<div className='relative'>
|
||||
<Input
|
||||
id='email'
|
||||
name='email'
|
||||
placeholder='Enter your email'
|
||||
autoCapitalize='none'
|
||||
autoComplete='email'
|
||||
autoCorrect='off'
|
||||
value={email}
|
||||
onChange={handleEmailChange}
|
||||
className={cn(
|
||||
(emailError || (showEmailValidationError && emailErrors.length > 0)) &&
|
||||
'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
'absolute right-0 left-0 z-10 grid transition-[grid-template-rows] duration-200 ease-out',
|
||||
(showEmailValidationError && emailErrors.length > 0) ||
|
||||
(emailError && !showEmailValidationError)
|
||||
? 'grid-rows-[1fr]'
|
||||
: 'grid-rows-[0fr]'
|
||||
)}
|
||||
aria-live={
|
||||
(showEmailValidationError && emailErrors.length > 0) ||
|
||||
(emailError && !showEmailValidationError)
|
||||
? 'polite'
|
||||
: 'off'
|
||||
}
|
||||
>
|
||||
<div className='overflow-hidden'>
|
||||
<div className='mt-1 space-y-1 text-red-400 text-xs'>
|
||||
{showEmailValidationError && emailErrors.length > 0 ? (
|
||||
emailErrors.map((error, index) => <p key={index}>{error}</p>)
|
||||
) : emailError && !showEmailValidationError ? (
|
||||
<p>{emailError}</p>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{emailError && !showEmailValidationError && (
|
||||
<div className='mt-1 text-red-400 text-xs'>
|
||||
<p>{emailError}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='space-y-2'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label htmlFor='password'>Password</Label>
|
||||
</div>
|
||||
<div className='relative'>
|
||||
<Input
|
||||
id='password'
|
||||
name='password'
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
autoCapitalize='none'
|
||||
autoComplete='new-password'
|
||||
placeholder='Enter your password'
|
||||
autoCorrect='off'
|
||||
value={password}
|
||||
onChange={handlePasswordChange}
|
||||
className={cn(
|
||||
'pr-10',
|
||||
showValidationError &&
|
||||
passwordErrors.length > 0 &&
|
||||
'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
/>
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[#999] transition hover:text-[#ECECEC]'
|
||||
aria-label={showPassword ? 'Hide password' : 'Show password'}
|
||||
>
|
||||
{showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
|
||||
</button>
|
||||
</div>
|
||||
{showValidationError && passwordErrors.length > 0 && (
|
||||
<div className='mt-1 space-y-1 text-red-400 text-xs'>
|
||||
{passwordErrors.map((error, index) => (
|
||||
<p key={index}>{error}</p>
|
||||
))}
|
||||
<div className='relative'>
|
||||
<Input
|
||||
id='password'
|
||||
name='password'
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
autoCapitalize='none'
|
||||
autoComplete='new-password'
|
||||
placeholder='Enter your password'
|
||||
autoCorrect='off'
|
||||
value={password}
|
||||
onChange={handlePasswordChange}
|
||||
className={cn(
|
||||
'pr-10',
|
||||
showValidationError &&
|
||||
passwordErrors.length > 0 &&
|
||||
'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
/>
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[var(--landing-text-muted)] transition hover:text-[var(--landing-text)]'
|
||||
aria-label={showPassword ? 'Hide password' : 'Show password'}
|
||||
>
|
||||
{showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
'absolute right-0 left-0 z-10 grid transition-[grid-template-rows] duration-200 ease-out',
|
||||
showValidationError && passwordErrors.length > 0
|
||||
? 'grid-rows-[1fr]'
|
||||
: 'grid-rows-[0fr]'
|
||||
)}
|
||||
aria-live={showValidationError && passwordErrors.length > 0 ? 'polite' : 'off'}
|
||||
>
|
||||
<div className='overflow-hidden'>
|
||||
<div className='mt-1 space-y-1 text-red-400 text-xs'>
|
||||
{passwordErrors.map((error, index) => (
|
||||
<p key={index}>{error}</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -514,6 +553,7 @@ function SignupFormContent({
|
||||
disabled={isLoading}
|
||||
loading={isLoading}
|
||||
loadingText='Creating account'
|
||||
className='!mt-6'
|
||||
>
|
||||
Create account
|
||||
</BrandedButton>
|
||||
@@ -532,10 +572,12 @@ function SignupFormContent({
|
||||
})() && (
|
||||
<div className='relative my-6 font-light'>
|
||||
<div className='absolute inset-0 flex items-center'>
|
||||
<div className='w-full border-[#2A2A2A] border-t' />
|
||||
<div className='w-full border-[var(--landing-bg-elevated)] border-t' />
|
||||
</div>
|
||||
<div className='relative flex justify-center text-sm'>
|
||||
<span className='bg-[#1C1C1C] px-4 font-[340] text-[#999]'>Or continue with</span>
|
||||
<span className='bg-[var(--landing-bg)] px-4 font-[340] text-[var(--landing-text-muted)]'>
|
||||
Or continue with
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -570,23 +612,23 @@ function SignupFormContent({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='pt-6 text-center font-light text-[14px]'>
|
||||
<div className='pt-6 text-center font-light text-sm'>
|
||||
<span className='font-normal'>Already have an account? </span>
|
||||
<Link
|
||||
href={isInviteFlow ? `/login?invite_flow=true&callbackUrl=${redirectUrl}` : '/login'}
|
||||
className='font-medium text-[#ECECEC] underline-offset-4 transition hover:text-white hover:underline'
|
||||
className='font-medium text-[var(--landing-text)] underline-offset-4 transition hover:text-white hover:underline'
|
||||
>
|
||||
Sign in
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className='absolute right-0 bottom-0 left-0 px-8 pb-8 text-center font-[340] text-[#999] text-[13px] leading-relaxed sm:px-8 md:px-[44px]'>
|
||||
<div className='absolute right-0 bottom-0 left-0 px-8 pb-8 text-center font-[340] text-[var(--landing-text-muted)] text-small leading-relaxed sm:px-8 md:px-11'>
|
||||
By creating an account, you agree to our{' '}
|
||||
<Link
|
||||
href='/terms'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[#999] underline-offset-4 transition hover:text-[#ECECEC] hover:underline'
|
||||
className='text-[var(--landing-text-muted)] underline-offset-4 transition hover:text-[var(--landing-text)] hover:underline'
|
||||
>
|
||||
Terms of Service
|
||||
</Link>{' '}
|
||||
@@ -595,7 +637,7 @@ function SignupFormContent({
|
||||
href='/privacy'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[#999] underline-offset-4 transition hover:text-[#ECECEC] hover:underline'
|
||||
className='text-[var(--landing-text-muted)] underline-offset-4 transition hover:text-[var(--landing-text)] hover:underline'
|
||||
>
|
||||
Privacy Policy
|
||||
</Link>
|
||||
|
||||
@@ -4,13 +4,13 @@ export default function SSOLoading() {
|
||||
return (
|
||||
<div className='flex flex-col items-center'>
|
||||
<Skeleton className='h-[38px] w-[120px] rounded-[4px]' />
|
||||
<Skeleton className='mt-[12px] h-[14px] w-[260px] rounded-[4px]' />
|
||||
<div className='mt-[32px] w-full space-y-[8px]'>
|
||||
<Skeleton className='mt-3 h-[14px] w-[260px] rounded-[4px]' />
|
||||
<div className='mt-8 w-full space-y-2'>
|
||||
<Skeleton className='h-[14px] w-[80px] rounded-[4px]' />
|
||||
<Skeleton className='h-[44px] w-full rounded-[10px]' />
|
||||
</div>
|
||||
<Skeleton className='mt-[24px] h-[44px] w-full rounded-[10px]' />
|
||||
<Skeleton className='mt-[24px] h-[14px] w-[120px] rounded-[4px]' />
|
||||
<Skeleton className='mt-6 h-[44px] w-full rounded-[10px]' />
|
||||
<Skeleton className='mt-6 h-[14px] w-[120px] rounded-[4px]' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ export default function VerifyLoading() {
|
||||
return (
|
||||
<div className='flex flex-col items-center'>
|
||||
<Skeleton className='h-[38px] w-[180px] rounded-[4px]' />
|
||||
<Skeleton className='mt-[12px] h-[14px] w-[300px] rounded-[4px]' />
|
||||
<Skeleton className='mt-[4px] h-[14px] w-[240px] rounded-[4px]' />
|
||||
<Skeleton className='mt-[32px] h-[44px] w-full rounded-[10px]' />
|
||||
<Skeleton className='mt-3 h-[14px] w-[300px] rounded-[4px]' />
|
||||
<Skeleton className='mt-1 h-[14px] w-[240px] rounded-[4px]' />
|
||||
<Skeleton className='mt-8 h-[44px] w-full rounded-[10px]' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -59,10 +59,10 @@ function VerificationForm({
|
||||
return (
|
||||
<>
|
||||
<div className='space-y-1 text-center'>
|
||||
<h1 className='font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
<h1 className='text-balance font-[430] font-season text-[40px] text-white leading-[110%] tracking-[-0.02em]'>
|
||||
{isVerified ? 'Email Verified!' : 'Verify Your Email'}
|
||||
</h1>
|
||||
<p className='font-[430] font-season text-[#F6F6F6]/60 text-[18px] leading-[125%] tracking-[0.02em]'>
|
||||
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)] text-lg leading-[125%] tracking-[0.02em]'>
|
||||
{isVerified
|
||||
? 'Your email has been verified. Redirecting to dashboard...'
|
||||
: !isEmailVerificationEnabled
|
||||
@@ -78,7 +78,7 @@ function VerificationForm({
|
||||
{!isVerified && isEmailVerificationEnabled && (
|
||||
<div className='mt-8 space-y-8'>
|
||||
<div className='space-y-6'>
|
||||
<p className='text-center text-[#999] text-sm'>
|
||||
<p className='text-center text-[var(--landing-text-muted)] text-sm'>
|
||||
Enter the 6-digit code to verify your account.
|
||||
{hasEmailService ? " If you don't see it in your inbox, check your spam folder." : ''}
|
||||
</p>
|
||||
@@ -122,15 +122,16 @@ function VerificationForm({
|
||||
|
||||
{hasEmailService && (
|
||||
<div className='text-center'>
|
||||
<p className='text-[#999] text-sm'>
|
||||
<p className='text-[var(--landing-text-muted)] text-sm'>
|
||||
Didn't receive a code?{' '}
|
||||
{countdown > 0 ? (
|
||||
<span>
|
||||
Resend in <span className='font-medium text-[#ECECEC]'>{countdown}s</span>
|
||||
Resend in{' '}
|
||||
<span className='font-medium text-[var(--landing-text)]'>{countdown}s</span>
|
||||
</span>
|
||||
) : (
|
||||
<button
|
||||
className='font-medium text-[#ECECEC] underline-offset-4 transition hover:text-white hover:underline'
|
||||
className='font-medium text-[var(--landing-text)] underline-offset-4 transition hover:text-white hover:underline'
|
||||
onClick={handleResend}
|
||||
disabled={isLoading || isResendDisabled}
|
||||
>
|
||||
@@ -141,7 +142,7 @@ function VerificationForm({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='text-center font-light text-[14px]'>
|
||||
<div className='text-center font-light text-sm'>
|
||||
<button
|
||||
onClick={() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
@@ -151,7 +152,7 @@ function VerificationForm({
|
||||
}
|
||||
router.push('/signup')
|
||||
}}
|
||||
className='font-medium text-[#ECECEC] underline-offset-4 transition hover:text-white hover:underline'
|
||||
className='font-medium text-[var(--landing-text)] underline-offset-4 transition hover:text-white hover:underline'
|
||||
>
|
||||
Back to signup
|
||||
</button>
|
||||
@@ -166,8 +167,8 @@ function VerificationFormFallback() {
|
||||
return (
|
||||
<div className='text-center'>
|
||||
<div className='animate-pulse'>
|
||||
<div className='mx-auto mb-4 h-8 w-48 rounded bg-[#2A2A2A]' />
|
||||
<div className='mx-auto h-4 w-64 rounded bg-[#2A2A2A]' />
|
||||
<div className='mx-auto mb-4 h-8 w-48 rounded bg-[var(--surface-4)]' />
|
||||
<div className='mx-auto h-4 w-64 rounded bg-[var(--surface-4)]' />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -25,7 +25,7 @@ function DotGrid({ className, cols, rows, gap = 0 }: DotGridProps) {
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: cols * rows }, (_, i) => (
|
||||
<div key={i} className='h-[1.5px] w-[1.5px] rounded-full bg-[#2A2A2A]' />
|
||||
<div key={i} className='h-[1.5px] w-[1.5px] rounded-full bg-[var(--landing-bg-elevated)]' />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
@@ -89,7 +89,7 @@ function VikhyathCursor() {
|
||||
<div className='absolute top-0 left-[56.02px]'>
|
||||
<CursorArrow fill='#2ABBF8' />
|
||||
</div>
|
||||
<div className='-left-[4px] absolute top-[18px] flex items-center rounded bg-[#2ABBF8] px-[5px] py-[3px] font-[420] font-season text-[#202020] text-[14px] leading-[100%] tracking-[-0.02em]'>
|
||||
<div className='-left-[4px] absolute top-4.5 flex items-center rounded bg-[#2ABBF8] px-[5px] py-[3px] font-[420] font-season text-[var(--landing-text-dark)] text-sm leading-[100%] tracking-[-0.02em]'>
|
||||
Vikhyath
|
||||
</div>
|
||||
</div>
|
||||
@@ -113,7 +113,7 @@ function AlexaCursor() {
|
||||
<div className='absolute top-0 left-0'>
|
||||
<CursorArrow fill='#FFCC02' />
|
||||
</div>
|
||||
<div className='absolute top-[16px] left-[23px] flex items-center rounded bg-[#FFCC02] px-[5px] py-[3px] font-[420] font-season text-[#202020] text-[14px] leading-[100%] tracking-[-0.02em]'>
|
||||
<div className='absolute top-4 left-[23px] flex items-center rounded bg-[#FFCC02] px-[5px] py-[3px] font-[420] font-season text-[var(--landing-text-dark)] text-sm leading-[100%] tracking-[-0.02em]'>
|
||||
Alexa
|
||||
</div>
|
||||
</div>
|
||||
@@ -143,7 +143,7 @@ function YouCursor({ x, y, visible }: YouCursorProps) {
|
||||
<svg width='23.15' height='21.1' viewBox='0 0 17.5 16.4' fill='none'>
|
||||
<path d={CURSOR_ARROW_MIRRORED_PATH} fill='#33C482' />
|
||||
</svg>
|
||||
<div className='absolute top-[16px] left-[23px] flex items-center rounded bg-[#33C482] px-[5px] py-[3px] font-[420] font-season text-[#202020] text-[14px] leading-[100%] tracking-[-0.02em]'>
|
||||
<div className='absolute top-4 left-[23px] flex items-center rounded bg-[var(--brand-accent)] px-[5px] py-[3px] font-[420] font-season text-[var(--landing-text-dark)] text-sm leading-[100%] tracking-[-0.02em]'>
|
||||
You
|
||||
</div>
|
||||
</div>
|
||||
@@ -212,7 +212,7 @@ export default function Collaboration() {
|
||||
ref={sectionRef}
|
||||
id='collaboration'
|
||||
aria-labelledby='collaboration-heading'
|
||||
className='bg-[#1C1C1C]'
|
||||
className='bg-[var(--landing-bg)]'
|
||||
style={{ cursor: isHovering ? 'none' : 'auto' }}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
@@ -222,7 +222,7 @@ export default function Collaboration() {
|
||||
<style dangerouslySetInnerHTML={{ __html: CURSOR_KEYFRAMES }} />
|
||||
|
||||
<DotGrid
|
||||
className='overflow-hidden border-[#2A2A2A] border-y bg-[#1C1C1C] p-[6px]'
|
||||
className='overflow-hidden border-[var(--landing-bg-elevated)] border-y bg-[var(--landing-bg)] p-1.5'
|
||||
cols={120}
|
||||
rows={1}
|
||||
gap={6}
|
||||
@@ -230,33 +230,33 @@ export default function Collaboration() {
|
||||
|
||||
<div className='relative overflow-hidden'>
|
||||
<div className='grid grid-cols-1 md:grid-cols-[auto_1fr]'>
|
||||
<div className='flex flex-col items-start gap-3 px-4 pt-[60px] pb-8 sm:gap-4 sm:px-8 md:gap-[20px] md:px-[80px] md:pt-[100px]'>
|
||||
<div className='flex flex-col items-start gap-3 px-4 pt-[60px] pb-8 sm:gap-4 sm:px-8 md:gap-5 md:px-20 md:pt-[100px]'>
|
||||
<Badge
|
||||
variant='blue'
|
||||
size='md'
|
||||
dot
|
||||
className='bg-[#33C482]/10 font-season text-[#33C482] uppercase tracking-[0.02em]'
|
||||
className='bg-[color-mix(in_srgb,var(--brand-accent)_10%,transparent)] font-season text-[var(--brand-accent)] uppercase tracking-[0.02em]'
|
||||
>
|
||||
Teams
|
||||
</Badge>
|
||||
|
||||
<h2
|
||||
id='collaboration-heading'
|
||||
className='font-[430] font-season text-[32px] text-white leading-[100%] tracking-[-0.02em] sm:text-[36px] md:text-[40px]'
|
||||
className='text-balance font-[430] font-season text-[32px] text-white leading-[100%] tracking-[-0.02em] sm:text-[36px] md:text-[40px]'
|
||||
>
|
||||
Realtime
|
||||
<br />
|
||||
collaboration
|
||||
</h2>
|
||||
|
||||
<p className='font-[430] font-season text-[#F6F6F0]/50 text-[15px] leading-[150%] tracking-[0.02em] md:text-[18px]'>
|
||||
<p className='font-[430] font-season text-[#F6F6F0]/50 text-base leading-[150%] tracking-[0.02em] md:text-lg'>
|
||||
Grab your team. Build agents together <br className='hidden md:block' />
|
||||
in real-time inside your workspace.
|
||||
</p>
|
||||
|
||||
<Link
|
||||
href='/signup'
|
||||
className='group/cta mt-[12px] inline-flex h-[32px] cursor-none items-center gap-[6px] rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] px-[10px] font-[430] font-season text-[14px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
className='group/cta mt-3 inline-flex h-[32px] cursor-none items-center gap-1.5 rounded-[5px] border border-white bg-white px-2.5 font-[430] font-season text-black text-sm transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
>
|
||||
Build together
|
||||
<span className='relative h-[10px] w-[10px] shrink-0'>
|
||||
@@ -306,16 +306,16 @@ export default function Collaboration() {
|
||||
href='/blog/multiplayer'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='relative mx-4 mb-6 flex cursor-none items-center gap-[14px] rounded-[5px] border border-[#2A2A2A] bg-[#1C1C1C] px-[12px] py-[10px] transition-colors hover:border-[#3d3d3d] hover:bg-[#232323] sm:mx-8 md:absolute md:bottom-10 md:left-[80px] md:z-20 md:mx-0 md:mb-0'
|
||||
className='relative mx-4 mb-6 flex cursor-none items-center gap-3.5 rounded-[5px] border border-[var(--landing-bg-elevated)] bg-[var(--landing-bg)] px-3 py-2.5 transition-colors hover:border-[var(--landing-border-strong)] hover:bg-[var(--landing-bg-card)] sm:mx-8 md:absolute md:bottom-10 md:left-20 md:z-20 md:mx-0 md:mb-0'
|
||||
>
|
||||
<div className='relative h-7 w-11 shrink-0'>
|
||||
<Image src='/landing/multiplayer-cursors.svg' alt='' fill className='object-contain' />
|
||||
</div>
|
||||
<div className='flex flex-col gap-[2px]'>
|
||||
<span className='font-[430] font-season text-[#F6F6F0]/50 text-[12px] uppercase leading-[100%] tracking-[0.08em]'>
|
||||
<div className='flex flex-col gap-0.5'>
|
||||
<span className='font-[430] font-season text-[#F6F6F0]/50 text-caption uppercase leading-[100%] tracking-[0.08em]'>
|
||||
Blog
|
||||
</span>
|
||||
<span className='font-[430] font-season text-[#F6F6F0] text-[14px] leading-[125%] tracking-[0.02em]'>
|
||||
<span className='font-[430] font-season text-[#F6F6F0] text-sm leading-[125%] tracking-[0.02em]'>
|
||||
How we built realtime collaboration
|
||||
</span>
|
||||
</div>
|
||||
@@ -323,7 +323,7 @@ export default function Collaboration() {
|
||||
</div>
|
||||
|
||||
<DotGrid
|
||||
className='overflow-hidden border-[#2A2A2A] border-y bg-[#1C1C1C] p-[6px]'
|
||||
className='overflow-hidden border-[var(--landing-bg-elevated)] border-y bg-[var(--landing-bg)] p-1.5'
|
||||
cols={120}
|
||||
rows={1}
|
||||
gap={6}
|
||||
|
||||
@@ -100,14 +100,14 @@ export function AccessControlPanel() {
|
||||
<span className='font-[430] font-season text-[#F6F6F6]/30 text-[10px] uppercase leading-none tracking-[0.08em]'>
|
||||
{category.label}
|
||||
</span>
|
||||
<div className='mt-[8px] grid grid-cols-2 gap-x-4 gap-y-[8px]'>
|
||||
<div className='mt-2 grid grid-cols-2 gap-x-4 gap-y-2'>
|
||||
{category.features.map((feature, featIdx) => {
|
||||
const enabled = accessState[feature.key]
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={feature.key}
|
||||
className='flex cursor-pointer items-center gap-[8px] rounded-[4px] py-[2px]'
|
||||
className='flex cursor-pointer items-center gap-2 rounded-[4px] py-0.5'
|
||||
initial={{ opacity: 0, x: -6 }}
|
||||
animate={isInView ? { opacity: 1, x: 0 } : {}}
|
||||
transition={{
|
||||
@@ -143,7 +143,7 @@ export function AccessControlPanel() {
|
||||
<span className='font-[430] font-season text-[#F6F6F6]/30 text-[10px] uppercase leading-none tracking-[0.08em]'>
|
||||
{category.label}
|
||||
</span>
|
||||
<div className='mt-[8px] grid grid-cols-2 gap-x-4 gap-y-[8px]'>
|
||||
<div className='mt-2 grid grid-cols-2 gap-x-4 gap-y-2'>
|
||||
{category.features.map((feature, featIdx) => {
|
||||
const enabled = accessState[feature.key]
|
||||
const currentIndex =
|
||||
@@ -155,7 +155,7 @@ export function AccessControlPanel() {
|
||||
return (
|
||||
<motion.div
|
||||
key={feature.key}
|
||||
className='flex cursor-pointer items-center gap-[8px] rounded-[4px] py-[2px]'
|
||||
className='flex cursor-pointer items-center gap-2 rounded-[4px] py-0.5'
|
||||
initial={{ opacity: 0, x: -6 }}
|
||||
animate={isInView ? { opacity: 1, x: 0 } : {}}
|
||||
transition={{
|
||||
|
||||
@@ -125,7 +125,7 @@ function AuditRow({ entry, index }: AuditRowProps) {
|
||||
const timeAgo = formatTimeAgo(entry.insertedAt)
|
||||
|
||||
return (
|
||||
<div className='group relative overflow-hidden border-[#2A2A2A] border-b bg-[#1C1C1C] transition-colors duration-150 last:border-b-0 hover:bg-[#212121]'>
|
||||
<div className='group relative overflow-hidden border-[var(--landing-border)] border-b bg-[var(--landing-bg)] transition-colors duration-150 last:border-b-0 hover:bg-[#212121]'>
|
||||
{/* Left accent bar -- brightness encodes recency */}
|
||||
<div
|
||||
aria-hidden='true'
|
||||
@@ -209,8 +209,8 @@ export function AuditLogPreview() {
|
||||
transition={{
|
||||
layout: {
|
||||
type: 'spring',
|
||||
stiffness: 380,
|
||||
damping: 38,
|
||||
stiffness: 350,
|
||||
damping: 50,
|
||||
mass: 0.8,
|
||||
},
|
||||
y: { duration: 0.32, ease: [0.25, 0.46, 0.45, 0.94] },
|
||||
|
||||
@@ -22,13 +22,27 @@ import { DemoRequestModal } from '@/app/(home)/components/demo-request/demo-requ
|
||||
import { AccessControlPanel } from '@/app/(home)/components/enterprise/components/access-control-panel'
|
||||
import { AuditLogPreview } from '@/app/(home)/components/enterprise/components/audit-log-preview'
|
||||
|
||||
const MARQUEE_KEYFRAMES = `
|
||||
@keyframes marquee {
|
||||
const ENTERPRISE_FEATURE_MARQUEE_STYLES = `
|
||||
@keyframes enterprise-feature-marquee {
|
||||
0% { transform: translateX(0); }
|
||||
100% { transform: translateX(-25%); }
|
||||
}
|
||||
.enterprise-feature-marquee-track {
|
||||
animation: enterprise-feature-marquee 30s linear infinite;
|
||||
}
|
||||
.enterprise-feature-marquee:hover .enterprise-feature-marquee-track {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
.enterprise-feature-marquee-tag {
|
||||
transition: background-color 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
@keyframes marquee { 0%, 100% { transform: none; } }
|
||||
.enterprise-feature-marquee-track {
|
||||
animation: none;
|
||||
}
|
||||
.enterprise-feature-marquee-tag {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@@ -51,13 +65,13 @@ const FEATURE_TAGS = [
|
||||
|
||||
function TrustStrip() {
|
||||
return (
|
||||
<div className='mx-6 mt-4 grid grid-cols-1 overflow-hidden rounded-[8px] border border-[#2A2A2A] sm:grid-cols-3 md:mx-8'>
|
||||
<div className='mx-6 mt-4 grid grid-cols-1 overflow-hidden rounded-lg border border-[var(--landing-bg-elevated)] sm:grid-cols-3 md:mx-8'>
|
||||
{/* SOC 2 + HIPAA combined */}
|
||||
<Link
|
||||
href='https://app.vanta.com/sim.ai/trust/v35ia0jil4l7dteqjgaktn'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='group flex items-center gap-3 border-[#2A2A2A] border-b px-4 py-[14px] transition-colors hover:bg-[#212121] sm:border-r sm:border-b-0'
|
||||
className='group flex items-center gap-3 border-[var(--landing-bg-elevated)] border-b px-4 py-3.5 transition-colors hover:bg-[#212121] sm:border-r sm:border-b-0'
|
||||
>
|
||||
<Image
|
||||
src='/footer/soc2.png'
|
||||
@@ -68,10 +82,10 @@ function TrustStrip() {
|
||||
unoptimized
|
||||
/>
|
||||
<div className='flex flex-col gap-[3px]'>
|
||||
<strong className='font-[430] font-season text-[13px] text-white leading-none'>
|
||||
<strong className='font-[430] font-season text-small text-white leading-none'>
|
||||
SOC 2 & HIPAA
|
||||
</strong>
|
||||
<span className='font-[430] font-season text-[#F6F6F6]/30 text-[11px] leading-none tracking-[0.02em] transition-colors group-hover:text-[#F6F6F6]/55'>
|
||||
<span className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_30%,transparent)] text-xs leading-none tracking-[0.02em] transition-colors group-hover:text-[color-mix(in_srgb,var(--landing-text-subtle)_55%,transparent)]'>
|
||||
Type II · PHI protected →
|
||||
</span>
|
||||
</div>
|
||||
@@ -82,31 +96,31 @@ function TrustStrip() {
|
||||
href='https://github.com/simstudioai/sim'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='group flex items-center gap-3 border-[#2A2A2A] border-b px-4 py-[14px] transition-colors hover:bg-[#212121] sm:border-r sm:border-b-0'
|
||||
className='group flex items-center gap-3 border-[var(--landing-bg-elevated)] border-b px-4 py-3.5 transition-colors hover:bg-[#212121] sm:border-r sm:border-b-0'
|
||||
>
|
||||
<div className='flex h-[22px] w-[22px] shrink-0 items-center justify-center rounded-full bg-[#FFCC02]/10'>
|
||||
<GithubIcon width={11} height={11} className='text-[#FFCC02]/75' />
|
||||
</div>
|
||||
<div className='flex flex-col gap-[3px]'>
|
||||
<strong className='font-[430] font-season text-[13px] text-white leading-none'>
|
||||
<strong className='font-[430] font-season text-small text-white leading-none'>
|
||||
Open Source
|
||||
</strong>
|
||||
<span className='font-[430] font-season text-[#F6F6F6]/30 text-[11px] leading-none tracking-[0.02em] transition-colors group-hover:text-[#F6F6F6]/55'>
|
||||
<span className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_30%,transparent)] text-xs leading-none tracking-[0.02em] transition-colors group-hover:text-[color-mix(in_srgb,var(--landing-text-subtle)_55%,transparent)]'>
|
||||
View on GitHub →
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
{/* SSO */}
|
||||
<div className='flex items-center gap-3 px-4 py-[14px]'>
|
||||
<div className='flex items-center gap-3 px-4 py-3.5'>
|
||||
<div className='flex h-[22px] w-[22px] shrink-0 items-center justify-center rounded-full bg-[#2ABBF8]/10'>
|
||||
<Lock className='h-[14px] w-[14px] text-[#2ABBF8]/75' />
|
||||
</div>
|
||||
<div className='flex flex-col gap-[3px]'>
|
||||
<strong className='font-[430] font-season text-[13px] text-white leading-none'>
|
||||
<strong className='font-[430] font-season text-small text-white leading-none'>
|
||||
SSO & SCIM
|
||||
</strong>
|
||||
<span className='font-[430] font-season text-[#F6F6F6]/30 text-[11px] leading-none tracking-[0.02em]'>
|
||||
<span className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_30%,transparent)] text-xs leading-none tracking-[0.02em]'>
|
||||
Okta, Azure AD, Google
|
||||
</span>
|
||||
</div>
|
||||
@@ -117,9 +131,13 @@ function TrustStrip() {
|
||||
|
||||
export default function Enterprise() {
|
||||
return (
|
||||
<section id='enterprise' aria-labelledby='enterprise-heading' className='bg-[#F6F6F6]'>
|
||||
<div className='px-4 pt-[60px] pb-[40px] sm:px-8 sm:pt-[80px] sm:pb-0 md:px-[80px] md:pt-[100px]'>
|
||||
<div className='flex flex-col items-start gap-3 sm:gap-4 md:gap-[20px]'>
|
||||
<section
|
||||
id='enterprise'
|
||||
aria-labelledby='enterprise-heading'
|
||||
className='bg-[var(--landing-bg-section)]'
|
||||
>
|
||||
<div className='px-4 pt-[60px] pb-10 sm:px-8 sm:pt-20 sm:pb-0 md:px-20 md:pt-[100px]'>
|
||||
<div className='flex flex-col items-start gap-3 sm:gap-4 md:gap-5'>
|
||||
<Badge
|
||||
variant='blue'
|
||||
size='md'
|
||||
@@ -131,7 +149,7 @@ export default function Enterprise() {
|
||||
|
||||
<h2
|
||||
id='enterprise-heading'
|
||||
className='max-w-[600px] font-[430] font-season text-[#1C1C1C] text-[32px] leading-[100%] tracking-[-0.02em] sm:text-[36px] md:text-[40px]'
|
||||
className='max-w-[600px] text-balance font-[430] font-season text-[32px] text-[var(--landing-text-dark)] leading-[100%] tracking-[-0.02em] sm:text-[36px] md:text-[40px]'
|
||||
>
|
||||
Enterprise features for
|
||||
<br />
|
||||
@@ -139,10 +157,10 @@ export default function Enterprise() {
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 overflow-hidden rounded-[12px] bg-[#1C1C1C] sm:mt-10 md:mt-12'>
|
||||
<div className='grid grid-cols-1 border-[#2A2A2A] border-b lg:grid-cols-[1fr_420px]'>
|
||||
<div className='mt-8 overflow-hidden rounded-[12px] bg-[var(--landing-bg)] sm:mt-10 md:mt-12'>
|
||||
<div className='grid grid-cols-1 border-[var(--landing-border)] border-b lg:grid-cols-[1fr_420px]'>
|
||||
{/* Audit Trail */}
|
||||
<div className='border-[#2A2A2A] lg:border-r'>
|
||||
<div className='border-[var(--landing-border)] lg:border-r'>
|
||||
<div className='px-6 pt-6 md:px-8 md:pt-8'>
|
||||
<h3 className='font-[430] font-season text-[16px] text-white leading-[120%] tracking-[-0.01em]'>
|
||||
Audit Trail
|
||||
@@ -156,12 +174,12 @@ export default function Enterprise() {
|
||||
</div>
|
||||
|
||||
{/* Access Control */}
|
||||
<div className='border-[#2A2A2A] border-t lg:border-t-0'>
|
||||
<div className='border-[var(--landing-border)] border-t lg:border-t-0'>
|
||||
<div className='px-6 pt-6 md:px-8 md:pt-8'>
|
||||
<h3 className='font-[430] font-season text-[16px] text-white leading-[120%] tracking-[-0.01em]'>
|
||||
Access Control
|
||||
</h3>
|
||||
<p className='mt-[6px] font-[430] font-season text-[#F6F6F6]/50 text-[14px] leading-[150%] tracking-[0.02em]'>
|
||||
<p className='mt-1.5 font-[430] font-season text-[#F6F6F6]/50 text-[14px] leading-[150%] tracking-[0.02em]'>
|
||||
Restrict providers, surfaces, and tools per group.
|
||||
</p>
|
||||
</div>
|
||||
@@ -173,27 +191,27 @@ export default function Enterprise() {
|
||||
|
||||
<TrustStrip />
|
||||
|
||||
{/* Scrolling feature ticker */}
|
||||
<div className='relative mt-6 overflow-hidden border-[#2A2A2A] border-t'>
|
||||
<style dangerouslySetInnerHTML={{ __html: MARQUEE_KEYFRAMES }} />
|
||||
{/* Scrolling feature ticker — keyframe loop; pause on hover. Tags use transitions for hover. */}
|
||||
<div className='enterprise-feature-marquee relative mt-6 overflow-hidden border-[var(--landing-bg-elevated)] border-t'>
|
||||
<style dangerouslySetInnerHTML={{ __html: ENTERPRISE_FEATURE_MARQUEE_STYLES }} />
|
||||
{/* Fade edges */}
|
||||
<div
|
||||
aria-hidden='true'
|
||||
className='pointer-events-none absolute top-0 bottom-0 left-0 z-10 w-24'
|
||||
style={{ background: 'linear-gradient(to right, #1C1C1C, transparent)' }}
|
||||
style={{ background: 'linear-gradient(to right, var(--landing-bg), transparent)' }}
|
||||
/>
|
||||
<div
|
||||
aria-hidden='true'
|
||||
className='pointer-events-none absolute top-0 right-0 bottom-0 z-10 w-24'
|
||||
style={{ background: 'linear-gradient(to left, #1C1C1C, transparent)' }}
|
||||
style={{ background: 'linear-gradient(to left, var(--landing-bg), transparent)' }}
|
||||
/>
|
||||
{/* Duplicate tags for seamless loop */}
|
||||
<div className='flex w-max' style={{ animation: 'marquee 30s linear infinite' }}>
|
||||
<div className='enterprise-feature-marquee-track flex w-max'>
|
||||
{[...FEATURE_TAGS, ...FEATURE_TAGS, ...FEATURE_TAGS, ...FEATURE_TAGS].map(
|
||||
(tag, i) => (
|
||||
<span
|
||||
key={i}
|
||||
className='whitespace-nowrap border-[#2A2A2A] border-r px-5 py-4 font-[430] font-season text-[#F6F6F6]/40 text-[13px] leading-none tracking-[0.02em]'
|
||||
className='enterprise-feature-marquee-tag whitespace-nowrap border-[var(--landing-bg-elevated)] border-r px-5 py-4 font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_40%,transparent)] text-small leading-none tracking-[0.02em] hover:bg-white/[0.04] hover:text-[color-mix(in_srgb,var(--landing-text-subtle)_55%,transparent)]'
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
@@ -202,14 +220,14 @@ export default function Enterprise() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex items-center justify-between border-[#2A2A2A] border-t px-6 py-5 md:px-8 md:py-6'>
|
||||
<p className='font-[430] font-season text-[#F6F6F6]/40 text-[15px] leading-[150%] tracking-[0.02em]'>
|
||||
<div className='flex items-center justify-between border-[var(--landing-bg-elevated)] border-t px-6 py-5 md:px-8 md:py-6'>
|
||||
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_40%,transparent)] text-base leading-[150%] tracking-[0.02em]'>
|
||||
Ready for growth?
|
||||
</p>
|
||||
<DemoRequestModal>
|
||||
<button
|
||||
type='button'
|
||||
className='group/cta inline-flex h-[32px] cursor-pointer items-center gap-[6px] rounded-[5px] border border-white bg-white px-[10px] font-[430] font-season text-[14px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
className='group/cta inline-flex h-[32px] cursor-pointer items-center gap-1.5 rounded-[5px] border border-white bg-white px-2.5 font-[430] font-season text-[14px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
>
|
||||
Book a demo
|
||||
<span className='relative h-[10px] w-[10px] shrink-0'>
|
||||
|
||||
@@ -304,7 +304,7 @@ function WorkspacePreview({ activeTab, isActive }: { activeTab: number; isActive
|
||||
|
||||
function MockUserInput({ text }: { text: string }) {
|
||||
return (
|
||||
<div className='flex w-[380px] items-center gap-[6px] rounded-[16px] border border-[#E0E0E0] bg-white px-[10px] py-[8px] shadow-[0_2px_8px_rgba(0,0,0,0.06)]'>
|
||||
<div className='flex w-[380px] items-center gap-1.5 rounded-[16px] border border-[#E0E0E0] bg-white px-2.5 py-2 shadow-[0_2px_8px_rgba(0,0,0,0.06)]'>
|
||||
<div className='flex h-[24px] w-[24px] flex-shrink-0 items-center justify-center rounded-full border border-[#E8E8E8]'>
|
||||
<svg width='12' height='12' viewBox='0 0 12 12' fill='none'>
|
||||
<path d='M6 2.5v7M2.5 6h7' stroke='#999' strokeWidth='1.5' strokeLinecap='round' />
|
||||
@@ -364,7 +364,7 @@ function MiniCardHeader({
|
||||
color?: string
|
||||
}) {
|
||||
return (
|
||||
<div className='flex items-center gap-[4px] border-[#F0F0F0] border-b px-[8px] py-[5px]'>
|
||||
<div className='flex items-center gap-1 border-[#F0F0F0] border-b px-2 py-1.5'>
|
||||
<MiniCardIcon variant={variant} color={color} />
|
||||
<span className='truncate font-medium text-[#888] text-[7px] leading-none'>{label}</span>
|
||||
</div>
|
||||
@@ -419,7 +419,7 @@ function MiniCardBody({ variant, color }: { variant: CardVariant; color?: string
|
||||
|
||||
function PromptCardBody() {
|
||||
return (
|
||||
<div className='px-[8px] py-[6px]'>
|
||||
<div className='px-2 py-1.5'>
|
||||
<p className='break-words text-[#AAAAAA] text-[6.5px] leading-[10px]'>{TYPING_PROMPT}</p>
|
||||
</div>
|
||||
)
|
||||
@@ -427,7 +427,7 @@ function PromptCardBody() {
|
||||
|
||||
function FileCardBody() {
|
||||
return (
|
||||
<div className='flex flex-col gap-[3px] px-[8px] py-[6px]'>
|
||||
<div className='flex flex-col gap-[3px] px-2 py-1.5'>
|
||||
<div className='h-[2px] w-[78%] rounded-full bg-[#E8E8E8]' />
|
||||
<div className='h-[2px] w-[92%] rounded-full bg-[#E8E8E8]' />
|
||||
<div className='h-[2px] w-[62%] rounded-full bg-[#E8E8E8]' />
|
||||
@@ -450,7 +450,7 @@ const TABLE_ROW_WIDTHS = [
|
||||
function TableCardBody() {
|
||||
return (
|
||||
<div className='flex flex-col'>
|
||||
<div className='flex items-center gap-[4px] bg-[#FAFAFA] px-[6px] py-[3px]'>
|
||||
<div className='flex items-center gap-1 bg-[#FAFAFA] px-1.5 py-[3px]'>
|
||||
<div className='h-[2px] flex-1 rounded-full bg-[#D4D4D4]' />
|
||||
<div className='h-[2px] flex-1 rounded-full bg-[#D4D4D4]' />
|
||||
<div className='h-[2px] flex-1 rounded-full bg-[#D4D4D4]' />
|
||||
@@ -458,7 +458,7 @@ function TableCardBody() {
|
||||
{TABLE_ROW_WIDTHS.map((row, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className='flex items-center gap-[4px] border-[#F5F5F5] border-b px-[6px] py-[3.5px]'
|
||||
className='flex items-center gap-1 border-[#F5F5F5] border-b px-1.5 py-[3.5px]'
|
||||
>
|
||||
<div className='h-[1.5px] rounded-full bg-[#EBEBEB]' style={{ width: `${row[0]}%` }} />
|
||||
<div className='h-[1.5px] rounded-full bg-[#EBEBEB]' style={{ width: `${row[1]}%` }} />
|
||||
@@ -472,17 +472,17 @@ function TableCardBody() {
|
||||
function WorkflowCardBody({ color }: { color: string }) {
|
||||
return (
|
||||
<div className='relative h-full w-full'>
|
||||
<div className='absolute top-[10px] left-[10px] h-[14px] w-[14px] rounded-[3px] border border-[#E0E0E0] bg-[#F8F8F8]' />
|
||||
<div className='absolute top-2.5 left-[10px] h-[14px] w-[14px] rounded-[3px] border border-[#E0E0E0] bg-[#F8F8F8]' />
|
||||
<div className='absolute top-[16px] left-[24px] h-[1px] w-[16px] bg-[#D8D8D8]' />
|
||||
<div
|
||||
className='absolute top-[10px] left-[40px] h-[14px] w-[14px] rounded-[3px] border-[2px]'
|
||||
className='absolute top-2.5 left-[40px] h-[14px] w-[14px] rounded-[3px] border-[2px]'
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderColor: `${color}60`,
|
||||
backgroundClip: 'padding-box',
|
||||
}}
|
||||
/>
|
||||
<div className='absolute top-[24px] left-[46px] h-[12px] w-[1px] bg-[#D8D8D8]' />
|
||||
<div className='absolute top-6 left-[46px] h-[12px] w-[1px] bg-[#D8D8D8]' />
|
||||
<div className='absolute top-[36px] left-[40px] h-[14px] w-[14px] rounded-[3px] border border-[#E0E0E0] bg-[#F8F8F8]' />
|
||||
<div className='absolute top-[42px] left-[54px] h-[1px] w-[14px] bg-[#D8D8D8]' />
|
||||
<div
|
||||
@@ -502,9 +502,9 @@ const KB_WIDTHS = [70, 85, 55, 80, 48] as const
|
||||
|
||||
function KnowledgeCardBody() {
|
||||
return (
|
||||
<div className='flex flex-col gap-[5px] px-[8px] py-[6px]'>
|
||||
<div className='flex flex-col gap-[5px] px-2 py-1.5'>
|
||||
{KB_WIDTHS.map((w, i) => (
|
||||
<div key={i} className='flex items-center gap-[4px]'>
|
||||
<div key={i} className='flex items-center gap-1'>
|
||||
<div className='h-[3px] w-[3px] flex-shrink-0 rounded-full bg-[#D4D4D4]' />
|
||||
<div className='h-[1.5px] rounded-full bg-[#E8E8E8]' style={{ width: `${w}%` }} />
|
||||
</div>
|
||||
@@ -524,9 +524,9 @@ const LOG_ENTRIES = [
|
||||
|
||||
function LogsCardBody() {
|
||||
return (
|
||||
<div className='flex flex-col gap-[3px] px-[6px] py-[4px]'>
|
||||
<div className='flex flex-col gap-[3px] px-1.5 py-1'>
|
||||
{LOG_ENTRIES.map((entry, i) => (
|
||||
<div key={i} className='flex items-center gap-[4px] py-[1px]'>
|
||||
<div key={i} className='flex items-center gap-1 py-[1px]'>
|
||||
<div
|
||||
className='h-[3px] w-[3px] flex-shrink-0 rounded-full'
|
||||
style={{ backgroundColor: entry.color }}
|
||||
@@ -620,8 +620,8 @@ const MD_COMPONENTS: Components = {
|
||||
{children}
|
||||
</h2>
|
||||
),
|
||||
ul: ({ children }) => <ul className='mb-3 list-disc pl-[24px]'>{children}</ul>,
|
||||
ol: ({ children }) => <ol className='mb-3 list-decimal pl-[24px]'>{children}</ol>,
|
||||
ul: ({ children }) => <ul className='mb-3 list-disc pl-6'>{children}</ul>,
|
||||
ol: ({ children }) => <ol className='mb-3 list-decimal pl-6'>{children}</ol>,
|
||||
li: ({ children }) => (
|
||||
<li className='mb-1 text-[#1C1C1C] text-[14px] leading-[1.6]'>{children}</li>
|
||||
),
|
||||
@@ -633,8 +633,8 @@ function MockFullFiles() {
|
||||
|
||||
return (
|
||||
<div className='flex h-full flex-col'>
|
||||
<div className='flex h-[44px] shrink-0 items-center border-[#E5E5E5] border-b px-[24px]'>
|
||||
<div className='flex items-center gap-[6px]'>
|
||||
<div className='flex h-[44px] shrink-0 items-center border-[#E5E5E5] border-b px-6'>
|
||||
<div className='flex items-center gap-1.5'>
|
||||
<File className='h-[14px] w-[14px] text-[#999]' />
|
||||
<span className='text-[#999] text-[13px]'>Files</span>
|
||||
<span className='text-[#D4D4D4] text-[13px]'>/</span>
|
||||
@@ -654,7 +654,7 @@ function MockFullFiles() {
|
||||
onChange={(e) => setSource(e.target.value)}
|
||||
spellCheck={false}
|
||||
autoCorrect='off'
|
||||
className='h-full w-full resize-none overflow-auto whitespace-pre-wrap bg-transparent p-[24px] font-[300] font-mono text-[#1C1C1C] text-[12px] leading-[1.7] outline-none'
|
||||
className='h-full w-full resize-none overflow-auto whitespace-pre-wrap bg-transparent p-6 font-[300] font-mono text-[#1C1C1C] text-[12px] leading-[1.7] outline-none'
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
@@ -666,7 +666,7 @@ function MockFullFiles() {
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.4, delay: 0.5 }}
|
||||
>
|
||||
<div className='h-full overflow-auto p-[24px]'>
|
||||
<div className='h-full overflow-auto p-6'>
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]} components={MD_COMPONENTS}>
|
||||
{source}
|
||||
</ReactMarkdown>
|
||||
@@ -686,8 +686,8 @@ const KB_STATUS_STYLES: Record<string, { bg: string; text: string; label: string
|
||||
function MockFullKnowledgeBase({ revealedRows }: { revealedRows: number }) {
|
||||
return (
|
||||
<div className='flex h-full flex-col'>
|
||||
<div className='flex h-[44px] shrink-0 items-center border-[#E5E5E5] border-b px-[24px]'>
|
||||
<div className='flex items-center gap-[6px]'>
|
||||
<div className='flex h-[44px] shrink-0 items-center border-[#E5E5E5] border-b px-6'>
|
||||
<div className='flex items-center gap-1.5'>
|
||||
<Database className='h-[14px] w-[14px] text-[#999]' />
|
||||
<span className='text-[#999] text-[13px]'>Knowledge Base</span>
|
||||
<span className='text-[#D4D4D4] text-[13px]'>/</span>
|
||||
@@ -695,12 +695,12 @@ function MockFullKnowledgeBase({ revealedRows }: { revealedRows: number }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex h-[36px] shrink-0 items-center border-[#E5E5E5] border-b px-[24px]'>
|
||||
<div className='flex items-center gap-[6px]'>
|
||||
<div className='flex h-[24px] items-center gap-[4px] rounded-[6px] border border-[#E5E5E5] px-[8px] text-[#999] text-[12px]'>
|
||||
<div className='flex h-[36px] shrink-0 items-center border-[#E5E5E5] border-b px-6'>
|
||||
<div className='flex items-center gap-1.5'>
|
||||
<div className='flex h-[24px] items-center gap-1 rounded-[6px] border border-[#E5E5E5] px-2 text-[#999] text-[12px]'>
|
||||
Sort
|
||||
</div>
|
||||
<div className='flex h-[24px] items-center gap-[4px] rounded-[6px] border border-[#E5E5E5] px-[8px] text-[#999] text-[12px]'>
|
||||
<div className='flex h-[24px] items-center gap-1 rounded-[6px] border border-[#E5E5E5] px-2 text-[#999] text-[12px]'>
|
||||
Filter
|
||||
</div>
|
||||
</div>
|
||||
@@ -716,7 +716,7 @@ function MockFullKnowledgeBase({ revealedRows }: { revealedRows: number }) {
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th className='border-[#E5E5E5] border-r border-b bg-[#FAFAFA] px-[4px] py-[7px] text-center align-middle'>
|
||||
<th className='border-[#E5E5E5] border-r border-b bg-[#FAFAFA] px-1 py-[7px] text-center align-middle'>
|
||||
<div className='flex items-center justify-center'>
|
||||
<div className='h-[13px] w-[13px] rounded-[2px] border border-[#D4D4D4]' />
|
||||
</div>
|
||||
@@ -724,7 +724,7 @@ function MockFullKnowledgeBase({ revealedRows }: { revealedRows: number }) {
|
||||
{MOCK_KB_COLUMNS.map((col) => (
|
||||
<th
|
||||
key={col}
|
||||
className='border-[#E5E5E5] border-r border-b bg-[#FAFAFA] px-[8px] py-[7px] text-left align-middle'
|
||||
className='border-[#E5E5E5] border-r border-b bg-[#FAFAFA] px-2 py-[7px] text-left align-middle'
|
||||
>
|
||||
<span className='font-base text-[#999] text-[13px]'>{col}</span>
|
||||
</th>
|
||||
@@ -742,11 +742,11 @@ function MockFullKnowledgeBase({ revealedRows }: { revealedRows: number }) {
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.2, ease: 'easeOut' }}
|
||||
>
|
||||
<td className='border-[#E5E5E5] border-r border-b px-[4px] py-[7px] text-center align-middle'>
|
||||
<td className='border-[#E5E5E5] border-r border-b px-1 py-[7px] text-center align-middle'>
|
||||
<span className='text-[#999] text-[11px] tabular-nums'>{i + 1}</span>
|
||||
</td>
|
||||
<td className='border-[#E5E5E5] border-r border-b px-[8px] py-[7px] align-middle'>
|
||||
<span className='flex items-center gap-[8px] text-[#1C1C1C] text-[13px]'>
|
||||
<td className='border-[#E5E5E5] border-r border-b px-2 py-[7px] align-middle'>
|
||||
<span className='flex items-center gap-2 text-[#1C1C1C] text-[13px]'>
|
||||
<DocIcon className='h-[14px] w-[14px] shrink-0' />
|
||||
<span className='truncate'>{row[0]}</span>
|
||||
</span>
|
||||
@@ -754,14 +754,14 @@ function MockFullKnowledgeBase({ revealedRows }: { revealedRows: number }) {
|
||||
{row.slice(1, 4).map((cell, j) => (
|
||||
<td
|
||||
key={j}
|
||||
className='border-[#E5E5E5] border-r border-b px-[8px] py-[7px] align-middle'
|
||||
className='border-[#E5E5E5] border-r border-b px-2 py-[7px] align-middle'
|
||||
>
|
||||
<span className='text-[#999] text-[13px]'>{cell}</span>
|
||||
</td>
|
||||
))}
|
||||
<td className='border-[#E5E5E5] border-r border-b px-[8px] py-[7px] align-middle'>
|
||||
<td className='border-[#E5E5E5] border-r border-b px-2 py-[7px] align-middle'>
|
||||
<span
|
||||
className='inline-flex items-center rounded-full px-[8px] py-[2px] font-medium text-[11px]'
|
||||
className='inline-flex items-center rounded-full px-2 py-0.5 font-medium text-[11px]'
|
||||
style={{ backgroundColor: status.bg, color: status.text }}
|
||||
>
|
||||
{status.label}
|
||||
@@ -885,8 +885,8 @@ function MockFullLogs({ revealedRows }: { revealedRows: number }) {
|
||||
return (
|
||||
<div className='relative flex h-full'>
|
||||
<div className='flex min-w-0 flex-1 flex-col'>
|
||||
<div className='flex h-[44px] shrink-0 items-center border-[#E5E5E5] border-b px-[24px]'>
|
||||
<div className='flex items-center gap-[6px]'>
|
||||
<div className='flex h-[44px] shrink-0 items-center border-[#E5E5E5] border-b px-6'>
|
||||
<div className='flex items-center gap-1.5'>
|
||||
<Library className='h-[14px] w-[14px] text-[#999]' />
|
||||
<span className='font-medium text-[#1C1C1C] text-[13px]'>Logs</span>
|
||||
</div>
|
||||
@@ -902,7 +902,7 @@ function MockFullLogs({ revealedRows }: { revealedRows: number }) {
|
||||
<thead className='shadow-[inset_0_-1px_0_#E5E5E5]'>
|
||||
<tr>
|
||||
{['Workflow', 'Date', 'Status', 'Cost', 'Trigger', 'Duration'].map((col) => (
|
||||
<th key={col} className='h-10 px-[24px] py-[10px] text-left align-middle'>
|
||||
<th key={col} className='h-10 px-6 py-2.5 text-left align-middle'>
|
||||
<span className='font-base text-[#999] text-[13px]'>{col}</span>
|
||||
</th>
|
||||
))}
|
||||
@@ -924,8 +924,8 @@ function MockFullLogs({ revealedRows }: { revealedRows: number }) {
|
||||
)}
|
||||
onClick={() => setSelectedRow(i)}
|
||||
>
|
||||
<td className='px-[24px] py-[10px] align-middle'>
|
||||
<span className='flex items-center gap-[12px] font-medium text-[#1C1C1C] text-[14px]'>
|
||||
<td className='px-6 py-2.5 align-middle'>
|
||||
<span className='flex items-center gap-3 font-medium text-[#1C1C1C] text-[14px]'>
|
||||
<div
|
||||
className='h-[10px] w-[10px] shrink-0 rounded-[3px] border-[1.5px]'
|
||||
style={{
|
||||
@@ -937,26 +937,26 @@ function MockFullLogs({ revealedRows }: { revealedRows: number }) {
|
||||
<span className='truncate'>{row[0]}</span>
|
||||
</span>
|
||||
</td>
|
||||
<td className='px-[24px] py-[10px] align-middle'>
|
||||
<td className='px-6 py-2.5 align-middle'>
|
||||
<span className='font-medium text-[#999] text-[14px]'>{row[1]}</span>
|
||||
</td>
|
||||
<td className='px-[24px] py-[10px] align-middle'>
|
||||
<td className='px-6 py-2.5 align-middle'>
|
||||
<span
|
||||
className='inline-flex items-center rounded-full px-[8px] py-[2px] font-medium text-[11px]'
|
||||
className='inline-flex items-center rounded-full px-2 py-0.5 font-medium text-[11px]'
|
||||
style={{ backgroundColor: statusStyle.bg, color: statusStyle.text }}
|
||||
>
|
||||
{statusStyle.label}
|
||||
</span>
|
||||
</td>
|
||||
<td className='px-[24px] py-[10px] align-middle'>
|
||||
<td className='px-6 py-2.5 align-middle'>
|
||||
<span className='font-medium text-[#999] text-[14px]'>{row[3]}</span>
|
||||
</td>
|
||||
<td className='px-[24px] py-[10px] align-middle'>
|
||||
<span className='rounded-[4px] bg-[#F5F5F5] px-[6px] py-[2px] text-[#666] text-[11px]'>
|
||||
<td className='px-6 py-2.5 align-middle'>
|
||||
<span className='rounded-[4px] bg-[#F5F5F5] px-1.5 py-0.5 text-[#666] text-[11px]'>
|
||||
{row[4]}
|
||||
</span>
|
||||
</td>
|
||||
<td className='px-[24px] py-[10px] align-middle'>
|
||||
<td className='px-6 py-2.5 align-middle'>
|
||||
<span className='font-medium text-[#999] text-[14px]'>{row[5]}</span>
|
||||
</td>
|
||||
</motion.tr>
|
||||
@@ -1001,7 +1001,7 @@ function MockLogDetailsSidebar({ selectedRow, onPrev, onNext }: MockLogDetailsSi
|
||||
const isNextDisabled = selectedRow === MOCK_LOG_DATA.length - 1
|
||||
|
||||
return (
|
||||
<div className='flex h-full flex-col overflow-y-auto px-[14px] pt-[12px]'>
|
||||
<div className='flex h-full flex-col overflow-y-auto px-3.5 pt-3'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<span className='font-medium text-[#1C1C1C] text-[14px]'>Log Details</span>
|
||||
<div className='flex items-center gap-[1px]'>
|
||||
@@ -1030,18 +1030,18 @@ function MockLogDetailsSidebar({ selectedRow, onPrev, onNext }: MockLogDetailsSi
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mt-[20px] flex flex-col gap-[10px]'>
|
||||
<div className='flex items-center gap-[16px] px-[1px]'>
|
||||
<div className='flex w-[120px] shrink-0 flex-col gap-[8px]'>
|
||||
<div className='mt-5 flex flex-col gap-2.5'>
|
||||
<div className='flex items-center gap-4 px-[1px]'>
|
||||
<div className='flex w-[120px] shrink-0 flex-col gap-2'>
|
||||
<span className='font-medium text-[#999] text-[12px]'>Timestamp</span>
|
||||
<div className='flex items-center gap-[6px]'>
|
||||
<div className='flex items-center gap-1.5'>
|
||||
<span className='font-medium text-[#666] text-[13px]'>{date}</span>
|
||||
<span className='font-medium text-[#666] text-[13px]'>{time}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex min-w-0 flex-1 flex-col gap-[8px]'>
|
||||
<div className='flex min-w-0 flex-1 flex-col gap-2'>
|
||||
<span className='font-medium text-[#999] text-[12px]'>Workflow</span>
|
||||
<div className='flex items-center gap-[8px]'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<div
|
||||
className='h-[10px] w-[10px] shrink-0 rounded-[3px] border-[1.5px]'
|
||||
style={{
|
||||
@@ -1056,42 +1056,39 @@ function MockLogDetailsSidebar({ selectedRow, onPrev, onNext }: MockLogDetailsSi
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col'>
|
||||
<div className='flex h-[42px] items-center justify-between border-[#E5E5E5] border-b px-[8px]'>
|
||||
<div className='flex h-[42px] items-center justify-between border-[#E5E5E5] border-b px-2'>
|
||||
<span className='font-medium text-[#999] text-[12px]'>Level</span>
|
||||
<span
|
||||
className='inline-flex items-center rounded-full px-[8px] py-[2px] font-medium text-[11px]'
|
||||
className='inline-flex items-center rounded-full px-2 py-0.5 font-medium text-[11px]'
|
||||
style={{ backgroundColor: statusStyle.bg, color: statusStyle.text }}
|
||||
>
|
||||
{statusStyle.label}
|
||||
</span>
|
||||
</div>
|
||||
<div className='flex h-[42px] items-center justify-between border-[#E5E5E5] border-b px-[8px]'>
|
||||
<div className='flex h-[42px] items-center justify-between border-[#E5E5E5] border-b px-2'>
|
||||
<span className='font-medium text-[#999] text-[12px]'>Trigger</span>
|
||||
<span className='rounded-[4px] bg-[#F5F5F5] px-[6px] py-[2px] text-[#666] text-[11px]'>
|
||||
<span className='rounded-[4px] bg-[#F5F5F5] px-1.5 py-0.5 text-[#666] text-[11px]'>
|
||||
{row[4]}
|
||||
</span>
|
||||
</div>
|
||||
<div className='flex h-[42px] items-center justify-between px-[8px]'>
|
||||
<div className='flex h-[42px] items-center justify-between px-2'>
|
||||
<span className='font-medium text-[#999] text-[12px]'>Duration</span>
|
||||
<span className='font-medium text-[#666] text-[13px]'>{row[5]}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-[6px] rounded-[6px] border border-[#E5E5E5] bg-[#FAFAFA] px-[10px] py-[8px]'>
|
||||
<div className='flex flex-col gap-1.5 rounded-[6px] border border-[#E5E5E5] bg-[#FAFAFA] px-2.5 py-2'>
|
||||
<span className='font-medium text-[#999] text-[12px]'>Workflow Output</span>
|
||||
<div className='rounded-[6px] bg-[#F0F0F0] p-[10px] font-mono text-[#555] text-[11px] leading-[1.5]'>
|
||||
<div className='rounded-[6px] bg-[#F0F0F0] p-2.5 font-mono text-[#555] text-[11px] leading-[1.5]'>
|
||||
{detail.output}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-[6px] rounded-[6px] border border-[#E5E5E5] bg-[#FAFAFA] px-[10px] py-[8px]'>
|
||||
<div className='flex flex-col gap-1.5 rounded-[6px] border border-[#E5E5E5] bg-[#FAFAFA] px-2.5 py-2'>
|
||||
<span className='font-medium text-[#999] text-[12px]'>Trace Spans</span>
|
||||
<div className='flex flex-col gap-[6px]'>
|
||||
<div className='flex flex-col gap-1.5'>
|
||||
{detail.spans.map((span, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={cn('flex flex-col gap-[3px]', span.depth === 1 && 'ml-[12px]')}
|
||||
>
|
||||
<div key={i} className={cn('flex flex-col gap-[3px]', span.depth === 1 && 'ml-3')}>
|
||||
<div className='flex items-center justify-between'>
|
||||
<span className='font-mono text-[#555] text-[11px]'>{span.name}</span>
|
||||
<span className='font-medium text-[#999] text-[11px]'>{span.ms}ms</span>
|
||||
@@ -1116,8 +1113,8 @@ function MockFullTable({ revealedRows }: { revealedRows: number }) {
|
||||
|
||||
return (
|
||||
<div className='flex h-full flex-col'>
|
||||
<div className='flex h-[44px] shrink-0 items-center border-[#E5E5E5] border-b px-[24px]'>
|
||||
<div className='flex items-center gap-[6px]'>
|
||||
<div className='flex h-[44px] shrink-0 items-center border-[#E5E5E5] border-b px-6'>
|
||||
<div className='flex items-center gap-1.5'>
|
||||
<Table className='h-[14px] w-[14px] text-[#999]' />
|
||||
<span className='text-[#999] text-[13px]'>Tables</span>
|
||||
<span className='text-[#D4D4D4] text-[13px]'>/</span>
|
||||
@@ -1125,12 +1122,12 @@ function MockFullTable({ revealedRows }: { revealedRows: number }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex h-[36px] shrink-0 items-center border-[#E5E5E5] border-b px-[24px]'>
|
||||
<div className='flex items-center gap-[6px]'>
|
||||
<div className='flex h-[24px] items-center gap-[4px] rounded-[6px] border border-[#E5E5E5] px-[8px] text-[#999] text-[12px]'>
|
||||
<div className='flex h-[36px] shrink-0 items-center border-[#E5E5E5] border-b px-6'>
|
||||
<div className='flex items-center gap-1.5'>
|
||||
<div className='flex h-[24px] items-center gap-1 rounded-[6px] border border-[#E5E5E5] px-2 text-[#999] text-[12px]'>
|
||||
Sort
|
||||
</div>
|
||||
<div className='flex h-[24px] items-center gap-[4px] rounded-[6px] border border-[#E5E5E5] px-[8px] text-[#999] text-[12px]'>
|
||||
<div className='flex h-[24px] items-center gap-1 rounded-[6px] border border-[#E5E5E5] px-2 text-[#999] text-[12px]'>
|
||||
Filter
|
||||
</div>
|
||||
</div>
|
||||
@@ -1146,7 +1143,7 @@ function MockFullTable({ revealedRows }: { revealedRows: number }) {
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th className='border-[#E5E5E5] border-r border-b bg-[#FAFAFA] px-[4px] py-[7px] text-center align-middle'>
|
||||
<th className='border-[#E5E5E5] border-r border-b bg-[#FAFAFA] px-1 py-[7px] text-center align-middle'>
|
||||
<div className='flex items-center justify-center'>
|
||||
<div className='h-[13px] w-[13px] rounded-[2px] border border-[#D4D4D4]' />
|
||||
</div>
|
||||
@@ -1154,9 +1151,9 @@ function MockFullTable({ revealedRows }: { revealedRows: number }) {
|
||||
{MOCK_TABLE_COLUMNS.map((col) => (
|
||||
<th
|
||||
key={col}
|
||||
className='border-[#E5E5E5] border-r border-b bg-[#FAFAFA] px-[8px] py-[7px] text-left align-middle'
|
||||
className='border-[#E5E5E5] border-r border-b bg-[#FAFAFA] px-2 py-[7px] text-left align-middle'
|
||||
>
|
||||
<div className='flex items-center gap-[6px]'>
|
||||
<div className='flex items-center gap-1.5'>
|
||||
<ColumnTypeIcon />
|
||||
<span className='font-medium text-[#1C1C1C] text-[13px]'>{col}</span>
|
||||
<ChevronDown className='ml-auto h-[7px] w-[9px] shrink-0 text-[#CCC]' />
|
||||
@@ -1179,7 +1176,7 @@ function MockFullTable({ revealedRows }: { revealedRows: number }) {
|
||||
>
|
||||
<td
|
||||
className={cn(
|
||||
'border-[#E5E5E5] border-r border-b px-[4px] py-[7px] text-center align-middle',
|
||||
'border-[#E5E5E5] border-r border-b px-1 py-[7px] text-center align-middle',
|
||||
isSelected ? 'bg-[rgba(37,99,235,0.06)]' : 'hover:bg-[#FAFAFA]'
|
||||
)}
|
||||
>
|
||||
@@ -1189,7 +1186,7 @@ function MockFullTable({ revealedRows }: { revealedRows: number }) {
|
||||
<td
|
||||
key={j}
|
||||
className={cn(
|
||||
'relative border-[#E5E5E5] border-r border-b px-[8px] py-[7px] align-middle',
|
||||
'relative border-[#E5E5E5] border-r border-b px-2 py-[7px] align-middle',
|
||||
isSelected ? 'bg-[rgba(37,99,235,0.06)]' : 'hover:bg-[#FAFAFA]'
|
||||
)}
|
||||
>
|
||||
@@ -1311,13 +1308,13 @@ function DefaultPreview() {
|
||||
return (
|
||||
<motion.div
|
||||
key={key}
|
||||
className='absolute flex items-center justify-center rounded-xl border border-[#E5E5E5] bg-white p-[10px] shadow-[0_2px_4px_0_rgba(0,0,0,0.06)]'
|
||||
className='absolute flex items-center justify-center rounded-xl border border-[#E5E5E5] bg-white p-2.5 shadow-[0_2px_4px_0_rgba(0,0,0,0.06)]'
|
||||
initial={{ top: '50%', left: '50%', opacity: 0, scale: 0, x: '-50%', y: '-50%' }}
|
||||
animate={inView ? { top, left, opacity: 1, scale: 1, x: '-50%', y: '-50%' } : undefined}
|
||||
transition={{
|
||||
type: 'spring',
|
||||
stiffness: 50,
|
||||
damping: 12,
|
||||
stiffness: 80,
|
||||
damping: 20,
|
||||
delay: explodeDelay,
|
||||
}}
|
||||
style={{ color }}
|
||||
@@ -1334,7 +1331,7 @@ function DefaultPreview() {
|
||||
animate={inView ? { opacity: 1, x: '-50%', y: '-50%' } : undefined}
|
||||
transition={{ duration: 0.4, ease: 'easeOut', delay: 0 }}
|
||||
>
|
||||
<div className='flex h-[36px] items-center gap-[8px] rounded-[8px] border border-[#E5E5E5] bg-white px-[10px] shadow-[0_2px_6px_0_rgba(0,0,0,0.08)]'>
|
||||
<div className='flex h-[36px] items-center gap-2 rounded-[8px] border border-[#E5E5E5] bg-white px-2.5 shadow-[0_2px_6px_0_rgba(0,0,0,0.08)]'>
|
||||
<div className='flex h-[22px] w-[22px] flex-shrink-0 items-center justify-center rounded-[5px] bg-[#1e1e1e]'>
|
||||
<svg width='11' height='11' viewBox='0 0 10 10' fill='none'>
|
||||
<path
|
||||
|
||||
@@ -152,7 +152,7 @@ function DotGrid({
|
||||
return (
|
||||
<div
|
||||
aria-hidden='true'
|
||||
className={`h-full shrink-0 bg-[#F6F6F6] p-[6px] ${borderLeft ? 'border-[#E9E9E9] border-l' : ''}`}
|
||||
className={`h-full shrink-0 bg-[var(--landing-bg-section)] p-1.5 ${borderLeft ? 'border-[var(--divider)] border-l' : ''}`}
|
||||
style={{
|
||||
width: width ? `${width}px` : undefined,
|
||||
display: 'grid',
|
||||
@@ -181,7 +181,7 @@ export default function Features() {
|
||||
<section
|
||||
id='features'
|
||||
aria-labelledby='features-heading'
|
||||
className='relative overflow-hidden bg-[#F6F6F6]'
|
||||
className='relative overflow-hidden bg-[var(--landing-bg-section)]'
|
||||
>
|
||||
<div aria-hidden='true' className='absolute top-0 left-0 w-full'>
|
||||
<Image
|
||||
@@ -195,10 +195,7 @@ export default function Features() {
|
||||
</div>
|
||||
|
||||
<div className='relative z-10 pt-[60px] lg:pt-[100px]'>
|
||||
<div
|
||||
ref={sectionRef}
|
||||
className='flex flex-col items-start gap-[20px] px-[24px] lg:px-[80px]'
|
||||
>
|
||||
<div ref={sectionRef} className='flex flex-col items-start gap-5 px-6 lg:px-20'>
|
||||
<Badge
|
||||
variant='blue'
|
||||
size='md'
|
||||
@@ -216,31 +213,31 @@ export default function Features() {
|
||||
</Badge>
|
||||
<h2
|
||||
id='features-heading'
|
||||
className='max-w-[900px] font-[430] font-season text-[#1C1C1C] text-[28px] leading-[110%] tracking-[-0.02em] md:text-[40px]'
|
||||
className='max-w-[900px] text-balance font-[430] font-season text-[28px] text-[var(--landing-text-dark)] leading-[110%] tracking-[-0.02em] md:text-[40px]'
|
||||
>
|
||||
{HEADING_LETTERS.map((char, i) => (
|
||||
<ScrollLetter key={i} scrollYProgress={scrollYProgress} charIndex={i}>
|
||||
{char}
|
||||
</ScrollLetter>
|
||||
))}
|
||||
<span className='text-[#1C1C1C]/40'>
|
||||
<span className='text-[color-mix(in_srgb,var(--landing-text-dark)_40%,transparent)]'>
|
||||
Design powerful workflows, connect your data, and monitor every run — all in one
|
||||
platform.
|
||||
</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className='relative mt-[40px] pb-[40px] lg:mt-[73px] lg:pb-[80px]'>
|
||||
<div className='relative mt-10 pb-10 lg:mt-[73px] lg:pb-20'>
|
||||
<div
|
||||
aria-hidden='true'
|
||||
className='absolute top-0 bottom-0 left-[80px] z-20 hidden w-px bg-[#E9E9E9] lg:block'
|
||||
className='absolute top-0 bottom-0 left-[80px] z-20 hidden w-px bg-[var(--divider)] lg:block'
|
||||
/>
|
||||
<div
|
||||
aria-hidden='true'
|
||||
className='absolute top-0 right-[80px] bottom-0 z-20 hidden w-px bg-[#E9E9E9] lg:block'
|
||||
className='absolute top-0 right-[80px] bottom-0 z-20 hidden w-px bg-[var(--divider)] lg:block'
|
||||
/>
|
||||
|
||||
<div className='flex h-[68px] border border-[#E9E9E9] lg:overflow-hidden'>
|
||||
<div className='flex h-[68px] border border-[var(--divider)] lg:overflow-hidden'>
|
||||
<div className='h-full shrink-0'>
|
||||
<div className='h-full lg:hidden'>
|
||||
<DotGrid cols={3} rows={8} width={24} />
|
||||
@@ -258,7 +255,7 @@ export default function Features() {
|
||||
role='tab'
|
||||
aria-selected={index === activeTab}
|
||||
onClick={() => setActiveTab(index)}
|
||||
className={`relative h-full flex-1 items-center justify-center whitespace-nowrap px-[12px] font-medium font-season text-[#212121] text-[12px] uppercase lg:px-0 lg:text-[14px]${tab.hideOnMobile ? ' hidden lg:flex' : ' flex'}${index > 0 ? ' border-[#E9E9E9] border-l' : ''}`}
|
||||
className={`relative h-full flex-1 items-center justify-center whitespace-nowrap px-3 font-medium font-season text-[var(--landing-text-dark)] text-caption uppercase lg:px-0 lg:text-sm${tab.hideOnMobile ? ' hidden lg:flex' : ' flex'}${index > 0 ? ' border-[var(--divider)] border-l' : ''}`}
|
||||
style={{ backgroundColor: index === activeTab ? '#FDFDFD' : '#F6F6F6' }}
|
||||
>
|
||||
{tab.mobileLabel ? (
|
||||
@@ -298,19 +295,19 @@ export default function Features() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mt-[32px] flex flex-col gap-[24px] px-[24px] lg:mt-[60px] lg:grid lg:grid-cols-[1fr_2.8fr] lg:gap-[60px] lg:px-[120px]'>
|
||||
<div className='flex flex-col items-start justify-between gap-[24px] pt-[20px] lg:h-[560px] lg:gap-0'>
|
||||
<div className='flex flex-col items-start gap-[16px]'>
|
||||
<h3 className='font-[430] font-season text-[#1C1C1C] text-[24px] leading-[120%] tracking-[-0.02em] lg:text-[28px]'>
|
||||
<div className='mt-8 flex flex-col gap-6 px-6 lg:mt-[60px] lg:grid lg:grid-cols-[1fr_2.8fr] lg:gap-[60px] lg:px-[120px]'>
|
||||
<div className='flex flex-col items-start justify-between gap-6 pt-5 lg:h-[560px] lg:gap-0'>
|
||||
<div className='flex flex-col items-start gap-4'>
|
||||
<h3 className='font-[430] font-season text-[24px] text-[var(--landing-text-dark)] leading-[120%] tracking-[-0.02em] lg:text-[28px]'>
|
||||
{FEATURE_TABS[activeTab].title}
|
||||
</h3>
|
||||
<p className='font-[430] font-season text-[#1C1C1C]/50 text-[16px] leading-[150%] tracking-[0.02em] lg:text-[18px]'>
|
||||
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-dark)_50%,transparent)] text-md leading-[150%] tracking-[0.02em] lg:text-lg'>
|
||||
{FEATURE_TABS[activeTab].description}
|
||||
</p>
|
||||
</div>
|
||||
<Link
|
||||
href='/signup'
|
||||
className='group/cta inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#1D1D1D] bg-[#1D1D1D] px-[10px] font-[430] font-season text-[14px] text-white transition-colors hover:border-[#2A2A2A] hover:bg-[#2A2A2A]'
|
||||
className='group/cta inline-flex h-[32px] items-center gap-1.5 rounded-[5px] border border-[#1D1D1D] bg-[#1D1D1D] px-2.5 font-[430] font-season text-sm text-white transition-colors hover:border-[var(--landing-bg-elevated)] hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
{FEATURE_TABS[activeTab].cta}
|
||||
<span className='relative h-[10px] w-[10px] shrink-0'>
|
||||
@@ -336,7 +333,7 @@ export default function Features() {
|
||||
<FeaturesPreview activeTab={activeTab} />
|
||||
</div>
|
||||
|
||||
<div aria-hidden='true' className='mt-[60px] hidden h-px bg-[#E9E9E9] lg:block' />
|
||||
<div aria-hidden='true' className='mt-[60px] hidden h-px bg-[var(--divider)] lg:block' />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useAnimatedPlaceholder } from '@/app/workspace/[workspaceId]/home/hooks
|
||||
const MAX_HEIGHT = 120
|
||||
|
||||
const CTA_BUTTON =
|
||||
'inline-flex items-center h-[32px] rounded-[5px] border px-[10px] font-[430] font-season text-[14px]'
|
||||
'inline-flex items-center h-[32px] rounded-[5px] border px-2.5 font-[430] font-season text-sm'
|
||||
|
||||
export function FooterCTA() {
|
||||
const landingSubmit = useLandingSubmit()
|
||||
@@ -41,14 +41,14 @@ export function FooterCTA() {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className='flex flex-col items-center px-4 pt-[120px] pb-[100px] sm:px-8 md:px-[80px]'>
|
||||
<h2 className='text-center font-[430] font-season text-[#1C1C1C] text-[28px] leading-[100%] tracking-[-0.02em] sm:text-[32px] md:text-[36px]'>
|
||||
<div className='flex flex-col items-center px-4 pt-[120px] pb-[100px] sm:px-8 md:px-20'>
|
||||
<h2 className='text-balance text-center font-[430] font-season text-[28px] text-[var(--landing-text-dark)] leading-[100%] tracking-[-0.02em] sm:text-[32px] md:text-[36px]'>
|
||||
What should we get done?
|
||||
</h2>
|
||||
|
||||
<div className='mt-8 w-full max-w-[42rem]'>
|
||||
<div
|
||||
className='cursor-text rounded-[20px] border border-[#E5E5E5] bg-white px-[10px] py-[8px] shadow-sm'
|
||||
className='cursor-text rounded-[20px] border border-[var(--landing-bg-skeleton)] bg-white px-2.5 py-2 shadow-sm'
|
||||
onClick={() => textareaRef.current?.focus()}
|
||||
>
|
||||
<textarea
|
||||
@@ -59,7 +59,7 @@ export function FooterCTA() {
|
||||
onInput={handleInput}
|
||||
placeholder={animatedPlaceholder}
|
||||
rows={2}
|
||||
className='m-0 box-border min-h-[48px] w-full resize-none border-0 bg-transparent px-[4px] py-[4px] font-body text-[#1C1C1C] text-[15px] leading-[24px] tracking-[-0.015em] outline-none placeholder:font-[380] placeholder:text-[#999] focus-visible:ring-0'
|
||||
className='m-0 box-border min-h-[48px] w-full resize-none border-0 bg-transparent px-1 py-1 font-body text-[var(--landing-text-dark)] text-base leading-[24px] tracking-[-0.015em] outline-none placeholder:font-[380] placeholder:text-[var(--landing-text-muted)] focus-visible:ring-0'
|
||||
style={{ caretColor: '#1C1C1C', maxHeight: `${MAX_HEIGHT}px` }}
|
||||
/>
|
||||
<div className='flex items-center justify-end'>
|
||||
@@ -79,18 +79,18 @@ export function FooterCTA() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mt-8 flex gap-[8px]'>
|
||||
<div className='mt-8 flex gap-2'>
|
||||
<a
|
||||
href='https://docs.sim.ai'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className={`${CTA_BUTTON} border-[#D4D4D4] text-[#1C1C1C] transition-colors hover:bg-[#E8E8E8]`}
|
||||
className={`${CTA_BUTTON} border-[var(--landing-border-subtle)] text-[var(--landing-text-dark)] transition-colors hover:bg-[var(--landing-bg-skeleton)]`}
|
||||
>
|
||||
Docs
|
||||
</a>
|
||||
<Link
|
||||
href='/signup'
|
||||
className={`${CTA_BUTTON} gap-[8px] border-[#1C1C1C] bg-[#1C1C1C] text-white transition-colors hover:border-[#333] hover:bg-[#333]`}
|
||||
className={`${CTA_BUTTON} gap-2 border-[var(--landing-bg)] bg-[var(--landing-bg)] text-white transition-colors hover:border-[var(--landing-bg-elevated)] hover:bg-[var(--landing-bg-elevated)]`}
|
||||
>
|
||||
Get started
|
||||
</Link>
|
||||
|
||||
@@ -2,7 +2,8 @@ import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { FooterCTA } from '@/app/(home)/components/footer/footer-cta'
|
||||
|
||||
const LINK_CLASS = 'text-[14px] text-[#999] transition-colors hover:text-[#ECECEC]'
|
||||
const LINK_CLASS =
|
||||
'text-sm text-[var(--landing-text-muted)] transition-colors hover:text-[var(--landing-text)]'
|
||||
|
||||
interface FooterItem {
|
||||
label: string
|
||||
@@ -81,8 +82,8 @@ const LEGAL_LINKS: FooterItem[] = [
|
||||
function FooterColumn({ title, items }: { title: string; items: FooterItem[] }) {
|
||||
return (
|
||||
<div>
|
||||
<h3 className='mb-[16px] font-medium text-[#ECECEC] text-[14px]'>{title}</h3>
|
||||
<div className='flex flex-col gap-[10px]'>
|
||||
<h3 className='mb-4 font-medium text-[var(--landing-text)] text-sm'>{title}</h3>
|
||||
<div className='flex flex-col gap-2.5'>
|
||||
{items.map(({ label, href, external }) =>
|
||||
external ? (
|
||||
<a
|
||||
@@ -113,16 +114,16 @@ export default function Footer({ hideCTA }: FooterProps) {
|
||||
return (
|
||||
<footer
|
||||
role='contentinfo'
|
||||
className={`bg-[#F6F6F6] pb-[40px] font-[430] font-season text-[14px]${hideCTA ? ' pt-[40px]' : ''}`}
|
||||
className={`bg-[var(--landing-bg-section)] pb-10 font-[430] font-season text-sm${hideCTA ? ' pt-10' : ''}`}
|
||||
>
|
||||
{!hideCTA && <FooterCTA />}
|
||||
<div className='px-4 sm:px-8 md:px-[80px]'>
|
||||
<div className='relative overflow-hidden rounded-lg bg-[#1C1C1C] px-6 pt-[40px] pb-[32px] sm:px-10 sm:pt-[48px] sm:pb-[40px]'>
|
||||
<div className='px-4 sm:px-8 md:px-20'>
|
||||
<div className='relative overflow-hidden rounded-lg bg-[var(--landing-bg)] px-6 pt-10 pb-8 sm:px-10 sm:pt-12 sm:pb-10'>
|
||||
<nav
|
||||
aria-label='Footer navigation'
|
||||
className='relative z-[1] grid grid-cols-2 gap-x-8 gap-y-10 sm:grid-cols-3 lg:grid-cols-7'
|
||||
>
|
||||
<div className='col-span-2 flex flex-col gap-[24px] sm:col-span-1'>
|
||||
<div className='col-span-2 flex flex-col gap-6 sm:col-span-1'>
|
||||
<Link href='/' aria-label='Sim home'>
|
||||
<Image
|
||||
src='/logo/sim-landing.svg'
|
||||
|
||||
@@ -20,13 +20,13 @@ const LandingPreview = dynamic(
|
||||
),
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => <div className='aspect-[1116/549] w-full rounded bg-[#1b1b1b]' />,
|
||||
loading: () => <div className='aspect-[1116/549] w-full rounded bg-[var(--landing-bg)]' />,
|
||||
}
|
||||
)
|
||||
|
||||
/** Shared base classes for CTA link buttons — matches Deploy/Run button styling in the preview panel. */
|
||||
const CTA_BASE =
|
||||
'inline-flex items-center h-[32px] rounded-[5px] border px-[10px] font-[430] font-season text-[14px]'
|
||||
'inline-flex items-center h-[32px] rounded-[5px] border px-2.5 font-[430] font-season text-sm'
|
||||
|
||||
export default function Hero() {
|
||||
const blockStates = useBlockCycle()
|
||||
@@ -35,7 +35,7 @@ export default function Hero() {
|
||||
<section
|
||||
id='hero'
|
||||
aria-labelledby='hero-heading'
|
||||
className='relative flex flex-col items-center overflow-hidden bg-[#1C1C1C] pt-[60px] pb-[12px] lg:pt-[100px]'
|
||||
className='relative flex flex-col items-center overflow-hidden bg-[var(--landing-bg)] pt-[60px] pb-3 lg:pt-[100px]'
|
||||
>
|
||||
<p className='sr-only'>
|
||||
Sim is the open-source platform to build AI agents and run your agentic workforce. Connect
|
||||
@@ -59,22 +59,22 @@ export default function Hero() {
|
||||
<Image src='/landing/card-right.svg' alt='' fill className='object-contain' />
|
||||
</div>
|
||||
|
||||
<div className='relative z-10 flex flex-col items-center gap-[12px]'>
|
||||
<div className='relative z-10 flex flex-col items-center gap-3'>
|
||||
<h1
|
||||
id='hero-heading'
|
||||
className='font-[430] font-season text-[36px] text-white leading-[100%] tracking-[-0.02em] sm:text-[48px] lg:text-[72px]'
|
||||
className='text-balance font-[430] font-season text-[36px] text-white leading-[100%] tracking-[-0.02em] sm:text-[48px] lg:text-[72px]'
|
||||
>
|
||||
Build AI Agents
|
||||
</h1>
|
||||
<p className='font-[430] font-season text-[#F6F6F6]/60 text-[15px] leading-[125%] tracking-[0.02em] lg:text-[18px]'>
|
||||
<p className='font-[430] font-season text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)] text-base leading-[125%] tracking-[0.02em] lg:text-lg'>
|
||||
Sim is the AI Workspace for Agent Builders.
|
||||
</p>
|
||||
|
||||
<div className='mt-[12px] flex items-center gap-[8px]'>
|
||||
<div className='mt-3 flex items-center gap-2'>
|
||||
<DemoRequestModal>
|
||||
<button
|
||||
type='button'
|
||||
className={`${CTA_BASE} border-[#3d3d3d] bg-transparent text-[#ECECEC] transition-colors hover:bg-[#2A2A2A]`}
|
||||
className={`${CTA_BASE} border-[var(--landing-border-strong)] bg-transparent text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]`}
|
||||
aria-label='Get a demo'
|
||||
>
|
||||
Get a demo
|
||||
@@ -82,7 +82,7 @@ export default function Hero() {
|
||||
</DemoRequestModal>
|
||||
<Link
|
||||
href='/signup'
|
||||
className={`${CTA_BASE} gap-[8px] border-[#FFFFFF] bg-[#FFFFFF] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]`}
|
||||
className={`${CTA_BASE} gap-2 border-white bg-white text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]`}
|
||||
aria-label='Get started with Sim'
|
||||
>
|
||||
Get started
|
||||
@@ -119,7 +119,7 @@ export default function Hero() {
|
||||
<BlocksRightSideAnimated animState={blockStates.rightSide} />
|
||||
</div>
|
||||
|
||||
<div className='relative z-10 overflow-hidden rounded border border-[#2A2A2A]'>
|
||||
<div className='relative z-10 overflow-hidden rounded border border-[var(--landing-bg-elevated)]'>
|
||||
<LandingPreview />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+4
-4
@@ -48,10 +48,10 @@ export const LandingPreviewHome = memo(function LandingPreviewHome() {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className='flex min-w-0 flex-1 flex-col items-center justify-center px-[24px] pb-[2vh]'>
|
||||
<div className='flex min-w-0 flex-1 flex-col items-center justify-center px-6 pb-[2vh]'>
|
||||
<p
|
||||
role='presentation'
|
||||
className='mb-[24px] max-w-[42rem] font-[430] font-season text-[32px] tracking-[-0.02em]'
|
||||
className='mb-6 max-w-[42rem] font-[430] font-season text-[32px] tracking-[-0.02em]'
|
||||
style={{ color: C.TEXT_PRIMARY }}
|
||||
>
|
||||
What should we get done?
|
||||
@@ -59,7 +59,7 @@ export const LandingPreviewHome = memo(function LandingPreviewHome() {
|
||||
|
||||
<div className='w-full max-w-[32rem]'>
|
||||
<div
|
||||
className='cursor-text rounded-[20px] border px-[10px] py-[8px]'
|
||||
className='cursor-text rounded-[20px] border px-2.5 py-2'
|
||||
style={{ borderColor: C.BORDER, backgroundColor: C.SURFACE }}
|
||||
onClick={() => textareaRef.current?.focus()}
|
||||
>
|
||||
@@ -71,7 +71,7 @@ export const LandingPreviewHome = memo(function LandingPreviewHome() {
|
||||
onInput={handleInput}
|
||||
placeholder={animatedPlaceholder}
|
||||
rows={1}
|
||||
className='m-0 box-border min-h-[24px] w-full resize-none overflow-y-auto border-0 bg-transparent px-[4px] py-[4px] font-body text-[15px] leading-[24px] tracking-[-0.015em] outline-none placeholder:font-[380] placeholder:text-[#787878] focus-visible:ring-0'
|
||||
className='m-0 box-border min-h-[24px] w-full resize-none overflow-y-auto border-0 bg-transparent px-1 py-1 font-body text-[15px] leading-[24px] tracking-[-0.015em] outline-none placeholder:font-[380] placeholder:text-[#787878] focus-visible:ring-0'
|
||||
style={{
|
||||
color: C.TEXT_PRIMARY,
|
||||
caretColor: C.TEXT_PRIMARY,
|
||||
|
||||
+17
-17
@@ -59,10 +59,10 @@ export const LandingPreviewPanel = memo(function LandingPreviewPanel() {
|
||||
|
||||
return (
|
||||
<div className='flex h-full w-[280px] flex-shrink-0 flex-col bg-[#1e1e1e]'>
|
||||
<div className='flex h-full flex-col border-[#2c2c2c] border-l pt-[14px]'>
|
||||
<div className='flex h-full flex-col border-[#2c2c2c] border-l pt-3.5'>
|
||||
{/* Header — More + Chat | Deploy + Run */}
|
||||
<div className='flex flex-shrink-0 items-center justify-between px-[8px]'>
|
||||
<div className='pointer-events-none flex gap-[6px]'>
|
||||
<div className='flex flex-shrink-0 items-center justify-between px-2'>
|
||||
<div className='pointer-events-none flex gap-1.5'>
|
||||
<div className='flex h-[30px] w-[30px] items-center justify-center rounded-[5px] border border-[#3d3d3d] bg-[#363636]'>
|
||||
<MoreHorizontal className='h-[14px] w-[14px] text-[#e6e6e6]' />
|
||||
</div>
|
||||
@@ -72,14 +72,14 @@ export const LandingPreviewPanel = memo(function LandingPreviewPanel() {
|
||||
</div>
|
||||
<Link
|
||||
href='/signup'
|
||||
className='flex gap-[6px]'
|
||||
className='flex gap-1.5'
|
||||
onMouseMove={(e) => setCursorPos({ x: e.clientX, y: e.clientY })}
|
||||
onMouseLeave={() => setCursorPos(null)}
|
||||
>
|
||||
<div className='flex h-[30px] items-center rounded-[5px] bg-[#33C482] px-[10px] transition-colors hover:bg-[#2DAC72]'>
|
||||
<div className='flex h-[30px] items-center rounded-[5px] bg-[#33C482] px-2.5 transition-colors hover:bg-[#2DAC72]'>
|
||||
<span className='font-medium text-[#1b1b1b] text-[12px]'>Deploy</span>
|
||||
</div>
|
||||
<div className='flex h-[30px] items-center gap-[8px] rounded-[5px] bg-[#33C482] px-[10px] transition-colors hover:bg-[#2DAC72]'>
|
||||
<div className='flex h-[30px] items-center gap-2 rounded-[5px] bg-[#33C482] px-2.5 transition-colors hover:bg-[#2DAC72]'>
|
||||
<Play className='h-[11.5px] w-[11.5px] text-[#1b1b1b]' />
|
||||
<span className='font-medium text-[#1b1b1b] text-[12px]'>Run</span>
|
||||
</div>
|
||||
@@ -101,7 +101,7 @@ export const LandingPreviewPanel = memo(function LandingPreviewPanel() {
|
||||
<div className='h-full w-[8px] bg-[#FA4EDF]' />
|
||||
<div className='h-full w-[14px] bg-[#FA4EDF] opacity-60' />
|
||||
</div>
|
||||
<div className='flex items-center gap-[5px] bg-white px-[6px] py-[4px] font-medium text-[#1C1C1C] text-[11px]'>
|
||||
<div className='flex items-center gap-[5px] bg-white px-1.5 py-1 font-medium text-[#1C1C1C] text-[11px]'>
|
||||
Get started
|
||||
<ChevronDown className='-rotate-90 h-[7px] w-[7px] text-[#1C1C1C]' />
|
||||
</div>
|
||||
@@ -111,31 +111,31 @@ export const LandingPreviewPanel = memo(function LandingPreviewPanel() {
|
||||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<div className='flex flex-shrink-0 items-center px-[8px] pt-[14px]'>
|
||||
<div className='pointer-events-none flex gap-[4px]'>
|
||||
<div className='flex h-[28px] items-center rounded-[6px] border border-[#3d3d3d] bg-[#363636] px-[8px] py-[5px]'>
|
||||
<div className='flex flex-shrink-0 items-center px-2 pt-3.5'>
|
||||
<div className='pointer-events-none flex gap-1'>
|
||||
<div className='flex h-[28px] items-center rounded-[6px] border border-[#3d3d3d] bg-[#363636] px-2 py-[5px]'>
|
||||
<span className='font-medium text-[#e6e6e6] text-[12.5px]'>Copilot</span>
|
||||
</div>
|
||||
<div className='flex h-[28px] items-center rounded-[6px] border border-transparent px-[8px] py-[5px]'>
|
||||
<div className='flex h-[28px] items-center rounded-[6px] border border-transparent px-2 py-[5px]'>
|
||||
<span className='font-medium text-[#787878] text-[12.5px]'>Toolbar</span>
|
||||
</div>
|
||||
<div className='flex h-[28px] items-center rounded-[6px] border border-transparent px-[8px] py-[5px]'>
|
||||
<div className='flex h-[28px] items-center rounded-[6px] border border-transparent px-2 py-[5px]'>
|
||||
<span className='font-medium text-[#787878] text-[12.5px]'>Editor</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tab content — copilot */}
|
||||
<div className='flex flex-1 flex-col overflow-hidden pt-[12px]'>
|
||||
<div className='flex flex-1 flex-col overflow-hidden pt-3'>
|
||||
<div className='flex h-full flex-col'>
|
||||
{/* Copilot header bar — matches mx-[-1px] in real copilot */}
|
||||
<div className='pointer-events-none mx-[-1px] flex flex-shrink-0 items-center rounded-[4px] border border-[#2c2c2c] bg-[#292929] px-[12px] py-[6px]'>
|
||||
<div className='pointer-events-none mx-[-1px] flex flex-shrink-0 items-center rounded-[4px] border border-[#2c2c2c] bg-[#292929] px-3 py-1.5'>
|
||||
<span className='truncate font-medium text-[#e6e6e6] text-[14px]'>New Chat</span>
|
||||
</div>
|
||||
|
||||
{/* User input — matches real UserInput at p-[8px] inside copilot welcome state */}
|
||||
<div className='px-[8px] pt-[12px] pb-[8px]'>
|
||||
<div className='rounded-[4px] border border-[#3d3d3d] bg-[#292929] px-[6px] py-[6px]'>
|
||||
<div className='px-2 pt-3 pb-2'>
|
||||
<div className='rounded-[4px] border border-[#3d3d3d] bg-[#292929] px-1.5 py-1.5'>
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
value={inputValue}
|
||||
@@ -143,7 +143,7 @@ export const LandingPreviewPanel = memo(function LandingPreviewPanel() {
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder='Build an AI agent...'
|
||||
rows={2}
|
||||
className='mb-[6px] min-h-[48px] w-full cursor-text resize-none border-0 bg-transparent px-[2px] py-1 font-base text-[#e6e6e6] text-sm leading-[1.25rem] placeholder-[#787878] caret-[#e6e6e6] outline-none'
|
||||
className='mb-1.5 min-h-[48px] w-full cursor-text resize-none border-0 bg-transparent px-0.5 py-1 font-base text-[#e6e6e6] text-sm leading-[1.25rem] placeholder-[#787878] caret-[#e6e6e6] outline-none'
|
||||
/>
|
||||
<div className='flex items-center justify-end'>
|
||||
<button
|
||||
|
||||
+14
-14
@@ -57,7 +57,7 @@ function StaticNavItem({
|
||||
label: string
|
||||
}) {
|
||||
return (
|
||||
<div className='pointer-events-none mx-[2px] flex h-[28px] items-center gap-[8px] rounded-[8px] px-[8px]'>
|
||||
<div className='pointer-events-none mx-0.5 flex h-[28px] items-center gap-2 rounded-[8px] px-2'>
|
||||
<Icon className='h-[14px] w-[14px] flex-shrink-0' style={{ color: C.TEXT_ICON }} />
|
||||
<span className='truncate text-[13px]' style={{ color: C.TEXT_BODY, fontWeight: 450 }}>
|
||||
{label}
|
||||
@@ -82,13 +82,13 @@ export function LandingPreviewSidebar({
|
||||
|
||||
return (
|
||||
<div
|
||||
className='flex h-full w-[248px] flex-shrink-0 flex-col pt-[12px]'
|
||||
className='flex h-full w-[248px] flex-shrink-0 flex-col pt-3'
|
||||
style={{ backgroundColor: C.SURFACE_1 }}
|
||||
>
|
||||
{/* Workspace Header */}
|
||||
<div className='flex-shrink-0 px-[10px]'>
|
||||
<div className='flex-shrink-0 px-2.5'>
|
||||
<div
|
||||
className='pointer-events-none flex h-[32px] w-full items-center gap-[8px] rounded-[8px] border pr-[8px] pl-[5px]'
|
||||
className='pointer-events-none flex h-[32px] w-full items-center gap-2 rounded-[8px] border pr-2 pl-[5px]'
|
||||
style={{ borderColor: C.BORDER, backgroundColor: C.SURFACE_2 }}
|
||||
>
|
||||
<div className='flex h-[20px] w-[20px] flex-shrink-0 items-center justify-center rounded-[4px] bg-white'>
|
||||
@@ -112,11 +112,11 @@ export function LandingPreviewSidebar({
|
||||
</div>
|
||||
|
||||
{/* Top Navigation: Home (interactive), Search (static) */}
|
||||
<div className='mt-[10px] flex flex-shrink-0 flex-col gap-[2px] px-[8px]'>
|
||||
<div className='mt-2.5 flex flex-shrink-0 flex-col gap-0.5 px-2'>
|
||||
<button
|
||||
type='button'
|
||||
onClick={onSelectHome}
|
||||
className='mx-[2px] flex h-[28px] items-center gap-[8px] rounded-[8px] px-[8px] transition-colors'
|
||||
className='mx-0.5 flex h-[28px] items-center gap-2 rounded-[8px] px-2 transition-colors'
|
||||
style={{ backgroundColor: isHomeActive ? C.SURFACE_ACTIVE : 'transparent' }}
|
||||
onMouseEnter={(e) => {
|
||||
if (!isHomeActive) e.currentTarget.style.backgroundColor = C.SURFACE_ACTIVE
|
||||
@@ -134,13 +134,13 @@ export function LandingPreviewSidebar({
|
||||
</div>
|
||||
|
||||
{/* Workspace */}
|
||||
<div className='mt-[14px] flex flex-shrink-0 flex-col'>
|
||||
<div className='px-[16px] pb-[6px]'>
|
||||
<div className='mt-3.5 flex flex-shrink-0 flex-col'>
|
||||
<div className='px-4 pb-1.5'>
|
||||
<div className='font-base text-[12px]' style={{ color: C.TEXT_ICON }}>
|
||||
Workspace
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col gap-[2px] px-[8px]'>
|
||||
<div className='flex flex-col gap-0.5 px-2'>
|
||||
{WORKSPACE_NAV.map((item) => (
|
||||
<StaticNavItem key={item.id} icon={item.icon} label={item.label} />
|
||||
))}
|
||||
@@ -148,15 +148,15 @@ export function LandingPreviewSidebar({
|
||||
</div>
|
||||
|
||||
{/* Scrollable Tasks + Workflows */}
|
||||
<div className='flex flex-1 flex-col overflow-y-auto overflow-x-hidden pt-[14px]'>
|
||||
<div className='flex flex-1 flex-col overflow-y-auto overflow-x-hidden pt-3.5'>
|
||||
{/* Workflows */}
|
||||
<div className='flex flex-col'>
|
||||
<div className='px-[16px]'>
|
||||
<div className='px-4'>
|
||||
<div className='font-base text-[12px]' style={{ color: C.TEXT_ICON }}>
|
||||
Workflows
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-[6px] flex flex-col gap-[2px] px-[8px]'>
|
||||
<div className='mt-1.5 flex flex-col gap-0.5 px-2'>
|
||||
{workflows.map((workflow) => {
|
||||
const isActive = activeView === 'workflow' && workflow.id === activeWorkflowId
|
||||
return (
|
||||
@@ -164,7 +164,7 @@ export function LandingPreviewSidebar({
|
||||
key={workflow.id}
|
||||
type='button'
|
||||
onClick={() => onSelectWorkflow(workflow.id)}
|
||||
className='group mx-[2px] flex h-[28px] w-full items-center gap-[8px] rounded-[8px] px-[8px] transition-colors'
|
||||
className='group mx-0.5 flex h-[28px] w-full items-center gap-2 rounded-[8px] px-2 transition-colors'
|
||||
style={{ backgroundColor: isActive ? C.SURFACE_ACTIVE : 'transparent' }}
|
||||
onMouseEnter={(e) => {
|
||||
if (!isActive) e.currentTarget.style.backgroundColor = C.SURFACE_ACTIVE
|
||||
@@ -195,7 +195,7 @@ export function LandingPreviewSidebar({
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className='flex flex-shrink-0 flex-col gap-[2px] px-[8px] pt-[9px] pb-[8px]'>
|
||||
<div className='flex flex-shrink-0 flex-col gap-0.5 px-2 pt-[9px] pb-2'>
|
||||
{FOOTER_NAV.map((item) => (
|
||||
<StaticNavItem key={item.id} icon={item.icon} label={item.label} />
|
||||
))}
|
||||
|
||||
+1
-1
@@ -137,7 +137,7 @@ function PreviewFlow({ workflow, animate = false, fitViewOptions }: LandingPrevi
|
||||
proOptions={PRO_OPTIONS}
|
||||
fitView
|
||||
fitViewOptions={resolvedFitViewOptions}
|
||||
className='h-full w-full bg-[#1b1b1b]'
|
||||
className='h-full w-full bg-[var(--landing-bg)]'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
+12
-12
@@ -150,10 +150,10 @@ export const PreviewBlockNode = memo(function PreviewBlockNode({
|
||||
transition={{ duration: 0.45, delay, ease: EASE_OUT }}
|
||||
>
|
||||
<div className='w-[280px] select-none rounded-[8px] border border-[#3d3d3d] bg-[#232323]'>
|
||||
<div className='border-[#3d3d3d] border-b p-[8px]'>
|
||||
<div className='border-[#3d3d3d] border-b p-2'>
|
||||
<span className='font-medium text-[#e6e6e6] text-[16px]'>Note</span>
|
||||
</div>
|
||||
<div className='p-[10px]'>
|
||||
<div className='p-2.5'>
|
||||
<NoteMarkdown content={markdown} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -186,9 +186,9 @@ export const PreviewBlockNode = memo(function PreviewBlockNode({
|
||||
|
||||
{/* Header */}
|
||||
<div
|
||||
className={`flex items-center justify-between p-[8px] ${hasContent ? 'border-[#3d3d3d] border-b' : ''}`}
|
||||
className={`flex items-center justify-between p-2 ${hasContent ? 'border-[#3d3d3d] border-b' : ''}`}
|
||||
>
|
||||
<div className='relative z-10 flex min-w-0 flex-1 items-center gap-[10px]'>
|
||||
<div className='relative z-10 flex min-w-0 flex-1 items-center gap-2.5'>
|
||||
<div
|
||||
className='flex h-[24px] w-[24px] flex-shrink-0 items-center justify-center rounded-[6px]'
|
||||
style={{ background: bgColor }}
|
||||
@@ -201,17 +201,17 @@ export const PreviewBlockNode = memo(function PreviewBlockNode({
|
||||
|
||||
{/* Sub-block rows + tools */}
|
||||
{hasContent && (
|
||||
<div className='flex flex-col gap-[8px] p-[8px]'>
|
||||
<div className='flex flex-col gap-2 p-2'>
|
||||
{rows.map((row) => {
|
||||
const modelEntry = row.title === 'Model' ? getModelIconEntry(row.value) : null
|
||||
const ModelIcon = modelEntry?.icon
|
||||
return (
|
||||
<div key={row.title} className='flex items-center gap-[8px]'>
|
||||
<div key={row.title} className='flex items-center gap-2'>
|
||||
<span className='flex-shrink-0 font-normal text-[#b3b3b3] text-[14px] capitalize'>
|
||||
{row.title}
|
||||
</span>
|
||||
{row.value && (
|
||||
<span className='flex min-w-0 flex-1 items-center justify-end gap-[5px] font-normal text-[#e6e6e6] text-[14px]'>
|
||||
<span className='flex min-w-0 flex-1 items-center justify-end gap-2 font-normal text-[#e6e6e6] text-[14px]'>
|
||||
{ModelIcon && (
|
||||
<ModelIcon
|
||||
className={`inline-block flex-shrink-0 text-[#e6e6e6] ${modelEntry.size ?? 'h-[14px] w-[14px]'}`}
|
||||
@@ -226,15 +226,15 @@ export const PreviewBlockNode = memo(function PreviewBlockNode({
|
||||
|
||||
{/* Tool chips — inline with label */}
|
||||
{tools && tools.length > 0 && (
|
||||
<div className='flex items-center gap-[8px]'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<span className='flex-shrink-0 font-normal text-[#b3b3b3] text-[14px]'>Tools</span>
|
||||
<div className='flex flex-1 flex-wrap items-center justify-end gap-[5px]'>
|
||||
<div className='flex flex-1 flex-wrap items-center justify-end gap-2'>
|
||||
{tools.map((tool) => {
|
||||
const ToolIcon = BLOCK_ICONS[tool.type]
|
||||
return (
|
||||
<div
|
||||
key={tool.type}
|
||||
className='flex items-center gap-[5px] rounded-[5px] border border-[#3d3d3d] bg-[#2a2a2a] px-[6px] py-[3px]'
|
||||
className='flex items-center gap-2 rounded-[5px] border border-[#3d3d3d] bg-[#2a2a2a] px-2 py-1'
|
||||
>
|
||||
<div
|
||||
className='flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[4px]'
|
||||
@@ -277,13 +277,13 @@ function NoteMarkdown({ content }: { content: string }) {
|
||||
const lines = content.split('\n')
|
||||
|
||||
return (
|
||||
<div className='flex flex-col gap-[4px]'>
|
||||
<div className='flex flex-col gap-1'>
|
||||
{lines.map((line, i) => {
|
||||
const trimmed = line.trim()
|
||||
if (!trimmed) return <div key={i} className='h-[4px]' />
|
||||
|
||||
if (trimmed === '---') {
|
||||
return <hr key={i} className='my-[4px] border-[#3d3d3d] border-t' />
|
||||
return <hr key={i} className='my-1 border-[#3d3d3d] border-t' />
|
||||
}
|
||||
|
||||
if (trimmed.startsWith('### ')) {
|
||||
|
||||
@@ -81,7 +81,7 @@ export function LandingPreview() {
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className='dark flex aspect-[1116/549] w-full overflow-hidden rounded bg-[#1e1e1e] antialiased'
|
||||
className='dark flex aspect-[1116/549] w-full overflow-hidden rounded bg-[var(--landing-bg-surface)] antialiased'
|
||||
initial='hidden'
|
||||
animate='visible'
|
||||
variants={containerVariants}
|
||||
@@ -95,8 +95,8 @@ export function LandingPreview() {
|
||||
onSelectHome={handleSelectHome}
|
||||
/>
|
||||
</motion.div>
|
||||
<div className='flex min-w-0 flex-1 flex-col py-[8px] pr-[8px] pl-[8px] lg:pl-0'>
|
||||
<div className='flex flex-1 overflow-hidden rounded-[8px] border border-[#2c2c2c] bg-[#1b1b1b]'>
|
||||
<div className='flex min-w-0 flex-1 flex-col py-2 pr-2 pl-2 lg:pl-0'>
|
||||
<div className='flex flex-1 overflow-hidden rounded-[8px] border border-[#2c2c2c] bg-[var(--landing-bg)]'>
|
||||
<div
|
||||
className={
|
||||
isWorkflowView
|
||||
|
||||
@@ -29,7 +29,7 @@ function BlogCard({
|
||||
<Link
|
||||
href={`/blog/${slug}`}
|
||||
className={cn(
|
||||
'group/card flex flex-col overflow-hidden rounded-[5px] border border-[#2A2A2A] bg-[#1C1C1C] transition-colors hover:border-[#3D3D3D] hover:bg-[#2A2A2A]',
|
||||
'group/card flex flex-col overflow-hidden rounded-[5px] border border-[var(--landing-bg-elevated)] bg-[var(--landing-bg)] transition-colors hover:border-[var(--landing-border-strong)] hover:bg-[var(--landing-bg-elevated)]',
|
||||
className
|
||||
)}
|
||||
prefetch={false}
|
||||
@@ -44,9 +44,9 @@ function BlogCard({
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
<div className='flex-shrink-0 px-[10px] py-[6px]'>
|
||||
<div className='flex-shrink-0 px-2.5 py-1.5'>
|
||||
<span
|
||||
className='font-[430] font-season text-[#cdcdcd] leading-[140%]'
|
||||
className='font-[430] font-season text-[var(--landing-text-body)] leading-[140%]'
|
||||
style={{ fontSize: titleSize }}
|
||||
>
|
||||
{title}
|
||||
@@ -66,8 +66,8 @@ export function BlogDropdown({ posts }: BlogDropdownProps) {
|
||||
if (!featured) return null
|
||||
|
||||
return (
|
||||
<div className='w-[560px] rounded-[5px] border border-[#2A2A2A] bg-[#1C1C1C] p-[16px] shadow-[0_16px_48px_rgba(0,0,0,0.4)]'>
|
||||
<div className='grid grid-cols-3 gap-[8px]'>
|
||||
<div className='w-[560px] rounded-[5px] border border-[var(--landing-bg-elevated)] bg-[var(--landing-bg)] p-4 shadow-overlay'>
|
||||
<div className='grid grid-cols-3 gap-2'>
|
||||
<BlogCard
|
||||
slug={featured.slug}
|
||||
image={featured.ogImage}
|
||||
|
||||
@@ -37,15 +37,15 @@ const RESOURCE_CARDS = [
|
||||
|
||||
export function DocsDropdown() {
|
||||
return (
|
||||
<div className='w-[480px] rounded-[5px] border border-[#2A2A2A] bg-[#1C1C1C] p-[16px] shadow-[0_16px_48px_rgba(0,0,0,0.4)]'>
|
||||
<div className='grid grid-cols-2 gap-[10px]'>
|
||||
<div className='w-[480px] rounded-[5px] border border-[var(--landing-bg-elevated)] bg-[var(--landing-bg)] p-4 shadow-overlay'>
|
||||
<div className='grid grid-cols-2 gap-2.5'>
|
||||
{PREVIEW_CARDS.map((card) => (
|
||||
<a
|
||||
key={card.title}
|
||||
href={card.href}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='group/card overflow-hidden rounded-[5px] border border-[#2A2A2A] bg-[#1C1C1C] transition-colors hover:border-[#3D3D3D] hover:bg-[#2A2A2A]'
|
||||
className='group/card overflow-hidden rounded-[5px] border border-[var(--landing-bg-elevated)] bg-[var(--landing-bg)] transition-colors hover:border-[var(--landing-border-strong)] hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
<div className='relative h-[120px] w-full overflow-hidden bg-[#141414]'>
|
||||
<Image
|
||||
@@ -57,8 +57,8 @@ export function DocsDropdown() {
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
<div className='px-[10px] py-[8px]'>
|
||||
<span className='font-[430] font-season text-[#cdcdcd] text-[13px]'>
|
||||
<div className='px-2.5 py-2'>
|
||||
<span className='font-[430] font-season text-[var(--landing-text-body)] text-small'>
|
||||
{card.title}
|
||||
</span>
|
||||
</div>
|
||||
@@ -66,7 +66,7 @@ export function DocsDropdown() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className='mt-[8px] grid grid-cols-3 gap-[8px]'>
|
||||
<div className='mt-2 grid grid-cols-3 gap-2'>
|
||||
{RESOURCE_CARDS.map((card) => {
|
||||
const Icon = card.icon
|
||||
return (
|
||||
@@ -75,15 +75,15 @@ export function DocsDropdown() {
|
||||
href={card.href}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='flex flex-col gap-[4px] rounded-[5px] border border-[#2A2A2A] px-[10px] py-[8px] transition-colors hover:border-[#3D3D3D] hover:bg-[#232323]'
|
||||
className='flex flex-col gap-1 rounded-[5px] border border-[var(--landing-bg-elevated)] px-2.5 py-2 transition-colors hover:border-[var(--landing-border-strong)] hover:bg-[var(--landing-bg-card)]'
|
||||
>
|
||||
<div className='flex items-center gap-[6px]'>
|
||||
<Icon className='h-[13px] w-[13px] flex-shrink-0 text-[#939393]' />
|
||||
<span className='font-[430] font-season text-[#cdcdcd] text-[12px]'>
|
||||
<div className='flex items-center gap-1.5'>
|
||||
<Icon className='h-[13px] w-[13px] flex-shrink-0 text-[var(--landing-text-icon)]' />
|
||||
<span className='font-[430] font-season text-[var(--landing-text-body)] text-caption'>
|
||||
{card.title}
|
||||
</span>
|
||||
</div>
|
||||
<span className='font-season text-[#939393] text-[11px] leading-[130%]'>
|
||||
<span className='font-season text-[var(--landing-text-icon)] text-xs leading-[130%]'>
|
||||
{card.description}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -31,7 +31,7 @@ export function GitHubStars() {
|
||||
href='https://github.com/simstudioai/sim'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='flex items-center gap-[8px] px-[12px]'
|
||||
className='flex items-center gap-2 px-3'
|
||||
aria-label={`GitHub repository — ${stars} stars`}
|
||||
>
|
||||
<GithubOutlineIcon className='h-[14px] w-[14px]' />
|
||||
|
||||
@@ -32,8 +32,8 @@ const NAV_LINKS: NavLink[] = [
|
||||
{ label: 'Enterprise', href: 'https://form.typeform.com/to/jqCO12pF', external: true },
|
||||
]
|
||||
|
||||
const LOGO_CELL = 'flex items-center pl-[20px] lg:pl-[80px] pr-[20px]'
|
||||
const LINK_CELL = 'flex items-center px-[14px]'
|
||||
const LOGO_CELL = 'flex items-center pl-5 lg:pl-20 pr-5'
|
||||
const LINK_CELL = 'flex items-center px-3.5'
|
||||
|
||||
interface NavbarProps {
|
||||
logoOnly?: boolean
|
||||
@@ -96,7 +96,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
return (
|
||||
<nav
|
||||
aria-label='Primary navigation'
|
||||
className='relative flex h-[52px] border-[#2A2A2A] border-b-[1px] bg-[#1C1C1C] font-[430] font-season text-[#ECECEC] text-[14px]'
|
||||
className='relative flex h-[52px] border-[var(--landing-bg-elevated)] border-b-[1px] bg-[var(--landing-bg)] font-[430] font-season text-[var(--landing-text)] text-sm'
|
||||
itemScope
|
||||
itemType='https://schema.org/SiteNavigationElement'
|
||||
>
|
||||
@@ -138,9 +138,9 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
const isHighlighted = isActive || isThisHovered
|
||||
const isDimmed = anyHighlighted && !isHighlighted
|
||||
const linkClass = cn(
|
||||
icon ? `${LINK_CELL} gap-[8px]` : LINK_CELL,
|
||||
icon ? `${LINK_CELL} gap-2` : LINK_CELL,
|
||||
'transition-colors duration-200',
|
||||
isDimmed && 'text-[#F6F6F6]/60'
|
||||
isDimmed && 'text-[color-mix(in_srgb,var(--landing-text-subtle)_60%,transparent)]'
|
||||
)
|
||||
const chevron = icon === 'chevron' && <NavChevron open={isActive} />
|
||||
|
||||
@@ -171,7 +171,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
'-mt-[2px] absolute top-full left-0 z-50',
|
||||
'-mt-0.5 absolute top-full left-0 z-50',
|
||||
isActive
|
||||
? 'pointer-events-auto opacity-100'
|
||||
: 'pointer-events-none opacity-0'
|
||||
@@ -225,14 +225,14 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
'hidden items-center gap-[8px] pr-[80px] pl-[20px] lg:flex',
|
||||
'hidden items-center gap-2 pr-20 pl-5 lg:flex',
|
||||
isSessionPending && 'invisible'
|
||||
)}
|
||||
>
|
||||
{isAuthenticated ? (
|
||||
<Link
|
||||
href='/workspace'
|
||||
className='inline-flex h-[30px] items-center gap-[7px] rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] px-[9px] text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
className='inline-flex h-[30px] items-center gap-[7px] rounded-[5px] border border-[var(--white)] bg-[var(--white)] px-[9px] text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
aria-label='Go to app'
|
||||
>
|
||||
Go to App
|
||||
@@ -241,14 +241,14 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
<>
|
||||
<Link
|
||||
href='/login'
|
||||
className='inline-flex h-[30px] items-center rounded-[5px] border border-[#3d3d3d] px-[9px] text-[#ECECEC] text-[13.5px] transition-colors hover:bg-[#2A2A2A]'
|
||||
className='inline-flex h-[30px] items-center rounded-[5px] border border-[var(--landing-border-strong)] px-[9px] text-[13.5px] text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]'
|
||||
aria-label='Log in'
|
||||
>
|
||||
Log in
|
||||
</Link>
|
||||
<Link
|
||||
href='/signup'
|
||||
className='inline-flex h-[30px] items-center gap-[7px] rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] px-[9px] text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
className='inline-flex h-[30px] items-center gap-[7px] rounded-[5px] border border-[var(--white)] bg-[var(--white)] px-2.5 text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
aria-label='Get started with Sim'
|
||||
>
|
||||
Get started
|
||||
@@ -257,10 +257,10 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='flex flex-1 items-center justify-end pr-[20px] lg:hidden'>
|
||||
<div className='flex flex-1 items-center justify-end pr-5 lg:hidden'>
|
||||
<button
|
||||
type='button'
|
||||
className='flex h-[32px] w-[32px] items-center justify-center rounded-[5px] transition-colors hover:bg-[#2A2A2A]'
|
||||
className='flex h-[32px] w-[32px] items-center justify-center rounded-[5px] transition-colors hover:bg-[var(--landing-bg-elevated)]'
|
||||
onClick={() => setMobileMenuOpen((prev) => !prev)}
|
||||
aria-label={mobileMenuOpen ? 'Close menu' : 'Open menu'}
|
||||
aria-expanded={mobileMenuOpen}
|
||||
@@ -271,7 +271,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
'fixed inset-x-0 top-[52px] bottom-0 z-50 flex flex-col overflow-y-auto bg-[#1C1C1C] font-[430] font-season text-[14px] transition-all duration-200 lg:hidden',
|
||||
'fixed inset-x-0 top-[52px] bottom-0 z-50 flex flex-col overflow-y-auto bg-[var(--landing-bg)] font-[430] font-season text-sm transition-all duration-200 lg:hidden',
|
||||
mobileMenuOpen ? 'visible opacity-100' : 'invisible opacity-0'
|
||||
)}
|
||||
>
|
||||
@@ -280,13 +280,13 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
const href =
|
||||
useHomeLinks && rawHref.startsWith('/#') ? `/?home${rawHref.slice(1)}` : rawHref
|
||||
return (
|
||||
<li key={label} className='border-[#2A2A2A] border-b'>
|
||||
<li key={label} className='border-[var(--landing-border)] border-b'>
|
||||
{external ? (
|
||||
<a
|
||||
href={href}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='flex items-center justify-between px-[20px] py-[14px] text-[#ECECEC] transition-colors active:bg-[#2A2A2A]'
|
||||
className='flex items-center justify-between px-5 py-3.5 text-[var(--landing-text)] transition-colors active:bg-[var(--landing-bg-elevated)]'
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
{label}
|
||||
@@ -295,7 +295,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
) : (
|
||||
<Link
|
||||
href={href}
|
||||
className='flex items-center px-[20px] py-[14px] text-[#ECECEC] transition-colors active:bg-[#2A2A2A]'
|
||||
className='flex items-center px-5 py-3.5 text-[var(--landing-text)] transition-colors active:bg-[var(--landing-bg-elevated)]'
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
{label}
|
||||
@@ -304,12 +304,12 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
<li className='border-[#2A2A2A] border-b'>
|
||||
<li className='border-[var(--landing-border)] border-b'>
|
||||
<a
|
||||
href='https://github.com/simstudioai/sim'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='flex items-center gap-[8px] px-[20px] py-[14px] text-[#ECECEC] transition-colors active:bg-[#2A2A2A]'
|
||||
className='flex items-center gap-2 px-5 py-3.5 text-[var(--landing-text)] transition-colors active:bg-[var(--landing-bg-elevated)]'
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
<GithubOutlineIcon className='h-[14px] w-[14px]' />
|
||||
@@ -319,15 +319,12 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
</ul>
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
'mt-auto flex flex-col gap-[10px] p-[20px]',
|
||||
isSessionPending && 'invisible'
|
||||
)}
|
||||
className={cn('mt-auto flex flex-col gap-2.5 p-5', isSessionPending && 'invisible')}
|
||||
>
|
||||
{isAuthenticated ? (
|
||||
<Link
|
||||
href='/workspace'
|
||||
className='flex h-[32px] items-center justify-center rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] text-[14px] text-black transition-colors active:bg-[#E0E0E0]'
|
||||
className='flex h-[32px] items-center justify-center rounded-[5px] border border-[var(--white)] bg-[var(--white)] text-[14px] text-black transition-colors active:bg-[#E0E0E0]'
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
aria-label='Go to app'
|
||||
>
|
||||
@@ -337,7 +334,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
<>
|
||||
<Link
|
||||
href='/login'
|
||||
className='flex h-[32px] items-center justify-center rounded-[5px] border border-[#3d3d3d] text-[#ECECEC] text-[14px] transition-colors active:bg-[#2A2A2A]'
|
||||
className='flex h-[32px] items-center justify-center rounded-[5px] border border-[var(--landing-border-strong)] text-[14px] text-[var(--landing-text)] transition-colors active:bg-[var(--landing-bg-elevated)]'
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
aria-label='Log in'
|
||||
>
|
||||
@@ -345,7 +342,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
|
||||
</Link>
|
||||
<Link
|
||||
href='/signup'
|
||||
className='flex h-[32px] items-center justify-center rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] text-[14px] text-black transition-colors active:bg-[#E0E0E0]'
|
||||
className='flex h-[32px] items-center justify-center rounded-[5px] border border-[var(--white)] bg-[var(--white)] text-[14px] text-black transition-colors active:bg-[#E0E0E0]'
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
aria-label='Get started with Sim'
|
||||
>
|
||||
@@ -432,7 +429,13 @@ function MobileMenuIcon({ open }: { open: boolean }) {
|
||||
|
||||
function ExternalArrowIcon() {
|
||||
return (
|
||||
<svg width='12' height='12' viewBox='0 0 12 12' fill='none' className='text-[#666]'>
|
||||
<svg
|
||||
width='12'
|
||||
height='12'
|
||||
viewBox='0 0 12 12'
|
||||
fill='none'
|
||||
className='text-[var(--landing-text-secondary)]'
|
||||
>
|
||||
<path
|
||||
d='M3.5 2.5H9.5V8.5M9 3L3 9'
|
||||
stroke='currentColor'
|
||||
|
||||
@@ -107,21 +107,21 @@ function PricingCard({ tier }: PricingCardProps) {
|
||||
|
||||
return (
|
||||
<article className='flex flex-1 flex-col' aria-labelledby={`${tier.id}-heading`}>
|
||||
<div className='flex flex-1 flex-col gap-6 rounded-t-lg border border-[#E5E5E5] border-b-0 bg-white p-5'>
|
||||
<div className='flex flex-1 flex-col gap-6 rounded-t-lg border border-[var(--landing-border-light)] border-b-0 bg-white p-5'>
|
||||
<div className='flex flex-col'>
|
||||
<h3
|
||||
id={`${tier.id}-heading`}
|
||||
className='font-[430] font-season text-[#1C1C1C] text-[24px] leading-[100%] tracking-[-0.02em]'
|
||||
className='font-[430] font-season text-[24px] text-[var(--landing-text-dark)] leading-[100%] tracking-[-0.02em]'
|
||||
>
|
||||
{tier.name}
|
||||
</h3>
|
||||
<p className='mt-2 min-h-[44px] font-[430] font-season text-[#5c5c5c] text-[14px] leading-[125%] tracking-[0.02em]'>
|
||||
<p className='mt-2 min-h-[44px] font-[430] font-season text-[#5c5c5c] text-sm leading-[125%] tracking-[0.02em]'>
|
||||
{tier.description}
|
||||
</p>
|
||||
<p className='mt-4 flex items-center gap-1.5 font-[430] font-season text-[#1C1C1C] text-[20px] leading-[100%] tracking-[-0.02em]'>
|
||||
<p className='mt-4 flex items-center gap-1.5 font-[430] font-season text-[20px] text-[var(--landing-text-dark)] leading-[100%] tracking-[-0.02em]'>
|
||||
{tier.price}
|
||||
{tier.billingPeriod && (
|
||||
<span className='text-[#737373] text-[16px]'>{tier.billingPeriod}</span>
|
||||
<span className='text-[#737373] text-md'>{tier.billingPeriod}</span>
|
||||
)}
|
||||
</p>
|
||||
<div className='mt-4'>
|
||||
@@ -129,7 +129,7 @@ function PricingCard({ tier }: PricingCardProps) {
|
||||
<DemoRequestModal theme='light'>
|
||||
<button
|
||||
type='button'
|
||||
className='flex h-[32px] w-full items-center justify-center rounded-[5px] border border-[#E5E5E5] bg-transparent px-[10px] font-[430] font-season text-[#1C1C1C] text-[14px] transition-colors hover:bg-[#F0F0F0]'
|
||||
className='flex h-[32px] w-full items-center justify-center rounded-[5px] border border-[var(--landing-border-light)] bg-transparent px-2.5 font-[430] font-season text-[14px] text-[var(--landing-text-dark)] transition-colors hover:bg-[var(--landing-bg-hover)]'
|
||||
>
|
||||
{tier.cta.label}
|
||||
</button>
|
||||
@@ -137,14 +137,14 @@ function PricingCard({ tier }: PricingCardProps) {
|
||||
) : isPro ? (
|
||||
<Link
|
||||
href={tier.cta.href || '/signup'}
|
||||
className='flex h-[32px] w-full items-center justify-center rounded-[5px] border border-[#1D1D1D] bg-[#1D1D1D] px-[10px] font-[430] font-season text-[14px] text-white transition-colors hover:border-[#2A2A2A] hover:bg-[#2A2A2A]'
|
||||
className='flex h-[32px] w-full items-center justify-center rounded-[5px] border border-[#1D1D1D] bg-[#1D1D1D] px-2.5 font-[430] font-season text-[14px] text-white transition-colors hover:border-[var(--landing-border)] hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
{tier.cta.label}
|
||||
</Link>
|
||||
) : (
|
||||
<Link
|
||||
href={tier.cta.href || '/signup'}
|
||||
className='flex h-[32px] w-full items-center justify-center rounded-[5px] border border-[#E5E5E5] px-[10px] font-[430] font-season text-[#1C1C1C] text-[14px] transition-colors hover:bg-[#F0F0F0]'
|
||||
className='flex h-[32px] w-full items-center justify-center rounded-[5px] border border-[var(--landing-border-light)] px-2.5 font-[430] font-season text-[14px] text-[var(--landing-text-dark)] transition-colors hover:bg-[var(--landing-bg-hover)]'
|
||||
>
|
||||
{tier.cta.label}
|
||||
</Link>
|
||||
@@ -156,7 +156,7 @@ function PricingCard({ tier }: PricingCardProps) {
|
||||
{tier.features.map((feature) => (
|
||||
<li key={feature} className='flex items-center gap-2'>
|
||||
<CheckIcon color='#404040' />
|
||||
<span className='font-[400] font-season text-[#5c5c5c] text-[14px] leading-[125%] tracking-[0.02em]'>
|
||||
<span className='font-[400] font-season text-[#5c5c5c] text-sm leading-[125%] tracking-[0.02em]'>
|
||||
{feature}
|
||||
</span>
|
||||
</li>
|
||||
@@ -187,9 +187,13 @@ function PricingCard({ tier }: PricingCardProps) {
|
||||
*/
|
||||
export default function Pricing() {
|
||||
return (
|
||||
<section id='pricing' aria-labelledby='pricing-heading' className='bg-[#F6F6F6]'>
|
||||
<div className='px-4 pt-[60px] pb-[40px] sm:px-8 sm:pt-[80px] sm:pb-0 md:px-[80px] md:pt-[100px]'>
|
||||
<div className='flex flex-col items-start gap-3 sm:gap-4 md:gap-[20px]'>
|
||||
<section
|
||||
id='pricing'
|
||||
aria-labelledby='pricing-heading'
|
||||
className='bg-[var(--landing-bg-section)]'
|
||||
>
|
||||
<div className='px-4 pt-[60px] pb-10 sm:px-8 sm:pt-20 sm:pb-0 md:px-20 md:pt-[100px]'>
|
||||
<div className='flex flex-col items-start gap-3 sm:gap-4 md:gap-5'>
|
||||
<Badge
|
||||
variant='blue'
|
||||
size='md'
|
||||
@@ -201,7 +205,7 @@ export default function Pricing() {
|
||||
|
||||
<h2
|
||||
id='pricing-heading'
|
||||
className='font-[430] font-season text-[#1C1C1C] text-[32px] leading-[100%] tracking-[-0.02em] sm:text-[36px] md:text-[40px]'
|
||||
className='text-balance font-[430] font-season text-[32px] text-[var(--landing-text-dark)] leading-[100%] tracking-[-0.02em] sm:text-[36px] md:text-[40px]'
|
||||
>
|
||||
Pricing
|
||||
</h2>
|
||||
|
||||
@@ -19,7 +19,7 @@ const LandingPreviewWorkflow = dynamic(
|
||||
).then((mod) => mod.LandingPreviewWorkflow),
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => <div className='h-full w-full bg-[#1b1b1b]' />,
|
||||
loading: () => <div className='h-full w-full bg-[var(--landing-bg)]' />,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -337,7 +337,7 @@ function DotGrid({ className, cols, rows, gap = 0 }: DotGridProps) {
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: cols * rows }, (_, i) => (
|
||||
<div key={i} className='h-[1.5px] w-[1.5px] rounded-full bg-[#2A2A2A]' />
|
||||
<div key={i} className='h-[1.5px] w-[1.5px] rounded-full bg-[var(--landing-bg-elevated)]' />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
@@ -412,7 +412,7 @@ export default function Templates() {
|
||||
ref={sectionRef}
|
||||
id='templates'
|
||||
aria-labelledby='templates-heading'
|
||||
className='mt-[40px] mb-[80px]'
|
||||
className='mt-10 mb-20'
|
||||
>
|
||||
<p className='sr-only'>
|
||||
Sim includes {TEMPLATE_WORKFLOWS.length} pre-built workflow templates covering OCR
|
||||
@@ -422,9 +422,9 @@ export default function Templates() {
|
||||
customise it, and deploy in minutes.
|
||||
</p>
|
||||
|
||||
<div className='bg-[#1C1C1C]'>
|
||||
<div className='bg-[var(--landing-bg)]'>
|
||||
<DotGrid
|
||||
className='overflow-hidden border-[#2A2A2A] border-y bg-[#1C1C1C] p-[6px]'
|
||||
className='overflow-hidden border-[var(--landing-bg-elevated)] border-y bg-[var(--landing-bg)] p-1.5'
|
||||
cols={160}
|
||||
rows={1}
|
||||
gap={6}
|
||||
@@ -449,8 +449,8 @@ export default function Templates() {
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className='px-[20px] pt-[60px] lg:px-[80px] lg:pt-[100px]'>
|
||||
<div className='flex flex-col items-start gap-[20px]'>
|
||||
<div className='px-5 pt-[60px] lg:px-20 lg:pt-[100px]'>
|
||||
<div className='flex flex-col items-start gap-5'>
|
||||
<Badge
|
||||
variant='blue'
|
||||
size='md'
|
||||
@@ -466,12 +466,12 @@ export default function Templates() {
|
||||
|
||||
<h2
|
||||
id='templates-heading'
|
||||
className='font-[430] font-season text-[28px] text-white leading-[100%] tracking-[-0.02em] lg:text-[40px]'
|
||||
className='text-balance font-[430] font-season text-[28px] text-white leading-[100%] tracking-[-0.02em] lg:text-[40px]'
|
||||
>
|
||||
Ship your agent in minutes
|
||||
</h2>
|
||||
|
||||
<p className='font-[430] font-season text-[#F6F6F0]/50 text-[15px] leading-[150%] tracking-[0.02em] lg:text-[18px]'>
|
||||
<p className='font-[430] font-season text-[#F6F6F0]/50 text-base leading-[150%] tracking-[0.02em] lg:text-lg'>
|
||||
Pre-built templates for every use case—pick one, swap{' '}
|
||||
<br className='hidden lg:inline' />
|
||||
models and tools to fit your stack, and deploy.
|
||||
@@ -479,11 +479,11 @@ export default function Templates() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mt-[40px] flex border-[#2A2A2A] border-y lg:mt-[73px]'>
|
||||
<div className='mt-10 flex border-[var(--landing-bg-elevated)] border-y lg:mt-[73px]'>
|
||||
<div className='shrink-0'>
|
||||
<div className='h-full lg:hidden'>
|
||||
<DotGrid
|
||||
className='h-full w-[24px] overflow-hidden border-[#2A2A2A] border-r p-[4px]'
|
||||
className='h-full w-[24px] overflow-hidden border-[var(--landing-bg-elevated)] border-r p-1'
|
||||
cols={2}
|
||||
rows={55}
|
||||
gap={4}
|
||||
@@ -491,7 +491,7 @@ export default function Templates() {
|
||||
</div>
|
||||
<div className='hidden h-full lg:block'>
|
||||
<DotGrid
|
||||
className='h-full w-[80px] overflow-hidden border-[#2A2A2A] border-r p-[6px]'
|
||||
className='h-full w-[80px] overflow-hidden border-[var(--landing-bg-elevated)] border-r p-1.5'
|
||||
cols={8}
|
||||
rows={55}
|
||||
gap={6}
|
||||
@@ -503,7 +503,7 @@ export default function Templates() {
|
||||
<div
|
||||
role='tablist'
|
||||
aria-label='Workflow templates'
|
||||
className='flex w-full shrink-0 flex-col border-[#2A2A2A] lg:w-[300px] lg:border-r'
|
||||
className='flex w-full shrink-0 flex-col border-[var(--landing-bg-elevated)] lg:w-[300px] lg:border-r'
|
||||
>
|
||||
{TEMPLATE_WORKFLOWS.map((workflow, index) => {
|
||||
const isActive = index === activeIndex
|
||||
@@ -521,7 +521,7 @@ export default function Templates() {
|
||||
isActive
|
||||
? 'z-10'
|
||||
: cn(
|
||||
'flex items-center px-[12px] py-[10px] hover:bg-[#232323]/50',
|
||||
'flex items-center px-3 py-2.5 hover:bg-[color-mix(in_srgb,var(--landing-bg-card)_50%,transparent)]',
|
||||
index < TEMPLATE_WORKFLOWS.length - 1 &&
|
||||
'shadow-[inset_0_-1px_0_0_#2A2A2A]'
|
||||
)
|
||||
@@ -543,8 +543,8 @@ export default function Templates() {
|
||||
className='absolute right-[-8px] bottom-0 left-2 h-2'
|
||||
style={buildBottomWallStyle(depth)}
|
||||
/>
|
||||
<div className='-translate-y-2 relative flex translate-x-2 items-center bg-[#242424] px-[12px] py-[10px] shadow-[inset_0_0_0_1.5px_#3E3E3E]'>
|
||||
<span className='flex-1 font-[430] font-season text-[16px] text-white'>
|
||||
<div className='-translate-y-2 relative flex translate-x-2 items-center bg-[var(--landing-bg-card)] px-3 py-2.5 shadow-[inset_0_0_0_1.5px_#3E3E3E]'>
|
||||
<span className='flex-1 font-[430] font-season text-md text-white'>
|
||||
{workflow.name}
|
||||
</span>
|
||||
<ChevronDown
|
||||
@@ -556,7 +556,7 @@ export default function Templates() {
|
||||
)
|
||||
})()
|
||||
) : (
|
||||
<span className='font-[430] font-season text-[#F6F6F0]/50 text-[16px]'>
|
||||
<span className='font-[430] font-season text-[#F6F6F0]/50 text-md'>
|
||||
{workflow.name}
|
||||
</span>
|
||||
)}
|
||||
@@ -571,19 +571,19 @@ export default function Templates() {
|
||||
transition={{ duration: 0.25, ease: [0.4, 0, 0.2, 1] }}
|
||||
className='overflow-hidden'
|
||||
>
|
||||
<div className='aspect-[16/10] w-full border-[#2A2A2A] border-y bg-[#1b1b1b]'>
|
||||
<div className='aspect-[16/10] w-full border-[var(--landing-bg-elevated)] border-y bg-[var(--landing-bg)]'>
|
||||
<LandingPreviewWorkflow
|
||||
workflow={workflow}
|
||||
animate
|
||||
fitViewOptions={{ padding: 0.15, maxZoom: 1.3 }}
|
||||
/>
|
||||
</div>
|
||||
<div className='p-[12px]'>
|
||||
<div className='p-3'>
|
||||
<button
|
||||
type='button'
|
||||
onClick={handleUseTemplate}
|
||||
disabled={isPreparingTemplate}
|
||||
className='inline-flex h-[32px] w-full cursor-pointer items-center justify-center gap-[6px] rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] font-[430] font-season text-[14px] text-black transition-colors active:bg-[#E0E0E0]'
|
||||
className='inline-flex h-[32px] w-full cursor-pointer items-center justify-center gap-1.5 rounded-[5px] border border-white bg-white font-[430] font-season text-black text-sm transition-colors active:bg-[#E0E0E0]'
|
||||
>
|
||||
{isPreparingTemplate ? 'Preparing...' : 'Use template'}
|
||||
</button>
|
||||
@@ -614,7 +614,7 @@ export default function Templates() {
|
||||
type='button'
|
||||
onClick={handleUseTemplate}
|
||||
disabled={isPreparingTemplate}
|
||||
className='group/cta absolute top-[16px] right-[16px] z-10 inline-flex h-[32px] cursor-pointer items-center gap-[6px] rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] px-[10px] font-[430] font-season text-[14px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
className='group/cta absolute top-4 right-[16px] z-10 inline-flex h-[32px] cursor-pointer items-center gap-1.5 rounded-[5px] border border-white bg-white px-2.5 font-[430] font-season text-black text-sm transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
>
|
||||
{isPreparingTemplate ? 'Preparing...' : 'Use template'}
|
||||
<span className='relative h-[10px] w-[10px] shrink-0'>
|
||||
@@ -642,7 +642,7 @@ export default function Templates() {
|
||||
<div className='shrink-0'>
|
||||
<div className='h-full lg:hidden'>
|
||||
<DotGrid
|
||||
className='h-full w-[24px] overflow-hidden border-[#2A2A2A] border-l p-[4px]'
|
||||
className='h-full w-[24px] overflow-hidden border-[var(--landing-bg-elevated)] border-l p-1'
|
||||
cols={2}
|
||||
rows={55}
|
||||
gap={4}
|
||||
@@ -650,7 +650,7 @@ export default function Templates() {
|
||||
</div>
|
||||
<div className='hidden h-full lg:block'>
|
||||
<DotGrid
|
||||
className='h-full w-[80px] overflow-hidden border-[#2A2A2A] border-l p-[6px]'
|
||||
className='h-full w-[80px] overflow-hidden border-[var(--landing-bg-elevated)] border-l p-1.5'
|
||||
cols={8}
|
||||
rows={55}
|
||||
gap={6}
|
||||
|
||||
@@ -36,7 +36,9 @@ export default async function Landing() {
|
||||
const blogPosts = await getNavBlogPosts()
|
||||
|
||||
return (
|
||||
<div className={`${season.variable} ${martianMono.variable} min-h-screen bg-[#1C1C1C]`}>
|
||||
<div
|
||||
className={`${season.variable} ${martianMono.variable} min-h-screen bg-[var(--landing-bg)]`}
|
||||
>
|
||||
<a
|
||||
href='#main-content'
|
||||
className='sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4 focus:z-[100] focus:rounded-md focus:bg-white focus:px-4 focus:py-2 focus:font-medium focus:text-black focus:text-sm'
|
||||
|
||||
@@ -10,7 +10,7 @@ export function BackLink() {
|
||||
return (
|
||||
<Link
|
||||
href='/blog'
|
||||
className='group flex items-center gap-1 text-[#999] text-sm hover:text-[#ECECEC]'
|
||||
className='group flex items-center gap-1 text-[var(--landing-text-muted)] text-sm hover:text-[var(--landing-text)]'
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
|
||||
@@ -7,51 +7,51 @@ export default function BlogPostLoading() {
|
||||
<div className='mx-auto max-w-[1450px] px-6 pt-8 sm:px-8 sm:pt-12 md:px-12 md:pt-16'>
|
||||
{/* Back link */}
|
||||
<div className='mb-6'>
|
||||
<Skeleton className='h-[16px] w-[60px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[16px] w-[60px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
{/* Image + title row */}
|
||||
<div className='flex flex-col gap-8 md:flex-row md:gap-12'>
|
||||
{/* Image */}
|
||||
<div className='w-full flex-shrink-0 md:w-[450px]'>
|
||||
<Skeleton className='aspect-[450/360] w-full rounded-lg bg-[#2A2A2A]' />
|
||||
<Skeleton className='aspect-[450/360] w-full rounded-lg bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
{/* Title + author */}
|
||||
<div className='flex flex-1 flex-col justify-between'>
|
||||
<div>
|
||||
<Skeleton className='h-[48px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='mt-[8px] h-[48px] w-[80%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[48px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='mt-2 h-[48px] w-[80%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
<div className='mt-4 flex items-center justify-between'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<Skeleton className='h-[24px] w-[24px] rounded-full bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[16px] w-[100px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[24px] w-[24px] rounded-full bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[16px] w-[100px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
<Skeleton className='h-[32px] w-[32px] rounded-[6px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[32px] w-[32px] rounded-[6px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Divider */}
|
||||
<Skeleton className='mt-8 h-[1px] w-full bg-[#2A2A2A] sm:mt-12' />
|
||||
<Skeleton className='mt-8 h-[1px] w-full bg-[var(--landing-bg-elevated)] sm:mt-12' />
|
||||
{/* Date + description */}
|
||||
<div className='flex flex-col gap-6 py-8 sm:flex-row sm:items-start sm:justify-between sm:gap-8 sm:py-10'>
|
||||
<Skeleton className='h-[16px] w-[120px] flex-shrink-0 rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='flex-1 space-y-[8px]'>
|
||||
<Skeleton className='h-[20px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[20px] w-[70%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[16px] w-[120px] flex-shrink-0 rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='flex-1 space-y-2'>
|
||||
<Skeleton className='h-[20px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[20px] w-[70%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Article body */}
|
||||
<div className='mx-auto max-w-[900px] px-6 pb-20 sm:px-8 md:px-12'>
|
||||
<div className='space-y-[16px]'>
|
||||
<Skeleton className='h-[16px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[16px] w-[95%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[16px] w-[88%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[16px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='mt-[24px] h-[24px] w-[200px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[16px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[16px] w-[92%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[16px] w-[85%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='space-y-4'>
|
||||
<Skeleton className='h-[16px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[16px] w-[95%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[16px] w-[88%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[16px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='mt-6 h-[24px] w-[200px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[16px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[16px] w-[92%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[16px] w-[85%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@@ -66,7 +66,7 @@ export default async function Page({ params }: { params: Promise<{ slug: string
|
||||
</div>
|
||||
<div className='flex flex-1 flex-col justify-between'>
|
||||
<h1
|
||||
className='font-[500] text-[#ECECEC] text-[36px] leading-tight tracking-tight sm:text-[48px] md:text-[56px] lg:text-[64px]'
|
||||
className='text-balance font-[500] text-[36px] text-[var(--landing-text)] leading-tight tracking-tight sm:text-[48px] md:text-[56px] lg:text-[64px]'
|
||||
itemProp='headline'
|
||||
>
|
||||
{post.title}
|
||||
@@ -85,7 +85,7 @@ export default async function Page({ params }: { params: Promise<{ slug: string
|
||||
href={a?.url || '#'}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer author'
|
||||
className='text-[#999] text-[14px] leading-[1.5] hover:text-[#ECECEC] sm:text-[16px]'
|
||||
className='text-[var(--landing-text-muted)] text-sm leading-[1.5] hover:text-[var(--landing-text)] sm:text-md'
|
||||
itemProp='author'
|
||||
itemScope
|
||||
itemType='https://schema.org/Person'
|
||||
@@ -99,11 +99,11 @@ export default async function Page({ params }: { params: Promise<{ slug: string
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr className='mt-8 border-[#2A2A2A] border-t sm:mt-12' />
|
||||
<hr className='mt-8 border-[var(--landing-bg-elevated)] border-t sm:mt-12' />
|
||||
<div className='flex flex-col gap-6 py-8 sm:flex-row sm:items-start sm:justify-between sm:gap-8 sm:py-10'>
|
||||
<div className='flex flex-shrink-0 items-center gap-4'>
|
||||
<time
|
||||
className='block text-[#999] text-[14px] leading-[1.5] sm:text-[16px]'
|
||||
className='block text-[var(--landing-text-muted)] text-sm leading-[1.5] sm:text-md'
|
||||
dateTime={post.date}
|
||||
itemProp='datePublished'
|
||||
>
|
||||
@@ -116,7 +116,7 @@ export default async function Page({ params }: { params: Promise<{ slug: string
|
||||
<meta itemProp='dateModified' content={post.updated ?? post.date} />
|
||||
</div>
|
||||
<div className='flex-1'>
|
||||
<p className='m-0 block translate-y-[-4px] font-[400] text-[#999] text-[18px] leading-[1.5] sm:text-[20px] md:text-[26px]'>
|
||||
<p className='m-0 block translate-y-[-4px] font-[400] text-[var(--landing-text-muted)] text-lg leading-[1.5] sm:text-[20px] md:text-[26px]'>
|
||||
{post.description}
|
||||
</p>
|
||||
</div>
|
||||
@@ -124,18 +124,18 @@ export default async function Page({ params }: { params: Promise<{ slug: string
|
||||
</header>
|
||||
|
||||
<div className='mx-auto max-w-[900px] px-6 pb-20 sm:px-8 md:px-12' itemProp='articleBody'>
|
||||
<div className='prose prose-lg prose-invert max-w-none prose-blockquote:border-[#3d3d3d] prose-hr:border-[#2A2A2A] prose-a:text-[#ECECEC] prose-blockquote:text-[#999] prose-code:text-[#ECECEC] prose-headings:text-[#ECECEC] prose-li:text-[#999] prose-p:text-[#999] prose-strong:text-[#ECECEC]'>
|
||||
<div className='prose prose-lg prose-invert max-w-none prose-blockquote:border-[var(--landing-border-strong)] prose-hr:border-[var(--landing-bg-elevated)] prose-a:text-[var(--landing-text)] prose-blockquote:text-[var(--landing-text-muted)] prose-code:text-[var(--landing-text)] prose-headings:text-[var(--landing-text)] prose-li:text-[var(--landing-text-muted)] prose-p:text-[var(--landing-text-muted)] prose-strong:text-[var(--landing-text)]'>
|
||||
<Article />
|
||||
{post.faq && post.faq.length > 0 ? <FAQ items={post.faq} /> : null}
|
||||
</div>
|
||||
</div>
|
||||
{related.length > 0 && (
|
||||
<div className='mx-auto max-w-[900px] px-6 pb-24 sm:px-8 md:px-12'>
|
||||
<h2 className='mb-4 font-[500] text-[#ECECEC] text-[24px]'>Related posts</h2>
|
||||
<h2 className='mb-4 font-[500] text-[24px] text-[var(--landing-text)]'>Related posts</h2>
|
||||
<div className='grid grid-cols-1 gap-4 sm:grid-cols-2 sm:gap-6 lg:grid-cols-3'>
|
||||
{related.map((p) => (
|
||||
<Link key={p.slug} href={`/blog/${p.slug}`} className='group'>
|
||||
<div className='overflow-hidden rounded-lg border border-[#2A2A2A]'>
|
||||
<div className='overflow-hidden rounded-lg border border-[var(--landing-bg-elevated)]'>
|
||||
<Image
|
||||
src={p.ogImage}
|
||||
alt={p.title}
|
||||
@@ -147,14 +147,16 @@ export default async function Page({ params }: { params: Promise<{ slug: string
|
||||
unoptimized
|
||||
/>
|
||||
<div className='p-3'>
|
||||
<div className='mb-1 text-[#999] text-xs'>
|
||||
<div className='mb-1 text-[var(--landing-text-muted)] text-xs'>
|
||||
{new Date(p.date).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})}
|
||||
</div>
|
||||
<div className='font-[500] text-[#ECECEC] text-sm leading-tight'>{p.title}</div>
|
||||
<div className='font-[500] text-[var(--landing-text)] text-sm leading-tight'>
|
||||
{p.title}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
@@ -41,7 +41,7 @@ export function ShareButton({ url, title }: ShareButtonProps) {
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
className='flex items-center gap-1.5 text-[#999] text-sm hover:text-[#ECECEC]'
|
||||
className='flex items-center gap-1.5 text-[var(--landing-text-muted)] text-sm hover:text-[var(--landing-text)]'
|
||||
aria-label='Share this post'
|
||||
>
|
||||
<Share2 className='h-4 w-4' />
|
||||
|
||||
@@ -6,16 +6,16 @@ export default function AuthorLoading() {
|
||||
return (
|
||||
<main className='mx-auto max-w-[900px] px-6 py-10 sm:px-8 md:px-12'>
|
||||
<div className='mb-6 flex items-center gap-3'>
|
||||
<Skeleton className='h-[40px] w-[40px] rounded-full bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[32px] w-[160px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[40px] w-[40px] rounded-full bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[32px] w-[160px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
<div className='grid grid-cols-1 gap-8 sm:grid-cols-2'>
|
||||
{Array.from({ length: SKELETON_POST_COUNT }).map((_, i) => (
|
||||
<div key={i} className='overflow-hidden rounded-lg border border-[#2A2A2A]'>
|
||||
<Skeleton className='h-[160px] w-full rounded-none bg-[#2A2A2A]' />
|
||||
<div key={i} className='overflow-hidden rounded-lg border border-[var(--landing-border)]'>
|
||||
<Skeleton className='h-[160px] w-full rounded-none bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='p-3'>
|
||||
<Skeleton className='mb-1 h-[12px] w-[80px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[14px] w-[200px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='mb-1 h-[12px] w-[80px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[14px] w-[200px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -23,7 +23,7 @@ export default async function AuthorPage({ params }: { params: Promise<{ id: str
|
||||
if (!author) {
|
||||
return (
|
||||
<main className='mx-auto max-w-[900px] px-6 py-10 sm:px-8 md:px-12'>
|
||||
<h1 className='font-[500] text-[#ECECEC] text-[32px]'>Author not found</h1>
|
||||
<h1 className='font-[500] text-[32px] text-[var(--landing-text)]'>Author not found</h1>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -52,12 +52,14 @@ export default async function AuthorPage({ params }: { params: Promise<{ id: str
|
||||
unoptimized
|
||||
/>
|
||||
) : null}
|
||||
<h1 className='font-[500] text-[#ECECEC] text-[32px] leading-tight'>{author.name}</h1>
|
||||
<h1 className='font-[500] text-[32px] text-[var(--landing-text)] leading-tight'>
|
||||
{author.name}
|
||||
</h1>
|
||||
</div>
|
||||
<div className='grid grid-cols-1 gap-8 sm:grid-cols-2'>
|
||||
{posts.map((p) => (
|
||||
<Link key={p.slug} href={`/blog/${p.slug}`} className='group'>
|
||||
<div className='overflow-hidden rounded-lg border border-[#2A2A2A]'>
|
||||
<div className='overflow-hidden rounded-lg border border-[var(--landing-bg-elevated)]'>
|
||||
<Image
|
||||
src={p.ogImage}
|
||||
alt={p.title}
|
||||
@@ -67,14 +69,16 @@ export default async function AuthorPage({ params }: { params: Promise<{ id: str
|
||||
unoptimized
|
||||
/>
|
||||
<div className='p-3'>
|
||||
<div className='mb-1 text-[#999] text-xs'>
|
||||
<div className='mb-1 text-[var(--landing-text-muted)] text-xs'>
|
||||
{new Date(p.date).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})}
|
||||
</div>
|
||||
<div className='font-[500] text-[#ECECEC] text-sm leading-tight'>{p.title}</div>
|
||||
<div className='font-[500] text-[var(--landing-text)] text-sm leading-tight'>
|
||||
{p.title}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
@@ -26,7 +26,7 @@ export default async function StudioLayout({ children }: { children: React.React
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex min-h-screen flex-col bg-[#1C1C1C] font-[430] font-season text-[#ECECEC]'>
|
||||
<div className='flex min-h-screen flex-col bg-[var(--landing-bg)] font-[430] font-season text-[var(--landing-text)]'>
|
||||
<script
|
||||
type='application/ld+json'
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(orgJsonLd) }}
|
||||
|
||||
@@ -5,20 +5,23 @@ const SKELETON_CARD_COUNT = 6
|
||||
export default function BlogLoading() {
|
||||
return (
|
||||
<main className='mx-auto max-w-[1200px] px-6 py-12 sm:px-8 md:px-12'>
|
||||
<Skeleton className='h-[48px] w-[100px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='mt-3 h-[18px] w-[420px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[48px] w-[100px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='mt-3 h-[18px] w-[420px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='mt-10 grid grid-cols-1 gap-4 md:grid-cols-2 md:gap-6 lg:grid-cols-3'>
|
||||
{Array.from({ length: SKELETON_CARD_COUNT }).map((_, i) => (
|
||||
<div key={i} className='flex flex-col overflow-hidden rounded-xl border border-[#2A2A2A]'>
|
||||
<Skeleton className='aspect-video w-full rounded-none bg-[#2A2A2A]' />
|
||||
<div
|
||||
key={i}
|
||||
className='flex flex-col overflow-hidden rounded-xl border border-[var(--landing-border)]'
|
||||
>
|
||||
<Skeleton className='aspect-video w-full rounded-none bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='flex flex-1 flex-col p-4'>
|
||||
<Skeleton className='mb-2 h-[12px] w-[80px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='mb-1 h-[20px] w-[85%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='mb-3 h-[14px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[14px] w-[70%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='mb-2 h-[12px] w-[80px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='mb-1 h-[20px] w-[85%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='mb-3 h-[14px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[14px] w-[70%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='mt-3 flex items-center gap-2'>
|
||||
<Skeleton className='h-[16px] w-[16px] rounded-full bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[12px] w-[80px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[16px] w-[16px] rounded-full bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[12px] w-[80px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -50,10 +50,10 @@ export default async function BlogIndex({
|
||||
type='application/ld+json'
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(blogJsonLd) }}
|
||||
/>
|
||||
<h1 className='mb-3 font-[500] text-[#ECECEC] text-[40px] leading-tight sm:text-[56px]'>
|
||||
<h1 className='mb-3 text-balance font-[500] text-[40px] text-[var(--landing-text)] leading-tight sm:text-[56px]'>
|
||||
Blog
|
||||
</h1>
|
||||
<p className='mb-10 text-[#999] text-[18px]'>
|
||||
<p className='mb-10 text-[var(--landing-text-muted)] text-lg'>
|
||||
Announcements, insights, and guides for building AI agent workflows.
|
||||
</p>
|
||||
|
||||
@@ -75,18 +75,18 @@ export default async function BlogIndex({
|
||||
{pageNum > 1 && (
|
||||
<Link
|
||||
href={`/blog?page=${pageNum - 1}${tag ? `&tag=${encodeURIComponent(tag)}` : ''}`}
|
||||
className='rounded-[5px] border border-[#3d3d3d] px-3 py-1 text-[#ECECEC] text-sm transition-colors hover:bg-[#2A2A2A]'
|
||||
className='rounded-[5px] border border-[var(--landing-border-strong)] px-3 py-1 text-[var(--landing-text)] text-sm transition-colors hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
Previous
|
||||
</Link>
|
||||
)}
|
||||
<span className='text-[#999] text-sm'>
|
||||
<span className='text-[var(--landing-text-muted)] text-sm'>
|
||||
Page {pageNum} of {totalPages}
|
||||
</span>
|
||||
{pageNum < totalPages && (
|
||||
<Link
|
||||
href={`/blog?page=${pageNum + 1}${tag ? `&tag=${encodeURIComponent(tag)}` : ''}`}
|
||||
className='rounded-[5px] border border-[#3d3d3d] px-3 py-1 text-[#ECECEC] text-sm transition-colors hover:bg-[#2A2A2A]'
|
||||
className='rounded-[5px] border border-[var(--landing-border-strong)] px-3 py-1 text-[var(--landing-text)] text-sm transition-colors hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
Next
|
||||
</Link>
|
||||
|
||||
@@ -25,7 +25,7 @@ export function PostGrid({ posts }: { posts: Post[] }) {
|
||||
<div className='grid grid-cols-1 gap-4 md:grid-cols-2 md:gap-6 lg:grid-cols-3'>
|
||||
{posts.map((p, index) => (
|
||||
<Link key={p.slug} href={`/blog/${p.slug}`} className='group flex flex-col'>
|
||||
<div className='flex h-full flex-col overflow-hidden rounded-xl border border-[#2A2A2A] transition-colors duration-300 hover:border-[#3d3d3d]'>
|
||||
<div className='flex h-full flex-col overflow-hidden rounded-xl border border-[var(--landing-bg-elevated)] transition-colors duration-300 hover:border-[var(--landing-border-strong)]'>
|
||||
{/* Image container with fixed aspect ratio to prevent layout shift */}
|
||||
<div className='relative aspect-video w-full overflow-hidden'>
|
||||
<Image
|
||||
@@ -40,29 +40,33 @@ export function PostGrid({ posts }: { posts: Post[] }) {
|
||||
/>
|
||||
</div>
|
||||
<div className='flex flex-1 flex-col p-4'>
|
||||
<div className='mb-2 text-[#999] text-xs'>
|
||||
<div className='mb-2 text-[var(--landing-text-muted)] text-xs'>
|
||||
{new Date(p.date).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})}
|
||||
</div>
|
||||
<h3 className='mb-1 font-[500] text-[#ECECEC] text-lg leading-tight'>{p.title}</h3>
|
||||
<p className='mb-3 line-clamp-3 flex-1 text-[#999] text-sm'>{p.description}</p>
|
||||
<h3 className='mb-1 font-[500] text-[var(--landing-text)] text-lg leading-tight'>
|
||||
{p.title}
|
||||
</h3>
|
||||
<p className='mb-3 line-clamp-3 flex-1 text-[var(--landing-text-muted)] text-sm'>
|
||||
{p.description}
|
||||
</p>
|
||||
<div className='flex items-center gap-2'>
|
||||
<div className='-space-x-1.5 flex'>
|
||||
{(p.authors && p.authors.length > 0 ? p.authors : [p.author])
|
||||
.slice(0, 3)
|
||||
.map((author, idx) => (
|
||||
<Avatar key={idx} className='size-4 border border-[#1C1C1C]'>
|
||||
<Avatar key={idx} className='size-4 border border-[var(--landing-text)]'>
|
||||
<AvatarImage src={author?.avatarUrl} alt={author?.name} />
|
||||
<AvatarFallback className='border border-[#1C1C1C] bg-[#2A2A2A] text-[#999] text-[10px]'>
|
||||
<AvatarFallback className='border border-[var(--landing-text)] bg-[var(--landing-bg-elevated)] text-[var(--landing-text-muted)] text-micro'>
|
||||
{author?.name.slice(0, 2)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
))}
|
||||
</div>
|
||||
<span className='text-[#999] text-xs'>
|
||||
<span className='text-[var(--landing-text-muted)] text-xs'>
|
||||
{(p.authors && p.authors.length > 0 ? p.authors : [p.author])
|
||||
.slice(0, 2)
|
||||
.map((a) => a?.name)
|
||||
|
||||
@@ -5,12 +5,12 @@ const SKELETON_TAG_COUNT = 12
|
||||
export default function TagsLoading() {
|
||||
return (
|
||||
<main className='mx-auto max-w-[900px] px-6 py-10 sm:px-8 md:px-12'>
|
||||
<Skeleton className='mb-6 h-[32px] w-[200px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='mb-6 h-[32px] w-[200px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='flex flex-wrap gap-3'>
|
||||
{Array.from({ length: SKELETON_TAG_COUNT }).map((_, i) => (
|
||||
<Skeleton
|
||||
key={i}
|
||||
className='h-[30px] rounded-full bg-[#2A2A2A]'
|
||||
className='h-[30px] rounded-full bg-[var(--landing-bg-elevated)]'
|
||||
style={{ width: `${60 + (i % 4) * 24}px` }}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -10,11 +10,13 @@ export default async function TagsIndex() {
|
||||
const tags = await getAllTags()
|
||||
return (
|
||||
<main className='mx-auto max-w-[900px] px-6 py-10 sm:px-8 md:px-12'>
|
||||
<h1 className='mb-6 font-[500] text-[#ECECEC] text-[32px] leading-tight'>Browse by tag</h1>
|
||||
<h1 className='mb-6 font-[500] text-[32px] text-[var(--landing-text)] leading-tight'>
|
||||
Browse by tag
|
||||
</h1>
|
||||
<div className='flex flex-wrap gap-3'>
|
||||
<Link
|
||||
href='/blog'
|
||||
className='rounded-full border border-[#3d3d3d] px-3 py-1 text-[#ECECEC] text-sm transition-colors hover:bg-[#2A2A2A]'
|
||||
className='rounded-full border border-[var(--landing-border-strong)] px-3 py-1 text-[var(--landing-text)] text-sm transition-colors hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
All
|
||||
</Link>
|
||||
@@ -22,7 +24,7 @@ export default async function TagsIndex() {
|
||||
<Link
|
||||
key={t.tag}
|
||||
href={`/blog?tag=${encodeURIComponent(t.tag)}`}
|
||||
className='rounded-full border border-[#3d3d3d] px-3 py-1 text-[#ECECEC] text-sm transition-colors hover:bg-[#2A2A2A]'
|
||||
className='rounded-full border border-[var(--landing-border-strong)] px-3 py-1 text-[var(--landing-text)] text-sm transition-colors hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
{t.tag} ({t.count})
|
||||
</Link>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { HIPAABadgeIcon } from '@/components/icons'
|
||||
|
||||
export default function ComplianceBadges() {
|
||||
return (
|
||||
<div className='mt-[6px] flex items-center gap-[12px]'>
|
||||
<div className='mt-1.5 flex items-center gap-3'>
|
||||
{/* SOC2 badge */}
|
||||
<Link
|
||||
href='https://app.vanta.com/sim.ai/trust/v35ia0jil4l7dteqjgaktn'
|
||||
|
||||
@@ -2,12 +2,12 @@ import { DiscordIcon, GithubIcon, LinkedInIcon, xIcon as XIcon } from '@/compone
|
||||
|
||||
export default function SocialLinks() {
|
||||
return (
|
||||
<div className='flex items-center gap-[12px]'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<a
|
||||
href='https://discord.gg/Hr4UWYEcTT'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='flex items-center text-[16px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='flex items-center text-md text-muted-foreground transition-colors hover:text-foreground'
|
||||
aria-label='Discord'
|
||||
>
|
||||
<DiscordIcon className='h-[20px] w-[20px]' aria-hidden='true' />
|
||||
@@ -16,7 +16,7 @@ export default function SocialLinks() {
|
||||
href='https://x.com/simdotai'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='flex items-center text-[16px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='flex items-center text-md text-muted-foreground transition-colors hover:text-foreground'
|
||||
aria-label='X (Twitter)'
|
||||
>
|
||||
<XIcon className='h-[18px] w-[18px]' aria-hidden='true' />
|
||||
@@ -25,7 +25,7 @@ export default function SocialLinks() {
|
||||
href='https://www.linkedin.com/company/simstudioai/'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='flex items-center text-[16px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='flex items-center text-md text-muted-foreground transition-colors hover:text-foreground'
|
||||
aria-label='LinkedIn'
|
||||
>
|
||||
<LinkedInIcon className='h-[18px] w-[18px]' aria-hidden='true' />
|
||||
@@ -34,7 +34,7 @@ export default function SocialLinks() {
|
||||
href='https://github.com/simstudioai/sim'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='flex items-center text-[16px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='flex items-center text-md text-muted-foreground transition-colors hover:text-foreground'
|
||||
aria-label='GitHub'
|
||||
>
|
||||
<GithubIcon className='h-[20px] w-[20px]' aria-hidden='true' />
|
||||
|
||||
@@ -36,8 +36,8 @@ export function StatusDotIcon({ status, className, ...props }: StatusDotIconProp
|
||||
|
||||
const STATUS_COLORS: Record<StatusType, string> = {
|
||||
operational: 'text-[#10B981] hover:text-[#059669]',
|
||||
degraded: 'text-[#F59E0B] hover:text-[#D97706]',
|
||||
outage: 'text-[#EF4444] hover:text-[#DC2626]',
|
||||
degraded: 'text-[var(--caution)] hover:text-[#D97706]',
|
||||
outage: 'text-[var(--text-error)] hover:text-[var(--error)]',
|
||||
maintenance: 'text-[#3B82F6] hover:text-[#2563EB]',
|
||||
loading: 'text-muted-foreground hover:text-foreground',
|
||||
error: 'text-muted-foreground hover:text-foreground',
|
||||
@@ -59,7 +59,7 @@ export default function StatusIndicator() {
|
||||
href={statusUrl}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className={`flex min-w-[165px] items-center gap-[6px] whitespace-nowrap text-[12px] transition-colors ${STATUS_COLORS[status]}`}
|
||||
className={`flex min-w-[165px] items-center gap-1.5 whitespace-nowrap text-caption transition-colors ${STATUS_COLORS[status]}`}
|
||||
aria-label={`System status: ${message}`}
|
||||
>
|
||||
<StatusDotIcon status={status} className='h-[6px] w-[6px]' aria-hidden='true' />
|
||||
|
||||
@@ -17,13 +17,13 @@ export default function Footer({ fullWidth = false }: FooterProps) {
|
||||
<div
|
||||
className={
|
||||
fullWidth
|
||||
? 'px-4 pt-[40px] pb-[40px] sm:px-4 sm:pt-[34px] sm:pb-[340px]'
|
||||
: 'px-4 pt-[40px] pb-[40px] sm:px-[50px] sm:pt-[34px] sm:pb-[340px]'
|
||||
? 'px-4 pt-10 pb-10 sm:px-4 sm:pt-[34px] sm:pb-[340px]'
|
||||
: 'px-4 pt-10 pb-10 sm:px-[50px] sm:pt-[34px] sm:pb-[340px]'
|
||||
}
|
||||
>
|
||||
<div className={`flex gap-[80px] ${fullWidth ? 'justify-center' : ''}`}>
|
||||
<div className={`flex gap-20 ${fullWidth ? 'justify-center' : ''}`}>
|
||||
{/* Logo and social links */}
|
||||
<div className='flex flex-col gap-[24px]'>
|
||||
<div className='flex flex-col gap-6'>
|
||||
<Logo />
|
||||
<SocialLinks />
|
||||
<ComplianceBadges />
|
||||
@@ -32,19 +32,19 @@ export default function Footer({ fullWidth = false }: FooterProps) {
|
||||
|
||||
{/* Links section */}
|
||||
<div>
|
||||
<h2 className='mb-[16px] font-medium text-[14px] text-foreground'>More Sim</h2>
|
||||
<div className='flex flex-col gap-[12px]'>
|
||||
<h2 className='mb-4 font-medium text-foreground text-sm'>More Sim</h2>
|
||||
<div className='flex flex-col gap-3'>
|
||||
<Link
|
||||
href='https://docs.sim.ai'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
Docs
|
||||
</Link>
|
||||
<Link
|
||||
href='#pricing'
|
||||
className='text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
Pricing
|
||||
</Link>
|
||||
@@ -52,19 +52,19 @@ export default function Footer({ fullWidth = false }: FooterProps) {
|
||||
href='https://form.typeform.com/to/jqCO12pF'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
Enterprise
|
||||
</Link>
|
||||
<Link
|
||||
href='/blog'
|
||||
className='text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
Blog
|
||||
</Link>
|
||||
<Link
|
||||
href='/changelog'
|
||||
className='text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
Changelog
|
||||
</Link>
|
||||
@@ -72,7 +72,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
|
||||
href='https://status.sim.ai'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
Status
|
||||
</Link>
|
||||
@@ -80,7 +80,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
|
||||
href='https://jobs.ashbyhq.com/sim'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
Careers
|
||||
</a>
|
||||
@@ -88,7 +88,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
|
||||
href='/privacy'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
Privacy Policy
|
||||
</Link>
|
||||
@@ -96,7 +96,7 @@ export default function Footer({ fullWidth = false }: FooterProps) {
|
||||
href='/terms'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
Terms of Service
|
||||
</Link>
|
||||
@@ -105,15 +105,15 @@ export default function Footer({ fullWidth = false }: FooterProps) {
|
||||
|
||||
{/* Blocks section */}
|
||||
<div className='hidden sm:block'>
|
||||
<h2 className='mb-[16px] font-medium text-[14px] text-foreground'>Blocks</h2>
|
||||
<div className='flex flex-col gap-[12px]'>
|
||||
<h2 className='mb-4 font-medium text-foreground text-sm'>Blocks</h2>
|
||||
<div className='flex flex-col gap-3'>
|
||||
{FOOTER_BLOCKS.map((block) => (
|
||||
<Link
|
||||
key={block}
|
||||
href={`https://docs.sim.ai/blocks/${block.toLowerCase().replaceAll(' ', '-')}`}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
{block}
|
||||
</Link>
|
||||
@@ -123,24 +123,24 @@ export default function Footer({ fullWidth = false }: FooterProps) {
|
||||
|
||||
{/* Tools section - split into columns */}
|
||||
<div className='hidden sm:block'>
|
||||
<h2 className='mb-[16px] font-medium text-[14px] text-foreground'>Tools</h2>
|
||||
<div className='flex gap-[80px]'>
|
||||
<h2 className='mb-4 font-medium text-foreground text-sm'>Tools</h2>
|
||||
<div className='flex gap-20'>
|
||||
{/* First column */}
|
||||
<div className='flex flex-col gap-[12px]'>
|
||||
<div className='flex flex-col gap-3'>
|
||||
{FOOTER_TOOLS.slice(0, Math.ceil(FOOTER_TOOLS.length / 4)).map((tool) => (
|
||||
<Link
|
||||
key={tool}
|
||||
href={`https://docs.sim.ai/tools/${tool.toLowerCase().replace(/\s+/g, '_')}`}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='whitespace-nowrap text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='whitespace-nowrap text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
{tool}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
{/* Second column */}
|
||||
<div className='flex flex-col gap-[12px]'>
|
||||
<div className='flex flex-col gap-3'>
|
||||
{FOOTER_TOOLS.slice(
|
||||
Math.ceil(FOOTER_TOOLS.length / 4),
|
||||
Math.ceil((FOOTER_TOOLS.length * 2) / 4)
|
||||
@@ -150,14 +150,14 @@ export default function Footer({ fullWidth = false }: FooterProps) {
|
||||
href={`https://docs.sim.ai/tools/${tool.toLowerCase().replace(/\s+/g, '_')}`}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='whitespace-nowrap text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='whitespace-nowrap text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
{tool}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
{/* Third column */}
|
||||
<div className='flex flex-col gap-[12px]'>
|
||||
<div className='flex flex-col gap-3'>
|
||||
{FOOTER_TOOLS.slice(
|
||||
Math.ceil((FOOTER_TOOLS.length * 2) / 4),
|
||||
Math.ceil((FOOTER_TOOLS.length * 3) / 4)
|
||||
@@ -167,21 +167,21 @@ export default function Footer({ fullWidth = false }: FooterProps) {
|
||||
href={`https://docs.sim.ai/tools/${tool.toLowerCase().replace(/\s+/g, '_')}`}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='whitespace-nowrap text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='whitespace-nowrap text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
{tool}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
{/* Fourth column */}
|
||||
<div className='flex flex-col gap-[12px]'>
|
||||
<div className='flex flex-col gap-3'>
|
||||
{FOOTER_TOOLS.slice(Math.ceil((FOOTER_TOOLS.length * 3) / 4)).map((tool) => (
|
||||
<Link
|
||||
key={tool}
|
||||
href={`https://docs.sim.ai/tools/${tool.toLowerCase().replace(/\s+/g, '_')}`}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='whitespace-nowrap text-[14px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='whitespace-nowrap text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
{tool}
|
||||
</Link>
|
||||
|
||||
@@ -27,8 +27,8 @@ export function IconButton({
|
||||
onMouseEnter={onMouseEnter}
|
||||
className={`flex items-center justify-center rounded-xl border p-2 outline-none transition-all duration-300 ${
|
||||
isAutoHovered
|
||||
? 'border-[#E5E5E5] shadow-[0_2px_4px_0_rgba(0,0,0,0.08)]'
|
||||
: 'border-transparent hover:border-[#E5E5E5] hover:shadow-[0_2px_4px_0_rgba(0,0,0,0.08)]'
|
||||
? 'border-[#454545] shadow-subtle'
|
||||
: 'border-transparent hover:border-[#454545] hover:shadow-subtle'
|
||||
}`}
|
||||
style={style}
|
||||
>
|
||||
|
||||
+6
-6
@@ -44,20 +44,20 @@ export const LandingBlock = React.memo(function LandingBlock({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`z-10 flex w-[250px] flex-col rounded-[8px] border border-[#E5E5E5] bg-white ${className ?? ''}`}
|
||||
className={`z-10 flex w-[250px] flex-col rounded-lg border border-[var(--landing-border-light)] bg-white ${className ?? ''}`}
|
||||
>
|
||||
{/* Header - matches workflow-block.tsx header styling */}
|
||||
<div
|
||||
className={`flex items-center justify-between p-[8px] ${hasContentBelowHeader ? 'border-[#E5E5E5] border-b' : ''}`}
|
||||
className={`flex items-center justify-between p-2 ${hasContentBelowHeader ? 'border-[var(--landing-border-light)] border-b' : ''}`}
|
||||
>
|
||||
<div className='flex min-w-0 flex-1 items-center gap-[10px]'>
|
||||
<div className='flex min-w-0 flex-1 items-center gap-2.5'>
|
||||
<div
|
||||
className='flex h-[24px] w-[24px] flex-shrink-0 items-center justify-center rounded-[6px]'
|
||||
className='flex h-[24px] w-[24px] flex-shrink-0 items-center justify-center rounded-md'
|
||||
style={{ background: color as string }}
|
||||
>
|
||||
{icon}
|
||||
</div>
|
||||
<span className='truncate font-medium text-[#171717] text-[16px]' title={name}>
|
||||
<span className='truncate font-medium text-[#171717] text-md' title={name}>
|
||||
{name}
|
||||
</span>
|
||||
</div>
|
||||
@@ -65,7 +65,7 @@ export const LandingBlock = React.memo(function LandingBlock({
|
||||
|
||||
{/* Content - SubBlock Rows matching workflow-block.tsx */}
|
||||
{hasContentBelowHeader && (
|
||||
<div className='flex flex-col gap-[8px] p-[8px]'>
|
||||
<div className='flex flex-col gap-2 p-2'>
|
||||
{tags.map((tag) => (
|
||||
<SubBlockRow key={tag.label} icon={tag.icon} label={tag.label} />
|
||||
))}
|
||||
|
||||
+3
-6
@@ -30,15 +30,12 @@ export const SubBlockRow = React.memo(function SubBlockRow({ label, value }: Sub
|
||||
: [label, value]
|
||||
|
||||
return (
|
||||
<div className='flex items-center gap-[8px]'>
|
||||
<span className='min-w-0 truncate text-[#888888] text-[14px] capitalize' title={title}>
|
||||
<div className='flex items-center gap-2'>
|
||||
<span className='min-w-0 truncate text-[#888888] text-sm capitalize' title={title}>
|
||||
{title}
|
||||
</span>
|
||||
{displayValue && (
|
||||
<span
|
||||
className='flex-1 truncate text-right text-[#171717] text-[14px]'
|
||||
title={displayValue}
|
||||
>
|
||||
<span className='flex-1 truncate text-right text-[#171717] text-sm' title={displayValue}>
|
||||
{displayValue}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -128,7 +128,7 @@ export function LandingCanvas({
|
||||
{/* <button
|
||||
type='button'
|
||||
aria-label='Use template'
|
||||
className='absolute top-[24px] left-[50px] z-20 inline-flex items-center justify-center rounded-[10px] border border-[#343434] bg-gradient-to-b from-[#060606] to-[#323232] px-3 py-1.5 text-sm text-white shadow-[inset_0_1.25px_2.5px_0_#9B77FF] transition-all duration-200'
|
||||
className='absolute top-6 left-[50px] z-20 inline-flex items-center justify-center rounded-[10px] border border-[#343434] bg-gradient-to-b from-[#060606] to-[#323232] px-3 py-1.5 text-sm text-white shadow-brand-inset transition-all duration-200'
|
||||
onClick={() => {
|
||||
// Template usage logic will be implemented here
|
||||
}}
|
||||
|
||||
@@ -363,20 +363,20 @@ export default function Hero() {
|
||||
return (
|
||||
<section
|
||||
id='hero'
|
||||
className='flex w-full flex-col items-center justify-center pt-[36px] sm:pt-[80px]'
|
||||
className='flex w-full flex-col items-center justify-center pt-9 sm:pt-20'
|
||||
aria-labelledby='hero-heading'
|
||||
>
|
||||
<h1
|
||||
id='hero-heading'
|
||||
className='px-4 text-center font-medium text-[36px] leading-none tracking-tight sm:px-0 sm:text-[74px]'
|
||||
className='text-balance px-4 text-center font-medium text-[36px] leading-none tracking-tight sm:px-0 sm:text-[74px]'
|
||||
>
|
||||
Workflows for LLMs
|
||||
</h1>
|
||||
<p className='px-4 pt-[6px] text-center text-[18px] opacity-70 sm:px-0 sm:pt-[10px] sm:text-[22px]'>
|
||||
<p className='px-4 pt-1.5 text-center text-lg opacity-70 sm:px-0 sm:pt-2.5 sm:text-[22px]'>
|
||||
Build and deploy AI agent workflows
|
||||
</p>
|
||||
<div
|
||||
className='flex items-center justify-center gap-[2px] pt-[18px] sm:pt-[32px]'
|
||||
className='flex items-center justify-center gap-0.5 pt-4.5 sm:pt-8'
|
||||
onMouseEnter={handleIconContainerMouseEnter}
|
||||
onMouseLeave={handleIconContainerMouseLeave}
|
||||
>
|
||||
@@ -397,7 +397,7 @@ export default function Hero() {
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div className='flex w-full items-center justify-center px-4 pt-[8px] sm:px-8 sm:pt-[12px] md:px-[50px]'>
|
||||
<div className='flex w-full items-center justify-center px-4 pt-2 sm:px-8 sm:pt-3 md:px-[50px]'>
|
||||
<div className='relative w-full sm:w-[640px]'>
|
||||
<label htmlFor='agent-description' className='sr-only'>
|
||||
Describe the AI agent you want to build
|
||||
@@ -424,7 +424,7 @@ export default function Hero() {
|
||||
key={isEmpty ? 'empty' : 'filled'}
|
||||
type='button'
|
||||
aria-label='Submit description'
|
||||
className='absolute right-2.5 bottom-4 flex h-[30px] w-[30px] items-center justify-center transition-all duration-200 sm:right-[11px] sm:bottom-[16px] sm:h-[34px] sm:w-[34px]'
|
||||
className='absolute right-2.5 bottom-4 flex h-[30px] w-[30px] items-center justify-center transition-all duration-200 sm:right-[11px] sm:bottom-4 sm:h-[34px] sm:w-[34px]'
|
||||
disabled={isEmpty}
|
||||
onClick={handleSubmit}
|
||||
style={{
|
||||
|
||||
@@ -93,7 +93,7 @@ function TickerRow({ direction, offset, showOdd, icons }: TickerRowProps) {
|
||||
return (
|
||||
<div className='relative h-[88px] w-full overflow-hidden'>
|
||||
<div
|
||||
className={`absolute flex items-center gap-[16px] ${
|
||||
className={`absolute flex items-center gap-4 ${
|
||||
direction === 'left' ? 'animate-slide-left' : 'animate-slide-right'
|
||||
}`}
|
||||
style={{
|
||||
@@ -121,21 +121,21 @@ export default function Integrations() {
|
||||
return (
|
||||
<section
|
||||
id='integrations'
|
||||
className='flex flex-col pt-[40px] pb-[27px] sm:pt-[24px]'
|
||||
className='flex flex-col pt-10 pb-[27px] sm:pt-6'
|
||||
aria-labelledby='integrations-heading'
|
||||
>
|
||||
<h2
|
||||
id='integrations-heading'
|
||||
className='mb-[4px] px-4 font-medium text-[28px] text-foreground tracking-tight sm:pl-[50px]'
|
||||
className='mb-1 px-4 font-medium text-[28px] text-foreground tracking-tight sm:pl-[50px]'
|
||||
>
|
||||
Integrations
|
||||
</h2>
|
||||
<p className='mb-[24px] px-4 text-[#515151] text-[18px] sm:pl-[50px]'>
|
||||
<p className='mb-6 px-4 text-[#515151] text-lg sm:pl-[50px]'>
|
||||
Immediately connect to 100+ models and apps
|
||||
</p>
|
||||
|
||||
{/* Sliding tickers */}
|
||||
<div className='flex w-full flex-col sm:px-[12px]'>
|
||||
<div className='flex w-full flex-col sm:px-3'>
|
||||
<TickerRow direction='left' offset={0} showOdd={false} icons={modelProviderIcons} />
|
||||
<TickerRow direction='right' offset={0.5} showOdd={true} icons={communicationIcons} />
|
||||
<TickerRow direction='left' offset={1} showOdd={false} icons={dataStorageIcons} />
|
||||
|
||||
@@ -159,7 +159,7 @@ function PricingCard({
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ul className='mb-[2px] space-y-3'>
|
||||
<ul className='mb-0.5 space-y-3'>
|
||||
{tier.features.map((feature, idx) => (
|
||||
<li key={idx} className='flex items-start gap-2'>
|
||||
<feature.icon
|
||||
@@ -182,7 +182,7 @@ function PricingCard({
|
||||
onClick={handleCtaClick}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#E8E8E8] bg-gradient-to-b from-[#F8F8F8] to-white px-3 py-[6px] font-medium text-[#6F3DFA] text-[14px] shadow-[inset_0_2px_4px_0_rgba(255,255,255,0.9)] transition-all'
|
||||
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#E8E8E8] bg-gradient-to-b from-[#F8F8F8] to-white px-3 py-1.5 font-medium text-[#6F3DFA] text-[14px] shadow-[inset_0_2px_4px_0_rgba(255,255,255,0.9)] transition-all'
|
||||
>
|
||||
<span className='flex items-center gap-1'>
|
||||
{tier.ctaText}
|
||||
@@ -200,7 +200,7 @@ function PricingCard({
|
||||
onClick={handleCtaClick}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#343434] bg-gradient-to-b from-[#060606] to-[#323232] px-3 py-[6px] font-medium text-[14px] text-white shadow-[inset_0_1.25px_2.5px_0_#9B77FF] transition-all'
|
||||
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#343434] bg-gradient-to-b from-[#060606] to-[#323232] px-3 py-1.5 font-medium text-[14px] text-white shadow-[inset_0_1.25px_2.5px_0_#9B77FF] transition-all'
|
||||
>
|
||||
<span className='flex items-center gap-1'>
|
||||
{tier.ctaText}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { PricingGrid } from '@/app/(landing)/components/landing-pricing/componen
|
||||
*/
|
||||
export default function LandingPricing() {
|
||||
return (
|
||||
<section id='pricing' className='px-4 pt-[23px] sm:px-0 sm:pt-[4px]' aria-label='Pricing plans'>
|
||||
<section id='pricing' className='px-4 pt-[23px] sm:px-0 sm:pt-1' aria-label='Pricing plans'>
|
||||
<h2 className='sr-only'>Pricing Plans</h2>
|
||||
<div className='relative mx-auto w-full max-w-[1289px]'>
|
||||
<PricingGrid />
|
||||
|
||||
@@ -79,12 +79,12 @@ export default function LandingTemplates() {
|
||||
return (
|
||||
<section
|
||||
id='templates'
|
||||
className='flex flex-col px-4 pt-[40px] sm:px-[50px] sm:pt-[34px]'
|
||||
className='flex flex-col px-4 pt-10 sm:px-[50px] sm:pt-[34px]'
|
||||
aria-labelledby='templates-heading'
|
||||
>
|
||||
<h2
|
||||
id='templates-heading'
|
||||
className='mb-[16px] font-medium text-[28px] text-foreground tracking-tight sm:mb-[24px]'
|
||||
className='mb-4 font-medium text-[28px] text-foreground tracking-tight sm:mb-6'
|
||||
>
|
||||
Templates
|
||||
</h2>
|
||||
|
||||
@@ -12,16 +12,16 @@ export default async function LegalLayout({ title, children }: LegalLayoutProps)
|
||||
const blogPosts = await getNavBlogPosts()
|
||||
|
||||
return (
|
||||
<main className='min-h-screen bg-[#1C1C1C] font-[430] font-season text-[#ECECEC]'>
|
||||
<main className='min-h-screen bg-[var(--landing-bg)] font-[430] font-season text-[var(--landing-text)]'>
|
||||
<header>
|
||||
<Navbar blogPosts={blogPosts} />
|
||||
</header>
|
||||
|
||||
<div className='mx-auto max-w-[800px] px-6 pt-[60px] pb-[80px] sm:px-12'>
|
||||
<h1 className='mb-12 text-center font-[500] text-4xl text-[#ECECEC] md:text-5xl'>
|
||||
<div className='mx-auto max-w-[800px] px-6 pt-[60px] pb-20 sm:px-12'>
|
||||
<h1 className='mb-12 text-balance text-center font-[500] text-4xl text-[var(--landing-text)] md:text-5xl'>
|
||||
{title}
|
||||
</h1>
|
||||
<div className='space-y-8 text-[#999] text-[15px] leading-[1.7] [&_h2]:mt-12 [&_h2]:mb-6 [&_h2]:text-[#ECECEC] [&_h3]:mt-8 [&_h3]:mb-4 [&_h3]:text-[#ECECEC] [&_li]:text-[#999] [&_strong]:text-[#ECECEC]'>
|
||||
<div className='space-y-8 text-[var(--landing-text-muted)] text-base leading-[1.7] [&_h2]:mt-12 [&_h2]:mb-6 [&_h2]:text-[var(--landing-text)] [&_h3]:mt-8 [&_h3]:mb-4 [&_h3]:text-[var(--landing-text)] [&_li]:text-[var(--landing-text-muted)] [&_strong]:text-[var(--landing-text)]'>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -71,7 +71,7 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
|
||||
href='https://docs.sim.ai'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[16px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-md text-muted-foreground transition-colors hover:text-foreground'
|
||||
prefetch={false}
|
||||
>
|
||||
Docs
|
||||
@@ -80,7 +80,7 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
|
||||
<li>
|
||||
<Link
|
||||
href={useHomeLinks ? '/?home#pricing' : '/#pricing'}
|
||||
className='text-[16px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-md text-muted-foreground transition-colors hover:text-foreground'
|
||||
scroll={true}
|
||||
>
|
||||
Pricing
|
||||
@@ -89,7 +89,7 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
|
||||
<li>
|
||||
<button
|
||||
onClick={handleEnterpriseClick}
|
||||
className='text-[16px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-md text-muted-foreground transition-colors hover:text-foreground'
|
||||
type='button'
|
||||
aria-label='Contact for Enterprise pricing'
|
||||
>
|
||||
@@ -101,7 +101,7 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
|
||||
href='https://jobs.ashbyhq.com/sim'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[16px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='text-md text-muted-foreground transition-colors hover:text-foreground'
|
||||
>
|
||||
Careers
|
||||
</a>
|
||||
@@ -111,7 +111,7 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
|
||||
href='https://github.com/simstudioai/sim'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='flex items-center gap-2 text-[16px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='flex items-center gap-2 text-md text-muted-foreground transition-colors hover:text-foreground'
|
||||
aria-label={`GitHub repository - ${githubStars} stars`}
|
||||
>
|
||||
<GithubIcon className='h-[16px] w-[16px]' aria-hidden='true' />
|
||||
@@ -125,8 +125,8 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
|
||||
<nav
|
||||
aria-label='Primary navigation'
|
||||
className={`flex w-full items-center justify-between px-4 ${
|
||||
variant === 'auth' ? 'pt-[20px] sm:pt-[16.5px]' : 'pt-[12px] sm:pt-[8.5px]'
|
||||
} pb-[21px] sm:px-8 md:px-[44px]`}
|
||||
variant === 'auth' ? 'pt-5 sm:pt-[16.5px]' : 'pt-3 sm:pt-[8.5px]'
|
||||
} pb-[21px] sm:px-8 md:px-11`}
|
||||
itemScope
|
||||
itemType='https://schema.org/SiteNavigationElement'
|
||||
>
|
||||
@@ -161,7 +161,7 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
|
||||
</Link>
|
||||
{/* Desktop Navigation Links - only show on landing and if hosted */}
|
||||
{variant === 'landing' && isHosted && (
|
||||
<ul className='hidden items-center justify-center gap-[20px] pt-[4px] md:flex'>
|
||||
<ul className='hidden items-center justify-center gap-5 pt-1 md:flex'>
|
||||
<NavLinks />
|
||||
</ul>
|
||||
)}
|
||||
@@ -170,14 +170,14 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
|
||||
{/* Auth Buttons - show only when hosted, regardless of variant */}
|
||||
{!hideAuthButtons && isHosted && (
|
||||
<div
|
||||
className={`flex items-center justify-center gap-[16px] pt-[1.5px]${isSessionPending ? ' invisible' : ''}`}
|
||||
className={`flex items-center justify-center gap-4 pt-[1.5px]${isSessionPending ? ' invisible' : ''}`}
|
||||
>
|
||||
{isAuthenticated ? (
|
||||
<Link
|
||||
href='/workspace'
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
className={`${buttonClass} group inline-flex items-center justify-center gap-2 rounded-[10px] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white transition-all`}
|
||||
className={`${buttonClass} group inline-flex items-center justify-center gap-2 rounded-[10px] py-1.5 pr-2.5 pl-3 text-[15px] text-white transition-all`}
|
||||
aria-label='Go to app'
|
||||
>
|
||||
<span className='flex items-center gap-1'>
|
||||
@@ -216,7 +216,7 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na
|
||||
href='/signup'
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
className={`${buttonClass} group inline-flex items-center justify-center gap-2 rounded-[10px] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white transition-all`}
|
||||
className={`${buttonClass} group inline-flex items-center justify-center gap-2 rounded-[10px] py-1.5 pr-2.5 pl-3 text-[15px] text-white transition-all`}
|
||||
aria-label='Get started with Sim - Sign up for free'
|
||||
prefetch={true}
|
||||
>
|
||||
|
||||
@@ -125,7 +125,7 @@ export default function Testimonials() {
|
||||
className='flex hidden h-[150px] items-center sm:block'
|
||||
aria-label='Social proof testimonials'
|
||||
>
|
||||
<div className='relative mx-auto h-full w-full max-w-[1289px] pl-[2px]'>
|
||||
<div className='relative mx-auto h-full w-full max-w-[1289px] pl-0.5'>
|
||||
<div
|
||||
className='relative h-full w-full overflow-hidden'
|
||||
onMouseEnter={() => setIsPaused(true)}
|
||||
@@ -146,7 +146,7 @@ export default function Testimonials() {
|
||||
<div key={`${absoluteIndex}`} className='flex h-full w-1/4 flex-shrink-0'>
|
||||
{/* Tweet container */}
|
||||
<div
|
||||
className='group flex h-full w-full cursor-pointer flex-col px-[12px] py-[12px] transition-all duration-100 hover:bg-[#0A0A0A] sm:px-[14px]'
|
||||
className='group flex h-full w-full cursor-pointer flex-col px-3 py-3 transition-all duration-100 hover:bg-[#0A0A0A] sm:px-3.5'
|
||||
onClick={() => window.open(tweet.tweetUrl, '_blank', 'noopener,noreferrer')}
|
||||
>
|
||||
{/* Top section with profile info */}
|
||||
@@ -179,7 +179,7 @@ export default function Testimonials() {
|
||||
</div>
|
||||
|
||||
{/* Tweet content below with padding */}
|
||||
<p className='mt-2 line-clamp-4 font-[380] text-[#0A0A0A] text-[13px] leading-[1.3] transition-colors duration-300 group-hover:text-white'>
|
||||
<p className='mt-2 line-clamp-4 font-[380] text-[#0A0A0A] text-small leading-[1.3] transition-colors duration-300 group-hover:text-white'>
|
||||
{tweet.text}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@ export function IntegrationFAQ({ faqs }: IntegrationFAQProps) {
|
||||
const [openIndex, setOpenIndex] = useState<number | null>(0)
|
||||
|
||||
return (
|
||||
<div className='divide-y divide-[#2A2A2A]'>
|
||||
<div className='divide-y divide-[var(--landing-border)]'>
|
||||
{faqs.map(({ question, answer }, index) => {
|
||||
const isOpen = openIndex === index
|
||||
return (
|
||||
@@ -27,7 +27,9 @@ export function IntegrationFAQ({ faqs }: IntegrationFAQProps) {
|
||||
<span
|
||||
className={cn(
|
||||
'font-[500] text-[15px] leading-snug transition-colors',
|
||||
isOpen ? 'text-[#ECECEC]' : 'text-[#999] hover:text-[#ECECEC]'
|
||||
isOpen
|
||||
? 'text-[var(--landing-text)]'
|
||||
: 'text-[var(--landing-text-muted)] hover:text-[var(--landing-text)]'
|
||||
)}
|
||||
>
|
||||
{question}
|
||||
@@ -43,7 +45,9 @@ export function IntegrationFAQ({ faqs }: IntegrationFAQProps) {
|
||||
|
||||
{isOpen && (
|
||||
<div className='pb-5'>
|
||||
<p className='text-[#999] text-[14px] leading-[1.75]'>{answer}</p>
|
||||
<p className='text-[14px] text-[var(--landing-text-muted)] leading-[1.75]'>
|
||||
{answer}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,7 @@ export function TemplateCardButton({ prompt, children }: TemplateCardButtonProps
|
||||
<button
|
||||
type='button'
|
||||
onClick={handleClick}
|
||||
className='group flex w-full flex-col items-start rounded-lg border border-[#2A2A2A] bg-[#242424] p-5 text-left transition-colors hover:border-[#3d3d3d] hover:bg-[#2A2A2A]'
|
||||
className='group flex w-full flex-col items-start rounded-lg border border-[var(--landing-border)] bg-[var(--landing-bg-card)] p-5 text-left transition-colors hover:border-[var(--landing-border-strong)] hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
|
||||
@@ -307,15 +307,18 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
aria-label='Breadcrumb'
|
||||
className='mb-10 flex items-center gap-2 text-[#555] text-[13px]'
|
||||
>
|
||||
<Link href='/' className='transition-colors hover:text-[#999]'>
|
||||
<Link href='/' className='transition-colors hover:text-[var(--landing-text-muted)]'>
|
||||
Home
|
||||
</Link>
|
||||
<span aria-hidden='true'>/</span>
|
||||
<Link href='/integrations' className='transition-colors hover:text-[#999]'>
|
||||
<Link
|
||||
href='/integrations'
|
||||
className='transition-colors hover:text-[var(--landing-text-muted)]'
|
||||
>
|
||||
Integrations
|
||||
</Link>
|
||||
<span aria-hidden='true'>/</span>
|
||||
<span className='text-[#999]'>{name}</span>
|
||||
<span className='text-[var(--landing-text-muted)]'>{name}</span>
|
||||
</nav>
|
||||
|
||||
{/* Hero */}
|
||||
@@ -334,20 +337,22 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
<p className='mb-0.5 text-[#555] text-[12px]'>Integration</p>
|
||||
<h1
|
||||
id='integration-heading'
|
||||
className='font-[500] text-[#ECECEC] text-[36px] leading-tight sm:text-[44px]'
|
||||
className='font-[500] text-[36px] text-[var(--landing-text)] leading-tight sm:text-[44px]'
|
||||
>
|
||||
{name}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className='mb-8 max-w-[700px] text-[#999] text-[17px] leading-[1.7]'>{description}</p>
|
||||
<p className='mb-8 max-w-[700px] text-[17px] text-[var(--landing-text-muted)] leading-[1.7]'>
|
||||
{description}
|
||||
</p>
|
||||
|
||||
{/* CTAs */}
|
||||
<div className='flex flex-wrap gap-[8px]'>
|
||||
<div className='flex flex-wrap gap-2'>
|
||||
<a
|
||||
href='https://sim.ai'
|
||||
className='inline-flex h-[32px] items-center rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] px-[10px] font-[430] font-season text-[#1C1C1C] text-[14px] transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
className='inline-flex h-[32px] items-center rounded-[5px] border border-[var(--white)] bg-[var(--white)] px-2.5 font-[430] font-season text-[14px] text-[var(--landing-text-dark)] transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
>
|
||||
Start building free
|
||||
</a>
|
||||
@@ -355,7 +360,7 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
href={docsUrl}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='inline-flex h-[32px] items-center gap-[6px] rounded-[5px] border border-[#3d3d3d] px-[10px] font-[430] font-season text-[#ECECEC] text-[14px] transition-colors hover:bg-[#2A2A2A]'
|
||||
className='inline-flex h-[32px] items-center gap-1.5 rounded-[5px] border border-[var(--landing-border-strong)] px-2.5 font-[430] font-season text-[14px] text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
View docs
|
||||
<svg
|
||||
@@ -381,16 +386,24 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
{/* Overview */}
|
||||
{longDescription && (
|
||||
<section aria-labelledby='overview-heading'>
|
||||
<h2 id='overview-heading' className='mb-4 font-[500] text-[#ECECEC] text-[20px]'>
|
||||
<h2
|
||||
id='overview-heading'
|
||||
className='mb-4 font-[500] text-[20px] text-[var(--landing-text)]'
|
||||
>
|
||||
Overview
|
||||
</h2>
|
||||
<p className='text-[#999] text-[15px] leading-[1.8]'>{longDescription}</p>
|
||||
<p className='text-[15px] text-[var(--landing-text-muted)] leading-[1.8]'>
|
||||
{longDescription}
|
||||
</p>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* How to automate — targets "how to connect X" queries */}
|
||||
<section aria-labelledby='how-it-works-heading'>
|
||||
<h2 id='how-it-works-heading' className='mb-6 font-[500] text-[#ECECEC] text-[20px]'>
|
||||
<h2
|
||||
id='how-it-works-heading'
|
||||
className='mb-6 font-[500] text-[20px] text-[var(--landing-text)]'
|
||||
>
|
||||
How to automate {name} with Sim
|
||||
</h2>
|
||||
<ol className='space-y-4' aria-label='Steps to set up automation'>
|
||||
@@ -418,14 +431,18 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
].map(({ step, title, body }) => (
|
||||
<li key={step} className='flex gap-4'>
|
||||
<span
|
||||
className='mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-full border border-[#3d3d3d] font-[500] text-[#555] text-[11px]'
|
||||
className='mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-full border border-[var(--landing-border-strong)] font-[500] text-[#555] text-[11px]'
|
||||
aria-hidden='true'
|
||||
>
|
||||
{step}
|
||||
</span>
|
||||
<div>
|
||||
<h3 className='mb-1 font-[500] text-[#ECECEC] text-[15px]'>{title}</h3>
|
||||
<p className='text-[#999] text-[14px] leading-relaxed'>{body}</p>
|
||||
<h3 className='mb-1 font-[500] text-[15px] text-[var(--landing-text)]'>
|
||||
{title}
|
||||
</h3>
|
||||
<p className='text-[14px] text-[var(--landing-text-muted)] leading-relaxed'>
|
||||
{body}
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
@@ -435,10 +452,13 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
{/* Triggers */}
|
||||
{triggers.length > 0 && (
|
||||
<section aria-labelledby='triggers-heading'>
|
||||
<h2 id='triggers-heading' className='mb-2 font-[500] text-[#ECECEC] text-[20px]'>
|
||||
<h2
|
||||
id='triggers-heading'
|
||||
className='mb-2 font-[500] text-[20px] text-[var(--landing-text)]'
|
||||
>
|
||||
Real-time triggers
|
||||
</h2>
|
||||
<p className='mb-4 text-[#999] text-[14px] leading-relaxed'>
|
||||
<p className='mb-4 text-[14px] text-[var(--landing-text-muted)] leading-relaxed'>
|
||||
Connect a {name} webhook to Sim and your workflow fires the instant an event
|
||||
happens — no polling, no delay. Sim receives the full event payload and makes
|
||||
every field available as a variable inside your workflow.
|
||||
@@ -452,10 +472,10 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
{triggers.map((trigger) => (
|
||||
<li
|
||||
key={trigger.id}
|
||||
className='rounded-lg border border-[#2A2A2A] bg-[#242424] p-4'
|
||||
className='rounded-lg border border-[var(--landing-border)] bg-[var(--landing-bg-card)] p-4'
|
||||
>
|
||||
<div className='mb-2 flex items-center gap-2'>
|
||||
<span className='inline-flex items-center gap-1 rounded-[4px] bg-[#2A2A2A] px-1.5 py-0.5 font-[500] text-[#ECECEC] text-[11px]'>
|
||||
<span className='inline-flex items-center gap-1 rounded-[4px] bg-[var(--landing-bg-elevated)] px-1.5 py-0.5 font-[500] text-[11px] text-[var(--landing-text)]'>
|
||||
<svg
|
||||
aria-hidden='true'
|
||||
className='h-2.5 w-2.5'
|
||||
@@ -469,9 +489,11 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
Event
|
||||
</span>
|
||||
</div>
|
||||
<p className='font-[500] text-[#ECECEC] text-[13px]'>{trigger.name}</p>
|
||||
<p className='font-[500] text-[13px] text-[var(--landing-text)]'>
|
||||
{trigger.name}
|
||||
</p>
|
||||
{trigger.description && (
|
||||
<p className='mt-1 text-[#999] text-[12px] leading-relaxed'>
|
||||
<p className='mt-1 text-[12px] text-[var(--landing-text-muted)] leading-relaxed'>
|
||||
{trigger.description}
|
||||
</p>
|
||||
)}
|
||||
@@ -484,10 +506,13 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
{/* Workflow templates */}
|
||||
{matchingTemplates.length > 0 && (
|
||||
<section aria-labelledby='templates-heading'>
|
||||
<h2 id='templates-heading' className='mb-2 font-[500] text-[#ECECEC] text-[20px]'>
|
||||
<h2
|
||||
id='templates-heading'
|
||||
className='mb-2 font-[500] text-[20px] text-[var(--landing-text)]'
|
||||
>
|
||||
Workflow templates
|
||||
</h2>
|
||||
<p className='mb-6 text-[#999] text-[14px]'>
|
||||
<p className='mb-6 text-[14px] text-[var(--landing-text-muted)]'>
|
||||
Ready-to-use workflows featuring {name}. Click any to build it instantly.
|
||||
</p>
|
||||
<ul
|
||||
@@ -522,7 +547,7 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
→
|
||||
</span>
|
||||
)}
|
||||
<span className='inline-flex items-center gap-1 rounded-[3px] bg-[#2A2A2A] px-1.5 py-0.5 font-[500] text-[#ECECEC]'>
|
||||
<span className='inline-flex items-center gap-1 rounded-[3px] bg-[var(--landing-bg-elevated)] px-1.5 py-0.5 font-[500] text-[var(--landing-text)]'>
|
||||
<IntegrationIcon
|
||||
bgColor={int?.bgColor ?? '#6B7280'}
|
||||
name={intName}
|
||||
@@ -539,11 +564,11 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
})}
|
||||
</div>
|
||||
|
||||
<p className='mb-1 font-[500] text-[#ECECEC] text-[14px]'>
|
||||
<p className='mb-1 font-[500] text-[14px] text-[var(--landing-text)]'>
|
||||
{template.title}
|
||||
</p>
|
||||
|
||||
<p className='mt-3 text-[#555] text-[13px] transition-colors group-hover:text-[#999]'>
|
||||
<p className='mt-3 text-[#555] text-[13px] transition-colors group-hover:text-[var(--landing-text-muted)]'>
|
||||
Try this workflow →
|
||||
</p>
|
||||
</TemplateCardButton>
|
||||
@@ -557,10 +582,13 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
{/* Tools */}
|
||||
{operations.length > 0 && (
|
||||
<section aria-labelledby='tools-heading'>
|
||||
<h2 id='tools-heading' className='mb-2 font-[500] text-[#ECECEC] text-[20px]'>
|
||||
<h2
|
||||
id='tools-heading'
|
||||
className='mb-2 font-[500] text-[20px] text-[var(--landing-text)]'
|
||||
>
|
||||
Supported tools
|
||||
</h2>
|
||||
<p className='mb-6 text-[#999] text-[14px]'>
|
||||
<p className='mb-6 text-[14px] text-[var(--landing-text-muted)]'>
|
||||
{operations.length} {name} tool{operations.length === 1 ? '' : 's'} available in
|
||||
Sim
|
||||
</p>
|
||||
@@ -571,9 +599,9 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
{operations.map((op) => (
|
||||
<li
|
||||
key={op.name}
|
||||
className='rounded-[6px] border border-[#2A2A2A] bg-[#242424] px-3.5 py-3'
|
||||
className='rounded-[6px] border border-[var(--landing-border)] bg-[var(--landing-bg-card)] px-3.5 py-3'
|
||||
>
|
||||
<p className='font-[500] text-[#ECECEC] text-[13px]'>{op.name}</p>
|
||||
<p className='font-[500] text-[13px] text-[var(--landing-text)]'>{op.name}</p>
|
||||
{op.description && (
|
||||
<p className='mt-0.5 text-[#555] text-[12px] leading-relaxed'>
|
||||
{op.description}
|
||||
@@ -587,7 +615,10 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
|
||||
{/* FAQ */}
|
||||
<section aria-labelledby='faq-heading'>
|
||||
<h2 id='faq-heading' className='mb-8 font-[500] text-[#ECECEC] text-[20px]'>
|
||||
<h2
|
||||
id='faq-heading'
|
||||
className='mb-8 font-[500] text-[20px] text-[var(--landing-text)]'
|
||||
>
|
||||
Frequently asked questions
|
||||
</h2>
|
||||
<IntegrationFAQ faqs={faqs} />
|
||||
@@ -597,24 +628,24 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
{/* Sidebar */}
|
||||
<aside className='space-y-5' aria-label='Integration details'>
|
||||
{/* Quick details */}
|
||||
<div className='rounded-lg border border-[#2A2A2A] bg-[#242424] p-5'>
|
||||
<h3 className='mb-4 font-[500] text-[#ECECEC] text-[14px]'>Details</h3>
|
||||
<div className='rounded-lg border border-[var(--landing-border)] bg-[var(--landing-bg-card)] p-5'>
|
||||
<h3 className='mb-4 font-[500] text-[14px] text-[var(--landing-text)]'>Details</h3>
|
||||
<dl className='space-y-3 text-[13px]'>
|
||||
{operations.length > 0 && (
|
||||
<div>
|
||||
<dt className='text-[#555]'>Tools</dt>
|
||||
<dd className='text-[#ECECEC]'>{operations.length} supported</dd>
|
||||
<dd className='text-[var(--landing-text)]'>{operations.length} supported</dd>
|
||||
</div>
|
||||
)}
|
||||
{triggers.length > 0 && (
|
||||
<div>
|
||||
<dt className='text-[#555]'>Triggers</dt>
|
||||
<dd className='text-[#ECECEC]'>{triggers.length} available</dd>
|
||||
<dd className='text-[var(--landing-text)]'>{triggers.length} available</dd>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<dt className='text-[#555]'>Auth</dt>
|
||||
<dd className='text-[#ECECEC]'>
|
||||
<dd className='text-[var(--landing-text)]'>
|
||||
{authType === 'oauth'
|
||||
? 'One-click OAuth'
|
||||
: authType === 'api-key'
|
||||
@@ -624,13 +655,13 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
</div>
|
||||
<div>
|
||||
<dt className='text-[#555]'>Pricing</dt>
|
||||
<dd className='text-[#ECECEC]'>Free to start</dd>
|
||||
<dd className='text-[var(--landing-text)]'>Free to start</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<div className='mt-5 flex flex-col gap-2'>
|
||||
<a
|
||||
href='https://sim.ai'
|
||||
className='flex h-[32px] w-full items-center justify-center rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] font-[430] font-season text-[#1C1C1C] text-[13px] transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
className='flex h-[32px] w-full items-center justify-center rounded-[5px] border border-[var(--white)] bg-[var(--white)] font-[430] font-season text-[13px] text-[var(--landing-text-dark)] transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
>
|
||||
Get started free
|
||||
</a>
|
||||
@@ -638,7 +669,7 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
href={docsUrl}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='flex h-[32px] w-full items-center justify-center gap-1.5 rounded-[5px] border border-[#3d3d3d] font-[430] font-season text-[#ECECEC] text-[13px] transition-colors hover:bg-[#2A2A2A]'
|
||||
className='flex h-[32px] w-full items-center justify-center gap-1.5 rounded-[5px] border border-[var(--landing-border-strong)] font-[430] font-season text-[13px] text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
View docs
|
||||
<svg
|
||||
@@ -658,10 +689,10 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
</div>
|
||||
|
||||
{/* Related integrations — internal linking for SEO */}
|
||||
<div className='rounded-lg border border-[#2A2A2A] bg-[#242424] p-5'>
|
||||
<div className='rounded-lg border border-[var(--landing-border)] bg-[var(--landing-bg-card)] p-5'>
|
||||
{relatedIntegrations.length > 0 && (
|
||||
<>
|
||||
<h3 className='mb-4 font-[500] text-[#ECECEC] text-[14px]'>
|
||||
<h3 className='mb-4 font-[500] text-[14px] text-[var(--landing-text)]'>
|
||||
Related integrations
|
||||
</h3>
|
||||
<ul className='space-y-2'>
|
||||
@@ -669,7 +700,7 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
<li key={rel.slug}>
|
||||
<Link
|
||||
href={`/integrations/${rel.slug}`}
|
||||
className='flex items-center gap-2.5 rounded-[6px] p-1.5 text-[#999] text-[13px] transition-colors hover:bg-[#2A2A2A] hover:text-[#ECECEC]'
|
||||
className='flex items-center gap-2.5 rounded-[6px] p-1.5 text-[13px] text-[var(--landing-text-muted)] transition-colors hover:bg-[var(--landing-bg-elevated)] hover:text-[var(--landing-text)]'
|
||||
>
|
||||
<IntegrationIcon
|
||||
bgColor={rel.bgColor}
|
||||
@@ -690,7 +721,7 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
)}
|
||||
<Link
|
||||
href='/integrations'
|
||||
className={`block text-[#555] text-[12px] transition-colors hover:text-[#999]${relatedIntegrations.length > 0 ? ' mt-4' : ''}`}
|
||||
className={`block text-[#555] text-[12px] transition-colors hover:text-[var(--landing-text-muted)]${relatedIntegrations.length > 0 ? ' mt-4' : ''}`}
|
||||
>
|
||||
All integrations →
|
||||
</Link>
|
||||
@@ -701,7 +732,7 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
{/* Bottom CTA */}
|
||||
<section
|
||||
aria-labelledby='cta-heading'
|
||||
className='mt-20 rounded-xl border border-[#2A2A2A] bg-[#242424] p-8 text-center sm:p-12'
|
||||
className='mt-20 rounded-xl border border-[var(--landing-border)] bg-[var(--landing-bg-card)] p-8 text-center sm:p-12'
|
||||
>
|
||||
{/* Logo pair: Sim × Integration */}
|
||||
<div className='mx-auto mb-6 flex items-center justify-center gap-3'>
|
||||
@@ -716,11 +747,11 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
<div className='flex items-center gap-2'>
|
||||
<span className='h-px w-5 bg-[#3d3d3d]' aria-hidden='true' />
|
||||
<span
|
||||
className='flex h-7 w-7 items-center justify-center rounded-full border border-[#3d3d3d]'
|
||||
className='flex h-7 w-7 items-center justify-center rounded-full border border-[var(--landing-border-strong)]'
|
||||
aria-hidden='true'
|
||||
>
|
||||
<svg
|
||||
className='h-3.5 w-3.5 text-[#666]'
|
||||
className='h-3.5 w-3.5 text-[var(--landing-text-secondary)]'
|
||||
viewBox='0 0 24 24'
|
||||
fill='none'
|
||||
stroke='currentColor'
|
||||
@@ -745,17 +776,17 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
|
||||
</div>
|
||||
<h2
|
||||
id='cta-heading'
|
||||
className='mb-3 font-[500] text-[#ECECEC] text-[28px] sm:text-[34px]'
|
||||
className='mb-3 font-[500] text-[28px] text-[var(--landing-text)] sm:text-[34px]'
|
||||
>
|
||||
Start automating {name} today
|
||||
</h2>
|
||||
<p className='mx-auto mb-8 max-w-[480px] text-[#999] text-[16px] leading-relaxed'>
|
||||
<p className='mx-auto mb-8 max-w-[480px] text-[16px] text-[var(--landing-text-muted)] leading-relaxed'>
|
||||
Build your first AI workflow with {name} in minutes. Connect to every tool your team
|
||||
uses. Free to start — no credit card required.
|
||||
</p>
|
||||
<a
|
||||
href='https://sim.ai'
|
||||
className='inline-flex h-[32px] items-center rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] px-[10px] font-[430] font-season text-[#1C1C1C] text-[14px] transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
className='inline-flex h-[32px] items-center rounded-[5px] border border-[var(--white)] bg-[var(--white)] px-2.5 font-[430] font-season text-[14px] text-[var(--landing-text-dark)] transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
>
|
||||
Build for free →
|
||||
</a>
|
||||
|
||||
@@ -15,7 +15,7 @@ export function IntegrationCard({ integration, IconComponent }: IntegrationCardP
|
||||
return (
|
||||
<Link
|
||||
href={`/integrations/${slug}`}
|
||||
className='group flex flex-col rounded-lg border border-[#2A2A2A] bg-[#242424] p-4 transition-colors hover:border-[#3d3d3d] hover:bg-[#2A2A2A]'
|
||||
className='group flex flex-col rounded-lg border border-[var(--landing-border)] bg-[var(--landing-bg-card)] p-4 transition-colors hover:border-[var(--landing-border-strong)] hover:bg-[var(--landing-bg-elevated)]'
|
||||
aria-label={`${name} integration`}
|
||||
>
|
||||
<IntegrationIcon
|
||||
@@ -27,26 +27,28 @@ export function IntegrationCard({ integration, IconComponent }: IntegrationCardP
|
||||
/>
|
||||
|
||||
{/* Name */}
|
||||
<h3 className='mb-1 font-[500] text-[#ECECEC] text-[14px] leading-snug'>{name}</h3>
|
||||
<h3 className='mb-1 font-[500] text-[14px] text-[var(--landing-text)] leading-snug'>
|
||||
{name}
|
||||
</h3>
|
||||
|
||||
{/* Description — clamped to 2 lines */}
|
||||
<p className='mb-3 line-clamp-2 flex-1 text-[#999] text-[12px] leading-relaxed'>
|
||||
<p className='mb-3 line-clamp-2 flex-1 text-[12px] text-[var(--landing-text-muted)] leading-relaxed'>
|
||||
{description}
|
||||
</p>
|
||||
|
||||
{/* Footer row */}
|
||||
<div className='flex flex-wrap items-center gap-1.5'>
|
||||
{operationCount > 0 && (
|
||||
<Badge className='border-0 bg-[#333] text-[#999] text-[11px]'>
|
||||
<Badge className='border-0 bg-[#333] text-[11px] text-[var(--landing-text-muted)]'>
|
||||
{operationCount} {operationCount === 1 ? 'tool' : 'tools'}
|
||||
</Badge>
|
||||
)}
|
||||
{triggerCount > 0 && (
|
||||
<Badge className='border-0 bg-[#333] text-[#999] text-[11px]'>
|
||||
<Badge className='border-0 bg-[#333] text-[11px] text-[var(--landing-text-muted)]'>
|
||||
{triggerCount} {triggerCount === 1 ? 'trigger' : 'triggers'}
|
||||
</Badge>
|
||||
)}
|
||||
<span className='ml-auto text-[#555] text-[12px] transition-colors group-hover:text-[#999]'>
|
||||
<span className='ml-auto text-[#555] text-[12px] transition-colors group-hover:text-[var(--landing-text-muted)]'>
|
||||
Learn more →
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -105,8 +105,8 @@ export function IntegrationGrid({ integrations }: IntegrationGridProps) {
|
||||
onClick={() => setActiveCategory(null)}
|
||||
className={`rounded-md border px-3 py-1 text-[12px] transition-colors ${
|
||||
activeCategory === null
|
||||
? 'border-[#555] bg-[#333] text-[#ECECEC]'
|
||||
: 'border-[#2A2A2A] bg-transparent text-[#999] hover:border-[#3d3d3d] hover:text-[#ECECEC]'
|
||||
? 'border-[#555] bg-[#333] text-[var(--landing-text)]'
|
||||
: 'border-[var(--landing-border)] bg-transparent text-[var(--landing-text-muted)] hover:border-[var(--landing-border-strong)] hover:text-[var(--landing-text)]'
|
||||
}`}
|
||||
>
|
||||
All
|
||||
@@ -118,8 +118,8 @@ export function IntegrationGrid({ integrations }: IntegrationGridProps) {
|
||||
onClick={() => setActiveCategory(activeCategory === cat ? null : cat)}
|
||||
className={`rounded-md border px-3 py-1 text-[12px] transition-colors ${
|
||||
activeCategory === cat
|
||||
? 'border-[#555] bg-[#333] text-[#ECECEC]'
|
||||
: 'border-[#2A2A2A] bg-transparent text-[#999] hover:border-[#3d3d3d] hover:text-[#ECECEC]'
|
||||
? 'border-[#555] bg-[#333] text-[var(--landing-text)]'
|
||||
: 'border-[var(--landing-border)] bg-transparent text-[var(--landing-text-muted)] hover:border-[var(--landing-border-strong)] hover:text-[var(--landing-text)]'
|
||||
}`}
|
||||
>
|
||||
{CATEGORY_LABELS[cat] || cat}
|
||||
|
||||
@@ -74,7 +74,7 @@ export function RequestIntegrationModal() {
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setOpen(true)}
|
||||
className='inline-flex h-[32px] shrink-0 items-center gap-[6px] rounded-[5px] border border-[#3d3d3d] px-[10px] font-[430] font-season text-[#ECECEC] text-[14px] transition-colors hover:bg-[#2A2A2A]'
|
||||
className='inline-flex h-[32px] shrink-0 items-center gap-1.5 rounded-[5px] border border-[var(--landing-border-strong)] px-2.5 font-[430] font-season text-[14px] text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
Request an integration
|
||||
</button>
|
||||
@@ -88,7 +88,7 @@ export function RequestIntegrationModal() {
|
||||
<div className='flex flex-col items-center gap-3 py-6 text-center'>
|
||||
<div className='flex h-10 w-10 items-center justify-center rounded-full bg-[#33C482]/10'>
|
||||
<svg
|
||||
className='h-5 w-5 text-[#33C482]'
|
||||
className='h-5 w-5 text-[var(--brand-accent)]'
|
||||
viewBox='0 0 24 24'
|
||||
fill='none'
|
||||
stroke='currentColor'
|
||||
@@ -99,7 +99,7 @@ export function RequestIntegrationModal() {
|
||||
<polyline points='20 6 9 17 4 12' />
|
||||
</svg>
|
||||
</div>
|
||||
<p className='text-[14px] text-[var(--text-primary)]'>
|
||||
<p className='text-[14px] text-[var(--landing-text)]'>
|
||||
Request submitted — we'll follow up at{' '}
|
||||
<span className='font-medium'>{email}</span>.
|
||||
</p>
|
||||
@@ -108,8 +108,8 @@ export function RequestIntegrationModal() {
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className='flex min-h-0 flex-1 flex-col'>
|
||||
<ModalBody>
|
||||
<div className='space-y-[12px]'>
|
||||
<div className='flex flex-col gap-[4px]'>
|
||||
<div className='space-y-3'>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Label htmlFor='integration-name'>Integration name</Label>
|
||||
<Input
|
||||
id='integration-name'
|
||||
@@ -122,7 +122,7 @@ export function RequestIntegrationModal() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-[4px]'>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Label htmlFor='requester-email'>Your email</Label>
|
||||
<Input
|
||||
id='requester-email'
|
||||
@@ -135,7 +135,7 @@ export function RequestIntegrationModal() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-[4px]'>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Label htmlFor='use-case'>
|
||||
Use case <span className='text-[var(--text-tertiary)]'>(optional)</span>
|
||||
</Label>
|
||||
|
||||
@@ -28,7 +28,7 @@ export default async function IntegrationsLayout({ children }: { children: React
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='dark flex min-h-screen flex-col bg-[#1C1C1C] font-[430] font-season text-[#ECECEC]'>
|
||||
<div className='dark flex min-h-screen flex-col bg-[var(--landing-bg)] font-[430] font-season text-[var(--landing-text)]'>
|
||||
<script
|
||||
type='application/ld+json'
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(orgJsonLd) }}
|
||||
|
||||
@@ -105,11 +105,11 @@ export default function IntegrationsPage() {
|
||||
<section aria-labelledby='integrations-heading' className='mb-16'>
|
||||
<h1
|
||||
id='integrations-heading'
|
||||
className='mb-4 font-[500] text-[#ECECEC] text-[40px] leading-tight sm:text-[56px]'
|
||||
className='mb-4 text-balance font-[500] text-[40px] text-[var(--landing-text)] leading-tight sm:text-[56px]'
|
||||
>
|
||||
Integrations
|
||||
</h1>
|
||||
<p className='max-w-[640px] text-[#999] text-[18px] leading-relaxed'>
|
||||
<p className='max-w-[640px] text-[18px] text-[var(--landing-text-muted)] leading-relaxed'>
|
||||
Connect every tool your team uses. Build AI-powered workflows that automate tasks across{' '}
|
||||
{TOP_NAMES.slice(0, 4).map((name, i, arr) => {
|
||||
const integration = allIntegrations.find((int) => int.name === name)
|
||||
@@ -136,16 +136,19 @@ export default function IntegrationsPage() {
|
||||
|
||||
{/* Searchable grid — client component */}
|
||||
<section aria-labelledby='all-integrations-heading'>
|
||||
<h2 id='all-integrations-heading' className='mb-8 font-[500] text-[#ECECEC] text-[24px]'>
|
||||
<h2
|
||||
id='all-integrations-heading'
|
||||
className='mb-8 font-[500] text-[24px] text-[var(--landing-text)]'
|
||||
>
|
||||
All Integrations
|
||||
</h2>
|
||||
<IntegrationGrid integrations={allIntegrations} />
|
||||
</section>
|
||||
|
||||
{/* Integration request */}
|
||||
<div className='mt-16 flex flex-col items-start gap-3 border-[#2A2A2A] border-t pt-10 sm:flex-row sm:items-center sm:justify-between'>
|
||||
<div className='mt-16 flex flex-col items-start gap-3 border-[var(--landing-border)] border-t pt-10 sm:flex-row sm:items-center sm:justify-between'>
|
||||
<div>
|
||||
<p className='font-[500] text-[#ECECEC] text-[15px]'>
|
||||
<p className='font-[500] text-[15px] text-[var(--landing-text)]'>
|
||||
Don't see the integration you need?
|
||||
</p>
|
||||
<p className='mt-0.5 text-[#555] text-[13px]'>
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Metadata } from 'next'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL('https://sim.ai'),
|
||||
manifest: '/manifest.json',
|
||||
manifest: '/manifest.webmanifest',
|
||||
icons: {
|
||||
icon: [{ url: '/icon.svg', type: 'image/svg+xml', sizes: 'any' }],
|
||||
apple: '/favicon/apple-touch-icon.png',
|
||||
|
||||
@@ -2,55 +2,55 @@ import { Skeleton } from '@/components/emcn'
|
||||
|
||||
export default function PrivacyLoading() {
|
||||
return (
|
||||
<main className='min-h-screen bg-[#1C1C1C] text-[#ECECEC]'>
|
||||
<div className='flex h-[52px] items-center border-[#2A2A2A] border-b px-6'>
|
||||
<Skeleton className='h-[22px] w-[60px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='ml-auto flex items-center gap-[12px]'>
|
||||
<Skeleton className='h-[30px] w-[64px] rounded-[5px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[30px] w-[80px] rounded-[5px] bg-[#2A2A2A]' />
|
||||
<main className='min-h-screen bg-[var(--landing-bg)] text-[var(--landing-text)]'>
|
||||
<div className='flex h-[52px] items-center border-[var(--landing-border)] border-b px-6'>
|
||||
<Skeleton className='h-[22px] w-[60px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='ml-auto flex items-center gap-3'>
|
||||
<Skeleton className='h-[30px] w-[64px] rounded-[5px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[30px] w-[80px] rounded-[5px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
<div className='mx-auto max-w-[800px] px-6 pt-[60px] pb-[80px] sm:px-12'>
|
||||
<Skeleton className='mx-auto h-[48px] w-[280px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mx-auto max-w-[800px] px-6 pt-[60px] pb-20 sm:px-12'>
|
||||
<Skeleton className='mx-auto h-[48px] w-[280px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='mt-12 space-y-8'>
|
||||
<div className='space-y-[10px]'>
|
||||
<Skeleton className='h-[15px] w-[180px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[95%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[88%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='space-y-2.5'>
|
||||
<Skeleton className='h-[15px] w-[180px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[95%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[88%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
<div className='mt-12 space-y-[10px]'>
|
||||
<Skeleton className='h-[28px] w-[320px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mt-4 space-y-[10px]'>
|
||||
<Skeleton className='h-[20px] w-[160px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[92%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[85%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mt-12 space-y-2.5'>
|
||||
<Skeleton className='h-[28px] w-[320px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='mt-4 space-y-2.5'>
|
||||
<Skeleton className='h-[20px] w-[160px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[92%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[85%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-12 space-y-[10px]'>
|
||||
<Skeleton className='h-[28px] w-[260px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[90%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mt-4 space-y-[8px] pl-6'>
|
||||
<Skeleton className='h-[15px] w-[70%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[60%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[75%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[65%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mt-12 space-y-2.5'>
|
||||
<Skeleton className='h-[28px] w-[260px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[90%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='mt-4 space-y-2 pl-6'>
|
||||
<Skeleton className='h-[15px] w-[70%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[60%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[75%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[65%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-12 space-y-[10px]'>
|
||||
<Skeleton className='h-[28px] w-[300px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[95%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[88%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mt-12 space-y-2.5'>
|
||||
<Skeleton className='h-[28px] w-[300px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[95%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[88%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
<div className='mt-12 space-y-[10px]'>
|
||||
<Skeleton className='h-[28px] w-[220px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[93%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[80%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mt-12 space-y-2.5'>
|
||||
<Skeleton className='h-[28px] w-[220px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[93%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[80%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import type { Metadata } from 'next'
|
||||
import Link from 'next/link'
|
||||
import { getEnv } from '@/lib/core/config/env'
|
||||
import { ExternalRedirect, LegalLayout } from '@/app/(landing)/components'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Privacy Policy',
|
||||
description:
|
||||
'Learn how Sim collects, uses, and protects your personal data, including data obtained from Google APIs.',
|
||||
alternates: { canonical: '/privacy' },
|
||||
}
|
||||
|
||||
export default function PrivacyPolicy() {
|
||||
return (
|
||||
<LegalLayout title='Privacy Policy'>
|
||||
@@ -574,7 +582,7 @@ export default function PrivacyPolicy() {
|
||||
Please note that we may ask you to verify your identity before responding to such
|
||||
requests.
|
||||
</p>
|
||||
<p className='mb-4 border-[#3d3d3d] border-l-4 bg-[#2A2A2A] p-3 text-[#ECECEC]'>
|
||||
<p className='mb-4 border-[var(--landing-border-strong)] border-l-4 bg-[var(--landing-bg-elevated)] p-3 text-[var(--landing-text)]'>
|
||||
You have the right to complain to a Data Protection Authority about our collection and use
|
||||
of your Personal Information. For more information, please contact your local data
|
||||
protection authority in the European Economic Area (EEA).
|
||||
@@ -596,7 +604,10 @@ export default function PrivacyPolicy() {
|
||||
sharing practices (such as analytics or advertising services) may be considered a "sale"
|
||||
or "share" under CCPA/CPRA. You have the right to opt-out of such data sharing. To
|
||||
exercise this right, contact us at{' '}
|
||||
<Link href='mailto:privacy@sim.ai' className='text-[#ECECEC] underline hover:text-white'>
|
||||
<Link
|
||||
href='mailto:privacy@sim.ai'
|
||||
className='text-[var(--landing-text)] underline hover:text-white'
|
||||
>
|
||||
privacy@sim.ai
|
||||
</Link>
|
||||
.
|
||||
@@ -682,7 +693,10 @@ export default function PrivacyPolicy() {
|
||||
Sim interacts with are not covered by this policy and should be reported directly to the
|
||||
solution vendor in accordance with their disclosure policy (if any). Before beginning your
|
||||
inquiry, email us at{' '}
|
||||
<Link href='mailto:security@sim.ai' className='text-[#ECECEC] underline hover:text-white'>
|
||||
<Link
|
||||
href='mailto:security@sim.ai'
|
||||
className='text-[var(--landing-text)] underline hover:text-white'
|
||||
>
|
||||
security@sim.ai
|
||||
</Link>{' '}
|
||||
if you're unsure whether a system or endpoint is in scope.
|
||||
@@ -701,7 +715,10 @@ export default function PrivacyPolicy() {
|
||||
<h3 className='mb-2 font-medium text-xl'>Reporting a vulnerability</h3>
|
||||
<p className='mb-4'>
|
||||
To report any security flaws, send an email to{' '}
|
||||
<Link href='mailto:security@sim.ai' className='text-[#ECECEC] underline hover:text-white'>
|
||||
<Link
|
||||
href='mailto:security@sim.ai'
|
||||
className='text-[var(--landing-text)] underline hover:text-white'
|
||||
>
|
||||
security@sim.ai
|
||||
</Link>
|
||||
. The next business day, we'll acknowledge receipt of your vulnerability report and keep
|
||||
@@ -745,7 +762,7 @@ export default function PrivacyPolicy() {
|
||||
Email:{' '}
|
||||
<Link
|
||||
href='mailto:privacy@sim.ai'
|
||||
className='text-[#ECECEC] underline hover:text-white'
|
||||
className='text-[var(--landing-text)] underline hover:text-white'
|
||||
>
|
||||
privacy@sim.ai
|
||||
</Link>
|
||||
|
||||
@@ -2,48 +2,48 @@ import { Skeleton } from '@/components/emcn'
|
||||
|
||||
export default function TermsLoading() {
|
||||
return (
|
||||
<main className='min-h-screen bg-[#1C1C1C] text-[#ECECEC]'>
|
||||
<div className='flex h-[52px] items-center border-[#2A2A2A] border-b px-6'>
|
||||
<Skeleton className='h-[22px] w-[60px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='ml-auto flex items-center gap-[12px]'>
|
||||
<Skeleton className='h-[30px] w-[64px] rounded-[5px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[30px] w-[80px] rounded-[5px] bg-[#2A2A2A]' />
|
||||
<main className='min-h-screen bg-[var(--landing-bg)] text-[var(--landing-text)]'>
|
||||
<div className='flex h-[52px] items-center border-[var(--landing-border)] border-b px-6'>
|
||||
<Skeleton className='h-[22px] w-[60px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='ml-auto flex items-center gap-3'>
|
||||
<Skeleton className='h-[30px] w-[64px] rounded-[5px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[30px] w-[80px] rounded-[5px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
<div className='mx-auto max-w-[800px] px-6 pt-[60px] pb-[80px] sm:px-12'>
|
||||
<Skeleton className='mx-auto h-[48px] w-[320px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mx-auto max-w-[800px] px-6 pt-[60px] pb-20 sm:px-12'>
|
||||
<Skeleton className='mx-auto h-[48px] w-[320px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='mt-12 space-y-8'>
|
||||
<div className='space-y-[10px]'>
|
||||
<Skeleton className='h-[15px] w-[180px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[95%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[88%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='space-y-2.5'>
|
||||
<Skeleton className='h-[15px] w-[180px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[95%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[88%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
<div className='mt-12 space-y-[10px]'>
|
||||
<Skeleton className='h-[28px] w-[140px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[92%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[85%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mt-12 space-y-2.5'>
|
||||
<Skeleton className='h-[28px] w-[140px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[92%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[85%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
<div className='mt-12 space-y-[10px]'>
|
||||
<Skeleton className='h-[28px] w-[260px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[90%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[75%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mt-12 space-y-2.5'>
|
||||
<Skeleton className='h-[28px] w-[260px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[90%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[75%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
<div className='mt-12 space-y-[10px]'>
|
||||
<Skeleton className='h-[28px] w-[380px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[95%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[88%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mt-12 space-y-2.5'>
|
||||
<Skeleton className='h-[28px] w-[380px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[95%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[88%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
<div className='mt-12 space-y-[10px]'>
|
||||
<Skeleton className='h-[28px] w-[300px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[93%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[15px] w-[80%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='mt-12 space-y-2.5'>
|
||||
<Skeleton className='h-[28px] w-[300px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[93%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[15px] w-[80%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import type { Metadata } from 'next'
|
||||
import Link from 'next/link'
|
||||
import { getEnv } from '@/lib/core/config/env'
|
||||
import { ExternalRedirect, LegalLayout } from '@/app/(landing)/components'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Terms of Service',
|
||||
description:
|
||||
'Read the terms and conditions for using the Sim platform, including subscription plans, data ownership, and acceptable use.',
|
||||
alternates: { canonical: '/terms' },
|
||||
}
|
||||
|
||||
export default function TermsOfService() {
|
||||
return (
|
||||
<LegalLayout title='Terms of Service'>
|
||||
@@ -281,7 +289,7 @@ export default function TermsOfService() {
|
||||
Agreement. The arbitration will be conducted by JAMS, an established alternative dispute
|
||||
resolution provider.
|
||||
</p>
|
||||
<p className='mb-4 border-[#3d3d3d] border-l-4 bg-[#2A2A2A] p-3 text-[#ECECEC]'>
|
||||
<p className='mb-4 border-[var(--landing-border-strong)] border-l-4 bg-[var(--landing-bg-elevated)] p-3 text-[var(--landing-text)]'>
|
||||
YOU AND COMPANY AGREE THAT EACH OF US MAY BRING CLAIMS AGAINST THE OTHER ONLY ON AN
|
||||
INDIVIDUAL BASIS AND NOT ON A CLASS, REPRESENTATIVE, OR COLLECTIVE BASIS. ONLY INDIVIDUAL
|
||||
RELIEF IS AVAILABLE, AND DISPUTES OF MORE THAN ONE CUSTOMER OR USER CANNOT BE ARBITRATED
|
||||
@@ -290,7 +298,10 @@ export default function TermsOfService() {
|
||||
<p className='mb-4'>
|
||||
You have the right to opt out of the provisions of this Arbitration Agreement by sending a
|
||||
timely written notice of your decision to opt out to:{' '}
|
||||
<Link href='mailto:legal@sim.ai' className='text-[#ECECEC] underline hover:text-white'>
|
||||
<Link
|
||||
href='mailto:legal@sim.ai'
|
||||
className='text-[var(--landing-text)] underline hover:text-white'
|
||||
>
|
||||
legal@sim.ai{' '}
|
||||
</Link>
|
||||
within 30 days after first becoming subject to this Arbitration Agreement.
|
||||
@@ -339,7 +350,7 @@ export default function TermsOfService() {
|
||||
Our Copyright Agent can be reached at:{' '}
|
||||
<Link
|
||||
href='mailto:copyright@sim.ai'
|
||||
className='text-[#ECECEC] underline hover:text-white'
|
||||
className='text-[var(--landing-text)] underline hover:text-white'
|
||||
>
|
||||
copyright@sim.ai
|
||||
</Link>
|
||||
@@ -350,7 +361,10 @@ export default function TermsOfService() {
|
||||
<h2 className='mb-4 font-semibold text-2xl'>18. Contact Us</h2>
|
||||
<p>
|
||||
If you have any questions about these Terms, please contact us at:{' '}
|
||||
<Link href='mailto:legal@sim.ai' className='text-[#ECECEC] underline hover:text-white'>
|
||||
<Link
|
||||
href='mailto:legal@sim.ai'
|
||||
className='text-[var(--landing-text)] underline hover:text-white'
|
||||
>
|
||||
legal@sim.ai
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
+183
-147
@@ -15,6 +15,23 @@
|
||||
--toolbar-triggers-height: 300px; /* TOOLBAR_TRIGGERS_HEIGHT.DEFAULT */
|
||||
--editor-connections-height: 172px; /* EDITOR_CONNECTIONS_HEIGHT.DEFAULT */
|
||||
--terminal-height: 206px; /* TERMINAL_HEIGHT.DEFAULT */
|
||||
|
||||
/* z-index scale for layered UI
|
||||
Popover must be above modal so dropdowns inside modals render correctly */
|
||||
--z-dropdown: 100;
|
||||
--z-modal: 200;
|
||||
--z-popover: 300;
|
||||
--z-tooltip: 400;
|
||||
--z-toast: 500;
|
||||
|
||||
/* Shadow scale */
|
||||
--shadow-subtle: 0 2px 4px 0 rgba(0, 0, 0, 0.08);
|
||||
--shadow-medium: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
--shadow-overlay: 0 16px 48px rgba(0, 0, 0, 0.15);
|
||||
--shadow-kbd: 0 4px 0 0 rgba(48, 48, 48, 1);
|
||||
--shadow-kbd-sm: 0 2px 0 0 rgba(48, 48, 48, 1);
|
||||
--shadow-brand-inset: inset 0 1.25px 2.5px 0 #9b77ff;
|
||||
--shadow-card: 0 1px 3px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.workspace-root {
|
||||
@@ -194,10 +211,8 @@ html[data-sidebar-collapsed] .sidebar-container .sidebar-collapse-btn {
|
||||
--border-success: #e0e0e0;
|
||||
|
||||
/* Brand & state */
|
||||
--brand-400: #8e4cfb;
|
||||
--brand-secondary: #33b4ff;
|
||||
--brand-tertiary: #22c55e;
|
||||
--brand-tertiary-2: #33c482;
|
||||
--brand-accent: #33c482;
|
||||
--selection: #1a5cf6;
|
||||
--warning: #ea580c;
|
||||
|
||||
@@ -209,67 +224,50 @@ html[data-sidebar-collapsed] .sidebar-container .sidebar-collapse-btn {
|
||||
--font-weight-medium: 440;
|
||||
--font-weight-semibold: 500;
|
||||
|
||||
/* Extended palette */
|
||||
--c-0D0D0D: #0d0d0d;
|
||||
--c-1A1A1A: #1a1a1a;
|
||||
--c-1F1F1F: #1f1f1f;
|
||||
--c-2A2A2A: #2a2a2a;
|
||||
--c-383838: #383838;
|
||||
--c-414141: #414141;
|
||||
--c-442929: #442929;
|
||||
--c-491515: #491515;
|
||||
--c-575757: #575757;
|
||||
--c-686868: #686868;
|
||||
--c-707070: #707070;
|
||||
--c-727272: #727272;
|
||||
--c-737373: #737373;
|
||||
--c-808080: #808080;
|
||||
--c-858585: #858585;
|
||||
--c-868686: #868686;
|
||||
--c-8D8D8D: #8d8d8d;
|
||||
--c-939393: #939393;
|
||||
--c-A8A8A8: #a8a8a8;
|
||||
--c-B8B8B8: #b8b8b8;
|
||||
--c-C0C0C0: #c0c0c0;
|
||||
--c-CDCDCD: #cdcdcd;
|
||||
--c-D0D0D0: #d0d0d0;
|
||||
--c-D2D2D2: #d2d2d2;
|
||||
--c-E0E0E0: #e0e0e0;
|
||||
--c-E5E5E5: #e5e5e5;
|
||||
--c-E8E8E8: #e8e8e8;
|
||||
--c-EEEEEE: #eeeeee;
|
||||
--c-F0F0F0: #f0f0f0;
|
||||
--c-F4F4F4: #f4f4f4;
|
||||
--c-F5F5F5: #f5f5f5;
|
||||
/* Landing / marketing - text (static dark-section colors) */
|
||||
--landing-text: #ececec;
|
||||
--landing-text-muted: #999999;
|
||||
--landing-text-subtle: #f6f6f6;
|
||||
--landing-text-dark: #1c1c1c;
|
||||
--landing-text-secondary: #666666;
|
||||
--landing-text-body: #cdcdcd;
|
||||
--landing-text-icon: #939393;
|
||||
|
||||
/* Blues and cyans */
|
||||
--c-00B0B0: #00b0b0;
|
||||
--c-264F78: #264f78;
|
||||
--c-2F55FF: #2f55ff;
|
||||
--c-2FA1FF: #2fa1ff;
|
||||
--c-336699: #336699;
|
||||
--c-34B5FF: #34b5ff;
|
||||
--c-601EE0: #601ee0;
|
||||
--c-611F69: #611f69;
|
||||
--c-802FFF: #802fff;
|
||||
--c-8357FF: #8357ff;
|
||||
--c-8C10FF: #8c10ff;
|
||||
/* Landing / marketing - surfaces */
|
||||
--landing-bg: #1c1c1c;
|
||||
--landing-bg-elevated: #2a2a2a;
|
||||
--landing-bg-card: #232323;
|
||||
--landing-bg-section: #f6f6f6;
|
||||
--landing-bg-subtle: #fafafa;
|
||||
--landing-bg-surface: #1e1e1e;
|
||||
--landing-bg-hover: #f0f0f0;
|
||||
--landing-bg-skeleton: #e8e8e8;
|
||||
|
||||
/* Greens */
|
||||
--c-4CAF50: #22c55e;
|
||||
/* Landing / marketing - borders */
|
||||
--landing-border: #2a2a2a;
|
||||
--landing-border-light: #e5e5e5;
|
||||
--landing-border-strong: #3d3d3d;
|
||||
--landing-border-subtle: #d4d4d4;
|
||||
|
||||
/* Oranges / Ambers */
|
||||
--c-F59E0B: #f59e0b;
|
||||
--c-F97316: #ea580c;
|
||||
--c-FF972F: #f97316;
|
||||
/* Code editor (theme-aware) */
|
||||
--code-bg: #f5f5f5;
|
||||
--code-foreground: #1a1a1a;
|
||||
--code-line-number: #737373;
|
||||
|
||||
/* Reds */
|
||||
--c-DC2626: #dc2626;
|
||||
--c-F6D2D2: #fecaca;
|
||||
--c-F87171: #f87171;
|
||||
--c-FF402F: #ef4444;
|
||||
--c-B91C1C: #b91c1c;
|
||||
--c-883827: #7c2d12;
|
||||
/* Workspace: additional text */
|
||||
--text-placeholder: #8d8d8d;
|
||||
--text-success: #22c55e;
|
||||
|
||||
/* Status / semantic colors */
|
||||
--error: #dc2626;
|
||||
--error-muted: #fecaca;
|
||||
--error-emphasis: #b91c1c;
|
||||
--caution: #f59e0b;
|
||||
--success: #22c55e;
|
||||
|
||||
/* Brand extended */
|
||||
--brand-knowledge: #00b0b0;
|
||||
--selection-dark: #264f78;
|
||||
|
||||
/* Terminal status badges */
|
||||
--terminal-status-error-bg: #fef2f2;
|
||||
@@ -280,6 +278,49 @@ html[data-sidebar-collapsed] .sidebar-container .sidebar-collapse-btn {
|
||||
--terminal-status-warning-bg: #fefce8;
|
||||
--terminal-status-warning-border: #facc15;
|
||||
--terminal-status-warning-color: #a16207;
|
||||
|
||||
/* Badge semantic colors */
|
||||
--badge-success-bg: #bbf7d0;
|
||||
--badge-success-text: #15803d;
|
||||
--badge-error-bg: #fecaca;
|
||||
--badge-error-text: #dc2626;
|
||||
--badge-gray-bg: #e7e5e4;
|
||||
--badge-gray-text: #57534e;
|
||||
--badge-blue-bg: #bfdbfe;
|
||||
--badge-blue-text: #1d4ed8;
|
||||
--badge-blue-secondary-bg: #bae6fd;
|
||||
--badge-blue-secondary-text: #0369a1;
|
||||
--badge-purple-bg: #e9d5ff;
|
||||
--badge-purple-text: #7c3aed;
|
||||
--badge-orange-bg: #fed7aa;
|
||||
--badge-orange-text: #c2410c;
|
||||
--badge-amber-bg: #fde68a;
|
||||
--badge-amber-text: #a16207;
|
||||
--badge-teal-bg: #99f6e4;
|
||||
--badge-teal-text: #0f766e;
|
||||
--badge-cyan-bg: #cffafe;
|
||||
--badge-cyan-text: #0891b2;
|
||||
--badge-pink-bg: #fbcfe8;
|
||||
--badge-pink-text: #be185d;
|
||||
|
||||
/* Search/highlight */
|
||||
--highlight-search-active: #f6ad55;
|
||||
--highlight-search: #fcd34d;
|
||||
--highlight-match-bg: #bae6fd;
|
||||
--highlight-match-text: #0369a1;
|
||||
|
||||
/* Selection */
|
||||
--selection-bg: #add6ff;
|
||||
|
||||
/* Active indicator */
|
||||
--indicator-online: #33c482;
|
||||
--indicator-active: #4ade80;
|
||||
--indicator-inactive: #b7b7b7;
|
||||
--indicator-seat-filled: #34b5ff;
|
||||
|
||||
/* Scrollbar colors */
|
||||
--scrollbar-thumb-color: #c0c0c0;
|
||||
--scrollbar-thumb-hover-color: #a8a8a8;
|
||||
}
|
||||
.dark {
|
||||
/* Surface */
|
||||
@@ -316,10 +357,8 @@ html[data-sidebar-collapsed] .sidebar-container .sidebar-collapse-btn {
|
||||
--border-success: #575757;
|
||||
|
||||
/* Brand & state */
|
||||
--brand-400: #8e4cfb;
|
||||
--brand-secondary: #33b4ff;
|
||||
--brand-tertiary: #22c55e;
|
||||
--brand-tertiary-2: #33c482;
|
||||
--brand-accent: #33c482;
|
||||
--selection: #4b83f7;
|
||||
--warning: #ff6600;
|
||||
|
||||
@@ -331,70 +370,25 @@ html[data-sidebar-collapsed] .sidebar-container .sidebar-collapse-btn {
|
||||
--font-weight-medium: 480;
|
||||
--font-weight-semibold: 550;
|
||||
|
||||
/* Extended palette (exhaustive from code usage via -[#...]) */
|
||||
/* Neutral deep shades */
|
||||
--c-0D0D0D: #0d0d0d;
|
||||
--c-1A1A1A: #1a1a1a;
|
||||
--c-1F1F1F: #1f1f1f;
|
||||
--c-2A2A2A: #2a2a2a;
|
||||
--c-383838: #383838;
|
||||
--c-414141: #414141;
|
||||
--c-442929: #442929;
|
||||
--c-491515: #491515;
|
||||
--c-575757: #575757;
|
||||
--c-686868: #686868;
|
||||
--c-707070: #707070;
|
||||
--c-727272: #727272;
|
||||
--c-737373: #737373;
|
||||
--c-808080: #808080;
|
||||
--c-858585: #858585;
|
||||
--c-868686: #868686;
|
||||
--c-8D8D8D: #8d8d8d;
|
||||
--c-939393: #939393;
|
||||
--c-A8A8A8: #a8a8a8;
|
||||
--c-B8B8B8: #b8b8b8;
|
||||
--c-C0C0C0: #c0c0c0;
|
||||
--c-CDCDCD: #cdcdcd;
|
||||
--c-D0D0D0: #d0d0d0;
|
||||
--c-D2D2D2: #d2d2d2;
|
||||
--c-E0E0E0: #e0e0e0;
|
||||
--c-E5E5E5: #e5e5e5;
|
||||
--c-E8E8E8: #e8e8e8;
|
||||
--c-EEEEEE: #eeeeee;
|
||||
--c-F0F0F0: #f0f0f0;
|
||||
--c-F4F4F4: #f4f4f4;
|
||||
--c-F5F5F5: #f5f5f5;
|
||||
/* Code editor (dark mode overrides) */
|
||||
--code-bg: #1f1f1f;
|
||||
--code-foreground: #eeeeee;
|
||||
--code-line-number: #a8a8a8;
|
||||
|
||||
--c-CFCFCF: #cfcfcf;
|
||||
/* Workspace text */
|
||||
--text-placeholder: #8d8d8d;
|
||||
--text-success: #22c55e;
|
||||
|
||||
/* Blues and cyans */
|
||||
--c-00B0B0: #00b0b0;
|
||||
--c-264F78: #264f78;
|
||||
--c-2F55FF: #2f55ff;
|
||||
--c-2FA1FF: #2fa1ff;
|
||||
--c-336699: #336699;
|
||||
--c-34B5FF: #34b5ff;
|
||||
--c-601EE0: #601ee0;
|
||||
--c-611F69: #611f69;
|
||||
--c-802FFF: #802fff;
|
||||
--c-8357FF: #8357ff;
|
||||
--c-8C10FF: #8c10ff;
|
||||
/* Status / semantic (dark overrides where needed) */
|
||||
--error: #f87171;
|
||||
--error-muted: #f6d2d2;
|
||||
--error-emphasis: #b91c1c;
|
||||
--caution: #f59e0b;
|
||||
--success: #22c55e;
|
||||
|
||||
/* Greens */
|
||||
--c-4CAF50: #4caf50;
|
||||
|
||||
/* Oranges / Ambers */
|
||||
--c-F59E0B: #f59e0b;
|
||||
--c-F97316: #f97316;
|
||||
--c-FF972F: #ff972f;
|
||||
|
||||
/* Reds */
|
||||
--c-DC2626: #dc2626;
|
||||
--c-F6D2D2: #f6d2d2;
|
||||
--c-F87171: #f87171;
|
||||
--c-FF402F: #ff402f;
|
||||
--c-B91C1C: #b91c1c;
|
||||
--c-883827: #883827;
|
||||
/* Brand extended */
|
||||
--brand-knowledge: #00b0b0;
|
||||
--selection-dark: #264f78;
|
||||
|
||||
/* Terminal status badges */
|
||||
--terminal-status-error-bg: #491515;
|
||||
@@ -405,6 +399,52 @@ html[data-sidebar-collapsed] .sidebar-container .sidebar-collapse-btn {
|
||||
--terminal-status-warning-bg: #3d3520;
|
||||
--terminal-status-warning-border: #5c4d1f;
|
||||
--terminal-status-warning-color: #d4a72c;
|
||||
|
||||
/* Badge semantic colors */
|
||||
--badge-success-bg: rgba(34, 197, 94, 0.2);
|
||||
--badge-success-text: #86efac;
|
||||
--badge-error-bg: #551a1a;
|
||||
--badge-error-text: #fca5a5;
|
||||
--badge-gray-bg: #3a3a3a;
|
||||
--badge-gray-text: #a8a8a8;
|
||||
--badge-blue-bg: rgba(59, 130, 246, 0.2);
|
||||
--badge-blue-text: #93c5fd;
|
||||
--badge-blue-secondary-bg: rgba(51, 180, 255, 0.2);
|
||||
--badge-blue-secondary-text: #7dd3fc;
|
||||
--badge-purple-bg: rgba(168, 85, 247, 0.2);
|
||||
--badge-purple-text: #d8b4fe;
|
||||
--badge-orange-bg: rgba(249, 115, 22, 0.2);
|
||||
--badge-orange-text: #fdba74;
|
||||
--badge-amber-bg: rgba(245, 158, 11, 0.2);
|
||||
--badge-amber-text: #fcd34d;
|
||||
--badge-teal-bg: rgba(20, 184, 166, 0.2);
|
||||
--badge-teal-text: #5eead4;
|
||||
--badge-cyan-bg: rgba(14, 165, 233, 0.2);
|
||||
--badge-cyan-text: #7dd3fc;
|
||||
--badge-pink-bg: rgba(236, 72, 153, 0.2);
|
||||
--badge-pink-text: #f9a8d4;
|
||||
|
||||
/* Search/highlight */
|
||||
--highlight-search-active: #f6ad55;
|
||||
--highlight-search: #fcd34d;
|
||||
--highlight-match-bg: rgba(51, 180, 255, 0.2);
|
||||
--highlight-match-text: #7dd3fc;
|
||||
|
||||
/* Selection */
|
||||
--selection-bg: #264f78;
|
||||
|
||||
/* Active indicator */
|
||||
--indicator-online: #33c482;
|
||||
--indicator-active: #4ade80;
|
||||
--indicator-inactive: #b7b7b7;
|
||||
--indicator-seat-filled: #34b5ff;
|
||||
|
||||
/* Scrollbar colors */
|
||||
--scrollbar-thumb-color: #5a5a5a;
|
||||
--scrollbar-thumb-hover-color: #6a6a6a;
|
||||
|
||||
/* Shadow scale - dark */
|
||||
--shadow-overlay: 0 16px 48px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +485,7 @@ html[data-sidebar-collapsed] .sidebar-container .sidebar-collapse-btn {
|
||||
caret-color: var(--text-primary);
|
||||
}
|
||||
|
||||
.dark body {
|
||||
body {
|
||||
@apply antialiased;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
@@ -458,12 +498,12 @@ html[data-sidebar-collapsed] .sidebar-container .sidebar-collapse-btn {
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #c0c0c0;
|
||||
background-color: var(--scrollbar-thumb-color);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #a8a8a8;
|
||||
background-color: var(--scrollbar-thumb-hover-color);
|
||||
}
|
||||
|
||||
/* Dark Mode Global Scrollbar */
|
||||
@@ -472,20 +512,20 @@ html[data-sidebar-collapsed] .sidebar-container .sidebar-collapse-btn {
|
||||
}
|
||||
|
||||
.dark ::-webkit-scrollbar-thumb {
|
||||
background-color: #5a5a5a;
|
||||
background-color: var(--scrollbar-thumb-color);
|
||||
}
|
||||
|
||||
.dark ::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #6a6a6a;
|
||||
background-color: var(--scrollbar-thumb-hover-color);
|
||||
}
|
||||
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #c0c0c0 transparent;
|
||||
scrollbar-color: var(--scrollbar-thumb-color) transparent;
|
||||
}
|
||||
|
||||
.dark * {
|
||||
scrollbar-color: #5a5a5a transparent;
|
||||
scrollbar-color: var(--scrollbar-thumb-color) transparent;
|
||||
}
|
||||
|
||||
.copilot-scrollable {
|
||||
@@ -624,13 +664,13 @@ input[type="search"]::-ms-clear {
|
||||
}
|
||||
|
||||
.branded-button-custom {
|
||||
background: var(--brand-primary-hex) !important;
|
||||
border-color: var(--brand-primary-hex) !important;
|
||||
background: var(--brand) !important;
|
||||
border-color: var(--brand) !important;
|
||||
}
|
||||
|
||||
.branded-button-custom:hover {
|
||||
background: var(--brand-primary-hover-hex) !important;
|
||||
border-color: var(--brand-primary-hover-hex) !important;
|
||||
background: var(--brand-hover) !important;
|
||||
border-color: var(--brand-hover) !important;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -722,12 +762,10 @@ input[type="search"]::-ms-clear {
|
||||
--base-muted-foreground: #737373;
|
||||
--gradient-primary: 263 85% 70%;
|
||||
--gradient-secondary: 336 95% 65%;
|
||||
--brand-primary-hex: #6f3dfa;
|
||||
--brand-primary-hover-hex: #6338d9;
|
||||
--brand-accent-hex: #6f3dfa;
|
||||
--brand-accent-hover-hex: #6f3dfa;
|
||||
--brand-background-hex: #ffffff;
|
||||
--surface-elevated: #202020;
|
||||
--brand: #6f3dfa;
|
||||
--brand-hover: #6338d9;
|
||||
--brand-link: #6f3dfa;
|
||||
--brand-link-hover: #6f3dfa;
|
||||
}
|
||||
|
||||
.dark {
|
||||
@@ -761,12 +799,10 @@ input[type="search"]::-ms-clear {
|
||||
--base-muted-foreground: #a3a3a3;
|
||||
--gradient-primary: 263 90% 75%;
|
||||
--gradient-secondary: 336 100% 72%;
|
||||
--brand-primary-hex: #701ffc;
|
||||
--brand-primary-hover-hex: #802fff;
|
||||
--brand-accent-hex: #9d54ff;
|
||||
--brand-accent-hover-hex: #a66fff;
|
||||
--brand-background-hex: #0c0c0c;
|
||||
--surface-elevated: #202020;
|
||||
--brand: #701ffc;
|
||||
--brand-hover: #802fff;
|
||||
--brand-link: #9d54ff;
|
||||
--brand-link-hover: #a66fff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ export async function POST(request: NextRequest) {
|
||||
// Merge customizations with the additional fields
|
||||
const mergedCustomizations = {
|
||||
...(customizations || {}),
|
||||
primaryColor: customizations?.primaryColor || 'var(--brand-primary-hover-hex)',
|
||||
primaryColor: customizations?.primaryColor || 'var(--brand-hover)',
|
||||
welcomeMessage: customizations?.welcomeMessage || 'Hi there! How can I help you today?',
|
||||
}
|
||||
|
||||
|
||||
@@ -47,35 +47,37 @@ export default async function ChangelogContent() {
|
||||
<div className='min-h-screen'>
|
||||
<div className='relative grid md:grid-cols-2'>
|
||||
{/* Left intro panel */}
|
||||
<div className='relative top-0 overflow-hidden border-[#2A2A2A] border-b px-6 py-16 sm:px-10 md:sticky md:h-dvh md:border-r md:border-b-0 md:px-12 md:py-24'>
|
||||
<div className='relative top-0 overflow-hidden border-[var(--landing-bg-elevated)] border-b px-6 py-16 sm:px-10 md:sticky md:h-dvh md:border-r md:border-b-0 md:px-12 md:py-24'>
|
||||
<div className='relative mx-auto h-full max-w-xl md:flex md:flex-col md:justify-center'>
|
||||
<h1 className='mt-6 font-[500] text-4xl tracking-tight sm:text-5xl'>Changelog</h1>
|
||||
<p className='mt-4 text-[#999] text-sm'>
|
||||
<h1 className='mt-6 text-balance font-[500] text-4xl tracking-tight sm:text-5xl'>
|
||||
Changelog
|
||||
</h1>
|
||||
<p className='mt-4 text-[var(--landing-text-muted)] text-sm'>
|
||||
Stay up-to-date with the latest features, improvements, and bug fixes in Sim. All
|
||||
changes are documented here with detailed release notes.
|
||||
</p>
|
||||
<hr className='mt-6 border-[#2A2A2A]' />
|
||||
<hr className='mt-6 border-[var(--landing-bg-elevated)]' />
|
||||
|
||||
<div className='mt-6 flex flex-wrap items-center gap-3 text-sm'>
|
||||
<Link
|
||||
href='https://github.com/simstudioai/sim/releases'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='inline-flex items-center gap-2 rounded-[5px] border border-[#FFFFFF] bg-[#FFFFFF] px-[9px] py-[5px] text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
className='inline-flex items-center gap-2 rounded-[5px] border border-[var(--white)] bg-[var(--white)] px-[9px] py-[5px] text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]'
|
||||
>
|
||||
<Github className='h-4 w-4' />
|
||||
View on GitHub
|
||||
</Link>
|
||||
<Link
|
||||
href='https://docs.sim.ai'
|
||||
className='inline-flex items-center gap-2 rounded-[5px] border border-[#3d3d3d] px-[9px] py-[5px] text-[#ECECEC] text-[13.5px] transition-colors hover:bg-[#2A2A2A]'
|
||||
className='inline-flex items-center gap-2 rounded-[5px] border border-[var(--landing-border-strong)] px-[9px] py-[5px] text-[13.5px] text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
<BookOpen className='h-4 w-4' />
|
||||
Documentation
|
||||
</Link>
|
||||
<Link
|
||||
href='/changelog.xml'
|
||||
className='inline-flex items-center gap-2 rounded-[5px] border border-[#3d3d3d] px-[9px] py-[5px] text-[#ECECEC] text-[13.5px] transition-colors hover:bg-[#2A2A2A]'
|
||||
className='inline-flex items-center gap-2 rounded-[5px] border border-[var(--landing-border-strong)] px-[9px] py-[5px] text-[13.5px] text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]'
|
||||
>
|
||||
<Rss className='h-4 w-4' />
|
||||
RSS Feed
|
||||
|
||||
@@ -98,7 +98,7 @@ export default function ChangelogList({ initialEntries }: Props) {
|
||||
<div key={entry.tag}>
|
||||
<div className='flex items-center justify-between gap-4'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<div className='font-[500] text-[#ECECEC] text-[18px] tracking-tight'>
|
||||
<div className='font-[500] text-[var(--landing-text)] text-lg tracking-tight'>
|
||||
{entry.tag}
|
||||
</div>
|
||||
{entry.contributors && entry.contributors.length > 0 && (
|
||||
@@ -113,7 +113,7 @@ export default function ChangelogList({ initialEntries }: Props) {
|
||||
title={`@${contributor}`}
|
||||
className='block'
|
||||
>
|
||||
<Avatar className='size-6 ring-2 ring-[#1C1C1C]'>
|
||||
<Avatar className='size-6 ring-2 ring-[var(--landing-bg)]'>
|
||||
<AvatarImage
|
||||
src={`https://avatars.githubusercontent.com/${contributor}`}
|
||||
alt={`@${contributor}`}
|
||||
@@ -124,14 +124,14 @@ export default function ChangelogList({ initialEntries }: Props) {
|
||||
</a>
|
||||
))}
|
||||
{entry.contributors.length > 5 && (
|
||||
<div className='relative flex size-6 items-center justify-center rounded-full bg-[#2A2A2A] text-[#ECECEC] text-[10px] ring-2 ring-[#1C1C1C] hover:z-10'>
|
||||
<div className='relative flex size-6 items-center justify-center rounded-full bg-[var(--landing-bg-elevated)] text-[var(--landing-text)] text-micro ring-2 ring-[var(--landing-bg)] hover:z-10'>
|
||||
+{entry.contributors.length - 5}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className='text-[#999] text-xs'>
|
||||
<div className='text-[var(--landing-text-muted)] text-xs'>
|
||||
{new Date(entry.date).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
@@ -146,7 +146,7 @@ export default function ChangelogList({ initialEntries }: Props) {
|
||||
h2: ({ children, ...props }) =>
|
||||
isContributorsLabel(children) ? null : (
|
||||
<h3
|
||||
className='mt-5 mb-2 font-[500] text-[#ECECEC] text-[13px] tracking-tight'
|
||||
className='mt-5 mb-2 font-[500] text-[var(--landing-text)] text-small tracking-tight'
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -155,7 +155,7 @@ export default function ChangelogList({ initialEntries }: Props) {
|
||||
h3: ({ children, ...props }) =>
|
||||
isContributorsLabel(children) ? null : (
|
||||
<h4
|
||||
className='mt-4 mb-1 font-[500] text-[#ECECEC] text-[13px] tracking-tight'
|
||||
className='mt-4 mb-1 font-[500] text-[var(--landing-text)] text-small tracking-tight'
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -170,25 +170,31 @@ export default function ChangelogList({ initialEntries }: Props) {
|
||||
const text = String(children)
|
||||
if (/^\s*contributors\s*:?\s*$/i.test(text)) return null
|
||||
return (
|
||||
<li className='text-[#999] text-[13px] leading-relaxed' {...props}>
|
||||
<li
|
||||
className='text-[var(--landing-text-muted)] text-small leading-relaxed'
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</li>
|
||||
)
|
||||
},
|
||||
p: ({ children, ...props }) =>
|
||||
/^\s*contributors\s*:?\s*$/i.test(String(children)) ? null : (
|
||||
<p className='mb-3 text-[#999] text-[13px] leading-relaxed' {...props}>
|
||||
<p
|
||||
className='mb-3 text-[var(--landing-text-muted)] text-small leading-relaxed'
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</p>
|
||||
),
|
||||
strong: ({ children, ...props }) => (
|
||||
<strong className='font-[500] text-[#ECECEC]' {...props}>
|
||||
<strong className='font-[500] text-[var(--landing-text)]' {...props}>
|
||||
{children}
|
||||
</strong>
|
||||
),
|
||||
code: ({ children, ...props }) => (
|
||||
<code
|
||||
className='rounded bg-[#2A2A2A] px-1 py-0.5 font-mono text-[#ECECEC] text-xs'
|
||||
className='rounded bg-[var(--landing-bg-elevated)] px-1 py-0.5 font-mono text-[var(--landing-text)] text-xs'
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -217,7 +223,7 @@ export default function ChangelogList({ initialEntries }: Props) {
|
||||
type='button'
|
||||
onClick={loadMore}
|
||||
disabled={loading}
|
||||
className='rounded-[5px] border border-[#3d3d3d] px-3 py-1.5 text-[#ECECEC] text-[13px] transition-colors hover:bg-[#2A2A2A] disabled:opacity-60'
|
||||
className='rounded-[5px] border border-[var(--landing-border-strong)] px-3 py-1.5 text-[var(--landing-text)] text-small transition-colors hover:bg-[var(--landing-bg-elevated)] disabled:opacity-60'
|
||||
>
|
||||
{loading ? 'Loading…' : 'Show more'}
|
||||
</button>
|
||||
|
||||
@@ -7,7 +7,7 @@ export default async function ChangelogLayout({ children }: { children: React.Re
|
||||
const blogPosts = await getNavBlogPosts()
|
||||
return (
|
||||
<div
|
||||
className={`${martianMono.variable} relative min-h-screen bg-[#1C1C1C] font-[430] font-season text-[#ECECEC]`}
|
||||
className={`${martianMono.variable} relative min-h-screen bg-[var(--landing-bg)] font-[430] font-season text-[var(--landing-text)]`}
|
||||
>
|
||||
<header>
|
||||
<Navbar blogPosts={blogPosts} />
|
||||
|
||||
@@ -4,29 +4,29 @@ export default function ChangelogLoading() {
|
||||
return (
|
||||
<div className='min-h-screen'>
|
||||
<div className='relative grid md:grid-cols-2'>
|
||||
<div className='relative top-0 overflow-hidden border-[#2A2A2A] border-b px-6 py-16 sm:px-10 md:sticky md:h-dvh md:border-r md:border-b-0 md:px-12 md:py-24'>
|
||||
<div className='relative top-0 overflow-hidden border-[var(--landing-border)] border-b px-6 py-16 sm:px-10 md:sticky md:h-dvh md:border-r md:border-b-0 md:px-12 md:py-24'>
|
||||
<div className='relative mx-auto h-full max-w-xl md:flex md:flex-col md:justify-center'>
|
||||
<Skeleton className='mt-6 h-[48px] w-[200px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='mt-4 h-[14px] w-[300px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='mt-[4px] h-[14px] w-[260px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='mt-6 h-[1px] w-full bg-[#2A2A2A]' />
|
||||
<Skeleton className='mt-6 h-[48px] w-[200px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='mt-4 h-[14px] w-[300px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='mt-1 h-[14px] w-[260px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='mt-6 h-[1px] w-full bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='mt-6 flex flex-wrap items-center gap-3'>
|
||||
<Skeleton className='h-[32px] w-[130px] rounded-[5px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[32px] w-[120px] rounded-[5px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[32px] w-[80px] rounded-[5px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[32px] w-[130px] rounded-[5px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[32px] w-[120px] rounded-[5px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[32px] w-[80px] rounded-[5px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='px-6 py-16 sm:px-10 md:px-12 md:py-24'>
|
||||
<div className='max-w-2xl space-y-[32px]'>
|
||||
<div className='max-w-2xl space-y-8'>
|
||||
{Array.from({ length: 4 }).map((_, i) => (
|
||||
<div key={i} className='space-y-[12px]'>
|
||||
<Skeleton className='h-[20px] w-[160px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[14px] w-[100px] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div className='space-y-[8px]'>
|
||||
<Skeleton className='h-[14px] w-full rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[14px] w-[90%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<Skeleton className='h-[14px] w-[75%] rounded-[4px] bg-[#2A2A2A]' />
|
||||
<div key={i} className='space-y-3'>
|
||||
<Skeleton className='h-[20px] w-[160px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[14px] w-[100px] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<div className='space-y-2'>
|
||||
<Skeleton className='h-[14px] w-full rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[14px] w-[90%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
<Skeleton className='h-[14px] w-[75%] rounded-[4px] bg-[var(--landing-bg-elevated)]' />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -466,7 +466,7 @@ export default function ChatClient({ identifier }: { identifier: string }) {
|
||||
if (authRequired) {
|
||||
// const title = new URLSearchParams(window.location.search).get('title') || 'chat'
|
||||
// const primaryColor =
|
||||
// new URLSearchParams(window.location.search).get('color') || 'var(--brand-primary-hover-hex)'
|
||||
// new URLSearchParams(window.location.search).get('color') || 'var(--brand-hover)'
|
||||
|
||||
if (authRequired === 'password') {
|
||||
return <PasswordAuth identifier={identifier} onAuthSuccess={handleAuthSuccess} />
|
||||
|
||||
@@ -182,18 +182,18 @@ export default function EmailAuth({ identifier, onAuthSuccess }: EmailAuthProps)
|
||||
|
||||
return (
|
||||
<AuthBackground className='dark font-[430] font-season'>
|
||||
<main className='relative flex min-h-screen flex-col text-[#ECECEC]'>
|
||||
<header className='shrink-0 bg-[#1C1C1C]'>
|
||||
<main className='relative flex min-h-screen flex-col text-[var(--landing-text)]'>
|
||||
<header className='shrink-0 bg-[var(--landing-bg)]'>
|
||||
<Navbar logoOnly />
|
||||
</header>
|
||||
<div className='relative z-30 flex flex-1 items-center justify-center px-4 pb-24'>
|
||||
<div className='w-full max-w-lg px-4'>
|
||||
<div className='flex flex-col items-center justify-center'>
|
||||
<div className='space-y-1 text-center'>
|
||||
<h1 className='font-[500] text-[#ECECEC] text-[32px] tracking-tight'>
|
||||
<h1 className='font-[500] text-[32px] text-[var(--landing-text)] tracking-tight'>
|
||||
{showOtpVerification ? 'Verify Your Email' : 'Email Verification'}
|
||||
</h1>
|
||||
<p className='font-[380] text-[#999] text-[16px]'>
|
||||
<p className='font-[380] text-[var(--text-subtle)] text-md'>
|
||||
{showOtpVerification
|
||||
? `A verification code has been sent to ${email}`
|
||||
: 'This chat requires email verification'}
|
||||
@@ -246,7 +246,7 @@ export default function EmailAuth({ identifier, onAuthSuccess }: EmailAuthProps)
|
||||
</form>
|
||||
) : (
|
||||
<div className='space-y-6'>
|
||||
<p className='text-center text-[#999] text-sm'>
|
||||
<p className='text-center text-[var(--text-subtle)] text-sm'>
|
||||
Enter the 6-digit code to verify your account. If you don't see it in your
|
||||
inbox, check your spam folder.
|
||||
</p>
|
||||
@@ -301,7 +301,7 @@ export default function EmailAuth({ identifier, onAuthSuccess }: EmailAuthProps)
|
||||
</span>
|
||||
) : (
|
||||
<button
|
||||
className='font-medium text-[var(--brand-accent-hex)] underline-offset-4 transition hover:text-[var(--brand-accent-hover-hex)] hover:underline'
|
||||
className='font-medium text-[var(--brand-link)] underline-offset-4 transition hover:text-[var(--brand-link-hover)] hover:underline'
|
||||
onClick={handleResendOtp}
|
||||
disabled={isVerifyingOtp || isResendDisabled}
|
||||
>
|
||||
@@ -311,14 +311,14 @@ export default function EmailAuth({ identifier, onAuthSuccess }: EmailAuthProps)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='text-center font-light text-[14px]'>
|
||||
<div className='text-center font-light text-sm'>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowOtpVerification(false)
|
||||
setOtpValue('')
|
||||
setAuthError(null)
|
||||
}}
|
||||
className='font-medium text-[var(--brand-accent-hex)] underline-offset-4 transition hover:text-[var(--brand-accent-hover-hex)] hover:underline'
|
||||
className='font-medium text-[var(--brand-link)] underline-offset-4 transition hover:text-[var(--brand-link-hover)] hover:underline'
|
||||
>
|
||||
Change email
|
||||
</button>
|
||||
|
||||
@@ -80,18 +80,18 @@ export default function PasswordAuth({ identifier, onAuthSuccess }: PasswordAuth
|
||||
|
||||
return (
|
||||
<AuthBackground className='dark font-[430] font-season'>
|
||||
<main className='relative flex min-h-screen flex-col text-[#ECECEC]'>
|
||||
<header className='shrink-0 bg-[#1C1C1C]'>
|
||||
<main className='relative flex min-h-screen flex-col text-[var(--landing-text)]'>
|
||||
<header className='shrink-0 bg-[var(--landing-bg)]'>
|
||||
<Navbar logoOnly />
|
||||
</header>
|
||||
<div className='relative z-30 flex flex-1 items-center justify-center px-4 pb-24'>
|
||||
<div className='w-full max-w-lg px-4'>
|
||||
<div className='flex flex-col items-center justify-center'>
|
||||
<div className='space-y-1 text-center'>
|
||||
<h1 className='font-[500] text-[#ECECEC] text-[32px] tracking-tight'>
|
||||
<h1 className='font-[500] text-[32px] text-[var(--landing-text)] tracking-tight'>
|
||||
Password Required
|
||||
</h1>
|
||||
<p className='font-[380] text-[#999] text-[16px]'>
|
||||
<p className='font-[380] text-[var(--text-subtle)] text-md'>
|
||||
This chat is password-protected
|
||||
</p>
|
||||
</div>
|
||||
@@ -103,47 +103,59 @@ export default function PasswordAuth({ identifier, onAuthSuccess }: PasswordAuth
|
||||
}}
|
||||
className='mt-8 w-full max-w-[410px] space-y-6'
|
||||
>
|
||||
<div className='space-y-2'>
|
||||
<div className='space-y-6'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label htmlFor='password'>Password</Label>
|
||||
</div>
|
||||
<div className='relative'>
|
||||
<Input
|
||||
id='password'
|
||||
name='password'
|
||||
required
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
autoCapitalize='none'
|
||||
autoComplete='new-password'
|
||||
autoCorrect='off'
|
||||
placeholder='Enter password'
|
||||
value={password}
|
||||
onChange={handlePasswordChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
className={cn(
|
||||
'pr-10',
|
||||
showValidationError &&
|
||||
passwordErrors.length > 0 &&
|
||||
'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
autoFocus
|
||||
/>
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[#999] hover:text-[#ECECEC]'
|
||||
aria-label={showPassword ? 'Hide password' : 'Show password'}
|
||||
>
|
||||
{showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
|
||||
</button>
|
||||
</div>
|
||||
{showValidationError && passwordErrors.length > 0 && (
|
||||
<div className='mt-1 space-y-1 text-red-400 text-xs'>
|
||||
{passwordErrors.map((error, index) => (
|
||||
<p key={index}>{error}</p>
|
||||
))}
|
||||
<div className='relative'>
|
||||
<Input
|
||||
id='password'
|
||||
name='password'
|
||||
required
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
autoCapitalize='none'
|
||||
autoComplete='new-password'
|
||||
autoCorrect='off'
|
||||
placeholder='Enter password'
|
||||
value={password}
|
||||
onChange={handlePasswordChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
className={cn(
|
||||
'pr-10',
|
||||
showValidationError &&
|
||||
passwordErrors.length > 0 &&
|
||||
'border-red-500 focus:border-red-500'
|
||||
)}
|
||||
autoFocus
|
||||
/>
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[var(--text-subtle)] hover:text-[var(--landing-text)]'
|
||||
aria-label={showPassword ? 'Hide password' : 'Show password'}
|
||||
>
|
||||
{showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
'absolute right-0 left-0 z-10 grid transition-[grid-template-rows] duration-200 ease-out',
|
||||
showValidationError && passwordErrors.length > 0
|
||||
? 'grid-rows-[1fr]'
|
||||
: 'grid-rows-[0fr]'
|
||||
)}
|
||||
aria-live='polite'
|
||||
>
|
||||
<div className='overflow-hidden'>
|
||||
<div className='mt-1 space-y-1 text-red-400 text-xs'>
|
||||
{passwordErrors.map((error, index) => (
|
||||
<p key={index}>{error}</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BrandedButton
|
||||
|
||||
@@ -20,13 +20,13 @@ interface ChatHeaderProps {
|
||||
|
||||
export function ChatHeader({ chatConfig, starCount }: ChatHeaderProps) {
|
||||
const brand = useBrandConfig()
|
||||
const primaryColor = chatConfig?.customizations?.primaryColor || 'var(--brand-primary-hex)'
|
||||
const primaryColor = chatConfig?.customizations?.primaryColor || 'var(--brand)'
|
||||
const customImage = chatConfig?.customizations?.imageUrl || chatConfig?.customizations?.logoUrl
|
||||
|
||||
return (
|
||||
<nav
|
||||
aria-label='Chat navigation'
|
||||
className={`flex w-full items-center justify-between px-4 pt-[12px] pb-[21px] sm:px-8 sm:pt-[8.5px] md:px-[44px] md:pt-[16px]`}
|
||||
className={`flex w-full items-center justify-between px-4 pt-3 pb-[21px] sm:px-8 sm:pt-[8.5px] md:px-[44px] md:pt-4`}
|
||||
>
|
||||
<div className='flex items-center gap-[34px]'>
|
||||
<div className='flex items-center gap-3'>
|
||||
@@ -40,19 +40,19 @@ export function ChatHeader({ chatConfig, starCount }: ChatHeaderProps) {
|
||||
className='h-6 w-6 rounded-md object-cover'
|
||||
/>
|
||||
)}
|
||||
<h2 className='font-medium text-[18px] text-foreground'>
|
||||
<h2 className='font-medium text-foreground text-lg'>
|
||||
{chatConfig?.customizations?.headerText || chatConfig?.title || 'Chat'}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!brand.logoUrl && (
|
||||
<div className='flex items-center gap-[16px]'>
|
||||
<div className='flex items-center gap-4'>
|
||||
<a
|
||||
href='https://github.com/simstudioai/sim'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='flex items-center gap-2 text-[16px] text-muted-foreground transition-colors hover:text-foreground'
|
||||
className='flex items-center gap-2 text-md text-muted-foreground transition-colors hover:text-foreground'
|
||||
aria-label={`GitHub repository - ${starCount} stars`}
|
||||
>
|
||||
<GithubIcon className='h-[16px] w-[16px]' aria-hidden='true' />
|
||||
|
||||
@@ -303,7 +303,7 @@ export const ChatInput: React.FC<{
|
||||
<div className='truncate font-medium text-gray-800 text-xs dark:text-gray-200'>
|
||||
{file.name}
|
||||
</div>
|
||||
<div className='text-[10px] text-gray-500 dark:text-gray-400'>
|
||||
<div className='text-gray-500 text-micro dark:text-gray-400'>
|
||||
{formatFileSize(file.size)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -119,7 +119,7 @@ export function ChatFileDownload({ file }: ChatFileDownloadProps) {
|
||||
<div className='flex h-8 w-8 flex-shrink-0 items-center justify-center'>{renderIcon()}</div>
|
||||
<div className='min-w-0 flex-1 text-left'>
|
||||
<div className='w-[100px] truncate text-xs'>{file.name}</div>
|
||||
<div className='text-[10px] text-[var(--text-muted)]'>{formatFileSize(file.size)}</div>
|
||||
<div className='text-[var(--text-muted)] text-micro'>{formatFileSize(file.size)}</div>
|
||||
</div>
|
||||
<div className='flex-shrink-0'>
|
||||
{isDownloading ? (
|
||||
|
||||
@@ -208,7 +208,7 @@ const MarkdownRenderer = memo(function MarkdownRenderer({
|
||||
const processedContent = content.trim()
|
||||
|
||||
return (
|
||||
<div className='space-y-4 break-words font-sans text-[#0D0D0D] text-base leading-relaxed dark:text-gray-100'>
|
||||
<div className='space-y-4 break-words font-sans text-[var(--text-primary)] text-base leading-relaxed dark:text-gray-100'>
|
||||
<ReactMarkdown remarkPlugins={REMARK_PLUGINS} components={components}>
|
||||
{processedContent}
|
||||
</ReactMarkdown>
|
||||
|
||||
@@ -146,7 +146,7 @@ export const ClientChatMessage = memo(
|
||||
{attachment.name}
|
||||
</div>
|
||||
{attachment.size && (
|
||||
<div className='text-[10px] text-gray-500 md:text-xs dark:text-gray-400'>
|
||||
<div className='text-gray-500 text-micro md:text-xs dark:text-gray-400'>
|
||||
{formatFileSize(attachment.size)}
|
||||
</div>
|
||||
)}
|
||||
@@ -163,7 +163,7 @@ export const ClientChatMessage = memo(
|
||||
{/* Only render message bubble if there's actual text content (not just file count message) */}
|
||||
{message.content && !String(message.content).startsWith('Sent') && (
|
||||
<div className='flex justify-end'>
|
||||
<div className='max-w-[80%] rounded-3xl bg-[#F4F4F4] px-4 py-3 dark:bg-gray-600'>
|
||||
<div className='max-w-[80%] rounded-3xl bg-[var(--surface-4)] px-4 py-3 dark:bg-gray-600'>
|
||||
<div className='whitespace-pre-wrap break-words text-base text-gray-800 leading-relaxed dark:text-gray-100'>
|
||||
{isJsonObject ? (
|
||||
<pre>{JSON.stringify(message.content, null, 2)}</pre>
|
||||
|
||||
@@ -95,7 +95,7 @@ export function FormField({
|
||||
onCheckedChange={onChange}
|
||||
style={value ? { backgroundColor: primaryColor } : undefined}
|
||||
/>
|
||||
<span className={'text-[14px] text-muted-foreground'}>{value ? 'Yes' : 'No'}</span>
|
||||
<span className={'text-muted-foreground text-sm'}>{value ? 'Yes' : 'No'}</span>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -122,7 +122,7 @@ export function FormField({
|
||||
placeholder={
|
||||
placeholder || (field.type === 'array' ? '["item1", "item2"]' : '{"key": "value"}')
|
||||
}
|
||||
className='min-h-[100px] rounded-[10px] font-mono text-[13px] shadow-sm transition-colors focus:border-gray-400 focus:ring-2 focus:ring-gray-100'
|
||||
className='min-h-[100px] rounded-[10px] font-mono text-small shadow-sm transition-colors focus:border-gray-400 focus:ring-2 focus:ring-gray-100'
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -141,7 +141,7 @@ export function FormField({
|
||||
className={cn(
|
||||
'flex cursor-pointer flex-col items-center justify-center rounded-[10px] border-2 border-dashed px-6 py-8 transition-colors',
|
||||
isDragging
|
||||
? 'border-[var(--brand-primary-hex)] bg-[var(--brand-primary-hex)]/5'
|
||||
? 'border-[var(--brand)] bg-[color-mix(in_srgb,var(--brand)_5%,transparent)]'
|
||||
: 'border-border hover:border-muted-foreground/50'
|
||||
)}
|
||||
>
|
||||
@@ -156,7 +156,7 @@ export function FormField({
|
||||
className='mb-2 h-6 w-6 text-muted-foreground'
|
||||
style={isDragging ? { color: primaryColor } : undefined}
|
||||
/>
|
||||
<p className={'text-center text-[14px] text-muted-foreground'}>
|
||||
<p className={'text-center text-muted-foreground text-sm'}>
|
||||
<span style={{ color: primaryColor }} className='font-medium'>
|
||||
Click to upload
|
||||
</span>{' '}
|
||||
@@ -169,13 +169,13 @@ export function FormField({
|
||||
{files.map((file, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className='flex items-center justify-between rounded-[8px] border border-border bg-muted/30 px-3 py-2'
|
||||
className='flex items-center justify-between rounded-lg border border-border bg-muted/30 px-3 py-2'
|
||||
>
|
||||
<div className='min-w-0 flex-1'>
|
||||
<p className={'truncate font-medium text-[13px] text-foreground'}>
|
||||
<p className={'truncate font-medium text-foreground text-small'}>
|
||||
{file.name}
|
||||
</p>
|
||||
<p className={'text-[12px] text-muted-foreground'}>
|
||||
<p className={'text-caption text-muted-foreground'}>
|
||||
{formatFileSize(file.size)}
|
||||
</p>
|
||||
</div>
|
||||
@@ -212,7 +212,7 @@ export function FormField({
|
||||
|
||||
return (
|
||||
<div className='space-y-2'>
|
||||
<Label className={'font-medium text-[14px] text-foreground'}>
|
||||
<Label className={'font-medium text-foreground text-sm'}>
|
||||
{displayLabel}
|
||||
{isRequired && <span className='ml-0.5 text-[var(--text-error)]'>*</span>}
|
||||
</Label>
|
||||
|
||||
@@ -33,18 +33,18 @@ export function PasswordAuth({ onSubmit, error }: PasswordAuthProps) {
|
||||
|
||||
return (
|
||||
<AuthBackground className='dark font-[430] font-season'>
|
||||
<main className='relative flex min-h-screen flex-col text-[#ECECEC]'>
|
||||
<header className='shrink-0 bg-[#1C1C1C]'>
|
||||
<main className='relative flex min-h-screen flex-col text-[var(--landing-text)]'>
|
||||
<header className='shrink-0 bg-[var(--landing-bg)]'>
|
||||
<Navbar logoOnly />
|
||||
</header>
|
||||
<div className='relative z-30 flex flex-1 items-center justify-center px-4 pb-24'>
|
||||
<div className='w-full max-w-lg px-4'>
|
||||
<div className='flex flex-col items-center justify-center'>
|
||||
<div className='space-y-1 text-center'>
|
||||
<h1 className='font-[500] text-[#ECECEC] text-[32px] tracking-tight'>
|
||||
<h1 className='font-[500] text-[32px] text-[var(--landing-text)] tracking-tight'>
|
||||
Password Required
|
||||
</h1>
|
||||
<p className='font-[380] text-[#999] text-[16px]'>
|
||||
<p className='font-[380] text-[var(--text-subtle)] text-md'>
|
||||
Enter the password to access this form.
|
||||
</p>
|
||||
</div>
|
||||
@@ -65,12 +65,12 @@ export function PasswordAuth({ onSubmit, error }: PasswordAuthProps) {
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[#999] hover:text-[#ECECEC]'
|
||||
className='-translate-y-1/2 absolute top-1/2 right-3 text-[var(--text-subtle)] hover:text-[var(--landing-text)]'
|
||||
>
|
||||
{showPassword ? <EyeOff className='h-4 w-4' /> : <Eye className='h-4 w-4' />}
|
||||
</button>
|
||||
</div>
|
||||
{error && <p className='text-[14px] text-red-500'>{error}</p>}
|
||||
{error && <p className='text-red-500 text-sm'>{error}</p>}
|
||||
</div>
|
||||
|
||||
<BrandedButton
|
||||
|
||||
@@ -9,7 +9,7 @@ export function PoweredBySim() {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'fixed right-0 bottom-0 left-0 z-50 pb-8 text-center font-[340] text-[#999] text-[13px] leading-relaxed'
|
||||
'fixed right-0 bottom-0 left-0 z-50 pb-8 text-center font-[340] text-[var(--text-subtle)] text-small leading-relaxed'
|
||||
}
|
||||
>
|
||||
<a
|
||||
|
||||
@@ -6,7 +6,7 @@ interface ThankYouScreenProps {
|
||||
primaryColor?: string
|
||||
}
|
||||
|
||||
/** Default green color matching --brand-tertiary-2 */
|
||||
/** Default green color matching --brand-accent */
|
||||
const DEFAULT_THANK_YOU_COLOR = '#33C482'
|
||||
|
||||
/** Legacy blue default that should be treated as "no custom color" */
|
||||
@@ -32,7 +32,7 @@ export function ThankYouScreen({ title, message, primaryColor }: ThankYouScreenP
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
<p className={'mt-3 max-w-md font-[380] text-[#999] text-[16px]'}>{message}</p>
|
||||
<p className={'mt-3 max-w-md font-[380] text-[var(--text-subtle)] text-md'}>{message}</p>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user