From 9aa253104922e1eb3603e01c219e93f1ed2f31ec Mon Sep 17 00:00:00 2001 From: waleed Date: Tue, 19 May 2026 15:57:54 -0700 Subject: [PATCH] fix(branding): align auth and deploy UI colors --- .../(auth)/components/auth-button-classes.ts | 4 + apps/sim/app/_styles/globals.css | 17 +- .../chat/components/auth/email/email-auth.tsx | 16 +- .../[identifier]/components/email-auth.tsx | 16 +- apps/sim/app/manifest.ts | 2 +- .../deploy-modal/components/a2a/a2a.tsx | 117 +--- .../deploy-modal/components/api/api.tsx | 2 - .../deploy-modal/components/chat/chat.tsx | 62 +- .../form/components/embed-code-generator.tsx | 61 -- .../form/components/form-builder.tsx | 356 ----------- .../deploy-modal/components/form/form.tsx | 563 ------------------ .../form/hooks/use-identifier-validation.ts | 89 --- .../general/components/api-info-modal.tsx | 25 +- .../components/version-description-modal.tsx | 18 +- .../general/components/versions.tsx | 69 +-- .../components/general/general.tsx | 47 +- .../deploy-modal/components/mcp/mcp.tsx | 94 ++- .../components/template/template.tsx | 483 --------------- .../components/deploy-modal/deploy-modal.tsx | 322 +++------- apps/sim/components/emails/_styles/base.ts | 4 +- .../components/whitelabeling-settings.tsx | 14 +- apps/sim/ee/whitelabeling/inject-theme.ts | 4 +- apps/sim/ee/whitelabeling/metadata.ts | 2 +- .../ee/whitelabeling/org-branding-utils.ts | 4 +- apps/sim/lib/api/contracts/organization.ts | 2 +- apps/sim/lib/branding/defaults.ts | 8 +- apps/sim/lib/branding/types.ts | 2 +- apps/sim/lib/core/config/env.ts | 2 +- apps/sim/tailwind.config.ts | 5 - 29 files changed, 292 insertions(+), 2118 deletions(-) delete mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/form/components/embed-code-generator.tsx delete mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/form/components/form-builder.tsx delete mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/form/form.tsx delete mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/form/hooks/use-identifier-validation.ts delete mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/template/template.tsx diff --git a/apps/sim/app/(auth)/components/auth-button-classes.ts b/apps/sim/app/(auth)/components/auth-button-classes.ts index a55f334ea8e..95a3592fe96 100644 --- a/apps/sim/app/(auth)/components/auth-button-classes.ts +++ b/apps/sim/app/(auth)/components/auth-button-classes.ts @@ -4,3 +4,7 @@ export const AUTH_PRIMARY_CTA_BASE = /** Full-width variant used for primary auth form submit buttons. */ export const AUTH_SUBMIT_BTN = `${AUTH_PRIMARY_CTA_BASE} w-full` as const + +/** Shared className for inline auth action links on dark auth surfaces. */ +export const AUTH_TEXT_LINK = + 'font-medium text-[var(--brand-accent)] underline-offset-4 transition hover:text-[var(--brand-accent-hover)] hover:underline disabled:cursor-not-allowed disabled:opacity-50' as const diff --git a/apps/sim/app/_styles/globals.css b/apps/sim/app/_styles/globals.css index 15fb1c30cf3..1555a0cc2ab 100644 --- a/apps/sim/app/_styles/globals.css +++ b/apps/sim/app/_styles/globals.css @@ -36,7 +36,6 @@ --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); } @@ -762,12 +761,8 @@ input[type="search"]::-ms-clear { --card-text: 0 0% 3.9%; --card-hover: 0 0% 96.1%; --base-muted-foreground: #737373; - --gradient-primary: 263 85% 70%; - --gradient-secondary: 336 95% 65%; - --brand: #6f3dfa; - --brand-hover: #6338d9; - --brand-link: #6f3dfa; - --brand-link-hover: #6f3dfa; + --brand: #33c482; + --brand-hover: #2dac72; } .dark { @@ -799,12 +794,8 @@ input[type="search"]::-ms-clear { --card-text: 0 0% 98%; --card-hover: 0 0% 12.0%; --base-muted-foreground: #a3a3a3; - --gradient-primary: 263 90% 75%; - --gradient-secondary: 336 100% 72%; - --brand: #701ffc; - --brand-hover: #802fff; - --brand-link: #9d54ff; - --brand-link-hover: #a66fff; + --brand: #33c482; + --brand-hover: #2dac72; } } diff --git a/apps/sim/app/chat/components/auth/email/email-auth.tsx b/apps/sim/app/chat/components/auth/email/email-auth.tsx index 2515b92f4f4..3224e0bb4bb 100644 --- a/apps/sim/app/chat/components/auth/email/email-auth.tsx +++ b/apps/sim/app/chat/components/auth/email/email-auth.tsx @@ -7,7 +7,7 @@ import { Input, InputOTP, InputOTPGroup, InputOTPSlot, Label, Loader } from '@/c import { cn } from '@/lib/core/utils/cn' import { quickValidateEmail } from '@/lib/messaging/email/validation' import AuthBackground from '@/app/(auth)/components/auth-background' -import { AUTH_SUBMIT_BTN } from '@/app/(auth)/components/auth-button-classes' +import { AUTH_SUBMIT_BTN, AUTH_TEXT_LINK } from '@/app/(auth)/components/auth-button-classes' import { SupportFooter } from '@/app/(auth)/components/support-footer' import Navbar from '@/app/(landing)/components/navbar/navbar' import { useChatEmailOtpRequest, useChatEmailOtpVerify } from '@/hooks/queries/chats' @@ -123,7 +123,7 @@ export default function EmailAuth({ identifier }: EmailAuthProps) {
-

+

{showOtpVerification ? 'Verify Your Email' : 'Email Verification'}

@@ -159,11 +159,11 @@ export default function EmailAuth({ identifier }: EmailAuthProps) { className={cn( showEmailValidationError && emailErrors.length > 0 && - 'border-red-500 focus:border-red-500' + 'border-[var(--text-error)] focus:border-[var(--text-error)]' )} /> {showEmailValidationError && emailErrors.length > 0 && ( -

+
{emailErrors.map((error) => (

{error}

))} @@ -211,7 +211,7 @@ export default function EmailAuth({ identifier }: EmailAuthProps) { ))} @@ -219,7 +219,7 @@ export default function EmailAuth({ identifier }: EmailAuthProps) {
{authError && ( -
+

{authError}

)} @@ -251,7 +251,7 @@ export default function EmailAuth({ identifier }: EmailAuthProps) { ) : ( diff --git a/apps/sim/app/form/[identifier]/components/email-auth.tsx b/apps/sim/app/form/[identifier]/components/email-auth.tsx index b75cb159c3c..7fdc78b5aff 100644 --- a/apps/sim/app/form/[identifier]/components/email-auth.tsx +++ b/apps/sim/app/form/[identifier]/components/email-auth.tsx @@ -7,7 +7,7 @@ import { Input, InputOTP, InputOTPGroup, InputOTPSlot, Label, Loader } from '@/c import { cn } from '@/lib/core/utils/cn' import { quickValidateEmail } from '@/lib/messaging/email/validation' import AuthBackground from '@/app/(auth)/components/auth-background' -import { AUTH_SUBMIT_BTN } from '@/app/(auth)/components/auth-button-classes' +import { AUTH_SUBMIT_BTN, AUTH_TEXT_LINK } from '@/app/(auth)/components/auth-button-classes' import { SupportFooter } from '@/app/(auth)/components/support-footer' import Navbar from '@/app/(landing)/components/navbar/navbar' import { useFormEmailOtpRequest, useFormEmailOtpVerify } from '@/hooks/queries/forms' @@ -120,7 +120,7 @@ export function EmailAuth({ identifier, onAuthenticated }: EmailAuthProps) {
-

+

{showOtpVerification ? 'Verify Your Email' : 'Email Verification'}

@@ -154,11 +154,11 @@ export function EmailAuth({ identifier, onAuthenticated }: EmailAuthProps) { className={cn( showEmailValidationError && emailErrors.length > 0 && - 'border-red-500 focus:border-red-500' + 'border-[var(--text-error)] focus:border-[var(--text-error)]' )} /> {showEmailValidationError && emailErrors.length > 0 && ( -

+
{emailErrors.map((error) => (

{error}

))} @@ -206,7 +206,7 @@ export function EmailAuth({ identifier, onAuthenticated }: EmailAuthProps) { ))} @@ -214,7 +214,7 @@ export function EmailAuth({ identifier, onAuthenticated }: EmailAuthProps) {
{authError && ( -
+

{authError}

)} @@ -248,7 +248,7 @@ export function EmailAuth({ identifier, onAuthenticated }: EmailAuthProps) { ) : ( diff --git a/apps/sim/app/manifest.ts b/apps/sim/app/manifest.ts index cb91437f3c1..23e600614a0 100644 --- a/apps/sim/app/manifest.ts +++ b/apps/sim/app/manifest.ts @@ -18,7 +18,7 @@ export default function manifest(): MetadataRoute.Manifest { scope: '/', display: 'standalone', background_color: '#ffffff', - theme_color: brand.theme?.primaryColor || '#6F3DFA', + theme_color: brand.theme?.primaryColor || '#33C482', orientation: 'portrait-primary', icons: [ { diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx index d2aae6bceb2..f5802447f10 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/a2a/a2a.tsx @@ -1,6 +1,6 @@ 'use client' -import { useCallback, useEffect, useMemo, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import { createLogger } from '@sim/logger' import { generateId } from '@sim/utils/id' import { Check, Clipboard } from 'lucide-react' @@ -81,7 +81,6 @@ interface A2aDeployProps { workflowNeedsRedeployment?: boolean onSubmittingChange?: (submitting: boolean) => void onCanSaveChange?: (canSave: boolean) => void - /** Callback for when republish status changes - depends on local form state */ onNeedsRepublishChange?: (needsRepublish: boolean) => void onDeployWorkflow?: () => Promise } @@ -147,13 +146,12 @@ export function A2aDeploy({ return missing }, [startBlockId, startBlockInputFormat]) - const handleAddA2AInputs = useCallback(() => { + const handleAddA2AInputs = () => { if (!startBlockId) return const normalizedExisting = normalizeInputFormatValue(startBlockInputFormat) const newFields: InputFormatField[] = [] - // Add input field if missing (for TextPart) if (missingFields.input) { newFields.push({ id: generateId(), @@ -164,7 +162,6 @@ export function A2aDeploy({ }) } - // Add data field if missing (for DataPart) if (missingFields.data) { newFields.push({ id: generateId(), @@ -175,7 +172,6 @@ export function A2aDeploy({ }) } - // Add files field if missing (for FilePart) if (missingFields.files) { newFields.push({ id: generateId(), @@ -193,7 +189,7 @@ export function A2aDeploy({ `Added A2A input fields to Start block: ${newFields.map((f) => f.name).join(', ')}` ) } - }, [startBlockId, startBlockInputFormat, missingFields, collaborativeSetSubblockValue]) + } const [name, setName] = useState('') const [description, setDescription] = useState('') @@ -258,10 +254,7 @@ export function A2aDeploy({ workflowName, ]) - const hasWorkflowChanges = useMemo(() => { - if (!existingAgent) return false - return !!workflowNeedsRedeployment - }, [existingAgent, workflowNeedsRedeployment]) + const hasWorkflowChanges = existingAgent ? !!workflowNeedsRedeployment : false const needsRepublish = existingAgent && (hasFormChanges || hasWorkflowChanges) @@ -284,7 +277,7 @@ export function A2aDeploy({ onSubmittingChange?.(isSubmitting) }, [isSubmitting, onSubmittingChange]) - const handleCreateOrUpdate = useCallback(async () => { + const handleCreateOrUpdate = async () => { const capabilities: AgentCapabilities = { streaming: true, pushNotifications: pushNotificationsEnabled, @@ -319,20 +312,9 @@ export function A2aDeploy({ } catch (error) { logger.error('Failed to save A2A agent:', error) } - }, [ - existingAgent, - name, - description, - pushNotificationsEnabled, - authScheme, - skillTags, - workspaceId, - workflowId, - createAgent, - updateAgent, - ]) + } - const handlePublish = useCallback(async () => { + const handlePublish = async () => { if (!existingAgent) return try { await publishAgent.mutateAsync({ @@ -343,9 +325,9 @@ export function A2aDeploy({ } catch (error) { logger.error('Failed to publish A2A agent:', error) } - }, [existingAgent, workspaceId, publishAgent]) + } - const handleUnpublish = useCallback(async () => { + const handleUnpublish = async () => { if (!existingAgent) return try { await publishAgent.mutateAsync({ @@ -356,9 +338,9 @@ export function A2aDeploy({ } catch (error) { logger.error('Failed to unpublish A2A agent:', error) } - }, [existingAgent, workspaceId, publishAgent]) + } - const handleDelete = useCallback(async () => { + const handleDelete = async () => { if (!existingAgent) return try { await deleteAgent.mutateAsync({ @@ -370,9 +352,9 @@ export function A2aDeploy({ } catch (error) { logger.error('Failed to delete A2A agent:', error) } - }, [existingAgent, workspaceId, deleteAgent, workflowName, workflowDescription]) + } - const handlePublishNewAgent = useCallback(async () => { + const handlePublishNewAgent = async () => { const capabilities: AgentCapabilities = { streaming: true, pushNotifications: pushNotificationsEnabled, @@ -406,21 +388,9 @@ export function A2aDeploy({ } catch (error) { logger.error('Failed to publish A2A agent:', error) } - }, [ - name, - description, - pushNotificationsEnabled, - authScheme, - skillTags, - workspaceId, - workflowId, - createAgent, - publishAgent, - isDeployed, - onDeployWorkflow, - ]) + } - const handleUpdateAndRepublish = useCallback(async () => { + const handleUpdateAndRepublish = async () => { if (!existingAgent) return const capabilities: AgentCapabilities = { @@ -455,20 +425,7 @@ export function A2aDeploy({ } catch (error) { logger.error('Failed to update and republish A2A agent:', error) } - }, [ - existingAgent, - isDeployed, - workflowNeedsRedeployment, - onDeployWorkflow, - name, - description, - pushNotificationsEnabled, - authScheme, - skillTags, - workspaceId, - updateAgent, - publishAgent, - ]) + } const baseUrl = getBaseUrl() const endpoint = existingAgent ? `${baseUrl}/api/a2a/serve/${existingAgent.id}` : null @@ -484,7 +441,7 @@ export function A2aDeploy({ ) }, [startBlockInputFormat]) - const getExampleInputData = useCallback((): Record => { + const getExampleInputData = (): Record => { const data: Record = {} for (const field of additionalInputFields) { switch (field.type) { @@ -508,13 +465,12 @@ export function A2aDeploy({ } } return data - }, [additionalInputFields]) + } - const getJsonRpcPayload = useCallback((): Record => { + const getJsonRpcPayload = (): Record => { const inputData = getExampleInputData() const hasAdditionalData = Object.keys(inputData).length > 0 - // Build parts array: TextPart for message text, DataPart for additional fields const parts: Array> = [{ kind: 'text', text: 'Hello, agent!' }] if (hasAdditionalData) { parts.push({ kind: 'data', data: inputData }) @@ -531,9 +487,9 @@ export function A2aDeploy({ }, }, } - }, [getExampleInputData, useStreamingExample]) + } - const getCurlCommand = useCallback((): string => { + const getCurlCommand = (): string => { if (!endpoint) return '' const payload = getJsonRpcPayload() const requiresAuth = authScheme !== 'none' @@ -623,13 +579,13 @@ console.log(data);` default: return '' } - }, [endpoint, language, getJsonRpcPayload, authScheme]) + } - const handleCopyCommand = useCallback(() => { + const handleCopyCommand = () => { navigator.clipboard.writeText(getCurlCommand()) setCodeCopied(true) setTimeout(() => setCodeCopied(false), 2000) - }, [getCurlCommand]) + } if (isLoading) { return ( @@ -664,7 +620,6 @@ console.log(data);` }} className='-mx-1 space-y-3 overflow-y-auto px-1 pb-4' > - {/* Endpoint URL (shown when agent exists) */} {existingAgent && endpoint && (
@@ -692,15 +647,15 @@ console.log(data);`
-
-
+
+
{baseUrl.replace(/^https?:\/\//, '')}/api/a2a/serve/
@@ -710,13 +665,12 @@ console.log(data);`
)} - {/* Agent Name */}
- {/* Description */}