Skip to content
Draft

feat #2104

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cursorrules
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ENSURE that you use the logger.info and logger.warn and logger.error instead of

## Comments

You must use TSDOC for comments. Do not use ==== for comments to separate sections.
You must use TSDOC for comments. Do not use ==== for comments to separate sections. Do not leave any comments that are not TSDOC.

## Globals styles

Expand Down
38 changes: 27 additions & 11 deletions apps/sim/.cursorrules
Original file line number Diff line number Diff line change
Expand Up @@ -428,20 +428,22 @@ setSidebarWidth: (width) => {
### Tailwind Classes

1. **No Inline Styles**: Use Tailwind utility classes exclusively
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]`)
6. **Transitions**: Add transitions for interactive states (`transition-colors`)
7. **Prefer px units**: Use arbitrary px values over scale utilities (e.g., `px-[4px]` instead of `px-1`)
2. **Dark Mode**: Include dark mode variants only when the value differs from light mode
3. **No Duplicate Dark Classes**: Never add a `dark:` class when the value is identical to the light mode class (e.g., `text-[var(--text-primary)] dark:text-[var(--text-primary)]` is redundant - just use `text-[var(--text-primary)]`)
4. **Exact Values**: Use exact values from design system (`text-[14px]`, `h-[25px]`)
5. **cn for Conditionals**: Use `cn()` from `@/lib/utils` for conditional classes (wraps clsx + tailwind-merge for conflict resolution)
6. **Consistent Spacing**: Use spacing tokens (`gap-[8px]`, `px-[14px]`)
7. **Transitions**: Add transitions for interactive states (`transition-colors`)
8. **Prefer px units**: Use arbitrary px values over scale utilities (e.g., `px-[4px]` instead of `px-1`)

```typescript
import { cn } from '@/lib/utils'

