feat: place all styles in global vars (#1923)

* feat: place all styles in global vars

* feat: prevented on workspace
This commit is contained in:
Emir Karabeg
2025-11-12 04:51:46 -08:00
committed by GitHub
parent a0c4bce56e
commit 42e2769526
84 changed files with 955 additions and 582 deletions
+2 -2
View File
@@ -428,7 +428,7 @@ setSidebarWidth: (width) => {
### Tailwind Classes
1. **No Inline Styles**: Use Tailwind utility classes exclusively
2. **Dark Mode**: Always include dark mode variants (`dark:bg-[#1E1E1E]`)
2. **Dark Mode**: Always include dark mode variants (`dark:bg-[var(--surface-1)]`)
3. **Exact Values**: Use exact values from design system (`text-[14px]`, `h-[25px]`)
4. **clsx for Conditionals**: Use clsx() for conditional classes
5. **Consistent Spacing**: Use spacing tokens (`gap-[8px]`, `px-[14px]`)
@@ -441,7 +441,7 @@ setSidebarWidth: (width) => {
'base-classes that-always-apply',
isActive && 'active-state-classes',
disabled ? 'cursor-not-allowed opacity-60' : 'cursor-pointer hover:bg-accent',
'dark:bg-[#1E1E1E] dark:border-[#2C2C2C]' // Dark mode variants
'dark:bg-[var(--surface-1)] dark:border-[var(--border)]' // Dark mode variants
)}
>
```
+29 -5
View File
@@ -1,7 +1,7 @@
'use client'
import { useEffect, useState } from 'react'
import { Eye, EyeOff } from 'lucide-react'
import { ArrowRight, ChevronRight, Eye, EyeOff } from 'lucide-react'
import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import { Button } from '@/components/ui/button'
@@ -106,6 +106,7 @@ export default function LoginPage({
const [passwordErrors, setPasswordErrors] = useState<string[]>([])
const [showValidationError, setShowValidationError] = useState(false)
const [buttonClass, setButtonClass] = useState('auth-button-gradient')
const [isButtonHovered, setIsButtonHovered] = useState(false)
const [callbackUrl, setCallbackUrl] = useState('/workspace')
const [isInviteFlow, setIsInviteFlow] = useState(false)
@@ -113,6 +114,7 @@ export default function LoginPage({
const [forgotPasswordOpen, setForgotPasswordOpen] = useState(false)
const [forgotPasswordEmail, setForgotPasswordEmail] = useState('')
const [isSubmittingReset, setIsSubmittingReset] = useState(false)
const [isResetButtonHovered, setIsResetButtonHovered] = useState(false)
const [resetStatus, setResetStatus] = useState<{
type: 'success' | 'error' | null
message: string
@@ -482,10 +484,21 @@ export default function LoginPage({
<Button
type='submit'
className={`${buttonClass} flex w-full items-center justify-center gap-2 rounded-[10px] border font-medium text-[15px] text-white transition-all duration-200`}
onMouseEnter={() => setIsButtonHovered(true)}
onMouseLeave={() => setIsButtonHovered(false)}
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all'
disabled={isLoading}
>
{isLoading ? 'Signing in...' : 'Sign in'}
<span className='flex items-center gap-1'>
{isLoading ? 'Signing in...' : 'Sign in'}
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isButtonHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</Button>
</form>
)}
@@ -600,10 +613,21 @@ export default function LoginPage({
<Button
type='button'
onClick={handleForgotPassword}
className={`${buttonClass} w-full rounded-[10px] border font-medium text-[15px] text-white transition-all duration-200`}
onMouseEnter={() => setIsResetButtonHovered(true)}
onMouseLeave={() => setIsResetButtonHovered(false)}
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all'
disabled={isSubmittingReset}
>
{isSubmittingReset ? 'Sending...' : 'Send Reset Link'}
<span className='flex items-center gap-1'>
{isSubmittingReset ? 'Sending...' : 'Send Reset Link'}
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isResetButtonHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</Button>
</div>
</DialogContent>
@@ -1,7 +1,7 @@
'use client'
import { useEffect, useState } from 'react'
import { Eye, EyeOff } from 'lucide-react'
import { ArrowRight, ChevronRight, Eye, EyeOff } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
@@ -28,6 +28,7 @@ export function RequestResetForm({
className,
}: RequestResetFormProps) {
const [buttonClass, setButtonClass] = useState('auth-button-gradient')
const [isButtonHovered, setIsButtonHovered] = useState(false)
useEffect(() => {
const checkCustomBrand = () => {
@@ -96,9 +97,20 @@ export function RequestResetForm({
<Button
type='submit'
disabled={isSubmitting}
className={`${buttonClass} flex w-full items-center justify-center gap-2 rounded-[10px] border font-medium text-[15px] text-white transition-all duration-200`}
onMouseEnter={() => setIsButtonHovered(true)}
onMouseLeave={() => setIsButtonHovered(false)}
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all'
>
{isSubmitting ? 'Sending...' : 'Send Reset Link'}
<span className='flex items-center gap-1'>
{isSubmitting ? 'Sending...' : 'Send Reset Link'}
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isButtonHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</Button>
</form>
)
@@ -127,6 +139,7 @@ export function SetNewPasswordForm({
const [showPassword, setShowPassword] = useState(false)
const [showConfirmPassword, setShowConfirmPassword] = useState(false)
const [buttonClass, setButtonClass] = useState('auth-button-gradient')
const [isButtonHovered, setIsButtonHovered] = useState(false)
useEffect(() => {
const checkCustomBrand = () => {
@@ -286,9 +299,20 @@ export function SetNewPasswordForm({
<Button
disabled={isSubmitting || !token}
type='submit'
className={`${buttonClass} flex w-full items-center justify-center gap-2 rounded-[10px] border font-medium text-[15px] text-white transition-all duration-200`}
onMouseEnter={() => setIsButtonHovered(true)}
onMouseLeave={() => setIsButtonHovered(false)}
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all'
>
{isSubmitting ? 'Resetting...' : 'Reset Password'}
<span className='flex items-center gap-1'>
{isSubmitting ? 'Resetting...' : 'Reset Password'}
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isButtonHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</Button>
</form>
)
+15 -3
View File
@@ -1,7 +1,7 @@
'use client'
import { Suspense, useEffect, useState } from 'react'
import { Eye, EyeOff } from 'lucide-react'
import { ArrowRight, ChevronRight, Eye, EyeOff } from 'lucide-react'
import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import { Button } from '@/components/ui/button'
@@ -96,6 +96,7 @@ function SignupFormContent({
const [redirectUrl, setRedirectUrl] = useState('')
const [isInviteFlow, setIsInviteFlow] = useState(false)
const [buttonClass, setButtonClass] = useState('auth-button-gradient')
const [isButtonHovered, setIsButtonHovered] = useState(false)
const [name, setName] = useState('')
const [nameErrors, setNameErrors] = useState<string[]>([])
@@ -506,10 +507,21 @@ function SignupFormContent({
<Button
type='submit'
className={`${buttonClass} flex w-full items-center justify-center gap-2 rounded-[10px] border font-medium text-[15px] text-white transition-all duration-200`}
onMouseEnter={() => setIsButtonHovered(true)}
onMouseLeave={() => setIsButtonHovered(false)}
className='group inline-flex w-full items-center justify-center gap-2 rounded-[10px] border border-[#6F3DFA] bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] py-[6px] pr-[10px] pl-[12px] text-[15px] text-white shadow-[inset_0_2px_4px_0_#9B77FF] transition-all'
disabled={isLoading}
>
{isLoading ? 'Creating account...' : 'Create account'}
<span className='flex items-center gap-1'>
{isLoading ? 'Creating account...' : 'Create account'}
<span className='inline-flex transition-transform duration-200 group-hover:translate-x-0.5'>
{isButtonHovered ? (
<ArrowRight className='h-4 w-4' aria-hidden='true' />
) : (
<ChevronRight className='h-4 w-4' aria-hidden='true' />
)}
</span>
</span>
</Button>
</form>
)}
+372 -117
View File
@@ -52,13 +52,13 @@
.workflow-container,
.workflow-container .react-flow__pane,
.workflow-container .react-flow__renderer {
background-color: #e4e4e4 !important;
background-color: var(--bg) !important;
}
.dark .workflow-container,
.dark .workflow-container .react-flow__pane,
.dark .workflow-container .react-flow__renderer {
background-color: #1b1b1b !important;
background-color: var(--bg) !important;
}
/**
@@ -75,90 +75,238 @@
}
/**
* Theme system - CSS custom properties for light and dark modes
* Dark color tokens - single source of truth for all colors (dark-only)
*/
@layer base {
:root,
.light {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--card: 0 0% 99.2%;
--card-foreground: 0 0% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: 0 0% 11.2%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 11.2%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 46.9%;
--accent: 0 0% 92.5%;
--accent-foreground: 0 0% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--input-background: 0 0% 79.22%;
--ring: 0 0% 3.9%;
--radius: 0.5rem;
--scrollbar-track: 0 0% 85%;
--scrollbar-thumb: 0 0% 65%;
--scrollbar-thumb-hover: 0 0% 55%;
--scrollbar-size: 8px;
--workflow-background: 0 0% 100%;
--card-background: 0 0% 99.2%;
--card-border: 0 0% 89.8%;
--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-primary-hex: #6f3dfa;
--brand-primary-hover-hex: #6338d9;
--brand-accent-hex: #6f3dfa;
--brand-accent-hover-hex: #6f3dfa;
--brand-background-hex: #ffffff;
--surface-elevated: #202020;
}
/* Neutrals (surfaces) */
--bg: #ffffff;
--surface-1: #ffffff;
--surface-2: #fafafa;
--surface-3: #f8f8f8;
--surface-4: #f6f6f6;
--surface-5: #f3f3f3;
--surface-6: #f0f0f0;
--surface-9: #eaeaea;
--surface-11: #e6e6e6;
--surface-12: #e0e0e0;
--surface-13: #dcdcdc;
--surface-14: #d6d6d6;
--surface-15: #cfcfcf;
--surface-elevated: #ffffff;
--bg-strong: #f5f5f5;
/* Text */
--text-primary: #1b1b1b;
--text-secondary: #404040;
--text-tertiary: #555555;
--text-muted: #737373;
--text-subtle: #8a8a8a;
--text-inverse: #1b1b1b;
--text-error: #ef4444;
/* Borders / dividers */
--border: #dddddd;
--border-strong: #d1d1d1;
--divider: #e5e5e5;
--border-muted: #eeeeee;
/* Brand & state */
--brand-400: #8e4cfb;
--brand-500: #6f3dfa;
--brand-secondary: #33b4ff;
--brand-tertiary: #22c55e;
--warning: #ff6600;
/* Utility */
--white: #ffffff;
/* RGB for opacity usage */
--surface-4-rgb: 246 246 246;
--surface-5-rgb: 243 243 243;
--surface-7-rgb: 230 230 230;
--surface-9-rgb: 234 234 234;
--divider-rgb: 229 229 229;
--white-rgb: 255 255 255;
--black-rgb: 0 0 0;
/* 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;
/* 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;
/* 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;
}
.dark {
--background: 0 0% 10.59%;
--foreground: 0 0% 98%;
--card: 0 0% 9.0%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 9.0%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 11.2%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 12.0%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 17.5%;
--muted-foreground: 0 0% 65.1%;
--accent: 0 0% 17.5%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 16.1%;
--input: 0 0% 16.1%;
--input-background: 0 0% 20.78%;
--ring: 0 0% 83.9%;
--scrollbar-track: 0 0% 17.5%;
--scrollbar-thumb: 0 0% 30%;
--scrollbar-thumb-hover: 0 0% 40%;
--workflow-background: 0 0% 10.59%;
--card-background: 0 0% 9.0%;
--card-border: 0 0% 22.7%;
--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-primary-hex: #701ffc;
--brand-primary-hover-hex: #802fff;
--brand-accent-hex: #9d54ff;
--brand-accent-hover-hex: #a66fff;
--brand-background-hex: #0c0c0c;
/* Neutrals (surfaces) */
--bg: #1b1b1b;
--surface-1: #1e1e1e;
--surface-2: #232323;
--surface-3: #242424;
--surface-4: #252525;
--surface-5: #272727;
--surface-6: #282828;
--surface-9: #363636;
--surface-11: #3d3d3d;
--surface-12: #434343;
--surface-13: #454545;
--surface-14: #4a4a4a;
--surface-15: #5a5a5a;
--surface-elevated: #202020;
--bg-strong: #0c0c0c;
/* Text */
--text-primary: #e6e6e6;
--text-secondary: #b1b1b1;
--text-tertiary: #aeaeae;
--text-muted: #787878;
--text-subtle: #7d7d7d;
--text-inverse: #1b1b1b;
--text-error: #ef4444;
/* Borders / dividers */
--border: #2c2c2c;
--border-strong: #303030;
--divider: #393939;
--border-muted: #424242;
/* Brand & state */
--brand-400: #8e4cfb;
--brand-secondary: #33b4ff;
--brand-tertiary: #22c55e;
--warning: #ff6600;
/* Utility */
--white: #ffffff;
/* RGB for opacity usage */
--surface-4-rgb: 37 37 37;
--surface-5-rgb: 39 39 39;
--surface-7-rgb: 44 44 44;
--surface-9-rgb: 54 54 54;
--divider-rgb: 57 57 57;
--white-rgb: 255 255 255;
--black-rgb: 0 0 0;
/* 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;
/* 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;
/* 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;
}
}
@@ -167,7 +315,7 @@
*/
@layer base {
* {
@apply border-border;
border-color: var(--border);
overscroll-behavior-x: none;
}
@@ -176,7 +324,8 @@
}
body {
@apply bg-background text-foreground;
background-color: var(--bg);
color: var(--text-primary);
overscroll-behavior-x: none;
overscroll-behavior-y: none;
min-height: 100vh;
@@ -185,6 +334,19 @@
letter-spacing: 0.28px;
}
/* Ensure visible text caret across inputs and editors */
input,
textarea,
[contenteditable="true"] {
caret-color: var(--text-primary);
}
.dark input,
.dark textarea,
.dark [contenteditable="true"] {
caret-color: var(--text-primary);
}
.dark body {
@apply antialiased;
}
@@ -194,7 +356,7 @@
}
::-webkit-scrollbar-track {
background: #f5f5f5;
background: var(--white);
}
::-webkit-scrollbar-thumb {
@@ -208,7 +370,7 @@
/* Dark Mode Global Scrollbar */
.dark ::-webkit-scrollbar-track {
background: #272727;
background: var(--surface-5);
}
.dark ::-webkit-scrollbar-thumb {
@@ -221,11 +383,11 @@
* {
scrollbar-width: thin;
scrollbar-color: hsl(var(--muted-foreground) / 0.3) #f5f5f5;
scrollbar-color: hsl(var(--muted-foreground) / 0.3) var(--white);
}
.dark * {
scrollbar-color: hsl(var(--muted-foreground) / 0.3) #272727;
scrollbar-color: hsl(var(--muted-foreground) / 0.3) var(--surface-5);
}
.copilot-scrollable {
@@ -241,20 +403,20 @@
}
.panel-tab-active {
background-color: #f5f5f5;
color: #1a1a1a;
border-color: #e5e5e5;
background-color: var(--white);
color: var(--text-inverse);
border-color: var(--border-muted);
}
.dark .panel-tab-active {
background-color: #1f1f1f;
color: #ffffff;
border-color: #424242;
background-color: var(--surface-1);
color: var(--white);
border-color: var(--border-muted);
}
.panel-tab-inactive:hover {
background-color: hsl(var(--secondary));
color: hsl(var(--card-foreground));
background-color: var(--surface-9);
color: var(--text-primary);
}
/**
@@ -332,24 +494,29 @@ input[type="search"]::-ms-clear {
}
.auth-card {
background-color: rgba(255, 255, 255, 0.9) !important;
border-color: #e5e5e5 !important;
background-color: var(--white) !important;
border-color: var(--border-muted) !important;
}
.dark .auth-card {
background-color: var(--surface-1) !important;
border-color: var(--border-muted) !important;
}
.auth-text-primary {
color: #1a1a1a !important;
color: var(--text-inverse) !important;
}
.auth-text-secondary {
color: #4a4a4a !important;
color: var(--text-secondary) !important;
}
.auth-text-muted {
color: #737373 !important;
color: var(--text-muted) !important;
}
.auth-divider {
border-color: #e5e5e5 !important;
border-color: var(--border-muted) !important;
}
.auth-card-shadow {
@@ -359,7 +526,7 @@ input[type="search"]::-ms-clear {
}
.auth-link {
color: #737373 !important;
color: var(--text-muted) !important;
}
.transition-ring {
@@ -399,25 +566,25 @@ input[type="search"]::-ms-clear {
}
.auth-button-gradient {
background: linear-gradient(to bottom, #8357ff, #6f3dfa) !important;
border-color: #6f3dfa !important;
box-shadow: inset 0 2px 4px 0 #9b77ff !important;
background: linear-gradient(to bottom, var(--brand-500), var(--brand-400)) !important;
border-color: var(--brand-400) !important;
box-shadow: inset 0 2px 4px 0 var(--brand-400) !important;
}
.auth-button-gradient:hover {
background: linear-gradient(to bottom, #8357ff, #6f3dfa) !important;
background: linear-gradient(to bottom, var(--brand-500), var(--brand-400)) !important;
opacity: 0.9;
}
.auth-button-custom {
background: var(--brand-accent-hex) !important;
border-color: var(--brand-accent-hex) !important;
background: var(--brand-500) !important;
border-color: var(--brand-500) !important;
box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.1) !important;
}
.auth-button-custom:hover {
background: var(--brand-accent-hover-hex, var(--brand-accent-hex)) !important;
border-color: var(--brand-accent-hover-hex, var(--brand-accent-hex)) !important;
background: var(--brand-500) !important;
border-color: var(--brand-500) !important;
opacity: 1;
}
@@ -440,32 +607,120 @@ input[type="search"]::-ms-clear {
}
html[data-panel-active-tab="copilot"] .panel-container [data-tab-button="copilot"] {
background-color: rgb(53 53 53) !important;
color: rgb(230 230 230) !important;
background-color: var(--surface-11) !important;
color: var(--text-primary) !important;
}
html[data-panel-active-tab="copilot"] .panel-container [data-tab-button="toolbar"],
html[data-panel-active-tab="copilot"] .panel-container [data-tab-button="editor"] {
background-color: transparent !important;
color: rgb(174 174 174) !important;
color: var(--text-tertiary) !important;
}
html[data-panel-active-tab="toolbar"] .panel-container [data-tab-button="toolbar"] {
background-color: rgb(53 53 53) !important;
color: rgb(230 230 230) !important;
background-color: var(--surface-11) !important;
color: var(--text-primary) !important;
}
html[data-panel-active-tab="toolbar"] .panel-container [data-tab-button="copilot"],
html[data-panel-active-tab="toolbar"] .panel-container [data-tab-button="editor"] {
background-color: transparent !important;
color: rgb(174 174 174) !important;
color: var(--text-tertiary) !important;
}
html[data-panel-active-tab="editor"] .panel-container [data-tab-button="editor"] {
background-color: rgb(53 53 53) !important;
color: rgb(230 230 230) !important;
background-color: var(--surface-11) !important;
color: var(--text-primary) !important;
}
html[data-panel-active-tab="editor"] .panel-container [data-tab-button="copilot"],
html[data-panel-active-tab="editor"] .panel-container [data-tab-button="toolbar"] {
background-color: transparent !important;
color: rgb(174 174 174) !important;
color: var(--text-tertiary) !important;
}
}
/**
* @depricated
* Legacy globals (light/dark) kept for backward-compat with old classes.
* Do not modify; remove after migration.
*/
@layer base {
:root,
.light {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--card: 0 0% 99.2%;
--card-foreground: 0 0% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: 0 0% 11.2%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 11.2%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 46.9%;
--accent: 0 0% 92.5%;
--accent-foreground: 0 0% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--input: 0 0% 89.8%;
--input-background: 0 0% 100%;
--ring: 0 0% 3.9%;
--radius: 0.5rem;
--scrollbar-track: 0 0% 85%;
--scrollbar-thumb: 0 0% 65%;
--scrollbar-thumb-hover: 0 0% 55%;
--scrollbar-size: 8px;
--workflow-background: 0 0% 100%;
--card-background: 0 0% 99.2%;
--card-border: 0 0% 89.8%;
--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-primary-hex: #6f3dfa;
--brand-primary-hover-hex: #6338d9;
--brand-accent-hex: #6f3dfa;
--brand-accent-hover-hex: #6f3dfa;
--brand-background-hex: #ffffff;
--surface-elevated: #202020;
}
.dark {
--background: 0 0% 10.59%;
--foreground: 0 0% 98%;
--card: 0 0% 9.0%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 9.0%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 11.2%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 12.0%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 17.5%;
/* --muted-foreground: 0 0% 65.1%; */
--accent: 0 0% 17.5%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--input: 0 0% 16.1%;
--input-background: 0 0% 20.78%;
--ring: 0 0% 83.9%;
--scrollbar-track: 0 0% 17.5%;
--scrollbar-thumb: 0 0% 30%;
--scrollbar-thumb-hover: 0 0% 40%;
--workflow-background: 0 0% 10.59%;
--card-background: 0 0% 9.0%;
--card-border: 0 0% 22.7%;
--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-primary-hex: #701ffc;
--brand-primary-hover-hex: #802fff;
--brand-accent-hex: #9d54ff;
--brand-accent-hover-hex: #a66fff;
--brand-background-hex: #0c0c0c;
--surface-elevated: #202020;
}
}
+1 -1
View File
@@ -129,7 +129,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
var editorParsed = JSON.parse(editorStored);
var editorState = editorParsed?.state;
var connectionsHeight = editorState?.connectionsHeight;
if (connectionsHeight !== undefined && connectionsHeight >= 30 && connectionsHeight <= 200) {
if (connectionsHeight !== undefined && connectionsHeight >= 30 && connectionsHeight <= 300) {
document.documentElement.style.setProperty('--editor-connections-height', connectionsHeight + 'px');
}
}
+16 -14
View File
@@ -7,20 +7,22 @@ import { ThemeProvider as NextThemesProvider } from 'next-themes'
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
const pathname = usePathname()
// Force light mode for certain pages
const forcedTheme =
pathname === '/' ||
pathname.startsWith('/login') ||
pathname.startsWith('/signup') ||
pathname.startsWith('/sso') ||
pathname.startsWith('/terms') ||
pathname.startsWith('/privacy') ||
pathname.startsWith('/invite') ||
pathname.startsWith('/verify') ||
pathname.startsWith('/careers') ||
pathname.startsWith('/changelog') ||
pathname.startsWith('/chat') ||
pathname.startsWith('/studio')
// Force dark mode for workspace pages
// Force light mode for certain public pages
const forcedTheme = pathname.startsWith('/workspace')
? 'dark'
: pathname === '/' ||
pathname.startsWith('/login') ||
pathname.startsWith('/signup') ||
pathname.startsWith('/sso') ||
pathname.startsWith('/terms') ||
pathname.startsWith('/privacy') ||
pathname.startsWith('/invite') ||
pathname.startsWith('/verify') ||
pathname.startsWith('/careers') ||
pathname.startsWith('/changelog') ||
pathname.startsWith('/chat') ||
pathname.startsWith('/studio')
? 'light'
: undefined
@@ -1,8 +1,8 @@
export const filterButtonClass =
'w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
'w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[var(--white)] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
export const dropdownContentClass =
'w-[220px] rounded-lg border-[#E5E5E5] bg-[#FFFFFF] p-0 shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
'w-[220px] rounded-lg border-[#E5E5E5] bg-[var(--white)] p-0 shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
export const commandListClass = 'overflow-y-auto overflow-x-hidden'
@@ -49,7 +49,7 @@ export function Controls({
placeholder='Search workflows...'
value={searchQuery}
onChange={(e) => setSearchQuery?.(e.target.value)}
className='h-9 w-full rounded-[11px] border-[#E5E5E5] bg-[#FFFFFF] pr-10 pl-9 dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
className='h-9 w-full rounded-[11px] border-[#E5E5E5] bg-[var(--white)] pr-10 pl-9 dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
/>
{searchQuery && (
<button
@@ -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-[var(--surface-elevated)]'
className='w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[var(--white)] 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-[var(--surface-elevated)]'
className='w-[180px] rounded-lg border-[#E5E5E5] bg-[var(--white)] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
<DropdownMenuItem
key='all'
@@ -1,8 +1,8 @@
export const filterButtonClass =
'w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
'w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[var(--white)] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
export const dropdownContentClass =
'w-[200px] rounded-lg border-[#E5E5E5] bg-[#FFFFFF] p-0 shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
'w-[200px] rounded-lg border-[#E5E5E5] bg-[var(--white)] p-0 shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
export const commandListClass = 'overflow-y-auto overflow-x-hidden'
@@ -569,7 +569,7 @@ export function Chat() {
return (
<div
className='fixed z-30 flex flex-col overflow-hidden rounded-[6px] bg-[#1E1E1E] px-[10px] pt-[2px] pb-[8px]'
className='fixed z-30 flex flex-col overflow-hidden rounded-[6px] bg-[var(--surface-1)] px-[10px] pt-[2px] pb-[8px]'
style={{
left: `${actualPosition.x}px`,
top: `${actualPosition.y}px`,
@@ -583,11 +583,13 @@ export function Chat() {
>
{/* Header with drag handle */}
<div
className='flex h-[32px] flex-shrink-0 cursor-grab items-center justify-between bg-[#1E1E1E] p-0 active:cursor-grabbing'
className='flex h-[32px] flex-shrink-0 cursor-grab items-center justify-between bg-[var(--surface-1)] p-0 active:cursor-grabbing'
onMouseDown={handleMouseDown}
>
<div className='flex items-center'>
<span className='flex-shrink-0 font-medium text-[#E6E6E6] text-[14px]'>Chat</span>
<span className='flex-shrink-0 font-medium text-[14px] text-[var(--text-primary)]'>
Chat
</span>
</div>
{/* Output selector - centered with mx-auto */}
@@ -683,14 +685,14 @@ export function Chat() {
<div>
<div className='rounded-lg border border-[#883827] bg-[#491515]'>
<div className='flex items-start gap-2'>
<AlertCircle className='mt-0.5 h-3 w-3 shrink-0 text-[#EF4444]' />
<AlertCircle className='mt-0.5 h-3 w-3 shrink-0 text-[var(--text-error)]' />
<div className='flex-1'>
<div className='mb-1 font-medium text-[#EF4444] text-[11px]'>
<div className='mb-1 font-medium text-[11px] text-[var(--text-error)]'>
File upload error
</div>
<div className='space-y-1'>
{uploadErrors.map((err, idx) => (
<div key={idx} className='text-[#EF4444] text-[10px]'>
<div key={idx} className='text-[10px] text-[var(--text-error)]'>
{err}
</div>
))}
@@ -703,10 +705,8 @@ export function Chat() {
{/* Combined input container */}
<div
className={`rounded-[4px] border bg-[#282828] py-0 pr-[6px] pl-[4px] transition-colors dark:bg-[#363636] ${
isDragOver
? 'border-[var(--brand-primary-hover-hex)] bg-purple-50/50 dark:border-[var(--brand-primary-hover-hex)] dark:bg-purple-950/20'
: 'border-[#3D3D3D]'
className={`rounded-[4px] border bg-[var(--surface-9)] py-0 pr-[6px] pl-[4px] transition-colors ${
isDragOver ? 'border-[var(--brand-secondary)]' : 'border-[var(--surface-11)]'
}`}
>
{/* File thumbnails */}
@@ -720,7 +720,7 @@ export function Chat() {
<div
key={file.id}
className={cn(
'group relative flex-shrink-0 overflow-hidden rounded-[6px] bg-[#232323]',
'group relative flex-shrink-0 overflow-hidden rounded-[6px] bg-[var(--surface-2)]',
previewUrl
? 'h-[40px] w-[40px]'
: 'flex min-w-[80px] max-w-[120px] items-center justify-center px-[8px] py-[2px]'
@@ -735,10 +735,10 @@ export function Chat() {
/>
) : (
<div className='min-w-0 flex-1'>
<div className='truncate font-medium text-[#FFFFFF] text-[10px]'>
<div className='truncate font-medium text-[10px] text-[var(--white)]'>
{file.name}
</div>
<div className='text-[#AEAEAE] text-[9px]'>
<div className='text-[9px] text-[var(--text-tertiary)]'>
{formatFileSize(file.size)}
</div>
</div>
@@ -781,7 +781,7 @@ export function Chat() {
onClick={() => document.getElementById('floating-chat-file-input')?.click()}
title='Attach file'
className={cn(
'cursor-pointer rounded-[6px] bg-transparent p-[0px] dark:bg-transparent',
'!bg-transparent cursor-pointer rounded-[6px] p-[0px]',
(!activeWorkflowId || isExecuting || chatFiles.length >= 15) &&
'cursor-not-allowed opacity-50'
)}
@@ -799,8 +799,8 @@ export function Chat() {
className={cn(
'h-[22px] w-[22px] rounded-full p-0 transition-colors',
chatMessage.trim() || chatFiles.length > 0
? 'bg-[#C0C0C0] hover:bg-[#D0D0D0] dark:bg-[#C0C0C0] dark:hover:bg-[#D0D0D0]'
: 'bg-[#C0C0C0] dark:bg-[#C0C0C0]'
? '!bg-[var(--c-C0C0C0)] hover:!bg-[var(--c-D0D0D0)]'
: '!bg-[var(--c-C0C0C0)]'
)}
>
<ArrowUp className='h-3.5 w-3.5 text-black' strokeWidth={2.25} />
@@ -1,5 +1,4 @@
import { useMemo } from 'react'
import { File, FileText, Image as ImageIcon } from 'lucide-react'
import { StreamingIndicator } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/copilot/components/copilot-message/components/smooth-streaming'
interface ChatAttachment {
@@ -33,17 +32,6 @@ const formatFileSize = (bytes?: number): string => {
return `${Math.round((bytes / 1024 ** i) * 10) / 10} ${sizes[i]}`
}
/**
* Returns appropriate icon for file type
*/
const getFileIcon = (type: string) => {
if (type.includes('pdf')) return <FileText className='h-5 w-5 text-muted-foreground' />
if (type.startsWith('image/')) return <ImageIcon className='h-5 w-5 text-muted-foreground' />
if (type.includes('text') || type.includes('json'))
return <FileText className='h-5 w-5 text-muted-foreground' />
return <File className='h-5 w-5 text-muted-foreground' />
}
/**
* Opens image attachment in new window
*/
@@ -123,7 +111,7 @@ export function ChatMessage({ message }: ChatMessageProps) {
return (
<div className='w-full max-w-full overflow-hidden opacity-100 transition-opacity duration-200'>
{message.attachments && message.attachments.length > 0 && (
<div className='mb-2 flex flex-wrap gap-1.5'>
<div className='mb-2 flex flex-wrap gap-[6px]'>
{message.attachments.map((attachment) => {
const isImage = attachment.type.startsWith('image/')
const hasValidDataUrl =
@@ -132,9 +120,9 @@ export function ChatMessage({ message }: ChatMessageProps) {
return (
<div
key={attachment.id}
className={`relative overflow-hidden rounded-md border border-border/50 bg-muted/20 ${
className={`group relative flex-shrink-0 overflow-hidden rounded-[6px] bg-[var(--surface-2)] ${
hasValidDataUrl ? 'cursor-pointer' : ''
} ${isImage ? 'h-16 w-16' : 'flex h-16 min-w-[120px] max-w-[200px] items-center gap-2 px-2'}`}
} ${isImage ? 'h-[40px] w-[40px]' : 'flex min-w-[80px] max-w-[120px] items-center justify-center px-[8px] py-[2px]'}`}
onClick={(e) => {
if (hasValidDataUrl) {
e.preventDefault()
@@ -150,21 +138,16 @@ export function ChatMessage({ message }: ChatMessageProps) {
className='h-full w-full object-cover'
/>
) : (
<>
<div className='flex h-8 w-8 flex-shrink-0 items-center justify-center rounded bg-background/50'>
{getFileIcon(attachment.type)}
<div className='min-w-0 flex-1'>
<div className='truncate font-medium text-[10px] text-[var(--white)]'>
{attachment.name}
</div>
<div className='min-w-0 flex-1'>
<div className='truncate font-medium text-foreground text-xs'>
{attachment.name}
{attachment.size && (
<div className='text-[9px] text-[var(--text-tertiary)]'>
{formatFileSize(attachment.size)}
</div>
{attachment.size && (
<div className='text-[10px] text-muted-foreground'>
{formatFileSize(attachment.size)}
</div>
)}
</div>
</>
)}
</div>
)}
</div>
)
@@ -173,8 +156,8 @@ export function ChatMessage({ message }: ChatMessageProps) {
)}
{formattedContent && !formattedContent.startsWith('Uploaded') && (
<div className='rounded-[4px] border border-[#3D3D3D] bg-[#282828] px-[8px] py-[6px] transition-all duration-200 dark:border-[#3D3D3D] dark:bg-[#363636]'>
<div className='whitespace-pre-wrap break-words font-medium font-sans text-[#0D0D0D] text-sm leading-[1.25rem] dark:text-gray-100'>
<div className='rounded-[4px] border border-[var(--surface-11)] bg-[var(--surface-9)] px-[8px] py-[6px] transition-all duration-200'>
<div className='whitespace-pre-wrap break-words font-medium font-sans text-gray-100 text-sm leading-[1.25rem]'>
<WordWrap text={formattedContent} />
</div>
</div>
@@ -185,7 +168,7 @@ export function ChatMessage({ message }: ChatMessageProps) {
return (
<div className='w-full max-w-full overflow-hidden pl-[2px] opacity-100 transition-opacity duration-200'>
<div className='whitespace-pre-wrap break-words font-[470] font-season text-[#707070] text-sm leading-[1.25rem] dark:text-[#E8E8E8]'>
<div className='whitespace-pre-wrap break-words font-[470] font-season text-[#E8E8E8] text-sm leading-[1.25rem]'>
<WordWrap text={formattedContent} />
{message.isStreaming && <StreamingIndicator />}
</div>
@@ -82,8 +82,8 @@ export function CommandList() {
>
{/* Left side: Icon and Label */}
<div className='flex items-center gap-[8px]'>
<Icon className='h-[14px] w-[14px] text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:group-hover:text-[#E6E6E6]' />
<span className='font-medium text-[#AEAEAE] text-[14px] group-hover:text-[#E6E6E6] dark:group-hover:text-[#E6E6E6]'>
<Icon className='h-[14px] w-[14px] text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]' />
<span className='font-medium text-[14px] text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]'>
{command.label}
</span>
</div>
@@ -91,7 +91,7 @@ export function CommandList() {
{/* Right side: Keyboard Shortcut */}
<div className='flex items-center gap-[4px]'>
<Button
className='group-hover:-translate-y-0.5 w-[26px] py-[3px] text-[12px] hover:translate-y-0 hover:text-[#AEAEAE] hover:shadow-[0_2px_0_0] group-hover:text-[#E6E6E6] group-hover:shadow-[0_4px_0_0] group-hover:dark:text-[#E6E6E6] group-hover:dark:shadow-[#303030] hover:dark:text-[#AEAEAE] hover:dark:shadow-[#303030]'
className='group-hover:-translate-y-0.5 w-[26px] py-[3px] text-[12px] hover:translate-y-0 hover:text-[var(--text-tertiary)] hover:shadow-[0_2px_0_0] group-hover:text-[var(--text-primary)] group-hover:shadow-[0_4px_0_0]'
variant='3d'
>
<span>⌘</span>
@@ -99,7 +99,7 @@ export function CommandList() {
{shortcuts.map((key, index) => (
<Button
key={index}
className='group-hover:-translate-y-0.5 w-[26px] py-[3px] text-[12px] hover:translate-y-0 hover:text-[#AEAEAE] hover:shadow-[0_2px_0_0] group-hover:text-[#E6E6E6] group-hover:shadow-[0_4px_0_0] group-hover:dark:text-[#E6E6E6] group-hover:dark:shadow-[#303030] hover:dark:text-[#AEAEAE] hover:dark:shadow-[#303030]'
className='group-hover:-translate-y-0.5 w-[26px] py-[3px] text-[12px] hover:translate-y-0 hover:text-[var(--text-tertiary)] hover:shadow-[0_2px_0_0] group-hover:text-[var(--text-primary)] group-hover:shadow-[0_4px_0_0]'
variant='3d'
>
{key}
@@ -76,7 +76,7 @@ const CursorsComponent = () => {
{/* Name tag underneath and to the right */}
<div
className='absolute top-[18px] left-[4px] h-[21px] w-[140px] truncate whitespace-nowrap rounded-[2px] p-[6px] font-medium text-[#1E1E1E] text-[11px]'
className='absolute top-[18px] left-[4px] h-[21px] w-[140px] truncate whitespace-nowrap rounded-[2px] p-[6px] font-medium text-[11px] text-[var(--surface-1)]'
style={{ backgroundColor: color }}
>
{name}
@@ -303,12 +303,12 @@ export const DiffControls = memo(function DiffControls() {
return (
<div className='-translate-x-1/2 fixed bottom-20 left-1/2 z-30'>
<div className='flex items-center gap-[6px] rounded-[10px] bg-[#242424] p-[6px]'>
<div className='flex items-center gap-[6px] rounded-[10px] bg-[var(--surface-3)] p-[6px]'>
{/* Toggle (left, icon-only) */}
<Button
variant='ghost'
onClick={handleToggleDiff}
className='h-[30px] w-[30px] rounded-[8px] bg-[#363636] p-0 text-[#868686] hover:bg-[#8E4CFB] hover:text-[#E6E6E6]'
className='h-[30px] w-[30px] rounded-[8px] bg-[var(--surface-9)] p-0 text-[#868686] hover:bg-[var(--brand-400)] hover:text-[var(--text-primary)]'
title={isShowingDiff ? 'View original' : 'Preview changes'}
>
{isShowingDiff ? (
@@ -322,7 +322,7 @@ export const DiffControls = memo(function DiffControls() {
<Button
variant='ghost'
onClick={handleReject}
className='h-[30px] rounded-[8px] bg-[#363636] px-3 text-[#868686] hover:bg-[#8E4CFB] hover:text-[#E6E6E6]'
className='h-[30px] rounded-[8px] bg-[var(--surface-9)] px-3 text-[#868686] hover:bg-[var(--brand-400)] hover:text-[var(--text-primary)]'
title='Reject changes'
>
Reject
@@ -57,7 +57,7 @@ const NoteMarkdown = memo(function NoteMarkdown({ content }: { content: string }
li: ({ children }) => <li className='mb-0'>{children}</li>,
code: ({ inline, children }: any) =>
inline ? (
<code className='rounded bg-[#393939] px-1 py-0.5 text-[#F59E0B] text-xs'>
<code className='rounded bg-[var(--divider)] px-1 py-0.5 text-[#F59E0B] text-xs'>
{children}
</code>
) : (
@@ -70,7 +70,7 @@ const NoteMarkdown = memo(function NoteMarkdown({ content }: { content: string }
href={href}
target='_blank'
rel='noopener noreferrer'
className='text-[#33B4FF] underline-offset-2 hover:underline'
className='text-[var(--brand-secondary)] underline-offset-2 hover:underline'
>
{children}
</a>
@@ -152,14 +152,14 @@ export const NoteBlock = memo(function NoteBlock({ id, data }: NodeProps<NoteBlo
<div className='group relative'>
<div
className={cn(
'relative z-[20] w-[250px] cursor-default select-none rounded-[8px] bg-[#232323]'
'relative z-[20] w-[250px] cursor-default select-none rounded-[8px] bg-[var(--surface-2)]'
)}
onClick={handleClick}
>
<ActionBar blockId={id} blockType={type} disabled={!userPermissions.canEdit} />
<div
className='note-drag-handle flex cursor-grab items-center justify-between border-[#393939] border-b p-[8px] [&:active]:cursor-grabbing'
className='note-drag-handle flex cursor-grab items-center justify-between border-[var(--divider)] border-b p-[8px] [&:active]:cursor-grabbing'
onMouseDown={(event) => {
event.stopPropagation()
}}
@@ -307,7 +307,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
if (inline) {
return (
<code
className='whitespace-normal break-all rounded bg-gray-300 px-1 py-0.5 font-mono text-[#707070] text-[0.9em] dark:bg-[#3D3D3D] dark:text-[#E8E8E8]'
className='whitespace-normal break-all rounded bg-gray-300 px-1 py-0.5 font-mono text-[#707070] text-[0.9em] dark:bg-[var(--surface-11)] dark:text-[#E8E8E8]'
{...props}
>
{children}
@@ -176,7 +176,7 @@ export function ThinkingBlock({
return next
})
}}
className='mb-1 inline-flex items-center gap-1 text-left font-[470] font-season text-[#B1B1B1] text-sm transition-colors hover:text-[#E6E6E6]'
className='mb-1 inline-flex items-center gap-1 text-left font-[470] font-season text-[var(--text-secondary)] text-sm transition-colors hover:text-[var(--text-primary)]'
type='button'
disabled={!hasContent}
>
@@ -194,7 +194,7 @@ export function ThinkingBlock({
</button>
{isExpanded && (
<div className='ml-1 border-[#303030] border-l-2 pl-2'>
<div className='ml-1 border-[var(--border-strong)] border-l-2 pl-2'>
<pre
className='whitespace-pre-wrap font-[470] font-season text-[12px] leading-[1.15rem]'
style={{ color: '#B8B8B8' }}
@@ -267,8 +267,8 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
{/* Inline Checkpoint Discard Confirmation - shown below input in edit mode */}
{showCheckpointDiscardModal && (
<div className='mt-[8px] rounded-[4px] border border-[#3D3D3D] bg-[#282828] p-[10px] dark:border-[#3D3D3D] dark:bg-[#363636]'>
<p className='mb-[8px] text-[#E6E6E6] text-sm'>
<div className='mt-[8px] rounded-[4px] border border-[var(--surface-11)] bg-[var(--surface-6)] p-[10px] dark:border-[var(--surface-11)] dark:bg-[var(--surface-9)]'>
<p className='mb-[8px] text-[var(--text-primary)] text-sm'>
Continue from a previous message?
</p>
<div className='flex gap-[6px]'>
@@ -278,7 +278,7 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
className='flex flex-1 items-center justify-center gap-[6px] px-[8px] py-[4px] text-xs'
>
<span>Cancel</span>
<span className='text-[#787878] text-[10px]'>(Esc)</span>
<span className='text-[10px] text-[var(--text-muted)]'>(Esc)</span>
</Button>
<Button
onClick={handleContinueAndRevert}
@@ -314,7 +314,7 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
onClick={handleMessageClick}
onMouseEnter={() => setIsHoveringMessage(true)}
onMouseLeave={() => setIsHoveringMessage(false)}
className='group relative w-full cursor-pointer rounded-[4px] border border-[#3D3D3D] bg-[#282828] px-[6px] py-[6px] transition-all duration-200 hover:border-[#4A4A4A] hover:bg-[#363636] dark:border-[#3D3D3D] dark:bg-[#363636] dark:hover:border-[#454545] dark:hover:bg-[#3D3D3D]'
className='group relative w-full cursor-pointer rounded-[4px] border border-[var(--surface-11)] bg-[var(--surface-6)] px-[6px] py-[6px] transition-all duration-200 hover:border-[var(--surface-14)] hover:bg-[var(--surface-9)] dark:border-[var(--surface-11)] dark:bg-[var(--surface-9)] dark:hover:border-[var(--surface-13)] dark:hover:bg-[var(--surface-11)]'
>
<div
ref={messageContentRef}
@@ -360,7 +360,7 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
{/* Gradient fade when truncated - applies to entire message box */}
{!isExpanded && needsExpansion && (
<div className='pointer-events-none absolute right-0 bottom-0 left-0 h-6 bg-gradient-to-t from-0% from-[#282828] via-40% via-[#282828]/70 to-100% to-transparent group-hover:from-[#363636] group-hover:via-[#363636]/70 dark:from-[#363636] dark:via-[#363636]/70 dark:group-hover:from-[#3D3D3D] dark:group-hover:via-[#3D3D3D]/70' />
<div className='pointer-events-none absolute right-0 bottom-0 left-0 h-6 bg-gradient-to-t from-0% from-[var(--surface-6)] via-40% via-[var(--surface-6)]/70 to-100% to-transparent group-hover:from-[var(--surface-9)] group-hover:via-[var(--surface-9)]/70 dark:from-[var(--surface-9)] dark:via-[var(--surface-9)]/70 dark:group-hover:from-[var(--surface-11)] dark:group-hover:via-[var(--surface-11)]/70' />
)}
{/* Abort button when hovering and response is generating (only on last user message) */}
@@ -408,11 +408,13 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
{/* Inline Restore Checkpoint Confirmation */}
{showRestoreConfirmation && (
<div className='mt-[8px] rounded-[4px] border border-[#3D3D3D] bg-[#282828] p-[10px] dark:border-[#3D3D3D] dark:bg-[#363636]'>
<p className='mb-[8px] text-[#E6E6E6] text-sm'>
<div className='mt-[8px] rounded-[4px] border border-[var(--surface-11)] bg-[var(--surface-6)] p-[10px] dark:border-[var(--surface-11)] dark:bg-[var(--surface-9)]'>
<p className='mb-[8px] text-[var(--text-primary)] text-sm'>
Revert to checkpoint? This will restore your workflow to the state saved at this
checkpoint.{' '}
<span className='font-medium text-[#EF4444]'>This action cannot be undone.</span>
<span className='font-medium text-[var(--text-error)]'>
This action cannot be undone.
</span>
</p>
<div className='flex gap-[6px]'>
<Button
@@ -421,7 +423,7 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
className='flex flex-1 items-center justify-center gap-[6px] px-[8px] py-[4px] text-xs'
>
<span>Cancel</span>
<span className='text-[#787878] text-[10px]'>(Esc)</span>
<span className='text-[10px] text-[var(--text-muted)]'>(Esc)</span>
</Button>
<Button
onClick={handleConfirmRevert}
@@ -66,7 +66,7 @@ export const TodoList = memo(function TodoList({
return (
<div
className={cn(
'w-full rounded-t-[4px] rounded-b-none border-[#3D3D3D] border-x border-t bg-[#282828] dark:border-[#3D3D3D] dark:bg-[#363636]',
'w-full rounded-t-[4px] rounded-b-none border-[var(--surface-11)] border-x border-t bg-[var(--surface-6)] dark:border-[var(--surface-11)] dark:bg-[var(--surface-9)]',
className
)}
>
@@ -84,17 +84,19 @@ export const TodoList = memo(function TodoList({
<ChevronDown className='h-[14px] w-[14px]' />
)}
</Button>
<span className='font-medium text-[#E6E6E6] text-xs dark:text-[#E6E6E6]'>Todo:</span>
<span className='font-medium text-[#E6E6E6] text-xs dark:text-[#E6E6E6]'>
<span className='font-medium text-[var(--text-primary)] text-xs dark:text-[var(--text-primary)]'>
Todo:
</span>
<span className='font-medium text-[var(--text-primary)] text-xs dark:text-[var(--text-primary)]'>
{completedCount}/{totalCount}
</span>
</div>
<div className='flex flex-1 items-center gap-[8px] pl-[10px]'>
{/* Progress bar */}
<div className='h-1.5 flex-1 overflow-hidden rounded-full bg-[#3D3D3D] dark:bg-[#3D3D3D]'>
<div className='h-1.5 flex-1 overflow-hidden rounded-full bg-[var(--surface-11)] dark:bg-[var(--surface-11)]'>
<div
className='h-full bg-[#8E4CFB] transition-all duration-300 ease-out dark:bg-[#8E4CFB]'
className='h-full bg-[var(--brand-400)] transition-all duration-300 ease-out dark:bg-[var(--brand-400)]'
style={{ width: `${progress}%` }}
/>
</div>
@@ -119,20 +121,21 @@ export const TodoList = memo(function TodoList({
<div
key={todo.id}
className={cn(
'flex items-start gap-2 px-3 py-1.5 transition-colors hover:bg-[#363636]/50 dark:hover:bg-[#3D3D3D]/50',
index !== todos.length - 1 && 'border-[#3D3D3D] border-b dark:border-[#3D3D3D]'
'flex items-start gap-2 px-3 py-1.5 transition-colors hover:bg-[var(--surface-9)]/50 dark:hover:bg-[var(--surface-11)]/50',
index !== todos.length - 1 &&
'border-[var(--surface-11)] border-b dark:border-[var(--surface-11)]'
)}
>
{todo.executing ? (
<div className='mt-0.5 flex h-4 w-4 flex-shrink-0 items-center justify-center'>
<Loader2 className='h-3 w-3 animate-spin text-[#E6E6E6] dark:text-[#E6E6E6]' />
<Loader2 className='h-3 w-3 animate-spin text-[var(--text-primary)] dark:text-[var(--text-primary)]' />
</div>
) : (
<div
className={cn(
'mt-0.5 flex h-4 w-4 flex-shrink-0 items-center justify-center rounded border transition-all',
todo.completed
? 'border-[#8E4CFB] bg-[#8E4CFB] dark:border-[#8E4CFB] dark:bg-[#8E4CFB]'
? 'border-[var(--brand-400)] bg-[var(--brand-400)] dark:border-[var(--brand-400)] dark:bg-[var(--brand-400)]'
: 'border-[#707070] dark:border-[#707070]'
)}
>
@@ -144,8 +147,8 @@ export const TodoList = memo(function TodoList({
className={cn(
'flex-1 font-base text-[12px] leading-relaxed',
todo.completed
? 'text-[#787878] line-through dark:text-[#787878]'
: 'text-[#FFFFFF] dark:text-[#FFFFFF]'
? 'text-[var(--text-muted)] line-through dark:text-[var(--text-muted)]'
: 'text-[var(--white)] dark:text-[var(--white)]'
)}
>
{todo.content}
@@ -583,7 +583,9 @@ export function MentionMenu({
<span className='flex-1 truncate'>{item.label}</span>
{item.category === 'logs' && (
<>
<span className='text-[#AEAEAE] text-[10px] dark:text-[#AEAEAE]'>·</span>
<span className='text-[10px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]'>
·
</span>
<span className='whitespace-nowrap text-[10px]'>
{formatTimestamp(item.data.createdAt)}
</span>
@@ -756,11 +758,15 @@ export function MentionMenu({
mentionData.logsList.map((log) => (
<PopoverItem key={log.id} onClick={() => insertLogMention(log)}>
<span className='min-w-0 flex-1 truncate'>{log.workflowName}</span>
<span className='text-[#AEAEAE] text-[10px] dark:text-[#AEAEAE]'>·</span>
<span className='text-[10px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]'>
·
</span>
<span className='whitespace-nowrap text-[10px]'>
{formatTimestamp(log.createdAt)}
</span>
<span className='text-[#AEAEAE] text-[10px] dark:text-[#AEAEAE]'>·</span>
<span className='text-[10px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]'>
·
</span>
<span className='text-[10px] capitalize'>
{(log.trigger || 'manual').toLowerCase()}
</span>
@@ -568,8 +568,8 @@ const UserInput = forwardRef<UserInputRef, UserInputProps>(
<div
ref={setInputContainerRef}
className={cn(
'relative w-full rounded-[4px] border border-[#3D3D3D] bg-[#282828] px-[6px] py-[6px] transition-colors dark:bg-[#363636]',
fileAttachments.isDragging && 'ring-[#33B4FF] ring-[1.75px]'
'relative w-full rounded-[4px] border border-[var(--surface-11)] bg-[var(--surface-6)] px-[6px] py-[6px] transition-colors dark:bg-[var(--surface-9)]',
fileAttachments.isDragging && 'ring-[1.75px] ring-[var(--brand-secondary)]'
)}
onDragEnter={fileAttachments.handleDragEnter}
onDragLeave={fileAttachments.handleDragLeave}
@@ -635,7 +635,7 @@ const UserInput = forwardRef<UserInputRef, UserInputProps>(
placeholder={fileAttachments.isDragging ? 'Drop files here...' : effectivePlaceholder}
disabled={disabled}
rows={2}
className='relative z-[2] m-0 box-border h-auto min-h-[48px] w-full resize-none overflow-y-auto overflow-x-hidden break-words border-0 bg-transparent px-[2px] py-1 font-medium font-sans text-sm text-transparent leading-[1.25rem] caret-foreground outline-none [-ms-overflow-style:none] [scrollbar-width:none] [text-rendering:auto] focus-visible:ring-0 focus-visible:ring-offset-0 [&::-webkit-scrollbar]:hidden'
className='relative z-[2] m-0 box-border h-auto min-h-[48px] w-full resize-none overflow-y-auto overflow-x-hidden break-words border-0 bg-transparent px-[2px] py-1 font-medium font-sans text-sm text-transparent leading-[1.25rem] caret-foreground outline-none [-ms-overflow-style:none] [scrollbar-width:none] [text-rendering:auto] placeholder:text-[var(--text-muted)] focus-visible:ring-0 focus-visible:ring-offset-0 dark:placeholder:text-[var(--text-muted)] [&::-webkit-scrollbar]:hidden'
/>
{/* Mention Menu Portal */}
@@ -64,14 +64,16 @@ export function Welcome({ onQuestionClick, mode = 'ask' }: WelcomeProps) {
>
<div className='flex flex-col items-start'>
<p className='font-medium'>{title}</p>
<p className='text-[#B1B1B1] dark:text-[#B1B1B1]'>{question}</p>
<p className='text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'>
{question}
</p>
</div>
</Button>
))}
</div>
{/* Tips */}
<p className='pt-[12px] text-center text-[#B1B1B1] text-[13px] dark:text-[#B1B1B1]'>
<p className='pt-[12px] text-center text-[13px] text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'>
Tip: Use <span className='font-medium'>@</span> to reference chats, workflows, knowledge,
blocks, or templates
</p>
@@ -334,7 +334,7 @@ export const Copilot = forwardRef<CopilotRef, CopilotProps>(({ panelWidth }, ref
>
{/* Header */}
<div className='flex flex-shrink-0 items-center justify-between rounded-[4px] bg-[#2A2A2A] px-[12px] py-[8px] dark:bg-[#2A2A2A]'>
<h2 className='font-medium text-[#FFFFFF] text-[14px] dark:text-[#FFFFFF]'>
<h2 className='font-medium text-[14px] text-[var(--white)] dark:text-[var(--white)]'>
{currentChat?.title || 'New Chat'}
</h2>
<div className='flex items-center gap-[8px]'>
@@ -353,7 +353,7 @@ export const Copilot = forwardRef<CopilotRef, CopilotProps>(({ panelWidth }, ref
<ChatHistorySkeleton />
</PopoverScrollArea>
) : groupedChats.length === 0 ? (
<div className='px-[6px] py-[16px] text-center text-[#FFFFFF] text-[12px] dark:text-[#FFFFFF]'>
<div className='px-[6px] py-[16px] text-center text-[12px] text-[var(--white)] dark:text-[var(--white)]'>
No chats yet
</div>
) : (
@@ -91,7 +91,7 @@ export function FieldItem({
onDragStart={handleDragStart}
onClick={handleClick}
className={clsx(
'group flex h-[25px] cursor-grab items-center gap-[8px] rounded-[8px] px-[8px] text-[14px] hover:bg-[#2C2C2C] active:cursor-grabbing dark:hover:bg-[#2C2C2C]',
'group flex h-[25px] cursor-grab items-center gap-[8px] rounded-[8px] px-[8px] text-[14px] hover:bg-[var(--border)] active:cursor-grabbing dark:hover:bg-[var(--border)]',
hasChildren && 'cursor-pointer'
)}
style={{ marginLeft: `${indent}px` }}
@@ -99,7 +99,7 @@ export function FieldItem({
<span
className={clsx(
'flex-1 truncate font-medium',
'text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]'
'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:group-hover:text-[var(--text-primary)]'
)}
>
{field.name}
@@ -109,7 +109,7 @@ export function FieldItem({
<ChevronDown
className={clsx(
'h-3.5 w-3.5 flex-shrink-0 transition-transform',
'text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]',
'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:group-hover:text-[var(--text-primary)]',
isExpanded && 'rotate-180'
)}
/>
@@ -119,7 +119,7 @@ function ConnectionItem({
draggable
onDragStart={(e) => onConnectionDragStart(e, connection)}
className={clsx(
'group flex h-[25px] cursor-grab items-center gap-[8px] rounded-[8px] px-[5.5px] text-[14px] hover:bg-[#2C2C2C] active:cursor-grabbing dark:hover:bg-[#2C2C2C]',
'group flex h-[25px] cursor-grab items-center gap-[8px] rounded-[8px] px-[5.5px] text-[14px] hover:bg-[var(--border)] active:cursor-grabbing dark:hover:bg-[var(--border)]',
hasFields && 'cursor-pointer'
)}
onClick={() => hasFields && onToggleExpand(connection.id)}
@@ -141,7 +141,7 @@ function ConnectionItem({
<span
className={clsx(
'truncate font-medium',
'text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]'
'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:group-hover:text-[var(--text-primary)]'
)}
>
{connection.name}
@@ -150,7 +150,7 @@ function ConnectionItem({
<ChevronDown
className={clsx(
'h-3.5 w-3.5 flex-shrink-0 transition-transform',
'text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]',
'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:group-hover:text-[var(--text-primary)]',
isExpanded && 'rotate-180'
)}
/>
@@ -49,7 +49,7 @@ function CheckboxItem({ blockId, option, isPreview, subBlockValues, disabled }:
/>
<Label
htmlFor={`${blockId}-${option.id}`}
className='cursor-pointer font-medium font-sans text-[#E6E6E6] text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50'
className='cursor-pointer font-medium font-sans text-[var(--text-primary)] text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50'
>
{option.label}
</Label>
@@ -708,17 +708,19 @@ export function ConditionInput({
{conditionalBlocks.map((block, index) => (
<div
key={block.id}
className='group relative overflow-visible rounded-[4px] border border-[#303030] bg-[#1F1F1F]'
className='group relative overflow-visible rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F]'
>
<div
className={cn(
'flex items-center justify-between overflow-hidden bg-transparent px-[10px] py-[5px]',
block.title === 'else'
? 'rounded-[4px] border-0'
: 'rounded-t-[4px] border-[#303030] border-b'
: 'rounded-t-[4px] border-[var(--border-strong)] border-b'
)}
>
<span className='font-medium text-[#AEAEAE] text-[14px]'>{block.title}</span>
<span className='font-medium text-[14px] text-[var(--text-tertiary)]'>
{block.title}
</span>
<div className='flex items-center gap-[8px]'>
<Tooltip.Root>
<Tooltip.Trigger asChild>
@@ -777,7 +779,7 @@ export function ConditionInput({
variant='ghost'
onClick={() => removeBlock(block.id)}
disabled={isPreview || conditionalBlocks.length === 1 || disabled}
className='h-auto p-0 text-[#EF4444] hover:text-[#EF4444]'
className='h-auto p-0 text-[var(--text-error)] hover:text-[var(--text-error)]'
>
<Trash className='h-[14px] w-[14px]' />
<span className='sr-only'>Delete Block</span>
@@ -284,7 +284,7 @@ export const EnvVarDropdown: React.FC<EnvVarDropdownProps> = ({
onCloseAutoFocus={(e) => e.preventDefault()}
>
{filteredEnvVars.length === 0 ? (
<div className='px-[6px] py-[8px] text-[#FFFFFF]/60 text-[12px]'>
<div className='px-[6px] py-[8px] text-[12px] text-[var(--white)]/60'>
No matching environment variables
</div>
) : (
@@ -130,8 +130,10 @@ export function EvalInput({
}
const renderMetricHeader = (metric: EvalMetric, index: number) => (
<div className='flex items-center justify-between overflow-hidden rounded-t-[4px] border-[#303030] border-b bg-transparent px-[10px] py-[5px]'>
<span className='font-medium text-[#AEAEAE] text-[14px]'>Metric {index + 1}</span>
<div className='flex items-center justify-between overflow-hidden rounded-t-[4px] border-[var(--border-strong)] border-b bg-transparent px-[10px] py-[5px]'>
<span className='font-medium text-[14px] text-[var(--text-tertiary)]'>
Metric {index + 1}
</span>
<div className='flex items-center gap-[8px]'>
<Tooltip.Root key={`add-${metric.id}`}>
<Tooltip.Trigger asChild>
@@ -154,7 +156,7 @@ export function EvalInput({
variant='ghost'
onClick={() => removeMetric(metric.id)}
disabled={isPreview || disabled || metrics.length === 1}
className='h-auto p-0 text-[#EF4444] hover:text-[#EF4444]'
className='h-auto p-0 text-[var(--text-error)] hover:text-[var(--text-error)]'
>
<Trash className='h-[14px] w-[14px]' />
<span className='sr-only'>Delete Metric</span>
@@ -172,11 +174,11 @@ export function EvalInput({
<div
key={metric.id}
data-metric-id={metric.id}
className='group relative overflow-visible rounded-[4px] border border-[#303030] bg-[#1F1F1F]'
className='group relative overflow-visible rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F]'
>
{renderMetricHeader(metric, index)}
<div className='flex flex-col gap-[6px] border-[#303030] px-[10px] pt-[6px] pb-[10px]'>
<div className='flex flex-col gap-[6px] border-[var(--border-strong)] px-[10px] pt-[6px] pb-[10px]'>
<div key={`name-${metric.id}`} className='space-y-[4px]'>
<Label className='text-[13px]'>Name</Label>
<Input
@@ -247,9 +247,9 @@ export function InputMapping({
if (!selectedWorkflowId) {
return (
<div className='flex flex-col items-center justify-center rounded-[4px] border border-[#303030] bg-[#1F1F1F] p-8 text-center'>
<div className='flex flex-col items-center justify-center rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F] p-8 text-center'>
<svg
className='mb-3 h-10 w-10 text-[#AEAEAE]'
className='mb-3 h-10 w-10 text-[var(--text-tertiary)]'
fill='none'
viewBox='0 0 24 24'
stroke='currentColor'
@@ -261,8 +261,8 @@ export function InputMapping({
d='M13 10V3L4 14h7v7l9-11h-7z'
/>
</svg>
<p className='font-medium text-[#AEAEAE] text-sm'>No workflow selected</p>
<p className='mt-1 text-[#AEAEAE]/80 text-xs'>
<p className='font-medium text-[var(--text-tertiary)] text-sm'>No workflow selected</p>
<p className='mt-1 text-[var(--text-tertiary)]/80 text-xs'>
Select a workflow above to configure inputs
</p>
</div>
@@ -290,7 +290,7 @@ export function InputMapping({
}
if (!childInputFields || childInputFields.length === 0) {
return <p className='text-[#787878] text-sm'>No inputs available</p>
return <p className='text-[var(--text-muted)] text-sm'>No inputs available</p>
}
return (
@@ -354,22 +354,22 @@ function InputMappingField({
}
return (
<div className='group relative overflow-visible rounded-[4px] border border-[#303030] bg-[#1F1F1F]'>
<div className='group relative overflow-visible rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F]'>
<div className='flex items-center justify-between bg-transparent px-[10px] py-[5px]'>
<Label className='font-medium text-[#AEAEAE] text-[14px]'>{fieldName}</Label>
<Label className='font-medium text-[14px] text-[var(--text-tertiary)]'>{fieldName}</Label>
{fieldType && (
<span className='rounded-md bg-[#2A2A2A] px-1.5 py-0.5 font-mono text-[#AEAEAE] text-[10px]'>
<span className='rounded-md bg-[#2A2A2A] px-1.5 py-0.5 font-mono text-[10px] text-[var(--text-tertiary)]'>
{fieldType}
</span>
)}
</div>
<div className='relative w-full border-[#303030] border-t bg-transparent'>
<div className='relative w-full border-[var(--border-strong)] border-t bg-transparent'>
<Input
ref={(el) => {
if (el) inputRefs.current.set(fieldId, el)
}}
className={cn(
'allow-scroll !bg-transparent w-full overflow-auto rounded-none border-0 px-[10px] py-[8px] text-transparent caret-white [-ms-overflow-style:none] [scrollbar-width:none] placeholder:text-[#787878] focus-visible:ring-0 focus-visible:ring-offset-0 [&::-webkit-scrollbar]:hidden'
'allow-scroll !bg-transparent w-full overflow-auto rounded-none border-0 px-[10px] py-[8px] text-transparent caret-white [-ms-overflow-style:none] [scrollbar-width:none] placeholder:text-[var(--text-muted)] focus-visible:ring-0 focus-visible:ring-offset-0 [&::-webkit-scrollbar]:hidden'
)}
type='text'
value={value}
@@ -326,13 +326,13 @@ export function LongInput({
{/* Custom resize handle */}
{!wandHook.isStreaming && (
<div
className='absolute right-1 bottom-1 flex h-4 w-4 cursor-ns-resize items-center justify-center rounded-[4px] border border-[#3D3D3D] bg-[#282828] dark:bg-[#363636]'
className='absolute right-1 bottom-1 flex h-4 w-4 cursor-ns-resize items-center justify-center rounded-[4px] border border-[var(--surface-11)] bg-[var(--surface-6)] dark:bg-[var(--surface-9)]'
onMouseDown={startResize}
onDragStart={(e) => {
e.preventDefault()
}}
>
<ChevronsUpDown className='h-3 w-3 text-[#787878]' />
<ChevronsUpDown className='h-3 w-3 text-[var(--text-muted)]' />
</div>
)}
</div>
@@ -165,7 +165,7 @@ export function FieldFormat({
onClick={() => toggleCollapse(field.id)}
>
<div className='flex min-w-0 flex-1 items-center gap-[8px]'>
<span className='block truncate font-medium text-[#AEAEAE] text-[14px]'>
<span className='block truncate font-medium text-[14px] text-[var(--text-tertiary)]'>
{field.name || `${title} ${index + 1}`}
</span>
{field.name && showType && <Badge className='h-[20px] text-[13px]'>{field.type}</Badge>}
@@ -179,7 +179,7 @@ export function FieldFormat({
variant='ghost'
onClick={() => removeField(field.id)}
disabled={isReadOnly || fields.length === 1}
className='h-auto p-0 text-[#EF4444] hover:text-[#EF4444]'
className='h-auto p-0 text-[var(--text-error)] hover:text-[var(--text-error)]'
>
<Trash className='h-[14px] w-[14px]' />
<span className='sr-only'>Delete Field</span>
@@ -240,7 +240,7 @@ export function FieldFormat({
return Array.from({ length: lineCount }, (_, i) => (
<div
key={i}
className='font-medium font-mono text-[#787878] text-xs'
className='font-medium font-mono text-[var(--text-muted)] text-xs'
style={{ height: `${21}px`, lineHeight: `${21}px` }}
>
{i + 1}
@@ -279,7 +279,7 @@ export function FieldFormat({
return Array.from({ length: lineCount }, (_, i) => (
<div
key={i}
className='font-medium font-mono text-[#787878] text-xs'
className='font-medium font-mono text-[var(--text-muted)] text-xs'
style={{ height: `${21}px`, lineHeight: `${21}px` }}
>
{i + 1}
@@ -364,14 +364,14 @@ export function FieldFormat({
key={field.id}
data-field-id={field.id}
className={cn(
'rounded-[4px] border border-[#303030] bg-[#1F1F1F]',
'rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F]',
field.collapsed ? 'overflow-hidden' : 'overflow-visible'
)}
>
{renderFieldHeader(field, index)}
{!field.collapsed && (
<div className='flex flex-col gap-[6px] border-[#303030] border-t px-[10px] pt-[6px] pb-[10px]'>
<div className='flex flex-col gap-[6px] border-[var(--border-strong)] border-t px-[10px] pt-[6px] pb-[10px]'>
<div className='flex flex-col gap-[4px]'>
<Label className='text-[13px]'>Name</Label>
<Input
@@ -43,7 +43,7 @@ export function Switch({
/>
<Label
htmlFor={`${blockId}-${subBlockId}`}
className='cursor-pointer font-medium font-sans text-[#E6E6E6] text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50'
className='cursor-pointer font-medium font-sans text-[var(--text-primary)] text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50'
>
{title}
</Label>
@@ -134,13 +134,13 @@ export function Table({
const renderHeader = () => (
<thead className='bg-transparent'>
<tr className='border-[#303030] border-b bg-transparent'>
<tr className='border-[var(--border-strong)] border-b bg-transparent'>
{columns.map((column, index) => (
<th
key={column}
className={cn(
'bg-transparent px-[10px] py-[5px] text-left font-medium text-[#AEAEAE] text-[14px]',
index < columns.length - 1 && 'border-[#303030] border-r'
'bg-transparent px-[10px] py-[5px] text-left font-medium text-[14px] text-[var(--text-tertiary)]',
index < columns.length - 1 && 'border-[var(--border-strong)] border-r'
)}
>
{column}
@@ -187,7 +187,7 @@ export function Table({
key={`${row.id}-${column}`}
className={cn(
'relative bg-transparent p-0',
cellIndex < columns.length - 1 && 'border-[#303030] border-r'
cellIndex < columns.length - 1 && 'border-[var(--border-strong)] border-r'
)}
>
<div className='relative w-full'>
@@ -203,7 +203,7 @@ export function Table({
onDragOver={handlers.onDragOver}
disabled={isPreview || disabled}
autoComplete='off'
className='w-full border-0 bg-transparent px-[10px] py-[8px] text-transparent caret-white placeholder:text-[#787878] focus-visible:ring-0 focus-visible:ring-offset-0'
className='w-full border-0 bg-transparent px-[10px] py-[8px] text-transparent caret-white placeholder:text-[var(--text-muted)] focus-visible:ring-0 focus-visible:ring-offset-0'
/>
<div
data-overlay={cellKey}
@@ -270,12 +270,15 @@ export function Table({
return (
<div className='relative'>
<div className='overflow-visible rounded-[4px] border border-[#303030] bg-[#1F1F1F]'>
<div className='overflow-visible rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F]'>
<table className='w-full bg-transparent'>
{renderHeader()}
<tbody className='bg-transparent'>
{rows.map((row, rowIndex) => (
<tr key={row.id} className='group relative border-[#303030] border-t bg-transparent'>
<tr
key={row.id}
className='group relative border-[var(--border-strong)] border-t bg-transparent'
>
{columns.map((column, cellIndex) => renderCell(row, rowIndex, column, cellIndex))}
{renderDeleteButton(rowIndex)}
</tr>
@@ -1324,7 +1324,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
/>
<PopoverScrollArea>
{flatTagList.length === 0 ? (
<div className='px-[6px] py-[8px] text-[#FFFFFF]/60 text-[12px]'>
<div className='px-[6px] py-[8px] text-[12px] text-[var(--white)]/60'>
No matching tags found
</div>
) : (
@@ -1362,7 +1362,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
: tag}
</span>
{variableInfo && (
<span className='ml-auto text-[#FFFFFF]/60 text-[10px]'>
<span className='ml-auto text-[10px] text-[var(--white)]/60'>
{variableInfo.type}
</span>
)}
@@ -1468,7 +1468,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
<TagIcon icon={tagIcon} color={blockColor} />
<span className='flex-1 truncate'>{child.display}</span>
{childType && childType !== 'any' && (
<span className='ml-auto text-[#FFFFFF]/60 text-[10px]'>
<span className='ml-auto text-[10px] text-[var(--white)]/60'>
{childType}
</span>
)}
@@ -1547,7 +1547,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
<TagIcon icon={displayIcon} color={blockColor} />
<span className='flex-1 truncate'>{nestedTag.display}</span>
{tagDescription && tagDescription !== 'any' && (
<span className='ml-auto text-[#FFFFFF]/60 text-[10px]'>
<span className='ml-auto text-[10px] text-[var(--white)]/60'>
{tagDescription}
</span>
)}
@@ -27,7 +27,7 @@ export function Text({ blockId, subBlockId, content, className }: TextProps) {
return (
<div
id={`${blockId}-${subBlockId}`}
className={`rounded-md border bg-[#232323] p-4 shadow-sm ${className || ''}`}
className={`rounded-md border bg-[var(--surface-2)] p-4 shadow-sm ${className || ''}`}
>
<div
className='prose prose-sm dark:prose-invert max-w-none break-words text-sm [&_a]:text-blue-600 [&_a]:underline [&_a]:hover:text-blue-700 [&_a]:dark:text-blue-400 [&_a]:dark:hover:text-blue-300 [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:text-xs [&_strong]:font-semibold [&_ul]:ml-5 [&_ul]:list-disc'
@@ -40,7 +40,7 @@ export function Text({ blockId, subBlockId, content, className }: TextProps) {
return (
<div
id={`${blockId}-${subBlockId}`}
className={`whitespace-pre-wrap break-words rounded-md border bg-[#232323] p-4 text-muted-foreground text-sm shadow-sm ${className || ''}`}
className={`whitespace-pre-wrap break-words rounded-md border bg-[var(--surface-2)] p-4 text-muted-foreground text-sm shadow-sm ${className || ''}`}
>
{content}
</div>
@@ -125,7 +125,7 @@ export function TimeInput({
type='text'
autoComplete='off'
/>
<span className='text-[#E6E6E6]'>:</span>
<span className='text-[var(--text-primary)]'>:</span>
<Input
className='w-[4rem]'
value={minute}
@@ -181,7 +181,7 @@ export function CommandEmpty({ children, className }: CommandEmptyProps) {
if (filteredItems.length > 0) return null
return (
<div className={cn('px-[6px] py-[8px] text-[#FFFFFF]/60 text-[12px]', className)}>
<div className={cn('px-[6px] py-[8px] text-[12px] text-[var(--white)]/60', className)}>
{children}
</div>
)
@@ -213,8 +213,8 @@ export function CommandItem({
<button
id={value}
className={cn(
'flex h-[25px] w-full cursor-pointer select-none items-center gap-[8px] rounded-[6px] px-[6px] font-base text-[#E6E6E6] text-[12px] outline-none transition-colors hover:bg-[#363636] hover:text-[#E6E6E6] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 data-[disabled=true]:pointer-events-none data-[selected=true]:bg-[#363636] data-[selected=true]:text-[#E6E6E6] data-[disabled=true]:opacity-50',
(isActive || isHovered) && 'bg-[#363636] text-[#E6E6E6]',
'flex h-[25px] w-full cursor-pointer select-none items-center gap-[8px] rounded-[6px] px-[6px] font-base text-[12px] text-[var(--text-primary)] outline-none transition-colors hover:bg-[var(--surface-9)] hover:text-[var(--text-primary)] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 data-[disabled=true]:pointer-events-none data-[selected=true]:bg-[var(--surface-9)] data-[selected=true]:text-[var(--text-primary)] data-[disabled=true]:opacity-50',
(isActive || isHovered) && 'bg-[var(--surface-9)] text-[var(--text-primary)]',
className
)}
onClick={() => !disabled && onSelect?.()}
@@ -1095,13 +1095,13 @@ export function ToolInput({
case 'dropdown':
return (
<Select value={value} onValueChange={onChange}>
<SelectTrigger className='w-full rounded-[4px] border border-[#303030] bg-[#1F1F1F] px-[10px] py-[8px] text-left font-medium text-sm'>
<SelectTrigger className='w-full rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F] px-[10px] py-[8px] text-left font-medium text-sm'>
<SelectValue
placeholder={uiComponent.placeholder || 'Select option'}
className='truncate'
/>
</SelectTrigger>
<SelectContent className='border-[#303030] bg-[#1F1F1F]'>
<SelectContent className='border-[var(--border-strong)] bg-[#1F1F1F]'>
{uiComponent.options
?.filter((option: any) => option.id !== '')
.map((option: any) => (
@@ -1321,8 +1321,8 @@ export function ToolInput({
{selectedTools.length === 0 ? (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<div className='flex w-full cursor-pointer items-center justify-center rounded-[4px] border border-[#303030] bg-[#1F1F1F] px-[10px] py-[6px] font-medium text-sm transition-colors hover:bg-[#252525]'>
<div className='flex items-center text-[#787878] text-[13px]'>
<div className='flex w-full cursor-pointer items-center justify-center rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F] px-[10px] py-[6px] font-medium text-sm transition-colors hover:bg-[var(--surface-4)]'>
<div className='flex items-center text-[13px] text-[var(--text-muted)]'>
<PlusIcon className='mr-2 h-4 w-4' />
Add Tool
</div>
@@ -1540,7 +1540,7 @@ export function ToolInput({
<div
key={`${tool.toolId}-${toolIndex}`}
className={cn(
'group relative flex flex-col overflow-visible rounded-[4px] border border-[#303030] bg-[#1F1F1F] transition-all duration-200 ease-in-out',
'group relative flex flex-col overflow-visible rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F] transition-all duration-200 ease-in-out',
draggedIndex === toolIndex ? 'scale-95 opacity-40' : '',
dragOverIndex === toolIndex && draggedIndex !== toolIndex && draggedIndex !== null
? 'translate-y-1 transform border-t-2 border-t-muted-foreground/40'
@@ -1558,7 +1558,9 @@ export function ToolInput({
<div
className={cn(
'flex items-center justify-between px-[10px] py-[8px]',
isExpandedForDisplay && !isCustomTool && 'border-[#303030] border-b',
isExpandedForDisplay &&
!isCustomTool &&
'border-[var(--border-strong)] border-b',
'cursor-pointer'
)}
onClick={() => {
@@ -1617,21 +1619,21 @@ export function ToolInput({
aria-label='Toggle tool usage control'
>
<span
className={`font-medium text-[#AEAEAE] text-xs ${
className={`font-medium text-[var(--text-tertiary)] text-xs ${
tool.usageControl === 'auto' ? 'block' : 'hidden'
}`}
>
Auto
</span>
<span
className={`font-medium text-[#AEAEAE] text-xs ${
className={`font-medium text-[var(--text-tertiary)] text-xs ${
tool.usageControl === 'force' ? 'block' : 'hidden'
}`}
>
Force
</span>
<span
className={`font-medium text-[#AEAEAE] text-xs ${
className={`font-medium text-[var(--text-tertiary)] text-xs ${
tool.usageControl === 'none' ? 'block' : 'hidden'
}`}
>
@@ -1667,7 +1669,7 @@ export function ToolInput({
e.stopPropagation()
handleRemoveTool(toolIndex)
}}
className='text-[#AEAEAE] transition-colors hover:text-[#EEEEEE]'
className='text-[var(--text-tertiary)] transition-colors hover:text-[#EEEEEE]'
aria-label='Remove tool'
>
<XIcon className='h-[14px] w-[14px]' />
@@ -1684,16 +1686,18 @@ export function ToolInput({
return hasOperations && operationOptions.length > 0 ? (
<div className='relative min-w-0 space-y-[6px]'>
<div className='font-medium text-[#AEAEAE] text-[13px]'>Operation</div>
<div className='font-medium text-[13px] text-[var(--text-tertiary)]'>
Operation
</div>
<div className='w-full min-w-0'>
<Select
value={tool.operation || operationOptions[0].id}
onValueChange={(value) => handleOperationChange(toolIndex, value)}
>
<SelectTrigger className='w-full min-w-0 rounded-[4px] border border-[#303030] bg-[#1F1F1F] px-[10px] py-[8px] text-left font-medium text-sm'>
<SelectTrigger className='w-full min-w-0 rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F] px-[10px] py-[8px] text-left font-medium text-sm'>
<SelectValue placeholder='Select operation' className='truncate' />
</SelectTrigger>
<SelectContent className='border-[#303030] bg-[#1F1F1F]'>
<SelectContent className='border-[var(--border-strong)] bg-[#1F1F1F]'>
{operationOptions
.filter((option) => option.id !== '')
.map((option) => (
@@ -1711,7 +1715,9 @@ export function ToolInput({
{/* OAuth credential selector if required */}
{requiresOAuth && oauthConfig && (
<div className='relative min-w-0 space-y-[6px]'>
<div className='font-medium text-[#AEAEAE] text-[13px]'>Account</div>
<div className='font-medium text-[13px] text-[var(--text-tertiary)]'>
Account
</div>
<div className='w-full min-w-0'>
<ToolCredentialSelector
value={tool.params.credential || ''}
@@ -1768,7 +1774,7 @@ export function ToolInput({
key={`group-${groupTitle}`}
className='relative min-w-0 space-y-[6px]'
>
<div className='flex items-center font-medium text-[#AEAEAE] text-[13px]'>
<div className='flex items-center font-medium text-[13px] text-[var(--text-tertiary)]'>
{groupTitle}
</div>
<div className='relative w-full min-w-0'>
@@ -1802,13 +1808,15 @@ export function ToolInput({
standaloneParams.forEach((param) => {
renderedElements.push(
<div key={param.id} className='relative min-w-0 space-y-[6px]'>
<div className='flex items-center font-medium text-[#AEAEAE] text-[13px]'>
<div className='flex items-center font-medium text-[13px] text-[var(--text-tertiary)]'>
{param.uiComponent?.title || formatParameterLabel(param.id)}
{param.required && param.visibility === 'user-only' && (
<span className='ml-1 text-red-500'>*</span>
)}
{(!param.required || param.visibility !== 'user-only') && (
<span className='ml-1 text-[#787878] text-xs'>(Optional)</span>
<span className='ml-1 text-[var(--text-muted)] text-xs'>
(Optional)
</span>
)}
</div>
<div className='relative w-full min-w-0'>
@@ -1853,8 +1861,8 @@ export function ToolInput({
{/* Add Tool Button */}
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<div className='flex w-full cursor-pointer items-center justify-center rounded-[4px] border border-[#303030] bg-[#1F1F1F] px-[10px] py-[6px] font-medium text-sm transition-colors hover:bg-[#252525]'>
<div className='flex items-center text-[#787878] text-[13px]'>
<div className='flex w-full cursor-pointer items-center justify-center rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F] px-[10px] py-[6px] font-medium text-sm transition-colors hover:bg-[var(--surface-4)]'>
<div className='flex items-center text-[13px] text-[var(--text-muted)]'>
<PlusIcon className='mr-2 h-4 w-4' />
Add Tool
</div>
@@ -71,7 +71,7 @@ export function SubflowEditor({
<div className='flex-1 overflow-y-auto overflow-x-hidden px-[8px] pt-[5px] pb-[8px]'>
{/* Type Selection */}
<div>
<Label className='mb-[6.5px] block pl-[2px] font-medium text-[#E6E6E6] text-[13px] dark:text-[#E6E6E6]'>
<Label className='mb-[6.5px] block pl-[2px] font-medium text-[13px] text-[var(--text-primary)] dark:text-[var(--text-primary)]'>
{currentBlock.type === 'loop' ? 'Loop Type' : 'Parallel Type'}
</Label>
<Combobox
@@ -96,7 +96,7 @@ export function SubflowEditor({
{/* Configuration */}
<div>
<Label className='mb-[6.5px] block pl-[2px] font-medium text-[#E6E6E6] text-[13px] dark:text-[#E6E6E6]'>
<Label className='mb-[6.5px] block pl-[2px] font-medium text-[13px] text-[var(--text-primary)] dark:text-[var(--text-primary)]'>
{isCountMode
? `${currentBlock.type === 'loop' ? 'Loop' : 'Parallel'} Iterations`
: isConditionMode
@@ -165,7 +165,7 @@ export function SubflowEditor({
{hasIncomingConnections && (
<div
className={
'connections-section flex flex-shrink-0 flex-col overflow-hidden border-[#2C2C2C] border-t dark:border-[#2C2C2C]' +
'connections-section flex flex-shrink-0 flex-col overflow-hidden border-[var(--border)] border-t dark:border-[var(--border)]' +
(!isResizing ? ' transition-[height] duration-100 ease-out' : '')
}
style={{ height: `${connectionsHeight}px` }}
@@ -198,7 +198,7 @@ export function SubflowEditor({
(!isConnectionsAtMinHeight ? ' rotate-180' : '')
}
/>
<div className='font-medium text-[#E6E6E6] text-[13px] dark:text-[#E6E6E6]'>
<div className='font-medium text-[13px] text-[var(--text-primary)] dark:text-[var(--text-primary)]'>
Connections
</div>
</div>
@@ -1,16 +1,7 @@
'use client'
import { useCallback, useEffect, useRef, useState } from 'react'
import {
BookOpen,
Check,
ChevronUp,
Crosshair,
Pencil,
RepeatIcon,
Settings,
SplitIcon,
} from 'lucide-react'
import { BookOpen, Check, ChevronUp, Pencil, RepeatIcon, Settings, SplitIcon } from 'lucide-react'
import { Button, Tooltip } from '@/components/emcn'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
import { getSubBlockStableKey } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/utils'
@@ -197,7 +188,7 @@ export function Editor() {
>
<IconComponent
icon={isSubflow ? subflowIcon : blockConfig?.icon}
className='h-[12px] w-[12px] text-[#FFFFFF]'
className='h-[12px] w-[12px] text-[var(--white)]'
/>
</div>
)}
@@ -215,11 +206,11 @@ export function Editor() {
handleCancelRename()
}
}}
className='min-w-0 flex-1 truncate bg-transparent pr-[8px] font-medium text-[#FFFFFF] text-[14px] outline-none dark:text-[#FFFFFF]'
className='min-w-0 flex-1 truncate bg-transparent pr-[8px] font-medium text-[14px] text-[var(--white)] outline-none dark:text-[var(--white)]'
/>
) : (
<h2
className='min-w-0 flex-1 truncate pr-[8px] font-medium text-[#FFFFFF] text-[14px] dark:text-[#FFFFFF]'
className='min-w-0 flex-1 truncate pr-[8px] font-medium text-[14px] text-[var(--white)] dark:text-[var(--white)]'
title={title}
>
{title}
@@ -251,7 +242,7 @@ export function Editor() {
</Tooltip.Root>
)}
{/* Focus on block button */}
{currentBlock && (
{/* {currentBlock && (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<Button
@@ -267,7 +258,7 @@ export function Editor() {
<p>Focus on block</p>
</Tooltip.Content>
</Tooltip.Root>
)}
)} */}
{/* Mode toggles - Only show for regular blocks, not subflows */}
{currentBlock && !isSubflow && hasAdvancedMode && (
<Tooltip.Root>
@@ -380,7 +371,7 @@ export function Editor() {
{hasIncomingConnections && (
<div
className={
'connections-section flex flex-shrink-0 flex-col overflow-hidden border-[#2C2C2C] border-t dark:border-[#2C2C2C]' +
'connections-section flex flex-shrink-0 flex-col overflow-hidden border-[var(--border)] border-t dark:border-[var(--border)]' +
(!isResizing ? ' transition-[height] duration-100 ease-out' : '')
}
style={{ height: `${connectionsHeight}px` }}
@@ -415,7 +406,7 @@ export function Editor() {
(!isConnectionsAtMinHeight ? ' rotate-180' : '')
}
/>
<div className='font-medium text-[#E6E6E6] text-[13px] dark:text-[#E6E6E6]'>
<div className='font-medium text-[13px] text-[var(--text-primary)] dark:text-[var(--text-primary)]'>
Connections
</div>
</div>
@@ -6,9 +6,9 @@ import { usePanelEditorStore } from '@/stores/panel-new/editor/store'
*/
const MIN_CONNECTIONS_HEIGHT = 30
/**
* Maximum height for the connections section (same as default fixed height)
* Maximum height for the connections section
*/
const MAX_CONNECTIONS_HEIGHT = 200
const MAX_CONNECTIONS_HEIGHT = 300
/**
* Props for the useConnectionsResize hook
@@ -299,7 +299,9 @@ export function Toolbar({ isActive = true }: ToolbarProps) {
className='flex flex-shrink-0 cursor-pointer items-center justify-between rounded-[4px] bg-[#2A2A2A] px-[12px] py-[8px] dark:bg-[#2A2A2A]'
onClick={handleSearchClick}
>
<h2 className='font-medium text-[#FFFFFF] text-[14px] dark:text-[#FFFFFF]'>Toolbar</h2>
<h2 className='font-medium text-[14px] text-[var(--white)] dark:text-[var(--white)]'>
Toolbar
</h2>
<div className='flex shrink-0 items-center gap-[8px]'>
{!isSearchActive ? (
<Button
@@ -317,7 +319,7 @@ export function Toolbar({ isActive = true }: ToolbarProps) {
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onBlur={handleSearchBlur}
className='w-full border-none bg-transparent pr-[2px] text-right font-medium text-[#E6E6E6] text-[13px] placeholder:text-[#737373] focus:outline-none dark:text-[#E6E6E6]'
className='w-full border-none bg-transparent pr-[2px] text-right font-medium text-[13px] text-[var(--text-primary)] placeholder:text-[#737373] focus:outline-none dark:text-[var(--text-primary)]'
/>
)}
</div>
@@ -335,7 +337,7 @@ export function Toolbar({ isActive = true }: ToolbarProps) {
>
<div
ref={triggersHeaderRef}
className='px-[10px] pt-[5px] pb-[5px] font-medium text-[#E6E6E6] text-[13px] dark:text-[#E6E6E6]'
className='px-[10px] pt-[5px] pb-[5px] font-medium text-[13px] text-[var(--text-primary)] dark:text-[var(--text-primary)]'
>
Triggers
</div>
@@ -359,7 +361,7 @@ export function Toolbar({ isActive = true }: ToolbarProps) {
onClick={() => handleItemClick(trigger.type, isTriggerCapable)}
className={clsx(
'group flex h-[25px] items-center gap-[8px] rounded-[8px] px-[5px] text-[14px]',
'cursor-pointer hover:bg-[#2C2C2C] active:cursor-grabbing dark:hover:bg-[#2C2C2C]'
'cursor-pointer hover:bg-[var(--border)] active:cursor-grabbing dark:hover:bg-[var(--border)]'
)}
>
<div
@@ -379,7 +381,7 @@ export function Toolbar({ isActive = true }: ToolbarProps) {
<span
className={clsx(
'truncate font-medium',
'text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]'
'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:group-hover:text-[var(--text-primary)]'
)}
>
{trigger.name}
@@ -392,7 +394,7 @@ export function Toolbar({ isActive = true }: ToolbarProps) {
</div>
{/* Resize Handle */}
<div className='relative flex-shrink-0 border-[#2C2C2C] border-t dark:border-[#2C2C2C]'>
<div className='relative flex-shrink-0 border-[var(--border)] border-t dark:border-[var(--border)]'>
<div
className='absolute top-[-4px] right-0 left-0 z-30 h-[8px] cursor-ns-resize'
onMouseDown={handleMouseDown}
@@ -404,7 +406,7 @@ export function Toolbar({ isActive = true }: ToolbarProps) {
<div
ref={blocksHeaderRef}
onClick={handleBlocksHeaderClick}
className='cursor-pointer px-[10px] pt-[5px] pb-[5px] font-medium text-[#E6E6E6] text-[13px] dark:text-[#E6E6E6]'
className='cursor-pointer px-[10px] pt-[5px] pb-[5px] font-medium text-[13px] text-[var(--text-primary)] dark:text-[var(--text-primary)]'
>
Blocks
</div>
@@ -435,7 +437,7 @@ export function Toolbar({ isActive = true }: ToolbarProps) {
onClick={() => handleItemClick(block.type, false)}
className={clsx(
'group flex h-[25px] items-center gap-[8px] rounded-[8px] px-[5.5px] text-[14px]',
'cursor-pointer hover:bg-[#2C2C2C] active:cursor-grabbing dark:hover:bg-[#2C2C2C]'
'cursor-pointer hover:bg-[var(--border)] active:cursor-grabbing dark:hover:bg-[var(--border)]'
)}
>
<div
@@ -455,7 +457,7 @@ export function Toolbar({ isActive = true }: ToolbarProps) {
<span
className={clsx(
'truncate font-medium',
'text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]'
'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:group-hover:text-[var(--text-primary)]'
)}
>
{block.name}
@@ -258,10 +258,10 @@ export function Panel() {
<>
<aside
ref={panelRef}
className='panel-container fixed inset-y-0 right-0 z-10 overflow-hidden dark:bg-[#1E1E1E]'
className='panel-container fixed inset-y-0 right-0 z-10 overflow-hidden dark:bg-[var(--surface-1)]'
aria-label='Workflow panel'
>
<div className='flex h-full flex-col border-l pt-[14px] dark:border-[#2C2C2C]'>
<div className='flex h-full flex-col border-l pt-[14px] dark:border-[var(--border)]'>
{/* Header */}
<div className='flex flex-shrink-0 items-center justify-between px-[8px]'>
{/* More and Chat */}
@@ -352,7 +352,7 @@ export function Panel() {
<div className='flex flex-shrink-0 items-center justify-between px-[8px] pt-[14px]'>
<div className='flex gap-[4px]'>
<Button
className='h-[28px] px-[8px] py-[5px] text-[12.5px] hover:bg-[#363636] hover:text-[#E6E6E6] dark:hover:bg-[#363636] dark:hover:text-[#E6E6E6]'
className='h-[28px] px-[8px] py-[5px] text-[12.5px] hover:bg-[var(--surface-9)] hover:text-[var(--text-primary)] dark:hover:bg-[var(--surface-9)] dark:hover:text-[var(--text-primary)]'
variant={_hasHydrated && activeTab === 'copilot' ? 'active' : 'ghost'}
onClick={() => handleTabClick('copilot')}
data-tab-button='copilot'
@@ -360,7 +360,7 @@ export function Panel() {
Copilot
</Button>
<Button
className='h-[28px] px-[8px] py-[5px] text-[12.5px] hover:bg-[#363636] hover:text-[#E6E6E6] dark:hover:bg-[#363636] dark:hover:text-[#E6E6E6]'
className='h-[28px] px-[8px] py-[5px] text-[12.5px] hover:bg-[var(--surface-9)] hover:text-[var(--text-primary)] dark:hover:bg-[var(--surface-9)] dark:hover:text-[var(--text-primary)]'
variant={_hasHydrated && activeTab === 'toolbar' ? 'active' : 'ghost'}
onClick={() => handleTabClick('toolbar')}
data-tab-button='toolbar'
@@ -368,7 +368,7 @@ export function Panel() {
Toolbar
</Button>
<Button
className='h-[28px] px-[8px] py-[5px] text-[12.5px] hover:bg-[#363636] hover:text-[#E6E6E6] dark:hover:bg-[#363636] dark:hover:text-[#E6E6E6]'
className='h-[28px] px-[8px] py-[5px] text-[12.5px] hover:bg-[var(--surface-9)] hover:text-[var(--text-primary)] dark:hover:bg-[var(--surface-9)] dark:hover:text-[var(--text-primary)]'
variant={_hasHydrated && activeTab === 'editor' ? 'active' : 'ghost'}
onClick={() => handleTabClick('editor')}
data-tab-button='editor'
@@ -440,7 +440,7 @@ export function Panel() {
<ModalDescription>
Deleting this workflow will permanently remove all associated blocks, executions, and
configuration.{' '}
<span className='text-[#EF4444] dark:text-[#EF4444]'>
<span className='text-[var(--text-error)] dark:text-[var(--text-error)]'>
This action cannot be undone.
</span>
</ModalDescription>
@@ -455,7 +455,7 @@ export function Panel() {
Cancel
</Button>
<Button
className='h-[32px] bg-[#EF4444] px-[12px] text-[#FFFFFF] hover:bg-[#EF4444] hover:text-[#FFFFFF] dark:bg-[#EF4444] dark:text-[#FFFFFF] hover:dark:bg-[#EF4444] dark:hover:text-[#FFFFFF]'
className='h-[32px] bg-[var(--text-error)] px-[12px] text-[var(--white)] hover:bg-[var(--text-error)] hover:text-[var(--white)] dark:bg-[var(--text-error)] dark:text-[var(--white)] hover:dark:bg-[var(--text-error)] dark:hover:text-[var(--white)]'
onClick={handleDeleteWorkflow}
disabled={isDeleting}
>
@@ -439,7 +439,7 @@ export function ConsoleEntry({ entry, consoleWidth }: ConsoleEntryProps) {
onClick={() => setShowInput(false)}
className={`flex h-5 items-center rounded-lg px-2 transition-colors ${
!showInput
? 'border-[#e5e5e5] bg-[#f5f5f5] text-[#1a1a1a] dark:border-[#424242] dark:bg-[#1f1f1f] dark:text-[#ffffff]'
? 'border-[#e5e5e5] bg-[#f5f5f5] text-[#1a1a1a] dark:border-[var(--border-muted)] dark:bg-[#1f1f1f] dark:text-[var(--white)]'
: 'bg-secondary text-muted-foreground hover:bg-secondary hover:text-card-foreground'
}`}
>
@@ -449,7 +449,7 @@ export function ConsoleEntry({ entry, consoleWidth }: ConsoleEntryProps) {
onClick={() => setShowInput(true)}
className={`flex h-5 items-center rounded-lg px-2 transition-colors ${
showInput
? 'border-[#e5e5e5] bg-[#f5f5f5] text-[#1a1a1a] dark:border-[#424242] dark:bg-[#1f1f1f] dark:text-[#ffffff]'
? 'border-[#e5e5e5] bg-[#f5f5f5] text-[#1a1a1a] dark:border-[var(--border-muted)] dark:bg-[#1f1f1f] dark:text-[var(--white)]'
: 'bg-secondary text-muted-foreground hover:bg-secondary hover:text-card-foreground'
}`}
>
@@ -255,7 +255,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-[var(--surface-elevated)] dark:hover:text-muted-foreground'
className='h-9 rounded-lg border border-[#E5E5E5] bg-[var(--white)] 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' />
@@ -294,7 +294,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-[var(--surface-elevated)]'
className='min-w-32 rounded-lg border-[#E5E5E5] bg-[var(--white)] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
{VARIABLE_TYPES.map((type) => (
<DropdownMenuItem
@@ -324,7 +324,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-[var(--surface-elevated)]'
className='min-w-32 rounded-lg border-[#E5E5E5] bg-[var(--white)] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
<DropdownMenuItem
onClick={() => toggleCollapsed(variable.id)}
@@ -429,7 +429,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-[var(--surface-elevated)] dark:hover:text-muted-foreground'
className='mt-2 h-9 w-full rounded-lg border border-[#E5E5E5] bg-[var(--white)] 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' />
@@ -107,7 +107,7 @@ export const SubflowNodeComponent = memo(({ data, id }: NodeProps<SubflowNodeDat
*/
const getHandleClasses = (position: 'left' | 'right') => {
const baseClasses = '!z-[10] !cursor-crosshair !border-none !transition-[colors] !duration-150'
const colorClasses = '!bg-[#434343]'
const colorClasses = '!bg-[var(--surface-12)]'
const positionClasses = {
left: '!left-[-7px] !h-5 !w-[7px] !rounded-l-[2px] !rounded-r-none hover:!left-[-10px] hover:!w-[10px] hover:!rounded-l-full',
@@ -130,9 +130,9 @@ export const SubflowNodeComponent = memo(({ data, id }: NodeProps<SubflowNodeDat
const hasRing = isFocused || diffStatus === 'new' || diffStatus === 'edited'
const ringStyles = cn(
hasRing && 'ring-[1.75px]',
isFocused && 'ring-[#33B4FF]',
isFocused && 'ring-[var(--brand-secondary)]',
diffStatus === 'new' && 'ring-[#22C55F]',
diffStatus === 'edited' && 'ring-[#FF6600]'
diffStatus === 'edited' && 'ring-[var(--warning)]'
)
return (
@@ -143,7 +143,7 @@ export const SubflowNodeComponent = memo(({ data, id }: NodeProps<SubflowNodeDat
ref={blockRef}
onClick={() => setCurrentBlockId(id)}
className={cn(
'relative cursor-pointer select-none rounded-[8px] border border-[#393939]',
'relative cursor-pointer select-none rounded-[8px] border border-[var(--divider)]',
'transition-block-bg transition-ring',
'z-[20]'
)}
@@ -161,7 +161,7 @@ export const SubflowNodeComponent = memo(({ data, id }: NodeProps<SubflowNodeDat
{/* Header Section */}
<div
className={cn(
'workflow-drag-handle flex cursor-grab items-center justify-between rounded-t-[8px] border-[#393939] border-b bg-[#232323] py-[8px] pr-[12px] pl-[8px] dark:bg-[#232323] [&:active]:cursor-grabbing'
'workflow-drag-handle flex cursor-grab items-center justify-between rounded-t-[8px] border-[var(--divider)] border-b bg-[var(--surface-2)] py-[8px] pr-[12px] pl-[8px] dark:bg-[var(--surface-2)] [&:active]:cursor-grabbing'
)}
onMouseDown={(e) => {
e.stopPropagation()
@@ -210,7 +210,7 @@ export const SubflowNodeComponent = memo(({ data, id }: NodeProps<SubflowNodeDat
>
{/* Subflow Start */}
<div
className='absolute top-[16px] left-[16px] flex items-center justify-center rounded-[8px] bg-[#232323] px-[12px] py-[6px]'
className='absolute top-[16px] left-[16px] flex items-center justify-center rounded-[8px] bg-[var(--surface-2)] px-[12px] py-[6px]'
style={{ pointerEvents: isPreview ? 'none' : 'auto' }}
data-parent-id={id}
data-node-role={`${data.kind}-start`}
@@ -87,7 +87,7 @@ function ValueRow({ name, value, level, path, expandedPaths, onToggle, wrapText
onClick={handleClick}
className={clsx(
'flex items-center gap-2 rounded-md px-2 py-1',
isExpandable && 'cursor-pointer hover:bg-[#2C2C2C]'
isExpandable && 'cursor-pointer hover:bg-[var(--border)]'
)}
style={{
paddingLeft: `${indent + 8}px`,
@@ -105,11 +105,14 @@ function ValueRow({ name, value, level, path, expandedPaths, onToggle, wrapText
<div className='h-3 w-3 flex-shrink-0' />
)}
<span className='font-medium text-[#AEAEAE] text-[13px]'>{name}:</span>
<span className='font-medium text-[13px] text-[var(--text-tertiary)]'>{name}:</span>
{!isExpandable ? (
<span
className={clsx('flex-1 text-[#E6E6E6] text-[13px]', !wrapText && 'truncate')}
className={clsx(
'flex-1 text-[13px] text-[var(--text-primary)]',
!wrapText && 'truncate'
)}
style={wrapText ? { wordBreak: 'break-word' } : undefined}
>
{formatValue(value, type)}
@@ -195,7 +198,9 @@ export function PrettierOutput({ output, wrapText }: PrettierOutputProps) {
return (
<div className='p-2'>
<div className='flex items-center gap-2 py-1'>
<span className='text-[#E6E6E6] text-[13px]'>{formatValue(output, type)}</span>
<span className='text-[13px] text-[var(--text-primary)]'>
{formatValue(output, type)}
</span>
<Badge className='rounded-[4px] px-2 py-0.5 font-mono text-[10px]'>{type}</Badge>
</div>
</div>
@@ -77,7 +77,8 @@ const RUN_ID_COLORS = [
/**
* Shared styling constants
*/
const HEADER_TEXT_CLASS = 'font-medium text-[#AEAEAE] text-[12px] dark:text-[#AEAEAE]'
const HEADER_TEXT_CLASS =
'font-medium text-[var(--text-tertiary)] text-[12px] dark:text-[var(--text-tertiary)]'
const ROW_TEXT_CLASS = 'font-medium text-[#D2D2D2] text-[12px] dark:text-[#D2D2D2]'
const COLUMN_BASE_CLASS = 'flex-shrink-0'
@@ -674,13 +675,13 @@ export function Terminal() {
<aside
ref={terminalRef}
className={clsx(
'terminal-container fixed right-[var(--panel-width)] bottom-0 left-[var(--sidebar-width)] z-10 overflow-hidden dark:bg-[#1E1E1E]',
'terminal-container fixed right-[var(--panel-width)] bottom-0 left-[var(--sidebar-width)] z-10 overflow-hidden dark:bg-[var(--surface-1)]',
isToggling && 'transition-[height] duration-100 ease-out'
)}
onTransitionEnd={handleTransitionEnd}
aria-label='Terminal'
>
<div className='relative flex h-full border-t dark:border-[#2C2C2C]'>
<div className='relative flex h-full border-t dark:border-[var(--border)]'>
{/* Left Section - Logs Table */}
<div
className={clsx('flex flex-col', !selectedEntry && 'flex-1')}
@@ -688,7 +689,7 @@ export function Terminal() {
>
{/* Header */}
<div
className='group flex h-[30px] flex-shrink-0 cursor-pointer items-center bg-[#1E1E1E] pr-[16px] pl-[24px]'
className='group flex h-[30px] flex-shrink-0 cursor-pointer items-center bg-[var(--surface-1)] pr-[16px] pl-[24px]'
onClick={handleHeaderClick}
>
{uniqueBlocks.length > 0 ? (
@@ -706,7 +707,7 @@ export function Terminal() {
<Filter
className={clsx(
'h-[11px] w-[11px]',
filters.blockIds.size > 0 && 'text-[#33B4FF]'
filters.blockIds.size > 0 && 'text-[var(--brand-secondary)]'
)}
/>
</div>
@@ -759,7 +760,7 @@ export function Terminal() {
<Filter
className={clsx(
'h-[11px] w-[11px]',
filters.statuses.size > 0 && 'text-[#33B4FF]'
filters.statuses.size > 0 && 'text-[var(--brand-secondary)]'
)}
/>
</div>
@@ -818,7 +819,7 @@ export function Terminal() {
<Filter
className={clsx(
'h-[11px] w-[11px]',
filters.runIds.size > 0 && 'text-[#33B4FF]'
filters.runIds.size > 0 && 'text-[var(--brand-secondary)]'
)}
/>
</div>
@@ -954,8 +955,8 @@ export function Terminal() {
<div
key={entry.id}
className={clsx(
'flex h-[36px] cursor-pointer items-center px-[24px] hover:bg-[#2C2C2C]',
isSelected && 'bg-[#2C2C2C]'
'flex h-[36px] cursor-pointer items-center px-[24px] hover:bg-[var(--border)]',
isSelected && 'bg-[var(--border)]'
)}
onClick={() => handleRowClick(entry)}
>
@@ -1056,7 +1057,7 @@ export function Terminal() {
{/* Right Section - Block Output (Overlay) */}
{selectedEntry && (
<div
className='absolute top-0 right-0 bottom-0 flex flex-col border-l dark:border-[#2C2C2C] dark:bg-[#1E1E1E]'
className='absolute top-0 right-0 bottom-0 flex flex-col border-l dark:border-[var(--border)] dark:bg-[var(--surface-1)]'
style={{ width: `${outputPanelWidth}px` }}
>
{/* Horizontal Resize Handle */}
@@ -1070,7 +1071,7 @@ export function Terminal() {
{/* Header */}
<div
className='group flex h-[30px] flex-shrink-0 cursor-pointer items-center justify-between bg-[#1E1E1E] px-[16px]'
className='group flex h-[30px] flex-shrink-0 cursor-pointer items-center justify-between bg-[var(--surface-1)] px-[16px]'
onClick={handleHeaderClick}
>
<div className='flex items-center'>
@@ -1078,7 +1079,9 @@ export function Terminal() {
variant='ghost'
className={clsx(
'px-[8px] py-[6px] text-[12px]',
!showInput && hasInputData && '!text-[#E6E6E6] dark:!text-[#E6E6E6]'
!showInput &&
hasInputData &&
'!text-[var(--text-primary)] dark:!text-[var(--text-primary)]'
)}
onClick={(e) => {
e.stopPropagation()
@@ -1099,7 +1102,7 @@ export function Terminal() {
variant='ghost'
className={clsx(
'px-[8px] py-[6px] text-[12px]',
showInput && '!text-[#E6E6E6] dark:!text-[#E6E6E6] '
showInput && '!text-[var(--text-primary)] dark:!text-[var(--text-primary)] '
)}
onClick={(e) => {
e.stopPropagation()
@@ -1268,7 +1271,7 @@ export function Terminal() {
language={
(selectedEntry.input.language as 'javascript' | 'json') || 'javascript'
}
className='m-0 min-h-full rounded-none border-0 bg-[#1E1E1E]'
className='m-0 min-h-full rounded-none border-0 bg-[var(--surface-1)]'
paddingLeft={8}
gutterStyle={{ backgroundColor: 'transparent' }}
wrapText={wrapText}
@@ -1278,7 +1281,7 @@ export function Terminal() {
code={JSON.stringify(outputData, null, 2)}
showGutter
language='json'
className='m-0 min-h-full rounded-none border-0 bg-[#1E1E1E]'
className='m-0 min-h-full rounded-none border-0 bg-[var(--surface-1)]'
paddingLeft={8}
gutterStyle={{ backgroundColor: 'transparent' }}
wrapText={wrapText}
@@ -1289,7 +1292,7 @@ export function Terminal() {
code={JSON.stringify(outputData, null, 2)}
showGutter
language='json'
className='m-0 min-h-full rounded-none border-0 bg-[#1E1E1E]'
className='m-0 min-h-full rounded-none border-0 bg-[var(--surface-1)]'
paddingLeft={8}
gutterStyle={{ backgroundColor: 'transparent' }}
wrapText={wrapText}
@@ -274,7 +274,7 @@ export function Variables() {
aria-controls={`variable-content-${variable.id}`}
>
<div className='flex min-w-0 flex-1 items-center gap-[8px]'>
<span className='block truncate font-medium text-[#AEAEAE] text-[14px]'>
<span className='block truncate font-medium text-[14px] text-[var(--text-tertiary)]'>
{variable.name || `Variable ${index + 1}`}
</span>
{variable.name && (
@@ -289,7 +289,7 @@ export function Variables() {
e.stopPropagation()
handleRemoveVariable(variable.id)
}}
className='h-auto p-0 text-[#EF4444] hover:text-[#EF4444]'
className='h-auto p-0 text-[var(--text-error)] hover:text-[var(--text-error)]'
aria-label={`Delete ${variable.name || `variable ${index + 1}`}`}
>
<Trash style={{ width: `${ICON_SIZE}px`, height: `${ICON_SIZE}px` }} />
@@ -324,7 +324,7 @@ export function Variables() {
return Array.from({ length: lineCount }, (_, i) => (
<div
key={i}
className='font-medium font-mono text-[#787878] text-xs'
className='font-medium font-mono text-[var(--text-muted)] text-xs'
style={{ height: `${LINE_HEIGHT}px`, lineHeight: `${LINE_HEIGHT}px` }}
>
{i + 1}
@@ -373,7 +373,7 @@ export function Variables() {
return (
<div
className='fixed z-30 flex flex-col overflow-hidden rounded-[6px] bg-[#1E1E1E] px-[10px] pt-[2px] pb-[8px]'
className='fixed z-30 flex flex-col overflow-hidden rounded-[6px] bg-[var(--surface-1)] px-[10px] pt-[2px] pb-[8px]'
style={{
left: `${actualPosition.x}px`,
top: `${actualPosition.y}px`,
@@ -387,11 +387,13 @@ export function Variables() {
>
{/* Header (drag handle) */}
<div
className='flex h-[32px] flex-shrink-0 cursor-grab items-center justify-between bg-[#1E1E1E] p-0 active:cursor-grabbing'
className='flex h-[32px] flex-shrink-0 cursor-grab items-center justify-between bg-[var(--surface-1)] p-0 active:cursor-grabbing'
onMouseDown={handleMouseDown}
>
<div className='flex items-center'>
<span className='flex-shrink-0 font-medium text-[#E6E6E6] text-[14px]'>Variables</span>
<span className='flex-shrink-0 font-medium text-[14px] text-[var(--text-primary)]'>
Variables
</span>
</div>
<div className='flex items-center gap-[8px]'>
<Button
@@ -419,7 +421,7 @@ export function Variables() {
{/* Content */}
<div className='flex flex-1 flex-col overflow-hidden pt-[8px]'>
{workflowVariables.length === 0 ? (
<div className='flex flex-1 items-center justify-center text-[#8D8D8D] text-[13px]'>
<div className='flex flex-1 items-center justify-center text-[13px] text-[var(--text-tertiary)]'>
{STRINGS.emptyState}
</div>
) : (
@@ -429,7 +431,7 @@ export function Variables() {
<div
key={variable.id}
className={cn(
'rounded-[4px] border border-[#303030] bg-[#1F1F1F]',
'rounded-[4px] border border-[var(--border-strong)] bg-[var(--surface-1)]',
(collapsedById[variable.id] ?? false) ? 'overflow-hidden' : 'overflow-visible'
)}
>
@@ -438,7 +440,7 @@ export function Variables() {
{!(collapsedById[variable.id] ?? false) && (
<div
id={`variable-content-${variable.id}`}
className='flex flex-col gap-[6px] border-[#303030] border-t px-[10px] pt-[6px] pb-[10px]'
className='flex flex-col gap-[6px] border-[var(--border-strong)] border-t px-[10px] pt-[6px] pb-[10px]'
>
<div className='flex flex-col gap-[4px]'>
<Label className='text-[13px]'>{STRINGS.labels.name}</Label>
@@ -452,7 +454,7 @@ export function Variables() {
placeholder={STRINGS.placeholders.name}
/>
{nameErrors[variable.id] && (
<p className='text-[#EF4444] text-xs' role='alert'>
<p className='text-[var(--text-error)] text-xs' role='alert'>
{nameErrors[variable.id]}
</p>
)}
@@ -77,7 +77,7 @@ export const ActionBar = memo(
'-right-20 absolute top-0',
'flex flex-col items-center',
'opacity-0 transition-opacity duration-200 group-hover:opacity-100',
'gap-[6px] rounded-[10px] bg-[#242424] p-[6px]'
'gap-[6px] rounded-[10px] bg-[var(--surface-3)] p-[6px]'
)}
>
<Tooltip.Root>
@@ -90,7 +90,7 @@ export const ActionBar = memo(
collaborativeToggleBlockEnabled(blockId)
}
}}
className='h-[30px] w-[30px] rounded-[8px] bg-[#363636] p-0 text-[#868686] hover:bg-[#33B4FF] hover:text-[#1B1B1B] dark:text-[#868686] dark:hover:bg-[#33B4FF] dark:hover:text-[#1B1B1B]'
className='h-[30px] w-[30px] rounded-[8px] bg-[var(--surface-9)] p-0 text-[#868686] hover:bg-[var(--brand-secondary)] hover:text-[var(--bg)] dark:text-[#868686] dark:hover:bg-[var(--brand-secondary)] dark:hover:text-[var(--bg)]'
disabled={disabled}
>
{isEnabled ? (
@@ -116,7 +116,7 @@ export const ActionBar = memo(
collaborativeDuplicateBlock(blockId)
}
}}
className='h-[30px] w-[30px] rounded-[8px] bg-[#363636] p-0 text-[#868686] hover:bg-[#33B4FF] hover:text-[#1B1B1B] dark:text-[#868686] dark:hover:bg-[#33B4FF] dark:hover:text-[#1B1B1B]'
className='h-[30px] w-[30px] rounded-[8px] bg-[var(--surface-9)] p-0 text-[#868686] hover:bg-[var(--brand-secondary)] hover:text-[var(--bg)] dark:text-[#868686] dark:hover:bg-[var(--brand-secondary)] dark:hover:text-[var(--bg)]'
disabled={disabled}
>
<Duplicate className='h-[14px] w-[14px]' />
@@ -139,7 +139,7 @@ export const ActionBar = memo(
)
}
}}
className='h-[30px] w-[30px] rounded-[8px] bg-[#363636] p-0 text-[#868686] hover:bg-[#33B4FF] hover:text-[#1B1B1B] dark:text-[#868686] dark:hover:bg-[#33B4FF] dark:hover:text-[#1B1B1B]'
className='h-[30px] w-[30px] rounded-[8px] bg-[var(--surface-9)] p-0 text-[#868686] hover:bg-[var(--brand-secondary)] hover:text-[var(--bg)] dark:text-[#868686] dark:hover:bg-[var(--brand-secondary)] dark:hover:text-[var(--bg)]'
disabled={disabled || !userPermissions.canEdit}
>
<LogOut className='h-[14px] w-[14px]' />
@@ -161,7 +161,7 @@ export const ActionBar = memo(
collaborativeToggleBlockHandles(blockId)
}
}}
className='h-[30px] w-[30px] rounded-[8px] bg-[#363636] p-0 text-[#868686] hover:bg-[#33B4FF] hover:text-[#1B1B1B] dark:text-[#868686] dark:hover:bg-[#33B4FF] dark:hover:text-[#1B1B1B]'
className='h-[30px] w-[30px] rounded-[8px] bg-[var(--surface-9)] p-0 text-[#868686] hover:bg-[var(--brand-secondary)] hover:text-[var(--bg)] dark:text-[#868686] dark:hover:bg-[var(--brand-secondary)] dark:hover:text-[var(--bg)]'
disabled={disabled}
>
{horizontalHandles ? (
@@ -186,7 +186,7 @@ export const ActionBar = memo(
collaborativeRemoveBlock(blockId)
}
}}
className='h-[30px] w-[30px] rounded-[8px] bg-[#363636] p-0 text-[#868686] hover:bg-[#33B4FF] hover:text-[#1B1B1B] dark:text-[#868686] dark:hover:bg-[#33B4FF] dark:hover:text-[#1B1B1B]'
className='h-[30px] w-[30px] rounded-[8px] bg-[var(--surface-9)] p-0 text-[#868686] hover:bg-[var(--brand-secondary)] hover:text-[var(--bg)] dark:text-[#868686] dark:hover:bg-[var(--brand-secondary)] dark:hover:text-[var(--bg)] '
disabled={disabled}
>
<Trash2 className='h-[14px] w-[14px]' />
@@ -53,16 +53,22 @@ export function Connections({ blockId, horizontalHandles }: ConnectionsProps) {
{visibleConnections.map((connection: ConnectedBlock) => {
const Icon = getConnectionIcon(connection)
if (!Icon) return null
return <Icon key={connection.id} className='h-[14px] w-[14px] text-[#AEAEAE]' />
return (
<Icon key={connection.id} className='h-[14px] w-[14px] text-[var(--text-tertiary)]' />
)
})}
{remainingCount > 0 && <span className='text-[#AEAEAE] text-[14px]'>+{remainingCount}</span>}
{remainingCount > 0 && (
<span className='text-[14px] text-[var(--text-tertiary)]'>+{remainingCount}</span>
)}
</>
)
if (!horizontalHandles) {
return (
<div className='-translate-x-full -translate-y-1/2 pointer-events-none absolute top-1/2 left-0 flex flex-col items-end gap-[8px] pr-[8px] opacity-0 transition-opacity group-hover:opacity-100'>
<span className='text-[#AEAEAE] text-[14px] leading-[14px]'>{connectionText}</span>
<span className='text-[14px] text-[var(--text-tertiary)] leading-[14px]'>
{connectionText}
</span>
<div className='flex items-center justify-end gap-[4px]'>{connectionIcons}</div>
</div>
)
@@ -70,8 +76,8 @@ export function Connections({ blockId, horizontalHandles }: ConnectionsProps) {
return (
<div className='pointer-events-none absolute bottom-full left-0 ml-[8px] flex items-center gap-[8px] pb-[8px] opacity-0 transition-opacity group-hover:opacity-100'>
<span className='text-[#AEAEAE] text-[14px]'>{connectionText}</span>
<div className='h-[14px] w-[1px] bg-[#AEAEAE]' />
<span className='text-[14px] text-[var(--text-tertiary)]'>{connectionText}</span>
<div className='h-[14px] w-[1px] bg-[var(--text-tertiary)]' />
<div className='flex items-center gap-[4px]'>{connectionIcons}</div>
</div>
)
@@ -305,12 +305,12 @@ const SubBlockRow = ({
return (
<div className='flex items-center gap-[8px]'>
<span className='min-w-0 truncate text-[#AEAEAE] text-[14px]' title={title}>
<span className='min-w-0 truncate text-[14px] text-[var(--text-tertiary)]' title={title}>
{title}
</span>
{displayValue !== undefined && (
<span
className='flex-1 truncate text-right text-[#FFFFFF] text-[14px]'
className='flex-1 truncate text-right text-[14px] text-[var(--white)]'
title={displayValue}
>
{displayValue}
@@ -590,7 +590,7 @@ export const WorkflowBlock = memo(function WorkflowBlock({
*/
const getHandleClasses = (position: 'left' | 'right' | 'top' | 'bottom', isError = false) => {
const baseClasses = '!z-[10] !cursor-crosshair !border-none !transition-[colors] !duration-150'
const colorClasses = isError ? '!bg-red-400 dark:!bg-red-500' : '!bg-[#434343]'
const colorClasses = isError ? '!bg-red-400 dark:!bg-red-500' : '!bg-[var(--surface-12)]'
const positionClasses = {
left: '!left-[-7px] !h-5 !w-[7px] !rounded-l-[2px] !rounded-r-none hover:!left-[-10px] hover:!w-[10px] hover:!rounded-l-full',
@@ -701,7 +701,7 @@ export const WorkflowBlock = memo(function WorkflowBlock({
ref={contentRef}
onClick={handleClick}
className={cn(
'relative z-[20] w-[250px] cursor-default select-none rounded-[8px] bg-[#232323]'
'relative z-[20] w-[250px] cursor-default select-none rounded-[8px] bg-[var(--surface-2)]'
)}
>
{isPending && (
@@ -734,7 +734,7 @@ export const WorkflowBlock = memo(function WorkflowBlock({
<div
className={cn(
'workflow-drag-handle flex cursor-grab items-center justify-between p-[8px] [&:active]:cursor-grabbing',
hasContentBelowHeader && 'border-[#393939] border-b'
hasContentBelowHeader && 'border-[var(--divider)] border-b'
)}
onMouseDown={(e) => {
e.stopPropagation()
@@ -855,10 +855,13 @@ export const WorkflowBlock = memo(function WorkflowBlock({
{showWebhookIndicator && (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<Badge variant='outline' className='bg-[#22C55E] text-[#22C55E]'>
<Badge
variant='outline'
className='bg-[var(--brand-tertiary)] text-[var(--brand-tertiary)]'
>
<div className='relative flex items-center justify-center'>
<div className='197, 94, 0.2)] absolute h-3 w-3 rounded-full bg-[rgba(34,' />
<div className='relative h-2 w-2 rounded-full bg-[#22C55E]' />
<div className='relative h-2 w-2 rounded-full bg-[var(--brand-tertiary)]' />
</div>
Webhook
</Badge>
@@ -79,10 +79,10 @@ export const WorkflowEdge = ({
const isErrorEdge = (sourceHandle ?? dataSourceHandle) === 'error'
const getEdgeColor = () => {
if (edgeDiffStatus === 'deleted') return '#ef4444' // Red for deleted edges
if (isErrorEdge) return '#EF4444' // Red for error paths (matches error handle)
if (edgeDiffStatus === 'new') return '#22C55E' // Green for new edges
return '#434343' // Matches workflow-block handle color
if (edgeDiffStatus === 'deleted') return 'var(--text-error)'
if (isErrorEdge) return 'var(--text-error)'
if (edgeDiffStatus === 'new') return 'var(--brand-tertiary)'
return 'var(--surface-12)'
}
const edgeStyle = {
@@ -133,7 +133,7 @@ export const WorkflowEdge = ({
}
}}
>
<X className='h-4 w-4 text-[#EF4444] transition-colors group-hover:text-[#EF4444]/80 dark:text-[#EF4444] dark:group-hover:text-[#EF4444]/80' />
<X className='h-4 w-4 text-[var(--text-error)] transition-colors group-hover:text-[var(--text-error)]/80 dark:text-[var(--text-error)] dark:group-hover:text-[var(--text-error)]/80' />
</div>
</EdgeLabelRenderer>
)}
@@ -50,11 +50,11 @@ export function useBlockCore({ blockId, data, isPending = false }: UseBlockCoreO
const ringStyles = cn(
hasRing && 'ring-[1.75px]',
isActive && 'ring-[#8C10FF] animate-pulse-ring',
isPending && 'ring-[#FF6600]',
isFocused && 'ring-[#33B4FF]',
isPending && 'ring-[var(--warning)]',
isFocused && 'ring-[var(--brand-secondary)]',
diffStatus === 'new' && 'ring-[#22C55F]',
diffStatus === 'edited' && 'ring-[#FF6600]',
isDeletedBlock && 'ring-[#EF4444]'
diffStatus === 'edited' && 'ring-[var(--warning)]',
isDeletedBlock && 'ring-[var(--text-error)]'
)
return { hasRing, ringStyles }
@@ -79,28 +79,30 @@ export function FooterNavigation() {
return (
<>
<div className='flex flex-shrink-0 flex-col gap-[2px] border-t px-[7.75px] pt-[8px] pb-[8px] dark:border-[#2C2C2C]'>
<div className='flex flex-shrink-0 flex-col gap-[2px] border-t px-[7.75px] pt-[8px] pb-[8px] dark:border-[var(--border)]'>
{navigationItems.map((item) => {
const Icon = item.icon
const active = item.href ? isActive(item.href) : false
const itemClasses = clsx(
'group flex h-[24px] items-center gap-[8px] rounded-[8px] px-[7px] text-[14px]',
active ? 'bg-[#2C2C2C] dark:bg-[#2C2C2C]' : 'hover:bg-[#2C2C2C] dark:hover:bg-[#2C2C2C]'
active
? 'bg-[var(--border)] dark:bg-[var(--border)]'
: 'hover:bg-[var(--border)] dark:hover:bg-[var(--border)]'
)
const iconClasses = clsx(
'h-[14px] w-[14px] flex-shrink-0',
active
? 'text-[#E6E6E6] dark:text-[#E6E6E6]'
: 'text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]'
? 'text-[var(--text-primary)] dark:text-[var(--text-primary)]'
: 'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:group-hover:text-[var(--text-primary)]'
)
const labelClasses = clsx(
'truncate font-base text-[13px]',
active
? 'text-[#E6E6E6] dark:text-[#E6E6E6]'
: 'text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]'
? 'text-[var(--text-primary)] dark:text-[var(--text-primary)]'
: 'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:group-hover:text-[var(--text-primary)]'
)
const content = (
@@ -478,14 +478,14 @@ export function SearchModal({
</VisuallyHidden.Root>
{/* Search input container */}
<div className='flex items-center gap-[6px] rounded-[10px] border border-[#2C2C2C] bg-[#272727] px-[10px] py-[8px] shadow-sm dark:border-[#2C2C2C] dark:bg-[#272727]'>
<Search className='h-[16px] w-[16px] flex-shrink-0 text-[#7D7D7D] dark:text-[#7D7D7D]' />
<div className='flex items-center gap-[6px] rounded-[10px] border border-[var(--border)] bg-[var(--surface-5)] px-[10px] py-[8px] shadow-sm dark:border-[var(--border)] dark:bg-[var(--surface-5)]'>
<Search className='h-[16px] w-[16px] flex-shrink-0 text-[var(--text-subtle)] dark:text-[var(--text-subtle)]' />
<input
type='text'
placeholder='Search anything...'
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className='w-full border-0 bg-transparent font-base text-[#E6E6E6] text-[16px] placeholder:text-[#B1B1B1] focus:outline-none dark:text-[#E6E6E6] dark:placeholder:text-[#B1B1B1]'
className='w-full border-0 bg-transparent font-base text-[16px] text-[var(--text-primary)] placeholder:text-[var(--text-secondary)] focus:outline-none dark:text-[var(--text-primary)] dark:placeholder:text-[var(--text-secondary)]'
autoFocus
/>
</div>
@@ -499,7 +499,7 @@ export function SearchModal({
return (
<div key={type} className='mb-[10px] last:mb-0'>
{/* Section header */}
<div className='pt-[2px] pb-[4px] font-medium text-[#7D7D7D] text-[11px] uppercase tracking-wide dark:text-[#7D7D7D]'>
<div className='pt-[2px] pb-[4px] font-medium text-[11px] text-[var(--text-subtle)] uppercase tracking-wide dark:text-[var(--text-subtle)]'>
{sectionTitles[type]}
</div>
@@ -520,10 +520,10 @@ export function SearchModal({
data-search-item-index={globalIndex}
onClick={() => handleItemClick(item)}
className={cn(
'group flex h-[28px] w-full items-center gap-[8px] rounded-[6px] bg-[#252525]/60 px-[8px] text-left text-[13px] transition-all focus:outline-none dark:bg-[#252525]/60',
'group flex h-[28px] w-full items-center gap-[8px] rounded-[6px] bg-[var(--surface-4)]/60 px-[8px] text-left text-[13px] transition-all focus:outline-none dark:bg-[var(--surface-4)]/60',
isSelected
? 'bg-[#2C2C2C] shadow-sm dark:bg-[#2C2C2C]'
: 'hover:bg-[#2C2C2C] dark:hover:bg-[#2C2C2C]'
? 'bg-[var(--border)] shadow-sm dark:bg-[var(--border)]'
: 'hover:bg-[var(--border)] dark:hover:bg-[var(--border)]'
)}
>
{/* Icon - different rendering for workflows vs others */}
@@ -549,7 +549,7 @@ export function SearchModal({
'transition-transform duration-100 group-hover:scale-110',
showColoredIcon
? '!h-[10px] !w-[10px] text-white'
: 'h-[14px] w-[14px] text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]'
: 'h-[14px] w-[14px] text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:group-hover:text-[var(--text-primary)]'
)}
/>
</div>
@@ -563,8 +563,8 @@ export function SearchModal({
className={cn(
'truncate font-medium',
isSelected
? 'text-[#E6E6E6] dark:text-[#E6E6E6]'
: 'text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]'
? 'text-[var(--text-primary)] dark:text-[var(--text-primary)]'
: 'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:group-hover:text-[var(--text-primary)]'
)}
>
{item.name}
@@ -573,7 +573,7 @@ export function SearchModal({
{/* Shortcut */}
{item.shortcut && (
<span className='ml-auto flex-shrink-0 font-medium text-[#7D7D7D] text-[11px] dark:text-[#7D7D7D]'>
<span className='ml-auto flex-shrink-0 font-medium text-[11px] text-[var(--text-subtle)] dark:text-[var(--text-subtle)]'>
{item.shortcut}
</span>
)}
@@ -586,8 +586,8 @@ export function SearchModal({
})}
</div>
) : searchQuery ? (
<div className='flex items-center justify-center rounded-[10px] bg-[#272727] px-[16px] py-[24px] shadow-sm dark:bg-[#272727]'>
<p className='text-[#7D7D7D] text-[13px] dark:text-[#7D7D7D]'>
<div className='flex items-center justify-center rounded-[10px] bg-[var(--surface-5)] px-[16px] py-[24px] shadow-sm dark:bg-[var(--surface-5)]'>
<p className='text-[13px] text-[var(--text-subtle)] dark:text-[var(--text-subtle)]'>
No results found for "{searchQuery}"
</p>
</div>
@@ -3,13 +3,14 @@ import { Info } from 'lucide-react'
import { Tooltip } from '@/components/emcn'
import { Button } from '@/components/ui/button'
import { Label } from '@/components/ui/label'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
// COMMENTED OUT: Theme switching disabled - dark mode is forced for workspace
// import {
// Select,
// SelectContent,
// SelectItem,
// SelectTrigger,
// SelectValue,
// } from '@/components/ui/select'
import { Skeleton } from '@/components/ui/skeleton'
import { Switch } from '@/components/ui/switch'
import { useSession } from '@/lib/auth-client'
@@ -95,14 +96,15 @@ export function General() {
}
}
// Sync theme from store to next-themes when theme changes
useEffect(() => {
if (!isLoading && theme) {
// Ensure next-themes is in sync with our store
const { syncThemeToNextThemes } = require('@/lib/theme-sync')
syncThemeToNextThemes(theme)
}
}, [theme, isLoading])
// COMMENTED OUT: Theme switching disabled - dark mode is forced for workspace
// // Sync theme from store to next-themes when theme changes
// useEffect(() => {
// if (!isLoading && theme) {
// // Ensure next-themes is in sync with our store
// const { syncThemeToNextThemes } = require('@/lib/theme-sync')
// syncThemeToNextThemes(theme)
// }
// }, [theme, isLoading])
const handleThemeChange = async (value: 'system' | 'light' | 'dark') => {
await setTheme(value)
@@ -143,15 +145,16 @@ export function General() {
<div className='flex flex-col gap-4'>
{isLoading ? (
<>
{/* COMMENTED OUT: Theme switching disabled - dark mode is forced for workspace */}
{/* Theme setting with skeleton value */}
<div className='flex items-center justify-between'>
{/* <div className='flex items-center justify-between'>
<div className='flex items-center gap-2'>
<Label htmlFor='theme-select' className='font-normal'>
Theme
</Label>
</div>
<Skeleton className='h-9 w-[180px]' />
</div>
</div> */}
{/* Auto-connect setting with skeleton value */}
<div className='flex items-center justify-between'>
@@ -207,7 +210,8 @@ export function General() {
</>
) : (
<>
<div className='flex items-center justify-between'>
{/* COMMENTED OUT: Theme switching disabled - dark mode is forced for workspace */}
{/* <div className='flex items-center justify-between'>
<div className='flex items-center gap-2'>
<Label htmlFor='theme-select' className='font-normal'>
Theme
@@ -221,7 +225,7 @@ export function General() {
<SelectTrigger id='theme-select' className='h-9 w-[180px]'>
<SelectValue placeholder='Select theme' />
</SelectTrigger>
<SelectContent className='min-w-32 rounded-[10px] border-[#E5E5E5] bg-[#FFFFFF] shadow-xs dark:border-[#414141] dark:bg-[#202020]'>
<SelectContent className='min-w-32 rounded-[10px] border-[#E5E5E5] bg-[var(--white)] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'>
<SelectItem
value='system'
className='rounded-[8px] text-card-foreground text-sm hover:bg-muted focus:bg-muted'
@@ -242,7 +246,7 @@ export function General() {
</SelectItem>
</SelectContent>
</Select>
</div>
</div> */}
<div className='flex items-center justify-between'>
<div className='flex items-center gap-2'>
<Label htmlFor='auto-connect' className='font-normal'>
@@ -97,7 +97,7 @@ export function DeleteModal({
<ModalTitle>{title}</ModalTitle>
<ModalDescription>
{description}{' '}
<span className='text-[#EF4444] dark:text-[#EF4444]'>
<span className='text-[var(--text-error)] dark:text-[var(--text-error)]'>
This action cannot be undone.
</span>
</ModalDescription>
@@ -112,7 +112,7 @@ export function DeleteModal({
Cancel
</Button>
<Button
className='h-[32px] bg-[#EF4444] px-[12px] text-[#FFFFFF] hover:bg-[#EF4444] hover:text-[#FFFFFF] dark:bg-[#EF4444] dark:text-[#FFFFFF] hover:dark:bg-[#EF4444] dark:hover:text-[#FFFFFF]'
className='h-[32px] bg-[var(--text-error)] px-[12px] text-[var(--white)] hover:bg-[var(--text-error)] hover:text-[var(--white)] dark:bg-[var(--text-error)] dark:text-[var(--white)] hover:dark:bg-[var(--text-error)] dark:hover:text-[var(--white)]'
onClick={onConfirm}
disabled={isDeleting}
>
@@ -197,19 +197,19 @@ export function FolderItem({ folder, level, hoverHandlers }: FolderItemProps) {
>
<ChevronRight
className={clsx(
'mr-[8px] h-[10px] w-[10px] flex-shrink-0 text-[#787878] transition-all dark:text-[#787878]',
'mr-[8px] h-[10px] w-[10px] flex-shrink-0 text-[var(--text-muted)] transition-all dark:text-[var(--text-muted)]',
isExpanded ? 'rotate-90' : ''
)}
aria-hidden='true'
/>
{isExpanded ? (
<FolderOpen
className='mr-[10px] h-[16px] w-[16px] flex-shrink-0 text-[#787878] dark:text-[#787878]'
className='mr-[10px] h-[16px] w-[16px] flex-shrink-0 text-[var(--text-muted)] dark:text-[var(--text-muted)]'
aria-hidden='true'
/>
) : (
<Folder
className='mr-[10px] h-[16px] w-[16px] flex-shrink-0 text-[#787878] dark:text-[#787878]'
className='mr-[10px] h-[16px] w-[16px] flex-shrink-0 text-[var(--text-muted)] dark:text-[var(--text-muted)]'
aria-hidden='true'
/>
)}
@@ -221,7 +221,7 @@ export function FolderItem({ folder, level, hoverHandlers }: FolderItemProps) {
onKeyDown={handleRenameKeyDown}
onBlur={handleInputBlur}
className={clsx(
'min-w-0 flex-1 border-0 bg-transparent p-0 font-medium text-[#AEAEAE] text-[14px] outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 dark:text-[#AEAEAE]'
'min-w-0 flex-1 border-0 bg-transparent p-0 font-medium text-[14px] text-[var(--text-tertiary)] outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 dark:text-[var(--text-tertiary)]'
)}
maxLength={50}
disabled={isRenaming}
@@ -236,7 +236,7 @@ export function FolderItem({ folder, level, hoverHandlers }: FolderItemProps) {
/>
) : (
<span
className='truncate font-medium text-[#AEAEAE] dark:text-[#AEAEAE]'
className='truncate font-medium text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]'
onDoubleClick={handleDoubleClick}
>
{folder.name}
@@ -234,9 +234,11 @@ export function WorkflowItem({ workflow, active, level, onWorkflowClick }: Workf
data-item-id={workflow.id}
className={clsx(
'group flex h-[25px] items-center gap-[8px] rounded-[8px] px-[5.5px] text-[14px]',
active ? 'bg-[#2C2C2C] dark:bg-[#2C2C2C]' : 'hover:bg-[#2C2C2C] dark:hover:bg-[#2C2C2C]',
active
? 'bg-[var(--border)] dark:bg-[var(--border)]'
: 'hover:bg-[var(--border)] dark:hover:bg-[var(--border)]',
isSelected && selectedWorkflows.size > 1 && !active
? 'bg-[#2C2C2C] dark:bg-[#2C2C2C]'
? 'bg-[var(--border)] dark:bg-[var(--border)]'
: '',
isDragging ? 'opacity-50' : ''
)}
@@ -261,8 +263,8 @@ export function WorkflowItem({ workflow, active, level, onWorkflowClick }: Workf
className={clsx(
'w-full border-0 bg-transparent p-0 font-medium text-[14px] outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0',
active
? 'text-[#E6E6E6] dark:text-[#E6E6E6]'
: 'text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]'
? 'text-[var(--text-primary)] dark:text-[var(--text-primary)]'
: 'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]'
)}
maxLength={100}
disabled={isRenaming}
@@ -280,8 +282,8 @@ export function WorkflowItem({ workflow, active, level, onWorkflowClick }: Workf
className={clsx(
'truncate font-medium',
active
? 'text-[#E6E6E6] dark:text-[#E6E6E6]'
: 'text-[#AEAEAE] group-hover:text-[#E6E6E6] dark:text-[#AEAEAE] dark:group-hover:text-[#E6E6E6]'
? 'text-[var(--text-primary)] dark:text-[var(--text-primary)]'
: 'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)] dark:text-[var(--text-tertiary)] dark:group-hover:text-[var(--text-primary)]'
)}
onDoubleClick={handleDoubleClick}
>
@@ -259,7 +259,7 @@ export function WorkspaceHeader({
{/* Workspace Name */}
<div className='flex min-w-0 flex-1 items-center gap-[8px]'>
<h2
className='max-w-full truncate font-base text-[14px] dark:text-[#FFFFFF]'
className='max-w-full truncate font-base text-[14px] dark:text-[var(--white)]'
title={activeWorkspace?.name || 'Loading...'}
>
{activeWorkspace?.name || 'Loading...'}
@@ -278,7 +278,7 @@ export function WorkspaceHeader({
className='group !p-[3px] -m-[3px]'
onClick={handleRefresh}
>
<RefreshCw className='h-[14px] w-[14px] text-[#EF4444] dark:text-[#EF4444]' />
<RefreshCw className='h-[14px] w-[14px] text-[var(--text-error)] dark:text-[var(--text-error)]' />
</Button>
</Tooltip.Trigger>
<Tooltip.Content>Connection lost - refresh</Tooltip.Content>
@@ -378,7 +378,7 @@ export function WorkspaceHeader({
{workspaces.map((workspace, index) => (
<div key={workspace.id} className={index > 0 ? 'mt-[2px]' : ''}>
{editingWorkspaceId === workspace.id ? (
<div className='flex h-[25px] items-center gap-[8px] rounded-[6px] bg-[#363636] px-[6px] dark:bg-[#363636]'>
<div className='flex h-[25px] items-center gap-[8px] rounded-[6px] bg-[var(--surface-9)] px-[6px] dark:bg-[var(--surface-9)]'>
<input
ref={listRenameInputRef}
value={editingName}
@@ -408,7 +408,7 @@ export function WorkspaceHeader({
setIsListRenaming(false)
}
}}
className='w-full border-0 bg-transparent p-0 font-base text-[#E6E6E6] text-[12px] outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 dark:text-[#E6E6E6]'
className='w-full border-0 bg-transparent p-0 font-base text-[12px] text-[var(--text-primary)] outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 dark:text-[var(--text-primary)]'
maxLength={100}
autoComplete='off'
autoCorrect='off'
@@ -16,7 +16,7 @@ export const KeyboardShortcut = ({ shortcut, className }: KeyboardShortcutProps)
return (
<kbd
className={cn(
'flex h-6 w-8 items-center justify-center rounded-[5px] border border-border bg-background font-mono text-[#CDCDCD] text-xs dark:text-[#454545]',
'flex h-6 w-8 items-center justify-center rounded-[5px] border border-border bg-background font-mono text-[#CDCDCD] text-xs dark:text-[var(--surface-13)]',
className
)}
>
@@ -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-[var(--surface-elevated)]'
className='min-w-32 rounded-lg border-[#E5E5E5] bg-[var(--white)] shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
>
{userPermissions.canEdit && (
<DropdownMenuItem
@@ -440,7 +440,7 @@ export function SidebarNew() {
<>
{isCollapsed ? (
/* Floating collapsed header */
<div className='fixed top-[14px] left-[10px] z-10 max-w-[232px] rounded-[8px] border bg-white px-[12px] py-[8px] dark:border-[#2C2C2C] dark:bg-[#1E1E1E]'>
<div className='fixed top-[14px] left-[10px] z-10 max-w-[232px] rounded-[8px] border border-[var(--border)] bg-[var(--surface-1)] px-[12px] py-[8px]'>
<WorkspaceHeader
activeWorkspace={activeWorkspace}
workspaceId={workspaceId}
@@ -466,11 +466,11 @@ export function SidebarNew() {
<>
<aside
ref={sidebarRef}
className='sidebar-container fixed inset-y-0 left-0 z-10 overflow-hidden dark:bg-[#1E1E1E]'
className='sidebar-container fixed inset-y-0 left-0 z-10 overflow-hidden bg-[var(--surface-1)]'
aria-label='Workspace sidebar'
onClick={handleSidebarClick}
>
<div className='flex h-full flex-col border-r pt-[14px] dark:border-[#2C2C2C]'>
<div className='flex h-full flex-col border-r pt-[14px] dark:border-[var(--border)]'>
{/* Header */}
<div className='flex-shrink-0 px-[14px]'>
<WorkspaceHeader
@@ -496,16 +496,18 @@ export function SidebarNew() {
{/* Search */}
<div
className='mx-[8px] mt-[12px] flex flex-shrink-0 cursor-pointer items-center justify-between rounded-[8px] bg-[#272727] px-[8px] py-[7px] dark:bg-[#272727]'
className='mx-[8px] mt-[12px] flex flex-shrink-0 cursor-pointer items-center justify-between rounded-[8px] bg-[var(--surface-5)] px-[8px] py-[7px]'
onClick={() => setIsSearchModalOpen(true)}
>
<div className='flex items-center gap-[6px]'>
<Search className='h-[14px] w-[14px] text-[#7D7D7D] dark:text-[#7D7D7D]' />
<p className='translate-y-[0.25px] font-medium text-[#B1B1B1] text-small dark:text-[#B1B1B1]'>
<Search className='h-[14px] w-[14px] text-[var(--text-subtle)] dark:text-[var(--text-subtle)]' />
<p className='translate-y-[0.25px] font-medium text-[var(--text-secondary)] text-small dark:text-[var(--text-secondary)]'>
Search
</p>
</div>
<p className='font-medium text-[#7D7D7D] text-small dark:text-[#7D7D7D]'>⌘K</p>
<p className='font-medium text-[var(--text-subtle)] text-small dark:text-[var(--text-subtle)]'>
⌘K
</p>
</div>
{/* Workflows */}
@@ -513,7 +515,7 @@ export function SidebarNew() {
{/* Header - Always visible */}
<div className='flex flex-shrink-0 flex-col space-y-[4px] px-[14px]'>
<div className='flex items-center justify-between'>
<div className='font-medium text-[#AEAEAE] text-small dark:text-[#AEAEAE]'>
<div className='font-medium text-[var(--text-tertiary)] text-small dark:text-[var(--text-tertiary)]'>
Workflows
</div>
<div className='flex items-center justify-center gap-[10px]'>
@@ -8,9 +8,9 @@ const badgeVariants = cva(
variants: {
variant: {
default:
'bg-[#272727] text-[#B1B1B1] dark:bg-[#272727] dark:text-[#B1B1B1] hover:text-[#E6E6E6] dark:hover:text-[#E6E6E6]',
'bg-[var(--surface-5)] text-[var(--text-secondary)] dark:bg-[var(--surface-5)] dark:text-[var(--text-secondary)] hover:text-[var(--text-primary)] dark:hover:text-[var(--text-primary)]',
outline:
'border border-[#575757] bg-transparent text-[#B1B1B1] dark:border-[#575757] dark:bg-transparent dark:text-[#B1B1B1] hover:text-[#E6E6E6] dark:hover:text-[#E6E6E6]',
'border border-[#575757] bg-transparent text-[var(--text-secondary)] dark:border-[#575757] dark:bg-transparent dark:text-[var(--text-secondary)] hover:text-[var(--text-primary)] dark:hover:text-[var(--text-primary)]',
},
},
defaultVariants: {
@@ -3,19 +3,21 @@ import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
const buttonVariants = cva(
'inline-flex items-center text-[#B1B1B1] hover:text-[#E6E6E6] dark:hover:text-[#E6E6E6] dark:text-[#B1B1B1] justify-center font-medium transition-colors disabled:pointer-events-none disabled:opacity-50 outline-none focus:outline-none focus-visible:outline-none rounded-[4px] px-[8px] py-[6px] text-[12px]',
'inline-flex items-center text-[var(--text-secondary)] hover:text-[var(--text-primary)] dark:hover:text-[var(--text-primary)] dark:text-[var(--text-secondary)] justify-center font-medium transition-colors disabled:pointer-events-none disabled:opacity-50 outline-none focus:outline-none focus-visible:outline-none rounded-[4px] px-[8px] py-[6px] text-[12px]',
{
variants: {
variant: {
default: 'bg-[#272727] dark:bg-[#272727] hover:bg-[#363636] dark:hover:bg-[#363636]',
active: 'bg-[#363636] dark:bg-[#363636] dark:text-[#E6E6E6] text-[#E6E6E6]',
'3d': 'dark:text-[#AEAEAE] border-t border-l border-r dark:border-[#303030] shadow-[0_2px_0_0] dark:shadow-[#303030] hover:shadow-[0_4px_0_0] transition-all hover:-translate-y-0.5 hover:dark:text-[#E6E6E6]',
default:
'bg-[var(--surface-5)] dark:bg-[var(--surface-5)] hover:bg-[var(--surface-9)] dark:hover:bg-[var(--surface-9)]',
active:
'bg-[var(--surface-9)] dark:bg-[var(--surface-9)] dark:text-[var(--text-primary)] text-[var(--text-primary)]',
'3d': 'dark:text-[var(--text-tertiary)] border-t border-l border-r dark:border-[var(--border-strong)] shadow-[0_2px_0_0] dark:shadow-[var(--border-strong)] hover:shadow-[0_4px_0_0] transition-all hover:-translate-y-0.5 hover:dark:text-[var(--text-primary)]',
outline:
'border border-[#727272] bg-[#303030] hover:bg-[#3D3D3D] dark:border-[#727272] dark:bg-[#303030] dark:hover:bg-[#3D3D3D]',
'border border-[#727272] bg-[var(--border-strong)] hover:bg-[var(--surface-11)] dark:border-[#727272] dark:bg-[var(--border-strong)] dark:hover:bg-[var(--surface-11)]',
primary:
'bg-[#8E4CFB] dark:bg-[#8E4CFB] dark:text-[#E6E6E6] text-[#E6E6E6] hover:bg-[#8E4CFB] hover:dark:bg-[#8E4CFB] hover:text-[#E6E6E6] hover:dark:text-[#E6E6E6]',
'bg-[var(--brand-400)] dark:bg-[var(--brand-400)] dark:text-[var(--text-primary)] text-[var(--text-primary)] hover:bg-[var(--brand-400)] hover:dark:bg-[var(--brand-400)] hover:text-[var(--text-primary)] hover:dark:text-[var(--text-primary)]',
ghost: '',
'ghost-secondary': 'text-[#787878] dark:text-[#787878]',
'ghost-secondary': 'text-[var(--text-muted)] dark:text-[var(--text-muted)]',
},
},
defaultVariants: {
@@ -77,9 +77,9 @@ function Container({
<div
className={cn(
// Base container styling
'group relative min-h-[100px] rounded-[4px] border border-[#303030]',
'group relative min-h-[100px] rounded-[4px] border border-[var(--border-strong)]',
'bg-[#1F1F1F] font-medium font-mono text-sm transition-colors',
'dark:border-[#303030]',
'dark:border-[var(--border-strong)]',
// Streaming state
isStreaming && 'streaming-effect',
className
@@ -17,7 +17,7 @@ import { Input } from '../input/input'
import { Popover, PopoverAnchor, PopoverContent, PopoverScrollArea } from '../popover/popover'
const comboboxVariants = cva(
'flex w-full rounded-[4px] border border-[#3D3D3D] bg-[#282828] dark:bg-[#363636] px-[8px] py-[6px] font-sans font-medium text-sm text-[#E6E6E6] placeholder:text-[#787878] dark:placeholder:text-[#787878] outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50 hover:border-[#4A4A4A] hover:bg-[#363636] dark:hover:border-[#454545] dark:hover:bg-[#3D3D3D]',
'flex w-full rounded-[4px] border border-[var(--surface-11)] bg-[var(--surface-6)] dark:bg-[var(--surface-9)] px-[8px] py-[6px] font-sans font-medium text-sm text-[var(--text-primary)] placeholder:text-[var(--text-muted)] dark:placeholder:text-[var(--text-muted)] outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50 hover:border-[var(--surface-14)] hover:bg-[var(--surface-9)] dark:hover:border-[var(--surface-13)] dark:hover:bg-[var(--surface-11)]',
{
variants: {
variant: {
@@ -338,7 +338,7 @@ const Combobox = forwardRef<HTMLDivElement, ComboboxProps>(
<Input
ref={inputRef}
className={cn(
'w-full pr-[40px] font-medium transition-colors hover:border-[#4A4A4A] hover:bg-[#363636] dark:hover:border-[#454545] dark:hover:bg-[#3D3D3D]',
'w-full pr-[40px] font-medium transition-colors hover:border-[var(--surface-14)] hover:bg-[var(--surface-9)] dark:hover:border-[var(--surface-13)] dark:hover:bg-[var(--surface-11)]',
(overlayContent || SelectedIcon) && 'text-transparent caret-foreground',
SelectedIcon && !overlayContent && 'pl-[28px]',
className
@@ -361,7 +361,9 @@ const Combobox = forwardRef<HTMLDivElement, ComboboxProps>(
{SelectedIcon && (
<SelectedIcon className='mr-[8px] h-3 w-3 flex-shrink-0 opacity-60' />
)}
<span className='truncate text-[#E6E6E6]'>{selectedOption?.label}</span>
<span className='truncate text-[var(--text-primary)]'>
{selectedOption?.label}
</span>
</>
)}
</div>
@@ -397,7 +399,7 @@ const Combobox = forwardRef<HTMLDivElement, ComboboxProps>(
<span
className={cn(
'flex-1 truncate',
!selectedOption && 'text-[#787878]',
!selectedOption && 'text-[var(--text-muted)]',
overlayContent && 'text-transparent'
)}
>
@@ -441,8 +443,8 @@ const Combobox = forwardRef<HTMLDivElement, ComboboxProps>(
<div ref={dropdownRef} role='listbox'>
{isLoading ? (
<div className='flex items-center justify-center py-[14px]'>
<Loader2 className='h-[16px] w-[16px] animate-spin text-[#787878]' />
<span className='ml-[8px] font-medium font-sans text-[#787878] text-sm'>
<Loader2 className='h-[16px] w-[16px] animate-spin text-[var(--text-muted)]' />
<span className='ml-[8px] font-medium font-sans text-[var(--text-muted)] text-sm'>
Loading options...
</span>
</div>
@@ -451,7 +453,7 @@ const Combobox = forwardRef<HTMLDivElement, ComboboxProps>(
{error}
</div>
) : filteredOptions.length === 0 ? (
<div className='py-[14px] text-center font-medium font-sans text-[#787878] text-sm'>
<div className='py-[14px] text-center font-medium font-sans text-[var(--text-muted)] text-sm'>
{editable && value ? 'No matching options found' : 'No options available'}
</div>
) : (
@@ -476,12 +478,14 @@ const Combobox = forwardRef<HTMLDivElement, ComboboxProps>(
onMouseEnter={() => setHighlightedIndex(index)}
className={cn(
'relative flex cursor-pointer select-none items-center rounded-[4px] px-[8px] py-[6px] font-medium font-sans text-sm',
isHighlighted && 'bg-[#3D3D3D]',
!isHighlighted && 'hover:bg-[#3D3D3D]'
isHighlighted && 'bg-[var(--surface-11)]',
!isHighlighted && 'hover:bg-[var(--surface-11)]'
)}
>
{OptionIcon && <OptionIcon className='mr-[8px] h-3 w-3 opacity-60' />}
<span className='flex-1 truncate text-[#E6E6E6]'>{option.label}</span>
<span className='flex-1 truncate text-[var(--text-primary)]'>
{option.label}
</span>
{isSelected && <Check className='ml-[8px] h-4 w-4 flex-shrink-0' />}
</div>
)
@@ -3,7 +3,7 @@ import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
const inputVariants = cva(
'flex w-full rounded-[4px] border border-[#3D3D3D] bg-[#282828] dark:bg-[#363636] px-[8px] py-[6px] font-medium font-sans text-sm text-foreground transition-colors placeholder:text-[#787878] dark:placeholder:text-[#787878] outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50',
'flex w-full rounded-[4px] border border-[var(--surface-11)] bg-[var(--surface-6)] dark:bg-[var(--surface-9)] px-[8px] py-[6px] font-medium font-sans text-sm text-foreground transition-colors placeholder:text-[var(--text-muted)] dark:placeholder:text-[var(--text-muted)] outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50',
{
variants: {
variant: {
@@ -18,7 +18,7 @@ function Label({ className, ...props }: LabelProps) {
return (
<LabelPrimitive.Root
className={cn(
'inline-flex items-center font-medium text-[#E6E6E6] text-[13px] leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50 dark:text-[#E6E6E6]',
'inline-flex items-center font-medium text-[13px] text-[var(--text-primary)] leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50 dark:text-[var(--text-primary)]',
className
)}
{...props}
@@ -69,10 +69,10 @@ const MODAL_SPACING = {
*/
const MODAL_COLORS = {
OVERLAY_BG: 'bg-black/80',
CONTENT_BG: 'bg-[#242424] dark:bg-[#242424]',
TITLE_TEXT: 'text-[#E6E6E6] dark:text-[#E6E6E6]',
DESCRIPTION_TEXT: 'text-[#AEAEAE] dark:text-[#AEAEAE]',
CLOSE_BUTTON_TEXT: 'text-[#B1B1B1] dark:text-[#B1B1B1]',
CONTENT_BG: 'bg-[var(--surface-3)] dark:bg-[var(--surface-3)]',
TITLE_TEXT: 'text-[var(--text-primary)] dark:text-[var(--text-primary)]',
DESCRIPTION_TEXT: 'text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]',
CLOSE_BUTTON_TEXT: 'text-[var(--text-secondary)] dark:text-[var(--text-secondary)]',
} as const
/**
@@ -59,16 +59,16 @@ import { cn } from '@/lib/utils'
* Ensures consistent height and styling across items, folders, and back button.
*/
const POPOVER_ITEM_BASE_CLASSES =
'flex h-[25px] min-w-0 cursor-pointer items-center gap-[8px] rounded-[6px] px-[6px] font-base text-[#E6E6E6] text-[12px] transition-colors dark:text-[#E6E6E6] [&_svg]:transition-colors disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed'
'flex h-[25px] min-w-0 cursor-pointer items-center gap-[8px] rounded-[6px] px-[6px] font-base text-[var(--text-primary)] text-[12px] transition-colors dark:text-[var(--text-primary)] [&_svg]:transition-colors disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed'
/**
* Variant-specific active state styles for popover items.
*/
const POPOVER_ITEM_ACTIVE_CLASSES = {
primary:
'bg-[#33B4FF] text-[#1B1B1B] dark:bg-[#33B4FF] dark:text-[#1B1B1B] [&_svg]:text-[#1B1B1B] dark:[&_svg]:text-[#1B1B1B]',
'bg-[var(--brand-secondary)] text-[var(--bg)] dark:bg-[var(--brand-secondary)] dark:text-[var(--bg)] [&_svg]:text-[var(--bg)] dark:[&_svg]:text-[var(--bg)]',
default:
'bg-[#363636] text-[#E6E6E6] dark:bg-[#363636] dark:text-[#E6E6E6] [&_svg]:text-[#E6E6E6] dark:[&_svg]:text-[#E6E6E6]',
'bg-[var(--surface-9)] text-[var(--text-primary)] dark:bg-[var(--surface-9)] dark:text-[var(--text-primary)] [&_svg]:text-[var(--text-primary)] dark:[&_svg]:text-[var(--text-primary)]',
}
/**
@@ -76,9 +76,9 @@ const POPOVER_ITEM_ACTIVE_CLASSES = {
*/
const POPOVER_ITEM_HOVER_CLASSES = {
primary:
'hover:bg-[#33B4FF] hover:text-[#1B1B1B] dark:hover:bg-[#33B4FF] dark:hover:text-[#1B1B1B] hover:[&_svg]:text-[#1B1B1B] dark:hover:[&_svg]:text-[#1B1B1B]',
'hover:bg-[var(--brand-secondary)] hover:text-[var(--bg)] dark:hover:bg-[var(--brand-secondary)] dark:hover:text-[var(--bg)] hover:[&_svg]:text-[var(--bg)] dark:hover:[&_svg]:text-[var(--bg)]',
default:
'hover:bg-[#363636] hover:text-[#E6E6E6] dark:hover:bg-[#363636] dark:hover:text-[#E6E6E6] hover:[&_svg]:text-[#E6E6E6] dark:hover:[&_svg]:text-[#E6E6E6]',
'hover:bg-[var(--surface-9)] hover:text-[var(--text-primary)] dark:hover:bg-[var(--surface-9)] dark:hover:text-[var(--text-primary)] hover:[&_svg]:text-[var(--text-primary)] dark:hover:[&_svg]:text-[var(--text-primary)]',
}
type PopoverVariant = 'default' | 'primary'
@@ -260,6 +260,12 @@ const PopoverContent = React.forwardRef<
// Smart default offset: larger offset when rendering above to avoid covering cursor
const effectiveSideOffset = sideOffset ?? (side === 'top' ? 20 : 14)
// Detect explicit width constraints provided by the consumer.
// When present, we enable default text truncation behavior for inner flexible items,
// so callers don't need to manually pass 'truncate' to every label.
const hasUserWidthConstraint =
style?.minWidth !== undefined || style?.maxWidth !== undefined || style?.width !== undefined
return (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
@@ -272,7 +278,9 @@ const PopoverContent = React.forwardRef<
sticky='partial'
{...restProps}
className={cn(
'z-[9999999] flex flex-col overflow-hidden rounded-[8px] bg-[#242424] px-[5.5px] py-[5px] text-foreground outline-none dark:bg-[#242424]',
'z-[9999999] flex flex-col overflow-hidden rounded-[8px] bg-[var(--surface-3)] px-[5.5px] py-[5px] text-foreground outline-none dark:bg-[var(--surface-3)]',
// If width is constrained by the caller, ensure inner flexible text truncates by default.
hasUserWidthConstraint && '[&_.flex-1]:truncate',
className
)}
style={{
@@ -407,7 +415,7 @@ const PopoverSection = React.forwardRef<HTMLDivElement, PopoverSectionProps>(
return (
<div
className={cn(
'px-[6px] py-[4px] font-base text-[#AEAEAE] text-[12px] dark:text-[#AEAEAE]',
'px-[6px] py-[4px] font-base text-[12px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]',
className
)}
ref={ref}
@@ -576,7 +584,7 @@ const PopoverBackButton = React.forwardRef<HTMLDivElement, PopoverBackButtonProp
</div>
)}
{folderTitle && !onFolderSelect && (
<div className='px-[6px] py-[4px] font-base text-[#AEAEAE] text-[12px] dark:text-[#AEAEAE]'>
<div className='px-[6px] py-[4px] font-base text-[12px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]'>
{folderTitle}
</div>
)}
@@ -631,10 +639,10 @@ const PopoverSearch = React.forwardRef<HTMLDivElement, PopoverSearchProps>(
return (
<div ref={ref} className={cn('flex items-center px-[8px] py-[6px]', className)} {...props}>
<Search className='mr-2 h-[12px] w-[12px] shrink-0 text-[#787878]' />
<Search className='mr-2 h-[12px] w-[12px] shrink-0 text-[var(--text-muted)]' />
<input
ref={inputRef}
className='w-full bg-transparent font-base text-[#E6E6E6] text-[12px] placeholder:text-[#787878] focus:outline-none'
className='w-full bg-transparent font-base text-[12px] text-[var(--text-primary)] placeholder:text-[var(--text-muted)] focus:outline-none'
placeholder={placeholder}
value={searchQuery}
onChange={handleChange}
@@ -3,7 +3,7 @@ import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
const textareaVariants = cva(
'flex w-full rounded-[4px] border border-[#3D3D3D] bg-[#282828] dark:bg-[#363636] px-[8px] py-[8px] font-medium font-sans text-sm text-foreground transition-colors placeholder:text-[#787878] dark:placeholder:text-[#787878] outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 resize overflow-auto disabled:cursor-not-allowed disabled:opacity-50',
'flex w-full rounded-[4px] border border-[var(--surface-11)] bg-[var(--surface-6)] dark:bg-[var(--surface-9)] px-[8px] py-[8px] font-medium font-sans text-sm text-[var(--text-primary)] transition-colors placeholder:text-[var(--text-muted)] dark:placeholder:text-[var(--text-muted)] outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 resize overflow-auto disabled:cursor-not-allowed disabled:opacity-50',
{
variants: {
variant: {
+1 -1
View File
@@ -87,7 +87,7 @@ const AlertDialogContent = React.forwardRef<
<AlertDialogPrimitive.Content
ref={ref}
className={cn(
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-[8px] border border-border bg-background px-6 py-5 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in',
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-[8px] border border-[var(--border-muted)] bg-[var(--surface-3)] px-6 py-5 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in dark:bg-[var(--surface-3)]',
className
)}
onPointerDown={(e) => {
+1 -1
View File
@@ -12,7 +12,7 @@ const Checkbox = React.forwardRef<
<CheckboxPrimitive.Root
ref={ref}
className={cn(
'peer h-4 w-4 shrink-0 rounded-sm border border-[#3D3D3D] bg-[#272727] ring-offset-background transition-colors hover:border-[#4A4A4A] hover:bg-[#282828] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-[#4A4A4A] data-[state=checked]:bg-[#3D3D3D] data-[state=checked]:text-[#E6E6E6] dark:border-[#3D3D3D] dark:bg-[#363636] dark:data-[state=checked]:border-[#5A5A5A] dark:data-[state=checked]:bg-[#454545] dark:hover:border-[#454545] dark:hover:bg-[#3D3D3D]',
'peer h-4 w-4 shrink-0 rounded-sm border border-[var(--surface-11)] bg-[var(--surface-5)] ring-offset-background transition-colors hover:border-[var(--surface-14)] hover:bg-[var(--surface-6)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-[var(--surface-14)] data-[state=checked]:bg-[var(--surface-11)] data-[state=checked]:text-[var(--text-primary)] dark:border-[var(--surface-11)] dark:bg-[var(--surface-9)] dark:data-[state=checked]:border-[var(--surface-15)] dark:data-[state=checked]:bg-[var(--surface-13)] dark:hover:border-[var(--surface-13)] dark:hover:bg-[var(--surface-11)]',
className
)}
{...props}
+1 -1
View File
@@ -70,7 +70,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-[8px] border border-border bg-background p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in',
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-[8px] border border-[var(--border-muted)] bg-[var(--surface-3)] p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in dark:bg-[var(--surface-3)]',
className
)}
onInteractOutside={(e) => {
+2 -2
View File
@@ -10,7 +10,7 @@ const Switch = React.forwardRef<
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent bg-[#272727] transition-colors hover:bg-[#282828] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-[#3D3D3D] data-[state=unchecked]:bg-[#272727] dark:bg-[#272727] dark:data-[state=checked]:bg-[#454545] dark:data-[state=unchecked]:bg-[#363636] dark:hover:bg-[#282828]',
'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent bg-[var(--surface-5)] transition-colors hover:bg-[var(--surface-6)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-[var(--surface-11)] data-[state=unchecked]:bg-[var(--surface-5)] dark:bg-[var(--surface-5)] dark:data-[state=checked]:bg-[var(--surface-13)] dark:data-[state=unchecked]:bg-[var(--surface-9)] dark:hover:bg-[var(--surface-6)]',
className
)}
{...props}
@@ -18,7 +18,7 @@ const Switch = React.forwardRef<
>
<SwitchPrimitives.Thumb
className={cn(
'pointer-events-none block h-4 w-4 rounded-full bg-[#E6E6E6] shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0'
'pointer-events-none block h-4 w-4 rounded-full bg-[var(--text-primary)] shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0'
)}
/>
</SwitchPrimitives.Root>
+4 -2
View File
@@ -1,7 +1,7 @@
/**
* Environment utility functions for consistent environment detection across the application
*/
import { env, isTruthy } from './env'
import { env, getEnv, isTruthy } from './env'
/**
* Is the application running in production mode
@@ -21,7 +21,9 @@ export const isTest = env.NODE_ENV === 'test'
/**
* Is this the hosted version of the application
*/
export const isHosted = true
export const isHosted =
getEnv('NEXT_PUBLIC_APP_URL') === 'https://www.sim.ai' ||
getEnv('NEXT_PUBLIC_APP_URL') === 'https://www.staging.sim.ai'
/**
* Is billing enforcement enabled
+23 -20
View File
@@ -5,33 +5,36 @@
/**
* Updates the theme in next-themes by dispatching a storage event
* This works by updating localStorage and notifying next-themes of the change
*
* COMMENTED OUT: Theme switching disabled - dark mode is forced for workspace
*/
export function syncThemeToNextThemes(theme: 'system' | 'light' | 'dark') {
if (typeof window === 'undefined') return
// Update localStorage
localStorage.setItem('sim-theme', theme)
// COMMENTED OUT: Dark mode is forced for workspace pages
// // Update localStorage
// localStorage.setItem('sim-theme', theme)
// Dispatch storage event to notify next-themes
window.dispatchEvent(
new StorageEvent('storage', {
key: 'sim-theme',
newValue: theme,
oldValue: localStorage.getItem('sim-theme'),
storageArea: localStorage,
url: window.location.href,
})
)
// // Dispatch storage event to notify next-themes
// window.dispatchEvent(
// new StorageEvent('storage', {
// key: 'sim-theme',
// newValue: theme,
// oldValue: localStorage.getItem('sim-theme'),
// storageArea: localStorage,
// url: window.location.href,
// })
// )
// Also update the HTML class immediately for instant feedback
const root = document.documentElement
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
const actualTheme = theme === 'system' ? systemTheme : theme
// // Also update the HTML class immediately for instant feedback
// const root = document.documentElement
// const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
// const actualTheme = theme === 'system' ? systemTheme : theme
// Remove existing theme classes
root.classList.remove('light', 'dark')
// Add new theme class
root.classList.add(actualTheme)
// // Remove existing theme classes
// root.classList.remove('light', 'dark')
// // Add new theme class
// root.classList.add(actualTheme)
}
/**
+1 -1
View File
@@ -9,7 +9,7 @@ import { usePanelStore } from '../store'
*/
const DEFAULT_CONNECTIONS_HEIGHT = 115
const MIN_CONNECTIONS_HEIGHT = 30
const MAX_CONNECTIONS_HEIGHT = 200
const MAX_CONNECTIONS_HEIGHT = 300
/**
* State for the Editor panel.
+28 -24
View File
@@ -1,7 +1,8 @@
import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'
import { createLogger } from '@/lib/logs/console/logger'
import { syncThemeToNextThemes } from '@/lib/theme-sync'
// COMMENTED OUT: Theme switching disabled - dark mode is forced for workspace
// import { syncThemeToNextThemes } from '@/lib/theme-sync'
import { withOptimisticUpdate } from '@/lib/utils'
import type { General, GeneralStore, UserSettings } from '@/stores/settings/general/types'
@@ -130,25 +131,27 @@ export const useGeneralStore = create<GeneralStore>()(
)
},
// COMMENTED OUT: Theme switching disabled - dark mode is forced for workspace
setTheme: async (theme) => {
if (get().isThemeLoading) return
await withOptimisticUpdate({
getCurrentState: () => get().theme,
optimisticUpdate: () => {
set({ theme, isThemeLoading: true })
syncThemeToNextThemes(theme)
},
apiCall: async () => {
await get().updateSetting('theme', theme)
},
rollback: (originalTheme) => {
set({ theme: originalTheme })
syncThemeToNextThemes(originalTheme)
},
onComplete: () => set({ isThemeLoading: false }),
errorMessage: 'Failed to sync theme to database',
})
// COMMENTED OUT: Dark mode is forced for workspace pages
// await withOptimisticUpdate({
// getCurrentState: () => get().theme,
// optimisticUpdate: () => {
// set({ theme, isThemeLoading: true })
// syncThemeToNextThemes(theme)
// },
// apiCall: async () => {
// await get().updateSetting('theme', theme)
// },
// rollback: (originalTheme) => {
// set({ theme: originalTheme })
// syncThemeToNextThemes(originalTheme)
// },
// onComplete: () => set({ isThemeLoading: false }),
// errorMessage: 'Failed to sync theme to database',
// })
},
setTelemetryEnabled: async (enabled) => {
@@ -231,13 +234,14 @@ export const useGeneralStore = create<GeneralStore>()(
isLoading: false,
})
// Sync theme to next-themes if it's different
if (data.theme && typeof window !== 'undefined') {
const currentTheme = localStorage.getItem('sim-theme')
if (currentTheme !== data.theme) {
syncThemeToNextThemes(data.theme)
}
}
// COMMENTED OUT: Theme switching disabled - dark mode is forced for workspace
// // Sync theme to next-themes if it's different
// if (data.theme && typeof window !== 'undefined') {
// const currentTheme = localStorage.getItem('sim-theme')
// if (currentTheme !== data.theme) {
// syncThemeToNextThemes(data.theme)
// }
// }
lastLoadTime = now
errorRetryCount = 0