Skip to content

Commit 3aa4155

Browse files
committed
feat(copilot): base UI copilot
1 parent bbcde83 commit 3aa4155

File tree

30 files changed

+1812
-1068
lines changed

30 files changed

+1812
-1068
lines changed

apps/sim/app/globals.css

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
--sidebar-width: 232px;
2020
--triggers-height: 200px;
2121
--blocks-height: 200px;
22-
--panel-width: 240px;
22+
--panel-width: 244px;
2323
}
2424

2525
.sidebar-container {
@@ -310,6 +310,19 @@
310310
scrollbar-color: hsl(var(--muted-foreground) / 0.3) #272727;
311311
}
312312

313+
/* Dark Mode Copilot Scrollbar - Match copilot background */
314+
.copilot-scrollable {
315+
scrollbar-gutter: stable;
316+
}
317+
318+
.dark .copilot-scrollable::-webkit-scrollbar-track {
319+
background: #232323;
320+
}
321+
322+
.dark .copilot-scrollable {
323+
scrollbar-color: hsl(var(--muted-foreground) / 0.3) #232323;
324+
}
325+
313326
/* For Firefox */
314327
* {
315328
scrollbar-width: thin;

apps/sim/app/invite/components/status-card.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
'use client'
22

33
import { useEffect, useState } from 'react'
4-
import { AlertCircle, CheckCircle2, Mail, RotateCcw, ShieldX, UserPlus, Users2 } from 'lucide-react'
4+
import {
5+
AlertCircle,
6+
CheckCircle2,
7+
Loader2,
8+
Mail,
9+
RotateCcw,
10+
ShieldX,
11+
UserPlus,
12+
Users2,
13+
} from 'lucide-react'
514
import { useRouter } from 'next/navigation'
615
import { Button } from '@/components/ui/button'
7-
import { LoadingAgent } from '@/components/ui/loading-agent'
816
import { useBrandConfig } from '@/lib/branding/branding'
917
import { inter } from '@/app/fonts/inter/inter'
1018
import { soehne } from '@/app/fonts/soehne/soehne'
@@ -96,7 +104,7 @@ export function InviteStatusCard({
96104
</p>
97105
</div>
98106
<div className='flex w-full items-center justify-center py-8'>
99-
<LoadingAgent size='lg' />
107+
<Loader2 className='h-8 w-8 animate-spin text-[var(--brand-primary-hex)]' />
100108
</div>
101109

102110
<div
@@ -156,7 +164,7 @@ export function InviteStatusCard({
156164
>
157165
{action.loading ? (
158166
<>
159-
<LoadingAgent size='sm' />
167+
<Loader2 className='mr-2 h-4 w-4 animate-spin' />
160168
{action.label}...
161169
</>
162170
) : (

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/copilot/components/copilot-message/components/markdown-renderer.tsx

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ if (typeof document !== 'undefined') {
3131
style.id = styleId
3232
style.textContent = `
3333
.copilot-markdown-wrapper pre {
34-
color: #e5e7eb !important;
34+
color: #F5F5F5 !important;
3535
font-weight: 400 !important;
3636
text-shadow: none !important;
3737
filter: none !important;
@@ -44,7 +44,7 @@ if (typeof document !== 'undefined') {
4444
}
4545
4646
.dark .copilot-markdown-wrapper pre {
47-
color: #f3f4f6 !important;
47+
color: #F0F0F0 !important;
4848
}
4949
5050
.copilot-markdown-wrapper pre code,
@@ -141,45 +141,45 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
141141
() => ({
142142
// Paragraph
143143
p: ({ children }: React.HTMLAttributes<HTMLParagraphElement>) => (
144-
<p className='mb-1 font-sans text-gray-800 text-sm leading-[1.25rem] last:mb-0 dark:text-gray-200'>
144+
<p className='mb-1 font-[470] font-season text-[#707070] text-sm leading-[1.25rem] last:mb-0 dark:text-[#E8E8E8]'>
145145
{children}
146146
</p>
147147
),
148148

149149
// Headings
150150
h1: ({ children }: React.HTMLAttributes<HTMLHeadingElement>) => (
151-
<h1 className='mt-3 mb-3 font-sans font-semibold text-2xl text-gray-900 dark:text-gray-100'>
151+
<h1 className='mt-3 mb-3 font-season font-semibold text-2xl text-[#0D0D0D] dark:text-[#F0F0F0]'>
152152
{children}
153153
</h1>
154154
),
155155
h2: ({ children }: React.HTMLAttributes<HTMLHeadingElement>) => (
156-
<h2 className='mt-2.5 mb-2.5 font-sans font-semibold text-gray-900 text-xl dark:text-gray-100'>
156+
<h2 className='mt-2.5 mb-2.5 font-season font-semibold text-[#0D0D0D] text-xl dark:text-[#F0F0F0]'>
157157
{children}
158158
</h2>
159159
),
160160
h3: ({ children }: React.HTMLAttributes<HTMLHeadingElement>) => (
161-
<h3 className='mt-2 mb-2 font-sans font-semibold text-gray-900 text-lg dark:text-gray-100'>
161+
<h3 className='mt-2 mb-2 font-season font-semibold text-[#0D0D0D] text-lg dark:text-[#F0F0F0]'>
162162
{children}
163163
</h3>
164164
),
165165
h4: ({ children }: React.HTMLAttributes<HTMLHeadingElement>) => (
166-
<h4 className='mt-5 mb-2 font-sans font-semibold text-base text-gray-900 dark:text-gray-100'>
166+
<h4 className='mt-5 mb-2 font-season font-semibold text-[#0D0D0D] text-base dark:text-[#F0F0F0]'>
167167
{children}
168168
</h4>
169169
),
170170

171171
// Lists
172172
ul: ({ children }: React.HTMLAttributes<HTMLUListElement>) => (
173173
<ul
174-
className='mt-1 mb-1 space-y-1 pl-6 font-sans text-gray-800 dark:text-gray-200'
174+
className='mt-1 mb-1 space-y-1 pl-6 font-[470] font-season text-[#707070] dark:text-[#E8E8E8]'
175175
style={{ listStyleType: 'disc' }}
176176
>
177177
{children}
178178
</ul>
179179
),
180180
ol: ({ children }: React.HTMLAttributes<HTMLOListElement>) => (
181181
<ol
182-
className='mt-1 mb-1 space-y-1 pl-6 font-sans text-gray-800 dark:text-gray-200'
182+
className='mt-1 mb-1 space-y-1 pl-6 font-[470] font-season text-[#707070] dark:text-[#E8E8E8]'
183183
style={{ listStyleType: 'decimal' }}
184184
>
185185
{children}
@@ -189,7 +189,10 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
189189
children,
190190
ordered,
191191
}: React.LiHTMLAttributes<HTMLLIElement> & { ordered?: boolean }) => (
192-
<li className='font-sans text-gray-800 dark:text-gray-200' style={{ display: 'list-item' }}>
192+
<li
193+
className='font-[470] font-season text-[#707070] dark:text-[#E8E8E8]'
194+
style={{ display: 'list-item' }}
195+
>
193196
{children}
194197
</li>
195198
),
@@ -250,7 +253,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
250253
return (
251254
<div className='my-6 w-0 min-w-full rounded-md bg-gray-900 text-sm dark:bg-black'>
252255
<div className='flex items-center justify-between border-gray-700 border-b px-4 py-1.5 dark:border-gray-800'>
253-
<span className='font-sans text-gray-400 text-xs'>{language}</span>
256+
<span className='font-season text-gray-400 text-xs'>{language}</span>
254257
<button
255258
onClick={handleCopy}
256259
className='text-muted-foreground transition-colors hover:text-gray-300'
@@ -264,7 +267,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
264267
</button>
265268
</div>
266269
<div className='overflow-x-auto'>
267-
<pre className='whitespace-pre p-4 font-mono text-gray-100 text-sm leading-relaxed'>
270+
<pre className='whitespace-pre p-4 font-mono text-[#F5F5F5] text-sm leading-relaxed dark:text-[#F0F0F0]'>
268271
{actualCodeText}
269272
</pre>
270273
</div>
@@ -282,7 +285,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
282285
if (inline) {
283286
return (
284287
<code
285-
className='whitespace-normal break-all rounded bg-gray-200 px-1 py-0.5 font-mono text-[0.9em] text-gray-800 dark:bg-gray-700 dark:text-gray-200'
288+
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]'
286289
{...props}
287290
>
288291
{children}
@@ -298,27 +301,27 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
298301

299302
// Bold text
300303
strong: ({ children }: React.HTMLAttributes<HTMLElement>) => (
301-
<strong className='font-semibold text-gray-900 dark:text-gray-100'>{children}</strong>
304+
<strong className='font-semibold text-[#0D0D0D] dark:text-[#F0F0F0]'>{children}</strong>
302305
),
303306

304307
// Bold text (alternative)
305308
b: ({ children }: React.HTMLAttributes<HTMLElement>) => (
306-
<b className='font-semibold text-gray-900 dark:text-gray-100'>{children}</b>
309+
<b className='font-semibold text-[#0D0D0D] dark:text-[#F0F0F0]'>{children}</b>
307310
),
308311

309312
// Italic text
310313
em: ({ children }: React.HTMLAttributes<HTMLElement>) => (
311-
<em className='text-gray-800 italic dark:text-gray-200'>{children}</em>
314+
<em className='text-[#707070] italic dark:text-[#E8E8E8]'>{children}</em>
312315
),
313316

314317
// Italic text (alternative)
315318
i: ({ children }: React.HTMLAttributes<HTMLElement>) => (
316-
<i className='text-gray-800 italic dark:text-gray-200'>{children}</i>
319+
<i className='text-[#707070] italic dark:text-[#E8E8E8]'>{children}</i>
317320
),
318321

319322
// Blockquotes
320323
blockquote: ({ children }: React.HTMLAttributes<HTMLQuoteElement>) => (
321-
<blockquote className='my-4 border-gray-300 border-l-4 py-1 pl-4 font-sans text-gray-700 italic dark:border-gray-600 dark:text-gray-300'>
324+
<blockquote className='my-4 border-gray-300 border-l-4 py-1 pl-4 font-season text-[#858585] italic dark:border-gray-600 dark:text-[#E0E0E0]'>
322325
{children}
323326
</blockquote>
324327
),
@@ -336,29 +339,29 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
336339
// Tables
337340
table: ({ children }: React.TableHTMLAttributes<HTMLTableElement>) => (
338341
<div className='my-4 max-w-full overflow-x-auto'>
339-
<table className='min-w-full table-auto border border-gray-300 font-sans text-sm dark:border-gray-700'>
342+
<table className='min-w-full table-auto border border-gray-300 font-season text-sm dark:border-gray-600'>
340343
{children}
341344
</table>
342345
</div>
343346
),
344347
thead: ({ children }: React.HTMLAttributes<HTMLTableSectionElement>) => (
345-
<thead className='bg-gray-100 text-left dark:bg-gray-800'>{children}</thead>
348+
<thead className='bg-gray-200 text-left dark:bg-[#2A2A2A]'>{children}</thead>
346349
),
347350
tbody: ({ children }: React.HTMLAttributes<HTMLTableSectionElement>) => (
348-
<tbody className='divide-y divide-gray-200 dark:divide-gray-700'>{children}</tbody>
351+
<tbody className='divide-y divide-gray-300 dark:divide-gray-600'>{children}</tbody>
349352
),
350353
tr: ({ children }: React.HTMLAttributes<HTMLTableRowElement>) => (
351-
<tr className='border-gray-200 border-b transition-colors hover:bg-gray-50 dark:border-gray-700 dark:hover:bg-gray-800/60'>
354+
<tr className='border-gray-300 border-b transition-colors hover:bg-gray-100 dark:border-gray-600 dark:hover:bg-[#2A2A2A]/60'>
352355
{children}
353356
</tr>
354357
),
355358
th: ({ children }: React.ThHTMLAttributes<HTMLTableCellElement>) => (
356-
<th className='border-gray-300 border-r px-4 py-2 font-medium text-gray-700 last:border-r-0 dark:border-gray-700 dark:text-gray-300'>
359+
<th className='border-gray-300 border-r px-4 py-2 align-top font-[470] text-[#858585] last:border-r-0 dark:border-gray-600 dark:text-[#E0E0E0]'>
357360
{children}
358361
</th>
359362
),
360363
td: ({ children }: React.TdHTMLAttributes<HTMLTableCellElement>) => (
361-
<td className='break-words border-gray-300 border-r px-4 py-2 text-gray-800 last:border-r-0 dark:border-gray-700 dark:text-gray-200'>
364+
<td className='break-words border-gray-300 border-r px-4 py-2 align-top font-[470] text-[#707070] last:border-r-0 dark:border-gray-600 dark:text-[#E8E8E8]'>
362365
{children}
363366
</td>
364367
),
@@ -377,7 +380,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
377380
)
378381

379382
return (
380-
<div className='copilot-markdown-wrapper max-w-full space-y-3 break-words font-sans text-[#0D0D0D] text-sm leading-[1.25rem] dark:text-gray-100'>
383+
<div className='copilot-markdown-wrapper max-w-full space-y-3 break-words font-[470] font-season text-[#707070] text-sm leading-[1.25rem] dark:text-[#E8E8E8]'>
381384
<ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
382385
{content}
383386
</ReactMarkdown>

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/copilot/components/copilot-message/components/thinking-block.tsx

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use client'
22

33
import { useEffect, useRef, useState } from 'react'
4-
import { Brain } from 'lucide-react'
5-
import { cn } from '@/lib/utils'
4+
import clsx from 'clsx'
5+
import { ChevronUp } from 'lucide-react'
66

77
/**
88
* Timer update interval in milliseconds
@@ -14,6 +14,57 @@ const TIMER_UPDATE_INTERVAL = 100
1414
*/
1515
const SECONDS_THRESHOLD = 1000
1616

17+
/**
18+
* ShimmerOverlayText component for thinking block
19+
* Applies shimmer effect to the "Thought for X.Xs" text during streaming
20+
*/
21+
function ShimmerOverlayText({
22+
label,
23+
value,
24+
active = false,
25+
}: {
26+
label: string
27+
value: string
28+
active?: boolean
29+
}) {
30+
return (
31+
<span className='relative inline-block'>
32+
<span style={{ color: '#B8B8B8' }}>{label}</span>
33+
<span style={{ color: '#787878' }}>{value}</span>
34+
{active ? (
35+
<span
36+
aria-hidden='true'
37+
className='pointer-events-none absolute inset-0 select-none overflow-hidden'
38+
>
39+
<span
40+
className='block text-transparent'
41+
style={{
42+
backgroundImage:
43+
'linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.85) 50%, rgba(255,255,255,0) 100%)',
44+
backgroundSize: '200% 100%',
45+
backgroundRepeat: 'no-repeat',
46+
WebkitBackgroundClip: 'text',
47+
backgroundClip: 'text',
48+
animation: 'thinking-shimmer 1.4s ease-in-out infinite',
49+
mixBlendMode: 'screen',
50+
}}
51+
>
52+
{label}
53+
{value}
54+
</span>
55+
</span>
56+
) : null}
57+
<style>{`
58+
@keyframes thinking-shimmer {
59+
0% { background-position: 150% 0; }
60+
50% { background-position: 0% 0; }
61+
100% { background-position: -150% 0; }
62+
}
63+
`}</style>
64+
</span>
65+
)
66+
}
67+
1768
/**
1869
* Props for the ThinkingBlock component
1970
*/
@@ -105,6 +156,8 @@ export function ThinkingBlock({
105156
return `${seconds}s`
106157
}
107158

159+
const hasContent = content && content.trim().length > 0
160+
108161
return (
109162
<div className='mt-1 mb-0'>
110163
<button
@@ -116,28 +169,32 @@ export function ThinkingBlock({
116169
return next
117170
})
118171
}}
119-
className={cn(
120-
'mb-1 inline-flex items-center gap-1 text-[11px] text-gray-400 transition-colors hover:text-gray-500',
121-
'font-normal italic'
122-
)}
172+
className='mb-1 inline-flex items-center gap-1 text-left font-[470] font-season text-[#B1B1B1] text-sm transition-colors hover:text-[#E6E6E6]'
123173
type='button'
174+
disabled={!hasContent}
124175
>
125-
<Brain className='h-3 w-3' />
126-
<span>
127-
Thought for {formatDuration(duration)}
128-
{isExpanded ? ' (click to collapse)' : ''}
129-
</span>
130-
{isStreaming && (
131-
<span className='inline-flex h-1 w-1 animate-pulse rounded-full bg-gray-400' />
176+
<ShimmerOverlayText
177+
label='Thought'
178+
value={` for ${formatDuration(duration)}`}
179+
active={isStreaming}
180+
/>
181+
{hasContent && (
182+
<ChevronUp
183+
className={clsx('h-3 w-3 transition-transform', isExpanded && 'rotate-180')}
184+
aria-hidden='true'
185+
/>
132186
)}
133187
</button>
134188

135189
{isExpanded && (
136-
<div className='ml-1 border-gray-200 border-l-2 pl-2 dark:border-gray-700'>
137-
<pre className='whitespace-pre-wrap font-mono text-[11px] text-gray-400 dark:text-gray-500'>
190+
<div className='ml-1 border-[#303030] border-l-2 pl-2'>
191+
<pre
192+
className='whitespace-pre-wrap font-[470] font-season text-[12px] leading-[1.15rem]'
193+
style={{ color: '#B8B8B8' }}
194+
>
138195
{content}
139196
{isStreaming && (
140-
<span className='ml-1 inline-block h-2 w-1 animate-pulse bg-gray-400' />
197+
<span className='ml-1 inline-block h-2 w-1 animate-pulse bg-[#B8B8B8]' />
141198
)}
142199
</pre>
143200
</div>

0 commit comments

Comments
 (0)