<div
className={clsx(
className={cn(
'base-classes that-always-apply',
isActive && 'active-state-classes',
disabled ? 'cursor-not-allowed opacity-60' : 'cursor-pointer hover:bg-accent',
'dark:bg-[var(--surface-1)] dark:border-[var(--border)]' // Dark mode variants
disabled ? 'cursor-not-allowed opacity-60' : 'cursor-pointer hover:bg-accent'
)}
>
```
Expand Down Expand Up @@ -620,9 +622,10 @@ Before considering a component/hook complete, verify:

### Styling
- [ ] No styles attributes (use className with Tailwind)
- [ ] Dark mode variants included
- [ ] Dark mode variants only when values differ from light mode
- [ ] No duplicate dark: classes with identical values
- [ ] Consistent spacing using design tokens
- [ ] clsx for conditional classes
- [ ] cn() for conditional classes

### Accessibility
- [ ] Semantic HTML elements
Expand Down Expand Up @@ -652,6 +655,11 @@ Before considering a component/hook complete, verify:
// ❌ Inline styles
<div style={{ width: 200, marginTop: 10 }}>

// ❌ Duplicate dark mode classes (same value as light mode)
<div className='text-[var(--text-primary)] dark:text-[var(--text-primary)]'>
<div className='bg-[var(--surface-9)] dark:bg-[var(--surface-9)]'>
<div className='hover:bg-[var(--border)] dark:hover:bg-[var(--border)]'>

// ❌ console.log
console.log('Debug info')

Expand Down Expand Up @@ -690,6 +698,14 @@ export function Component() {
// ✅ Tailwind classes
<div className='w-[200px] mt-[10px]'>

// ✅ No duplicate dark classes - CSS variables already handle theming
<div className='text-[var(--text-primary)]'>
<div className='bg-[var(--surface-9)]'>
<div className='hover:bg-[var(--border)]'>

// ✅ Only add dark: when values differ between modes
<div className='bg-[var(--surface-6)] dark:bg-[var(--surface-9)]'>

// ✅ Logger
logger.info('Debug info', { context })

Expand Down
34 changes: 16 additions & 18 deletions apps/sim/app/_shell/providers/theme-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,23 @@ import { ThemeProvider as NextThemesProvider } from 'next-themes'
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
const pathname = usePathname()

// Force dark mode for workspace pages and templates
// Force light mode for certain public pages
// Force light mode for public/marketing pages
// Workspace and templates respect user's theme preference from settings
const forcedTheme =
pathname.startsWith('/workspace') || pathname.startsWith('/templates')
? '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
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

return (
<NextThemesProvider
Expand Down
42 changes: 21 additions & 21 deletions apps/sim/app/_styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,20 @@
.light {
/* 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-1: #f5f5f5;
--surface-2: #f2f2f2;
--surface-3: #f0f0f0;
--surface-4: #eeeeee;
--surface-5: #ebebeb;
--surface-6: #e8e8e8;
--surface-9: #cecece;
--surface-11: #c8c8c8;
--surface-12: #c4c4c4;
--surface-13: #c0c0c0;
--surface-14: #bcbcbc;
--surface-15: #b8b8b8;
--surface-elevated: #ffffff;
--bg-strong: #f5f5f5;
--bg-strong: #ebebeb;

/* Text */
--text-primary: #1b1b1b;
Expand All @@ -107,11 +107,11 @@
--text-error: #ef4444;

/* Borders / dividers */
--border: #dddddd;
--border-strong: #d1d1d1;
--border: #ebebeb;
--border-strong: #e0e0e0;
--divider: #e5e5e5;
--border-muted: #eeeeee;
--border-success: #d5d5d5;
--border-muted: #f0f0f0;
--border-success: #cecece;

/* Brand & state */
--brand-400: #8e4cfb;
Expand All @@ -124,10 +124,10 @@
--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;
--surface-4-rgb: 238 238 238;
--surface-5-rgb: 235 235 235;
--surface-7-rgb: 224 224 224;
--surface-9-rgb: 206 206 206;
--divider-rgb: 229 229 229;
--white-rgb: 255 255 255;
--black-rgb: 0 0 0;
Expand Down
9 changes: 0 additions & 9 deletions apps/sim/app/api/users/me/settings/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ const logger = createLogger('UserSettingsAPI')
const SettingsSchema = z.object({
theme: z.enum(['system', 'light', 'dark']).optional(),
autoConnect: z.boolean().optional(),
autoPan: z.boolean().optional(),
consoleExpandedByDefault: z.boolean().optional(),
telemetryEnabled: z.boolean().optional(),
emailPreferences: z
.object({
Expand All @@ -25,7 +23,6 @@ const SettingsSchema = z.object({
})
.optional(),
billingUsageNotificationsEnabled: z.boolean().optional(),
showFloatingControls: z.boolean().optional(),
showTrainingControls: z.boolean().optional(),
superUserModeEnabled: z.boolean().optional(),
errorNotificationsEnabled: z.boolean().optional(),
Expand All @@ -35,12 +32,9 @@ const SettingsSchema = z.object({
const defaultSettings = {
theme: 'system',
autoConnect: true,
autoPan: true,
consoleExpandedByDefault: true,
telemetryEnabled: true,
emailPreferences: {},
billingUsageNotificationsEnabled: true,
showFloatingControls: true,
showTrainingControls: false,
superUserModeEnabled: false,
errorNotificationsEnabled: true,
Expand Down Expand Up @@ -72,12 +66,9 @@ export async function GET() {
data: {
theme: userSettings.theme,
autoConnect: userSettings.autoConnect,
autoPan: userSettings.autoPan,
consoleExpandedByDefault: userSettings.consoleExpandedByDefault,
telemetryEnabled: userSettings.telemetryEnabled,
emailPreferences: userSettings.emailPreferences ?? {},
billingUsageNotificationsEnabled: userSettings.billingUsageNotificationsEnabled ?? true,
showFloatingControls: userSettings.showFloatingControls ?? true,
showTrainingControls: userSettings.showTrainingControls ?? false,
superUserModeEnabled: userSettings.superUserModeEnabled ?? true,
errorNotificationsEnabled: userSettings.errorNotificationsEnabled ?? true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export const TxtIcon: React.FC<IconProps> = ({ className = 'w-6 h-6' }) => (
<path d='M14 2V8H20' fill='#9E9E9E' />
<path
d='M14 2L20 8V20C20 21.1 19.1 22 18 22H6C4.9 22 4 21.1 4 20V4C4 2.9 4.9 2 6 2H14Z'
stroke='#424242'
stroke='var(--border-muted)'
strokeWidth='0.5'
strokeLinecap='round'
strokeLinejoin='round'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ export function WorkflowDetails({
<LineChart
data={details.errorRates}
label='Error Rate'
color='#ef4444'
color='var(--text-error)'
unit='%'
/>
{hasDuration && (
Expand Down Expand Up @@ -467,12 +467,12 @@ export function WorkflowDetails({
<div
className='h-[6px] w-[6px] rounded-[2px]'
style={{
backgroundColor: isError ? '#EF4444' : '#B7B7B7',
backgroundColor: isError ? 'var(--text-error)' : '#B7B7B7',
}}
/>
<span
className='font-medium text-[11.5px]'
style={{ color: isError ? '#EF4444' : '#B7B7B7' }}
style={{ color: isError ? 'var(--text-error)' : '#B7B7B7' }}
>
{statusLabel}
</span>
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/app/workspace/[workspaceId]/logs/logs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -483,12 +483,12 @@ export default function Logs() {
<div
className='h-[6px] w-[6px] rounded-[2px]'
style={{
backgroundColor: isError ? '#EF4444' : '#B7B7B7',
backgroundColor: isError ? 'var(--text-error)' : '#B7B7B7',
}}
/>
<span
className='font-medium text-[11.5px]'
style={{ color: isError ? '#EF4444' : '#B7B7B7' }}
style={{ color: isError ? 'var(--text-error)' : '#B7B7B7' }}
>
{statusLabel}
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ interface TemplateCardProps {

export function TemplateCardSkeleton({ className }: { className?: string }) {
return (
<div className={cn('h-[268px] w-full rounded-[8px] bg-[#202020] p-[8px]', className)}>
<div
className={cn(
'h-[268px] w-full rounded-[8px] bg-[var(--surface-elevated)] p-[8px]',
className
)}
>
<div className='h-[180px] w-full animate-pulse rounded-[6px] bg-gray-700' />

<div className='mt-[14px] flex items-center justify-between'>
Expand Down Expand Up @@ -193,7 +198,10 @@ function TemplateCardInner({
return (
<div
onClick={handleCardClick}
className={cn('w-full cursor-pointer rounded-[8px] bg-[#202020] p-[8px]', className)}
className={cn(
'w-full cursor-pointer rounded-[8px] bg-[var(--surface-elevated)] p-[8px]',
className
)}
>
<div
ref={previewRef}
Expand Down Expand Up @@ -238,7 +246,7 @@ function TemplateCardInner({
)
})}
<div
className='flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center rounded-[4px] bg-[#4A4A4A]'
className='flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center rounded-[4px] bg-[var(--surface-14)]'
style={{ marginLeft: '-4px' }}
>
<span className='font-medium text-[10px] text-white'>+{blockTypes.length - 3}</span>
Expand Down Expand Up @@ -273,7 +281,7 @@ function TemplateCardInner({
<img src={authorImageUrl} alt={author} className='h-full w-full object-cover' />
</div>
) : (
<div className='flex h-[26px] w-[26px] flex-shrink-0 items-center justify-center rounded-full bg-[#4A4A4A]'>
<div className='flex h-[26px] w-[26px] flex-shrink-0 items-center justify-center rounded-full bg-[var(--surface-14)]'>
<User className='h-[18px] w-[18px] text-[#888888]' />
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ import {
ChatMessage,
OutputSelect,
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components'
import {
useChatBoundarySync,
useChatDrag,
useChatFileUpload,
useChatResize,
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/chat/hooks'
import { useChatFileUpload } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/chat/hooks'
import { useScrollManagement } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks'
import {
useFloatBoundarySync,
useFloatDrag,
useFloatResize,
} from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-float'
import { useWorkflowExecution } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution'
import type { BlockLog, ExecutionResult } from '@/executor/types'
import { getChatPosition, useChatStore } from '@/stores/chat/store'
Expand Down Expand Up @@ -312,15 +312,15 @@ export function Chat() {
)

// Drag hook
const { handleMouseDown } = useChatDrag({
const { handleMouseDown } = useFloatDrag({
position: actualPosition,
width: chatWidth,
height: chatHeight,
onPositionChange: setChatPosition,
})

// Boundary sync hook - keeps chat within bounds when layout changes
useChatBoundarySync({
useFloatBoundarySync({
isOpen: isChatOpen,
position: actualPosition,
width: chatWidth,
Expand All @@ -334,7 +334,7 @@ export function Chat() {
handleMouseMove: handleResizeMouseMove,
handleMouseLeave: handleResizeMouseLeave,
handleMouseDown: handleResizeMouseDown,
} = useChatResize({
} = useFloatResize({
position: actualPosition,
width: chatWidth,
height: chatHeight,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function OutputSelect({
valueMode = 'id',
disablePopoverPortal = false,
align = 'start',
maxHeight = 300,
maxHeight = 200,
}: OutputSelectProps) {
const [open, setOpen] = useState(false)
const [highlightedIndex, setHighlightedIndex] = useState(-1)
Expand Down Expand Up @@ -420,6 +420,7 @@ export function OutputSelect({
maxHeight={maxHeight}
maxWidth={300}
minWidth={160}
border
disablePortal={disablePopoverPortal}
onKeyDown={handleKeyDown}
tabIndex={0}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
export { useChatBoundarySync } from './use-chat-boundary-sync'
export { useChatDrag } from './use-chat-drag'
export type { ChatFile } from './use-chat-file-upload'
export { useChatFileUpload } from './use-chat-file-upload'
export { useChatResize } from './use-chat-resize'
export { type ChatFile, useChatFileUpload } from './use-chat-file-upload'
Loading