diff --git a/apps/sim/app/_styles/globals.css b/apps/sim/app/_styles/globals.css index c99b6a04651..78b947eac66 100644 --- a/apps/sim/app/_styles/globals.css +++ b/apps/sim/app/_styles/globals.css @@ -154,7 +154,6 @@ */ --color-amber-50: #fffbeb; --color-amber-200: #fde68a; - --color-amber-300: #fcd34d; --color-amber-400: #fbbf24; --color-amber-500: #f59e0b; --color-amber-600: #d97706; @@ -166,7 +165,6 @@ --color-emerald-400: #34d399; --color-emerald-500: #10b981; --color-green-500: #22c55e; - --color-orange-400: #fb923c; --color-purple-500: #a855f7; --color-red-50: #fef2f2; --color-red-300: #fca5a5; @@ -235,6 +233,18 @@ --animate-hero-edge-draw: hero-edge-draw 520ms ease-out forwards; } +/** Runtime collaborator colours must exist even without a matching utility class. */ +@theme static { + --color-black: #000000; + --color-white: #ffffff; + --color-amber-300: #fcd34d; + --color-orange-400: #fb923c; + --color-pink-400: #f472b6; + --color-purple-400: #c084fc; + --color-violet-500: #8b5cf6; + --color-cool-gray-500: #6b7280; +} + /** * One period of the running block's hatch (26px horizontal). Shifting by * exactly one period is what makes the loop seamless. diff --git a/apps/sim/app/workspace/[workspaceId]/components/presence/presence-avatars.tsx b/apps/sim/app/workspace/[workspaceId]/components/presence/presence-avatars.tsx index e10ad0d62b5..ff53ee14325 100644 --- a/apps/sim/app/workspace/[workspaceId]/components/presence/presence-avatars.tsx +++ b/apps/sim/app/workspace/[workspaceId]/components/presence/presence-avatars.tsx @@ -98,7 +98,7 @@ export function PresenceAvatars({ style={{ zIndex: 0 }} aria-label={`${overflowCount} more ${overflowCount === 1 ? 'user' : 'users'}`} > - + +{overflowCount} diff --git a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/collaboration/caret-presence.ts b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/collaboration/caret-presence.ts index c522b60e088..b6df0b9c6b7 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/collaboration/caret-presence.ts +++ b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/collaboration/caret-presence.ts @@ -18,7 +18,7 @@ import type { Awareness } from 'y-protocols/awareness' export const CARET_LABEL_HOLD_MS = 2000 /** Fallback caret color when a peer's awareness carries no `color`. */ -export const DEFAULT_CARET_COLOR = '#000000' +export const DEFAULT_CARET_COLOR = 'var(--color-black)' /** * The active-state class {@link activateCaretLabel} toggles on the caret node to reveal the diff --git a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/editor-extensions.ts b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/editor-extensions.ts index b85ae7dc191..9d6a3484d7b 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/editor-extensions.ts +++ b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/editor-extensions.ts @@ -35,6 +35,20 @@ import { } from '@/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/raw-markdown-snippet' import { SlashCommand } from '@/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/slash-command/slash-command' +const FileCollaborationCaret = CollaborationCaret.extend({ + addProseMirrorPlugins() { + // Older peers need a resolved colour to apply their selection opacity. + // Resolve at editor mount, before the parent captures and publishes user. + const color = this.options.user.color + const token = typeof color === 'string' ? /^var\((--[\w-]+)\)$/.exec(color)?.[1] : undefined + if (token && typeof document !== 'undefined') { + const resolved = getComputedStyle(document.documentElement).getPropertyValue(token).trim() + if (resolved) this.options.user = { ...this.options.user, color: resolved } + } + return this.parent?.() ?? [] + }, +}) + /** Live collaboration binding for the editor. When present, the editor's history * is Yjs-backed and remote carets/selection render via CollaborationCaret. */ export interface EditorCollaboration { @@ -87,15 +101,15 @@ export function createMarkdownEditorExtensions({ // relayed by the socket provider once connected). `render` tags each caret // with the peer's client id and shows its name label; the selection tint is // a translucent fill of the peer's identity color. - CollaborationCaret.configure({ + FileCollaborationCaret.configure({ provider: { awareness: collaboration.awareness }, user: collaboration.user, render: renderCaret, selectionRender: (user) => { - const hex = typeof user.color === 'string' ? user.color : DEFAULT_CARET_COLOR + const color = typeof user.color === 'string' ? user.color : DEFAULT_CARET_COLOR return { class: 'collaboration-carets__selection', - style: `background-color: ${withAlpha(hex, 0.2)};`, + style: `background-color: ${withAlpha(color, 0.2)};`, } }, }), diff --git a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/list-collaboration.test.ts b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/list-collaboration.test.ts index 1c09208e5ff..e0649f5cc0a 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/list-collaboration.test.ts +++ b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/list-collaboration.test.ts @@ -296,3 +296,24 @@ describe('list editing with delayed peer updates', () => { ) }) }) + +it('publishes resolved global colours so older peers keep translucent selections', () => { + const doc = new Y.Doc() + const awareness = new Awareness(doc) + const user = { name: 'User', color: 'var(--color-pink-400)' } + const extensions = createMarkdownEditorExtensions({ + placeholder: '', + collaboration: { doc, awareness, user }, + }) + document.documentElement.style.setProperty('--color-pink-400', '#f472b6') + const editor = new Editor({ extensions }) + cleanups.push(() => { + editor.destroy() + awareness.destroy() + doc.destroy() + document.documentElement.style.removeProperty('--color-pink-400') + }) + + expect(awareness.getLocalState()?.user.color).toBe('#f472b6') + expect(user.color).toBe('var(--color-pink-400)') +}) diff --git a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-editor.css b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-editor.css index c977cce38f7..3b6cc3f2b85 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-editor.css +++ b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-editor.css @@ -440,7 +440,7 @@ * text without ever shifting the text (or any following text) as the highlight is applied/removed. */ .rich-markdown-nodes mark { - background-color: rgba(255, 212, 0, 0.4); + background-color: color-mix(in srgb, var(--color-amber-400) 40%, transparent); color: inherit; border-radius: 2px; padding: 0 0.1em; @@ -604,5 +604,5 @@ * its solid fill with a fixed dark ink for exactly this reason. */ .rich-markdown-nodes .rich-find-match-active { background-color: var(--brand-secondary); - color: #000; + color: var(--color-black); } diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/constants.ts b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/constants.ts index af00af4b441..e0ea9d30e45 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/constants.ts +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/constants.ts @@ -1,5 +1,5 @@ /** Tailwind class applied to selected rows / columns / cells. */ -export const SELECTION_TINT_BG = 'bg-[rgba(37,99,235,0.06)]' +export const SELECTION_TINT_BG = 'bg-[color-mix(in_srgb,var(--selection)_6%,transparent)]' /** * Fill marking every cell matching the active find query. Reuses the app's diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/diff-controls/diff-controls.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/diff-controls/diff-controls.tsx index 4b9937f017c..adc95e4e4ef 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/diff-controls/diff-controls.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/diff-controls/diff-controls.tsx @@ -81,14 +81,14 @@ export const DiffControls = memo(function DiffControls() { width: '2px', transform: 'skewX(-18.4deg)', background: - 'linear-gradient(to right, var(--border) 50%, color-mix(in srgb, var(--brand-accent) 70%, black) 50%)', + 'linear-gradient(to right, var(--border) 50%, color-mix(in srgb, var(--brand-accent) 70%, var(--color-black)) 50%)', }} /> {/* Accept side */}