fix(whitelabel): fix privacy policy & terms, remove unused/unnecessary envvars for whitelabeling (#969)

* fix(whitelabel): fix privacy policy & terms for whitelabeling

* remove unused hide branding url

* removed support email envvar, remove landing page except for hosted version

* remove unnecessary comments

* removed primary, secondary, accent color envvars and standardized usage of brand colors in css file

* fix primaryColor refernce

* fix invalid css
This commit is contained in:
Waleed Latif
2025-08-14 20:03:01 -07:00
committed by GitHub
parent fd9e61f85a
commit 72c07e8ad2
71 changed files with 283 additions and 263 deletions

View File

@@ -9,7 +9,7 @@ export default function AuthLayout({ children }: { children: React.ReactNode })
const brand = useBrandConfig()
return (
<main className='relative flex min-h-screen flex-col bg-[#0C0C0C] font-geist-sans text-white'>
<main className='relative flex min-h-screen flex-col bg-[var(--brand-background-hex)] font-geist-sans text-white'>
{/* Background pattern */}
<GridPattern
x={-5}

View File

@@ -456,7 +456,7 @@ export default function LoginPage({
<Button
type='submit'
className='flex h-11 w-full items-center justify-center gap-2 bg-[#701ffc] font-medium text-base text-white shadow-[#701ffc]/20 shadow-lg transition-colors duration-200 hover:bg-[#802FFF]'
className='flex h-11 w-full items-center justify-center gap-2 bg-brand-primary font-medium text-base text-white shadow-[var(--brand-primary-hex)]/20 shadow-lg transition-colors duration-200 hover:bg-brand-primary-hover'
disabled={isLoading}
>
{isLoading ? 'Signing in...' : 'Sign In'}
@@ -468,7 +468,7 @@ export default function LoginPage({
<span className='text-neutral-400'>Don't have an account? </span>
<Link
href={isInviteFlow ? `/signup?invite_flow=true&callbackUrl=${callbackUrl}` : '/signup'}
className='font-medium text-[#9D54FF] underline-offset-4 transition hover:text-[#a66fff] hover:underline'
className='font-medium text-[var(--brand-accent-hex)] underline-offset-4 transition hover:text-[var(--brand-accent-hover-hex)] hover:underline'
>
Sign up
</Link>
@@ -497,7 +497,7 @@ export default function LoginPage({
placeholder='Enter your email'
required
type='email'
className='border-neutral-700/80 bg-neutral-900 text-white placeholder:text-white/60 focus:border-[#802FFF]/70 focus:ring-[#802FFF]/20'
className='border-neutral-700/80 bg-neutral-900 text-white placeholder:text-white/60 focus:border-[var(--brand-primary-hover-hex)]/70 focus:ring-[var(--brand-primary-hover-hex)]/20'
/>
</div>
{resetStatus.type && (
@@ -512,7 +512,7 @@ export default function LoginPage({
<Button
type='button'
onClick={handleForgotPassword}
className='h-11 w-full bg-[#701ffc] font-medium text-base text-white shadow-[#701ffc]/20 shadow-lg transition-colors duration-200 hover:bg-[#802FFF]'
className='h-11 w-full bg-[var(--brand-primary-hex)] font-medium text-base text-white shadow-[var(--brand-primary-hex)]/20 shadow-lg transition-colors duration-200 hover:bg-[var(--brand-primary-hover-hex)]'
disabled={isSubmittingReset}
>
{isSubmittingReset ? 'Sending...' : 'Send Reset Link'}

View File

@@ -488,7 +488,7 @@ function SignupFormContent({
<Button
type='submit'
className='flex h-11 w-full items-center justify-center gap-2 bg-[#701ffc] font-medium text-base text-white shadow-[#701ffc]/20 shadow-lg transition-colors duration-200 hover:bg-[#802FFF]'
className='flex h-11 w-full items-center justify-center gap-2 bg-[var(--brand-primary-hex)] font-medium text-base text-white shadow-[var(--brand-primary-hex)]/20 shadow-lg transition-colors duration-200 hover:bg-[var(--brand-primary-hover-hex)]'
disabled={isLoading}
>
{isLoading ? 'Creating account...' : 'Create Account'}
@@ -500,7 +500,7 @@ function SignupFormContent({
<span className='text-neutral-400'>Already have an account? </span>
<Link
href={isInviteFlow ? `/login?invite_flow=true&callbackUrl=${redirectUrl}` : '/login'}
className='font-medium text-[#9D54FF] underline-offset-4 transition hover:text-[#a66fff] hover:underline'
className='font-medium text-[var(--brand-accent-hex)] underline-offset-4 transition hover:text-[var(--brand-accent-hover-hex)] hover:underline'
>
Sign in
</Link>

View File

@@ -124,7 +124,7 @@ function VerificationForm({
<Button
onClick={verifyCode}
className='h-11 w-full bg-[#701ffc] font-medium text-base text-white shadow-[#701ffc]/20 shadow-lg transition-colors duration-200 hover:bg-[#802FFF]'
className='h-11 w-full bg-[var(--brand-primary-hex)] font-medium text-base text-white shadow-[var(--brand-primary-hex)]/20 shadow-lg transition-colors duration-200 hover:bg-[var(--brand-primary-hover-hex)]'
disabled={!isOtpComplete || isLoading}
>
{isLoading ? 'Verifying...' : 'Verify Email'}
@@ -140,7 +140,7 @@ function VerificationForm({
</span>
) : (
<button
className='font-medium text-[#9D54FF] underline-offset-4 transition hover:text-[#a66fff] hover:underline'
className='font-medium text-[var(--brand-accent-hex)] underline-offset-4 transition hover:text-[var(--brand-accent-hover-hex)] hover:underline'
onClick={handleResend}
disabled={isLoading || isResendDisabled}
>

View File

@@ -35,7 +35,7 @@ export const BlogCard = ({
}: BlogCardProps) => {
return (
<Link href={href}>
<div className='flex flex-col rounded-3xl border border-[#606060]/40 bg-[#101010] p-8 transition-all duration-500 hover:bg-[#202020]'>
<div className='flex flex-col rounded-3xl border border-[#606060]/40 bg-[#101010] p-8 transition-all duration-500 hover:bg-[var(--surface-elevated)]'>
{image ? (
<Image
src={image}

View File

@@ -245,7 +245,7 @@ export default function NavClient({
target='_blank'
rel='noopener noreferrer'
>
<Button className='h-[43px] bg-[#701ffc] px-6 py-2 font-geist-sans font-medium text-base text-neutral-100 transition-colors duration-200 hover:bg-[#802FFF]'>
<Button className='h-[43px] bg-[var(--brand-primary-hex)] px-6 py-2 font-geist-sans font-medium text-base text-neutral-100 transition-colors duration-200 hover:bg-[var(--brand-primary-hover-hex)]'>
Contact
</Button>
</Link>
@@ -277,7 +277,7 @@ export default function NavClient({
>
<SheetContent
side='right'
className='flex h-full w-[280px] flex-col border-[#181818] border-l bg-[#0C0C0C] p-6 pt-6 text-white shadow-xl sm:w-[320px] [&>button]:hidden'
className='flex h-full w-[280px] flex-col border-[#181818] border-l bg-[var(--brand-background-hex)] p-6 pt-6 text-white shadow-xl sm:w-[320px] [&>button]:hidden'
onOpenAutoFocus={(e) => e.preventDefault()}
onCloseAutoFocus={(e) => e.preventDefault()}
>
@@ -311,7 +311,7 @@ export default function NavClient({
target='_blank'
rel='noopener noreferrer'
>
<Button className='w-full bg-[#701ffc] py-6 font-medium text-base text-white shadow-[#701ffc]/20 shadow-lg transition-colors duration-200 hover:bg-[#802FFF]'>
<Button className='w-full bg-[var(--brand-primary-hex)] py-6 font-medium text-base text-white shadow-[var(--brand-primary-hex)]/20 shadow-lg transition-colors duration-200 hover:bg-[var(--brand-primary-hover-hex)]'>
Contact
</Button>
</Link>

View File

@@ -62,7 +62,7 @@ function Hero() {
<Button
variant={'secondary'}
onClick={handleNavigate}
className='animate-fade-in items-center bg-[#701ffc] px-7 py-6 font-[420] font-geist-sans text-lg text-neutral-100 tracking-normal shadow-[#701ffc]/30 shadow-lg hover:bg-[#802FFF]'
className='animate-fade-in items-center bg-[var(--brand-primary-hex)] px-7 py-6 font-[420] font-geist-sans text-lg text-neutral-100 tracking-normal shadow-[var(--brand-primary-hex)]/30 shadow-lg hover:bg-[var(--brand-primary-hover-hex)]'
aria-label='Start using the platform'
>
<div className='text-[1.15rem]'>Start now</div>
@@ -104,7 +104,7 @@ function Hero() {
className='aspect-[5/3] h-auto md:aspect-auto'
>
<g filter='url(#filter0_b_0_1)'>
<ellipse cx='300' cy='240' rx='290' ry='220' fill='#0C0C0C' />
<ellipse cx='300' cy='240' rx='290' ry='220' fill='var(--brand-background-hex)' />
</g>
<defs>
<filter

View File

@@ -151,7 +151,7 @@ export default function ContributorsPage() {
)
return (
<main className='relative min-h-screen bg-[#0C0C0C] font-geist-sans text-white'>
<main className='relative min-h-screen bg-[var(--brand-background-hex)] font-geist-sans text-white'>
{/* Grid pattern background */}
<div className='absolute inset-0 bottom-[400px] z-0'>
<GridPattern
@@ -239,7 +239,7 @@ export default function ContributorsPage() {
<div className='mb-6 grid grid-cols-1 gap-3 sm:mb-8 sm:grid-cols-2 sm:gap-4 lg:grid-cols-5'>
<div className='rounded-lg border border-[#606060]/20 bg-neutral-800/30 p-3 text-center sm:rounded-xl sm:p-4'>
<div className='mb-1 flex items-center justify-center sm:mb-2'>
<Star className='h-4 w-4 text-[#701ffc] sm:h-5 sm:w-5' />
<Star className='h-4 w-4 text-[var(--brand-primary-hex)] sm:h-5 sm:w-5' />
</div>
<div className='font-bold text-lg text-white sm:text-xl'>{repoStats.stars}</div>
<div className='text-neutral-400 text-xs'>Stars</div>
@@ -247,7 +247,7 @@ export default function ContributorsPage() {
<div className='rounded-lg border border-[#606060]/20 bg-neutral-800/30 p-3 text-center sm:rounded-xl sm:p-4'>
<div className='mb-1 flex items-center justify-center sm:mb-2'>
<GitFork className='h-4 w-4 text-[#701ffc] sm:h-5 sm:w-5' />
<GitFork className='h-4 w-4 text-[var(--brand-primary-hex)] sm:h-5 sm:w-5' />
</div>
<div className='font-bold text-lg text-white sm:text-xl'>{repoStats.forks}</div>
<div className='text-neutral-400 text-xs'>Forks</div>
@@ -255,7 +255,7 @@ export default function ContributorsPage() {
<div className='rounded-lg border border-[#606060]/20 bg-neutral-800/30 p-3 text-center sm:rounded-xl sm:p-4'>
<div className='mb-1 flex items-center justify-center sm:mb-2'>
<GitGraph className='h-4 w-4 text-[#701ffc] sm:h-5 sm:w-5' />
<GitGraph className='h-4 w-4 text-[var(--brand-primary-hex)] sm:h-5 sm:w-5' />
</div>
<div className='font-bold text-lg text-white sm:text-xl'>
{filteredContributors?.length || 0}
@@ -265,7 +265,7 @@ export default function ContributorsPage() {
<div className='rounded-lg border border-[#606060]/20 bg-neutral-800/30 p-3 text-center sm:rounded-xl sm:p-4'>
<div className='mb-1 flex items-center justify-center sm:mb-2'>
<MessageCircle className='h-4 w-4 text-[#701ffc] sm:h-5 sm:w-5' />
<MessageCircle className='h-4 w-4 text-[var(--brand-primary-hex)] sm:h-5 sm:w-5' />
</div>
<div className='font-bold text-lg text-white sm:text-xl'>
{repoStats.openIssues}
@@ -275,7 +275,7 @@ export default function ContributorsPage() {
<div className='rounded-lg border border-[#606060]/20 bg-neutral-800/30 p-3 text-center sm:rounded-xl sm:p-4'>
<div className='mb-1 flex items-center justify-center sm:mb-2'>
<GitPullRequest className='h-4 w-4 text-[#701ffc] sm:h-5 sm:w-5' />
<GitPullRequest className='h-4 w-4 text-[var(--brand-primary-hex)] sm:h-5 sm:w-5' />
</div>
<div className='font-bold text-lg text-white sm:text-xl'>{repoStats.openPRs}</div>
<div className='text-neutral-400 text-xs'>Pull Requests</div>
@@ -291,8 +291,8 @@ export default function ContributorsPage() {
<AreaChart data={timelineData} className='-mx-2 sm:-mx-5 mt-1 sm:mt-2'>
<defs>
<linearGradient id='commits' x1='0' y1='0' x2='0' y2='1'>
<stop offset='5%' stopColor='#701ffc' stopOpacity={0.3} />
<stop offset='95%' stopColor='#701ffc' stopOpacity={0} />
<stop offset='5%' stopColor='var(--brand-primary-hex)' stopOpacity={0.3} />
<stop offset='95%' stopColor='var(--brand-primary-hex)' stopOpacity={0} />
</linearGradient>
</defs>
<XAxis
@@ -320,7 +320,7 @@ export default function ContributorsPage() {
<div className='rounded-lg border border-[#606060]/30 bg-[#0f0f0f] p-2 shadow-lg backdrop-blur-sm sm:p-3'>
<div className='grid gap-1 sm:gap-2'>
<div className='flex items-center gap-1 sm:gap-2'>
<GitGraph className='h-3 w-3 text-[#701ffc] sm:h-4 sm:w-4' />
<GitGraph className='h-3 w-3 text-[var(--brand-primary-hex)] sm:h-4 sm:w-4' />
<span className='text-neutral-400 text-xs sm:text-sm'>
Commits:
</span>
@@ -338,7 +338,7 @@ export default function ContributorsPage() {
<Area
type='monotone'
dataKey='commits'
stroke='#701ffc'
stroke='var(--brand-primary-hex)'
strokeWidth={2}
fill='url(#commits)'
/>
@@ -393,7 +393,7 @@ export default function ContributorsPage() {
animate={{ opacity: 1, y: 0 }}
style={{ animationDelay: `${index * 50}ms` }}
>
<Avatar className='h-12 w-12 ring-2 ring-[#606060]/30 transition-transform group-hover:scale-105 group-hover:ring-[#701ffc]/60 sm:h-16 sm:w-16'>
<Avatar className='h-12 w-12 ring-2 ring-[#606060]/30 transition-transform group-hover:scale-105 group-hover:ring-[var(--brand-primary-hex)]/60 sm:h-16 sm:w-16'>
<AvatarImage
src={contributor.avatar_url}
alt={contributor.login}
@@ -405,13 +405,13 @@ export default function ContributorsPage() {
</Avatar>
<div className='mt-2 text-center sm:mt-3'>
<span className='block font-medium text-white text-xs transition-colors group-hover:text-[#701ffc] sm:text-sm'>
<span className='block font-medium text-white text-xs transition-colors group-hover:text-[var(--brand-primary-hex)] sm:text-sm'>
{contributor.login.length > 12
? `${contributor.login.slice(0, 12)}...`
: contributor.login}
</span>
<div className='mt-1 flex items-center justify-center gap-1 sm:mt-2'>
<GitGraph className='h-2 w-2 text-neutral-400 transition-colors group-hover:text-[#701ffc] sm:h-3 sm:w-3' />
<GitGraph className='h-2 w-2 text-neutral-400 transition-colors group-hover:text-[var(--brand-primary-hex)] sm:h-3 sm:w-3' />
<span className='font-medium text-neutral-300 text-xs transition-colors group-hover:text-white sm:text-sm'>
{contributor.contributions}
</span>
@@ -508,7 +508,7 @@ export default function ContributorsPage() {
/>
<Bar
dataKey='contributions'
className='fill-[#701ffc]'
className='fill-[var(--brand-primary-hex)]'
radius={[4, 4, 0, 0]}
/>
</BarChart>
@@ -532,7 +532,7 @@ export default function ContributorsPage() {
>
<div className='relative p-6 sm:p-8 md:p-12 lg:p-16'>
<div className='text-center'>
<div className='mb-4 inline-flex items-center rounded-full border border-[#701ffc]/20 bg-[#701ffc]/10 px-3 py-1 font-medium text-[#701ffc] text-xs sm:mb-6 sm:px-4 sm:py-2 sm:text-sm'>
<div className='mb-4 inline-flex items-center rounded-full border border-[var(--brand-primary-hex)]/20 bg-[var(--brand-primary-hex)]/10 px-3 py-1 font-medium text-[var(--brand-primary-hex)] text-xs sm:mb-6 sm:px-4 sm:py-2 sm:text-sm'>
<Github className='mr-1 h-3 w-3 sm:mr-2 sm:h-4 sm:w-4' />
Apache-2.0 Licensed
</div>
@@ -550,7 +550,7 @@ export default function ContributorsPage() {
<Button
asChild
size='lg'
className='bg-[#701ffc] text-white transition-colors duration-500 hover:bg-[#802FFF]'
className='bg-[var(--brand-primary-hex)] text-white transition-colors duration-500 hover:bg-[var(--brand-primary-hover-hex)]'
>
<a
href='https://github.com/simstudioai/sim/blob/main/.github/CONTRIBUTING.md'

View File

@@ -12,7 +12,7 @@ export default function Landing() {
}
return (
<main className='relative min-h-screen bg-[#0C0C0C] font-geist-sans'>
<main className='relative min-h-screen bg-[var(--brand-background-hex)] font-geist-sans'>
<NavWrapper onOpenTypeformLink={handleOpenTypeformLink} />
<Hero />

View File

@@ -11,7 +11,7 @@ export default function PrivacyPolicy() {
}
return (
<main className='relative min-h-screen overflow-hidden bg-[#0C0C0C] text-white'>
<main className='relative min-h-screen overflow-hidden bg-[var(--brand-background-hex)] text-white'>
{/* Grid pattern background - only covers content area */}
<div className='absolute inset-0 bottom-[400px] z-0 overflow-hidden'>
<GridPattern
@@ -42,7 +42,7 @@ export default function PrivacyPolicy() {
className='h-full w-full'
>
<g filter='url(#filter0_b_privacy)'>
<rect width='600' height='1600' rx='0' fill='#0C0C0C' />
<rect width='600' height='1600' rx='0' fill='var(--brand-background-hex)' />
</g>
<defs>
<filter
@@ -391,7 +391,7 @@ export default function PrivacyPolicy() {
Privacy & Terms web page:{' '}
<Link
href='https://policies.google.com/privacy?hl=en'
className='text-[#B5A1D4] hover:text-[#701ffc]'
className='text-[#B5A1D4] hover:text-[var(--brand-primary-hex)]'
target='_blank'
rel='noopener noreferrer'
>
@@ -569,7 +569,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-[#701ffc] border-l-4 bg-[#701ffc]/10 p-3'>
<p className='mb-4 border-[var(--brand-primary-hex)] border-l-4 bg-[var(--brand-primary-hex)]/10 p-3'>
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).
@@ -661,7 +661,7 @@ export default function PrivacyPolicy() {
policy (if any). Before beginning your inquiry, email us at{' '}
<Link
href='mailto:security@sim.ai'
className='text-[#B5A1D4] hover:text-[#701ffc]'
className='text-[#B5A1D4] hover:text-[var(--brand-primary-hex)]'
>
security@sim.ai
</Link>{' '}
@@ -686,7 +686,7 @@ export default function PrivacyPolicy() {
To report any security flaws, send an email to{' '}
<Link
href='mailto:security@sim.ai'
className='text-[#B5A1D4] hover:text-[#701ffc]'
className='text-[#B5A1D4] hover:text-[var(--brand-primary-hex)]'
>
security@sim.ai
</Link>
@@ -726,7 +726,7 @@ export default function PrivacyPolicy() {
If you have any questions about this Privacy Policy, please contact us at:{' '}
<Link
href='mailto:privacy@sim.ai'
className='text-[#B5A1D4] hover:text-[#701ffc]'
className='text-[#B5A1D4] hover:text-[var(--brand-primary-hex)]'
>
privacy@sim.ai
</Link>

View File

@@ -11,7 +11,7 @@ export default function TermsOfService() {
}
return (
<main className='relative min-h-screen overflow-hidden bg-[#0C0C0C] text-white'>
<main className='relative min-h-screen overflow-hidden bg-[var(--brand-background-hex)] text-white'>
{/* Grid pattern background */}
<div className='absolute inset-0 bottom-[400px] z-0 overflow-hidden'>
<GridPattern
@@ -42,7 +42,7 @@ export default function TermsOfService() {
className='h-full w-full'
>
<g filter='url(#filter0_b_terms)'>
<rect width='600' height='1600' rx='0' fill='#0C0C0C' />
<rect width='600' height='1600' rx='0' fill='var(--brand-background-hex)' />
</g>
<defs>
<filter
@@ -268,7 +268,7 @@ export default function TermsOfService() {
Arbitration Agreement. The arbitration will be conducted by JAMS, an established
alternative dispute resolution provider.
</p>
<p className='mb-4 border-[#701ffc] border-l-4 bg-[#701ffc]/10 p-3'>
<p className='mb-4 border-[var(--brand-primary-hex)] border-l-4 bg-[var(--brand-primary-hex)]/10 p-3'>
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
@@ -277,7 +277,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-[#B5A1D4] hover:text-[#701ffc]'>
<Link
href='mailto:legal@sim.ai'
className='text-[#B5A1D4] hover:text-[var(--brand-primary-hex)]'
>
legal@sim.ai{' '}
</Link>
within 30 days after first becoming subject to this Arbitration Agreement.
@@ -330,7 +333,7 @@ export default function TermsOfService() {
Our Copyright Agent can be reached at:{' '}
<Link
href='mailto:copyright@sim.ai'
className='text-[#B5A1D4] hover:text-[#701ffc]'
className='text-[#B5A1D4] hover:text-[var(--brand-primary-hex)]'
>
copyright@sim.ai
</Link>
@@ -341,7 +344,10 @@ export default function TermsOfService() {
<h2 className='mb-4 font-semibold text-2xl text-white'>12. Contact Us</h2>
<p>
If you have any questions about these Terms, please contact us at:{' '}
<Link href='mailto:legal@sim.ai' className='text-[#B5A1D4] hover:text-[#701ffc]'>
<Link
href='mailto:legal@sim.ai'
className='text-[#B5A1D4] hover:text-[var(--brand-primary-hex)]'
>
legal@sim.ai
</Link>
</p>

View File

@@ -150,7 +150,7 @@ export async function POST(request: NextRequest) {
// Merge customizations with the additional fields
const mergedCustomizations = {
...(customizations || {}),
primaryColor: customizations?.primaryColor || '#802FFF',
primaryColor: customizations?.primaryColor || 'var(--brand-primary-hover-hex)',
welcomeMessage: customizations?.welcomeMessage || 'Hi there! How can I help you today?',
}

View File

@@ -429,7 +429,8 @@ export default function ChatClient({ subdomain }: { subdomain: string }) {
if (authRequired) {
// Get title and description from the URL params or use defaults
const title = new URLSearchParams(window.location.search).get('title') || 'chat'
const primaryColor = new URLSearchParams(window.location.search).get('color') || '#802FFF'
const primaryColor =
new URLSearchParams(window.location.search).get('color') || 'var(--brand-primary-hover-hex)'
if (authRequired === 'password') {
return (

View File

@@ -18,7 +18,7 @@ export default function EmailAuth({
subdomain,
onAuthSuccess,
title = 'chat',
primaryColor = '#802FFF',
primaryColor = 'var(--brand-primary-hover-hex)',
}: EmailAuthProps) {
// Email auth state
const [email, setEmail] = useState('')
@@ -149,10 +149,10 @@ export default function EmailAuth({
xmlns='http://www.w3.org/2000/svg'
className='rounded-[6px]'
>
<rect width='50' height='50' fill='#701FFC' />
<rect width='50' height='50' fill='var(--brand-primary-hex)' />
<path
d='M34.1455 20.0728H16.0364C12.7026 20.0728 10 22.7753 10 26.1091V35.1637C10 38.4975 12.7026 41.2 16.0364 41.2H34.1455C37.4792 41.2 40.1818 38.4975 40.1818 35.1637V26.1091C40.1818 22.7753 37.4792 20.0728 34.1455 20.0728Z'
fill='#701FFC'
fill='var(--brand-primary-hex)'
stroke='white'
strokeWidth='3.5'
strokeLinecap='round'
@@ -160,7 +160,7 @@ export default function EmailAuth({
/>
<path
d='M25.0919 14.0364C26.7588 14.0364 28.1101 12.6851 28.1101 11.0182C28.1101 9.35129 26.7588 8 25.0919 8C23.425 8 22.0737 9.35129 22.0737 11.0182C22.0737 12.6851 23.425 14.0364 25.0919 14.0364Z'
fill='#701FFC'
fill='var(--brand-primary-hex)'
stroke='white'
strokeWidth='4'
strokeLinecap='round'
@@ -168,7 +168,7 @@ export default function EmailAuth({
/>
<path
d='M25.0915 14.856V19.0277V14.856ZM20.5645 32.1398V29.1216V32.1398ZM29.619 29.1216V32.1398V29.1216Z'
fill='#701FFC'
fill='var(--brand-primary-hex)'
/>
<path
d='M25.0915 14.856V19.0277M20.5645 32.1398V29.1216M29.619 29.1216V32.1398'
@@ -177,7 +177,7 @@ export default function EmailAuth({
strokeLinecap='round'
strokeLinejoin='round'
/>
<circle cx='25' cy='11' r='2' fill='#701FFC' />
<circle cx='25' cy='11' r='2' fill='var(--brand-primary-hex)' />
</svg>
</a>
</div>

View File

@@ -17,7 +17,7 @@ export default function PasswordAuth({
subdomain,
onAuthSuccess,
title = 'chat',
primaryColor = '#802FFF',
primaryColor = 'var(--brand-primary-hover-hex)',
}: PasswordAuthProps) {
// Password auth state
const [password, setPassword] = useState('')
@@ -91,10 +91,10 @@ export default function PasswordAuth({
xmlns='http://www.w3.org/2000/svg'
className='rounded-[6px]'
>
<rect width='50' height='50' fill='#701FFC' />
<rect width='50' height='50' fill='var(--brand-primary-hex)' />
<path
d='M34.1455 20.0728H16.0364C12.7026 20.0728 10 22.7753 10 26.1091V35.1637C10 38.4975 12.7026 41.2 16.0364 41.2H34.1455C37.4792 41.2 40.1818 38.4975 40.1818 35.1637V26.1091C40.1818 22.7753 37.4792 20.0728 34.1455 20.0728Z'
fill='#701FFC'
fill='var(--brand-primary-hex)'
stroke='white'
strokeWidth='3.5'
strokeLinecap='round'
@@ -102,7 +102,7 @@ export default function PasswordAuth({
/>
<path
d='M25.0919 14.0364C26.7588 14.0364 28.1101 12.6851 28.1101 11.0182C28.1101 9.35129 26.7588 8 25.0919 8C23.425 8 22.0737 9.35129 22.0737 11.0182C22.0737 12.6851 23.425 14.0364 25.0919 14.0364Z'
fill='#701FFC'
fill='var(--brand-primary-hex)'
stroke='white'
strokeWidth='4'
strokeLinecap='round'
@@ -110,7 +110,7 @@ export default function PasswordAuth({
/>
<path
d='M25.0915 14.856V19.0277V14.856ZM20.5645 32.1398V29.1216V32.1398ZM29.619 29.1216V32.1398V29.1216Z'
fill='#701FFC'
fill='var(--brand-primary-hex)'
/>
<path
d='M25.0915 14.856V19.0277M20.5645 32.1398V29.1216M29.619 29.1216V32.1398'
@@ -119,7 +119,7 @@ export default function PasswordAuth({
strokeLinecap='round'
strokeLinejoin='round'
/>
<circle cx='25' cy='11' r='2' fill='#701FFC' />
<circle cx='25' cy='11' r='2' fill='var(--brand-primary-hex)' />
</svg>
</a>
</div>

View File

@@ -21,10 +21,10 @@ export function ChatErrorState({ error, starCount }: ChatErrorStateProps) {
xmlns='http://www.w3.org/2000/svg'
className='rounded-[6px]'
>
<rect width='50' height='50' fill='#701FFC' />
<rect width='50' height='50' fill='var(--brand-primary-hex)' />
<path
d='M34.1455 20.0728H16.0364C12.7026 20.0728 10 22.7753 10 26.1091V35.1637C10 38.4975 12.7026 41.2 16.0364 41.2H34.1455C37.4792 41.2 40.1818 38.4975 40.1818 35.1637V26.1091C40.1818 22.7753 37.4792 20.0728 34.1455 20.0728Z'
fill='#701FFC'
fill='var(--brand-primary-hex)'
stroke='white'
strokeWidth='3.5'
strokeLinecap='round'
@@ -32,7 +32,7 @@ export function ChatErrorState({ error, starCount }: ChatErrorStateProps) {
/>
<path
d='M25.0919 14.0364C26.7588 14.0364 28.1101 12.6851 28.1101 11.0182C28.1101 9.35129 26.7588 8 25.0919 8C23.425 8 22.0737 9.35129 22.0737 11.0182C22.0737 12.6851 23.425 14.0364 25.0919 14.0364Z'
fill='#701FFC'
fill='var(--brand-primary-hex)'
stroke='white'
strokeWidth='4'
strokeLinecap='round'
@@ -40,7 +40,7 @@ export function ChatErrorState({ error, starCount }: ChatErrorStateProps) {
/>
<path
d='M25.0915 14.856V19.0277V14.856ZM20.5645 32.1398V29.1216V32.1398ZM29.619 29.1216V32.1398V29.1216Z'
fill='#701FFC'
fill='var(--brand-primary-hex)'
/>
<path
d='M25.0915 14.856V19.0277M20.5645 32.1398V29.1216M29.619 29.1216V32.1398'
@@ -49,7 +49,7 @@ export function ChatErrorState({ error, starCount }: ChatErrorStateProps) {
strokeLinecap='round'
strokeLinejoin='round'
/>
<circle cx='25' cy='11' r='2' fill='#701FFC' />
<circle cx='25' cy='11' r='2' fill='var(--brand-primary-hex)' />
</svg>
</a>
<ChatHeader chatConfig={null} starCount={starCount} />

View File

@@ -16,7 +16,7 @@ interface ChatHeaderProps {
}
export function ChatHeader({ chatConfig, starCount }: ChatHeaderProps) {
const primaryColor = chatConfig?.customizations?.primaryColor || '#701FFC'
const primaryColor = chatConfig?.customizations?.primaryColor || 'var(--brand-primary-hex)'
const customImage = chatConfig?.customizations?.imageUrl || chatConfig?.customizations?.logoUrl
return (

View File

@@ -93,6 +93,17 @@
/* Gradient Colors */
--gradient-primary: 263 85% 70%; /* More vibrant purple */
--gradient-secondary: 336 95% 65%; /* More vibrant pink */
/* Brand Colors (Default Sim Theme) */
--brand-primary-hex: #701ffc; /* Primary brand purple */
--brand-primary-hover-hex: #802fff; /* Primary brand purple hover */
--brand-secondary-hex: #6518e6; /* Secondary brand purple */
--brand-accent-hex: #9d54ff; /* Accent purple for links */
--brand-accent-hover-hex: #a66fff; /* Accent purple hover */
--brand-background-hex: #0c0c0c; /* Primary dark background */
/* UI Surface Colors */
--surface-elevated: #202020; /* Elevated surface background for dark mode */
}
/* Dark Mode Theme */
@@ -153,6 +164,17 @@
/* Gradient Colors - Adjusted for dark mode */
--gradient-primary: 263 90% 75%; /* More vibrant purple for dark mode */
--gradient-secondary: 336 100% 72%; /* More vibrant pink for dark mode */
/* Brand Colors (Same in dark mode) */
--brand-primary-hex: #701ffc; /* Primary brand purple */
--brand-primary-hover-hex: #802fff; /* Primary brand purple hover */
--brand-secondary-hex: #6518e6; /* Secondary brand purple */
--brand-accent-hex: #9d54ff; /* Accent purple for links */
--brand-accent-hover-hex: #a66fff; /* Accent purple hover */
--brand-background-hex: #0c0c0c; /* Primary dark background */
/* UI Surface Colors */
--surface-elevated: #202020; /* Elevated surface background for dark mode */
}
}
@@ -340,6 +362,60 @@ input[type="search"]::-ms-clear {
background-clip: text;
}
/* Brand Color Utilities */
.bg-brand-primary {
background-color: var(--brand-primary-hex);
}
.bg-brand-primary-hover {
background-color: var(--brand-primary-hover-hex);
}
.bg-brand-secondary {
background-color: var(--brand-secondary-hex);
}
.bg-brand-accent {
background-color: var(--brand-accent-hex);
}
.bg-brand-background {
background-color: var(--brand-background-hex);
}
.text-brand-primary {
color: var(--brand-primary-hex);
}
.text-brand-accent {
color: var(--brand-accent-hex);
}
.text-brand-accent-hover {
color: var(--brand-accent-hover-hex);
}
.border-brand-primary {
border-color: var(--brand-primary-hex);
}
.hover\:bg-brand-primary-hover:hover {
background-color: var(--brand-primary-hover-hex);
}
.hover\:bg-brand-secondary:hover {
background-color: var(--brand-secondary-hex);
}
.hover\:text-brand-accent-hover:hover {
color: var(--brand-accent-hover-hex);
}
/* Surface Utilities */
.bg-surface-elevated {
background-color: var(--surface-elevated);
}
/* Animation Classes */
.animate-pulse-ring {
animation: pulse-ring 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;

View File

@@ -11,8 +11,8 @@ export default function manifest(): MetadataRoute.Manifest {
'Build and deploy AI agents using our Figma-like canvas. Build, write evals, and deploy AI agent workflows that automate workflows and streamline your business processes.',
start_url: '/',
display: 'standalone',
background_color: brand.primaryColor || '#ffffff',
theme_color: brand.primaryColor || '#ffffff',
background_color: '#701FFC', // Default Sim brand primary color
theme_color: '#701FFC', // Default Sim brand primary color
icons: [
{
src: '/favicon/android-chrome-192x192.png',

View File

@@ -166,7 +166,7 @@ function UnsubscribeContent() {
'_blank'
)
}
className='w-full bg-[#701ffc] font-medium text-white shadow-sm transition-colors duration-200 hover:bg-[#802FFF]'
className='w-full bg-[var(--brand-primary-hex)] font-medium text-white shadow-sm transition-colors duration-200 hover:bg-[var(--brand-primary-hover-hex)]'
>
Contact Support
</Button>

View File

@@ -192,7 +192,7 @@ export function CreateChunkModal({
<Button
onClick={handleCreateChunk}
disabled={!isFormValid || isCreating}
className='bg-[#701FFC] font-[480] text-primary-foreground shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
className='bg-[var(--brand-primary-hex)] font-[480] text-primary-foreground shadow-[0_0_0_0_var(--brand-primary-hex)] transition-all duration-200 hover:bg-[var(--brand-secondary-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
>
{isCreating ? (
<>

View File

@@ -66,7 +66,7 @@ export function DocumentLoading({
<Button
disabled
size='sm'
className='flex items-center gap-1 bg-[#701FFC] font-[480] text-primary-foreground shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:opacity-50'
className='flex items-center gap-1 bg-[var(--brand-primary-hex)] font-[480] text-primary-foreground shadow-[0_0_0_0_var(--brand-primary-hex)] transition-all duration-200 hover:bg-[var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:opacity-50'
>
<Plus className='h-3.5 w-3.5' />
<span>Create Chunk</span>

View File

@@ -312,7 +312,7 @@ export function EditChunkModal({
<Button
onClick={handleSaveContent}
disabled={!isFormValid || isSaving || !hasUnsavedChanges || isNavigating}
className='bg-[#701FFC] font-[480] text-primary-foreground shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
className='bg-[var(--brand-primary-hex)] font-[480] text-primary-foreground shadow-[0_0_0_0_var(--brand-primary-hex)] transition-all duration-200 hover:bg-[var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
>
{isSaving ? (
<>

View File

@@ -314,7 +314,7 @@ export function Document({
onCheckedChange={(checked) => handleSelectChunk(chunk.id, checked as boolean)}
disabled={!userPermissions.canEdit}
aria-label={`Select chunk ${chunk.chunkIndex}`}
className='h-3.5 w-3.5 border-gray-300 focus-visible:ring-[#701FFC]/20 data-[state=checked]:border-[#701FFC] data-[state=checked]:bg-[#701FFC] [&>*]:h-3 [&>*]:w-3'
className='h-3.5 w-3.5 border-gray-300 focus-visible:ring-[var(--brand-primary-hex)]/20 data-[state=checked]:border-[var(--brand-primary-hex)] data-[state=checked]:bg-[var(--brand-primary-hex)] [&>*]:h-3 [&>*]:w-3'
onClick={(e) => e.stopPropagation()}
/>
</td>
@@ -685,7 +685,7 @@ export function Document({
onClick={() => setIsCreateChunkModalOpen(true)}
disabled={documentData?.processingStatus === 'failed' || !userPermissions.canEdit}
size='sm'
className='flex items-center gap-1 bg-[#701FFC] font-[480] text-white shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:cursor-not-allowed disabled:opacity-50'
className='flex items-center gap-1 bg-[var(--brand-primary-hex)] font-[480] text-white shadow-[0_0_0_0_var(--brand-primary-hex)] transition-all duration-200 hover:bg-[var(--brand-secondary-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:cursor-not-allowed disabled:opacity-50'
>
<Plus className='h-3.5 w-3.5' />
<span>Create Chunk</span>
@@ -726,7 +726,7 @@ export function Document({
!userPermissions.canEdit
}
aria-label='Select all chunks'
className='h-3.5 w-3.5 border-gray-300 focus-visible:ring-[#701FFC]/20 data-[state=checked]:border-[#701FFC] data-[state=checked]:bg-[#701FFC] [&>*]:h-3 [&>*]:w-3'
className='h-3.5 w-3.5 border-gray-300 focus-visible:ring-[var(--brand-primary-hex)]/20 data-[state=checked]:border-[var(--brand-primary-hex)] data-[state=checked]:bg-[var(--brand-primary-hex)] [&>*]:h-3 [&>*]:w-3'
/>
</th>
<th className='px-4 pt-2 pb-3 text-left font-medium'>

View File

@@ -86,7 +86,7 @@ const getStatusDisplay = (doc: DocumentData) => {
</>
),
className:
'inline-flex items-center rounded-md bg-[#701FFC]/10 px-2 py-1 text-xs font-medium text-[#701FFC] dark:bg-[#701FFC]/20 dark:text-[#8B5FFF]',
'inline-flex items-center rounded-md bg-[var(--brand-primary-hex)]/10 px-2 py-1 text-xs font-medium text-[var(--brand-primary-hex)] dark:bg-[var(--brand-primary-hex)]/20 dark:text-[var(--brand-primary-hex)]',
}
case 'failed':
return {
@@ -729,7 +729,7 @@ export function KnowledgeBase({
onCheckedChange={handleSelectAll}
disabled={!userPermissions.canEdit}
aria-label='Select all documents'
className='h-3.5 w-3.5 border-gray-300 focus-visible:ring-[#701FFC]/20 data-[state=checked]:border-[#701FFC] data-[state=checked]:bg-[#701FFC] [&>*]:h-3 [&>*]:w-3'
className='h-3.5 w-3.5 border-gray-300 focus-visible:ring-[var(--brand-primary-hex)]/20 data-[state=checked]:border-[var(--brand-primary-hex)] data-[state=checked]:bg-[var(--brand-primary-hex)] [&>*]:h-3 [&>*]:w-3'
/>
</th>
<th className='px-4 pt-2 pb-3 text-left font-medium'>
@@ -886,7 +886,7 @@ export function KnowledgeBase({
disabled={!userPermissions.canEdit}
onClick={(e) => e.stopPropagation()}
aria-label={`Select ${doc.filename}`}
className='h-3.5 w-3.5 border-gray-300 focus-visible:ring-[#701FFC]/20 data-[state=checked]:border-[#701FFC] data-[state=checked]:bg-[#701FFC] [&>*]:h-3 [&>*]:w-3'
className='h-3.5 w-3.5 border-gray-300 focus-visible:ring-[var(--brand-primary-hex)]/20 data-[state=checked]:border-[var(--brand-primary-hex)] data-[state=checked]:bg-[var(--brand-primary-hex)] [&>*]:h-3 [&>*]:w-3'
/>
</td>

View File

@@ -57,7 +57,7 @@ export function KnowledgeBaseLoading({ knowledgeBaseName }: KnowledgeBaseLoading
<Button
disabled
size='sm'
className='flex items-center gap-1 bg-[#701FFC] font-[480] text-primary-foreground shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:opacity-50'
className='flex items-center gap-1 bg-[var(--brand-primary-hex)] font-[480] text-primary-foreground shadow-[0_0_0_0_var(--brand-primary-hex)] transition-all duration-200 hover:bg-[var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:opacity-50'
>
<div className='h-3.5 w-3.5 animate-pulse rounded bg-primary-foreground/30' />
<span>Add Documents</span>

View File

@@ -612,7 +612,7 @@ export function CreateModal({ open, onOpenChange, onKnowledgeBaseCreated }: Crea
<Button
type='submit'
disabled={isSubmitting}
className='bg-[#701FFC] font-[480] text-primary-foreground shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
className='bg-[var(--brand-primary-hex)] font-[480] text-primary-foreground shadow-[0_0_0_0_var(--brand-primary-hex)] transition-all duration-200 hover:bg-[var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
>
{isSubmitting ? 'Creating...' : 'Create Knowledge Base'}
</Button>

View File

@@ -27,7 +27,7 @@ export function PrimaryButton({
disabled={disabled}
size={size}
className={cn(
'flex items-center gap-1 bg-[#701FFC] font-[480] text-white shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]',
'flex items-center gap-1 bg-[var(--brand-primary-hex)] font-[480] text-white shadow-[0_0_0_0_var(--brand-primary-hex)] transition-all duration-200 hover:bg-[var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]',
disabled && 'disabled:cursor-not-allowed disabled:opacity-50',
className
)}

View File

@@ -33,7 +33,7 @@ export function SearchInput({
/>
{isLoading ? (
<div className='-translate-y-1/2 absolute top-1/2 right-3'>
<div className='h-[18px] w-[18px] animate-spin rounded-full border-2 border-gray-300 border-t-[#701FFC]' />
<div className='h-[18px] w-[18px] animate-spin rounded-full border-2 border-gray-300 border-t-[var(--brand-primary-hex)]' />
</div>
) : (
value &&

View File

@@ -37,7 +37,7 @@ export default function KnowledgeLoading() {
<Button
disabled
size='sm'
className='flex items-center gap-1 bg-[#701FFC] font-[480] text-primary-foreground shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:opacity-50'
className='flex items-center gap-1 bg-[var(--brand-primary-hex)] font-[480] text-primary-foreground shadow-[0_0_0_0_var(--brand-primary-hex)] transition-all duration-200 hover:bg-[var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:opacity-50'
>
<Plus className='h-3.5 w-3.5' />
<span>Create</span>

View File

@@ -97,7 +97,7 @@ export default function FolderFilter() {
<Button
variant='outline'
size='sm'
className='w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[#202020]'
className='w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
{loading ? 'Loading folders...' : getSelectedFoldersText()}
<ChevronDown className='ml-2 h-4 w-4 text-muted-foreground' />
@@ -105,7 +105,7 @@ export default function FolderFilter() {
</DropdownMenuTrigger>
<DropdownMenuContent
align='start'
className='max-h-[300px] w-[200px] overflow-y-auto rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[#202020]'
className='max-h-[300px] w-[200px] overflow-y-auto rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
<DropdownMenuItem
key='all'

View File

@@ -29,7 +29,7 @@ export default function Level() {
<Button
variant='outline'
size='sm'
className='w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[#202020]'
className='w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
{getDisplayLabel()}
<ChevronDown className='ml-2 h-4 w-4 text-muted-foreground' />
@@ -37,7 +37,7 @@ export default function Level() {
</DropdownMenuTrigger>
<DropdownMenuContent
align='start'
className='w-[180px] rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[#202020]'
className='w-[180px] rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
<DropdownMenuItem
key='all'

View File

@@ -20,7 +20,7 @@ export default function Timeline() {
<Button
variant='outline'
size='sm'
className='w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[#202020]'
className='w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
{timeRange}
<ChevronDown className='ml-2 h-4 w-4 text-muted-foreground' />
@@ -28,7 +28,7 @@ export default function Timeline() {
</DropdownMenuTrigger>
<DropdownMenuContent
align='start'
className='w-[180px] rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[#202020]'
className='w-[180px] rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
<DropdownMenuItem
key='all'

View File

@@ -46,7 +46,7 @@ export default function Trigger() {
<Button
variant='outline'
size='sm'
className='w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[#202020]'
className='w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
{getSelectedTriggersText()}
<ChevronDown className='ml-2 h-4 w-4 text-muted-foreground' />
@@ -54,7 +54,7 @@ export default function Trigger() {
</DropdownMenuTrigger>
<DropdownMenuContent
align='start'
className='w-[180px] rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[#202020]'
className='w-[180px] rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
<DropdownMenuItem
key='all'

View File

@@ -72,7 +72,7 @@ export default function Workflow() {
<Button
variant='outline'
size='sm'
className='w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[#202020]'
className='w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
{loading ? 'Loading workflows...' : getSelectedWorkflowsText()}
<ChevronDown className='ml-2 h-4 w-4 text-muted-foreground' />
@@ -80,7 +80,7 @@ export default function Workflow() {
</DropdownMenuTrigger>
<DropdownMenuContent
align='start'
className='max-h-[300px] w-[180px] overflow-y-auto rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[#202020]'
className='max-h-[300px] w-[180px] overflow-y-auto rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
style={{
scrollbarWidth: 'none',
msOverflowStyle: 'none',

View File

@@ -393,7 +393,7 @@ function TraceSpanItem({
// Block type specific icons
if (type === 'agent') {
return <AgentIcon className='h-3 w-3 text-[#802FFF]' />
return <AgentIcon className='h-3 w-3 text-[var(--brand-primary-hover-hex)]' />
}
if (type === 'evaluator') {
@@ -437,7 +437,7 @@ function TraceSpanItem({
const getSpanColor = (type: string) => {
switch (type.toLowerCase()) {
case 'agent':
return '#802FFF' // Purple from AgentBlock
return 'var(--brand-primary-hover-hex)' // Purple from AgentBlock
case 'provider':
return '#818cf8' // Indigo for provider
case 'model':

View File

@@ -458,8 +458,10 @@ export default function Logs() {
</Tooltip>
<Button
className={`group h-9 gap-2 rounded-[11px] border bg-card text-card-foreground shadow-xs transition-all duration-200 hover:border-[#701FFC] hover:bg-[#701FFC] hover:text-white ${
isLive ? 'border-[#701FFC] bg-[#701FFC] text-white' : 'border-border'
className={`group h-9 gap-2 rounded-[11px] border bg-card text-card-foreground shadow-xs transition-all duration-200 hover:border-[var(--brand-primary-hex)] hover:bg-[var(--brand-primary-hex)] hover:text-white ${
isLive
? 'border-[var(--brand-primary-hex)] bg-[var(--brand-primary-hex)] text-white'
: 'border-border'
}`}
onClick={toggleLive}
>

View File

@@ -412,8 +412,8 @@ export function TemplateCard({
onClick={handleUseClick}
className={cn(
'rounded-[8px] px-3 py-1 font-medium font-sans text-white text-xs transition-[background-color,box-shadow] duration-200',
'bg-[#701FFC] hover:bg-[#6518E6]',
'shadow-[0_0_0_0_#701FFC] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
'bg-[var(--brand-primary-hex)] hover:bg-[var(--brand-primary-hover-hex)]',
'shadow-[0_0_0_0_var(--brand-primary-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
)}
>
Use

View File

@@ -234,7 +234,7 @@ export default function Templates({ initialTemplates, currentUserId }: Templates
</div>
{/* <Button
onClick={handleCreateNew}
className='flex h-9 items-center gap-2 rounded-lg bg-[#701FFC] px-4 py-2 font-normal font-sans text-sm text-white hover:bg-[#601EE0]'
className='flex h-9 items-center gap-2 rounded-lg bg-[var(--brand-primary-hex)] px-4 py-2 font-normal font-sans text-sm text-white hover:bg-[#601EE0]'
>
<Plus className='h-4 w-4' />
Create New

View File

@@ -79,7 +79,7 @@ export function useChatDeployment() {
title: formData.title.trim(),
description: formData.description.trim(),
customizations: {
primaryColor: '#802FFF',
primaryColor: 'var(--brand-primary-hover-hex)',
welcomeMessage: formData.welcomeMessage.trim(),
...(imageUrl && { imageUrl }),
},

View File

@@ -512,10 +512,10 @@ export function DeployModal({
disabled={isSubmitting || (!keysLoaded && !apiKeys.length)}
className={cn(
'gap-2 font-medium',
'bg-[#802FFF] hover:bg-[#7028E6]',
'shadow-[0_0_0_0_#802FFF] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]',
'bg-[var(--brand-primary-hover-hex)] hover:bg-[var(--brand-primary-hover-hex)]',
'shadow-[0_0_0_0_var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]',
'text-white transition-all duration-200',
'disabled:opacity-50 disabled:hover:bg-[#802FFF] disabled:hover:shadow-none'
'disabled:opacity-50 disabled:hover:bg-[var(--brand-primary-hover-hex)] disabled:hover:shadow-none'
)}
>
{isSubmitting ? (
@@ -569,10 +569,10 @@ export function DeployModal({
disabled={chatSubmitting || !isChatFormValid}
className={cn(
'gap-2 font-medium',
'bg-[#802FFF] hover:bg-[#7028E6]',
'shadow-[0_0_0_0_#802FFF] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]',
'bg-[var(--brand-primary-hover-hex)] hover:bg-[var(--brand-primary-hover-hex)]',
'shadow-[0_0_0_0_var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]',
'text-white transition-all duration-200',
'disabled:opacity-50 disabled:hover:bg-[#802FFF] disabled:hover:shadow-none'
'disabled:opacity-50 disabled:hover:bg-[var(--brand-primary-hover-hex)] disabled:hover:shadow-none'
)}
>
{chatSubmitting ? (

View File

@@ -91,9 +91,9 @@ export function DeploymentControls({
disabled={isDisabled}
className={cn(
'h-12 w-12 rounded-[11px] border bg-card text-card-foreground shadow-xs',
'hover:border-[#701FFC] hover:bg-[#701FFC] hover:text-white',
'hover:border-[var(--brand-primary-hex)] hover:bg-[var(--brand-primary-hex)] hover:text-white',
'transition-all duration-200',
isDeployed && 'text-[#802FFF]',
isDeployed && 'text-[var(--brand-primary-hover-hex)]',
isDisabled &&
'cursor-not-allowed opacity-50 hover:border hover:bg-card hover:text-card-foreground hover:shadow-xs'
)}

View File

@@ -410,10 +410,10 @@ export function TemplateModal({ open, onOpenChange, workflowId }: TemplateModalP
disabled={isSubmitting}
className={cn(
'font-medium',
'bg-[#701FFC] hover:bg-[#6518E6]',
'shadow-[0_0_0_0_#701FFC] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]',
'bg-[var(--brand-primary-hex)] hover:bg-[var(--brand-primary-hover-hex)]',
'shadow-[0_0_0_0_var(--brand-primary-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]',
'text-white transition-all duration-200',
'disabled:opacity-50 disabled:hover:bg-[#701FFC] disabled:hover:shadow-none',
'disabled:opacity-50 disabled:hover:bg-[var(--brand-primary-hex)] disabled:hover:shadow-none',
'h-10 rounded-md px-4 py-2'
)}
>

View File

@@ -642,10 +642,10 @@ export function ControlBar({ hasValidationErrors = false }: ControlBarProps) {
const debugButtonClass = cn(
'h-12 w-12 rounded-[11px] font-medium',
'bg-[#701FFC] hover:bg-[#6518E6]',
'shadow-[0_0_0_0_#701FFC] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]',
'bg-[var(--brand-primary-hex)] hover:bg-[var(--brand-primary-hover-hex)]',
'shadow-[0_0_0_0_var(--brand-primary-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]]',
'text-white transition-all duration-200',
'disabled:opacity-50 disabled:hover:bg-[#701FFC] disabled:hover:shadow-none'
'disabled:opacity-50 disabled:hover:bg-[var(--brand-primary-hex)] disabled:hover:shadow-none'
)
return (
@@ -869,10 +869,10 @@ export function ControlBar({ hasValidationErrors = false }: ControlBarProps) {
<Button
className={cn(
'gap-2 font-medium',
'bg-[#701FFC] hover:bg-[#6518E6]',
'shadow-[0_0_0_0_#701FFC] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]',
'bg-[var(--brand-primary-hex)] hover:bg-[var(--brand-primary-hover-hex)]',
'shadow-[0_0_0_0_var(--brand-primary-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]',
'text-white transition-all duration-200',
'disabled:opacity-50 disabled:hover:bg-[#701FFC] disabled:hover:shadow-none',
'disabled:opacity-50 disabled:hover:bg-[var(--brand-primary-hex)] disabled:hover:shadow-none',
'h-12 rounded-[11px] px-4 py-2'
)}
onClick={handleRunClick}

View File

@@ -648,9 +648,9 @@ export function Chat({ panelWidth, chatMessage, setChatMessage }: ChatProps) {
}}
onKeyDown={handleKeyPress}
placeholder={isDragOver ? 'Drop files here...' : 'Type a message...'}
className={`h-9 flex-1 rounded-lg border-[#E5E5E5] bg-[#FFFFFF] text-muted-foreground shadow-xs focus-visible:ring-0 focus-visible:ring-offset-0 dark:border-[#414141] dark:bg-[#202020] ${
className={`h-9 flex-1 rounded-lg border-[#E5E5E5] bg-[#FFFFFF] text-muted-foreground shadow-xs focus-visible:ring-0 focus-visible:ring-offset-0 dark:border-[#414141] dark:bg-[var(--surface-elevated)] ${
isDragOver
? 'border-[#802FFF] bg-purple-50/50 dark:border-[#802FFF] dark:bg-purple-950/20'
? 'border-[var(--brand-primary-hover-hex)] bg-purple-50/50 dark:border-[var(--brand-primary-hover-hex)] dark:bg-purple-950/20'
: ''
}`}
disabled={!activeWorkflowId || isExecuting || isUploadingFiles}
@@ -664,7 +664,7 @@ export function Chat({ panelWidth, chatMessage, setChatMessage }: ChatProps) {
isExecuting ||
isUploadingFiles
}
className='h-9 w-9 rounded-lg bg-[#802FFF] text-white shadow-[0_0_0_0_#802FFF] transition-all duration-200 hover:bg-[#7028E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
className='h-9 w-9 rounded-lg bg-[var(--brand-primary-hover-hex)] text-white shadow-[0_0_0_0_var(--brand-primary-hover-hex)] transition-all duration-200 hover:bg-[var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
>
<ArrowUp className='h-4 w-4' />
</Button>

View File

@@ -327,8 +327,8 @@ export function OutputSelect({
onClick={() => setIsOutputDropdownOpen(!isOutputDropdownOpen)}
className={`flex h-9 w-full items-center justify-between rounded-[8px] border px-3 py-1.5 font-normal text-sm shadow-xs transition-colors ${
isOutputDropdownOpen
? 'border-[#E5E5E5] bg-[#FFFFFF] text-muted-foreground dark:border-[#414141] dark:bg-[#202020]'
: 'border-[#E5E5E5] bg-[#FFFFFF] text-muted-foreground hover:text-muted-foreground dark:border-[#414141] dark:bg-[#202020]'
? 'border-[#E5E5E5] bg-[#FFFFFF] text-muted-foreground dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
: 'border-[#E5E5E5] bg-[#FFFFFF] text-muted-foreground hover:text-muted-foreground dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
}`}
disabled={workflowOutputs.length === 0 || disabled}
>
@@ -362,7 +362,7 @@ export function OutputSelect({
</button>
{isOutputDropdownOpen && workflowOutputs.length > 0 && (
<div className='absolute left-0 z-50 mt-1 w-full overflow-hidden rounded-[8px] border border-[#E5E5E5] bg-[#FFFFFF] pt-1 shadow-xs dark:border-[#414141] dark:bg-[#202020]'>
<div className='absolute left-0 z-50 mt-1 w-full overflow-hidden rounded-[8px] border border-[#E5E5E5] bg-[#FFFFFF] pt-1 shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'>
<div className='max-h-[230px] overflow-y-auto'>
{Object.entries(groupedOutputs).map(([blockName, outputs]) => (
<div key={blockName}>

View File

@@ -604,10 +604,7 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
<div className='flex justify-end'>
<div className='max-w-[80%]'>
{/* Message content in purple box */}
<div
className='rounded-[10px] px-3 py-2'
style={{ backgroundColor: 'rgba(128, 47, 255, 0.08)' }}
>
<div className='rounded-[10px] bg-[var(--brand-primary-hover-hex)]/[0.08] px-3 py-2'>
<div className='whitespace-pre-wrap break-words font-normal text-base text-foreground leading-relaxed'>
<WordWrap text={message.content} />
</div>

View File

@@ -410,9 +410,9 @@ const UserInput = forwardRef<UserInputRef, UserInputProps>(
<div className={cn('relative flex-none pb-4', className)}>
<div
className={cn(
'rounded-[8px] border border-[#E5E5E5] bg-[#FFFFFF] p-2 shadow-xs transition-all duration-200 dark:border-[#414141] dark:bg-[#202020]',
'rounded-[8px] border border-[#E5E5E5] bg-[#FFFFFF] p-2 shadow-xs transition-all duration-200 dark:border-[#414141] dark:bg-[var(--surface-elevated)]',
isDragging &&
'border-[#802FFF] bg-purple-50/50 dark:border-[#802FFF] dark:bg-purple-950/20'
'border-[var(--brand-primary-hover-hex)] bg-purple-50/50 dark:border-[var(--brand-primary-hover-hex)] dark:bg-purple-950/20'
)}
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
@@ -540,7 +540,7 @@ const UserInput = forwardRef<UserInputRef, UserInputProps>(
onClick={handleSubmit}
disabled={!canSubmit}
size='icon'
className='h-6 w-6 rounded-full bg-[#802FFF] text-white shadow-[0_0_0_0_#802FFF] transition-all duration-200 hover:bg-[#7028E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
className='h-6 w-6 rounded-full bg-[var(--brand-primary-hover-hex)] text-white shadow-[0_0_0_0_var(--brand-primary-hover-hex)] transition-all duration-200 hover:bg-[var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
>
{isLoading ? (
<Loader2 className='h-3 w-3 animate-spin' />

View File

@@ -212,7 +212,7 @@ export function Variables() {
<div className='flex h-full items-center justify-center'>
<Button
onClick={handleAddVariable}
className='h-9 rounded-lg border border-[#E5E5E5] bg-[#FFFFFF] px-3 py-1.5 font-normal text-muted-foreground text-sm shadow-xs transition-colors hover:text-muted-foreground dark:border-[#414141] dark:bg-[#202020] dark:hover:text-muted-foreground'
className='h-9 rounded-lg border border-[#E5E5E5] bg-[#FFFFFF] px-3 py-1.5 font-normal text-muted-foreground text-sm shadow-xs transition-colors hover:text-muted-foreground dark:border-[#414141] dark:bg-[var(--surface-elevated)] dark:hover:text-muted-foreground'
variant='outline'
>
<Plus className='h-4 w-4' />
@@ -243,7 +243,7 @@ export function Variables() {
</DropdownMenuTrigger>
<DropdownMenuContent
align='end'
className='min-w-32 rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[#202020]'
className='min-w-32 rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
<DropdownMenuItem
onClick={() => collaborativeUpdateVariable(variable.id, 'type', 'plain')}
@@ -296,7 +296,7 @@ export function Variables() {
</DropdownMenuTrigger>
<DropdownMenuContent
align='end'
className='min-w-32 rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[#202020]'
className='min-w-32 rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
<DropdownMenuItem
onClick={() => collaborativeDuplicateVariable(variable.id)}
@@ -388,7 +388,7 @@ export function Variables() {
{/* Add Variable Button */}
<Button
onClick={handleAddVariable}
className='mt-2 h-9 w-full rounded-lg border border-[#E5E5E5] bg-[#FFFFFF] px-3 py-1.5 font-[380] text-muted-foreground text-sm shadow-xs transition-colors hover:text-muted-foreground dark:border-[#414141] dark:bg-[#202020] dark:hover:text-muted-foreground'
className='mt-2 h-9 w-full rounded-lg border border-[#E5E5E5] bg-[#FFFFFF] px-3 py-1.5 font-[380] text-muted-foreground text-sm shadow-xs transition-colors hover:text-muted-foreground dark:border-[#414141] dark:bg-[var(--surface-elevated)] dark:hover:text-muted-foreground'
variant='outline'
>
<Plus className='h-4 w-4' />

View File

@@ -401,7 +401,7 @@ export function Panel() {
</DropdownMenuTrigger>
<DropdownMenuContent
align='end'
className='z-[200] w-48 rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[#202020]'
className='z-[200] w-48 rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
sideOffset={8}
side='bottom'
avoidCollisions={true}

View File

@@ -54,7 +54,7 @@ const SkeletonControlBar = () => {
{/* Run Button */}
<Button
className='h-12 cursor-not-allowed gap-2 rounded-[11px] bg-[#701FFC] px-4 py-2 font-medium text-white shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:opacity-50 disabled:hover:bg-[#701FFC] disabled:hover:shadow-none'
className='h-12 cursor-not-allowed gap-2 rounded-[11px] bg-[var(--brand-primary-hex)] px-4 py-2 font-medium text-white shadow-[0_0_0_0_var(--brand-primary-hex)] transition-all duration-200 hover:bg-[var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:opacity-50 disabled:hover:bg-[var(--brand-primary-hex)] disabled:hover:shadow-none'
disabled
>
<Play className='h-3.5 w-3.5 fill-current stroke-current' />

View File

@@ -48,7 +48,7 @@ export function ActionBar({ blockId, blockType, disabled = false }: ActionBarPro
<Button
className={cn(
isEnabled
? 'bg-[#802FFF] hover:bg-[#802FFF]/90'
? 'bg-[var(--brand-primary-hover-hex)] hover:bg-[var(--brand-primary-hover-hex)]/90'
: 'bg-gray-400 hover:bg-gray-400 cursor-not-allowed'
)}
size="sm"

View File

@@ -226,7 +226,7 @@ export const WEBHOOK_PROVIDERS: { [key: string]: WebhookProvider } = {
<div
className={`flex items-center justify-center rounded ${props.className || ''}`}
style={{
backgroundColor: '#802FFF',
backgroundColor: 'var(--brand-primary-hover-hex)',
minWidth: '28px',
padding: '0 4px',
}}

View File

@@ -764,7 +764,7 @@ export function WorkflowBlock({ id, data }: NodeProps<WorkflowBlockProps>) {
}}
className={cn(
'h-7 p-1 text-gray-500',
blockAdvancedMode && 'text-[#701FFC]',
blockAdvancedMode && 'text-[var(--brand-primary-hex)]',
!userPermissions.canEdit && 'cursor-not-allowed opacity-50'
)}
disabled={!userPermissions.canEdit}

View File

@@ -39,7 +39,7 @@ const logger = createLogger('KnowledgeBaseTags')
// Predetermined colors for each tag slot (same as document tags)
const TAG_SLOT_COLORS = [
'#701FFC', // Purple
'var(--brand-primary-hex)', // Purple
'#FF6B35', // Orange
'#4ECDC4', // Teal
'#45B7D1', // Blue

View File

@@ -38,7 +38,7 @@ interface KnowledgeTagsProps {
// Predetermined colors for each tag slot
const TAG_SLOT_COLORS = [
'#701FFC', // Purple
'var(--brand-primary-hex)', // Purple
'#FF6B35', // Orange
'#4ECDC4', // Teal
'#45B7D1', // Blue

View File

@@ -231,7 +231,7 @@ export function Account({ onOpenChange }: AccountProps) {
<div className='flex items-center gap-3'>
<div className='relative flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-blue-500'>
{userData.isLoggedIn ? (
<div className='flex h-full w-full items-center justify-center bg-[#802FFF]'>
<div className='flex h-full w-full items-center justify-center bg-[var(--brand-primary-hover-hex)]'>
<AgentIcon className='-translate-y-[0.5px] text-white transition-transform duration-200 group-hover:scale-110' />
</div>
) : (
@@ -282,7 +282,7 @@ export function Account({ onOpenChange }: AccountProps) {
account.isActive && 'bg-accent'
)}
>
<div className='relative flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-full bg-[#802FFF]'>
<div className='relative flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-full bg-[var(--brand-primary-hover-hex)]'>
<User className='h-4 w-4 text-white' />
</div>
<div className='flex flex-col'>

View File

@@ -40,7 +40,7 @@ export function WorkflowContextMenu({ onStartEdit }: WorkflowContextMenuProps) {
<DropdownMenuContent
align='end'
onClick={(e) => e.stopPropagation()}
className='min-w-32 rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[#202020]'
className='min-w-32 rounded-lg border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
{userPermissions.canEdit && (
<DropdownMenuItem

View File

@@ -1033,7 +1033,7 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
}
className={cn(
'ml-auto flex h-9 items-center justify-center gap-2 rounded-[8px] px-4 py-2 font-medium transition-all duration-200',
'bg-[#701FFC] text-white shadow-[0_0_0_0_#701FFC] hover:bg-[#7028E6] hover:shadow-[0_0_0_4px_rgba(112,31,252,0.15)] disabled:opacity-50 disabled:hover:bg-[#701FFC] disabled:hover:shadow-none'
'bg-[var(--brand-primary-hex)] text-white shadow-[0_0_0_0_var(--brand-primary-hex)] hover:bg-[var(--brand-primary-hover-hex)] hover:shadow-[0_0_0_4px_rgba(112,31,252,0.15)] disabled:opacity-50 disabled:hover:bg-[var(--brand-primary-hex)] disabled:hover:shadow-none'
)}
>
{isSubmitting && <Loader2 className='h-4 w-4 animate-spin' />}

View File

@@ -1214,8 +1214,9 @@ const NavigationItem = ({ item }: NavigationItemProps) => {
className={cn(
'h-[42px] w-[42px] rounded-[10px] border bg-background text-foreground shadow-xs transition-all duration-200',
isGrayHover && 'hover:bg-secondary',
!isGrayHover && 'hover:border-[#701FFC] hover:bg-[#701FFC] hover:text-white',
item.active && 'border-[#701FFC] bg-[#701FFC] text-white'
!isGrayHover &&
'hover:border-[var(--brand-primary-hex)] hover:bg-[var(--brand-primary-hex)] hover:text-white',
item.active && 'border-[var(--brand-primary-hex)] bg-[var(--brand-primary-hex)] text-white'
)}
>
<item.icon className='h-4 w-4' />

View File

@@ -65,7 +65,7 @@ export const AgentBlock: BlockConfig<AgentResponse> = {
'Create powerful AI agents using any LLM provider with customizable system prompts and tool integrations.',
docsLink: 'https://docs.sim.ai/blocks/agent',
category: 'blocks',
bgColor: '#802FFF',
bgColor: 'var(--brand-primary-hover-hex)',
icon: AgentIcon,
subBlocks: [
{

View File

@@ -1,7 +1,7 @@
'use client'
import { useEffect } from 'react'
import { generateBrandCSS, getBrandConfig } from '@/lib/branding/branding'
import { getBrandConfig } from '@/lib/branding/branding'
interface BrandedLayoutProps {
children: React.ReactNode
@@ -24,18 +24,6 @@ export function BrandedLayout({ children }: BrandedLayoutProps) {
}
}
// Inject brand CSS
const brandStyleId = 'brand-styles'
let brandStyleElement = document.getElementById(brandStyleId) as HTMLStyleElement
if (!brandStyleElement) {
brandStyleElement = document.createElement('style')
brandStyleElement.id = brandStyleId
document.head.appendChild(brandStyleElement)
}
brandStyleElement.textContent = generateBrandCSS(config)
// Load custom CSS if provided
if (config.customCssUrl) {
const customCssId = 'custom-brand-css'

View File

@@ -31,7 +31,7 @@ export const baseStyles = {
},
button: {
display: 'inline-block',
backgroundColor: '#802FFF',
backgroundColor: 'var(--brand-primary-hover-hex)',
color: '#ffffff',
fontWeight: 'bold',
fontSize: '16px',
@@ -42,7 +42,7 @@ export const baseStyles = {
margin: '20px 0',
},
link: {
color: '#802FFF',
color: 'var(--brand-primary-hover-hex)',
textDecoration: 'underline',
},
footer: {
@@ -79,7 +79,7 @@ export const baseStyles = {
width: '249px',
},
sectionCenter: {
borderBottom: '1px solid #802FFF',
borderBottom: '1px solid var(--brand-primary-hover-hex)',
width: '102px',
},
}

View File

@@ -29,7 +29,7 @@ export function LoadingAgent({ size = 'md' }: LoadingAgentProps) {
>
<path
d='M15.6667 9.25H4.66667C2.64162 9.25 1 10.8916 1 12.9167V18.4167C1 20.4417 2.64162 22.0833 4.66667 22.0833H15.6667C17.6917 22.0833 19.3333 20.4417 19.3333 18.4167V12.9167C19.3333 10.8916 17.6917 9.25 15.6667 9.25Z'
stroke='#802FFF'
stroke='var(--brand-primary-hover-hex)'
strokeWidth='1.8'
strokeLinecap='round'
strokeLinejoin='round'
@@ -41,7 +41,7 @@ export function LoadingAgent({ size = 'md' }: LoadingAgentProps) {
/>
<path
d='M10.1663 5.58464C11.1789 5.58464 11.9997 4.76382 11.9997 3.7513C11.9997 2.73878 11.1789 1.91797 10.1663 1.91797C9.15382 1.91797 8.33301 2.73878 8.33301 3.7513C8.33301 4.76382 9.15382 5.58464 10.1663 5.58464Z'
stroke='#802FFF'
stroke='var(--brand-primary-hover-hex)'
strokeWidth='1.8'
strokeLinecap='round'
strokeLinejoin='round'
@@ -54,7 +54,7 @@ export function LoadingAgent({ size = 'md' }: LoadingAgentProps) {
/>
<path
d='M10.167 5.58594V9.2526M7.41699 16.5859V14.7526M12.917 14.7526V16.5859'
stroke='#802FFF'
stroke='var(--brand-primary-hover-hex)'
strokeWidth='1.8'
strokeLinecap='round'
strokeLinejoin='round'

View File

@@ -4,14 +4,8 @@ export interface BrandConfig {
name: string
logoUrl?: string
faviconUrl?: string
primaryColor?: string
secondaryColor?: string
accentColor?: string
customCssUrl?: string
hideBranding?: boolean
footerText?: string
supportEmail?: string
supportUrl?: string
documentationUrl?: string
termsUrl?: string
privacyUrl?: string
@@ -24,14 +18,8 @@ const defaultConfig: BrandConfig = {
name: 'Sim',
logoUrl: undefined,
faviconUrl: '/favicon/favicon.ico',
primaryColor: '#000000',
secondaryColor: '#6366f1',
accentColor: '#f59e0b',
customCssUrl: undefined,
hideBranding: false,
footerText: undefined,
supportEmail: 'help@sim.ai',
supportUrl: undefined,
documentationUrl: undefined,
termsUrl: undefined,
privacyUrl: undefined,
@@ -46,33 +34,14 @@ export const getBrandConfig = (): BrandConfig => {
name: getEnv('NEXT_PUBLIC_BRAND_NAME') || defaultConfig.name,
logoUrl: getEnv('NEXT_PUBLIC_BRAND_LOGO_URL') || defaultConfig.logoUrl,
faviconUrl: getEnv('NEXT_PUBLIC_BRAND_FAVICON_URL') || defaultConfig.faviconUrl,
primaryColor: getEnv('NEXT_PUBLIC_BRAND_PRIMARY_COLOR') || defaultConfig.primaryColor,
secondaryColor: getEnv('NEXT_PUBLIC_BRAND_SECONDARY_COLOR') || defaultConfig.secondaryColor,
accentColor: getEnv('NEXT_PUBLIC_BRAND_ACCENT_COLOR') || defaultConfig.accentColor,
customCssUrl: getEnv('NEXT_PUBLIC_CUSTOM_CSS_URL') || defaultConfig.customCssUrl,
hideBranding: getEnv('NEXT_PUBLIC_HIDE_BRANDING') === 'true',
footerText: getEnv('NEXT_PUBLIC_CUSTOM_FOOTER_TEXT') || defaultConfig.footerText,
supportEmail: getEnv('NEXT_PUBLIC_SUPPORT_EMAIL') || defaultConfig.supportEmail,
supportUrl: getEnv('NEXT_PUBLIC_SUPPORT_URL') || defaultConfig.supportUrl,
documentationUrl: getEnv('NEXT_PUBLIC_DOCUMENTATION_URL') || defaultConfig.documentationUrl,
termsUrl: getEnv('NEXT_PUBLIC_TERMS_URL') || defaultConfig.termsUrl,
privacyUrl: getEnv('NEXT_PUBLIC_PRIVACY_URL') || defaultConfig.privacyUrl,
}
}
/**
* Generate CSS custom properties for brand colors
*/
export const generateBrandCSS = (config: BrandConfig): string => {
return `
:root {
--brand-primary: ${config.primaryColor};
--brand-secondary: ${config.secondaryColor};
--brand-accent: ${config.accentColor};
}
`
}
/**
* Hook to use brand configuration in React components
*/

View File

@@ -116,7 +116,7 @@ export function generateBrandedMetadata(override: Partial<Metadata> = {}): Metad
other: {
'apple-mobile-web-app-capable': 'yes',
'mobile-web-app-capable': 'yes',
'msapplication-TileColor': brand.primaryColor || '#ffffff',
'msapplication-TileColor': '#701FFC', // Default Sim brand primary color
'msapplication-config': '/favicon/browserconfig.xml',
},
...override,

View File

@@ -195,14 +195,8 @@ export const env = createEnv({
NEXT_PUBLIC_BRAND_NAME: z.string().optional(), // Custom brand name (defaults to "Sim")
NEXT_PUBLIC_BRAND_LOGO_URL: z.string().url().optional(), // Custom logo URL
NEXT_PUBLIC_BRAND_FAVICON_URL: z.string().url().optional(), // Custom favicon URL
NEXT_PUBLIC_BRAND_PRIMARY_COLOR: z.string().optional(), // Primary brand color (hex)
NEXT_PUBLIC_BRAND_SECONDARY_COLOR: z.string().optional(), // Secondary brand color (hex)
NEXT_PUBLIC_BRAND_ACCENT_COLOR: z.string().optional(), // Accent brand color (hex)
NEXT_PUBLIC_CUSTOM_CSS_URL: z.string().url().optional(), // Custom CSS stylesheet URL
NEXT_PUBLIC_HIDE_BRANDING: z.string().optional(), // Hide "Powered by" branding
NEXT_PUBLIC_CUSTOM_FOOTER_TEXT: z.string().optional(), // Custom footer text
NEXT_PUBLIC_SUPPORT_EMAIL: z.string().email().optional(), // Custom support email
NEXT_PUBLIC_SUPPORT_URL: z.string().url().optional(), // Custom support URL
NEXT_PUBLIC_DOCUMENTATION_URL: z.string().url().optional(), // Custom documentation URL
NEXT_PUBLIC_TERMS_URL: z.string().url().optional(), // Custom terms of service URL
NEXT_PUBLIC_PRIVACY_URL: z.string().url().optional(), // Custom privacy policy URL
@@ -228,14 +222,8 @@ export const env = createEnv({
NEXT_PUBLIC_BRAND_NAME: process.env.NEXT_PUBLIC_BRAND_NAME,
NEXT_PUBLIC_BRAND_LOGO_URL: process.env.NEXT_PUBLIC_BRAND_LOGO_URL,
NEXT_PUBLIC_BRAND_FAVICON_URL: process.env.NEXT_PUBLIC_BRAND_FAVICON_URL,
NEXT_PUBLIC_BRAND_PRIMARY_COLOR: process.env.NEXT_PUBLIC_BRAND_PRIMARY_COLOR,
NEXT_PUBLIC_BRAND_SECONDARY_COLOR: process.env.NEXT_PUBLIC_BRAND_SECONDARY_COLOR,
NEXT_PUBLIC_BRAND_ACCENT_COLOR: process.env.NEXT_PUBLIC_BRAND_ACCENT_COLOR,
NEXT_PUBLIC_CUSTOM_CSS_URL: process.env.NEXT_PUBLIC_CUSTOM_CSS_URL,
NEXT_PUBLIC_HIDE_BRANDING: process.env.NEXT_PUBLIC_HIDE_BRANDING,
NEXT_PUBLIC_CUSTOM_FOOTER_TEXT: process.env.NEXT_PUBLIC_CUSTOM_FOOTER_TEXT,
NEXT_PUBLIC_SUPPORT_EMAIL: process.env.NEXT_PUBLIC_SUPPORT_EMAIL,
NEXT_PUBLIC_SUPPORT_URL: process.env.NEXT_PUBLIC_SUPPORT_URL,
NEXT_PUBLIC_DOCUMENTATION_URL: process.env.NEXT_PUBLIC_DOCUMENTATION_URL,
NEXT_PUBLIC_TERMS_URL: process.env.NEXT_PUBLIC_TERMS_URL,
NEXT_PUBLIC_PRIVACY_URL: process.env.NEXT_PUBLIC_PRIVACY_URL,

View File

@@ -183,25 +183,53 @@ const nextConfig: NextConfig = {
]
},
async redirects() {
// Only enable domain redirects for the hosted version
const redirects = []
// For self-hosted deployments, skip the landing page and go straight to login
if (!isHosted) {
return []
redirects.push({
source: '/',
destination: '/login',
permanent: false,
})
}
return [
{
source: '/((?!api|_next|_vercel|favicon|static|.*\\..*).*)',
destination: 'https://www.sim.ai/$1',
permanent: true,
has: [{ type: 'host', value: 'simstudio.ai' }],
},
{
source: '/((?!api|_next|_vercel|favicon|static|.*\\..*).*)',
destination: 'https://www.sim.ai/$1',
permanent: true,
has: [{ type: 'host', value: 'www.simstudio.ai' }],
},
]
// Add whitelabel redirects for terms and privacy pages if external URLs are configured
if (env.NEXT_PUBLIC_TERMS_URL?.startsWith('http')) {
redirects.push({
source: '/terms',
destination: env.NEXT_PUBLIC_TERMS_URL,
permanent: false,
})
}
if (env.NEXT_PUBLIC_PRIVACY_URL?.startsWith('http')) {
redirects.push({
source: '/privacy',
destination: env.NEXT_PUBLIC_PRIVACY_URL,
permanent: false,
})
}
// Only enable domain redirects for the hosted version
if (isHosted) {
redirects.push(
{
source: '/((?!api|_next|_vercel|favicon|static|.*\\..*).*)',
destination: 'https://www.sim.ai/$1',
permanent: true,
has: [{ type: 'host', key: 'host', value: 'simstudio.ai' }],
},
{
source: '/((?!api|_next|_vercel|favicon|static|.*\\..*).*)',
destination: 'https://www.sim.ai/$1',
permanent: true,
has: [{ type: 'host', key: 'host', value: 'www.simstudio.ai' }],
}
)
}
return redirects
},
}

View File

@@ -27,14 +27,8 @@ app:
NEXT_PUBLIC_BRAND_NAME: "Acme AI Studio"
NEXT_PUBLIC_BRAND_LOGO_URL: "https://acme.com/assets/logo.png"
NEXT_PUBLIC_BRAND_FAVICON_URL: "https://acme.com/assets/favicon.ico"
NEXT_PUBLIC_BRAND_PRIMARY_COLOR: "#1a365d" # Acme blue
NEXT_PUBLIC_BRAND_SECONDARY_COLOR: "#2d3748" # Dark gray
NEXT_PUBLIC_BRAND_ACCENT_COLOR: "#38b2ac" # Teal accent
NEXT_PUBLIC_CUSTOM_CSS_URL: "https://acme.com/assets/theme.css"
NEXT_PUBLIC_HIDE_BRANDING: "true" # Hide "Powered by Sim"
NEXT_PUBLIC_CUSTOM_FOOTER_TEXT: "© 2024 Acme Corp. All rights reserved."
NEXT_PUBLIC_SUPPORT_EMAIL: "ai-support@acme.com"
NEXT_PUBLIC_SUPPORT_URL: "https://help.acme.com/ai-studio"
NEXT_PUBLIC_DOCUMENTATION_URL: "https://docs.acme.com/ai-studio"
NEXT_PUBLIC_TERMS_URL: "https://acme.com/terms"
NEXT_PUBLIC_PRIVACY_URL: "https://acme.com/privacy"

View File

@@ -240,39 +240,15 @@
"type": "string",
"description": "Custom favicon URL"
},
"NEXT_PUBLIC_BRAND_PRIMARY_COLOR": {
"type": "string",
"description": "Primary brand color (hex)"
},
"NEXT_PUBLIC_BRAND_SECONDARY_COLOR": {
"type": "string",
"description": "Secondary brand color (hex)"
},
"NEXT_PUBLIC_BRAND_ACCENT_COLOR": {
"type": "string",
"description": "Accent brand color (hex)"
},
"NEXT_PUBLIC_CUSTOM_CSS_URL": {
"type": "string",
"description": "Custom stylesheet URL"
},
"NEXT_PUBLIC_HIDE_BRANDING": {
"type": "string",
"description": "Hide powered by branding"
},
"NEXT_PUBLIC_CUSTOM_FOOTER_TEXT": {
"type": "string",
"description": "Custom footer text"
},
"NEXT_PUBLIC_SUPPORT_EMAIL": {
"type": "string",
"format": "email",
"description": "Support email address"
},
"NEXT_PUBLIC_SUPPORT_URL": {
"type": "string",
"description": "Support page URL"
},
"NEXT_PUBLIC_DOCUMENTATION_URL": {
"type": "string",
"description": "Documentation URL"

View File

@@ -102,14 +102,8 @@ app:
NEXT_PUBLIC_BRAND_NAME: "Sim" # Custom brand name
NEXT_PUBLIC_BRAND_LOGO_URL: "" # Custom logo URL (leave empty for default)
NEXT_PUBLIC_BRAND_FAVICON_URL: "" # Custom favicon URL (leave empty for default)
NEXT_PUBLIC_BRAND_PRIMARY_COLOR: "#000000" # Primary brand color (hex)
NEXT_PUBLIC_BRAND_SECONDARY_COLOR: "#6366f1" # Secondary brand color (hex)
NEXT_PUBLIC_BRAND_ACCENT_COLOR: "#f59e0b" # Accent brand color (hex)
NEXT_PUBLIC_CUSTOM_CSS_URL: "" # Custom stylesheet URL (leave empty for none)
NEXT_PUBLIC_HIDE_BRANDING: "false" # Hide "Powered by" branding (true/false)
NEXT_PUBLIC_CUSTOM_FOOTER_TEXT: "" # Custom footer text (leave empty for default)
NEXT_PUBLIC_SUPPORT_EMAIL: "help@sim.ai" # Support email address
NEXT_PUBLIC_SUPPORT_URL: "" # Support page URL (leave empty for none)
NEXT_PUBLIC_DOCUMENTATION_URL: "" # Documentation URL (leave empty for none)
NEXT_PUBLIC_TERMS_URL: "" # Terms of service URL (leave empty for none)
NEXT_PUBLIC_PRIVACY_URL: "" # Privacy policy URL (leave empty for none)