diff --git a/bun.lock b/bun.lock index 6eb18971..e8e349c0 100644 --- a/bun.lock +++ b/bun.lock @@ -32,7 +32,7 @@ "@ibm/plex": "^6.4.1", "@lezer/highlight": "^1.2.3", "@octokit/rest": "^22.0.1", - "@opencode-ai/sdk": "^1.2.20", + "@opencode-ai/sdk": "^1.2.26", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", @@ -137,7 +137,7 @@ "@fontsource/ibm-plex-sans": "^5.1.1", "@ibm/plex": "^6.4.1", "@lezer/highlight": "^1.2.3", - "@opencode-ai/sdk": "^1.2.20", + "@opencode-ai/sdk": "^1.2.26", "@pierre/diffs": "1.1.0-beta.13", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", @@ -214,7 +214,7 @@ "version": "1.8.5", "dependencies": { "@openchamber/ui": "workspace:*", - "@opencode-ai/sdk": "^1.2.20", + "@opencode-ai/sdk": "^1.2.26", "adm-zip": "^0.5.16", "jsonc-parser": "^3.3.1", "react": "^19.1.1", @@ -246,7 +246,7 @@ "@fontsource/ibm-plex-sans": "^5.1.1", "@ibm/plex": "^6.4.1", "@octokit/rest": "^22.0.1", - "@opencode-ai/sdk": "^1.2.20", + "@opencode-ai/sdk": "^1.2.26", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", diff --git a/package.json b/package.json index 746c001a..1d30f652 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "vscode:type-check": "bun run --cwd packages/vscode type-check", "docs:validate": "node scripts/docs/validate-docs.mjs", "icons:sprite": "node scripts/generate-file-type-sprite.mjs", + "themes:port:opencode": "tsx scripts/port-opencode-theme.ts", "version:bump": "node scripts/bump-version.mjs", "release:prepare": "bun run build && bun run type-check && bun run lint", "release:test": "./scripts/test-release-build.sh", @@ -88,7 +89,7 @@ "@ibm/plex": "^6.4.1", "@lezer/highlight": "^1.2.3", "@octokit/rest": "^22.0.1", - "@opencode-ai/sdk": "^1.2.20", + "@opencode-ai/sdk": "^1.2.26", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", diff --git a/packages/ui/package.json b/packages/ui/package.json index fa5ade72..944f5a67 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -39,7 +39,7 @@ "@fontsource/ibm-plex-sans": "^5.1.1", "@ibm/plex": "^6.4.1", "@lezer/highlight": "^1.2.3", - "@opencode-ai/sdk": "^1.2.20", + "@opencode-ai/sdk": "^1.2.26", "@pierre/diffs": "1.1.0-beta.13", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", diff --git a/packages/ui/src/components/chat/ChatInput.tsx b/packages/ui/src/components/chat/ChatInput.tsx index ea084d5e..c870a266 100644 --- a/packages/ui/src/components/chat/ChatInput.tsx +++ b/packages/ui/src/components/chat/ChatInput.tsx @@ -59,6 +59,24 @@ const MAX_VISIBLE_TEXTAREA_LINES = 8; const EMPTY_QUEUE: QueuedMessage[] = []; const FILE_MENTION_TOKEN = /^@[^\s]+$/; +const appendWithLineBreaks = (base: string, next: string): string => { + const separator = !base + ? '' + : base.endsWith('\n\n') + ? '' + : base.endsWith('\n') + ? '\n' + : '\n\n'; + + const nextWithTrailingBreaks = next.endsWith('\n\n') + ? next + : next.endsWith('\n') + ? `${next}\n` + : `${next}\n\n`; + + return `${base}${separator}${nextWithTrailingBreaks}`; +}; + interface ChatInputProps { onOpenSettings?: () => void; scrollToBottom?: (options?: { instant?: boolean; force?: boolean }) => void; @@ -589,9 +607,9 @@ export const ChatInput: React.FC = ({ onOpenSettings, scrollToBo if (pending?.text) { if (pending.mode === 'append') { setMessage((prev) => { - if (!pending.text) return prev; - if (!prev.trim()) return pending.text; - return `${prev}\n\n${pending.text}`; + const next = pending.text; + if (!next.trim()) return prev; + return appendWithLineBreaks(prev, next); }); } else { setMessage(pending.text); diff --git a/packages/ui/src/components/chat/MessageList.tsx b/packages/ui/src/components/chat/MessageList.tsx index fe529c74..28b4072e 100644 --- a/packages/ui/src/components/chat/MessageList.tsx +++ b/packages/ui/src/components/chat/MessageList.tsx @@ -1097,14 +1097,25 @@ const MessageList = React.forwardRef(({ useFlushSync: false, }); - const virtualRows = shouldVirtualize ? virtualizer.getVirtualItems() : []; + const isVirtualRowInRange = React.useCallback( + (row: VirtualItem) => row.index >= 0 && row.index < stagedEntries.length, + [stagedEntries.length], + ); + + const virtualRows = shouldVirtualize ? virtualizer.getVirtualItems().filter(isVirtualRowInRange) : []; const lastNonEmptyVirtualRowsRef = React.useRef([]); if (shouldVirtualize && virtualRows.length > 0) { lastNonEmptyVirtualRowsRef.current = virtualRows; + } else if (!shouldVirtualize && lastNonEmptyVirtualRowsRef.current.length > 0) { + lastNonEmptyVirtualRowsRef.current = []; } + const fallbackVirtualRows = shouldVirtualize + ? lastNonEmptyVirtualRowsRef.current.filter(isVirtualRowInRange) + : []; + const effectiveVirtualRows = shouldVirtualize - ? (virtualRows.length > 0 ? virtualRows : lastNonEmptyVirtualRowsRef.current) + ? (virtualRows.length > 0 ? virtualRows : fallbackVirtualRows) : []; const renderVirtualized = shouldVirtualize && effectiveVirtualRows.length > 0; diff --git a/packages/ui/src/components/chat/message/TextSelectionMenu.tsx b/packages/ui/src/components/chat/message/TextSelectionMenu.tsx index 35f6a59b..d545caf1 100644 --- a/packages/ui/src/components/chat/message/TextSelectionMenu.tsx +++ b/packages/ui/src/components/chat/message/TextSelectionMenu.tsx @@ -16,17 +16,147 @@ interface MenuPosition { show: boolean; } +interface SelectionPayload { + plainText: string; + markdownText: string; + rect: DOMRect; +} + const DESKTOP_MENU_SIDE_MARGIN_PX = 8; const DESKTOP_MENU_FALLBACK_WIDTH_PX = 280; +const normalizeLineBreaks = (value: string): string => value.replace(/\r\n?/g, '\n'); + +const trimSelectionValue = (value: string): string => normalizeLineBreaks(value).trim(); + +const textToMarkdownInline = (value: string): string => value.replace(/\s+/g, ' ').trim(); + +const renderInlineMarkdownNode = (node: Node): string => { + if (node.nodeType === Node.TEXT_NODE) { + return textToMarkdownInline(node.textContent || ''); + } + + if (node.nodeType !== Node.ELEMENT_NODE) { + return ''; + } + + const element = node as HTMLElement; + const tag = element.tagName.toLowerCase(); + const childText = Array.from(element.childNodes) + .map((child) => renderInlineMarkdownNode(child)) + .join('') + .replace(/\s+/g, ' ') + .trim(); + + if (!childText && tag !== 'br') { + return ''; + } + + if (tag === 'br') return '\n'; + if (tag === 'strong' || tag === 'b') return `**${childText}**`; + if (tag === 'em' || tag === 'i') return `*${childText}*`; + if (tag === 'code') return `\`${childText.replace(/`/g, '\\`')}\``; + if (tag === 'a') { + const href = element.getAttribute('href'); + return href ? `[${childText}](${href})` : childText; + } + + return childText; +}; + +const renderListMarkdown = (list: HTMLElement, ordered: boolean): string => { + const items = Array.from(list.children).filter( + (child): child is HTMLElement => child instanceof HTMLElement && child.tagName.toLowerCase() === 'li' + ); + + return items + .map((item, index) => { + const prefix = ordered ? `${index + 1}. ` : '- '; + const body = Array.from(item.childNodes) + .map((child) => renderInlineMarkdownNode(child)) + .join('') + .replace(/\s+/g, ' ') + .trim(); + return body ? `${prefix}${body}` : ''; + }) + .filter(Boolean) + .join('\n'); +}; + +const renderBlockMarkdownNode = (node: Node): string => { + if (node.nodeType === Node.TEXT_NODE) { + return trimSelectionValue(node.textContent || ''); + } + + if (node.nodeType !== Node.ELEMENT_NODE) { + return ''; + } + + const element = node as HTMLElement; + const tag = element.tagName.toLowerCase(); + + if (tag === 'pre') { + const codeElement = element.querySelector('code'); + const languageClass = codeElement?.className || ''; + const language = (languageClass.match(/language-([\w-]+)/)?.[1] || '').trim(); + const code = normalizeLineBreaks(codeElement?.textContent || element.textContent || '').replace(/\n$/, ''); + return `\`\`\`${language}\n${code}\n\`\`\``; + } + + if (tag === 'ul') return renderListMarkdown(element, false); + if (tag === 'ol') return renderListMarkdown(element, true); + + if (tag === 'blockquote') { + const content = trimSelectionValue( + Array.from(element.childNodes).map((child) => renderBlockMarkdownNode(child)).join('\n') + ); + return content + .split('\n') + .filter((line) => line.length > 0) + .map((line) => `> ${line}`) + .join('\n'); + } + + if (/^h[1-6]$/.test(tag)) { + const level = Number.parseInt(tag[1], 10); + const text = trimSelectionValue(Array.from(element.childNodes).map((child) => renderInlineMarkdownNode(child)).join('')); + return text ? `${'#'.repeat(level)} ${text}` : ''; + } + + if (tag === 'p' || tag === 'div' || tag === 'li') { + return trimSelectionValue(Array.from(element.childNodes).map((child) => renderInlineMarkdownNode(child)).join('')); + } + + const blockChildren = Array.from(element.childNodes) + .map((child) => renderBlockMarkdownNode(child)) + .filter((child) => child.length > 0); + if (blockChildren.length > 0) { + return blockChildren.join('\n\n'); + } + + return trimSelectionValue(Array.from(element.childNodes).map((child) => renderInlineMarkdownNode(child)).join('')); +}; + +const rangeToMarkdown = (range: Range, plainText: string): string => { + const fragment = range.cloneContents(); + const markdown = Array.from(fragment.childNodes) + .map((node) => renderBlockMarkdownNode(node)) + .filter((value) => value.length > 0) + .join('\n\n') + .trim(); + + return markdown || trimSelectionValue(plainText); +}; + export const TextSelectionMenu: React.FC = ({ containerRef }) => { const [position, setPosition] = React.useState({ x: 0, y: 0, show: false }); const [selectedText, setSelectedText] = React.useState(''); + const [selectedTextMarkdown, setSelectedTextMarkdown] = React.useState(''); const [isDragging, setIsDragging] = React.useState(false); const [isOpening, setIsOpening] = React.useState(false); const menuRef = React.useRef(null); const menuWidthRef = React.useRef(DESKTOP_MENU_FALLBACK_WIDTH_PX); - const pendingSelectionRef = React.useRef<{ text: string; rect: DOMRect } | null>(null); + const pendingSelectionRef = React.useRef(null); const openRafRef = React.useRef(null); const isMenuVisibleRef = React.useRef(false); const createSession = useSessionStore((state) => state.createSession); @@ -61,6 +191,7 @@ export const TextSelectionMenu: React.FC = ({ containerR setPosition((prev) => ({ ...prev, show: false })); setSelectedText(''); + setSelectedTextMarkdown(''); isMenuVisibleRef.current = false; }, []); @@ -85,7 +216,7 @@ export const TextSelectionMenu: React.FC = ({ containerR const showMenu = React.useCallback(() => { if (!pendingSelectionRef.current) return; - const { text, rect } = pendingSelectionRef.current; + const { plainText, markdownText, rect } = pendingSelectionRef.current; const shouldAnimateIn = !position.show; // Position menu above the selection @@ -94,7 +225,8 @@ export const TextSelectionMenu: React.FC = ({ containerR : getDesktopClampedX(rect.left + rect.width / 2); const menuY = rect.top - 10; - setSelectedText(text); + setSelectedText(plainText); + setSelectedTextMarkdown(markdownText); setPosition({ x: menuX, y: menuY, @@ -160,7 +292,7 @@ export const TextSelectionMenu: React.FC = ({ containerR return; } - const text = selection.toString().trim(); + const text = trimSelectionValue(selection.toString()); // Only show if we have text and the selection is within our container if (!text) { @@ -184,7 +316,11 @@ export const TextSelectionMenu: React.FC = ({ containerR const rect = range.getBoundingClientRect(); // Store the selection but don't show menu yet if dragging - pendingSelectionRef.current = { text, rect }; + pendingSelectionRef.current = { + plainText: text, + markdownText: rangeToMarkdown(range, text), + rect, + }; // Only show menu if we're not currently dragging if (!isDragging) { @@ -247,16 +383,16 @@ export const TextSelectionMenu: React.FC = ({ containerR }, [containerRef, handleSelectionChange, hideMenu, showMenu]); const handleAddToChat = React.useCallback(() => { - if (!selectedText) return; + if (!selectedTextMarkdown) return; - const fenced = `\`\`\`md\n${selectedText}\n\`\`\``; - setPendingInputText(fenced, 'append'); + const markdownBlock = `\`\`\`md\n${selectedTextMarkdown}\n\`\`\``; + setPendingInputText(markdownBlock, 'append'); hideMenu(); // Clear selection window.getSelection()?.removeAllRanges(); - }, [selectedText, setPendingInputText, hideMenu]); + }, [selectedTextMarkdown, setPendingInputText, hideMenu]); const handleCreateNewSession = React.useCallback(async () => { if (!selectedText) return; diff --git a/packages/ui/src/components/chat/message/parts/ProgressiveGroup.tsx b/packages/ui/src/components/chat/message/parts/ProgressiveGroup.tsx index 6be3f955..bd9e12a9 100644 --- a/packages/ui/src/components/chat/message/parts/ProgressiveGroup.tsx +++ b/packages/ui/src/components/chat/message/parts/ProgressiveGroup.tsx @@ -206,7 +206,7 @@ const normalizePathValue = (value: string): string => { if (!trimmed) { return ''; } - return trimmed.replace(/\\/g, '/'); + return trimmed.replace(/\\/g, '/').replace(/\/{2,}/g, '/'); }; const trimTrailingSlashes = (value: string): string => { @@ -240,6 +240,45 @@ const getRelativePathFromDirectory = (filePath: string, currentDirectory: string return normalizedPath; }; +const renderReadFilePath = (displayPath: string) => { + const lastSlash = displayPath.lastIndexOf('/'); + + if (lastSlash === -1) { + return ( + + {displayPath} + + ); + } + + const dir = displayPath.slice(0, lastSlash); + const name = displayPath.slice(lastSlash + 1); + const hasAbsoluteRoot = dir.startsWith('/'); + const displayDir = hasAbsoluteRoot ? dir.slice(1) : dir; + + return ( + + {hasAbsoluteRoot ? / : null} + + {displayDir} + + / + {name} + + ); +}; + const resolveAbsolutePath = (currentDirectory: string, filePath: string): string => { const normalizedPath = normalizePathValue(filePath); if (!normalizedPath) { @@ -502,17 +541,7 @@ export const StaticToolRow: React.FC<{ title={entry.offset ? `${entry.displayPath}:${entry.offset}` : entry.displayPath} > {showToolFileIcons ? : null} - - {entry.displayPath} - + {renderReadFilePath(entry.displayPath)} )) : null} @@ -520,7 +549,7 @@ export const StaticToolRow: React.FC<{ ? descriptions.map((desc, index) => ( 0 ? ( diff --git a/packages/ui/src/components/chat/message/parts/ToolPart.tsx b/packages/ui/src/components/chat/message/parts/ToolPart.tsx index 7e7c2dc4..58f27807 100644 --- a/packages/ui/src/components/chat/message/parts/ToolPart.tsx +++ b/packages/ui/src/components/chat/message/parts/ToolPart.tsx @@ -103,7 +103,7 @@ const getMultiFileDescription = ( {showFileIcons ? : null} { - if (absolutePath.startsWith(currentDirectory)) { - const relativePath = absolutePath.substring(currentDirectory.length); +const normalizeDisplayPath = (value: string): string => { + const trimmed = value.trim().replace(/\\/g, '/').replace(/\/{2,}/g, '/'); + if (!trimmed || trimmed === '/') { + return trimmed; + } + return trimmed.replace(/\/+$/, ''); +}; - return relativePath.startsWith('/') ? relativePath.substring(1) : relativePath; +const getRelativePath = (absolutePath: string, currentDirectory: string): string => { + const normalizedAbsolutePath = normalizeDisplayPath(absolutePath); + const normalizedCurrentDirectory = normalizeDisplayPath(currentDirectory); + + if (!normalizedAbsolutePath) { + return ''; } - return absolutePath; + if (!normalizedCurrentDirectory) { + return normalizedAbsolutePath; + } + + if (normalizedAbsolutePath === normalizedCurrentDirectory) { + return '.'; + } + + const prefix = `${normalizedCurrentDirectory}/`; + if (normalizedAbsolutePath.startsWith(prefix)) { + return normalizedAbsolutePath.slice(prefix.length); + } + + return normalizedAbsolutePath; }; const usePierreThemeConfig = () => { @@ -390,6 +412,13 @@ const getToolDescriptionPath = (part: ToolPartType, state: ToolStateUnion, curre } } + if (part.tool === 'read' && input) { + const filePath = input?.filePath || input?.file_path || input?.path || metadata?.filePath || metadata?.file_path || metadata?.path; + if (typeof filePath === 'string') { + return getRelativePath(filePath, currentDirectory); + } + } + if (['write', 'create', 'file_write'].includes(part.tool) && input) { const filePath = input?.filePath || input?.file_path || input?.path; if (typeof filePath === 'string') { @@ -853,7 +882,7 @@ const TaskToolSummary: React.FC<{ ) : ( { const dir = path.slice(0, lastSlash); const name = path.slice(lastSlash + 1); + const hasAbsoluteRoot = dir.startsWith('/'); + const displayDir = hasAbsoluteRoot ? dir.slice(1) : dir; return ( + {hasAbsoluteRoot ? / : null} - {dir} + {displayDir} / @@ -998,20 +1030,23 @@ const renderAnimatedPathWithIcon = (path: string, _animate = true, grow = true, const dir = path.slice(0, lastSlash); const name = path.slice(lastSlash + 1); + const hasAbsoluteRoot = dir.startsWith('/'); + const displayDir = hasAbsoluteRoot ? dir.slice(1) : dir; return ( {showFileIcons ? : null} - + + {hasAbsoluteRoot ? / : null} - {dir} + {displayDir} / @@ -1933,7 +1968,7 @@ const ToolPart: React.FC = ({ renderAnimatedPathWithIcon(descriptionPath, animateTailText, false, showToolFileIcons) ) : ( ({ + sortableId: `${projectKey}:${group.id}`, + groupId: group.id, + })); + const sortableGroupIds = sortableEntries.map((entry) => entry.sortableId); + const sortableIdToGroupId = new Map(sortableEntries.map((entry) => [entry.sortableId, entry.groupId])); return ( { const { active, over } = event; if (!over || active.id === over.id) return; - const oldIndex = orderedGroups.findIndex((item) => item.id === active.id); - const newIndex = orderedGroups.findIndex((item) => item.id === over.id); + const activeId = typeof active.id === 'string' ? sortableIdToGroupId.get(active.id) : null; + const overId = typeof over.id === 'string' ? sortableIdToGroupId.get(over.id) : null; + if (!activeId || !overId) return; + const oldIndex = orderedGroups.findIndex((item) => item.id === activeId); + const newIndex = orderedGroups.findIndex((item) => item.id === overId); if (oldIndex === -1 || newIndex === -1 || oldIndex === newIndex) return; const next = arrayMove(orderedGroups, oldIndex, newIndex).map((item) => item.id); props.setGroupOrderByProject((prev) => { @@ -195,11 +204,11 @@ export function SidebarProjectsList(props: Props): React.ReactNode { }); }} > - group.id)} strategy={verticalListSortingStrategy}> + {orderedGroups.map((group) => { const groupKey = `${projectKey}:${group.id}`; return ( - + {props.renderGroupSessions(group, groupKey, projectKey)} ); diff --git a/packages/ui/src/components/ui/text.tsx b/packages/ui/src/components/ui/text.tsx index 45deeb38..3cc94530 100644 --- a/packages/ui/src/components/ui/text.tsx +++ b/packages/ui/src/components/ui/text.tsx @@ -10,6 +10,14 @@ type Variant = { }; const variants = [ + { + variant: "static", + component: ({ children, className, ...props }) => ( + + {children} + + ), + }, { variant: "shine", component: ({ children, className, ...props }) => ( @@ -210,7 +218,7 @@ export type TextProps = { Partial; export function Text({ variant = "shine", className, ...props }: TextProps) { - const FALLBACK_INDEX = 0; + const FALLBACK_INDEX = 1; const variantComponent = variants.find((v) => v.variant === variant)?.component; diff --git a/packages/ui/src/hooks/useChatScrollManager.ts b/packages/ui/src/hooks/useChatScrollManager.ts index bd8eaba4..9fd575b5 100644 --- a/packages/ui/src/hooks/useChatScrollManager.ts +++ b/packages/ui/src/hooks/useChatScrollManager.ts @@ -72,8 +72,6 @@ const PROGRAMMATIC_SCROLL_SUPPRESS_MS = 200; const DIRECT_SCROLL_INTENT_WINDOW_MS = 250; // Threshold for re-pinning: 10% of container height (matches bottom spacer) const PIN_THRESHOLD_RATIO = 0.10; -const REPIN_BLOCK_AFTER_RELEASE_MS = 4000; -const STRICT_REPIN_DISTANCE_PX = 160; const SORTED_PIN_THRESHOLD_PX = 24; export const useChatScrollManager = ({ @@ -113,7 +111,6 @@ export const useChatScrollManager = ({ const suppressUserScrollUntilRef = React.useRef(0); const lastDirectScrollIntentAtRef = React.useRef(0); const isPinnedRef = React.useRef(true); - const repinBlockedUntilRef = React.useRef(0); const lastScrollTopRef = React.useRef(0); const touchLastYRef = React.useRef(null); @@ -127,10 +124,6 @@ export const useChatScrollManager = ({ return container.scrollHeight - container.scrollTop - container.clientHeight; }, []); - const isStrictlyAtBottom = React.useCallback((distanceFromBottom: number) => { - return distanceFromBottom <= STRICT_REPIN_DISTANCE_PX; - }, []); - const updatePinnedState = React.useCallback((newPinned: boolean) => { if (isPinnedRef.current !== newPinned) { isPinnedRef.current = newPinned; @@ -148,9 +141,6 @@ export const useChatScrollManager = ({ }, [markProgrammaticScroll, scrollEngine]); const scrollPinnedToBottom = React.useCallback(() => { - if (Date.now() < repinBlockedUntilRef.current) { - return; - } if (streamingMessageId) { scrollToBottomInternal({ followBottom: true }); return; @@ -192,7 +182,6 @@ export const useChatScrollManager = ({ if (!container) return; // Re-pin when explicitly scrolling to bottom - repinBlockedUntilRef.current = 0; updatePinnedState(true); scrollToBottomInternal(options); @@ -201,7 +190,6 @@ export const useChatScrollManager = ({ const releasePinnedScroll = React.useCallback(() => { scrollEngine.cancelFollow(); - repinBlockedUntilRef.current = Date.now() + REPIN_BLOCK_AFTER_RELEASE_MS; updatePinnedState(false); updateScrollButtonVisibility(); }, [scrollEngine, updatePinnedState, updateScrollButtonVisibility]); @@ -221,26 +209,19 @@ export const useChatScrollManager = ({ // Handle pin/unpin logic const currentScrollTop = container.scrollTop; - const distanceFromBottom = getDistanceFromBottom(); - const scrollingUp = currentScrollTop < lastScrollTopRef.current; - // Unpin whenever we move away from bottom. - // Also handle programmatic jumps to older content (timeline navigation) - // so we don't snap back to bottom on the next content update. - if (isPinnedRef.current) { - const nearBottom = isNearBottom(distanceFromBottom, getPinThreshold()); - const scrollingUpByUserIntent = Boolean(!isProgrammatic && event?.isTrusted && hasDirectIntent && scrollingUp); - const programmaticJumpAwayFromBottom = Boolean(!event?.isTrusted && scrollingUp && !nearBottom); - - if (scrollingUpByUserIntent || programmaticJumpAwayFromBottom) { + // Unpin requires strict user intent check + if (event?.isTrusted && !isProgrammatic && hasDirectIntent) { + if (scrollingUp && isPinnedRef.current) { updatePinnedState(false); } } - // Re-pin only when returning to bottom, not while still scrolling up. - if (!isPinnedRef.current && now >= repinBlockedUntilRef.current) { - if (event?.isTrusted && !scrollingUp && isStrictlyAtBottom(distanceFromBottom)) { + // Re-pin at bottom should always work (even momentum scroll) + if (!isPinnedRef.current) { + const distanceFromBottom = getDistanceFromBottom(); + if (!scrollingUp && distanceFromBottom <= getPinThreshold()) { updatePinnedState(true); } } @@ -255,7 +236,6 @@ export const useChatScrollManager = ({ currentSessionId, getDistanceFromBottom, getPinThreshold, - isStrictlyAtBottom, scrollEngine, sessionMessages.length, updatePinnedState, @@ -275,7 +255,6 @@ export const useChatScrollManager = ({ rootHeight: container.clientHeight, }); - // Scrolling up while pinned → unpin and kill follow loop immediately if (isPinnedRef.current && shouldPauseAutoScrollOnWheel({ root: container, target: event.target, @@ -283,9 +262,7 @@ export const useChatScrollManager = ({ })) { scrollEngine.cancelFollow(); updatePinnedState(false); - return; } - }, [scrollEngine, updatePinnedState]); React.useEffect(() => { @@ -383,7 +360,6 @@ export const useChatScrollManager = ({ // Maintain pin-to-bottom when content changes React.useEffect(() => { if (!isPinnedRef.current) return; - if (Date.now() < repinBlockedUntilRef.current) return; if (isSyncing) return; const container = scrollRef.current; @@ -405,7 +381,7 @@ export const useChatScrollManager = ({ updateScrollButtonVisibility(); // Maintain pin when content grows - fast smooth follow - if (isPinnedRef.current && Date.now() >= repinBlockedUntilRef.current) { + if (isPinnedRef.current) { const distanceFromBottom = getDistanceFromBottom(); if (distanceFromBottom > getAutoFollowThreshold()) { scrollPinnedToBottom(); @@ -417,7 +393,7 @@ export const useChatScrollManager = ({ // Also observe children for content changes const childObserver = new MutationObserver(() => { - if (isPinnedRef.current && Date.now() >= repinBlockedUntilRef.current) { + if (isPinnedRef.current) { const distanceFromBottom = getDistanceFromBottom(); if (distanceFromBottom > getAutoFollowThreshold()) { scrollPinnedToBottom(); @@ -454,7 +430,7 @@ export const useChatScrollManager = ({ updateScrollButtonVisibility(); // Maintain pin when content changes - fast smooth follow - if (isPinnedRef.current && Date.now() >= repinBlockedUntilRef.current) { + if (isPinnedRef.current) { const distanceFromBottom = getDistanceFromBottom(); if (distanceFromBottom > getAutoFollowThreshold()) { scrollPinnedToBottom(); @@ -471,7 +447,7 @@ export const useChatScrollManager = ({ const handlers: AnimationHandlers = { onChunk: () => { updateScrollButtonVisibility(); - if (isPinnedRef.current && Date.now() >= repinBlockedUntilRef.current) { + if (isPinnedRef.current) { const distanceFromBottom = getDistanceFromBottom(); if (distanceFromBottom > getAutoFollowThreshold()) { scrollPinnedToBottom(); @@ -485,7 +461,7 @@ export const useChatScrollManager = ({ onAnimationStart: () => {}, onAnimatedHeightChange: () => { updateScrollButtonVisibility(); - if (isPinnedRef.current && Date.now() >= repinBlockedUntilRef.current) { + if (isPinnedRef.current) { const distanceFromBottom = getDistanceFromBottom(); if (distanceFromBottom > getAutoFollowThreshold()) { scrollPinnedToBottom(); diff --git a/packages/ui/src/lib/theme/themes/amoled-dark.json b/packages/ui/src/lib/theme/themes/amoled-dark.json index 7e5bb94a..de44ab53 100644 --- a/packages/ui/src/lib/theme/themes/amoled-dark.json +++ b/packages/ui/src/lib/theme/themes/amoled-dark.json @@ -2,12 +2,14 @@ "metadata": { "id": "amoled-dark", "name": "AMOLED", - "description": "Port of OpenCode AMOLED theme (dark variant)", + "description": "Ported from OpenCode AMOLED theme (dark variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "dark", "tags": [ "dark", "opencode", + "ported", "amoled" ] }, @@ -15,10 +17,10 @@ "primary": { "base": "#954af5", "hover": "#9f66f4", - "active": "#9f66f4", + "active": "#531195", "foreground": "#ffffff", "muted": "#954af580", - "emphasis": "#9f66f4" + "emphasis": "#954af5" }, "surface": { "background": "#000000", @@ -27,20 +29,20 @@ "mutedForeground": "#dbdbdb", "elevated": "#0a0a0a", "elevatedForeground": "#ffffff", - "overlay": "#00000080", - "subtle": "#191919" + "overlay": "#000000cc", + "subtle": "#111111" }, "interactive": { "border": "#434343", "borderHover": "#4e4e4e", "borderFocus": "#531195", - "selection": "#3c0770", + "selection": "#ffffff1f", "selectionForeground": "#ffffff", "focus": "#531195", - "focusRing": "#53119559", + "focusRing": "#53119561", "cursor": "#ffffff", - "hover": "#191919", - "active": "#191919" + "hover": "#ffffff17", + "active": "#ffffff1f" }, "status": { "error": "#c71133", @@ -48,15 +50,15 @@ "errorBackground": "#5d0212", "errorBorder": "#7d081d", "warning": "#c49925", - "warningForeground": "#ffffff", + "warningForeground": "#151313", "warningBackground": "#353003", "warningBorder": "#494308", "success": "#2bbd69", - "successForeground": "#ffffff", + "successForeground": "#151313", "successBackground": "#08391c", "successBorder": "#025027", "info": "#24b6b6", - "infoForeground": "#ffffff", + "infoForeground": "#151313", "infoBackground": "#063636", "infoBorder": "#0f4b4b" }, @@ -64,12 +66,12 @@ "open": "#2bbd69", "draft": "#dbdbdb", "blocked": "#c49925", - "merged": "#ff00ff", + "merged": "#18ffff", "closed": "#c71133" }, "syntax": { "base": { - "background": "#111111", + "background": "#0a0a0a", "foreground": "#ffffff", "comment": "#555555", "keyword": "#ff00ff", @@ -82,24 +84,24 @@ }, "tokens": { "commentDoc": "#555555", - "stringEscape": "#b388ff", + "stringEscape": "#ffffff", "keywordImport": "#ff00ff", "storageModifier": "#ff00ff", "functionCall": "#ffea00", "method": "#ffea00", "variableProperty": "#ffea00", "variableOther": "#ffffff", - "variableGlobal": "#b388ff", + "variableGlobal": "#18ffff", "variableLocal": "#dbdbdb", "parameter": "#ffffff", - "constant": "#b388ff", + "constant": "#18ffff", "class": "#fef5a2", "className": "#fef5a2", "interface": "#fef5a2", "struct": "#fef5a2", "enum": "#fef5a2", "typeParameter": "#fef5a2", - "namespace": "#ff00ff", + "namespace": "#fef5a2", "module": "#ff00ff", "tag": "#ff00ff", "jsxTag": "#ff00ff", @@ -107,12 +109,12 @@ "tagAttributeValue": "#00ff88", "boolean": "#18ffff", "decorator": "#ff00ff", - "label": "#ff00ff", + "label": "#ffea00", "punctuation": "#dbdbdb", "macro": "#ff00ff", "preprocessor": "#ff00ff", "regex": "#ffffff", - "url": "#e3d7fe", + "url": "#954af5", "key": "#ffea00", "exception": "#c71133" }, @@ -123,35 +125,58 @@ "diffRemovedBackground": "#230204", "diffModified": "#fef5a2", "diffModifiedBackground": "#1f1b27", - "lineNumber": "#bebebe", + "lineNumber": "#dbdbdb", "lineNumberActive": "#ffffff" } }, - "markdown": { - "heading1": "#e3d7fe", - "heading2": "#e3d7fe", - "heading3": "#ffffff", - "heading4": "#ffffff", - "link": "#e3d7fe", - "linkHover": "#a9fdfc", - "inlineCode": "#8cfeb0", - "inlineCodeBackground": "#111111", - "blockquote": "#fef5a2", - "blockquoteBorder": "#434343", - "listMarker": "#e3d7fe99" + "header": { + "background": "#000000", + "foreground": "#ffffff", + "border": "#434343", + "icon": "#dbdbdb", + "hover": "#ffffff17" + }, + "sidebar": { + "background": "#111111", + "foreground": "#dbdbdb", + "border": "#434343", + "icon": "#dbdbdb", + "hover": "#ffffff17", + "active": "#ffffff1f", + "accent": "#954af5", + "accentForeground": "#ffffff" }, "chat": { + "background": "#000000", "userMessage": "#ffffff", - "userMessageBackground": "#3c0770", + "userMessageBackground": "#0a0a0a", "assistantMessage": "#ffffff", "assistantMessageBackground": "#000000", "timestamp": "#dbdbdb", - "divider": "#434343" + "divider": "#434343", + "typing": "#dbdbdb" + }, + "markdown": { + "heading1": "#954af5", + "heading2": "#954af5", + "heading3": "#ffffff", + "heading4": "#ffffff", + "link": "#954af5", + "linkHover": "#9f66f4", + "inlineCode": "#2bbd69", + "inlineCodeBackground": "#111111", + "blockquote": "#dbdbdb", + "blockquoteBorder": "#434343", + "listMarker": "#954af599", + "bold": "#ffffff", + "italic": "#dbdbdb", + "strikethrough": "#dbdbdb", + "hr": "#434343" }, "tools": { - "background": "#11111180", - "border": "#434343b3", - "headerHover": "#19191980", + "background": "#111111", + "border": "#434343", + "headerHover": "#ffffff17", "icon": "#dbdbdb", "title": "#ffffff", "description": "#dbdbdb", @@ -160,8 +185,224 @@ "addedBackground": "#011406", "removed": "#f20e3f", "removedBackground": "#230204", - "lineNumber": "#bebebe" + "modified": "#fef5a2", + "modifiedBackground": "#1f1b27", + "lineNumber": "#dbdbdb" + }, + "bash": { + "background": "#0a0a0a", + "foreground": "#ffffff", + "info": "#24b6b6", + "warning": "#c49925", + "error": "#c71133" + }, + "lsp": { + "background": "#0a0a0a", + "foreground": "#ffffff", + "info": "#24b6b6", + "warning": "#c49925", + "error": "#c71133" } + }, + "forms": { + "inputBackground": "#0a0a0a", + "inputForeground": "#ffffff", + "inputBorder": "#434343", + "inputBorderHover": "#4e4e4e", + "inputBorderFocus": "#531195", + "inputPlaceholder": "#dbdbdb", + "inputDisabled": "#111111", + "inputSelection": "#ffffff1f", + "label": "#dbdbdb", + "helperText": "#dbdbdb" + }, + "buttons": { + "primary": { + "bg": "#954af5", + "fg": "#ffffff", + "border": "#954af5", + "hover": "#9f66f4", + "active": "#531195", + "disabled": "#111111" + }, + "secondary": { + "bg": "#0a0a0a", + "fg": "#ffffff", + "border": "#434343", + "hover": "#ffffff17", + "active": "#ffffff1f", + "disabled": "#111111" + }, + "ghost": { + "bg": "#00000000", + "fg": "#ffffff", + "border": "#00000000", + "hover": "#ffffff17", + "active": "#ffffff1f", + "disabled": "#dbdbdb" + }, + "destructive": { + "bg": "#c71133", + "fg": "#ffffff", + "border": "#7d081d", + "hover": "#5d0212", + "active": "#c71133", + "disabled": "#111111" + } + }, + "modal": { + "background": "#0a0a0a", + "foreground": "#ffffff", + "border": "#434343", + "overlay": "#000000d6" + }, + "popover": { + "background": "#0a0a0a", + "foreground": "#ffffff", + "border": "#434343", + "shadow": "0 18px 48px rgba(0, 0, 0, 0.45)" + }, + "commandPalette": { + "background": "#0a0a0a", + "foreground": "#ffffff", + "border": "#434343", + "inputBackground": "#0a0a0a", + "selectedBackground": "#ffffff1f", + "selectedForeground": "#ffffff", + "muted": "#dbdbdb" + }, + "fileAttachment": { + "background": "#111111", + "foreground": "#ffffff", + "border": "#434343", + "icon": "#dbdbdb", + "removeHover": "#5d0212" + }, + "sessions": { + "background": "#000000", + "foreground": "#ffffff", + "mutedForeground": "#dbdbdb", + "border": "#434343", + "hover": "#ffffff17", + "active": "#ffffff1f" + }, + "modelSelector": { + "background": "#0a0a0a", + "foreground": "#ffffff", + "border": "#434343", + "selectedBackground": "#ffffff1f", + "selectedForeground": "#ffffff" + }, + "permissions": { + "background": "#0a0a0a", + "foreground": "#ffffff", + "border": "#434343", + "allow": "#2bbd69", + "allowBackground": "#08391c", + "deny": "#c71133", + "denyBackground": "#5d0212" + }, + "loading": { + "spinner": "#954af5", + "spinnerTrack": "#111111", + "skeleton": "#111111", + "shimmer": "#ffffff17" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#ffffff33", + "thumbHover": "#ffffff57" + }, + "badges": { + "default": { + "bg": "#111111", + "fg": "#ffffff", + "border": "#434343" + }, + "info": { + "bg": "#063636", + "fg": "#24b6b6", + "border": "#0f4b4b" + }, + "success": { + "bg": "#08391c", + "fg": "#2bbd69", + "border": "#025027" + }, + "warning": { + "bg": "#353003", + "fg": "#c49925", + "border": "#494308" + }, + "error": { + "bg": "#5d0212", + "fg": "#c71133", + "border": "#7d081d" + } + }, + "toast": { + "background": "#0a0a0a", + "foreground": "#ffffff", + "border": "#434343", + "success": { + "background": "#08391c", + "foreground": "#2bbd69", + "border": "#025027" + }, + "warning": { + "background": "#353003", + "foreground": "#c49925", + "border": "#494308" + }, + "error": { + "background": "#5d0212", + "foreground": "#c71133", + "border": "#7d081d" + }, + "info": { + "background": "#063636", + "foreground": "#24b6b6", + "border": "#0f4b4b" + } + }, + "emptyState": { + "icon": "#dbdbdb", + "title": "#ffffff", + "description": "#dbdbdb", + "border": "#434343" + }, + "table": { + "border": "#434343", + "headerBackground": "#0a0a0a", + "headerForeground": "#ffffff", + "rowHover": "#ffffff17", + "rowSelected": "#ffffff1f" + }, + "charts": { + "series": [ + "#954af5", + "#24b6b6", + "#2bbd69", + "#c49925", + "#c71133" + ] + }, + "a11y": { + "focusRing": "#531195", + "selection": "#ffffff1f", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(0, 0, 0, 0.22)", + "md": "0 12px 32px rgba(0, 0, 0, 0.32)", + "lg": "0 24px 56px rgba(0, 0, 0, 0.42)", + "focus": "0 0 0 3px #53119559" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/amoled-light.json b/packages/ui/src/lib/theme/themes/amoled-light.json index 4f34fa80..1766c7b9 100644 --- a/packages/ui/src/lib/theme/themes/amoled-light.json +++ b/packages/ui/src/lib/theme/themes/amoled-light.json @@ -2,12 +2,14 @@ "metadata": { "id": "amoled-light", "name": "AMOLED", - "description": "Port of OpenCode AMOLED theme (light variant)", + "description": "Ported from OpenCode AMOLED theme (light variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "light", "tags": [ "light", "opencode", + "ported", "amoled" ] }, @@ -15,10 +17,10 @@ "primary": { "base": "#6209fd", "hover": "#5806e6", - "active": "#5806e6", + "active": "#babafa", "foreground": "#ffffff", "muted": "#6209fd80", - "emphasis": "#5806e6" + "emphasis": "#6209fd" }, "surface": { "background": "#f1f1f1", @@ -27,20 +29,20 @@ "mutedForeground": "#232323", "elevated": "#eaeaea", "elevatedForeground": "#0a0a0a", - "overlay": "#0000004d", - "subtle": "#dbdbdb" + "overlay": "#f1f1f133", + "subtle": "#e3e3e3" }, "interactive": { "border": "#b9b9b9", "borderHover": "#ababab", "borderFocus": "#babafa", - "selection": "#e7e8fe", - "selectionForeground": "#000000", + "selection": "#0a0a0a16", + "selectionForeground": "#0a0a0a", "focus": "#babafa", "focusRing": "#babafa47", "cursor": "#0a0a0a", - "hover": "#dbdbdb", - "active": "#dbdbdb" + "hover": "#0a0a0a0e", + "active": "#0a0a0a16" }, "status": { "error": "#ea1f40", @@ -64,12 +66,12 @@ "open": "#20e679", "draft": "#232323", "blocked": "#fbac7c", - "merged": "#d500f9", + "merged": "#00b0ff", "closed": "#ea1f40" }, "syntax": { "base": { - "background": "#e3e3e3", + "background": "#eaeaea", "foreground": "#0a0a0a", "comment": "#757575", "keyword": "#d500f9", @@ -82,24 +84,24 @@ }, "tokens": { "commentDoc": "#757575", - "stringEscape": "#6200ff", + "stringEscape": "#0a0a0a", "keywordImport": "#d500f9", "storageModifier": "#d500f9", "functionCall": "#ff9100", "method": "#ff9100", "variableProperty": "#ff9100", "variableOther": "#010101", - "variableGlobal": "#6200ff", - "variableLocal": "#232323", + "variableGlobal": "#00b0ff", + "variableLocal": "#0a0a0a", "parameter": "#010101", - "constant": "#6200ff", + "constant": "#00b0ff", "class": "#785110", "className": "#785110", "interface": "#785110", "struct": "#785110", "enum": "#785110", "typeParameter": "#785110", - "namespace": "#d500f9", + "namespace": "#785110", "module": "#d500f9", "tag": "#d500f9", "jsxTag": "#d500f9", @@ -107,12 +109,12 @@ "tagAttributeValue": "#00e676", "boolean": "#00b0ff", "decorator": "#d500f9", - "label": "#d500f9", + "label": "#ff9100", "punctuation": "#0a0a0a", "macro": "#d500f9", "preprocessor": "#d500f9", "regex": "#0a0a0a", - "url": "#580ce6", + "url": "#6209fd", "key": "#ff9100", "exception": "#ea1f40" }, @@ -123,35 +125,58 @@ "diffRemovedBackground": "#fffcfc", "diffModified": "#785110", "diffModifiedBackground": "#dddcea", - "lineNumber": "#3c3c3c", + "lineNumber": "#232323", "lineNumberActive": "#0a0a0a" } }, - "markdown": { - "heading1": "#580ce6", - "heading2": "#580ce6", - "heading3": "#0a0a0a", - "heading4": "#0a0a0a", - "link": "#580ce6", - "linkHover": "#13608a", - "inlineCode": "#126b37", - "inlineCodeBackground": "#e3e3e3", - "blockquote": "#785110", - "blockquoteBorder": "#b9b9b9", - "listMarker": "#580ce699" + "header": { + "background": "#f1f1f1", + "foreground": "#0a0a0a", + "border": "#b9b9b9", + "icon": "#232323", + "hover": "#0a0a0a0e" + }, + "sidebar": { + "background": "#e3e3e3", + "foreground": "#232323", + "border": "#b9b9b9", + "icon": "#232323", + "hover": "#0a0a0a0e", + "active": "#0a0a0a16", + "accent": "#6209fd", + "accentForeground": "#ffffff" }, "chat": { + "background": "#f1f1f1", "userMessage": "#0a0a0a", - "userMessageBackground": "#e7e8fe", + "userMessageBackground": "#eaeaea", "assistantMessage": "#0a0a0a", "assistantMessageBackground": "#f1f1f1", "timestamp": "#232323", - "divider": "#b9b9b9" + "divider": "#b9b9b9", + "typing": "#232323" + }, + "markdown": { + "heading1": "#6209fd", + "heading2": "#6209fd", + "heading3": "#0a0a0a", + "heading4": "#0a0a0a", + "link": "#6209fd", + "linkHover": "#5806e6", + "inlineCode": "#20e679", + "inlineCodeBackground": "#e3e3e3", + "blockquote": "#232323", + "blockquoteBorder": "#b9b9b9", + "listMarker": "#6209fd99", + "bold": "#0a0a0a", + "italic": "#232323", + "strikethrough": "#232323", + "hr": "#b9b9b9" }, "tools": { - "background": "#e3e3e380", - "border": "#b9b9b9b3", - "headerHover": "#dbdbdb80", + "background": "#e3e3e3", + "border": "#b9b9b9", + "headerHover": "#0a0a0a0e", "icon": "#232323", "title": "#0a0a0a", "description": "#232323", @@ -160,8 +185,224 @@ "addedBackground": "#f8fff9", "removed": "#ea1f40", "removedBackground": "#fffcfc", - "lineNumber": "#3c3c3c" + "modified": "#785110", + "modifiedBackground": "#dddcea", + "lineNumber": "#232323" + }, + "bash": { + "background": "#eaeaea", + "foreground": "#0a0a0a", + "info": "#7fcbfd", + "warning": "#fbac7c", + "error": "#ea1f40" + }, + "lsp": { + "background": "#eaeaea", + "foreground": "#0a0a0a", + "info": "#7fcbfd", + "warning": "#fbac7c", + "error": "#ea1f40" } + }, + "forms": { + "inputBackground": "#eaeaea", + "inputForeground": "#0a0a0a", + "inputBorder": "#b9b9b9", + "inputBorderHover": "#ababab", + "inputBorderFocus": "#babafa", + "inputPlaceholder": "#232323", + "inputDisabled": "#e3e3e3", + "inputSelection": "#0a0a0a16", + "label": "#232323", + "helperText": "#232323" + }, + "buttons": { + "primary": { + "bg": "#6209fd", + "fg": "#ffffff", + "border": "#6209fd", + "hover": "#5806e6", + "active": "#babafa", + "disabled": "#e3e3e3" + }, + "secondary": { + "bg": "#eaeaea", + "fg": "#0a0a0a", + "border": "#b9b9b9", + "hover": "#0a0a0a0e", + "active": "#0a0a0a16", + "disabled": "#e3e3e3" + }, + "ghost": { + "bg": "#00000000", + "fg": "#0a0a0a", + "border": "#00000000", + "hover": "#0a0a0a0e", + "active": "#0a0a0a16", + "disabled": "#232323" + }, + "destructive": { + "bg": "#ea1f40", + "fg": "#000000", + "border": "#fea6a4", + "hover": "#fee2e1", + "active": "#ea1f40", + "disabled": "#e3e3e3" + } + }, + "modal": { + "background": "#eaeaea", + "foreground": "#0a0a0a", + "border": "#b9b9b9", + "overlay": "#f1f1f13d" + }, + "popover": { + "background": "#eaeaea", + "foreground": "#0a0a0a", + "border": "#b9b9b9", + "shadow": "0 18px 48px rgba(15, 15, 15, 0.16)" + }, + "commandPalette": { + "background": "#eaeaea", + "foreground": "#0a0a0a", + "border": "#b9b9b9", + "inputBackground": "#eaeaea", + "selectedBackground": "#0a0a0a16", + "selectedForeground": "#0a0a0a", + "muted": "#232323" + }, + "fileAttachment": { + "background": "#e3e3e3", + "foreground": "#0a0a0a", + "border": "#b9b9b9", + "icon": "#232323", + "removeHover": "#fee2e1" + }, + "sessions": { + "background": "#f1f1f1", + "foreground": "#0a0a0a", + "mutedForeground": "#232323", + "border": "#b9b9b9", + "hover": "#0a0a0a0e", + "active": "#0a0a0a16" + }, + "modelSelector": { + "background": "#eaeaea", + "foreground": "#0a0a0a", + "border": "#b9b9b9", + "selectedBackground": "#0a0a0a16", + "selectedForeground": "#0a0a0a" + }, + "permissions": { + "background": "#eaeaea", + "foreground": "#0a0a0a", + "border": "#b9b9b9", + "allow": "#20e679", + "allowBackground": "#b4ffc7", + "deny": "#ea1f40", + "denyBackground": "#fee2e1" + }, + "loading": { + "spinner": "#6209fd", + "spinnerTrack": "#e3e3e3", + "skeleton": "#e3e3e3", + "shimmer": "#0a0a0a0e" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#0a0a0a26", + "thumbHover": "#0a0a0a40" + }, + "badges": { + "default": { + "bg": "#e3e3e3", + "fg": "#0a0a0a", + "border": "#b9b9b9" + }, + "info": { + "bg": "#d8edfd", + "fg": "#7fcbfd", + "border": "#7fcbfd" + }, + "success": { + "bg": "#b4ffc7", + "fg": "#20e679", + "border": "#20e679" + }, + "warning": { + "bg": "#ffe6c6", + "fg": "#fbac7c", + "border": "#fab141" + }, + "error": { + "bg": "#fee2e1", + "fg": "#ea1f40", + "border": "#fea6a4" + } + }, + "toast": { + "background": "#eaeaea", + "foreground": "#0a0a0a", + "border": "#b9b9b9", + "success": { + "background": "#b4ffc7", + "foreground": "#20e679", + "border": "#20e679" + }, + "warning": { + "background": "#ffe6c6", + "foreground": "#fbac7c", + "border": "#fab141" + }, + "error": { + "background": "#fee2e1", + "foreground": "#ea1f40", + "border": "#fea6a4" + }, + "info": { + "background": "#d8edfd", + "foreground": "#7fcbfd", + "border": "#7fcbfd" + } + }, + "emptyState": { + "icon": "#232323", + "title": "#0a0a0a", + "description": "#232323", + "border": "#b9b9b9" + }, + "table": { + "border": "#b9b9b9", + "headerBackground": "#eaeaea", + "headerForeground": "#0a0a0a", + "rowHover": "#0a0a0a0e", + "rowSelected": "#0a0a0a16" + }, + "charts": { + "series": [ + "#6209fd", + "#7fcbfd", + "#20e679", + "#fbac7c", + "#ea1f40" + ] + }, + "a11y": { + "focusRing": "#babafa", + "selection": "#0a0a0a16", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(15, 15, 15, 0.08)", + "md": "0 12px 32px rgba(15, 15, 15, 0.12)", + "lg": "0 24px 56px rgba(15, 15, 15, 0.16)", + "focus": "0 0 0 3px #babafa40" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/cursor-dark.json b/packages/ui/src/lib/theme/themes/cursor-dark.json index 37e55941..43179397 100644 --- a/packages/ui/src/lib/theme/themes/cursor-dark.json +++ b/packages/ui/src/lib/theme/themes/cursor-dark.json @@ -2,79 +2,81 @@ "metadata": { "id": "cursor-dark", "name": "Cursor", - "description": "Port of OpenCode Cursor theme (dark variant)", + "description": "Ported from OpenCode Cursor theme (dark variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "dark", "tags": [ "dark", "opencode", + "ported", "cursor" ] }, "colors": { "primary": { - "base": "#369ab3", + "base": "#88c0d0", "hover": "#41aac5", - "active": "#41aac5", + "active": "#1aaaa6", "foreground": "#000000", - "muted": "#369ab380", - "emphasis": "#41aac5" + "muted": "#88c0d080", + "emphasis": "#54eee9" }, "surface": { "background": "#0e0e0e", "foreground": "#e4e4e4", - "muted": "#1c1c1c", + "muted": "#141414", "mutedForeground": "#e4e4e45e", "elevated": "#161616", "elevatedForeground": "#e4e4e4", - "overlay": "#00000080", + "overlay": "#0e0e0ecc", "subtle": "#232323" }, "interactive": { "border": "#464646", "borderHover": "#4f4f4f", - "borderFocus": "#044c4a", - "selection": "#003735", - "selectionForeground": "#ffffff", - "focus": "#044c4a", - "focusRing": "#044c4a59", - "cursor": "#e4e4e4", - "hover": "#232323", - "active": "#232323" + "borderFocus": "#1aaaa6", + "selection": "#e4e4e41f", + "selectionForeground": "#e4e4e4", + "focus": "#1aaaa6", + "focusRing": "#1aaaa661", + "cursor": "#fcfcfc", + "hover": "#e4e4e417", + "active": "#e4e4e41f" }, "status": { - "error": "#c21a55", - "errorForeground": "#ffffff", + "error": "#e34671", + "errorForeground": "#151313", "errorBackground": "#5a0523", "errorBorder": "#7a0e33", - "warning": "#ca6803", - "warningForeground": "#ffffff", + "warning": "#f1b467", + "warningForeground": "#151313", "warningBackground": "#422902", "warningBorder": "#5b3a07", - "success": "#078146", - "successForeground": "#ffffff", + "success": "#3fa266", + "successForeground": "#151313", "successBackground": "#00391c", "successBorder": "#045029", - "info": "#4b7dad", - "infoForeground": "#ffffff", + "info": "#81a1c1", + "infoForeground": "#151313", "infoBackground": "#093152", "infoBorder": "#1a446a" }, "pr": { - "open": "#078146", + "open": "#3fa266", "draft": "#e4e4e45e", - "blocked": "#ca6803", - "merged": "#82D2CE", - "closed": "#c21a55" + "blocked": "#f1b467", + "merged": "#F8C762", + "closed": "#e34671" }, "syntax": { "base": { - "background": "#1c1c1c", + "background": "#161616", "foreground": "#e4e4e4", "comment": "#e4e4e45e", "keyword": "#82D2CE", "string": "#E394DC", - "number": "#EFB080", + "number": "#F8C762", "function": "#81a1c1", "variable": "#e4e4e4", "type": "#EFB080", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#e4e4e45e", - "stringEscape": "#F8C762", + "stringEscape": "#e4e4e4", "keywordImport": "#82D2CE", "storageModifier": "#82D2CE", "functionCall": "#81a1c1", @@ -90,7 +92,7 @@ "variableProperty": "#81a1c1", "variableOther": "#e4e4e4", "variableGlobal": "#F8C762", - "variableLocal": "#e4e4e45e", + "variableLocal": "#e4e4e4", "parameter": "#e4e4e4", "constant": "#F8C762", "class": "#EFB080", @@ -99,38 +101,65 @@ "struct": "#EFB080", "enum": "#EFB080", "typeParameter": "#EFB080", - "namespace": "#82D2CE", + "namespace": "#EFB080", "module": "#82D2CE", "tag": "#82D2CE", "jsxTag": "#82D2CE", "tagAttribute": "#81a1c1", "tagAttributeValue": "#E394DC", - "boolean": "#EFB080", + "boolean": "#F8C762", "decorator": "#82D2CE", - "label": "#82D2CE", + "label": "#81a1c1", "punctuation": "#e4e4e4", "macro": "#82D2CE", "preprocessor": "#82D2CE", "regex": "#e4e4e4", - "url": "#82D2CE", + "url": "#54eee9", "key": "#81a1c1", - "exception": "#c21a55" + "exception": "#e34671" }, "highlights": { "diffAdded": "#75f1a8", - "diffAddedBackground": "#011307", - "diffRemoved": "#f72661", - "diffRemovedBackground": "#240007", + "diffAddedBackground": "#021c0d", + "diffRemoved": "#fcc3c8", + "diffRemovedBackground": "#31010c", "diffModified": "#fdd8ac", - "diffModifiedBackground": "#29302f", + "diffModifiedBackground": "#1a1d1d", "lineNumber": "#bdbdbd", "lineNumberActive": "#e4e4e4" } }, + "header": { + "background": "#0e0e0e", + "foreground": "#e4e4e4", + "border": "#464646", + "icon": "#909090", + "hover": "#232323" + }, + "sidebar": { + "background": "#141414", + "foreground": "#e4e4e45e", + "border": "#464646", + "icon": "#272727", + "hover": "#232323", + "active": "#003735", + "accent": "#88c0d0", + "accentForeground": "#000000" + }, + "chat": { + "background": "#0e0e0e", + "userMessage": "#e4e4e4", + "userMessageBackground": "#1c1c1c", + "assistantMessage": "#e4e4e4", + "assistantMessageBackground": "#0e0e0e", + "timestamp": "#bdbdbd", + "divider": "#353535", + "typing": "#e4e4e45e" + }, "markdown": { "heading1": "#AAA0FA", "heading2": "#AAA0FA", - "heading3": "#e4e4e4", + "heading3": "#fcfcfc", "heading4": "#e4e4e4", "link": "#82D2CE", "linkHover": "#81a1c1", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#1c1c1c", "blockquote": "#e4e4e45e", "blockquoteBorder": "#464646", - "listMarker": "#e4e4e499" - }, - "chat": { - "userMessage": "#e4e4e4", - "userMessageBackground": "#003735", - "assistantMessage": "#e4e4e4", - "assistantMessageBackground": "#0e0e0e", - "timestamp": "#e4e4e45e", - "divider": "#464646" + "listMarker": "#e4e4e499", + "bold": "#F8C762", + "italic": "#82D2CE", + "strikethrough": "#e4e4e45e", + "hr": "#e4e4e45e" }, "tools": { - "background": "#1c1c1c80", - "border": "#464646b3", - "headerHover": "#23232380", - "icon": "#e4e4e45e", + "background": "#1c1c1c", + "border": "#353535", + "headerHover": "#232323", + "icon": "#272727", "title": "#e4e4e4", "description": "#e4e4e45e", "edit": { "added": "#75f1a8", - "addedBackground": "#011307", + "addedBackground": "#021c0d", "removed": "#f72661", - "removedBackground": "#240007", + "removedBackground": "#31010c", + "modified": "#fdd8ac", + "modifiedBackground": "#1a1d1d", "lineNumber": "#bdbdbd" + }, + "bash": { + "background": "#161616", + "foreground": "#e4e4e4", + "info": "#81a1c1", + "warning": "#f1b467", + "error": "#e34671" + }, + "lsp": { + "background": "#161616", + "foreground": "#e4e4e4", + "info": "#81a1c1", + "warning": "#f1b467", + "error": "#e34671" } + }, + "forms": { + "inputBackground": "#111111", + "inputForeground": "#e4e4e4", + "inputBorder": "#353535", + "inputBorderHover": "#3e3e3e", + "inputBorderFocus": "#1aaaa6", + "inputPlaceholder": "#bdbdbd", + "inputDisabled": "#191919", + "inputSelection": "#0e6865", + "label": "#e4e4e45e", + "helperText": "#bdbdbd" + }, + "buttons": { + "primary": { + "bg": "#88c0d0", + "fg": "#000000", + "border": "#044c4a", + "hover": "#41aac5", + "active": "#1aaaa6", + "disabled": "#3e3e3e" + }, + "secondary": { + "bg": "#161616", + "fg": "#e4e4e4", + "border": "#464646", + "hover": "#1c1c1c", + "active": "#232323", + "disabled": "#191919" + }, + "ghost": { + "bg": "#00000000", + "fg": "#e4e4e4", + "border": "#00000000", + "hover": "#1c1c1c", + "active": "#232323", + "disabled": "#bdbdbd" + }, + "destructive": { + "bg": "#e34671", + "fg": "#151313", + "border": "#7a0e33", + "hover": "#7a0e33", + "active": "#c21a55", + "disabled": "#191919" + } + }, + "modal": { + "background": "#161616", + "foreground": "#e4e4e4", + "border": "#464646", + "overlay": "#0e0e0ed6" + }, + "popover": { + "background": "#161616", + "foreground": "#e4e4e4", + "border": "#464646", + "shadow": "0 18px 48px rgba(0, 0, 0, 0.45)" + }, + "commandPalette": { + "background": "#161616", + "foreground": "#e4e4e4", + "border": "#464646", + "inputBackground": "#111111", + "selectedBackground": "#003735", + "selectedForeground": "#e4e4e4", + "muted": "#e4e4e45e" + }, + "fileAttachment": { + "background": "#1c1c1c", + "foreground": "#e4e4e4", + "border": "#353535", + "icon": "#272727", + "removeHover": "#5a0523" + }, + "sessions": { + "background": "#0e0e0e", + "foreground": "#e4e4e4", + "mutedForeground": "#e4e4e45e", + "border": "#2d2d2d", + "hover": "#232323", + "active": "#003735" + }, + "modelSelector": { + "background": "#161616", + "foreground": "#e4e4e4", + "border": "#464646", + "selectedBackground": "#003735", + "selectedForeground": "#e4e4e4" + }, + "permissions": { + "background": "#161616", + "foreground": "#e4e4e4", + "border": "#464646", + "allow": "#3fa266", + "allowBackground": "#00391c", + "deny": "#e34671", + "denyBackground": "#5a0523" + }, + "loading": { + "spinner": "#88c0d0", + "spinnerTrack": "#232323", + "skeleton": "#1c1c1c", + "shimmer": "#232323" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#e4e4e433", + "thumbHover": "#e4e4e457" + }, + "badges": { + "default": { + "bg": "#1c1c1c", + "fg": "#e4e4e4", + "border": "#353535" + }, + "info": { + "bg": "#093152", + "fg": "#81a1c1", + "border": "#1a446a" + }, + "success": { + "bg": "#00391c", + "fg": "#3fa266", + "border": "#045029" + }, + "warning": { + "bg": "#422902", + "fg": "#f1b467", + "border": "#5b3a07" + }, + "error": { + "bg": "#5a0523", + "fg": "#e34671", + "border": "#7a0e33" + } + }, + "toast": { + "background": "#161616", + "foreground": "#e4e4e4", + "border": "#464646", + "success": { + "background": "#00391c", + "foreground": "#3fa266", + "border": "#045029" + }, + "warning": { + "background": "#422902", + "foreground": "#f1b467", + "border": "#5b3a07" + }, + "error": { + "background": "#5a0523", + "foreground": "#e34671", + "border": "#7a0e33" + }, + "info": { + "background": "#093152", + "foreground": "#81a1c1", + "border": "#1a446a" + } + }, + "emptyState": { + "icon": "#e4e4e45e", + "title": "#e4e4e4", + "description": "#e4e4e45e", + "border": "#2d2d2d" + }, + "table": { + "border": "#2d2d2d", + "headerBackground": "#161616", + "headerForeground": "#e4e4e4", + "rowHover": "#232323", + "rowSelected": "#003735" + }, + "charts": { + "series": [ + "#88c0d0", + "#81a1c1", + "#3fa266", + "#f1b467", + "#e34671" + ] + }, + "a11y": { + "focusRing": "#1aaaa6", + "selection": "#003735", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(0, 0, 0, 0.22)", + "md": "0 12px 32px rgba(0, 0, 0, 0.32)", + "lg": "0 24px 56px rgba(0, 0, 0, 0.42)", + "focus": "0 0 0 3px #82D2CE59" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/cursor-light.json b/packages/ui/src/lib/theme/themes/cursor-light.json index 377f2038..785ec756 100644 --- a/packages/ui/src/lib/theme/themes/cursor-light.json +++ b/packages/ui/src/lib/theme/themes/cursor-light.json @@ -2,79 +2,81 @@ "metadata": { "id": "cursor-light", "name": "Cursor", - "description": "Port of OpenCode Cursor theme (light variant)", + "description": "Ported from OpenCode Cursor theme (light variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "light", "tags": [ "light", "opencode", + "ported", "cursor" ] }, "colors": { "primary": { - "base": "#659daa", + "base": "#6f9ba6", "hover": "#5992a0", - "active": "#5992a0", + "active": "#12659a", "foreground": "#000000", - "muted": "#659daa80", - "emphasis": "#5992a0" + "muted": "#6f9ba680", + "emphasis": "#0e5b8b" }, "surface": { "background": "#fcfcfc", "foreground": "#131313", - "muted": "#eeeeee", + "muted": "#f1f1f1", "mutedForeground": "#141414ad", "elevated": "#f5f5f5", "elevatedForeground": "#131313", - "overlay": "#0000004d", + "overlay": "#fcfcfc33", "subtle": "#e5e5e5" }, "interactive": { "border": "#c3c3c3", "borderHover": "#b5b5b5", - "borderFocus": "#88c9fd", - "selection": "#daedfd", - "selectionForeground": "#000000", - "focus": "#88c9fd", - "focusRing": "#88c9fd47", - "cursor": "#131313", - "hover": "#e5e5e5", - "active": "#e5e5e5" + "borderFocus": "#12659a", + "selection": "#13131316", + "selectionForeground": "#131313", + "focus": "#12659a", + "focusRing": "#12659a47", + "cursor": "#050505", + "hover": "#1313130e", + "active": "#13131316" }, "status": { - "error": "#c4174b", - "errorForeground": "#000000", + "error": "#cf2d56", + "errorForeground": "#ffffff", "errorBackground": "#fee2e4", "errorBorder": "#fba6af", - "warning": "#ffa5a8", + "warning": "#db704b", "warningForeground": "#000000", "warningBackground": "#fde4db", "warningBorder": "#faab90", - "success": "#6fdaad", + "success": "#1f8a65", "successForeground": "#000000", "successBackground": "#bbfadd", "successBorder": "#6fdaad", - "info": "#8ac9fa", + "info": "#3c7cab", "infoForeground": "#000000", "infoBackground": "#d8edfe", "infoBorder": "#8ac9fa" }, "pr": { - "open": "#6fdaad", + "open": "#1f8a65", "draft": "#141414ad", - "blocked": "#ffa5a8", - "merged": "#b3003f", - "closed": "#c4174b" + "blocked": "#db704b", + "merged": "#b8448b", + "closed": "#cf2d56" }, "syntax": { "base": { - "background": "#eeeeee", + "background": "#f5f5f5", "foreground": "#131313", "comment": "#141414ad", "keyword": "#b3003f", "string": "#9e94d5", - "number": "#db704b", + "number": "#b8448b", "function": "#141414ad", "variable": "#141414", "type": "#206595", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#141414ad", - "stringEscape": "#b8448b", + "stringEscape": "#131313", "keywordImport": "#b3003f", "storageModifier": "#b3003f", "functionCall": "#141414ad", @@ -90,7 +92,7 @@ "variableProperty": "#141414ad", "variableOther": "#141414", "variableGlobal": "#b8448b", - "variableLocal": "#141414ad", + "variableLocal": "#141414", "parameter": "#141414", "constant": "#b8448b", "class": "#206595", @@ -99,38 +101,65 @@ "struct": "#206595", "enum": "#206595", "typeParameter": "#206595", - "namespace": "#b3003f", + "namespace": "#206595", "module": "#b3003f", "tag": "#b3003f", "jsxTag": "#b3003f", "tagAttribute": "#141414ad", "tagAttributeValue": "#9e94d5", - "boolean": "#db704b", + "boolean": "#b8448b", "decorator": "#b3003f", - "label": "#b3003f", + "label": "#141414ad", "punctuation": "#141414", "macro": "#b3003f", "preprocessor": "#b3003f", "regex": "#131313", - "url": "#206595", + "url": "#0e5b8b", "key": "#141414ad", - "exception": "#c4174b" + "exception": "#cf2d56" }, "highlights": { "diffAdded": "#0c7251", - "diffAddedBackground": "#f7fffb", - "diffRemoved": "#ec3766", - "diffRemovedBackground": "#fffcfc", + "diffAddedBackground": "#ecfff5", + "diffRemoved": "#ae1945", + "diffRemovedBackground": "#fef7f8", "diffModified": "#FF8C00", - "diffModifiedBackground": "#e3e7eb", + "diffModifiedBackground": "#f0f2f3", "lineNumber": "#313131", "lineNumberActive": "#131313" } }, + "header": { + "background": "#fcfcfc", + "foreground": "#131313", + "border": "#c3c3c3", + "icon": "#2d2d2d", + "hover": "#e5e5e5" + }, + "sidebar": { + "background": "#f1f1f1", + "foreground": "#141414ad", + "border": "#c3c3c3", + "icon": "#c5c5c5", + "hover": "#e5e5e5", + "active": "#daedfd", + "accent": "#6f9ba6", + "accentForeground": "#000000" + }, + "chat": { + "background": "#fcfcfc", + "userMessage": "#131313", + "userMessageBackground": "#eeeeee", + "assistantMessage": "#131313", + "assistantMessageBackground": "#fcfcfc", + "timestamp": "#313131", + "divider": "#dfdfdf", + "typing": "#141414ad" + }, "markdown": { "heading1": "#206595", "heading2": "#206595", - "heading3": "#131313", + "heading3": "#050505", "heading4": "#131313", "link": "#206595", "linkHover": "#141414ad", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#eeeeee", "blockquote": "#141414ad", "blockquoteBorder": "#c3c3c3", - "listMarker": "#14141499" - }, - "chat": { - "userMessage": "#131313", - "userMessageBackground": "#daedfd", - "assistantMessage": "#131313", - "assistantMessageBackground": "#fcfcfc", - "timestamp": "#141414ad", - "divider": "#c3c3c3" + "listMarker": "#14141499", + "bold": "#141414", + "italic": "#141414", + "strikethrough": "#141414ad", + "hr": "#141414ad" }, "tools": { - "background": "#eeeeee80", - "border": "#c3c3c3b3", - "headerHover": "#e5e5e580", - "icon": "#141414ad", + "background": "#eeeeee", + "border": "#dfdfdf", + "headerHover": "#e5e5e5", + "icon": "#c5c5c5", "title": "#131313", "description": "#141414ad", "edit": { "added": "#0c7251", - "addedBackground": "#f7fffb", + "addedBackground": "#ecfff5", "removed": "#ec3766", - "removedBackground": "#fffcfc", + "removedBackground": "#fef7f8", + "modified": "#FF8C00", + "modifiedBackground": "#f0f2f3", "lineNumber": "#313131" + }, + "bash": { + "background": "#f5f5f5", + "foreground": "#131313", + "info": "#3c7cab", + "warning": "#db704b", + "error": "#cf2d56" + }, + "lsp": { + "background": "#f5f5f5", + "foreground": "#131313", + "info": "#3c7cab", + "warning": "#db704b", + "error": "#cf2d56" } + }, + "forms": { + "inputBackground": "#fcfcfc", + "inputForeground": "#131313", + "inputBorder": "#dfdfdf", + "inputBorderHover": "#d1d1d1", + "inputBorderFocus": "#12659a", + "inputPlaceholder": "#313131", + "inputDisabled": "#eaeaea", + "inputSelection": "#daedfd", + "label": "#141414ad", + "helperText": "#313131" + }, + "buttons": { + "primary": { + "bg": "#6f9ba6", + "fg": "#000000", + "border": "#88c9fd", + "hover": "#5992a0", + "active": "#12659a", + "disabled": "#cdcdcd" + }, + "secondary": { + "bg": "#f5f5f5", + "fg": "#131313", + "border": "#c3c3c3", + "hover": "#eeeeee", + "active": "#e5e5e5", + "disabled": "#eaeaea" + }, + "ghost": { + "bg": "#00000000", + "fg": "#131313", + "border": "#00000000", + "hover": "#eeeeee", + "active": "#e5e5e5", + "disabled": "#313131" + }, + "destructive": { + "bg": "#cf2d56", + "fg": "#ffffff", + "border": "#fba6af", + "hover": "#fdd4d8", + "active": "#d61853", + "disabled": "#eaeaea" + } + }, + "modal": { + "background": "#f5f5f5", + "foreground": "#131313", + "border": "#c3c3c3", + "overlay": "#fcfcfc3d" + }, + "popover": { + "background": "#f5f5f5", + "foreground": "#131313", + "border": "#c3c3c3", + "shadow": "0 18px 48px rgba(15, 15, 15, 0.16)" + }, + "commandPalette": { + "background": "#f5f5f5", + "foreground": "#131313", + "border": "#c3c3c3", + "inputBackground": "#fcfcfc", + "selectedBackground": "#daedfd", + "selectedForeground": "#131313", + "muted": "#141414ad" + }, + "fileAttachment": { + "background": "#eeeeee", + "foreground": "#131313", + "border": "#dfdfdf", + "icon": "#c5c5c5", + "removeHover": "#fee2e4" + }, + "sessions": { + "background": "#fcfcfc", + "foreground": "#131313", + "mutedForeground": "#141414ad", + "border": "#e9e9e9", + "hover": "#e5e5e5", + "active": "#daedfd" + }, + "modelSelector": { + "background": "#f5f5f5", + "foreground": "#131313", + "border": "#c3c3c3", + "selectedBackground": "#daedfd", + "selectedForeground": "#131313" + }, + "permissions": { + "background": "#f5f5f5", + "foreground": "#131313", + "border": "#c3c3c3", + "allow": "#1f8a65", + "allowBackground": "#bbfadd", + "deny": "#cf2d56", + "denyBackground": "#fee2e4" + }, + "loading": { + "spinner": "#6f9ba6", + "spinnerTrack": "#e5e5e5", + "skeleton": "#eeeeee", + "shimmer": "#e5e5e5" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#13131326", + "thumbHover": "#13131340" + }, + "badges": { + "default": { + "bg": "#eeeeee", + "fg": "#131313", + "border": "#dfdfdf" + }, + "info": { + "bg": "#d8edfe", + "fg": "#3c7cab", + "border": "#8ac9fa" + }, + "success": { + "bg": "#bbfadd", + "fg": "#1f8a65", + "border": "#6fdaad" + }, + "warning": { + "bg": "#fde4db", + "fg": "#db704b", + "border": "#faab90" + }, + "error": { + "bg": "#fee2e4", + "fg": "#cf2d56", + "border": "#fba6af" + } + }, + "toast": { + "background": "#f5f5f5", + "foreground": "#131313", + "border": "#c3c3c3", + "success": { + "background": "#bbfadd", + "foreground": "#1f8a65", + "border": "#6fdaad" + }, + "warning": { + "background": "#fde4db", + "foreground": "#db704b", + "border": "#faab90" + }, + "error": { + "background": "#fee2e4", + "foreground": "#cf2d56", + "border": "#fba6af" + }, + "info": { + "background": "#d8edfe", + "foreground": "#3c7cab", + "border": "#8ac9fa" + } + }, + "emptyState": { + "icon": "#141414ad", + "title": "#131313", + "description": "#141414ad", + "border": "#e9e9e9" + }, + "table": { + "border": "#e9e9e9", + "headerBackground": "#f5f5f5", + "headerForeground": "#131313", + "rowHover": "#e5e5e5", + "rowSelected": "#daedfd" + }, + "charts": { + "series": [ + "#6f9ba6", + "#3c7cab", + "#1f8a65", + "#db704b", + "#cf2d56" + ] + }, + "a11y": { + "focusRing": "#12659a", + "selection": "#daedfd", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(15, 15, 15, 0.08)", + "md": "0 12px 32px rgba(15, 15, 15, 0.12)", + "lg": "0 24px 56px rgba(15, 15, 15, 0.16)", + "focus": "0 0 0 3px #20659540" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/github-dark.json b/packages/ui/src/lib/theme/themes/github-dark.json index 30f8b3c0..c7d2e335 100644 --- a/packages/ui/src/lib/theme/themes/github-dark.json +++ b/packages/ui/src/lib/theme/themes/github-dark.json @@ -2,79 +2,81 @@ "metadata": { "id": "github-dark", "name": "GitHub", - "description": "Port of OpenCode GitHub theme (dark variant)", + "description": "Ported from OpenCode GitHub theme (dark variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "dark", "tags": [ "dark", "opencode", + "ported", "github" ] }, "colors": { "primary": { - "base": "#197de0", + "base": "#58a6ff", "hover": "#238cf5", - "active": "#238cf5", + "active": "#197de0", "foreground": "#000000", - "muted": "#197de080", - "emphasis": "#238cf5" + "muted": "#58a6ff80", + "emphasis": "#b7d7fd" }, "surface": { "background": "#05080e", "foreground": "#ccd4dc", - "muted": "#12151b", + "muted": "#0a0e14", "mutedForeground": "#8b949e", "elevated": "#0c0f16", "elevatedForeground": "#ccd4dc", - "overlay": "#00000080", + "overlay": "#05080ecc", "subtle": "#181c22" }, "interactive": { "border": "#393d44", "borderHover": "#41454c", - "borderFocus": "#09427a", - "selection": "#032f5a", - "selectionForeground": "#ffffff", - "focus": "#09427a", - "focusRing": "#09427a59", - "cursor": "#ccd4dc", - "hover": "#181c22", - "active": "#181c22" + "borderFocus": "#197de0", + "selection": "#ccd4dc1f", + "selectionForeground": "#ccd4dc", + "focus": "#197de0", + "focusRing": "#197de061", + "cursor": "#fafbfc", + "hover": "#ccd4dc17", + "active": "#ccd4dc1f" }, "status": { - "error": "#d01d21", - "errorForeground": "#ffffff", + "error": "#f85149", + "errorForeground": "#151313", "errorBackground": "#5e0206", "errorBorder": "#7e080d", - "warning": "#b37002", - "warningForeground": "#ffffff", + "warning": "#e3b341", + "warningForeground": "#151313", "warningBackground": "#3c2c02", "warningBorder": "#533e07", - "success": "#1a9132", - "successForeground": "#ffffff", + "success": "#3fb950", + "successForeground": "#151313", "successBackground": "#063a10", "successBorder": "#0f501a", - "info": "#a27516", - "infoForeground": "#ffffff", + "info": "#d29922", + "infoForeground": "#151313", "infoBackground": "#3f2b02", "infoBorder": "#563d07" }, "pr": { - "open": "#1a9132", + "open": "#3fb950", "draft": "#8b949e", - "blocked": "#b37002", - "merged": "#ff7b72", - "closed": "#d01d21" + "blocked": "#e3b341", + "merged": "#58a6ff", + "closed": "#f85149" }, "syntax": { "base": { - "background": "#12151b", + "background": "#0c0f16", "foreground": "#ccd4dc", "comment": "#8b949e", "keyword": "#ff7b72", "string": "#39c5cf", - "number": "#bc8cff", + "number": "#58a6ff", "function": "#39c5cf", "variable": "#d29922", "type": "#d29922", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#8b949e", - "stringEscape": "#58a6ff", + "stringEscape": "#ccd4dc", "keywordImport": "#ff7b72", "storageModifier": "#ff7b72", "functionCall": "#39c5cf", @@ -90,7 +92,7 @@ "variableProperty": "#39c5cf", "variableOther": "#d29922", "variableGlobal": "#58a6ff", - "variableLocal": "#8b949e", + "variableLocal": "#c9d1d9", "parameter": "#d29922", "constant": "#58a6ff", "class": "#d29922", @@ -99,38 +101,65 @@ "struct": "#d29922", "enum": "#d29922", "typeParameter": "#d29922", - "namespace": "#ff7b72", + "namespace": "#d29922", "module": "#ff7b72", "tag": "#ff7b72", "jsxTag": "#ff7b72", "tagAttribute": "#39c5cf", "tagAttributeValue": "#39c5cf", - "boolean": "#bc8cff", + "boolean": "#58a6ff", "decorator": "#ff7b72", - "label": "#ff7b72", + "label": "#39c5cf", "punctuation": "#c9d1d9", "macro": "#ff7b72", "preprocessor": "#ff7b72", "regex": "#ccd4dc", - "url": "#58a6ff", + "url": "#b7d7fd", "key": "#39c5cf", - "exception": "#d01d21" + "exception": "#f85149" }, "highlights": { "diffAdded": "#6af679", - "diffAddedBackground": "#011403", - "diffRemoved": "#f5031c", - "diffRemovedBackground": "#240202", + "diffAddedBackground": "#001d03", + "diffRemoved": "#fec3bb", + "diffRemovedBackground": "#330001", "diffModified": "#fdda8e", - "diffModifiedBackground": "#1b2432", + "diffModifiedBackground": "#0f151e", "lineNumber": "#6a7077", "lineNumberActive": "#ccd4dc" } }, + "header": { + "background": "#05080e", + "foreground": "#ccd4dc", + "border": "#393d44", + "icon": "#7b828a", + "hover": "#181c22" + }, + "sidebar": { + "background": "#0a0e14", + "foreground": "#8b949e", + "border": "#393d44", + "icon": "#1a1f26", + "hover": "#181c22", + "active": "#032f5a", + "accent": "#58a6ff", + "accentForeground": "#000000" + }, + "chat": { + "background": "#05080e", + "userMessage": "#ccd4dc", + "userMessageBackground": "#12151b", + "assistantMessage": "#ccd4dc", + "assistantMessageBackground": "#05080e", + "timestamp": "#6a7077", + "divider": "#292d33", + "typing": "#8b949e" + }, "markdown": { "heading1": "#58a6ff", "heading2": "#58a6ff", - "heading3": "#ccd4dc", + "heading3": "#fafbfc", "heading4": "#ccd4dc", "link": "#58a6ff", "linkHover": "#39c5cf", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#12151b", "blockquote": "#8b949e", "blockquoteBorder": "#393d44", - "listMarker": "#58a6ff99" - }, - "chat": { - "userMessage": "#ccd4dc", - "userMessageBackground": "#032f5a", - "assistantMessage": "#ccd4dc", - "assistantMessageBackground": "#05080e", - "timestamp": "#8b949e", - "divider": "#393d44" + "listMarker": "#58a6ff99", + "bold": "#d29922", + "italic": "#e3b341", + "strikethrough": "#8b949e", + "hr": "#30363d" }, "tools": { - "background": "#12151b80", - "border": "#393d44b3", - "headerHover": "#181c2280", - "icon": "#8b949e", + "background": "#12151b", + "border": "#292d33", + "headerHover": "#181c22", + "icon": "#1a1f26", "title": "#ccd4dc", "description": "#8b949e", "edit": { "added": "#6af679", - "addedBackground": "#011403", + "addedBackground": "#001d03", "removed": "#f5031c", - "removedBackground": "#240202", + "removedBackground": "#330001", + "modified": "#fdda8e", + "modifiedBackground": "#0f151e", "lineNumber": "#6a7077" + }, + "bash": { + "background": "#0c0f16", + "foreground": "#ccd4dc", + "info": "#d29922", + "warning": "#e3b341", + "error": "#f85149" + }, + "lsp": { + "background": "#0c0f16", + "foreground": "#ccd4dc", + "info": "#d29922", + "warning": "#e3b341", + "error": "#f85149" } + }, + "forms": { + "inputBackground": "#070b11", + "inputForeground": "#ccd4dc", + "inputBorder": "#292d33", + "inputBorderHover": "#31353b", + "inputBorderFocus": "#197de0", + "inputPlaceholder": "#6a7077", + "inputDisabled": "#0d1218", + "inputSelection": "#145ba2", + "label": "#8b949e", + "helperText": "#6a7077" + }, + "buttons": { + "primary": { + "bg": "#58a6ff", + "fg": "#000000", + "border": "#09427a", + "hover": "#238cf5", + "active": "#197de0", + "disabled": "#31353b" + }, + "secondary": { + "bg": "#0c0f16", + "fg": "#ccd4dc", + "border": "#393d44", + "hover": "#12151b", + "active": "#181c22", + "disabled": "#0d1218" + }, + "ghost": { + "bg": "#00000000", + "fg": "#ccd4dc", + "border": "#00000000", + "hover": "#12151b", + "active": "#181c22", + "disabled": "#6a7077" + }, + "destructive": { + "bg": "#f85149", + "fg": "#151313", + "border": "#7e080d", + "hover": "#7e080d", + "active": "#d01d21", + "disabled": "#0d1218" + } + }, + "modal": { + "background": "#0c0f16", + "foreground": "#ccd4dc", + "border": "#393d44", + "overlay": "#05080ed6" + }, + "popover": { + "background": "#0c0f16", + "foreground": "#ccd4dc", + "border": "#393d44", + "shadow": "0 18px 48px rgba(0, 0, 0, 0.45)" + }, + "commandPalette": { + "background": "#0c0f16", + "foreground": "#ccd4dc", + "border": "#393d44", + "inputBackground": "#070b11", + "selectedBackground": "#032f5a", + "selectedForeground": "#ccd4dc", + "muted": "#8b949e" + }, + "fileAttachment": { + "background": "#12151b", + "foreground": "#ccd4dc", + "border": "#292d33", + "icon": "#1a1f26", + "removeHover": "#5e0206" + }, + "sessions": { + "background": "#05080e", + "foreground": "#ccd4dc", + "mutedForeground": "#8b949e", + "border": "#21252b", + "hover": "#181c22", + "active": "#032f5a" + }, + "modelSelector": { + "background": "#0c0f16", + "foreground": "#ccd4dc", + "border": "#393d44", + "selectedBackground": "#032f5a", + "selectedForeground": "#ccd4dc" + }, + "permissions": { + "background": "#0c0f16", + "foreground": "#ccd4dc", + "border": "#393d44", + "allow": "#3fb950", + "allowBackground": "#063a10", + "deny": "#f85149", + "denyBackground": "#5e0206" + }, + "loading": { + "spinner": "#58a6ff", + "spinnerTrack": "#181c22", + "skeleton": "#12151b", + "shimmer": "#181c22" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#ccd4dc33", + "thumbHover": "#ccd4dc57" + }, + "badges": { + "default": { + "bg": "#12151b", + "fg": "#ccd4dc", + "border": "#292d33" + }, + "info": { + "bg": "#3f2b02", + "fg": "#d29922", + "border": "#563d07" + }, + "success": { + "bg": "#063a10", + "fg": "#3fb950", + "border": "#0f501a" + }, + "warning": { + "bg": "#3c2c02", + "fg": "#e3b341", + "border": "#533e07" + }, + "error": { + "bg": "#5e0206", + "fg": "#f85149", + "border": "#7e080d" + } + }, + "toast": { + "background": "#0c0f16", + "foreground": "#ccd4dc", + "border": "#393d44", + "success": { + "background": "#063a10", + "foreground": "#3fb950", + "border": "#0f501a" + }, + "warning": { + "background": "#3c2c02", + "foreground": "#e3b341", + "border": "#533e07" + }, + "error": { + "background": "#5e0206", + "foreground": "#f85149", + "border": "#7e080d" + }, + "info": { + "background": "#3f2b02", + "foreground": "#d29922", + "border": "#563d07" + } + }, + "emptyState": { + "icon": "#8b949e", + "title": "#ccd4dc", + "description": "#8b949e", + "border": "#21252b" + }, + "table": { + "border": "#21252b", + "headerBackground": "#0c0f16", + "headerForeground": "#ccd4dc", + "rowHover": "#181c22", + "rowSelected": "#032f5a" + }, + "charts": { + "series": [ + "#58a6ff", + "#d29922", + "#3fb950", + "#e3b341", + "#f85149" + ] + }, + "a11y": { + "focusRing": "#197de0", + "selection": "#032f5a", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(0, 0, 0, 0.22)", + "md": "0 12px 32px rgba(0, 0, 0, 0.32)", + "lg": "0 24px 56px rgba(0, 0, 0, 0.42)", + "focus": "0 0 0 3px #58a6ff59" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/github-light.json b/packages/ui/src/lib/theme/themes/github-light.json index 209ffba8..61c006d8 100644 --- a/packages/ui/src/lib/theme/themes/github-light.json +++ b/packages/ui/src/lib/theme/themes/github-light.json @@ -2,79 +2,81 @@ "metadata": { "id": "github-light", "name": "GitHub", - "description": "Port of OpenCode GitHub theme (light variant)", + "description": "Ported from OpenCode GitHub theme (light variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "light", "tags": [ "light", "opencode", + "ported", "github" ] }, "colors": { "primary": { - "base": "#0d69d9", + "base": "#0969da", "hover": "#0c5fc5", - "active": "#0c5fc5", + "active": "#0d69d9", "foreground": "#ffffff", - "muted": "#0d69d980", + "muted": "#0969da80", "emphasis": "#0c5fc5" }, "surface": { "background": "#ffffff", "foreground": "#1e2329", - "muted": "#f2f3f3", + "muted": "#f5f5f4", "mutedForeground": "#57606a", "elevated": "#f9f9f9", "elevatedForeground": "#1e2329", - "overlay": "#0000004d", + "overlay": "#ffffff33", "subtle": "#eaeaeb" }, "interactive": { "border": "#cacbcc", "borderHover": "#bcbec0", - "borderFocus": "#9dc3fb", - "selection": "#deebfe", - "selectionForeground": "#000000", - "focus": "#9dc3fb", - "focusRing": "#9dc3fb47", - "cursor": "#1e2329", - "hover": "#eaeaeb", - "active": "#eaeaeb" + "borderFocus": "#0d69d9", + "selection": "#1e232916", + "selectionForeground": "#1e2329", + "focus": "#0d69d9", + "focusRing": "#0d69d947", + "cursor": "#0e1319", + "hover": "#1e23290e", + "active": "#1e232916" }, "status": { - "error": "#bc212b", - "errorForeground": "#000000", + "error": "#cf222e", + "errorForeground": "#ffffff", "errorBackground": "#ffe2df", "errorBorder": "#ffa69f", - "warning": "#feab76", - "warningForeground": "#000000", + "warning": "#9a6700", + "warningForeground": "#ffffff", "warningBackground": "#ffe6c4", "warningBorder": "#f1b55c", - "success": "#76dc88", - "successForeground": "#000000", + "success": "#1a7f37", + "successForeground": "#ffffff", "successBackground": "#bffcc6", "successBorder": "#76dc88", - "info": "#ffa983", - "infoForeground": "#000000", + "info": "#bc4c00", + "infoForeground": "#ffffff", "infoBackground": "#ffe3d8", "infoBorder": "#ffa983" }, "pr": { - "open": "#76dc88", + "open": "#1a7f37", "draft": "#57606a", - "blocked": "#feab76", - "merged": "#cf222e", - "closed": "#bc212b" + "blocked": "#9a6700", + "merged": "#1b7c83", + "closed": "#cf222e" }, "syntax": { "base": { - "background": "#f2f3f3", + "background": "#f9f9f9", "foreground": "#1e2329", "comment": "#57606a", "keyword": "#cf222e", "string": "#0969da", - "number": "#8250df", + "number": "#1b7c83", "function": "#1b7c83", "variable": "#bc4c00", "type": "#bc4c00", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#57606a", - "stringEscape": "#1b7c83", + "stringEscape": "#1e2329", "keywordImport": "#cf222e", "storageModifier": "#cf222e", "functionCall": "#1b7c83", @@ -90,7 +92,7 @@ "variableProperty": "#1b7c83", "variableOther": "#bc4c00", "variableGlobal": "#1b7c83", - "variableLocal": "#57606a", + "variableLocal": "#24292f", "parameter": "#bc4c00", "constant": "#1b7c83", "class": "#bc4c00", @@ -99,38 +101,65 @@ "struct": "#bc4c00", "enum": "#bc4c00", "typeParameter": "#bc4c00", - "namespace": "#cf222e", + "namespace": "#bc4c00", "module": "#cf222e", "tag": "#cf222e", "jsxTag": "#cf222e", "tagAttribute": "#1b7c83", "tagAttributeValue": "#0969da", - "boolean": "#8250df", + "boolean": "#1b7c83", "decorator": "#cf222e", - "label": "#cf222e", + "label": "#1b7c83", "punctuation": "#24292f", "macro": "#cf222e", "preprocessor": "#cf222e", "regex": "#1e2329", - "url": "#0969da", + "url": "#0c5fc5", "key": "#1b7c83", - "exception": "#bc212b" + "exception": "#cf222e" }, "highlights": { "diffAdded": "#396e42", - "diffAddedBackground": "#f9fff9", - "diffRemoved": "#d54645", - "diffRemovedBackground": "#fffcfc", + "diffAddedBackground": "#f2fdf3", + "diffRemoved": "#ab272b", + "diffRemovedBackground": "#fff7f7", "diffModified": "#785105", - "diffModifiedBackground": "#e6ecf4", + "diffModifiedBackground": "#f3f5f9", "lineNumber": "#7b828a", "lineNumberActive": "#1e2329" } }, + "header": { + "background": "#ffffff", + "foreground": "#1e2329", + "border": "#cacbcc", + "icon": "#3a3f44", + "hover": "#eaeaeb" + }, + "sidebar": { + "background": "#f5f5f4", + "foreground": "#57606a", + "border": "#cacbcc", + "icon": "#cdcecc", + "hover": "#eaeaeb", + "active": "#deebfe", + "accent": "#0969da", + "accentForeground": "#ffffff" + }, + "chat": { + "background": "#ffffff", + "userMessage": "#1e2329", + "userMessageBackground": "#f2f3f3", + "assistantMessage": "#1e2329", + "assistantMessageBackground": "#ffffff", + "timestamp": "#7b828a", + "divider": "#e4e4e5", + "typing": "#57606a" + }, "markdown": { "heading1": "#0969da", "heading2": "#0969da", - "heading3": "#1e2329", + "heading3": "#0e1319", "heading4": "#1e2329", "link": "#0969da", "linkHover": "#1b7c83", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#f2f3f3", "blockquote": "#57606a", "blockquoteBorder": "#cacbcc", - "listMarker": "#0969da99" - }, - "chat": { - "userMessage": "#1e2329", - "userMessageBackground": "#deebfe", - "assistantMessage": "#1e2329", - "assistantMessageBackground": "#ffffff", - "timestamp": "#57606a", - "divider": "#cacbcc" + "listMarker": "#0969da99", + "bold": "#bc4c00", + "italic": "#9a6700", + "strikethrough": "#57606a", + "hr": "#d0d7de" }, "tools": { - "background": "#f2f3f380", - "border": "#cacbccb3", - "headerHover": "#eaeaeb80", - "icon": "#57606a", + "background": "#f2f3f3", + "border": "#e4e4e5", + "headerHover": "#eaeaeb", + "icon": "#cdcecc", "title": "#1e2329", "description": "#57606a", "edit": { "added": "#396e42", - "addedBackground": "#f9fff9", + "addedBackground": "#f2fdf3", "removed": "#d54645", - "removedBackground": "#fffcfc", + "removedBackground": "#fff7f7", + "modified": "#785105", + "modifiedBackground": "#f3f5f9", "lineNumber": "#7b828a" + }, + "bash": { + "background": "#f9f9f9", + "foreground": "#1e2329", + "info": "#bc4c00", + "warning": "#9a6700", + "error": "#cf222e" + }, + "lsp": { + "background": "#f9f9f9", + "foreground": "#1e2329", + "info": "#bc4c00", + "warning": "#9a6700", + "error": "#cf222e" } + }, + "forms": { + "inputBackground": "#ffffff", + "inputForeground": "#1e2329", + "inputBorder": "#e4e4e5", + "inputBorderHover": "#d7d8d9", + "inputBorderFocus": "#0d69d9", + "inputPlaceholder": "#7b828a", + "inputDisabled": "#efefee", + "inputSelection": "#deebfe", + "label": "#57606a", + "helperText": "#7b828a" + }, + "buttons": { + "primary": { + "bg": "#0969da", + "fg": "#ffffff", + "border": "#9dc3fb", + "hover": "#0c5fc5", + "active": "#0d69d9", + "disabled": "#d2d3d5" + }, + "secondary": { + "bg": "#f9f9f9", + "fg": "#1e2329", + "border": "#cacbcc", + "hover": "#f2f3f3", + "active": "#eaeaeb", + "disabled": "#efefee" + }, + "ghost": { + "bg": "#00000000", + "fg": "#1e2329", + "border": "#00000000", + "hover": "#f2f3f3", + "active": "#eaeaeb", + "disabled": "#7b828a" + }, + "destructive": { + "bg": "#cf222e", + "fg": "#ffffff", + "border": "#ffa69f", + "hover": "#fcd5d2", + "active": "#ce252f", + "disabled": "#efefee" + } + }, + "modal": { + "background": "#f9f9f9", + "foreground": "#1e2329", + "border": "#cacbcc", + "overlay": "#ffffff3d" + }, + "popover": { + "background": "#f9f9f9", + "foreground": "#1e2329", + "border": "#cacbcc", + "shadow": "0 18px 48px rgba(15, 15, 15, 0.16)" + }, + "commandPalette": { + "background": "#f9f9f9", + "foreground": "#1e2329", + "border": "#cacbcc", + "inputBackground": "#ffffff", + "selectedBackground": "#deebfe", + "selectedForeground": "#1e2329", + "muted": "#57606a" + }, + "fileAttachment": { + "background": "#f2f3f3", + "foreground": "#1e2329", + "border": "#e4e4e5", + "icon": "#cdcecc", + "removeHover": "#ffe2df" + }, + "sessions": { + "background": "#ffffff", + "foreground": "#1e2329", + "mutedForeground": "#57606a", + "border": "#ededee", + "hover": "#eaeaeb", + "active": "#deebfe" + }, + "modelSelector": { + "background": "#f9f9f9", + "foreground": "#1e2329", + "border": "#cacbcc", + "selectedBackground": "#deebfe", + "selectedForeground": "#1e2329" + }, + "permissions": { + "background": "#f9f9f9", + "foreground": "#1e2329", + "border": "#cacbcc", + "allow": "#1a7f37", + "allowBackground": "#bffcc6", + "deny": "#cf222e", + "denyBackground": "#ffe2df" + }, + "loading": { + "spinner": "#0969da", + "spinnerTrack": "#eaeaeb", + "skeleton": "#f2f3f3", + "shimmer": "#eaeaeb" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#1e232926", + "thumbHover": "#1e232940" + }, + "badges": { + "default": { + "bg": "#f2f3f3", + "fg": "#1e2329", + "border": "#e4e4e5" + }, + "info": { + "bg": "#ffe3d8", + "fg": "#bc4c00", + "border": "#ffa983" + }, + "success": { + "bg": "#bffcc6", + "fg": "#1a7f37", + "border": "#76dc88" + }, + "warning": { + "bg": "#ffe6c4", + "fg": "#9a6700", + "border": "#f1b55c" + }, + "error": { + "bg": "#ffe2df", + "fg": "#cf222e", + "border": "#ffa69f" + } + }, + "toast": { + "background": "#f9f9f9", + "foreground": "#1e2329", + "border": "#cacbcc", + "success": { + "background": "#bffcc6", + "foreground": "#1a7f37", + "border": "#76dc88" + }, + "warning": { + "background": "#ffe6c4", + "foreground": "#9a6700", + "border": "#f1b55c" + }, + "error": { + "background": "#ffe2df", + "foreground": "#cf222e", + "border": "#ffa69f" + }, + "info": { + "background": "#ffe3d8", + "foreground": "#bc4c00", + "border": "#ffa983" + } + }, + "emptyState": { + "icon": "#57606a", + "title": "#1e2329", + "description": "#57606a", + "border": "#ededee" + }, + "table": { + "border": "#ededee", + "headerBackground": "#f9f9f9", + "headerForeground": "#1e2329", + "rowHover": "#eaeaeb", + "rowSelected": "#deebfe" + }, + "charts": { + "series": [ + "#0969da", + "#bc4c00", + "#1a7f37", + "#9a6700", + "#cf222e" + ] + }, + "a11y": { + "focusRing": "#0d69d9", + "selection": "#deebfe", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(15, 15, 15, 0.08)", + "md": "0 12px 32px rgba(15, 15, 15, 0.12)", + "lg": "0 24px 56px rgba(15, 15, 15, 0.16)", + "focus": "0 0 0 3px #0969da40" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/index.ts b/packages/ui/src/lib/theme/themes/index.ts index 980a2770..6091f966 100644 --- a/packages/ui/src/lib/theme/themes/index.ts +++ b/packages/ui/src/lib/theme/themes/index.ts @@ -3,14 +3,26 @@ import { presetThemes } from './presets'; import { withPrColors } from './prColors'; import flexokiLightRaw from './flexoki-light.json'; import flexokiDarkRaw from './flexoki-dark.json'; +import openchamberLightRaw from './openchamber-light.json'; +import openchamberDarkRaw from './openchamber-dark.json'; export const flexokiLightTheme = withPrColors(flexokiLightRaw as Theme); export const flexokiDarkTheme = withPrColors(flexokiDarkRaw as Theme); +export const openchamberLightTheme = withPrColors(openchamberLightRaw as Theme); +export const openchamberDarkTheme = withPrColors(openchamberDarkRaw as Theme); -export const DEFAULT_LIGHT_THEME_ID = 'flexoki-light' as const; -export const DEFAULT_DARK_THEME_ID = 'flexoki-dark' as const; +export const DEFAULT_LIGHT_THEME_ID = 'openchamber-light' as const; +export const DEFAULT_DARK_THEME_ID = 'openchamber-dark' as const; -export const themes: Theme[] = [flexokiLightTheme, flexokiDarkTheme, ...presetThemes]; +export const themes: Theme[] = [ + openchamberLightTheme, + openchamberDarkTheme, + flexokiLightTheme, + flexokiDarkTheme, + ...presetThemes.filter( + (theme) => theme.metadata.id !== 'openchamber-light' && theme.metadata.id !== 'openchamber-dark', + ), +]; export function getThemeById(id: string): Theme | undefined { // Back-compat for a short-lived rename. diff --git a/packages/ui/src/lib/theme/themes/lucent-orng-dark.json b/packages/ui/src/lib/theme/themes/lucent-orng-dark.json index d28d9e6b..e8eeec03 100644 --- a/packages/ui/src/lib/theme/themes/lucent-orng-dark.json +++ b/packages/ui/src/lib/theme/themes/lucent-orng-dark.json @@ -2,79 +2,81 @@ "metadata": { "id": "lucent-orng-dark", "name": "Lucent Orng", - "description": "Port of OpenCode Lucent Orng theme (dark variant)", + "description": "Ported from OpenCode Lucent Orng theme (dark variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "dark", "tags": [ "dark", "opencode", + "ported", "lucent-orng" ] }, "colors": { "primary": { - "base": "#be3c07", + "base": "#EC5B2B", "hover": "#da4f1f", - "active": "#da4f1f", - "foreground": "#ffffff", - "muted": "#be3c0780", - "emphasis": "#da4f1f" + "active": "#be3c07", + "foreground": "#151313", + "muted": "#EC5B2B80", + "emphasis": "#fdc4b3" }, "surface": { "background": "#1a0c08", "foreground": "#eeeeee", - "muted": "#281b17", + "muted": "#21130e", "mutedForeground": "#808080", "elevated": "#221411", "elevatedForeground": "#eeeeee", - "overlay": "#00000080", + "overlay": "#1a0c08cc", "subtle": "#2f221f" }, "interactive": { "border": "#524845", "borderHover": "#5a514e", - "borderFocus": "#752101", - "selection": "#531906", - "selectionForeground": "#ffffff", - "focus": "#752101", - "focusRing": "#75210159", - "cursor": "#eeeeee", - "hover": "#2f221f", - "active": "#2f221f" + "borderFocus": "#be3c07", + "selection": "#eeeeee1f", + "selectionForeground": "#eeeeee", + "focus": "#be3c07", + "focusRing": "#be3c0761", + "cursor": "#fdfdfd", + "hover": "#eeeeee17", + "active": "#eeeeee1f" }, "status": { - "error": "#ce2245", - "errorForeground": "#ffffff", + "error": "#e06c75", + "errorForeground": "#151313", "errorBackground": "#5c0318", "errorBorder": "#7c0a25", - "warning": "#c51d33", - "warningForeground": "#ffffff", + "warning": "#EC5B2B", + "warningForeground": "#151313", "warningBackground": "#531906", "warningBorder": "#752101", - "success": "#1277e2", - "successForeground": "#ffffff", + "success": "#6ba1e6", + "successForeground": "#151313", "successBackground": "#042e5d", "successBorder": "#09417d", - "info": "#228f9b", - "infoForeground": "#ffffff", + "info": "#56b6c2", + "infoForeground": "#151313", "infoBackground": "#05363b", "infoBorder": "#0d4b51" }, "pr": { - "open": "#1277e2", + "open": "#6ba1e6", "draft": "#808080", - "blocked": "#c51d33", - "merged": "#EC5B2B", - "closed": "#ce2245" + "blocked": "#EC5B2B", + "merged": "#FFF7F1", + "closed": "#e06c75" }, "syntax": { "base": { - "background": "#281b17", + "background": "#221411", "foreground": "#eeeeee", "comment": "#808080", "keyword": "#EC5B2B", "string": "#6ba1e6", - "number": "#EE7948", + "number": "#FFF7F1", "function": "#56b6c2", "variable": "#e06c75", "type": "#e5c07b", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#808080", - "stringEscape": "#FFF7F1", + "stringEscape": "#eeeeee", "keywordImport": "#EC5B2B", "storageModifier": "#EC5B2B", "functionCall": "#56b6c2", @@ -90,7 +92,7 @@ "variableProperty": "#56b6c2", "variableOther": "#e06c75", "variableGlobal": "#FFF7F1", - "variableLocal": "#808080", + "variableLocal": "#eeeeee", "parameter": "#e06c75", "constant": "#FFF7F1", "class": "#e5c07b", @@ -99,38 +101,65 @@ "struct": "#e5c07b", "enum": "#e5c07b", "typeParameter": "#e5c07b", - "namespace": "#EC5B2B", + "namespace": "#e5c07b", "module": "#EC5B2B", "tag": "#EC5B2B", "jsxTag": "#EC5B2B", "tagAttribute": "#56b6c2", "tagAttributeValue": "#6ba1e6", - "boolean": "#EE7948", + "boolean": "#FFF7F1", "decorator": "#EC5B2B", - "label": "#EC5B2B", + "label": "#56b6c2", "punctuation": "#eeeeee", "macro": "#EC5B2B", "preprocessor": "#EC5B2B", "regex": "#eeeeee", - "url": "#EC5B2B", + "url": "#fdc4b3", "key": "#56b6c2", - "exception": "#ce2245" + "exception": "#e06c75" }, "highlights": { "diffAdded": "#b8d6fe", - "diffAddedBackground": "#010e24", - "diffRemoved": "#e92b53", - "diffRemovedBackground": "#230106", + "diffAddedBackground": "#021631", + "diffRemoved": "#fec2c4", + "diffRemovedBackground": "#30030a", "diffModified": "#ffba92", - "diffModifiedBackground": "#392018", + "diffModifiedBackground": "#28150f", "lineNumber": "#5d5d5d", "lineNumberActive": "#eeeeee" } }, + "header": { + "background": "#1a0c08", + "foreground": "#eeeeee", + "border": "#524845", + "icon": "#9b9691", + "hover": "#2f221f" + }, + "sidebar": { + "background": "#21130e", + "foreground": "#808080", + "border": "#524845", + "icon": "#342721", + "hover": "#2f221f", + "active": "#531906", + "accent": "#EC5B2B", + "accentForeground": "#151313" + }, + "chat": { + "background": "#1a0c08", + "userMessage": "#eeeeee", + "userMessageBackground": "#281b17", + "assistantMessage": "#eeeeee", + "assistantMessageBackground": "#1a0c08", + "timestamp": "#5d5d5d", + "divider": "#413632", + "typing": "#808080" + }, "markdown": { "heading1": "#EC5B2B", "heading2": "#EC5B2B", - "heading3": "#eeeeee", + "heading3": "#fdfdfd", "heading4": "#eeeeee", "link": "#EC5B2B", "linkHover": "#56b6c2", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#281b17", "blockquote": "#FFF7F1", "blockquoteBorder": "#524845", - "listMarker": "#EC5B2B99" - }, - "chat": { - "userMessage": "#eeeeee", - "userMessageBackground": "#531906", - "assistantMessage": "#eeeeee", - "assistantMessageBackground": "#1a0c08", - "timestamp": "#808080", - "divider": "#524845" + "listMarker": "#EC5B2B99", + "bold": "#EE7948", + "italic": "#e5c07b", + "strikethrough": "#808080", + "hr": "#808080" }, "tools": { - "background": "#281b1780", - "border": "#524845b3", - "headerHover": "#2f221f80", - "icon": "#808080", + "background": "#281b17", + "border": "#413632", + "headerHover": "#2f221f", + "icon": "#342721", "title": "#eeeeee", "description": "#808080", "edit": { "added": "#b8d6fe", - "addedBackground": "#010e24", + "addedBackground": "#021631", "removed": "#e92b53", - "removedBackground": "#230106", + "removedBackground": "#30030a", + "modified": "#ffba92", + "modifiedBackground": "#28150f", "lineNumber": "#5d5d5d" + }, + "bash": { + "background": "#221411", + "foreground": "#eeeeee", + "info": "#56b6c2", + "warning": "#EC5B2B", + "error": "#e06c75" + }, + "lsp": { + "background": "#221411", + "foreground": "#eeeeee", + "info": "#56b6c2", + "warning": "#EC5B2B", + "error": "#e06c75" } + }, + "forms": { + "inputBackground": "#1d0f0b", + "inputForeground": "#eeeeee", + "inputBorder": "#413632", + "inputBorderHover": "#493f3c", + "inputBorderFocus": "#be3c07", + "inputPlaceholder": "#5d5d5d", + "inputDisabled": "#251813", + "inputSelection": "#9b3108", + "label": "#808080", + "helperText": "#5d5d5d" + }, + "buttons": { + "primary": { + "bg": "#EC5B2B", + "fg": "#151313", + "border": "#752101", + "hover": "#da4f1f", + "active": "#be3c07", + "disabled": "#493f3c" + }, + "secondary": { + "bg": "#221411", + "fg": "#eeeeee", + "border": "#524845", + "hover": "#281b17", + "active": "#2f221f", + "disabled": "#251813" + }, + "ghost": { + "bg": "#00000000", + "fg": "#eeeeee", + "border": "#00000000", + "hover": "#281b17", + "active": "#2f221f", + "disabled": "#5d5d5d" + }, + "destructive": { + "bg": "#e06c75", + "fg": "#151313", + "border": "#7c0a25", + "hover": "#7c0a25", + "active": "#ce2245", + "disabled": "#251813" + } + }, + "modal": { + "background": "#221411", + "foreground": "#eeeeee", + "border": "#524845", + "overlay": "#1a0c08d6" + }, + "popover": { + "background": "#221411", + "foreground": "#eeeeee", + "border": "#524845", + "shadow": "0 18px 48px rgba(0, 0, 0, 0.45)" + }, + "commandPalette": { + "background": "#221411", + "foreground": "#eeeeee", + "border": "#524845", + "inputBackground": "#1d0f0b", + "selectedBackground": "#531906", + "selectedForeground": "#eeeeee", + "muted": "#808080" + }, + "fileAttachment": { + "background": "#281b17", + "foreground": "#eeeeee", + "border": "#413632", + "icon": "#342721", + "removeHover": "#5c0318" + }, + "sessions": { + "background": "#1a0c08", + "foreground": "#eeeeee", + "mutedForeground": "#808080", + "border": "#392d29", + "hover": "#2f221f", + "active": "#531906" + }, + "modelSelector": { + "background": "#221411", + "foreground": "#eeeeee", + "border": "#524845", + "selectedBackground": "#531906", + "selectedForeground": "#eeeeee" + }, + "permissions": { + "background": "#221411", + "foreground": "#eeeeee", + "border": "#524845", + "allow": "#6ba1e6", + "allowBackground": "#042e5d", + "deny": "#e06c75", + "denyBackground": "#5c0318" + }, + "loading": { + "spinner": "#EC5B2B", + "spinnerTrack": "#2f221f", + "skeleton": "#281b17", + "shimmer": "#2f221f" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#eeeeee33", + "thumbHover": "#eeeeee57" + }, + "badges": { + "default": { + "bg": "#281b17", + "fg": "#eeeeee", + "border": "#413632" + }, + "info": { + "bg": "#05363b", + "fg": "#56b6c2", + "border": "#0d4b51" + }, + "success": { + "bg": "#042e5d", + "fg": "#6ba1e6", + "border": "#09417d" + }, + "warning": { + "bg": "#531906", + "fg": "#EC5B2B", + "border": "#752101" + }, + "error": { + "bg": "#5c0318", + "fg": "#e06c75", + "border": "#7c0a25" + } + }, + "toast": { + "background": "#221411", + "foreground": "#eeeeee", + "border": "#524845", + "success": { + "background": "#042e5d", + "foreground": "#6ba1e6", + "border": "#09417d" + }, + "warning": { + "background": "#531906", + "foreground": "#EC5B2B", + "border": "#752101" + }, + "error": { + "background": "#5c0318", + "foreground": "#e06c75", + "border": "#7c0a25" + }, + "info": { + "background": "#05363b", + "foreground": "#56b6c2", + "border": "#0d4b51" + } + }, + "emptyState": { + "icon": "#808080", + "title": "#eeeeee", + "description": "#808080", + "border": "#392d29" + }, + "table": { + "border": "#392d29", + "headerBackground": "#221411", + "headerForeground": "#eeeeee", + "rowHover": "#2f221f", + "rowSelected": "#531906" + }, + "charts": { + "series": [ + "#EC5B2B", + "#56b6c2", + "#6ba1e6", + "#EC5B2B", + "#e06c75" + ] + }, + "a11y": { + "focusRing": "#be3c07", + "selection": "#531906", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(0, 0, 0, 0.22)", + "md": "0 12px 32px rgba(0, 0, 0, 0.32)", + "lg": "0 24px 56px rgba(0, 0, 0, 0.42)", + "focus": "0 0 0 3px #EC5B2B59" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/lucent-orng-light.json b/packages/ui/src/lib/theme/themes/lucent-orng-light.json index 69f3b1b4..c0f18310 100644 --- a/packages/ui/src/lib/theme/themes/lucent-orng-light.json +++ b/packages/ui/src/lib/theme/themes/lucent-orng-light.json @@ -2,79 +2,81 @@ "metadata": { "id": "lucent-orng-light", "name": "Lucent Orng", - "description": "Port of OpenCode Lucent Orng theme (light variant)", + "description": "Ported from OpenCode Lucent Orng theme (light variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "light", "tags": [ "light", "opencode", + "ported", "lucent-orng" ] }, "colors": { "primary": { - "base": "#f45214", + "base": "#EC5B2B", "hover": "#e14d17", - "active": "#e14d17", + "active": "#f45214", "foreground": "#000000", - "muted": "#f4521480", + "muted": "#EC5B2B80", "emphasis": "#e14d17" }, "surface": { "background": "#fef7f3", "foreground": "#181818", - "muted": "#f1eae6", + "muted": "#f3ece8", "mutedForeground": "#8a8a8a", "elevated": "#f7f1ed", "elevatedForeground": "#181818", - "overlay": "#0000004d", + "overlay": "#fef7f333", "subtle": "#e8e2de" }, "interactive": { "border": "#c6c1be", "borderHover": "#b9b4b1", - "borderFocus": "#fea88e", - "selection": "#ffe3da", - "selectionForeground": "#000000", - "focus": "#fea88e", - "focusRing": "#fea88e47", - "cursor": "#181818", - "hover": "#e8e2de", - "active": "#e8e2de" + "borderFocus": "#f45214", + "selection": "#18181816", + "selectionForeground": "#181818", + "focus": "#f45214", + "focusRing": "#f4521447", + "cursor": "#090909", + "hover": "#1818180e", + "active": "#18181816" }, "status": { - "error": "#ce0727", - "errorForeground": "#000000", + "error": "#d1383d", + "errorForeground": "#ffffff", "errorBackground": "#fde3e0", "errorBorder": "#faa8a3", - "warning": "#fca6ab", + "warning": "#EC5B2B", "warningForeground": "#000000", "warningBackground": "#ffe3da", "warningBorder": "#fea88e", - "success": "#9ec3fa", - "successForeground": "#000000", + "success": "#0062d1", + "successForeground": "#ffffff", "successBackground": "#deebfe", "successBorder": "#9ec3fa", - "info": "#77d1e1", + "info": "#318795", "infoForeground": "#000000", "infoBackground": "#bff5ff", "infoBorder": "#77d1e1" }, "pr": { - "open": "#9ec3fa", + "open": "#0062d1", "draft": "#8a8a8a", - "blocked": "#fca6ab", + "blocked": "#EC5B2B", "merged": "#EC5B2B", - "closed": "#ce0727" + "closed": "#d1383d" }, "syntax": { "base": { - "background": "#f1eae6", + "background": "#f7f1ed", "foreground": "#181818", "comment": "#8a8a8a", "keyword": "#EC5B2B", "string": "#0062d1", - "number": "#c94d24", + "number": "#EC5B2B", "function": "#318795", "variable": "#d1383d", "type": "#b0851f", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#8a8a8a", - "stringEscape": "#EC5B2B", + "stringEscape": "#181818", "keywordImport": "#EC5B2B", "storageModifier": "#EC5B2B", "functionCall": "#318795", @@ -90,7 +92,7 @@ "variableProperty": "#318795", "variableOther": "#d1383d", "variableGlobal": "#EC5B2B", - "variableLocal": "#8a8a8a", + "variableLocal": "#1a1a1a", "parameter": "#d1383d", "constant": "#EC5B2B", "class": "#b0851f", @@ -99,38 +101,65 @@ "struct": "#b0851f", "enum": "#b0851f", "typeParameter": "#b0851f", - "namespace": "#EC5B2B", + "namespace": "#b0851f", "module": "#EC5B2B", "tag": "#EC5B2B", "jsxTag": "#EC5B2B", "tagAttribute": "#318795", "tagAttributeValue": "#0062d1", - "boolean": "#c94d24", + "boolean": "#EC5B2B", "decorator": "#EC5B2B", - "label": "#EC5B2B", + "label": "#318795", "punctuation": "#1a1a1a", "macro": "#EC5B2B", "preprocessor": "#EC5B2B", "regex": "#181818", - "url": "#EC5B2B", + "url": "#e14d17", "key": "#318795", - "exception": "#ce0727" + "exception": "#d1383d" }, "highlights": { "diffAdded": "#2f60a4", - "diffAddedBackground": "#fbfdff", - "diffRemoved": "#e9055a", - "diffRemovedBackground": "#fffcfc", + "diffAddedBackground": "#f6faff", + "diffRemoved": "#ae1a45", + "diffRemovedBackground": "#fef7f8", "diffModified": "#FF8C00", - "diffModifiedBackground": "#f8e8e1", + "diffModifiedBackground": "#fbefea", "lineNumber": "#afafaf", "lineNumberActive": "#181818" } }, + "header": { + "background": "#fef7f3", + "foreground": "#181818", + "border": "#c6c1be", + "icon": "#323232", + "hover": "#e8e2de" + }, + "sidebar": { + "background": "#f3ece8", + "foreground": "#8a8a8a", + "border": "#c6c1be", + "icon": "#c8c4c0", + "hover": "#e8e2de", + "active": "#ffe3da", + "accent": "#EC5B2B", + "accentForeground": "#000000" + }, + "chat": { + "background": "#fef7f3", + "userMessage": "#181818", + "userMessageBackground": "#f1eae6", + "assistantMessage": "#181818", + "assistantMessageBackground": "#fef7f3", + "timestamp": "#afafaf", + "divider": "#e2dcd8", + "typing": "#8a8a8a" + }, "markdown": { "heading1": "#EC5B2B", "heading2": "#EC5B2B", - "heading3": "#181818", + "heading3": "#090909", "heading4": "#181818", "link": "#EC5B2B", "linkHover": "#318795", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#f1eae6", "blockquote": "#b0851f", "blockquoteBorder": "#c6c1be", - "listMarker": "#EC5B2B99" - }, - "chat": { - "userMessage": "#181818", - "userMessageBackground": "#ffe3da", - "assistantMessage": "#181818", - "assistantMessageBackground": "#fef7f3", - "timestamp": "#8a8a8a", - "divider": "#c6c1be" + "listMarker": "#EC5B2B99", + "bold": "#EC5B2B", + "italic": "#b0851f", + "strikethrough": "#8a8a8a", + "hr": "#8a8a8a" }, "tools": { - "background": "#f1eae680", - "border": "#c6c1beb3", - "headerHover": "#e8e2de80", - "icon": "#8a8a8a", + "background": "#f1eae6", + "border": "#e2dcd8", + "headerHover": "#e8e2de", + "icon": "#c8c4c0", "title": "#181818", "description": "#8a8a8a", "edit": { "added": "#2f60a4", - "addedBackground": "#fbfdff", + "addedBackground": "#f6faff", "removed": "#e9055a", - "removedBackground": "#fffcfc", + "removedBackground": "#fef7f8", + "modified": "#FF8C00", + "modifiedBackground": "#fbefea", "lineNumber": "#afafaf" + }, + "bash": { + "background": "#f7f1ed", + "foreground": "#181818", + "info": "#318795", + "warning": "#EC5B2B", + "error": "#d1383d" + }, + "lsp": { + "background": "#f7f1ed", + "foreground": "#181818", + "info": "#318795", + "warning": "#EC5B2B", + "error": "#d1383d" } + }, + "forms": { + "inputBackground": "#fef7f3", + "inputForeground": "#181818", + "inputBorder": "#e2dcd8", + "inputBorderHover": "#d4cecb", + "inputBorderFocus": "#f45214", + "inputPlaceholder": "#afafaf", + "inputDisabled": "#ece6e2", + "inputSelection": "#ffe3da", + "label": "#8a8a8a", + "helperText": "#afafaf" + }, + "buttons": { + "primary": { + "bg": "#EC5B2B", + "fg": "#000000", + "border": "#fea88e", + "hover": "#e14d17", + "active": "#f45214", + "disabled": "#cfcac7" + }, + "secondary": { + "bg": "#f7f1ed", + "fg": "#181818", + "border": "#c6c1be", + "hover": "#f1eae6", + "active": "#e8e2de", + "disabled": "#ece6e2" + }, + "ghost": { + "bg": "#00000000", + "fg": "#181818", + "border": "#00000000", + "hover": "#f1eae6", + "active": "#e8e2de", + "disabled": "#afafaf" + }, + "destructive": { + "bg": "#d1383d", + "fg": "#ffffff", + "border": "#faa8a3", + "hover": "#fdd5d2", + "active": "#e1032b", + "disabled": "#ece6e2" + } + }, + "modal": { + "background": "#f7f1ed", + "foreground": "#181818", + "border": "#c6c1be", + "overlay": "#fef7f33d" + }, + "popover": { + "background": "#f7f1ed", + "foreground": "#181818", + "border": "#c6c1be", + "shadow": "0 18px 48px rgba(15, 15, 15, 0.16)" + }, + "commandPalette": { + "background": "#f7f1ed", + "foreground": "#181818", + "border": "#c6c1be", + "inputBackground": "#fef7f3", + "selectedBackground": "#ffe3da", + "selectedForeground": "#181818", + "muted": "#8a8a8a" + }, + "fileAttachment": { + "background": "#f1eae6", + "foreground": "#181818", + "border": "#e2dcd8", + "icon": "#c8c4c0", + "removeHover": "#fde3e0" + }, + "sessions": { + "background": "#fef7f3", + "foreground": "#181818", + "mutedForeground": "#8a8a8a", + "border": "#ebe4e1", + "hover": "#e8e2de", + "active": "#ffe3da" + }, + "modelSelector": { + "background": "#f7f1ed", + "foreground": "#181818", + "border": "#c6c1be", + "selectedBackground": "#ffe3da", + "selectedForeground": "#181818" + }, + "permissions": { + "background": "#f7f1ed", + "foreground": "#181818", + "border": "#c6c1be", + "allow": "#0062d1", + "allowBackground": "#deebfe", + "deny": "#d1383d", + "denyBackground": "#fde3e0" + }, + "loading": { + "spinner": "#EC5B2B", + "spinnerTrack": "#e8e2de", + "skeleton": "#f1eae6", + "shimmer": "#e8e2de" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#18181826", + "thumbHover": "#18181840" + }, + "badges": { + "default": { + "bg": "#f1eae6", + "fg": "#181818", + "border": "#e2dcd8" + }, + "info": { + "bg": "#bff5ff", + "fg": "#318795", + "border": "#77d1e1" + }, + "success": { + "bg": "#deebfe", + "fg": "#0062d1", + "border": "#9ec3fa" + }, + "warning": { + "bg": "#ffe3da", + "fg": "#EC5B2B", + "border": "#fea88e" + }, + "error": { + "bg": "#fde3e0", + "fg": "#d1383d", + "border": "#faa8a3" + } + }, + "toast": { + "background": "#f7f1ed", + "foreground": "#181818", + "border": "#c6c1be", + "success": { + "background": "#deebfe", + "foreground": "#0062d1", + "border": "#9ec3fa" + }, + "warning": { + "background": "#ffe3da", + "foreground": "#EC5B2B", + "border": "#fea88e" + }, + "error": { + "background": "#fde3e0", + "foreground": "#d1383d", + "border": "#faa8a3" + }, + "info": { + "background": "#bff5ff", + "foreground": "#318795", + "border": "#77d1e1" + } + }, + "emptyState": { + "icon": "#8a8a8a", + "title": "#181818", + "description": "#8a8a8a", + "border": "#ebe4e1" + }, + "table": { + "border": "#ebe4e1", + "headerBackground": "#f7f1ed", + "headerForeground": "#181818", + "rowHover": "#e8e2de", + "rowSelected": "#ffe3da" + }, + "charts": { + "series": [ + "#EC5B2B", + "#318795", + "#0062d1", + "#EC5B2B", + "#d1383d" + ] + }, + "a11y": { + "focusRing": "#f45214", + "selection": "#ffe3da", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(15, 15, 15, 0.08)", + "md": "0 12px 32px rgba(15, 15, 15, 0.12)", + "lg": "0 24px 56px rgba(15, 15, 15, 0.16)", + "focus": "0 0 0 3px #EC5B2B40" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/oc-2-dark.json b/packages/ui/src/lib/theme/themes/oc-2-dark.json index b2ac6d3b..c2791829 100644 --- a/packages/ui/src/lib/theme/themes/oc-2-dark.json +++ b/packages/ui/src/lib/theme/themes/oc-2-dark.json @@ -2,79 +2,81 @@ "metadata": { "id": "oc-2-dark", "name": "OC-2", - "description": "Port of OpenCode OC-2 theme (dark variant)", + "description": "Ported from OpenCode OC-2 theme (dark variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "dark", "tags": [ "dark", "opencode", + "ported", "oc-2" ] }, "colors": { "primary": { - "base": "#e27618", + "base": "#fab283", "hover": "#f88524", - "active": "#f88524", + "active": "#1456f7", "foreground": "#000000", - "muted": "#e2761880", - "emphasis": "#f88524" + "muted": "#fab28380", + "emphasis": "#c0d4fb" }, "surface": { - "background": "#0c0c0c", + "background": "#121212", "foreground": "#f1ece8", - "muted": "#1b1b1a", + "muted": "#191919", "mutedForeground": "#cdc8c5", - "elevated": "#151414", + "elevated": "#1a1a1a", "elevatedForeground": "#f1ece8", - "overlay": "#00000080", - "subtle": "#232222" + "overlay": "#121212cc", + "subtle": "#282727" }, "interactive": { - "border": "#484746", - "borderHover": "#52504f", - "borderFocus": "#022fa6", - "selection": "#00207d", - "selectionForeground": "#ffffff", - "focus": "#022fa6", - "focusRing": "#022fa659", - "cursor": "#f1ece8", - "hover": "#232222", - "active": "#232222" + "border": "#4d4c4a", + "borderHover": "#565453", + "borderFocus": "#1456f7", + "selection": "#f1ece81f", + "selectionForeground": "#f1ece8", + "focus": "#1456f7", + "focusRing": "#1456f761", + "cursor": "#fefdfd", + "hover": "#f1ece817", + "active": "#f1ece81f" }, "status": { - "error": "#cb321c", - "errorForeground": "#ffffff", + "error": "#fc533a", + "errorForeground": "#151313", "errorBackground": "#5a0c03", "errorBorder": "#7a1608", - "warning": "#c78b05", - "warningForeground": "#ffffff", + "warning": "#fcd53a", + "warningForeground": "#151313", "warningBackground": "#382e05", "warningBorder": "#4e410b", - "success": "#089b00", - "successForeground": "#ffffff", + "success": "#12c905", + "successForeground": "#151313", "successBackground": "#083a05", "successBorder": "#10500d", - "info": "#cd73d5", - "infoForeground": "#ffffff", + "info": "#edb2f1", + "infoForeground": "#151313", "infoBackground": "#4d0853", "infoBorder": "#651b6c" }, "pr": { - "open": "#089b00", + "open": "#12c905", "draft": "#cdc8c5", - "blocked": "#c78b05", - "merged": "#edb2f1", - "closed": "#cb321c" + "blocked": "#fcd53a", + "merged": "#93e9f6", + "closed": "#fc533a" }, "syntax": { "base": { - "background": "#1b1b1a", + "background": "#1a1a1a", "foreground": "#f1ece8", "comment": "#8f8f8f", "keyword": "#edb2f1", "string": "#00ceb9", - "number": "#8cb0ff", + "number": "#93e9f6", "function": "#fab283", "variable": "#fefdfd", "type": "#fcd53a", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#8f8f8f", - "stringEscape": "#93e9f6", + "stringEscape": "#f1ece8", "keywordImport": "#edb2f1", "storageModifier": "#edb2f1", "functionCall": "#fab283", @@ -99,69 +101,308 @@ "struct": "#fcd53a", "enum": "#fcd53a", "typeParameter": "#fcd53a", - "namespace": "#edb2f1", + "namespace": "#fcd53a", "module": "#edb2f1", "tag": "#edb2f1", "jsxTag": "#edb2f1", "tagAttribute": "#fab283", "tagAttributeValue": "#00ceb9", - "boolean": "#8cb0ff", + "boolean": "#93e9f6", "decorator": "#edb2f1", - "label": "#edb2f1", + "label": "#fab283", "punctuation": "#cdc8c5", "macro": "#edb2f1", "preprocessor": "#edb2f1", "regex": "#f1ece8", - "url": "#cfdffd", + "url": "#c0d4fb", "key": "#fab283", - "exception": "#cb321c" + "exception": "#fc533a" }, "highlights": { "diffAdded": "#c4ffc0", - "diffAddedBackground": "#001401", - "diffRemoved": "#ec2f14", - "diffRemovedBackground": "#240200", + "diffAddedBackground": "#011d02", + "diffRemoved": "#fab283", + "diffRemovedBackground": "#310401", "diffModified": "#fde280", - "diffModifiedBackground": "#141c2c", + "diffModifiedBackground": "#151820", "lineNumber": "#afaca9", "lineNumberActive": "#f1ece8" } }, + "header": { + "background": "#121212", + "foreground": "#f1ece8", + "border": "#4d4c4a", + "icon": "#999794", + "hover": "#282727" + }, + "sidebar": { + "background": "#191919", + "foreground": "#cdc8c5", + "border": "#4d4c4a", + "icon": "#2c2c2b", + "hover": "#282727", + "active": "#00207d", + "accent": "#fab283", + "accentForeground": "#000000" + }, + "chat": { + "background": "#121212", + "userMessage": "#f1ece8", + "userMessageBackground": "#202020", + "assistantMessage": "#f1ece8", + "assistantMessageBackground": "#121212", + "timestamp": "#afaca9", + "divider": "#3b3a39", + "typing": "#cdc8c5" + }, "markdown": { "heading1": "#fed6bd", "heading2": "#fed6bd", - "heading3": "#f1ece8", + "heading3": "#fefdfd", "heading4": "#f1ece8", "link": "#cfdffd", "linkHover": "#facffe", "inlineCode": "#94fd8b", - "inlineCodeBackground": "#1b1b1a", + "inlineCodeBackground": "#202020", "blockquote": "#fde280", - "blockquoteBorder": "#484746", - "listMarker": "#cfdffd99" - }, - "chat": { - "userMessage": "#f1ece8", - "userMessageBackground": "#00207d", - "assistantMessage": "#f1ece8", - "assistantMessageBackground": "#0c0c0c", - "timestamp": "#cdc8c5", - "divider": "#484746" + "blockquoteBorder": "#4d4c4a", + "listMarker": "#cfdffd99", + "bold": "#facffe", + "italic": "#fde280", + "strikethrough": "#cdc8c5", + "hr": "#4d4c4a" }, "tools": { - "background": "#1b1b1a80", - "border": "#484746b3", - "headerHover": "#23222280", - "icon": "#cdc8c5", + "background": "#202020", + "border": "#3b3a39", + "headerHover": "#282727", + "icon": "#2c2c2b", "title": "#f1ece8", "description": "#cdc8c5", "edit": { "added": "#c4ffc0", - "addedBackground": "#001401", + "addedBackground": "#011d02", "removed": "#ec2f14", - "removedBackground": "#240200", + "removedBackground": "#310401", + "modified": "#fde280", + "modifiedBackground": "#151820", "lineNumber": "#afaca9" + }, + "bash": { + "background": "#1a1a1a", + "foreground": "#f1ece8", + "info": "#edb2f1", + "warning": "#fcd53a", + "error": "#fc533a" + }, + "lsp": { + "background": "#1a1a1a", + "foreground": "#f1ece8", + "info": "#edb2f1", + "warning": "#fcd53a", + "error": "#fc533a" } + }, + "forms": { + "inputBackground": "#151515", + "inputForeground": "#f1ece8", + "inputBorder": "#3b3a39", + "inputBorderHover": "#444342", + "inputBorderFocus": "#1456f7", + "inputPlaceholder": "#afaca9", + "inputDisabled": "#1d1d1d", + "inputSelection": "#0643da", + "label": "#cdc8c5", + "helperText": "#afaca9" + }, + "buttons": { + "primary": { + "bg": "#fab283", + "fg": "#000000", + "border": "#022fa6", + "hover": "#f88524", + "active": "#1456f7", + "disabled": "#444342" + }, + "secondary": { + "bg": "#1a1a1a", + "fg": "#f1ece8", + "border": "#4d4c4a", + "hover": "#202020", + "active": "#282727", + "disabled": "#1d1d1d" + }, + "ghost": { + "bg": "#00000000", + "fg": "#f1ece8", + "border": "#00000000", + "hover": "#202020", + "active": "#282727", + "disabled": "#afaca9" + }, + "destructive": { + "bg": "#fc533a", + "fg": "#151313", + "border": "#7a1608", + "hover": "#1F0603", + "active": "#cb321c", + "disabled": "#1d1d1d" + } + }, + "modal": { + "background": "#1a1a1a", + "foreground": "#f1ece8", + "border": "#4d4c4a", + "overlay": "#121212d6" + }, + "popover": { + "background": "#1a1a1a", + "foreground": "#f1ece8", + "border": "#4d4c4a", + "shadow": "0 18px 48px rgba(0, 0, 0, 0.45)" + }, + "commandPalette": { + "background": "#1a1a1a", + "foreground": "#f1ece8", + "border": "#4d4c4a", + "inputBackground": "#151515", + "selectedBackground": "#00207d", + "selectedForeground": "#f1ece8", + "muted": "#cdc8c5" + }, + "fileAttachment": { + "background": "#202020", + "foreground": "#f1ece8", + "border": "#3b3a39", + "icon": "#2c2c2b", + "removeHover": "#5a0c03" + }, + "sessions": { + "background": "#121212", + "foreground": "#f1ece8", + "mutedForeground": "#cdc8c5", + "border": "#323131", + "hover": "#282727", + "active": "#00207d" + }, + "modelSelector": { + "background": "#1a1a1a", + "foreground": "#f1ece8", + "border": "#4d4c4a", + "selectedBackground": "#00207d", + "selectedForeground": "#f1ece8" + }, + "permissions": { + "background": "#1a1a1a", + "foreground": "#f1ece8", + "border": "#4d4c4a", + "allow": "#12c905", + "allowBackground": "#083a05", + "deny": "#fc533a", + "denyBackground": "#5a0c03" + }, + "loading": { + "spinner": "#fab283", + "spinnerTrack": "#282727", + "skeleton": "#202020", + "shimmer": "#282727" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#f1ece833", + "thumbHover": "#f1ece857" + }, + "badges": { + "default": { + "bg": "#202020", + "fg": "#f1ece8", + "border": "#3b3a39" + }, + "info": { + "bg": "#4d0853", + "fg": "#edb2f1", + "border": "#651b6c" + }, + "success": { + "bg": "#083a05", + "fg": "#12c905", + "border": "#10500d" + }, + "warning": { + "bg": "#382e05", + "fg": "#fcd53a", + "border": "#4e410b" + }, + "error": { + "bg": "#5a0c03", + "fg": "#fc533a", + "border": "#7a1608" + } + }, + "toast": { + "background": "#1a1a1a", + "foreground": "#f1ece8", + "border": "#4d4c4a", + "success": { + "background": "#083a05", + "foreground": "#12c905", + "border": "#10500d" + }, + "warning": { + "background": "#382e05", + "foreground": "#fcd53a", + "border": "#4e410b" + }, + "error": { + "background": "#5a0c03", + "foreground": "#fc533a", + "border": "#7a1608" + }, + "info": { + "background": "#4d0853", + "foreground": "#edb2f1", + "border": "#651b6c" + } + }, + "emptyState": { + "icon": "#cdc8c5", + "title": "#f1ece8", + "description": "#cdc8c5", + "border": "#323131" + }, + "table": { + "border": "#323131", + "headerBackground": "#1a1a1a", + "headerForeground": "#f1ece8", + "rowHover": "#282727", + "rowSelected": "#00207d" + }, + "charts": { + "series": [ + "#fab283", + "#edb2f1", + "#12c905", + "#fcd53a", + "#fc533a" + ] + }, + "a11y": { + "focusRing": "#1456f7", + "selection": "#00207d", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(0, 0, 0, 0.22)", + "md": "0 12px 32px rgba(0, 0, 0, 0.32)", + "lg": "0 24px 56px rgba(0, 0, 0, 0.42)", + "focus": "0 0 0 3px #034cff59" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/oc-2-light.json b/packages/ui/src/lib/theme/themes/oc-2-light.json index cf074f03..a3563d02 100644 --- a/packages/ui/src/lib/theme/themes/oc-2-light.json +++ b/packages/ui/src/lib/theme/themes/oc-2-light.json @@ -2,79 +2,81 @@ "metadata": { "id": "oc-2-light", "name": "OC-2", - "description": "Port of OpenCode OC-2 theme (light variant)", + "description": "Ported from OpenCode OC-2 theme (light variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "light", "tags": [ "light", "opencode", + "ported", "oc-2" ] }, "colors": { "primary": { - "base": "#dddf79", + "base": "#dcde8d", "hover": "#d2d369", - "active": "#d2d369", + "active": "#054dfd", "foreground": "#000000", - "muted": "#dddf7980", - "emphasis": "#d2d369" + "muted": "#dcde8d80", + "emphasis": "#0445e6" }, "surface": { "background": "#f8f8f8", "foreground": "#161210", - "muted": "#ebebeb", + "muted": "#ededed", "mutedForeground": "#302c2a", "elevated": "#f1f1f1", "elevatedForeground": "#161210", - "overlay": "#0000004d", + "overlay": "#f8f8f833", "subtle": "#e2e2e2" }, "interactive": { "border": "#c1c0c0", "borderHover": "#b4b2b2", - "borderFocus": "#a3c1fd", - "selection": "#e0eafd", - "selectionForeground": "#000000", - "focus": "#a3c1fd", - "focusRing": "#a3c1fd47", - "cursor": "#161210", - "hover": "#e2e2e2", - "active": "#e2e2e2" + "borderFocus": "#054dfd", + "selection": "#16121016", + "selectionForeground": "#161210", + "focus": "#054dfd", + "focusRing": "#054dfd47", + "cursor": "#070504", + "hover": "#1612100e", + "active": "#16121016" }, "status": { - "error": "#fa3012", + "error": "#fc533a", "errorForeground": "#000000", "errorBackground": "#fde3de", "errorBorder": "#faaa9b", - "warning": "#f9b13f", + "warning": "#ffdc17", "warningForeground": "#000000", "warningBackground": "#feeb92", "warningBorder": "#dec025", - "success": "#2ce822", + "success": "#12c905", "successForeground": "#000000", "successBackground": "#bbffb4", "successBorder": "#2ce822", - "info": "#f39cf9", - "infoForeground": "#000000", + "info": "#a753ae", + "infoForeground": "#ffffff", "infoBackground": "#fcdffe", "infoBorder": "#f39cf9" }, "pr": { - "open": "#2ce822", + "open": "#12c905", "draft": "#302c2a", - "blocked": "#f9b13f", - "merged": "#a753ae", - "closed": "#fa3012" + "blocked": "#ffdc17", + "merged": "#007b80", + "closed": "#fc533a" }, "syntax": { "base": { - "background": "#ebebeb", + "background": "#f1f1f1", "foreground": "#161210", "comment": "#7a7a7a", "keyword": "#a753ae", "string": "#00ceb9", - "number": "#034cff", + "number": "#007b80", "function": "#a753ae", "variable": "#070504", "type": "#8a6f00", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#7a7a7a", - "stringEscape": "#007b80", + "stringEscape": "#161210", "keywordImport": "#a753ae", "storageModifier": "#a753ae", "functionCall": "#a753ae", @@ -90,7 +92,7 @@ "variableProperty": "#a753ae", "variableOther": "#070504", "variableGlobal": "#007b80", - "variableLocal": "#302c2a", + "variableLocal": "#161210", "parameter": "#070504", "constant": "#007b80", "class": "#8a6f00", @@ -99,38 +101,65 @@ "struct": "#8a6f00", "enum": "#8a6f00", "typeParameter": "#8a6f00", - "namespace": "#a753ae", + "namespace": "#8a6f00", "module": "#a753ae", "tag": "#a753ae", "jsxTag": "#a753ae", "tagAttribute": "#a753ae", "tagAttributeValue": "#00ceb9", - "boolean": "#034cff", + "boolean": "#007b80", "decorator": "#a753ae", "label": "#a753ae", "punctuation": "#161210", "macro": "#a753ae", "preprocessor": "#a753ae", "regex": "#161210", - "url": "#0040df", + "url": "#0445e6", "key": "#a753ae", - "exception": "#fa3012" + "exception": "#fc533a" }, "highlights": { "diffAdded": "#167517", - "diffAddedBackground": "#f9fff8", - "diffRemoved": "#fa3012", - "diffRemovedBackground": "#fffcfb", + "diffAddedBackground": "#efffee", + "diffRemoved": "#ff8c00", + "diffRemovedBackground": "#fef8f6", "diffModified": "#675912", - "diffModifiedBackground": "#dfe4f0", + "diffModifiedBackground": "#ebeef4", "lineNumber": "#494644", "lineNumberActive": "#161210" } }, + "header": { + "background": "#f8f8f8", + "foreground": "#161210", + "border": "#c1c0c0", + "icon": "#302c2a", + "hover": "#e2e2e2" + }, + "sidebar": { + "background": "#ededed", + "foreground": "#302c2a", + "border": "#c1c0c0", + "icon": "#c3c2c1", + "hover": "#e2e2e2", + "active": "#e0eafd", + "accent": "#dcde8d", + "accentForeground": "#000000" + }, + "chat": { + "background": "#f8f8f8", + "userMessage": "#161210", + "userMessageBackground": "#ebebeb", + "assistantMessage": "#161210", + "assistantMessageBackground": "#f8f8f8", + "timestamp": "#494644", + "divider": "#dcdcdb", + "typing": "#302c2a" + }, "markdown": { "heading1": "#5e5e11", "heading2": "#5e5e11", - "heading3": "#161210", + "heading3": "#070504", "heading4": "#161210", "link": "#0040df", "linkHover": "#8c1896", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#ebebeb", "blockquote": "#675912", "blockquoteBorder": "#c1c0c0", - "listMarker": "#0040df99" - }, - "chat": { - "userMessage": "#161210", - "userMessageBackground": "#e0eafd", - "assistantMessage": "#161210", - "assistantMessageBackground": "#f8f8f8", - "timestamp": "#302c2a", - "divider": "#c1c0c0" + "listMarker": "#0040df99", + "bold": "#8c1896", + "italic": "#675912", + "strikethrough": "#302c2a", + "hr": "#c1c0c0" }, "tools": { - "background": "#ebebeb80", - "border": "#c1c0c0b3", - "headerHover": "#e2e2e280", - "icon": "#302c2a", + "background": "#ebebeb", + "border": "#dcdcdb", + "headerHover": "#e2e2e2", + "icon": "#c3c2c1", "title": "#161210", "description": "#302c2a", "edit": { "added": "#167517", - "addedBackground": "#f9fff8", + "addedBackground": "#efffee", "removed": "#fa3012", - "removedBackground": "#fffcfb", + "removedBackground": "#fef8f6", + "modified": "#675912", + "modifiedBackground": "#ebeef4", "lineNumber": "#494644" + }, + "bash": { + "background": "#f1f1f1", + "foreground": "#161210", + "info": "#a753ae", + "warning": "#ffdc17", + "error": "#fc533a" + }, + "lsp": { + "background": "#f1f1f1", + "foreground": "#161210", + "info": "#a753ae", + "warning": "#ffdc17", + "error": "#fc533a" } + }, + "forms": { + "inputBackground": "#f8f8f8", + "inputForeground": "#161210", + "inputBorder": "#dcdcdb", + "inputBorderHover": "#cfcecd", + "inputBorderFocus": "#054dfd", + "inputPlaceholder": "#494644", + "inputDisabled": "#e6e6e6", + "inputSelection": "#e0eafd", + "label": "#302c2a", + "helperText": "#494644" + }, + "buttons": { + "primary": { + "bg": "#dcde8d", + "fg": "#000000", + "border": "#a3c1fd", + "hover": "#d2d369", + "active": "#054dfd", + "disabled": "#cac9c9" + }, + "secondary": { + "bg": "#f1f1f1", + "fg": "#161210", + "border": "#c1c0c0", + "hover": "#ebebeb", + "active": "#e2e2e2", + "disabled": "#e6e6e6" + }, + "ghost": { + "bg": "#00000000", + "fg": "#161210", + "border": "#00000000", + "hover": "#ebebeb", + "active": "#e2e2e2", + "disabled": "#494644" + }, + "destructive": { + "bg": "#fc533a", + "fg": "#000000", + "border": "#faaa9b", + "hover": "#FFF2F0", + "active": "#fb543c", + "disabled": "#e6e6e6" + } + }, + "modal": { + "background": "#f1f1f1", + "foreground": "#161210", + "border": "#c1c0c0", + "overlay": "#f8f8f83d" + }, + "popover": { + "background": "#f1f1f1", + "foreground": "#161210", + "border": "#c1c0c0", + "shadow": "0 18px 48px rgba(15, 15, 15, 0.16)" + }, + "commandPalette": { + "background": "#f1f1f1", + "foreground": "#161210", + "border": "#c1c0c0", + "inputBackground": "#f8f8f8", + "selectedBackground": "#e0eafd", + "selectedForeground": "#161210", + "muted": "#302c2a" + }, + "fileAttachment": { + "background": "#ebebeb", + "foreground": "#161210", + "border": "#dcdcdb", + "icon": "#c3c2c1", + "removeHover": "#fde3de" + }, + "sessions": { + "background": "#f8f8f8", + "foreground": "#161210", + "mutedForeground": "#302c2a", + "border": "#e5e5e5", + "hover": "#e2e2e2", + "active": "#e0eafd" + }, + "modelSelector": { + "background": "#f1f1f1", + "foreground": "#161210", + "border": "#c1c0c0", + "selectedBackground": "#e0eafd", + "selectedForeground": "#161210" + }, + "permissions": { + "background": "#f1f1f1", + "foreground": "#161210", + "border": "#c1c0c0", + "allow": "#12c905", + "allowBackground": "#bbffb4", + "deny": "#fc533a", + "denyBackground": "#fde3de" + }, + "loading": { + "spinner": "#dcde8d", + "spinnerTrack": "#e2e2e2", + "skeleton": "#ebebeb", + "shimmer": "#e2e2e2" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#16121026", + "thumbHover": "#16121040" + }, + "badges": { + "default": { + "bg": "#ebebeb", + "fg": "#161210", + "border": "#dcdcdb" + }, + "info": { + "bg": "#fcdffe", + "fg": "#a753ae", + "border": "#f39cf9" + }, + "success": { + "bg": "#bbffb4", + "fg": "#12c905", + "border": "#2ce822" + }, + "warning": { + "bg": "#feeb92", + "fg": "#ffdc17", + "border": "#dec025" + }, + "error": { + "bg": "#fde3de", + "fg": "#fc533a", + "border": "#faaa9b" + } + }, + "toast": { + "background": "#f1f1f1", + "foreground": "#161210", + "border": "#c1c0c0", + "success": { + "background": "#bbffb4", + "foreground": "#12c905", + "border": "#2ce822" + }, + "warning": { + "background": "#feeb92", + "foreground": "#ffdc17", + "border": "#dec025" + }, + "error": { + "background": "#fde3de", + "foreground": "#fc533a", + "border": "#faaa9b" + }, + "info": { + "background": "#fcdffe", + "foreground": "#a753ae", + "border": "#f39cf9" + } + }, + "emptyState": { + "icon": "#302c2a", + "title": "#161210", + "description": "#302c2a", + "border": "#e5e5e5" + }, + "table": { + "border": "#e5e5e5", + "headerBackground": "#f1f1f1", + "headerForeground": "#161210", + "rowHover": "#e2e2e2", + "rowSelected": "#e0eafd" + }, + "charts": { + "series": [ + "#dcde8d", + "#a753ae", + "#12c905", + "#ffdc17", + "#fc533a" + ] + }, + "a11y": { + "focusRing": "#054dfd", + "selection": "#e0eafd", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(15, 15, 15, 0.08)", + "md": "0 12px 32px rgba(15, 15, 15, 0.12)", + "lg": "0 24px 56px rgba(15, 15, 15, 0.16)", + "focus": "0 0 0 3px #034cff40" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/openchamber-dark.json b/packages/ui/src/lib/theme/themes/openchamber-dark.json new file mode 100644 index 00000000..8dd8f3ec --- /dev/null +++ b/packages/ui/src/lib/theme/themes/openchamber-dark.json @@ -0,0 +1,184 @@ +{ + "metadata": { + "id": "openchamber-dark", + "name": "OpenChamber", + "description": "OpenChamber brand theme - dark variant", + "author": "OpenChamber", + "version": "1.0.0", + "variant": "dark", + "tags": ["dark", "warm", "earthy", "brand"] + }, + "colors": { + "primary": { + "base": "#7a8a5a", + "hover": "#93a56b", + "active": "#a4b67d", + "foreground": "#0c0a08", + "muted": "#7a8a5a80", + "emphasis": "#93a56b" + }, + "surface": { + "background": "#1b1815", + "foreground": "#ebe0d1", + "muted": "#23201c", + "mutedForeground": "#83796f", + "elevated": "#2b2622", + "elevatedForeground": "#ebe0d1", + "overlay": "#1b1815cc", + "subtle": "#332d28" + }, + "interactive": { + "border": "#413e3a", + "borderHover": "#f0e6d830", + "borderFocus": "#373d2c", + "selection": "#f0e6d81f", + "selectionForeground": "#ebe0d1", + "focus": "#7a8a5a", + "focusRing": "#7a8a5a4d", + "cursor": "#ebe0d1", + "hover": "#332d28", + "active": "#f0e6d824" + }, + "status": { + "error": "#b34d3b", + "errorForeground": "#0c0a08", + "errorBackground": "#b85a4a20", + "errorBorder": "#b85a4a50", + "warning": "#c47a3a", + "warningForeground": "#0c0a08", + "warningBackground": "#c47a3a20", + "warningBorder": "#c47a3a50", + "success": "#7f905e", + "successForeground": "#0c0a08", + "successBackground": "#7a8a5a20", + "successBorder": "#7a8a5a50", + "info": "#667c8a", + "infoForeground": "#f0e6d8", + "infoBackground": "#5a6d7a20", + "infoBorder": "#5a6d7a50" + }, + "pr": { + "open": "#7a8a5a", + "draft": "#6a5e52", + "blocked": "#c47a3a", + "merged": "#5a6d7a", + "closed": "#b85a4a" + }, + "syntax": { + "base": { + "background": "#23201c", + "foreground": "#ebe0d1", + "comment": "#6a5e52", + "keyword": "#5a6d7a", + "string": "#93a56b", + "number": "#c47a3a", + "function": "#c47a3a", + "variable": "#ebe0d1", + "type": "#7a8a5a", + "operator": "#a89888" + }, + "tokens": { + "commentDoc": "#4a4238", + "stringEscape": "#ebe0d1", + "keywordImport": "#5a6d7a", + "storageModifier": "#5a6d7a", + "functionCall": "#c47a3a", + "method": "#93a56b", + "variableProperty": "#5a6d7a", + "variableOther": "#ebe0d1", + "variableGlobal": "#c47a3a", + "variableLocal": "#a89888", + "parameter": "#ebe0d1", + "constant": "#c47a3a", + "class": "#7a8a5a", + "className": "#7a8a5a", + "interface": "#7a8a5a", + "struct": "#7a8a5a", + "enum": "#7a8a5a", + "typeParameter": "#93a56b", + "namespace": "#5a6d7a", + "module": "#5a6d7a", + "tag": "#c47a3a", + "jsxTag": "#c47a3a", + "tagAttribute": "#93a56b", + "tagAttributeValue": "#93a56b", + "boolean": "#7a8a5a", + "decorator": "#5a6d7a", + "label": "#c47a3a", + "punctuation": "#a89888", + "macro": "#5a6d7a", + "preprocessor": "#5a6d7a", + "regex": "#93a56b", + "url": "#5a6d7a", + "key": "#c47a3a", + "exception": "#b85a4a" + }, + "highlights": { + "diffAdded": "#7a8a5a", + "diffAddedBackground": "#7a8a5a20", + "diffRemoved": "#b85a4a", + "diffRemovedBackground": "#b85a4a20", + "diffModified": "#5a6d7a", + "diffModifiedBackground": "#5a6d7a20", + "lineNumber": "#6a5e52", + "lineNumberActive": "#ebe0d1" + } + }, + "markdown": { + "heading1": "#c47a3a", + "heading2": "#93a56b", + "heading3": "#ebe0d1", + "heading4": "#ebe0d1", + "link": "#5a6d7a", + "linkHover": "#93a56b", + "inlineCode": "#93a56b", + "inlineCodeBackground": "#23201c", + "blockquote": "#a89888", + "blockquoteBorder": "#f0e6d830", + "listMarker": "#c47a3a99" + }, + "chat": { + "userMessage": "#ebe0d1", + "userMessageBackground": "#272a25", + "assistantMessage": "#ebe0d1", + "assistantMessageBackground": "#1b1815", + "timestamp": "#6a5e52", + "divider": "#f0e6d81c" + }, + "tools": { + "background": "#23201c80", + "border": "#f0e6d830", + "headerHover": "#2a252180", + "icon": "#a89888", + "title": "#ebe0d1", + "description": "#a19a96", + "edit": { + "added": "#7a8a5a", + "addedBackground": "#7a8a5a25", + "removed": "#b85a4a", + "removedBackground": "#b85a4a25", + "lineNumber": "#6a5e52" + } + } + }, + "config": { + "fonts": { + "sans": "\"IBM Plex Mono\", monospace", + "mono": "\"IBM Plex Mono\", monospace", + "heading": "\"IBM Plex Mono\", monospace" + }, + "radius": { + "none": "0", + "sm": "0.125rem", + "md": "0.375rem", + "lg": "0.5rem", + "xl": "0.75rem", + "full": "9999px" + }, + "transitions": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease" + } + } +} diff --git a/packages/ui/src/lib/theme/themes/openchamber-light.json b/packages/ui/src/lib/theme/themes/openchamber-light.json new file mode 100644 index 00000000..21b1937e --- /dev/null +++ b/packages/ui/src/lib/theme/themes/openchamber-light.json @@ -0,0 +1,184 @@ +{ + "metadata": { + "id": "openchamber-light", + "name": "OpenChamber", + "description": "OpenChamber brand theme - light variant", + "author": "OpenChamber", + "version": "1.0.0", + "variant": "light", + "tags": ["light", "warm", "earthy", "brand"] + }, + "colors": { + "primary": { + "base": "#4a6030", + "hover": "#5e773f", + "active": "#708a50", + "foreground": "#faf8f5", + "muted": "#4a603080", + "emphasis": "#5e773f" + }, + "surface": { + "background": "#f9f5eb", + "foreground": "#1a1612", + "muted": "#f4efe3", + "mutedForeground": "#5a5048", + "elevated": "#fcf9f0", + "elevatedForeground": "#1a1612", + "overlay": "#1a161220", + "subtle": "#efe8da" + }, + "interactive": { + "border": "#1a16121c", + "borderHover": "#1a161230", + "borderFocus": "#4a6030", + "selection": "#1a16121a", + "selectionForeground": "#1a1612", + "focus": "#4a6030", + "focusRing": "#4a603040", + "cursor": "#1a1612", + "hover": "#efe8da", + "active": "#1a16121f" + }, + "status": { + "error": "#a24d3f", + "errorForeground": "#faf8f5", + "errorBackground": "#a24d3f20", + "errorBorder": "#a24d3f50", + "warning": "#8c5520", + "warningForeground": "#faf8f5", + "warningBackground": "#8c552020", + "warningBorder": "#8c552050", + "success": "#4a6030", + "successForeground": "#faf8f5", + "successBackground": "#4a603020", + "successBorder": "#4a603050", + "info": "#3d4f5a", + "infoForeground": "#faf8f5", + "infoBackground": "#3d4f5a20", + "infoBorder": "#3d4f5a50" + }, + "pr": { + "open": "#4a6030", + "draft": "#8a7e72", + "blocked": "#8c5520", + "merged": "#3d4f5a", + "closed": "#a24d3f" + }, + "syntax": { + "base": { + "background": "#ece5d6", + "foreground": "#1a1612", + "comment": "#8a7e72", + "keyword": "#3d4f5a", + "string": "#5e773f", + "number": "#8c5520", + "function": "#8c5520", + "variable": "#1a1612", + "type": "#4a6030", + "operator": "#5a5048" + }, + "tokens": { + "commentDoc": "#b8b0a4", + "stringEscape": "#1a1612", + "keywordImport": "#3d4f5a", + "storageModifier": "#3d4f5a", + "functionCall": "#8c5520", + "method": "#5e773f", + "variableProperty": "#3d4f5a", + "variableOther": "#1a1612", + "variableGlobal": "#8c5520", + "variableLocal": "#5a5048", + "parameter": "#1a1612", + "constant": "#8c5520", + "class": "#4a6030", + "className": "#4a6030", + "interface": "#4a6030", + "struct": "#4a6030", + "enum": "#4a6030", + "typeParameter": "#5e773f", + "namespace": "#3d4f5a", + "module": "#3d4f5a", + "tag": "#8c5520", + "jsxTag": "#8c5520", + "tagAttribute": "#4a6030", + "tagAttributeValue": "#5e773f", + "boolean": "#4a6030", + "decorator": "#3d4f5a", + "label": "#8c5520", + "punctuation": "#5a5048", + "macro": "#3d4f5a", + "preprocessor": "#3d4f5a", + "regex": "#5e773f", + "url": "#3d4f5a", + "key": "#8c5520", + "exception": "#a24d3f" + }, + "highlights": { + "diffAdded": "#4a6030", + "diffAddedBackground": "#4a603020", + "diffRemoved": "#a24d3f", + "diffRemovedBackground": "#a24d3f20", + "diffModified": "#3d4f5a", + "diffModifiedBackground": "#3d4f5a20", + "lineNumber": "#8a7e72", + "lineNumberActive": "#1a1612" + } + }, + "markdown": { + "heading1": "#8c5520", + "heading2": "#4a6030", + "heading3": "#1a1612", + "heading4": "#1a1612", + "link": "#3d4f5a", + "linkHover": "#4a6030", + "inlineCode": "#4a6030", + "inlineCodeBackground": "#ece5d6", + "blockquote": "#5a5048", + "blockquoteBorder": "#1a161230", + "listMarker": "#8c552099" + }, + "chat": { + "userMessage": "#1a1612", + "userMessageBackground": "#efe8da", + "assistantMessage": "#1a1612", + "assistantMessageBackground": "#f9f5eb", + "timestamp": "#8a7e72", + "divider": "#1a16121c" + }, + "tools": { + "background": "#f4efe380", + "border": "#1a161230", + "headerHover": "#efe8da", + "icon": "#5a5048", + "title": "#1a1612", + "description": "#5a5048", + "edit": { + "added": "#4a6030", + "addedBackground": "#4a603025", + "removed": "#a24d3f", + "removedBackground": "#a24d3f25", + "lineNumber": "#8a7e72" + } + } + }, + "config": { + "fonts": { + "sans": "\"IBM Plex Mono\", monospace", + "mono": "\"IBM Plex Mono\", monospace", + "heading": "\"IBM Plex Mono\", monospace" + }, + "radius": { + "none": "0", + "sm": "0.125rem", + "md": "0.375rem", + "lg": "0.5rem", + "xl": "0.75rem", + "full": "9999px" + }, + "transitions": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease" + } + } +} diff --git a/packages/ui/src/lib/theme/themes/orng-dark.json b/packages/ui/src/lib/theme/themes/orng-dark.json index 0e321670..a459601e 100644 --- a/packages/ui/src/lib/theme/themes/orng-dark.json +++ b/packages/ui/src/lib/theme/themes/orng-dark.json @@ -2,79 +2,81 @@ "metadata": { "id": "orng-dark", "name": "Orng", - "description": "Port of OpenCode Orng theme (dark variant)", + "description": "Ported from OpenCode Orng theme (dark variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "dark", "tags": [ "dark", "opencode", + "ported", "orng" ] }, "colors": { "primary": { - "base": "#be3c07", + "base": "#EC5B2B", "hover": "#da4f1f", - "active": "#da4f1f", - "foreground": "#ffffff", - "muted": "#be3c0780", - "emphasis": "#da4f1f" + "active": "#be3c07", + "foreground": "#151313", + "muted": "#EC5B2B80", + "emphasis": "#fdc4b3" }, "surface": { "background": "#050505", "foreground": "#eeeeee", - "muted": "#141414", + "muted": "#0b0b0b", "mutedForeground": "#808080", "elevated": "#0e0e0e", "elevatedForeground": "#eeeeee", - "overlay": "#00000080", + "overlay": "#050505cc", "subtle": "#1c1c1c" }, "interactive": { "border": "#434343", "borderHover": "#4c4c4c", - "borderFocus": "#752101", - "selection": "#531906", - "selectionForeground": "#ffffff", - "focus": "#752101", - "focusRing": "#75210159", - "cursor": "#eeeeee", - "hover": "#1c1c1c", - "active": "#1c1c1c" + "borderFocus": "#be3c07", + "selection": "#eeeeee1f", + "selectionForeground": "#eeeeee", + "focus": "#be3c07", + "focusRing": "#be3c0761", + "cursor": "#fdfdfd", + "hover": "#eeeeee17", + "active": "#eeeeee1f" }, "status": { - "error": "#ce2245", - "errorForeground": "#ffffff", + "error": "#e06c75", + "errorForeground": "#151313", "errorBackground": "#5c0318", "errorBorder": "#7c0a25", - "warning": "#c51d33", - "warningForeground": "#ffffff", + "warning": "#EC5B2B", + "warningForeground": "#151313", "warningBackground": "#531906", "warningBorder": "#752101", - "success": "#1277e2", - "successForeground": "#ffffff", + "success": "#6ba1e6", + "successForeground": "#151313", "successBackground": "#042e5d", "successBorder": "#09417d", - "info": "#228f9b", - "infoForeground": "#ffffff", + "info": "#56b6c2", + "infoForeground": "#151313", "infoBackground": "#05363b", "infoBorder": "#0d4b51" }, "pr": { - "open": "#1277e2", + "open": "#6ba1e6", "draft": "#808080", - "blocked": "#c51d33", - "merged": "#EC5B2B", - "closed": "#ce2245" + "blocked": "#EC5B2B", + "merged": "#FFF7F1", + "closed": "#e06c75" }, "syntax": { "base": { - "background": "#141414", + "background": "#0e0e0e", "foreground": "#eeeeee", "comment": "#808080", "keyword": "#EC5B2B", "string": "#6ba1e6", - "number": "#EE7948", + "number": "#FFF7F1", "function": "#56b6c2", "variable": "#e06c75", "type": "#e5c07b", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#808080", - "stringEscape": "#FFF7F1", + "stringEscape": "#eeeeee", "keywordImport": "#EC5B2B", "storageModifier": "#EC5B2B", "functionCall": "#56b6c2", @@ -90,7 +92,7 @@ "variableProperty": "#56b6c2", "variableOther": "#e06c75", "variableGlobal": "#FFF7F1", - "variableLocal": "#808080", + "variableLocal": "#eeeeee", "parameter": "#e06c75", "constant": "#FFF7F1", "class": "#e5c07b", @@ -99,38 +101,65 @@ "struct": "#e5c07b", "enum": "#e5c07b", "typeParameter": "#e5c07b", - "namespace": "#EC5B2B", + "namespace": "#e5c07b", "module": "#EC5B2B", "tag": "#EC5B2B", "jsxTag": "#EC5B2B", "tagAttribute": "#56b6c2", "tagAttributeValue": "#6ba1e6", - "boolean": "#EE7948", + "boolean": "#FFF7F1", "decorator": "#EC5B2B", - "label": "#EC5B2B", + "label": "#56b6c2", "punctuation": "#eeeeee", "macro": "#EC5B2B", "preprocessor": "#EC5B2B", "regex": "#eeeeee", - "url": "#EC5B2B", + "url": "#fdc4b3", "key": "#56b6c2", - "exception": "#ce2245" + "exception": "#e06c75" }, "highlights": { "diffAdded": "#b8d6fe", - "diffAddedBackground": "#010e24", - "diffRemoved": "#e92b53", - "diffRemovedBackground": "#230106", + "diffAddedBackground": "#021631", + "diffRemoved": "#fec2c4", + "diffRemovedBackground": "#30030a", "diffModified": "#ffba92", - "diffModifiedBackground": "#281a16", + "diffModifiedBackground": "#150e0c", "lineNumber": "#5d5d5d", "lineNumberActive": "#eeeeee" } }, + "header": { + "background": "#050505", + "foreground": "#eeeeee", + "border": "#434343", + "icon": "#919191", + "hover": "#1c1c1c" + }, + "sidebar": { + "background": "#0b0b0b", + "foreground": "#808080", + "border": "#434343", + "icon": "#1e1e1e", + "hover": "#1c1c1c", + "active": "#531906", + "accent": "#EC5B2B", + "accentForeground": "#151313" + }, + "chat": { + "background": "#050505", + "userMessage": "#eeeeee", + "userMessageBackground": "#141414", + "assistantMessage": "#eeeeee", + "assistantMessageBackground": "#050505", + "timestamp": "#5d5d5d", + "divider": "#303030", + "typing": "#808080" + }, "markdown": { "heading1": "#EC5B2B", "heading2": "#EC5B2B", - "heading3": "#eeeeee", + "heading3": "#fdfdfd", "heading4": "#eeeeee", "link": "#EC5B2B", "linkHover": "#56b6c2", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#141414", "blockquote": "#FFF7F1", "blockquoteBorder": "#434343", - "listMarker": "#EC5B2B99" - }, - "chat": { - "userMessage": "#eeeeee", - "userMessageBackground": "#531906", - "assistantMessage": "#eeeeee", - "assistantMessageBackground": "#050505", - "timestamp": "#808080", - "divider": "#434343" + "listMarker": "#EC5B2B99", + "bold": "#EE7948", + "italic": "#e5c07b", + "strikethrough": "#808080", + "hr": "#808080" }, "tools": { - "background": "#14141480", - "border": "#434343b3", - "headerHover": "#1c1c1c80", - "icon": "#808080", + "background": "#141414", + "border": "#303030", + "headerHover": "#1c1c1c", + "icon": "#1e1e1e", "title": "#eeeeee", "description": "#808080", "edit": { "added": "#b8d6fe", - "addedBackground": "#010e24", + "addedBackground": "#021631", "removed": "#e92b53", - "removedBackground": "#230106", + "removedBackground": "#30030a", + "modified": "#ffba92", + "modifiedBackground": "#150e0c", "lineNumber": "#5d5d5d" + }, + "bash": { + "background": "#0e0e0e", + "foreground": "#eeeeee", + "info": "#56b6c2", + "warning": "#EC5B2B", + "error": "#e06c75" + }, + "lsp": { + "background": "#0e0e0e", + "foreground": "#eeeeee", + "info": "#56b6c2", + "warning": "#EC5B2B", + "error": "#e06c75" } + }, + "forms": { + "inputBackground": "#070707", + "inputForeground": "#eeeeee", + "inputBorder": "#303030", + "inputBorderHover": "#393939", + "inputBorderFocus": "#be3c07", + "inputPlaceholder": "#5d5d5d", + "inputDisabled": "#0f0f0f", + "inputSelection": "#9b3108", + "label": "#808080", + "helperText": "#5d5d5d" + }, + "buttons": { + "primary": { + "bg": "#EC5B2B", + "fg": "#151313", + "border": "#752101", + "hover": "#da4f1f", + "active": "#be3c07", + "disabled": "#393939" + }, + "secondary": { + "bg": "#0e0e0e", + "fg": "#eeeeee", + "border": "#434343", + "hover": "#141414", + "active": "#1c1c1c", + "disabled": "#0f0f0f" + }, + "ghost": { + "bg": "#00000000", + "fg": "#eeeeee", + "border": "#00000000", + "hover": "#141414", + "active": "#1c1c1c", + "disabled": "#5d5d5d" + }, + "destructive": { + "bg": "#e06c75", + "fg": "#151313", + "border": "#7c0a25", + "hover": "#7c0a25", + "active": "#ce2245", + "disabled": "#0f0f0f" + } + }, + "modal": { + "background": "#0e0e0e", + "foreground": "#eeeeee", + "border": "#434343", + "overlay": "#050505d6" + }, + "popover": { + "background": "#0e0e0e", + "foreground": "#eeeeee", + "border": "#434343", + "shadow": "0 18px 48px rgba(0, 0, 0, 0.45)" + }, + "commandPalette": { + "background": "#0e0e0e", + "foreground": "#eeeeee", + "border": "#434343", + "inputBackground": "#070707", + "selectedBackground": "#531906", + "selectedForeground": "#eeeeee", + "muted": "#808080" + }, + "fileAttachment": { + "background": "#141414", + "foreground": "#eeeeee", + "border": "#303030", + "icon": "#1e1e1e", + "removeHover": "#5c0318" + }, + "sessions": { + "background": "#050505", + "foreground": "#eeeeee", + "mutedForeground": "#808080", + "border": "#272727", + "hover": "#1c1c1c", + "active": "#531906" + }, + "modelSelector": { + "background": "#0e0e0e", + "foreground": "#eeeeee", + "border": "#434343", + "selectedBackground": "#531906", + "selectedForeground": "#eeeeee" + }, + "permissions": { + "background": "#0e0e0e", + "foreground": "#eeeeee", + "border": "#434343", + "allow": "#6ba1e6", + "allowBackground": "#042e5d", + "deny": "#e06c75", + "denyBackground": "#5c0318" + }, + "loading": { + "spinner": "#EC5B2B", + "spinnerTrack": "#1c1c1c", + "skeleton": "#141414", + "shimmer": "#1c1c1c" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#eeeeee33", + "thumbHover": "#eeeeee57" + }, + "badges": { + "default": { + "bg": "#141414", + "fg": "#eeeeee", + "border": "#303030" + }, + "info": { + "bg": "#05363b", + "fg": "#56b6c2", + "border": "#0d4b51" + }, + "success": { + "bg": "#042e5d", + "fg": "#6ba1e6", + "border": "#09417d" + }, + "warning": { + "bg": "#531906", + "fg": "#EC5B2B", + "border": "#752101" + }, + "error": { + "bg": "#5c0318", + "fg": "#e06c75", + "border": "#7c0a25" + } + }, + "toast": { + "background": "#0e0e0e", + "foreground": "#eeeeee", + "border": "#434343", + "success": { + "background": "#042e5d", + "foreground": "#6ba1e6", + "border": "#09417d" + }, + "warning": { + "background": "#531906", + "foreground": "#EC5B2B", + "border": "#752101" + }, + "error": { + "background": "#5c0318", + "foreground": "#e06c75", + "border": "#7c0a25" + }, + "info": { + "background": "#05363b", + "foreground": "#56b6c2", + "border": "#0d4b51" + } + }, + "emptyState": { + "icon": "#808080", + "title": "#eeeeee", + "description": "#808080", + "border": "#272727" + }, + "table": { + "border": "#272727", + "headerBackground": "#0e0e0e", + "headerForeground": "#eeeeee", + "rowHover": "#1c1c1c", + "rowSelected": "#531906" + }, + "charts": { + "series": [ + "#EC5B2B", + "#56b6c2", + "#6ba1e6", + "#EC5B2B", + "#e06c75" + ] + }, + "a11y": { + "focusRing": "#be3c07", + "selection": "#531906", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(0, 0, 0, 0.22)", + "md": "0 12px 32px rgba(0, 0, 0, 0.32)", + "lg": "0 24px 56px rgba(0, 0, 0, 0.42)", + "focus": "0 0 0 3px #EC5B2B59" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/orng-light.json b/packages/ui/src/lib/theme/themes/orng-light.json index d3bf48ff..2518cf45 100644 --- a/packages/ui/src/lib/theme/themes/orng-light.json +++ b/packages/ui/src/lib/theme/themes/orng-light.json @@ -2,79 +2,81 @@ "metadata": { "id": "orng-light", "name": "Orng", - "description": "Port of OpenCode Orng theme (light variant)", + "description": "Ported from OpenCode Orng theme (light variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "light", "tags": [ "light", "opencode", + "ported", "orng" ] }, "colors": { "primary": { - "base": "#f45214", + "base": "#EC5B2B", "hover": "#e14d17", - "active": "#e14d17", + "active": "#f45214", "foreground": "#000000", - "muted": "#f4521480", + "muted": "#EC5B2B80", "emphasis": "#e14d17" }, "surface": { "background": "#ffffff", "foreground": "#181818", - "muted": "#f2f2f2", + "muted": "#f4f4f4", "mutedForeground": "#8a8a8a", "elevated": "#f8f8f8", "elevatedForeground": "#181818", - "overlay": "#0000004d", + "overlay": "#ffffff33", "subtle": "#e9e9e9" }, "interactive": { "border": "#c7c7c7", "borderHover": "#b9b9b9", - "borderFocus": "#fea88e", - "selection": "#ffe3da", - "selectionForeground": "#000000", - "focus": "#fea88e", - "focusRing": "#fea88e47", - "cursor": "#181818", - "hover": "#e9e9e9", - "active": "#e9e9e9" + "borderFocus": "#f45214", + "selection": "#18181816", + "selectionForeground": "#181818", + "focus": "#f45214", + "focusRing": "#f4521447", + "cursor": "#090909", + "hover": "#1818180e", + "active": "#18181816" }, "status": { - "error": "#ce0727", - "errorForeground": "#000000", + "error": "#d1383d", + "errorForeground": "#ffffff", "errorBackground": "#fde3e0", "errorBorder": "#faa8a3", - "warning": "#fca6ab", + "warning": "#EC5B2B", "warningForeground": "#000000", "warningBackground": "#ffe3da", "warningBorder": "#fea88e", - "success": "#9ec3fa", - "successForeground": "#000000", + "success": "#0062d1", + "successForeground": "#ffffff", "successBackground": "#deebfe", "successBorder": "#9ec3fa", - "info": "#77d1e1", + "info": "#318795", "infoForeground": "#000000", "infoBackground": "#bff5ff", "infoBorder": "#77d1e1" }, "pr": { - "open": "#9ec3fa", + "open": "#0062d1", "draft": "#8a8a8a", - "blocked": "#fca6ab", + "blocked": "#EC5B2B", "merged": "#EC5B2B", - "closed": "#ce0727" + "closed": "#d1383d" }, "syntax": { "base": { - "background": "#f2f2f2", + "background": "#f8f8f8", "foreground": "#181818", "comment": "#8a8a8a", "keyword": "#EC5B2B", "string": "#0062d1", - "number": "#c94d24", + "number": "#EC5B2B", "function": "#318795", "variable": "#d1383d", "type": "#b0851f", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#8a8a8a", - "stringEscape": "#EC5B2B", + "stringEscape": "#181818", "keywordImport": "#EC5B2B", "storageModifier": "#EC5B2B", "functionCall": "#318795", @@ -90,7 +92,7 @@ "variableProperty": "#318795", "variableOther": "#d1383d", "variableGlobal": "#EC5B2B", - "variableLocal": "#8a8a8a", + "variableLocal": "#1a1a1a", "parameter": "#d1383d", "constant": "#EC5B2B", "class": "#b0851f", @@ -99,38 +101,65 @@ "struct": "#b0851f", "enum": "#b0851f", "typeParameter": "#b0851f", - "namespace": "#EC5B2B", + "namespace": "#b0851f", "module": "#EC5B2B", "tag": "#EC5B2B", "jsxTag": "#EC5B2B", "tagAttribute": "#318795", "tagAttributeValue": "#0062d1", - "boolean": "#c94d24", + "boolean": "#EC5B2B", "decorator": "#EC5B2B", - "label": "#EC5B2B", + "label": "#318795", "punctuation": "#1a1a1a", "macro": "#EC5B2B", "preprocessor": "#EC5B2B", "regex": "#181818", - "url": "#EC5B2B", + "url": "#e14d17", "key": "#318795", - "exception": "#ce0727" + "exception": "#d1383d" }, "highlights": { "diffAdded": "#2f60a4", - "diffAddedBackground": "#fbfdff", - "diffRemoved": "#e9055a", - "diffRemovedBackground": "#fffcfc", + "diffAddedBackground": "#f6faff", + "diffRemoved": "#ae1a45", + "diffRemovedBackground": "#fef7f8", "diffModified": "#FF8C00", - "diffModifiedBackground": "#f9eeeb", + "diffModifiedBackground": "#fcf7f5", "lineNumber": "#afafaf", "lineNumberActive": "#181818" } }, + "header": { + "background": "#ffffff", + "foreground": "#181818", + "border": "#c7c7c7", + "icon": "#323232", + "hover": "#e9e9e9" + }, + "sidebar": { + "background": "#f4f4f4", + "foreground": "#8a8a8a", + "border": "#c7c7c7", + "icon": "#c9c9c9", + "hover": "#e9e9e9", + "active": "#ffe3da", + "accent": "#EC5B2B", + "accentForeground": "#000000" + }, + "chat": { + "background": "#ffffff", + "userMessage": "#181818", + "userMessageBackground": "#f2f2f2", + "assistantMessage": "#181818", + "assistantMessageBackground": "#ffffff", + "timestamp": "#afafaf", + "divider": "#e3e3e3", + "typing": "#8a8a8a" + }, "markdown": { "heading1": "#EC5B2B", "heading2": "#EC5B2B", - "heading3": "#181818", + "heading3": "#090909", "heading4": "#181818", "link": "#EC5B2B", "linkHover": "#318795", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#f2f2f2", "blockquote": "#b0851f", "blockquoteBorder": "#c7c7c7", - "listMarker": "#EC5B2B99" - }, - "chat": { - "userMessage": "#181818", - "userMessageBackground": "#ffe3da", - "assistantMessage": "#181818", - "assistantMessageBackground": "#ffffff", - "timestamp": "#8a8a8a", - "divider": "#c7c7c7" + "listMarker": "#EC5B2B99", + "bold": "#EC5B2B", + "italic": "#b0851f", + "strikethrough": "#8a8a8a", + "hr": "#8a8a8a" }, "tools": { - "background": "#f2f2f280", - "border": "#c7c7c7b3", - "headerHover": "#e9e9e980", - "icon": "#8a8a8a", + "background": "#f2f2f2", + "border": "#e3e3e3", + "headerHover": "#e9e9e9", + "icon": "#c9c9c9", "title": "#181818", "description": "#8a8a8a", "edit": { "added": "#2f60a4", - "addedBackground": "#fbfdff", + "addedBackground": "#f6faff", "removed": "#e9055a", - "removedBackground": "#fffcfc", + "removedBackground": "#fef7f8", + "modified": "#FF8C00", + "modifiedBackground": "#fcf7f5", "lineNumber": "#afafaf" + }, + "bash": { + "background": "#f8f8f8", + "foreground": "#181818", + "info": "#318795", + "warning": "#EC5B2B", + "error": "#d1383d" + }, + "lsp": { + "background": "#f8f8f8", + "foreground": "#181818", + "info": "#318795", + "warning": "#EC5B2B", + "error": "#d1383d" } + }, + "forms": { + "inputBackground": "#ffffff", + "inputForeground": "#181818", + "inputBorder": "#e3e3e3", + "inputBorderHover": "#d5d5d5", + "inputBorderFocus": "#f45214", + "inputPlaceholder": "#afafaf", + "inputDisabled": "#ededed", + "inputSelection": "#ffe3da", + "label": "#8a8a8a", + "helperText": "#afafaf" + }, + "buttons": { + "primary": { + "bg": "#EC5B2B", + "fg": "#000000", + "border": "#fea88e", + "hover": "#e14d17", + "active": "#f45214", + "disabled": "#d0d0d0" + }, + "secondary": { + "bg": "#f8f8f8", + "fg": "#181818", + "border": "#c7c7c7", + "hover": "#f2f2f2", + "active": "#e9e9e9", + "disabled": "#ededed" + }, + "ghost": { + "bg": "#00000000", + "fg": "#181818", + "border": "#00000000", + "hover": "#f2f2f2", + "active": "#e9e9e9", + "disabled": "#afafaf" + }, + "destructive": { + "bg": "#d1383d", + "fg": "#ffffff", + "border": "#faa8a3", + "hover": "#fdd5d2", + "active": "#e1032b", + "disabled": "#ededed" + } + }, + "modal": { + "background": "#f8f8f8", + "foreground": "#181818", + "border": "#c7c7c7", + "overlay": "#ffffff3d" + }, + "popover": { + "background": "#f8f8f8", + "foreground": "#181818", + "border": "#c7c7c7", + "shadow": "0 18px 48px rgba(15, 15, 15, 0.16)" + }, + "commandPalette": { + "background": "#f8f8f8", + "foreground": "#181818", + "border": "#c7c7c7", + "inputBackground": "#ffffff", + "selectedBackground": "#ffe3da", + "selectedForeground": "#181818", + "muted": "#8a8a8a" + }, + "fileAttachment": { + "background": "#f2f2f2", + "foreground": "#181818", + "border": "#e3e3e3", + "icon": "#c9c9c9", + "removeHover": "#fde3e0" + }, + "sessions": { + "background": "#ffffff", + "foreground": "#181818", + "mutedForeground": "#8a8a8a", + "border": "#ececec", + "hover": "#e9e9e9", + "active": "#ffe3da" + }, + "modelSelector": { + "background": "#f8f8f8", + "foreground": "#181818", + "border": "#c7c7c7", + "selectedBackground": "#ffe3da", + "selectedForeground": "#181818" + }, + "permissions": { + "background": "#f8f8f8", + "foreground": "#181818", + "border": "#c7c7c7", + "allow": "#0062d1", + "allowBackground": "#deebfe", + "deny": "#d1383d", + "denyBackground": "#fde3e0" + }, + "loading": { + "spinner": "#EC5B2B", + "spinnerTrack": "#e9e9e9", + "skeleton": "#f2f2f2", + "shimmer": "#e9e9e9" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#18181826", + "thumbHover": "#18181840" + }, + "badges": { + "default": { + "bg": "#f2f2f2", + "fg": "#181818", + "border": "#e3e3e3" + }, + "info": { + "bg": "#bff5ff", + "fg": "#318795", + "border": "#77d1e1" + }, + "success": { + "bg": "#deebfe", + "fg": "#0062d1", + "border": "#9ec3fa" + }, + "warning": { + "bg": "#ffe3da", + "fg": "#EC5B2B", + "border": "#fea88e" + }, + "error": { + "bg": "#fde3e0", + "fg": "#d1383d", + "border": "#faa8a3" + } + }, + "toast": { + "background": "#f8f8f8", + "foreground": "#181818", + "border": "#c7c7c7", + "success": { + "background": "#deebfe", + "foreground": "#0062d1", + "border": "#9ec3fa" + }, + "warning": { + "background": "#ffe3da", + "foreground": "#EC5B2B", + "border": "#fea88e" + }, + "error": { + "background": "#fde3e0", + "foreground": "#d1383d", + "border": "#faa8a3" + }, + "info": { + "background": "#bff5ff", + "foreground": "#318795", + "border": "#77d1e1" + } + }, + "emptyState": { + "icon": "#8a8a8a", + "title": "#181818", + "description": "#8a8a8a", + "border": "#ececec" + }, + "table": { + "border": "#ececec", + "headerBackground": "#f8f8f8", + "headerForeground": "#181818", + "rowHover": "#e9e9e9", + "rowSelected": "#ffe3da" + }, + "charts": { + "series": [ + "#EC5B2B", + "#318795", + "#0062d1", + "#EC5B2B", + "#d1383d" + ] + }, + "a11y": { + "focusRing": "#f45214", + "selection": "#ffe3da", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(15, 15, 15, 0.08)", + "md": "0 12px 32px rgba(15, 15, 15, 0.12)", + "lg": "0 24px 56px rgba(15, 15, 15, 0.16)", + "focus": "0 0 0 3px #EC5B2B40" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/presets.ts b/packages/ui/src/lib/theme/themes/presets.ts index 3cbd7755..9f83165a 100644 --- a/packages/ui/src/lib/theme/themes/presets.ts +++ b/packages/ui/src/lib/theme/themes/presets.ts @@ -31,6 +31,8 @@ import nord_dark_Raw from './nord-dark.json'; import nord_light_Raw from './nord-light.json'; import oc_2_dark_Raw from './oc-2-dark.json'; import oc_2_light_Raw from './oc-2-light.json'; +import openchamber_dark_Raw from './openchamber-dark.json'; +import openchamber_light_Raw from './openchamber-light.json'; import onedarkpro_dark_Raw from './onedarkpro-dark.json'; import onedarkpro_light_Raw from './onedarkpro-light.json'; import orng_dark_Raw from './orng-dark.json'; @@ -57,6 +59,8 @@ import vitesse_dark_dark_Raw from './vitesse-dark-dark.json'; import vitesse_light_light_Raw from './vitesse-light-light.json'; export const presetThemes: Theme[] = [ + openchamber_dark_Raw as Theme, + openchamber_light_Raw as Theme, amoled_dark_Raw as Theme, amoled_light_Raw as Theme, aura_dark_Raw as Theme, diff --git a/packages/ui/src/lib/theme/themes/rosepine-dark.json b/packages/ui/src/lib/theme/themes/rosepine-dark.json index 1466919d..26b95177 100644 --- a/packages/ui/src/lib/theme/themes/rosepine-dark.json +++ b/packages/ui/src/lib/theme/themes/rosepine-dark.json @@ -2,79 +2,81 @@ "metadata": { "id": "rosepine-dark", "name": "Rose Pine", - "description": "Port of OpenCode Rose Pine theme (dark variant)", + "description": "Ported from OpenCode Rose Pine theme (dark variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "dark", "tags": [ "dark", "opencode", + "ported", "rosepine" ] }, "colors": { "primary": { - "base": "#51a6b4", + "base": "#9ccfd8", "hover": "#5db8c7", - "active": "#5db8c7", + "active": "#51a6b4", "foreground": "#000000", - "muted": "#51a6b480", - "emphasis": "#5db8c7" + "muted": "#9ccfd880", + "emphasis": "#8be4f3" }, "surface": { "background": "#0c0a16", "foreground": "#e0def5", - "muted": "#1a1824", + "muted": "#12101d", "mutedForeground": "#6e6a86", "elevated": "#14121e", "elevatedForeground": "#e0def5", - "overlay": "#00000080", + "overlay": "#0c0a16cc", "subtle": "#211f2c" }, "interactive": { "border": "#444251", "borderHover": "#4c4a59", - "borderFocus": "#0d4a53", - "selection": "#06353c", - "selectionForeground": "#ffffff", - "focus": "#0d4a53", - "focusRing": "#0d4a5359", - "cursor": "#e0def5", - "hover": "#211f2c", - "active": "#211f2c" + "borderFocus": "#51a6b4", + "selection": "#e0def51f", + "selectionForeground": "#e0def5", + "focus": "#51a6b4", + "focusRing": "#51a6b461", + "cursor": "#fcfcfe", + "hover": "#e0def517", + "active": "#e0def51f" }, "status": { - "error": "#d81b69", - "errorForeground": "#ffffff", + "error": "#eb6f92", + "errorForeground": "#151313", "errorBackground": "#590628", "errorBorder": "#780f39", - "warning": "#cc7520", - "warningForeground": "#ffffff", + "warning": "#f6c177", + "warningForeground": "#151313", "warningBackground": "#402a06", "warningBorder": "#5a3a01", - "success": "#0c7699", + "success": "#31748f", "successForeground": "#ffffff", "successBackground": "#023446", "successBorder": "#06495f", - "info": "#51a6b4", - "infoForeground": "#ffffff", + "info": "#9ccfd8", + "infoForeground": "#151313", "infoBackground": "#06353c", "infoBorder": "#0d4a53" }, "pr": { - "open": "#0c7699", + "open": "#31748f", "draft": "#6e6a86", - "blocked": "#cc7520", - "merged": "#31748f", - "closed": "#d81b69" + "blocked": "#f6c177", + "merged": "#c4a7e7", + "closed": "#eb6f92" }, "syntax": { "base": { - "background": "#1a1824", + "background": "#14121e", "foreground": "#e0def5", "comment": "#6e6a86", "keyword": "#31748f", "string": "#f6c177", - "number": "#ebbcba", + "number": "#c4a7e7", "function": "#ebbcba", "variable": "#e0def4", "type": "#9ccfd8", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#6e6a86", - "stringEscape": "#c4a7e7", + "stringEscape": "#e0def5", "keywordImport": "#31748f", "storageModifier": "#31748f", "functionCall": "#ebbcba", @@ -90,7 +92,7 @@ "variableProperty": "#ebbcba", "variableOther": "#e0def4", "variableGlobal": "#c4a7e7", - "variableLocal": "#6e6a86", + "variableLocal": "#908caa", "parameter": "#e0def4", "constant": "#c4a7e7", "class": "#9ccfd8", @@ -99,38 +101,65 @@ "struct": "#9ccfd8", "enum": "#9ccfd8", "typeParameter": "#9ccfd8", - "namespace": "#31748f", + "namespace": "#9ccfd8", "module": "#31748f", "tag": "#31748f", "jsxTag": "#31748f", "tagAttribute": "#ebbcba", "tagAttributeValue": "#f6c177", - "boolean": "#ebbcba", + "boolean": "#c4a7e7", "decorator": "#31748f", - "label": "#31748f", + "label": "#ebbcba", "punctuation": "#908caa", "macro": "#31748f", "preprocessor": "#31748f", "regex": "#e0def5", - "url": "#9ccfd8", + "url": "#8be4f3", "key": "#ebbcba", - "exception": "#d81b69" + "exception": "#eb6f92" }, "highlights": { "diffAdded": "#9bdffd", - "diffAddedBackground": "#011119", - "diffRemoved": "#e13474", - "diffRemovedBackground": "#23000b", + "diffAddedBackground": "#021a24", + "diffRemoved": "#fec0ce", + "diffRemovedBackground": "#300112", "diffModified": "#fdcd8b", - "diffModifiedBackground": "#292d37", + "diffModifiedBackground": "#191925", "lineNumber": "#4c4a5d", "lineNumberActive": "#e0def5" } }, + "header": { + "background": "#0c0a16", + "foreground": "#e0def5", + "border": "#444251", + "icon": "#8d8b9e", + "hover": "#211f2c" + }, + "sidebar": { + "background": "#12101d", + "foreground": "#6e6a86", + "border": "#444251", + "icon": "#242230", + "hover": "#211f2c", + "active": "#06353c", + "accent": "#9ccfd8", + "accentForeground": "#000000" + }, + "chat": { + "background": "#0c0a16", + "userMessage": "#e0def5", + "userMessageBackground": "#1a1824", + "assistantMessage": "#e0def5", + "assistantMessageBackground": "#0c0a16", + "timestamp": "#4c4a5d", + "divider": "#33313f", + "typing": "#6e6a86" + }, "markdown": { "heading1": "#c4a7e7", "heading2": "#c4a7e7", - "heading3": "#e0def5", + "heading3": "#fcfcfe", "heading4": "#e0def5", "link": "#9ccfd8", "linkHover": "#ebbcba", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#1a1824", "blockquote": "#6e6a86", "blockquoteBorder": "#444251", - "listMarker": "#9ccfd899" - }, - "chat": { - "userMessage": "#e0def5", - "userMessageBackground": "#06353c", - "assistantMessage": "#e0def5", - "assistantMessageBackground": "#0c0a16", - "timestamp": "#6e6a86", - "divider": "#444251" + "listMarker": "#9ccfd899", + "bold": "#eb6f92", + "italic": "#f6c177", + "strikethrough": "#6e6a86", + "hr": "#403d52" }, "tools": { - "background": "#1a182480", - "border": "#444251b3", - "headerHover": "#211f2c80", - "icon": "#6e6a86", + "background": "#1a1824", + "border": "#33313f", + "headerHover": "#211f2c", + "icon": "#242230", "title": "#e0def5", "description": "#6e6a86", "edit": { "added": "#9bdffd", - "addedBackground": "#011119", + "addedBackground": "#021a24", "removed": "#e13474", - "removedBackground": "#23000b", + "removedBackground": "#300112", + "modified": "#fdcd8b", + "modifiedBackground": "#191925", "lineNumber": "#4c4a5d" + }, + "bash": { + "background": "#14121e", + "foreground": "#e0def5", + "info": "#9ccfd8", + "warning": "#f6c177", + "error": "#eb6f92" + }, + "lsp": { + "background": "#14121e", + "foreground": "#e0def5", + "info": "#9ccfd8", + "warning": "#f6c177", + "error": "#eb6f92" } + }, + "forms": { + "inputBackground": "#0f0d19", + "inputForeground": "#e0def5", + "inputBorder": "#33313f", + "inputBorderHover": "#3b3948", + "inputBorderFocus": "#51a6b4", + "inputPlaceholder": "#4c4a5d", + "inputDisabled": "#161521", + "inputSelection": "#026673", + "label": "#6e6a86", + "helperText": "#4c4a5d" + }, + "buttons": { + "primary": { + "bg": "#9ccfd8", + "fg": "#000000", + "border": "#0d4a53", + "hover": "#5db8c7", + "active": "#51a6b4", + "disabled": "#3b3948" + }, + "secondary": { + "bg": "#14121e", + "fg": "#e0def5", + "border": "#444251", + "hover": "#1a1824", + "active": "#211f2c", + "disabled": "#161521" + }, + "ghost": { + "bg": "#00000000", + "fg": "#e0def5", + "border": "#00000000", + "hover": "#1a1824", + "active": "#211f2c", + "disabled": "#4c4a5d" + }, + "destructive": { + "bg": "#eb6f92", + "fg": "#151313", + "border": "#780f39", + "hover": "#780f39", + "active": "#d81b69", + "disabled": "#161521" + } + }, + "modal": { + "background": "#14121e", + "foreground": "#e0def5", + "border": "#444251", + "overlay": "#0c0a16d6" + }, + "popover": { + "background": "#14121e", + "foreground": "#e0def5", + "border": "#444251", + "shadow": "0 18px 48px rgba(0, 0, 0, 0.45)" + }, + "commandPalette": { + "background": "#14121e", + "foreground": "#e0def5", + "border": "#444251", + "inputBackground": "#0f0d19", + "selectedBackground": "#06353c", + "selectedForeground": "#e0def5", + "muted": "#6e6a86" + }, + "fileAttachment": { + "background": "#1a1824", + "foreground": "#e0def5", + "border": "#33313f", + "icon": "#242230", + "removeHover": "#590628" + }, + "sessions": { + "background": "#0c0a16", + "foreground": "#e0def5", + "mutedForeground": "#6e6a86", + "border": "#2b2936", + "hover": "#211f2c", + "active": "#06353c" + }, + "modelSelector": { + "background": "#14121e", + "foreground": "#e0def5", + "border": "#444251", + "selectedBackground": "#06353c", + "selectedForeground": "#e0def5" + }, + "permissions": { + "background": "#14121e", + "foreground": "#e0def5", + "border": "#444251", + "allow": "#31748f", + "allowBackground": "#023446", + "deny": "#eb6f92", + "denyBackground": "#590628" + }, + "loading": { + "spinner": "#9ccfd8", + "spinnerTrack": "#211f2c", + "skeleton": "#1a1824", + "shimmer": "#211f2c" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#e0def533", + "thumbHover": "#e0def557" + }, + "badges": { + "default": { + "bg": "#1a1824", + "fg": "#e0def5", + "border": "#33313f" + }, + "info": { + "bg": "#06353c", + "fg": "#9ccfd8", + "border": "#0d4a53" + }, + "success": { + "bg": "#023446", + "fg": "#31748f", + "border": "#06495f" + }, + "warning": { + "bg": "#402a06", + "fg": "#f6c177", + "border": "#5a3a01" + }, + "error": { + "bg": "#590628", + "fg": "#eb6f92", + "border": "#780f39" + } + }, + "toast": { + "background": "#14121e", + "foreground": "#e0def5", + "border": "#444251", + "success": { + "background": "#023446", + "foreground": "#31748f", + "border": "#06495f" + }, + "warning": { + "background": "#402a06", + "foreground": "#f6c177", + "border": "#5a3a01" + }, + "error": { + "background": "#590628", + "foreground": "#eb6f92", + "border": "#780f39" + }, + "info": { + "background": "#06353c", + "foreground": "#9ccfd8", + "border": "#0d4a53" + } + }, + "emptyState": { + "icon": "#6e6a86", + "title": "#e0def5", + "description": "#6e6a86", + "border": "#2b2936" + }, + "table": { + "border": "#2b2936", + "headerBackground": "#14121e", + "headerForeground": "#e0def5", + "rowHover": "#211f2c", + "rowSelected": "#06353c" + }, + "charts": { + "series": [ + "#9ccfd8", + "#9ccfd8", + "#31748f", + "#f6c177", + "#eb6f92" + ] + }, + "a11y": { + "focusRing": "#51a6b4", + "selection": "#06353c", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(0, 0, 0, 0.22)", + "md": "0 12px 32px rgba(0, 0, 0, 0.32)", + "lg": "0 24px 56px rgba(0, 0, 0, 0.42)", + "focus": "0 0 0 3px #9ccfd859" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/rosepine-light.json b/packages/ui/src/lib/theme/themes/rosepine-light.json index 84aea764..c6db2174 100644 --- a/packages/ui/src/lib/theme/themes/rosepine-light.json +++ b/packages/ui/src/lib/theme/themes/rosepine-light.json @@ -2,79 +2,81 @@ "metadata": { "id": "rosepine-light", "name": "Rose Pine", - "description": "Port of OpenCode Rose Pine theme (light variant)", + "description": "Ported from OpenCode Rose Pine theme (light variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "light", "tags": [ "light", "opencode", + "ported", "rosepine" ] }, "colors": { "primary": { - "base": "#157597", + "base": "#31748f", "hover": "#136a89", - "active": "#136a89", + "active": "#157597", "foreground": "#ffffff", - "muted": "#15759780", + "muted": "#31748f80", "emphasis": "#136a89" }, "surface": { "background": "#fbf5ef", "foreground": "#454066", - "muted": "#f2ebe8", + "muted": "#f5ede7", "mutedForeground": "#9893a5", "elevated": "#f6f0ec", "elevatedForeground": "#454066", - "overlay": "#0000004d", + "overlay": "#fbf5ef33", "subtle": "#ebe5e3" }, "interactive": { "border": "#d3cdd2", "borderHover": "#c9c3cb", - "borderFocus": "#84cded", - "selection": "#d0f0ff", - "selectionForeground": "#000000", - "focus": "#84cded", - "focusRing": "#84cded47", - "cursor": "#454066", - "hover": "#ebe5e3", - "active": "#ebe5e3" + "borderFocus": "#157597", + "selection": "#45406616", + "selectionForeground": "#454066", + "focus": "#157597", + "focusRing": "#15759747", + "cursor": "#332d53", + "hover": "#4540660e", + "active": "#45406616" }, "status": { - "error": "#b34e6e", + "error": "#b4637a", "errorForeground": "#000000", "errorBackground": "#fde2e8", "errorBorder": "#faa5bb", - "warning": "#fbac84", + "warning": "#ea9d34", "warningForeground": "#000000", "warningBackground": "#fde6cc", "warningBorder": "#fbaf4f", - "success": "#86ccec", - "successForeground": "#000000", + "success": "#286983", + "successForeground": "#ffffff", "successBackground": "#d1f0fe", "successBorder": "#86ccec", - "info": "#89cedb", + "info": "#56949f", "infoForeground": "#000000", "infoBackground": "#c8f3fb", "infoBorder": "#89cedb" }, "pr": { - "open": "#86ccec", + "open": "#286983", "draft": "#9893a5", - "blocked": "#fbac84", - "merged": "#286983", - "closed": "#b34e6e" + "blocked": "#ea9d34", + "merged": "#907aa9", + "closed": "#b4637a" }, "syntax": { "base": { - "background": "#f2ebe8", + "background": "#f6f0ec", "foreground": "#454066", "comment": "#9893a5", "keyword": "#286983", "string": "#ea9d34", - "number": "#d7827e", + "number": "#907aa9", "function": "#d7827e", "variable": "#575279", "type": "#56949f", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#9893a5", - "stringEscape": "#907aa9", + "stringEscape": "#454066", "keywordImport": "#286983", "storageModifier": "#286983", "functionCall": "#d7827e", @@ -90,7 +92,7 @@ "variableProperty": "#d7827e", "variableOther": "#575279", "variableGlobal": "#907aa9", - "variableLocal": "#9893a5", + "variableLocal": "#797593", "parameter": "#575279", "constant": "#907aa9", "class": "#56949f", @@ -99,38 +101,65 @@ "struct": "#56949f", "enum": "#56949f", "typeParameter": "#56949f", - "namespace": "#286983", + "namespace": "#56949f", "module": "#286983", "tag": "#286983", "jsxTag": "#286983", "tagAttribute": "#d7827e", "tagAttributeValue": "#ea9d34", - "boolean": "#d7827e", + "boolean": "#907aa9", "decorator": "#286983", - "label": "#286983", + "label": "#d7827e", "punctuation": "#797593", "macro": "#286983", "preprocessor": "#286983", "regex": "#454066", - "url": "#31748f", + "url": "#136a89", "key": "#d7827e", - "exception": "#b34e6e" + "exception": "#b4637a" }, "highlights": { "diffAdded": "#416677", - "diffAddedBackground": "#fafdff", - "diffRemoved": "#bd7488", - "diffRemovedBackground": "#fffcfc", + "diffAddedBackground": "#f3fbff", + "diffRemoved": "#894a5c", + "diffRemovedBackground": "#fff7f9", "diffModified": "#7c4e09", - "diffModifiedBackground": "#e4e3e0", + "diffModifiedBackground": "#f0ece8", "lineNumber": "#bdb9c7", "lineNumberActive": "#454066" } }, + "header": { + "background": "#fbf5ef", + "foreground": "#454066", + "border": "#d3cdd2", + "icon": "#635f83", + "hover": "#ebe5e3" + }, + "sidebar": { + "background": "#f5ede7", + "foreground": "#9893a5", + "border": "#d3cdd2", + "icon": "#e0cfc9", + "hover": "#ebe5e3", + "active": "#d0f0ff", + "accent": "#31748f", + "accentForeground": "#ffffff" + }, + "chat": { + "background": "#fbf5ef", + "userMessage": "#454066", + "userMessageBackground": "#f2ebe8", + "assistantMessage": "#454066", + "assistantMessageBackground": "#fbf5ef", + "timestamp": "#bdb9c7", + "divider": "#e7e1e0", + "typing": "#9893a5" + }, "markdown": { "heading1": "#907aa9", "heading2": "#907aa9", - "heading3": "#454066", + "heading3": "#332d53", "heading4": "#454066", "link": "#31748f", "linkHover": "#d7827e", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#f2ebe8", "blockquote": "#9893a5", "blockquoteBorder": "#d3cdd2", - "listMarker": "#31748f99" - }, - "chat": { - "userMessage": "#454066", - "userMessageBackground": "#d0f0ff", - "assistantMessage": "#454066", - "assistantMessageBackground": "#fbf5ef", - "timestamp": "#9893a5", - "divider": "#d3cdd2" + "listMarker": "#31748f99", + "bold": "#b4637a", + "italic": "#ea9d34", + "strikethrough": "#9893a5", + "hr": "#dfdad9" }, "tools": { - "background": "#f2ebe880", - "border": "#d3cdd2b3", - "headerHover": "#ebe5e380", - "icon": "#9893a5", + "background": "#f2ebe8", + "border": "#e7e1e0", + "headerHover": "#ebe5e3", + "icon": "#e0cfc9", "title": "#454066", "description": "#9893a5", "edit": { "added": "#416677", - "addedBackground": "#fafdff", + "addedBackground": "#f3fbff", "removed": "#bd7488", - "removedBackground": "#fffcfc", + "removedBackground": "#fff7f9", + "modified": "#7c4e09", + "modifiedBackground": "#f0ece8", "lineNumber": "#bdb9c7" + }, + "bash": { + "background": "#f6f0ec", + "foreground": "#454066", + "info": "#56949f", + "warning": "#ea9d34", + "error": "#b4637a" + }, + "lsp": { + "background": "#f6f0ec", + "foreground": "#454066", + "info": "#56949f", + "warning": "#ea9d34", + "error": "#b4637a" } + }, + "forms": { + "inputBackground": "#fbf5ef", + "inputForeground": "#454066", + "inputBorder": "#e7e1e0", + "inputBorderHover": "#ddd7d9", + "inputBorderFocus": "#157597", + "inputPlaceholder": "#bdb9c7", + "inputDisabled": "#f2e9e2", + "inputSelection": "#d0f0ff", + "label": "#9893a5", + "helperText": "#bdb9c7" + }, + "buttons": { + "primary": { + "bg": "#31748f", + "fg": "#ffffff", + "border": "#84cded", + "hover": "#136a89", + "active": "#157597", + "disabled": "#dad4d7" + }, + "secondary": { + "bg": "#f6f0ec", + "fg": "#454066", + "border": "#d3cdd2", + "hover": "#f2ebe8", + "active": "#ebe5e3", + "disabled": "#f2e9e2" + }, + "ghost": { + "bg": "#00000000", + "fg": "#454066", + "border": "#00000000", + "hover": "#f2ebe8", + "active": "#ebe5e3", + "disabled": "#bdb9c7" + }, + "destructive": { + "bg": "#b4637a", + "fg": "#000000", + "border": "#faa5bb", + "hover": "#fdd3dd", + "active": "#be5b79", + "disabled": "#f2e9e2" + } + }, + "modal": { + "background": "#f6f0ec", + "foreground": "#454066", + "border": "#d3cdd2", + "overlay": "#fbf5ef3d" + }, + "popover": { + "background": "#f6f0ec", + "foreground": "#454066", + "border": "#d3cdd2", + "shadow": "0 18px 48px rgba(15, 15, 15, 0.16)" + }, + "commandPalette": { + "background": "#f6f0ec", + "foreground": "#454066", + "border": "#d3cdd2", + "inputBackground": "#fbf5ef", + "selectedBackground": "#d0f0ff", + "selectedForeground": "#454066", + "muted": "#9893a5" + }, + "fileAttachment": { + "background": "#f2ebe8", + "foreground": "#454066", + "border": "#e7e1e0", + "icon": "#e0cfc9", + "removeHover": "#fde2e8" + }, + "sessions": { + "background": "#fbf5ef", + "foreground": "#454066", + "mutedForeground": "#9893a5", + "border": "#ede7e5", + "hover": "#ebe5e3", + "active": "#d0f0ff" + }, + "modelSelector": { + "background": "#f6f0ec", + "foreground": "#454066", + "border": "#d3cdd2", + "selectedBackground": "#d0f0ff", + "selectedForeground": "#454066" + }, + "permissions": { + "background": "#f6f0ec", + "foreground": "#454066", + "border": "#d3cdd2", + "allow": "#286983", + "allowBackground": "#d1f0fe", + "deny": "#b4637a", + "denyBackground": "#fde2e8" + }, + "loading": { + "spinner": "#31748f", + "spinnerTrack": "#ebe5e3", + "skeleton": "#f2ebe8", + "shimmer": "#ebe5e3" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#45406626", + "thumbHover": "#45406640" + }, + "badges": { + "default": { + "bg": "#f2ebe8", + "fg": "#454066", + "border": "#e7e1e0" + }, + "info": { + "bg": "#c8f3fb", + "fg": "#56949f", + "border": "#89cedb" + }, + "success": { + "bg": "#d1f0fe", + "fg": "#286983", + "border": "#86ccec" + }, + "warning": { + "bg": "#fde6cc", + "fg": "#ea9d34", + "border": "#fbaf4f" + }, + "error": { + "bg": "#fde2e8", + "fg": "#b4637a", + "border": "#faa5bb" + } + }, + "toast": { + "background": "#f6f0ec", + "foreground": "#454066", + "border": "#d3cdd2", + "success": { + "background": "#d1f0fe", + "foreground": "#286983", + "border": "#86ccec" + }, + "warning": { + "background": "#fde6cc", + "foreground": "#ea9d34", + "border": "#fbaf4f" + }, + "error": { + "background": "#fde2e8", + "foreground": "#b4637a", + "border": "#faa5bb" + }, + "info": { + "background": "#c8f3fb", + "foreground": "#56949f", + "border": "#89cedb" + } + }, + "emptyState": { + "icon": "#9893a5", + "title": "#454066", + "description": "#9893a5", + "border": "#ede7e5" + }, + "table": { + "border": "#ede7e5", + "headerBackground": "#f6f0ec", + "headerForeground": "#454066", + "rowHover": "#ebe5e3", + "rowSelected": "#d0f0ff" + }, + "charts": { + "series": [ + "#31748f", + "#56949f", + "#286983", + "#ea9d34", + "#b4637a" + ] + }, + "a11y": { + "focusRing": "#157597", + "selection": "#d0f0ff", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(15, 15, 15, 0.08)", + "md": "0 12px 32px rgba(15, 15, 15, 0.12)", + "lg": "0 24px 56px rgba(15, 15, 15, 0.16)", + "focus": "0 0 0 3px #31748f40" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/shadesofpurple-dark.json b/packages/ui/src/lib/theme/themes/shadesofpurple-dark.json index 97bd60a3..c4a81cbe 100644 --- a/packages/ui/src/lib/theme/themes/shadesofpurple-dark.json +++ b/packages/ui/src/lib/theme/themes/shadesofpurple-dark.json @@ -2,79 +2,81 @@ "metadata": { "id": "shadesofpurple-dark", "name": "Shades of Purple", - "description": "Port of OpenCode Shades of Purple theme (dark variant)", + "description": "Ported from OpenCode Shades of Purple theme (dark variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "dark", "tags": [ "dark", "opencode", + "ported", "shadesofpurple" ] }, "colors": { "primary": { - "base": "#ab4afb", + "base": "#c792ff", "hover": "#b569fb", - "active": "#b569fb", + "active": "#ab4afb", "foreground": "#000000", - "muted": "#ab4afb80", - "emphasis": "#b569fb" + "muted": "#c792ff80", + "emphasis": "#dfc8fb" }, "surface": { "background": "#0e051d", "foreground": "#f5f0fe", - "muted": "#1d142c", + "muted": "#150b24", "mutedForeground": "#d1ccd8", "elevated": "#170e25", "elevatedForeground": "#f5f0fe", - "overlay": "#00000080", + "overlay": "#0e051dcc", "subtle": "#251c33" }, "interactive": { "border": "#4b4359", "borderHover": "#544c62", - "borderFocus": "#5c0092", - "selection": "#410a67", - "selectionForeground": "#ffffff", - "focus": "#5c0092", - "focusRing": "#5c009259", - "cursor": "#f5f0fe", - "hover": "#251c33", - "active": "#251c33" + "borderFocus": "#ab4afb", + "selection": "#f5f0fe1f", + "selectionForeground": "#f5f0fe", + "focus": "#ab4afb", + "focusRing": "#ab4afb61", + "cursor": "#fefeff", + "hover": "#f5f0fe17", + "active": "#f5f0fe1f" }, "status": { - "error": "#e816a4", - "errorForeground": "#ffffff", + "error": "#ff7ac6", + "errorForeground": "#151313", "errorBackground": "#55073a", "errorBorder": "#731051", - "warning": "#d58611", - "warningForeground": "#ffffff", + "warning": "#ffd580", + "warningForeground": "#151313", "warningBackground": "#3d2c02", "warningBorder": "#543e06", - "success": "#0eb67d", - "successForeground": "#ffffff", + "success": "#7be0b0", + "successForeground": "#151313", "successBackground": "#053825", "successBorder": "#0d4e35", - "info": "#22a7dc", - "infoForeground": "#ffffff", + "info": "#7dd4ff", + "infoForeground": "#151313", "infoBackground": "#003448", "infoBorder": "#034862" }, "pr": { - "open": "#0eb67d", + "open": "#7be0b0", "draft": "#d1ccd8", - "blocked": "#d58611", - "merged": "#ff9d00", - "closed": "#e816a4" + "blocked": "#ffd580", + "merged": "#ff628c", + "closed": "#ff7ac6" }, "syntax": { "base": { - "background": "#1d142c", + "background": "#170e25", "foreground": "#f5f0fe", "comment": "#b362ff", "keyword": "#ff9d00", "string": "#a5ff90", - "number": "#fb94ff", + "number": "#ff628c", "function": "#9effff", "variable": "#fefeff", "type": "#fad000", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#b362ff", - "stringEscape": "#ff628c", + "stringEscape": "#f5f0fe", "keywordImport": "#ff9d00", "storageModifier": "#ff9d00", "functionCall": "#9effff", @@ -99,38 +101,65 @@ "struct": "#fad000", "enum": "#fad000", "typeParameter": "#fad000", - "namespace": "#ff9d00", + "namespace": "#fad000", "module": "#ff9d00", "tag": "#ff9d00", "jsxTag": "#ff9d00", "tagAttribute": "#9effff", "tagAttributeValue": "#a5ff90", - "boolean": "#fb94ff", + "boolean": "#ff628c", "decorator": "#ff9d00", - "label": "#ff9d00", + "label": "#9effff", "punctuation": "#d1ccd8", "macro": "#ff9d00", "preprocessor": "#ff9d00", "regex": "#f5f0fe", - "url": "#e7d6fd", + "url": "#dfc8fb", "key": "#9effff", - "exception": "#e816a4" + "exception": "#ff7ac6" }, "highlights": { "diffAdded": "#24f6c0", - "diffAddedBackground": "#01130c", - "diffRemoved": "#de299a", - "diffRemovedBackground": "#210113", + "diffAddedBackground": "#021c14", + "diffRemoved": "#fdbfdc", + "diffRemovedBackground": "#2d031c", "diffModified": "#fee2ad", - "diffModifiedBackground": "#2d213f", + "diffModifiedBackground": "#1c112c", "lineNumber": "#b4b0ba", "lineNumberActive": "#f5f0fe" } }, + "header": { + "background": "#0e051d", + "foreground": "#f5f0fe", + "border": "#4b4359", + "icon": "#9a93a8", + "hover": "#251c33" + }, + "sidebar": { + "background": "#150b24", + "foreground": "#d1ccd8", + "border": "#4b4359", + "icon": "#282039", + "hover": "#251c33", + "active": "#410a67", + "accent": "#c792ff", + "accentForeground": "#000000" + }, + "chat": { + "background": "#0e051d", + "userMessage": "#f5f0fe", + "userMessageBackground": "#1d142c", + "assistantMessage": "#f5f0fe", + "assistantMessageBackground": "#0e051d", + "timestamp": "#b4b0ba", + "divider": "#393047", + "typing": "#d1ccd8" + }, "markdown": { "heading1": "#e7d6fd", "heading2": "#e7d6fd", - "heading3": "#f5f0fe", + "heading3": "#fefeff", "heading4": "#f5f0fe", "link": "#e7d6fd", "linkHover": "#bae6fd", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#1d142c", "blockquote": "#fee2ad", "blockquoteBorder": "#4b4359", - "listMarker": "#e7d6fd99" - }, - "chat": { - "userMessage": "#f5f0fe", - "userMessageBackground": "#410a67", - "assistantMessage": "#f5f0fe", - "assistantMessageBackground": "#0e051d", - "timestamp": "#d1ccd8", - "divider": "#4b4359" + "listMarker": "#e7d6fd99", + "bold": "#fcd0e6", + "italic": "#fee2ad", + "strikethrough": "#d1ccd8", + "hr": "#4b4359" }, "tools": { - "background": "#1d142c80", - "border": "#4b4359b3", - "headerHover": "#251c3380", - "icon": "#d1ccd8", + "background": "#1d142c", + "border": "#393047", + "headerHover": "#251c33", + "icon": "#282039", "title": "#f5f0fe", "description": "#d1ccd8", "edit": { "added": "#24f6c0", - "addedBackground": "#01130c", + "addedBackground": "#021c14", "removed": "#de299a", - "removedBackground": "#210113", + "removedBackground": "#2d031c", + "modified": "#fee2ad", + "modifiedBackground": "#1c112c", "lineNumber": "#b4b0ba" + }, + "bash": { + "background": "#170e25", + "foreground": "#f5f0fe", + "info": "#7dd4ff", + "warning": "#ffd580", + "error": "#ff7ac6" + }, + "lsp": { + "background": "#170e25", + "foreground": "#f5f0fe", + "info": "#7dd4ff", + "warning": "#ffd580", + "error": "#ff7ac6" } + }, + "forms": { + "inputBackground": "#110820", + "inputForeground": "#f5f0fe", + "inputBorder": "#393047", + "inputBorderHover": "#423a50", + "inputBorderFocus": "#ab4afb", + "inputPlaceholder": "#b4b0ba", + "inputDisabled": "#191029", + "inputSelection": "#7b0bc0", + "label": "#d1ccd8", + "helperText": "#b4b0ba" + }, + "buttons": { + "primary": { + "bg": "#c792ff", + "fg": "#000000", + "border": "#5c0092", + "hover": "#b569fb", + "active": "#ab4afb", + "disabled": "#423a50" + }, + "secondary": { + "bg": "#170e25", + "fg": "#f5f0fe", + "border": "#4b4359", + "hover": "#1d142c", + "active": "#251c33", + "disabled": "#191029" + }, + "ghost": { + "bg": "#00000000", + "fg": "#f5f0fe", + "border": "#00000000", + "hover": "#1d142c", + "active": "#251c33", + "disabled": "#b4b0ba" + }, + "destructive": { + "bg": "#ff7ac6", + "fg": "#151313", + "border": "#731051", + "hover": "#731051", + "active": "#e816a4", + "disabled": "#191029" + } + }, + "modal": { + "background": "#170e25", + "foreground": "#f5f0fe", + "border": "#4b4359", + "overlay": "#0e051dd6" + }, + "popover": { + "background": "#170e25", + "foreground": "#f5f0fe", + "border": "#4b4359", + "shadow": "0 18px 48px rgba(0, 0, 0, 0.45)" + }, + "commandPalette": { + "background": "#170e25", + "foreground": "#f5f0fe", + "border": "#4b4359", + "inputBackground": "#110820", + "selectedBackground": "#410a67", + "selectedForeground": "#f5f0fe", + "muted": "#d1ccd8" + }, + "fileAttachment": { + "background": "#1d142c", + "foreground": "#f5f0fe", + "border": "#393047", + "icon": "#282039", + "removeHover": "#55073a" + }, + "sessions": { + "background": "#0e051d", + "foreground": "#f5f0fe", + "mutedForeground": "#d1ccd8", + "border": "#2f273e", + "hover": "#251c33", + "active": "#410a67" + }, + "modelSelector": { + "background": "#170e25", + "foreground": "#f5f0fe", + "border": "#4b4359", + "selectedBackground": "#410a67", + "selectedForeground": "#f5f0fe" + }, + "permissions": { + "background": "#170e25", + "foreground": "#f5f0fe", + "border": "#4b4359", + "allow": "#7be0b0", + "allowBackground": "#053825", + "deny": "#ff7ac6", + "denyBackground": "#55073a" + }, + "loading": { + "spinner": "#c792ff", + "spinnerTrack": "#251c33", + "skeleton": "#1d142c", + "shimmer": "#251c33" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#f5f0fe33", + "thumbHover": "#f5f0fe57" + }, + "badges": { + "default": { + "bg": "#1d142c", + "fg": "#f5f0fe", + "border": "#393047" + }, + "info": { + "bg": "#003448", + "fg": "#7dd4ff", + "border": "#034862" + }, + "success": { + "bg": "#053825", + "fg": "#7be0b0", + "border": "#0d4e35" + }, + "warning": { + "bg": "#3d2c02", + "fg": "#ffd580", + "border": "#543e06" + }, + "error": { + "bg": "#55073a", + "fg": "#ff7ac6", + "border": "#731051" + } + }, + "toast": { + "background": "#170e25", + "foreground": "#f5f0fe", + "border": "#4b4359", + "success": { + "background": "#053825", + "foreground": "#7be0b0", + "border": "#0d4e35" + }, + "warning": { + "background": "#3d2c02", + "foreground": "#ffd580", + "border": "#543e06" + }, + "error": { + "background": "#55073a", + "foreground": "#ff7ac6", + "border": "#731051" + }, + "info": { + "background": "#003448", + "foreground": "#7dd4ff", + "border": "#034862" + } + }, + "emptyState": { + "icon": "#d1ccd8", + "title": "#f5f0fe", + "description": "#d1ccd8", + "border": "#2f273e" + }, + "table": { + "border": "#2f273e", + "headerBackground": "#170e25", + "headerForeground": "#f5f0fe", + "rowHover": "#251c33", + "rowSelected": "#410a67" + }, + "charts": { + "series": [ + "#c792ff", + "#7dd4ff", + "#7be0b0", + "#ffd580", + "#ff7ac6" + ] + }, + "a11y": { + "focusRing": "#ab4afb", + "selection": "#410a67", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(0, 0, 0, 0.22)", + "md": "0 12px 32px rgba(0, 0, 0, 0.32)", + "lg": "0 24px 56px rgba(0, 0, 0, 0.42)", + "focus": "0 0 0 3px #c792ff59" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/shadesofpurple-light.json b/packages/ui/src/lib/theme/themes/shadesofpurple-light.json index 9ba7a1fb..869cd3f3 100644 --- a/packages/ui/src/lib/theme/themes/shadesofpurple-light.json +++ b/packages/ui/src/lib/theme/themes/shadesofpurple-light.json @@ -2,79 +2,81 @@ "metadata": { "id": "shadesofpurple-light", "name": "Shades of Purple", - "description": "Port of OpenCode Shades of Purple theme (light variant)", + "description": "Ported from OpenCode Shades of Purple theme (light variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "light", "tags": [ "light", "opencode", + "ported", "shadesofpurple" ] }, "colors": { "primary": { - "base": "#7a5bf7", + "base": "#7a5af8", "hover": "#7242fb", - "active": "#7242fb", + "active": "#7a5bf7", "foreground": "#000000", - "muted": "#7a5bf780", + "muted": "#7a5af880", "emphasis": "#7242fb" }, "surface": { "background": "#f8effe", "foreground": "#32224f", - "muted": "#ede4f4", + "muted": "#f0e6f6", "mutedForeground": "#4e406b", "elevated": "#f3e9f9", "elevatedForeground": "#32224f", - "overlay": "#0000004d", + "overlay": "#f8effe33", "subtle": "#e6dcee" }, "interactive": { "border": "#cabfd6", "borderHover": "#bfb4cc", - "borderFocus": "#bcb9fb", - "selection": "#e8e7ff", - "selectionForeground": "#000000", - "focus": "#bcb9fb", - "focusRing": "#bcb9fb47", - "cursor": "#32224f", - "hover": "#e6dcee", - "active": "#e6dcee" + "borderFocus": "#7a5bf7", + "selection": "#32224f16", + "selectionForeground": "#32224f", + "focus": "#7a5bf7", + "focusRing": "#7a5bf747", + "cursor": "#210f3d", + "hover": "#32224f0e", + "active": "#32224f16" }, "status": { - "error": "#fb50ce", + "error": "#ff6bd5", "errorForeground": "#000000", "errorBackground": "#fee0f2", "errorBorder": "#fb9ddd", - "warning": "#fdae57", + "warning": "#f7c948", "warningForeground": "#000000", "warningBackground": "#fee8b1", "warningBorder": "#ecba16", - "success": "#35e29f", + "success": "#3dd598", "successForeground": "#000000", "successBackground": "#b0fed6", "successBorder": "#35e29f", - "info": "#63d1fa", + "info": "#62d4ff", "infoForeground": "#000000", "infoBackground": "#d0f0fe", "infoBorder": "#63d1fa" }, "pr": { - "open": "#35e29f", + "open": "#3dd598", "draft": "#4e406b", - "blocked": "#fdae57", - "merged": "#c45f00", - "closed": "#fb50ce" + "blocked": "#f7c948", + "merged": "#e04d7a", + "closed": "#ff6bd5" }, "syntax": { "base": { - "background": "#ede4f4", + "background": "#f3e9f9", "foreground": "#32224f", "comment": "#8e4be3", "keyword": "#c45f00", "string": "#2f8b32", - "number": "#a13bd6", + "number": "#e04d7a", "function": "#008fb8", "variable": "#210f3d", "type": "#9d7a00", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#8e4be3", - "stringEscape": "#e04d7a", + "stringEscape": "#32224f", "keywordImport": "#c45f00", "storageModifier": "#c45f00", "functionCall": "#008fb8", @@ -90,7 +92,7 @@ "variableProperty": "#008fb8", "variableOther": "#210f3d", "variableGlobal": "#e04d7a", - "variableLocal": "#4e406b", + "variableLocal": "#32224f", "parameter": "#210f3d", "constant": "#e04d7a", "class": "#9d7a00", @@ -99,38 +101,65 @@ "struct": "#9d7a00", "enum": "#9d7a00", "typeParameter": "#9d7a00", - "namespace": "#c45f00", + "namespace": "#9d7a00", "module": "#c45f00", "tag": "#c45f00", "jsxTag": "#c45f00", "tagAttribute": "#008fb8", "tagAttributeValue": "#2f8b32", - "boolean": "#a13bd6", + "boolean": "#e04d7a", "decorator": "#c45f00", - "label": "#c45f00", + "label": "#008fb8", "punctuation": "#32224f", "macro": "#c45f00", "preprocessor": "#c45f00", "regex": "#32224f", - "url": "#5c1adc", + "url": "#7242fb", "key": "#008fb8", - "exception": "#fb50ce" + "exception": "#ff6bd5" }, "highlights": { "diffAdded": "#386d50", - "diffAddedBackground": "#f9fefb", - "diffRemoved": "#fcb1e9", - "diffRemovedBackground": "#fffcfe", + "diffAddedBackground": "#f2fdf5", + "diffRemoved": "#854777", + "diffRemovedBackground": "#fff7fc", "diffModified": "#6e560d", - "diffModifiedBackground": "#e7dff7", + "diffModifiedBackground": "#f0e7fa", "lineNumber": "#695e82", "lineNumberActive": "#32224f" } }, + "header": { + "background": "#f8effe", + "foreground": "#32224f", + "border": "#cabfd6", + "icon": "#4e406b", + "hover": "#e6dcee" + }, + "sidebar": { + "background": "#f0e6f6", + "foreground": "#4e406b", + "border": "#cabfd6", + "icon": "#cec3d9", + "hover": "#e6dcee", + "active": "#e8e7ff", + "accent": "#7a5af8", + "accentForeground": "#000000" + }, + "chat": { + "background": "#f8effe", + "userMessage": "#32224f", + "userMessageBackground": "#ede4f4", + "assistantMessage": "#32224f", + "assistantMessageBackground": "#f8effe", + "timestamp": "#695e82", + "divider": "#e1d7ea", + "typing": "#4e406b" + }, "markdown": { "heading1": "#5c1adc", "heading2": "#5c1adc", - "heading3": "#32224f", + "heading3": "#210f3d", "heading4": "#32224f", "link": "#5c1adc", "linkHover": "#03637f", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#ede4f4", "blockquote": "#6e560d", "blockquoteBorder": "#cabfd6", - "listMarker": "#5c1adc99" - }, - "chat": { - "userMessage": "#32224f", - "userMessageBackground": "#e8e7ff", - "assistantMessage": "#32224f", - "assistantMessageBackground": "#f8effe", - "timestamp": "#4e406b", - "divider": "#cabfd6" + "listMarker": "#5c1adc99", + "bold": "#990d7a", + "italic": "#6e560d", + "strikethrough": "#4e406b", + "hr": "#cabfd6" }, "tools": { - "background": "#ede4f480", - "border": "#cabfd6b3", - "headerHover": "#e6dcee80", - "icon": "#4e406b", + "background": "#ede4f4", + "border": "#e1d7ea", + "headerHover": "#e6dcee", + "icon": "#cec3d9", "title": "#32224f", "description": "#4e406b", "edit": { "added": "#386d50", - "addedBackground": "#f9fefb", + "addedBackground": "#f2fdf5", "removed": "#fcb1e9", - "removedBackground": "#fffcfe", + "removedBackground": "#fff7fc", + "modified": "#6e560d", + "modifiedBackground": "#f0e7fa", "lineNumber": "#695e82" + }, + "bash": { + "background": "#f3e9f9", + "foreground": "#32224f", + "info": "#62d4ff", + "warning": "#f7c948", + "error": "#ff6bd5" + }, + "lsp": { + "background": "#f3e9f9", + "foreground": "#32224f", + "info": "#62d4ff", + "warning": "#f7c948", + "error": "#ff6bd5" } + }, + "forms": { + "inputBackground": "#f8effe", + "inputForeground": "#32224f", + "inputBorder": "#e1d7ea", + "inputBorderHover": "#d5cbe0", + "inputBorderFocus": "#7a5bf7", + "inputPlaceholder": "#695e82", + "inputDisabled": "#eae0f2", + "inputSelection": "#e8e7ff", + "label": "#4e406b", + "helperText": "#695e82" + }, + "buttons": { + "primary": { + "bg": "#7a5af8", + "fg": "#000000", + "border": "#bcb9fb", + "hover": "#7242fb", + "active": "#7a5bf7", + "disabled": "#d1c7dc" + }, + "secondary": { + "bg": "#f3e9f9", + "fg": "#32224f", + "border": "#cabfd6", + "hover": "#ede4f4", + "active": "#e6dcee", + "disabled": "#eae0f2" + }, + "ghost": { + "bg": "#00000000", + "fg": "#32224f", + "border": "#00000000", + "hover": "#ede4f4", + "active": "#e6dcee", + "disabled": "#695e82" + }, + "destructive": { + "bg": "#ff6bd5", + "fg": "#000000", + "border": "#fb9ddd", + "hover": "#fed0ed", + "active": "#fe6cd5", + "disabled": "#eae0f2" + } + }, + "modal": { + "background": "#f3e9f9", + "foreground": "#32224f", + "border": "#cabfd6", + "overlay": "#f8effe3d" + }, + "popover": { + "background": "#f3e9f9", + "foreground": "#32224f", + "border": "#cabfd6", + "shadow": "0 18px 48px rgba(15, 15, 15, 0.16)" + }, + "commandPalette": { + "background": "#f3e9f9", + "foreground": "#32224f", + "border": "#cabfd6", + "inputBackground": "#f8effe", + "selectedBackground": "#e8e7ff", + "selectedForeground": "#32224f", + "muted": "#4e406b" + }, + "fileAttachment": { + "background": "#ede4f4", + "foreground": "#32224f", + "border": "#e1d7ea", + "icon": "#cec3d9", + "removeHover": "#fee0f2" + }, + "sessions": { + "background": "#f8effe", + "foreground": "#32224f", + "mutedForeground": "#4e406b", + "border": "#e8dff0", + "hover": "#e6dcee", + "active": "#e8e7ff" + }, + "modelSelector": { + "background": "#f3e9f9", + "foreground": "#32224f", + "border": "#cabfd6", + "selectedBackground": "#e8e7ff", + "selectedForeground": "#32224f" + }, + "permissions": { + "background": "#f3e9f9", + "foreground": "#32224f", + "border": "#cabfd6", + "allow": "#3dd598", + "allowBackground": "#b0fed6", + "deny": "#ff6bd5", + "denyBackground": "#fee0f2" + }, + "loading": { + "spinner": "#7a5af8", + "spinnerTrack": "#e6dcee", + "skeleton": "#ede4f4", + "shimmer": "#e6dcee" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#32224f26", + "thumbHover": "#32224f40" + }, + "badges": { + "default": { + "bg": "#ede4f4", + "fg": "#32224f", + "border": "#e1d7ea" + }, + "info": { + "bg": "#d0f0fe", + "fg": "#62d4ff", + "border": "#63d1fa" + }, + "success": { + "bg": "#b0fed6", + "fg": "#3dd598", + "border": "#35e29f" + }, + "warning": { + "bg": "#fee8b1", + "fg": "#f7c948", + "border": "#ecba16" + }, + "error": { + "bg": "#fee0f2", + "fg": "#ff6bd5", + "border": "#fb9ddd" + } + }, + "toast": { + "background": "#f3e9f9", + "foreground": "#32224f", + "border": "#cabfd6", + "success": { + "background": "#b0fed6", + "foreground": "#3dd598", + "border": "#35e29f" + }, + "warning": { + "background": "#fee8b1", + "foreground": "#f7c948", + "border": "#ecba16" + }, + "error": { + "background": "#fee0f2", + "foreground": "#ff6bd5", + "border": "#fb9ddd" + }, + "info": { + "background": "#d0f0fe", + "foreground": "#62d4ff", + "border": "#63d1fa" + } + }, + "emptyState": { + "icon": "#4e406b", + "title": "#32224f", + "description": "#4e406b", + "border": "#e8dff0" + }, + "table": { + "border": "#e8dff0", + "headerBackground": "#f3e9f9", + "headerForeground": "#32224f", + "rowHover": "#e6dcee", + "rowSelected": "#e8e7ff" + }, + "charts": { + "series": [ + "#7a5af8", + "#62d4ff", + "#3dd598", + "#f7c948", + "#ff6bd5" + ] + }, + "a11y": { + "focusRing": "#7a5bf7", + "selection": "#e8e7ff", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(15, 15, 15, 0.08)", + "md": "0 12px 32px rgba(15, 15, 15, 0.12)", + "lg": "0 24px 56px rgba(15, 15, 15, 0.16)", + "focus": "0 0 0 3px #7a5af840" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/vercel-dark.json b/packages/ui/src/lib/theme/themes/vercel-dark.json index d683fb47..24d96ae9 100644 --- a/packages/ui/src/lib/theme/themes/vercel-dark.json +++ b/packages/ui/src/lib/theme/themes/vercel-dark.json @@ -2,79 +2,81 @@ "metadata": { "id": "vercel-dark", "name": "Vercel", - "description": "Port of OpenCode Vercel theme (dark variant)", + "description": "Ported from OpenCode Vercel theme (dark variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "dark", "tags": [ "dark", "opencode", + "ported", "vercel" ] }, "colors": { "primary": { - "base": "#0164db", + "base": "#0070F3", "hover": "#207dfc", - "active": "#207dfc", + "active": "#2280d6", "foreground": "#ffffff", - "muted": "#0164db80", - "emphasis": "#207dfc" + "muted": "#0070F380", + "emphasis": "#b6d7fc" }, "surface": { "background": "#000000", "foreground": "#ededed", - "muted": "#0f0f0f", + "muted": "#000000", "mutedForeground": "#878787", "elevated": "#090909", "elevatedForeground": "#ededed", - "overlay": "#00000080", + "overlay": "#000000cc", "subtle": "#171717" }, "interactive": { "border": "#3f3f3f", "borderHover": "#484848", - "borderFocus": "#0e4374", - "selection": "#063056", - "selectionForeground": "#ffffff", - "focus": "#0e4374", - "focusRing": "#0e437459", - "cursor": "#ededed", - "hover": "#171717", - "active": "#171717" + "borderFocus": "#2280d6", + "selection": "#ededed1f", + "selectionForeground": "#ededed", + "focus": "#2280d6", + "focusRing": "#2280d661", + "cursor": "#fdfdfd", + "hover": "#ededed17", + "active": "#ededed1f" }, "status": { - "error": "#c41e2f", - "errorForeground": "#ffffff", + "error": "#E5484D", + "errorForeground": "#151313", "errorBackground": "#5b0710", "errorBorder": "#7b101b", - "warning": "#c37018", - "warningForeground": "#ffffff", + "warning": "#FFB224", + "warningForeground": "#151313", "warningBackground": "#412900", "warningBorder": "#593b03", - "success": "#148434", - "successForeground": "#ffffff", + "success": "#46A758", + "successForeground": "#151313", "successBackground": "#023a12", "successBorder": "#08501d", - "info": "#2280d6", - "infoForeground": "#ffffff", + "info": "#52A8FF", + "infoForeground": "#151313", "infoBackground": "#063056", "infoBorder": "#0e4374" }, "pr": { - "open": "#148434", + "open": "#46A758", "draft": "#878787", - "blocked": "#c37018", - "merged": "#F75590", - "closed": "#c41e2f" + "blocked": "#FFB224", + "merged": "#F2A700", + "closed": "#E5484D" }, "syntax": { "base": { - "background": "#0f0f0f", + "background": "#090909", "foreground": "#ededed", "comment": "#878787", "keyword": "#F75590", "string": "#63C46D", - "number": "#BF7AF0", + "number": "#F2A700", "function": "#0AC7AC", "variable": "#52A8FF", "type": "#0AC7AC", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#878787", - "stringEscape": "#F2A700", + "stringEscape": "#ededed", "keywordImport": "#F75590", "storageModifier": "#F75590", "functionCall": "#0AC7AC", @@ -90,7 +92,7 @@ "variableProperty": "#0AC7AC", "variableOther": "#52A8FF", "variableGlobal": "#F2A700", - "variableLocal": "#878787", + "variableLocal": "#EDEDED", "parameter": "#52A8FF", "constant": "#F2A700", "class": "#0AC7AC", @@ -99,38 +101,65 @@ "struct": "#0AC7AC", "enum": "#0AC7AC", "typeParameter": "#0AC7AC", - "namespace": "#F75590", + "namespace": "#0AC7AC", "module": "#F75590", "tag": "#F75590", "jsxTag": "#F75590", "tagAttribute": "#0AC7AC", "tagAttributeValue": "#63C46D", - "boolean": "#BF7AF0", + "boolean": "#F2A700", "decorator": "#F75590", - "label": "#F75590", + "label": "#0AC7AC", "punctuation": "#EDEDED", "macro": "#F75590", "preprocessor": "#F75590", "regex": "#ededed", - "url": "#52A8FF", + "url": "#b6d7fc", "key": "#0AC7AC", - "exception": "#c41e2f" + "exception": "#E5484D" }, "highlights": { "diffAdded": "#38fc61", - "diffAddedBackground": "#001402", - "diffRemoved": "#f22942", - "diffRemovedBackground": "#240103", + "diffAddedBackground": "#001d04", + "diffRemoved": "#fbc4c1", + "diffRemovedBackground": "#310206", "diffModified": "#fdd8a4", - "diffModifiedBackground": "#161e27", + "diffModifiedBackground": "#0a0d11", "lineNumber": "#646464", "lineNumberActive": "#ededed" } }, + "header": { + "background": "#000000", + "foreground": "#ededed", + "border": "#3f3f3f", + "icon": "#848484", + "hover": "#171717" + }, + "sidebar": { + "background": "#000000", + "foreground": "#878787", + "border": "#3f3f3f", + "icon": "#080808", + "hover": "#171717", + "active": "#063056", + "accent": "#0070F3", + "accentForeground": "#ffffff" + }, + "chat": { + "background": "#000000", + "userMessage": "#ededed", + "userMessageBackground": "#0f0f0f", + "assistantMessage": "#ededed", + "assistantMessageBackground": "#000000", + "timestamp": "#646464", + "divider": "#2c2c2c", + "typing": "#878787" + }, "markdown": { "heading1": "#BF7AF0", "heading2": "#BF7AF0", - "heading3": "#ededed", + "heading3": "#fdfdfd", "heading4": "#ededed", "link": "#52A8FF", "linkHover": "#0AC7AC", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#0f0f0f", "blockquote": "#878787", "blockquoteBorder": "#3f3f3f", - "listMarker": "#EDEDED99" - }, - "chat": { - "userMessage": "#ededed", - "userMessageBackground": "#063056", - "assistantMessage": "#ededed", - "assistantMessageBackground": "#000000", - "timestamp": "#878787", - "divider": "#3f3f3f" + "listMarker": "#EDEDED99", + "bold": "#F75590", + "italic": "#F2A700", + "strikethrough": "#878787", + "hr": "#454545" }, "tools": { - "background": "#0f0f0f80", - "border": "#3f3f3fb3", - "headerHover": "#17171780", - "icon": "#878787", + "background": "#0f0f0f", + "border": "#2c2c2c", + "headerHover": "#171717", + "icon": "#080808", "title": "#ededed", "description": "#878787", "edit": { "added": "#38fc61", - "addedBackground": "#001402", + "addedBackground": "#001d04", "removed": "#f22942", - "removedBackground": "#240103", + "removedBackground": "#310206", + "modified": "#fdd8a4", + "modifiedBackground": "#0a0d11", "lineNumber": "#646464" + }, + "bash": { + "background": "#090909", + "foreground": "#ededed", + "info": "#52A8FF", + "warning": "#FFB224", + "error": "#E5484D" + }, + "lsp": { + "background": "#090909", + "foreground": "#ededed", + "info": "#52A8FF", + "warning": "#FFB224", + "error": "#E5484D" } + }, + "forms": { + "inputBackground": "#000000", + "inputForeground": "#ededed", + "inputBorder": "#2c2c2c", + "inputBorderHover": "#353535", + "inputBorderFocus": "#2280d6", + "inputPlaceholder": "#646464", + "inputDisabled": "#010101", + "inputSelection": "#065ca1", + "label": "#878787", + "helperText": "#646464" + }, + "buttons": { + "primary": { + "bg": "#0070F3", + "fg": "#ffffff", + "border": "#0e4374", + "hover": "#207dfc", + "active": "#2280d6", + "disabled": "#353535" + }, + "secondary": { + "bg": "#090909", + "fg": "#ededed", + "border": "#3f3f3f", + "hover": "#0f0f0f", + "active": "#171717", + "disabled": "#010101" + }, + "ghost": { + "bg": "#00000000", + "fg": "#ededed", + "border": "#00000000", + "hover": "#0f0f0f", + "active": "#171717", + "disabled": "#646464" + }, + "destructive": { + "bg": "#E5484D", + "fg": "#151313", + "border": "#7b101b", + "hover": "#7b101b", + "active": "#c41e2f", + "disabled": "#010101" + } + }, + "modal": { + "background": "#090909", + "foreground": "#ededed", + "border": "#3f3f3f", + "overlay": "#000000d6" + }, + "popover": { + "background": "#090909", + "foreground": "#ededed", + "border": "#3f3f3f", + "shadow": "0 18px 48px rgba(0, 0, 0, 0.45)" + }, + "commandPalette": { + "background": "#090909", + "foreground": "#ededed", + "border": "#3f3f3f", + "inputBackground": "#000000", + "selectedBackground": "#063056", + "selectedForeground": "#ededed", + "muted": "#878787" + }, + "fileAttachment": { + "background": "#0f0f0f", + "foreground": "#ededed", + "border": "#2c2c2c", + "icon": "#080808", + "removeHover": "#5b0710" + }, + "sessions": { + "background": "#000000", + "foreground": "#ededed", + "mutedForeground": "#878787", + "border": "#222222", + "hover": "#171717", + "active": "#063056" + }, + "modelSelector": { + "background": "#090909", + "foreground": "#ededed", + "border": "#3f3f3f", + "selectedBackground": "#063056", + "selectedForeground": "#ededed" + }, + "permissions": { + "background": "#090909", + "foreground": "#ededed", + "border": "#3f3f3f", + "allow": "#46A758", + "allowBackground": "#023a12", + "deny": "#E5484D", + "denyBackground": "#5b0710" + }, + "loading": { + "spinner": "#0070F3", + "spinnerTrack": "#171717", + "skeleton": "#0f0f0f", + "shimmer": "#171717" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#ededed33", + "thumbHover": "#ededed57" + }, + "badges": { + "default": { + "bg": "#0f0f0f", + "fg": "#ededed", + "border": "#2c2c2c" + }, + "info": { + "bg": "#063056", + "fg": "#52A8FF", + "border": "#0e4374" + }, + "success": { + "bg": "#023a12", + "fg": "#46A758", + "border": "#08501d" + }, + "warning": { + "bg": "#412900", + "fg": "#FFB224", + "border": "#593b03" + }, + "error": { + "bg": "#5b0710", + "fg": "#E5484D", + "border": "#7b101b" + } + }, + "toast": { + "background": "#090909", + "foreground": "#ededed", + "border": "#3f3f3f", + "success": { + "background": "#023a12", + "foreground": "#46A758", + "border": "#08501d" + }, + "warning": { + "background": "#412900", + "foreground": "#FFB224", + "border": "#593b03" + }, + "error": { + "background": "#5b0710", + "foreground": "#E5484D", + "border": "#7b101b" + }, + "info": { + "background": "#063056", + "foreground": "#52A8FF", + "border": "#0e4374" + } + }, + "emptyState": { + "icon": "#878787", + "title": "#ededed", + "description": "#878787", + "border": "#222222" + }, + "table": { + "border": "#222222", + "headerBackground": "#090909", + "headerForeground": "#ededed", + "rowHover": "#171717", + "rowSelected": "#063056" + }, + "charts": { + "series": [ + "#0070F3", + "#52A8FF", + "#46A758", + "#FFB224", + "#E5484D" + ] + }, + "a11y": { + "focusRing": "#2280d6", + "selection": "#063056", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(0, 0, 0, 0.22)", + "md": "0 12px 32px rgba(0, 0, 0, 0.32)", + "lg": "0 24px 56px rgba(0, 0, 0, 0.42)", + "focus": "0 0 0 3px #52A8FF59" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/vercel-light.json b/packages/ui/src/lib/theme/themes/vercel-light.json index 876ce007..0cd65907 100644 --- a/packages/ui/src/lib/theme/themes/vercel-light.json +++ b/packages/ui/src/lib/theme/themes/vercel-light.json @@ -2,79 +2,81 @@ "metadata": { "id": "vercel-light", "name": "Vercel", - "description": "Port of OpenCode Vercel theme (light variant)", + "description": "Ported from OpenCode Vercel theme (light variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "light", "tags": [ "light", "opencode", + "ported", "vercel" ] }, "colors": { "primary": { - "base": "#0570f2", + "base": "#0070F3", "hover": "#0767dd", - "active": "#0767dd", + "active": "#0570f2", "foreground": "#000000", - "muted": "#0570f280", + "muted": "#0070F380", "emphasis": "#0767dd" }, "surface": { "background": "#ffffff", "foreground": "#161616", - "muted": "#f1f1f1", + "muted": "#f4f4f4", "mutedForeground": "#666666", "elevated": "#f8f8f8", "elevatedForeground": "#161616", - "overlay": "#0000004d", + "overlay": "#ffffff33", "subtle": "#e8e8e8" }, "interactive": { "border": "#c6c6c6", "borderHover": "#b8b8b8", - "borderFocus": "#9ec3fb", - "selection": "#deebfe", - "selectionForeground": "#000000", - "focus": "#9ec3fb", - "focusRing": "#9ec3fb47", - "cursor": "#161616", - "hover": "#e8e8e8", - "active": "#e8e8e8" + "borderFocus": "#0570f2", + "selection": "#16161616", + "selectionForeground": "#161616", + "focus": "#0570f2", + "focusRing": "#0570f247", + "cursor": "#070707", + "hover": "#1616160e", + "active": "#16161616" }, "status": { - "error": "#d12139", + "error": "#DC3545", "errorForeground": "#000000", "errorBackground": "#ffe2e1", "errorBorder": "#fea6a4", - "warning": "#fcaa8d", + "warning": "#FF9500", "warningForeground": "#000000", "warningBackground": "#ffe4ce", "warningBorder": "#faaf68", - "success": "#7ddb7e", + "success": "#388E3C", "successForeground": "#000000", "successBackground": "#c2fcc1", "successBorder": "#7ddb7e", - "info": "#9ec3fb", + "info": "#0070F3", "infoForeground": "#000000", "infoBackground": "#deebfe", "infoBorder": "#9ec3fb" }, "pr": { - "open": "#7ddb7e", + "open": "#388E3C", "draft": "#666666", - "blocked": "#fcaa8d", - "merged": "#E93D82", - "closed": "#d12139" + "blocked": "#FF9500", + "merged": "#FFB224", + "closed": "#DC3545" }, "syntax": { "base": { - "background": "#f1f1f1", + "background": "#f8f8f8", "foreground": "#161616", "comment": "#888888", "keyword": "#E93D82", "string": "#46A758", - "number": "#8E4EC6", + "number": "#FFB224", "function": "#12A594", "variable": "#0070F3", "type": "#12A594", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#888888", - "stringEscape": "#FFB224", + "stringEscape": "#161616", "keywordImport": "#E93D82", "storageModifier": "#E93D82", "functionCall": "#12A594", @@ -90,7 +92,7 @@ "variableProperty": "#12A594", "variableOther": "#0070F3", "variableGlobal": "#FFB224", - "variableLocal": "#666666", + "variableLocal": "#171717", "parameter": "#0070F3", "constant": "#FFB224", "class": "#12A594", @@ -99,38 +101,65 @@ "struct": "#12A594", "enum": "#12A594", "typeParameter": "#12A594", - "namespace": "#E93D82", + "namespace": "#12A594", "module": "#E93D82", "tag": "#E93D82", "jsxTag": "#E93D82", "tagAttribute": "#12A594", "tagAttributeValue": "#46A758", - "boolean": "#8E4EC6", + "boolean": "#FFB224", "decorator": "#E93D82", - "label": "#E93D82", + "label": "#12A594", "punctuation": "#171717", "macro": "#E93D82", "preprocessor": "#E93D82", "regex": "#161616", - "url": "#0070F3", + "url": "#0767dd", "key": "#12A594", - "exception": "#d12139" + "exception": "#DC3545" }, "highlights": { "diffAdded": "#0a752b", - "diffAddedBackground": "#f8fff9", - "diffRemoved": "#e22539", - "diffRemovedBackground": "#fffcfc", + "diffAddedBackground": "#effff0", + "diffRemoved": "#b11829", + "diffRemovedBackground": "#fff7f7", "diffModified": "#FF8C00", - "diffModifiedBackground": "#e7edf7", + "diffModifiedBackground": "#f3f6fb", "lineNumber": "#898989", "lineNumberActive": "#161616" } }, + "header": { + "background": "#ffffff", + "foreground": "#161616", + "border": "#c6c6c6", + "icon": "#303030", + "hover": "#e8e8e8" + }, + "sidebar": { + "background": "#f4f4f4", + "foreground": "#666666", + "border": "#c6c6c6", + "icon": "#c9c9c9", + "hover": "#e8e8e8", + "active": "#deebfe", + "accent": "#0070F3", + "accentForeground": "#000000" + }, + "chat": { + "background": "#ffffff", + "userMessage": "#161616", + "userMessageBackground": "#f1f1f1", + "assistantMessage": "#161616", + "assistantMessageBackground": "#ffffff", + "timestamp": "#898989", + "divider": "#e2e2e2", + "typing": "#666666" + }, "markdown": { "heading1": "#8E4EC6", "heading2": "#8E4EC6", - "heading3": "#161616", + "heading3": "#070707", "heading4": "#161616", "link": "#0070F3", "linkHover": "#12A594", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#f1f1f1", "blockquote": "#666666", "blockquoteBorder": "#c6c6c6", - "listMarker": "#17171799" - }, - "chat": { - "userMessage": "#161616", - "userMessageBackground": "#deebfe", - "assistantMessage": "#161616", - "assistantMessageBackground": "#ffffff", - "timestamp": "#666666", - "divider": "#c6c6c6" + "listMarker": "#17171799", + "bold": "#E93D82", + "italic": "#FFB224", + "strikethrough": "#666666", + "hr": "#999999" }, "tools": { - "background": "#f1f1f180", - "border": "#c6c6c6b3", - "headerHover": "#e8e8e880", - "icon": "#666666", + "background": "#f1f1f1", + "border": "#e2e2e2", + "headerHover": "#e8e8e8", + "icon": "#c9c9c9", "title": "#161616", "description": "#666666", "edit": { "added": "#0a752b", - "addedBackground": "#f8fff9", + "addedBackground": "#effff0", "removed": "#e22539", - "removedBackground": "#fffcfc", + "removedBackground": "#fff7f7", + "modified": "#FF8C00", + "modifiedBackground": "#f3f6fb", "lineNumber": "#898989" + }, + "bash": { + "background": "#f8f8f8", + "foreground": "#161616", + "info": "#0070F3", + "warning": "#FF9500", + "error": "#DC3545" + }, + "lsp": { + "background": "#f8f8f8", + "foreground": "#161616", + "info": "#0070F3", + "warning": "#FF9500", + "error": "#DC3545" } + }, + "forms": { + "inputBackground": "#ffffff", + "inputForeground": "#161616", + "inputBorder": "#e2e2e2", + "inputBorderHover": "#d4d4d4", + "inputBorderFocus": "#0570f2", + "inputPlaceholder": "#898989", + "inputDisabled": "#ededed", + "inputSelection": "#deebfe", + "label": "#666666", + "helperText": "#898989" + }, + "buttons": { + "primary": { + "bg": "#0070F3", + "fg": "#000000", + "border": "#9ec3fb", + "hover": "#0767dd", + "active": "#0570f2", + "disabled": "#d0d0d0" + }, + "secondary": { + "bg": "#f8f8f8", + "fg": "#161616", + "border": "#c6c6c6", + "hover": "#f1f1f1", + "active": "#e8e8e8", + "disabled": "#ededed" + }, + "ghost": { + "bg": "#00000000", + "fg": "#161616", + "border": "#00000000", + "hover": "#f1f1f1", + "active": "#e8e8e8", + "disabled": "#898989" + }, + "destructive": { + "bg": "#DC3545", + "fg": "#000000", + "border": "#fea6a4", + "hover": "#ffd4d2", + "active": "#e4223e", + "disabled": "#ededed" + } + }, + "modal": { + "background": "#f8f8f8", + "foreground": "#161616", + "border": "#c6c6c6", + "overlay": "#ffffff3d" + }, + "popover": { + "background": "#f8f8f8", + "foreground": "#161616", + "border": "#c6c6c6", + "shadow": "0 18px 48px rgba(15, 15, 15, 0.16)" + }, + "commandPalette": { + "background": "#f8f8f8", + "foreground": "#161616", + "border": "#c6c6c6", + "inputBackground": "#ffffff", + "selectedBackground": "#deebfe", + "selectedForeground": "#161616", + "muted": "#666666" + }, + "fileAttachment": { + "background": "#f1f1f1", + "foreground": "#161616", + "border": "#e2e2e2", + "icon": "#c9c9c9", + "removeHover": "#ffe2e1" + }, + "sessions": { + "background": "#ffffff", + "foreground": "#161616", + "mutedForeground": "#666666", + "border": "#ececec", + "hover": "#e8e8e8", + "active": "#deebfe" + }, + "modelSelector": { + "background": "#f8f8f8", + "foreground": "#161616", + "border": "#c6c6c6", + "selectedBackground": "#deebfe", + "selectedForeground": "#161616" + }, + "permissions": { + "background": "#f8f8f8", + "foreground": "#161616", + "border": "#c6c6c6", + "allow": "#388E3C", + "allowBackground": "#c2fcc1", + "deny": "#DC3545", + "denyBackground": "#ffe2e1" + }, + "loading": { + "spinner": "#0070F3", + "spinnerTrack": "#e8e8e8", + "skeleton": "#f1f1f1", + "shimmer": "#e8e8e8" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#16161626", + "thumbHover": "#16161640" + }, + "badges": { + "default": { + "bg": "#f1f1f1", + "fg": "#161616", + "border": "#e2e2e2" + }, + "info": { + "bg": "#deebfe", + "fg": "#0070F3", + "border": "#9ec3fb" + }, + "success": { + "bg": "#c2fcc1", + "fg": "#388E3C", + "border": "#7ddb7e" + }, + "warning": { + "bg": "#ffe4ce", + "fg": "#FF9500", + "border": "#faaf68" + }, + "error": { + "bg": "#ffe2e1", + "fg": "#DC3545", + "border": "#fea6a4" + } + }, + "toast": { + "background": "#f8f8f8", + "foreground": "#161616", + "border": "#c6c6c6", + "success": { + "background": "#c2fcc1", + "foreground": "#388E3C", + "border": "#7ddb7e" + }, + "warning": { + "background": "#ffe4ce", + "foreground": "#FF9500", + "border": "#faaf68" + }, + "error": { + "background": "#ffe2e1", + "foreground": "#DC3545", + "border": "#fea6a4" + }, + "info": { + "background": "#deebfe", + "foreground": "#0070F3", + "border": "#9ec3fb" + } + }, + "emptyState": { + "icon": "#666666", + "title": "#161616", + "description": "#666666", + "border": "#ececec" + }, + "table": { + "border": "#ececec", + "headerBackground": "#f8f8f8", + "headerForeground": "#161616", + "rowHover": "#e8e8e8", + "rowSelected": "#deebfe" + }, + "charts": { + "series": [ + "#0070F3", + "#0070F3", + "#388E3C", + "#FF9500", + "#DC3545" + ] + }, + "a11y": { + "focusRing": "#0570f2", + "selection": "#deebfe", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(15, 15, 15, 0.08)", + "md": "0 12px 32px rgba(15, 15, 15, 0.12)", + "lg": "0 24px 56px rgba(15, 15, 15, 0.16)", + "focus": "0 0 0 3px #0070F340" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/zenburn-dark.json b/packages/ui/src/lib/theme/themes/zenburn-dark.json index 492a49e7..8e115203 100644 --- a/packages/ui/src/lib/theme/themes/zenburn-dark.json +++ b/packages/ui/src/lib/theme/themes/zenburn-dark.json @@ -2,79 +2,81 @@ "metadata": { "id": "zenburn-dark", "name": "Zenburn", - "description": "Port of OpenCode Zenburn theme (dark variant)", + "description": "Ported from OpenCode Zenburn theme (dark variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "dark", "tags": [ "dark", "opencode", + "ported", "zenburn" ] }, "colors": { "primary": { - "base": "#24a9af", + "base": "#8cd0d3", "hover": "#31bbc1", - "active": "#31bbc1", + "active": "#24a9af", "foreground": "#000000", - "muted": "#24a9af80", - "emphasis": "#31bbc1" + "muted": "#8cd0d380", + "emphasis": "#6deaf0" }, "surface": { "background": "#262626", "foreground": "#dcdccb", - "muted": "#323231", + "muted": "#2c2c2b", "mutedForeground": "#9f9f9f", "elevated": "#2d2d2c", "elevatedForeground": "#dcdccb", - "overlay": "#00000080", + "overlay": "#262626cc", "subtle": "#383836" }, "interactive": { "border": "#565652", "borderHover": "#5d5d58", - "borderFocus": "#084b4e", - "selection": "#033638", - "selectionForeground": "#ffffff", - "focus": "#084b4e", - "focusRing": "#084b4e59", - "cursor": "#dcdccb", - "hover": "#383836", - "active": "#383836" + "borderFocus": "#24a9af", + "selection": "#dcdccb1f", + "selectionForeground": "#dcdccb", + "focus": "#24a9af", + "focusRing": "#24a9af61", + "cursor": "#fcfcfa", + "hover": "#dcdccb17", + "active": "#dcdccb1f" }, "status": { - "error": "#b56264", - "errorForeground": "#ffffff", + "error": "#cc9393", + "errorForeground": "#151313", "errorBackground": "#52181d", "errorBorder": "#6b292d", - "warning": "#c89343", - "warningForeground": "#ffffff", + "warning": "#f0dfaf", + "warningForeground": "#151313", "warningBackground": "#3a2d04", "warningBorder": "#504009", - "success": "#4e8050", - "successForeground": "#ffffff", + "success": "#7f9f7f", + "successForeground": "#151313", "successBackground": "#133816", "successBorder": "#234d26", - "info": "#c37c49", - "infoForeground": "#ffffff", + "info": "#dfaf8f", + "infoForeground": "#151313", "infoBackground": "#492303", "infoBorder": "#643309" }, "pr": { - "open": "#4e8050", + "open": "#7f9f7f", "draft": "#9f9f9f", - "blocked": "#c89343", - "merged": "#f0dfaf", - "closed": "#b56264" + "blocked": "#f0dfaf", + "merged": "#8fb28f", + "closed": "#cc9393" }, "syntax": { "base": { - "background": "#323231", + "background": "#2d2d2c", "foreground": "#dcdccb", "comment": "#7f9f7f", "keyword": "#f0dfaf", "string": "#cc9393", - "number": "#8cd0d3", + "number": "#8fb28f", "function": "#93e0e3", "variable": "#dcdccc", "type": "#93e0e3", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#7f9f7f", - "stringEscape": "#8fb28f", + "stringEscape": "#dcdccb", "keywordImport": "#f0dfaf", "storageModifier": "#f0dfaf", "functionCall": "#93e0e3", @@ -90,7 +92,7 @@ "variableProperty": "#93e0e3", "variableOther": "#dcdccc", "variableGlobal": "#8fb28f", - "variableLocal": "#9f9f9f", + "variableLocal": "#dcdccc", "parameter": "#dcdccc", "constant": "#8fb28f", "class": "#93e0e3", @@ -99,38 +101,65 @@ "struct": "#93e0e3", "enum": "#93e0e3", "typeParameter": "#93e0e3", - "namespace": "#f0dfaf", + "namespace": "#93e0e3", "module": "#f0dfaf", "tag": "#f0dfaf", "jsxTag": "#f0dfaf", "tagAttribute": "#93e0e3", "tagAttributeValue": "#cc9393", - "boolean": "#8cd0d3", + "boolean": "#8fb28f", "decorator": "#f0dfaf", - "label": "#f0dfaf", + "label": "#93e0e3", "punctuation": "#dcdccc", "macro": "#f0dfaf", "preprocessor": "#f0dfaf", "regex": "#dcdccb", - "url": "#8cd0d3", + "url": "#6deaf0", "key": "#93e0e3", - "exception": "#b56264" + "exception": "#cc9393" }, "highlights": { "diffAdded": "#aae6aa", - "diffAddedBackground": "#011402", - "diffRemoved": "#d67c7e", - "diffRemovedBackground": "#220205", + "diffAddedBackground": "#021d05", + "diffRemoved": "#fcc3c3", + "diffRemovedBackground": "#2f0409", "diffModified": "#fdeab3", - "diffModifiedBackground": "#3d4444", + "diffModifiedBackground": "#303333", "lineNumber": "#7b7b7b", "lineNumberActive": "#dcdccb" } }, + "header": { + "background": "#262626", + "foreground": "#dcdccb", + "border": "#565652", + "icon": "#97968d", + "hover": "#383836" + }, + "sidebar": { + "background": "#2c2c2b", + "foreground": "#9f9f9f", + "border": "#565652", + "icon": "#3d3c3b", + "hover": "#383836", + "active": "#033638", + "accent": "#8cd0d3", + "accentForeground": "#000000" + }, + "chat": { + "background": "#262626", + "userMessage": "#dcdccb", + "userMessageBackground": "#323231", + "assistantMessage": "#dcdccb", + "assistantMessageBackground": "#262626", + "timestamp": "#7b7b7b", + "divider": "#474745", + "typing": "#9f9f9f" + }, "markdown": { "heading1": "#f0dfaf", "heading2": "#f0dfaf", - "heading3": "#dcdccb", + "heading3": "#fcfcfa", "heading4": "#dcdccb", "link": "#8cd0d3", "linkHover": "#93e0e3", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#323231", "blockquote": "#9f9f9f", "blockquoteBorder": "#565652", - "listMarker": "#8cd0d399" - }, - "chat": { - "userMessage": "#dcdccb", - "userMessageBackground": "#033638", - "assistantMessage": "#dcdccb", - "assistantMessageBackground": "#262626", - "timestamp": "#9f9f9f", - "divider": "#565652" + "listMarker": "#8cd0d399", + "bold": "#dfaf8f", + "italic": "#e0cf9f", + "strikethrough": "#9f9f9f", + "hr": "#9f9f9f" }, "tools": { - "background": "#32323180", - "border": "#565652b3", - "headerHover": "#38383680", - "icon": "#9f9f9f", + "background": "#323231", + "border": "#474745", + "headerHover": "#383836", + "icon": "#3d3c3b", "title": "#dcdccb", "description": "#9f9f9f", "edit": { "added": "#aae6aa", - "addedBackground": "#011402", + "addedBackground": "#021d05", "removed": "#d67c7e", - "removedBackground": "#220205", + "removedBackground": "#2f0409", + "modified": "#fdeab3", + "modifiedBackground": "#303333", "lineNumber": "#7b7b7b" + }, + "bash": { + "background": "#2d2d2c", + "foreground": "#dcdccb", + "info": "#dfaf8f", + "warning": "#f0dfaf", + "error": "#cc9393" + }, + "lsp": { + "background": "#2d2d2c", + "foreground": "#dcdccb", + "info": "#dfaf8f", + "warning": "#f0dfaf", + "error": "#cc9393" } + }, + "forms": { + "inputBackground": "#292929", + "inputForeground": "#dcdccb", + "inputBorder": "#474745", + "inputBorderHover": "#4f4f4b", + "inputBorderFocus": "#24a9af", + "inputPlaceholder": "#7b7b7b", + "inputDisabled": "#30302f", + "inputSelection": "#14676a", + "label": "#9f9f9f", + "helperText": "#7b7b7b" + }, + "buttons": { + "primary": { + "bg": "#8cd0d3", + "fg": "#000000", + "border": "#084b4e", + "hover": "#31bbc1", + "active": "#24a9af", + "disabled": "#4f4f4b" + }, + "secondary": { + "bg": "#2d2d2c", + "fg": "#dcdccb", + "border": "#565652", + "hover": "#323231", + "active": "#383836", + "disabled": "#30302f" + }, + "ghost": { + "bg": "#00000000", + "fg": "#dcdccb", + "border": "#00000000", + "hover": "#323231", + "active": "#383836", + "disabled": "#7b7b7b" + }, + "destructive": { + "bg": "#cc9393", + "fg": "#151313", + "border": "#6b292d", + "hover": "#6b292d", + "active": "#b56264", + "disabled": "#30302f" + } + }, + "modal": { + "background": "#2d2d2c", + "foreground": "#dcdccb", + "border": "#565652", + "overlay": "#262626d6" + }, + "popover": { + "background": "#2d2d2c", + "foreground": "#dcdccb", + "border": "#565652", + "shadow": "0 18px 48px rgba(0, 0, 0, 0.45)" + }, + "commandPalette": { + "background": "#2d2d2c", + "foreground": "#dcdccb", + "border": "#565652", + "inputBackground": "#292929", + "selectedBackground": "#033638", + "selectedForeground": "#dcdccb", + "muted": "#9f9f9f" + }, + "fileAttachment": { + "background": "#323231", + "foreground": "#dcdccb", + "border": "#474745", + "icon": "#3d3c3b", + "removeHover": "#52181d" + }, + "sessions": { + "background": "#262626", + "foreground": "#dcdccb", + "mutedForeground": "#9f9f9f", + "border": "#40403e", + "hover": "#383836", + "active": "#033638" + }, + "modelSelector": { + "background": "#2d2d2c", + "foreground": "#dcdccb", + "border": "#565652", + "selectedBackground": "#033638", + "selectedForeground": "#dcdccb" + }, + "permissions": { + "background": "#2d2d2c", + "foreground": "#dcdccb", + "border": "#565652", + "allow": "#7f9f7f", + "allowBackground": "#133816", + "deny": "#cc9393", + "denyBackground": "#52181d" + }, + "loading": { + "spinner": "#8cd0d3", + "spinnerTrack": "#383836", + "skeleton": "#323231", + "shimmer": "#383836" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#dcdccb33", + "thumbHover": "#dcdccb57" + }, + "badges": { + "default": { + "bg": "#323231", + "fg": "#dcdccb", + "border": "#474745" + }, + "info": { + "bg": "#492303", + "fg": "#dfaf8f", + "border": "#643309" + }, + "success": { + "bg": "#133816", + "fg": "#7f9f7f", + "border": "#234d26" + }, + "warning": { + "bg": "#3a2d04", + "fg": "#f0dfaf", + "border": "#504009" + }, + "error": { + "bg": "#52181d", + "fg": "#cc9393", + "border": "#6b292d" + } + }, + "toast": { + "background": "#2d2d2c", + "foreground": "#dcdccb", + "border": "#565652", + "success": { + "background": "#133816", + "foreground": "#7f9f7f", + "border": "#234d26" + }, + "warning": { + "background": "#3a2d04", + "foreground": "#f0dfaf", + "border": "#504009" + }, + "error": { + "background": "#52181d", + "foreground": "#cc9393", + "border": "#6b292d" + }, + "info": { + "background": "#492303", + "foreground": "#dfaf8f", + "border": "#643309" + } + }, + "emptyState": { + "icon": "#9f9f9f", + "title": "#dcdccb", + "description": "#9f9f9f", + "border": "#40403e" + }, + "table": { + "border": "#40403e", + "headerBackground": "#2d2d2c", + "headerForeground": "#dcdccb", + "rowHover": "#383836", + "rowSelected": "#033638" + }, + "charts": { + "series": [ + "#8cd0d3", + "#dfaf8f", + "#7f9f7f", + "#f0dfaf", + "#cc9393" + ] + }, + "a11y": { + "focusRing": "#24a9af", + "selection": "#033638", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(0, 0, 0, 0.22)", + "md": "0 12px 32px rgba(0, 0, 0, 0.32)", + "lg": "0 24px 56px rgba(0, 0, 0, 0.42)", + "focus": "0 0 0 3px #8cd0d359" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/lib/theme/themes/zenburn-light.json b/packages/ui/src/lib/theme/themes/zenburn-light.json index 1026c4cf..74471b9e 100644 --- a/packages/ui/src/lib/theme/themes/zenburn-light.json +++ b/packages/ui/src/lib/theme/themes/zenburn-light.json @@ -2,79 +2,81 @@ "metadata": { "id": "zenburn-light", "name": "Zenburn", - "description": "Port of OpenCode Zenburn theme (light variant)", + "description": "Ported from OpenCode Zenburn theme (light variant)", + "author": "OpenCode", "version": "1.0.0", "variant": "light", "tags": [ "light", "opencode", + "ported", "zenburn" ] }, "colors": { "primary": { - "base": "#588094", + "base": "#5f7f8f", "hover": "#4d7689", - "active": "#4d7689", + "active": "#588094", "foreground": "#000000", - "muted": "#58809480", + "muted": "#5f7f8f80", "emphasis": "#4d7689" }, "surface": { "background": "#fffff4", "foreground": "#333333", - "muted": "#f4f4e9", + "muted": "#f6f6eb", "mutedForeground": "#6f6f6f", "elevated": "#f9f9ef", "elevatedForeground": "#333333", - "overlay": "#0000004d", + "overlay": "#fffff433", "subtle": "#ecece2" }, "interactive": { "border": "#d0d0c8", "borderHover": "#c5c5bd", - "borderFocus": "#a3c8da", - "selection": "#d7eefa", - "selectionForeground": "#000000", - "focus": "#a3c8da", - "focusRing": "#a3c8da47", - "cursor": "#333333", - "hover": "#ecece2", - "active": "#ecece2" + "borderFocus": "#588094", + "selection": "#33333316", + "selectionForeground": "#333333", + "focus": "#588094", + "focusRing": "#58809447", + "cursor": "#222222", + "hover": "#3333330e", + "active": "#33333316" }, "status": { - "error": "#8b5051", - "errorForeground": "#000000", + "error": "#8f5f5f", + "errorForeground": "#ffffff", "errorBackground": "#fee2e1", "errorBorder": "#eab0b0", - "warning": "#d5bf8f", + "warning": "#8f8f5f", "warningForeground": "#000000", "warningBackground": "#ecedca", "warningBorder": "#c5c58f", - "success": "#9bd29a", + "success": "#5f8f5f", "successForeground": "#000000", "successBackground": "#d2f5d1", "successBorder": "#9bd29a", - "info": "#d2bf9a", + "info": "#8f7f5f", "infoForeground": "#000000", "infoBackground": "#f5e9d1", "infoBorder": "#d2bf9a" }, "pr": { - "open": "#9bd29a", + "open": "#5f8f5f", "draft": "#6f6f6f", - "blocked": "#d5bf8f", - "merged": "#8f8f5f", - "closed": "#8b5051" + "blocked": "#8f8f5f", + "merged": "#5f8f5f", + "closed": "#8f5f5f" }, "syntax": { "base": { - "background": "#f4f4e9", + "background": "#f9f9ef", "foreground": "#333333", "comment": "#5f7f5f", "keyword": "#8f8f5f", "string": "#8f5f5f", - "number": "#5f7f8f", + "number": "#5f8f5f", "function": "#5f8f8f", "variable": "#3f3f3f", "type": "#5f8f8f", @@ -82,7 +84,7 @@ }, "tokens": { "commentDoc": "#5f7f5f", - "stringEscape": "#5f8f5f", + "stringEscape": "#333333", "keywordImport": "#8f8f5f", "storageModifier": "#8f8f5f", "functionCall": "#5f8f8f", @@ -90,7 +92,7 @@ "variableProperty": "#5f8f8f", "variableOther": "#3f3f3f", "variableGlobal": "#5f8f5f", - "variableLocal": "#6f6f6f", + "variableLocal": "#3f3f3f", "parameter": "#3f3f3f", "constant": "#5f8f5f", "class": "#5f8f8f", @@ -99,38 +101,65 @@ "struct": "#5f8f8f", "enum": "#5f8f8f", "typeParameter": "#5f8f8f", - "namespace": "#8f8f5f", + "namespace": "#5f8f8f", "module": "#8f8f5f", "tag": "#8f8f5f", "jsxTag": "#8f8f5f", "tagAttribute": "#5f8f8f", "tagAttributeValue": "#8f5f5f", - "boolean": "#5f7f8f", + "boolean": "#5f8f5f", "decorator": "#8f8f5f", - "label": "#8f8f5f", + "label": "#5f8f8f", "punctuation": "#3f3f3f", "macro": "#8f8f5f", "preprocessor": "#8f8f5f", "regex": "#333333", - "url": "#5f7f8f", + "url": "#4d7689", "key": "#5f8f8f", - "exception": "#8b5051" + "exception": "#8f5f5f" }, "highlights": { "diffAdded": "#4c694c", - "diffAddedBackground": "#fafefa", - "diffRemoved": "#996e6e", - "diffRemovedBackground": "#fffcfc", + "diffAddedBackground": "#f5fcf5", + "diffRemoved": "#7b5555", + "diffRemovedBackground": "#fff7f7", "diffModified": "#5f5d10", - "diffModifiedBackground": "#eceee6", + "diffModifiedBackground": "#f5f6ed", "lineNumber": "#939393", "lineNumberActive": "#333333" } }, + "header": { + "background": "#fffff4", + "foreground": "#333333", + "border": "#d0d0c8", + "icon": "#505050", + "hover": "#ecece2" + }, + "sidebar": { + "background": "#f6f6eb", + "foreground": "#6f6f6f", + "border": "#d0d0c8", + "icon": "#d4d3ca", + "hover": "#ecece2", + "active": "#d7eefa", + "accent": "#5f7f8f", + "accentForeground": "#000000" + }, + "chat": { + "background": "#fffff4", + "userMessage": "#333333", + "userMessageBackground": "#f4f4e9", + "assistantMessage": "#333333", + "assistantMessageBackground": "#fffff4", + "timestamp": "#939393", + "divider": "#e7e7de", + "typing": "#6f6f6f" + }, "markdown": { "heading1": "#8f8f5f", "heading2": "#8f8f5f", - "heading3": "#333333", + "heading3": "#222222", "heading4": "#333333", "link": "#5f7f8f", "linkHover": "#5f8f8f", @@ -138,30 +167,242 @@ "inlineCodeBackground": "#f4f4e9", "blockquote": "#6f6f6f", "blockquoteBorder": "#d0d0c8", - "listMarker": "#5f7f8f99" - }, - "chat": { - "userMessage": "#333333", - "userMessageBackground": "#d7eefa", - "assistantMessage": "#333333", - "assistantMessageBackground": "#fffff4", - "timestamp": "#6f6f6f", - "divider": "#d0d0c8" + "listMarker": "#5f7f8f99", + "bold": "#8f7f5f", + "italic": "#8f8f5f", + "strikethrough": "#6f6f6f", + "hr": "#6f6f6f" }, "tools": { - "background": "#f4f4e980", - "border": "#d0d0c8b3", - "headerHover": "#ecece280", - "icon": "#6f6f6f", + "background": "#f4f4e9", + "border": "#e7e7de", + "headerHover": "#ecece2", + "icon": "#d4d3ca", "title": "#333333", "description": "#6f6f6f", "edit": { "added": "#4c694c", - "addedBackground": "#fafefa", + "addedBackground": "#f5fcf5", "removed": "#996e6e", - "removedBackground": "#fffcfc", + "removedBackground": "#fff7f7", + "modified": "#5f5d10", + "modifiedBackground": "#f5f6ed", "lineNumber": "#939393" + }, + "bash": { + "background": "#f9f9ef", + "foreground": "#333333", + "info": "#8f7f5f", + "warning": "#8f8f5f", + "error": "#8f5f5f" + }, + "lsp": { + "background": "#f9f9ef", + "foreground": "#333333", + "info": "#8f7f5f", + "warning": "#8f8f5f", + "error": "#8f5f5f" } + }, + "forms": { + "inputBackground": "#fffff4", + "inputForeground": "#333333", + "inputBorder": "#e7e7de", + "inputBorderHover": "#dcdcd3", + "inputBorderFocus": "#588094", + "inputPlaceholder": "#939393", + "inputDisabled": "#f1f1e5", + "inputSelection": "#d7eefa", + "label": "#6f6f6f", + "helperText": "#939393" + }, + "buttons": { + "primary": { + "bg": "#5f7f8f", + "fg": "#000000", + "border": "#a3c8da", + "hover": "#4d7689", + "active": "#588094", + "disabled": "#d8d8cf" + }, + "secondary": { + "bg": "#f9f9ef", + "fg": "#333333", + "border": "#d0d0c8", + "hover": "#f4f4e9", + "active": "#ecece2", + "disabled": "#f1f1e5" + }, + "ghost": { + "bg": "#00000000", + "fg": "#333333", + "border": "#00000000", + "hover": "#f4f4e9", + "active": "#ecece2", + "disabled": "#939393" + }, + "destructive": { + "bg": "#8f5f5f", + "fg": "#ffffff", + "border": "#eab0b0", + "hover": "#fed4d3", + "active": "#955b5c", + "disabled": "#f1f1e5" + } + }, + "modal": { + "background": "#f9f9ef", + "foreground": "#333333", + "border": "#d0d0c8", + "overlay": "#fffff43d" + }, + "popover": { + "background": "#f9f9ef", + "foreground": "#333333", + "border": "#d0d0c8", + "shadow": "0 18px 48px rgba(15, 15, 15, 0.16)" + }, + "commandPalette": { + "background": "#f9f9ef", + "foreground": "#333333", + "border": "#d0d0c8", + "inputBackground": "#fffff4", + "selectedBackground": "#d7eefa", + "selectedForeground": "#333333", + "muted": "#6f6f6f" + }, + "fileAttachment": { + "background": "#f4f4e9", + "foreground": "#333333", + "border": "#e7e7de", + "icon": "#d4d3ca", + "removeHover": "#fee2e1" + }, + "sessions": { + "background": "#fffff4", + "foreground": "#333333", + "mutedForeground": "#6f6f6f", + "border": "#efefe5", + "hover": "#ecece2", + "active": "#d7eefa" + }, + "modelSelector": { + "background": "#f9f9ef", + "foreground": "#333333", + "border": "#d0d0c8", + "selectedBackground": "#d7eefa", + "selectedForeground": "#333333" + }, + "permissions": { + "background": "#f9f9ef", + "foreground": "#333333", + "border": "#d0d0c8", + "allow": "#5f8f5f", + "allowBackground": "#d2f5d1", + "deny": "#8f5f5f", + "denyBackground": "#fee2e1" + }, + "loading": { + "spinner": "#5f7f8f", + "spinnerTrack": "#ecece2", + "skeleton": "#f4f4e9", + "shimmer": "#ecece2" + }, + "scrollbar": { + "track": "transparent", + "thumb": "#33333326", + "thumbHover": "#33333340" + }, + "badges": { + "default": { + "bg": "#f4f4e9", + "fg": "#333333", + "border": "#e7e7de" + }, + "info": { + "bg": "#f5e9d1", + "fg": "#8f7f5f", + "border": "#d2bf9a" + }, + "success": { + "bg": "#d2f5d1", + "fg": "#5f8f5f", + "border": "#9bd29a" + }, + "warning": { + "bg": "#ecedca", + "fg": "#8f8f5f", + "border": "#c5c58f" + }, + "error": { + "bg": "#fee2e1", + "fg": "#8f5f5f", + "border": "#eab0b0" + } + }, + "toast": { + "background": "#f9f9ef", + "foreground": "#333333", + "border": "#d0d0c8", + "success": { + "background": "#d2f5d1", + "foreground": "#5f8f5f", + "border": "#9bd29a" + }, + "warning": { + "background": "#ecedca", + "foreground": "#8f8f5f", + "border": "#c5c58f" + }, + "error": { + "background": "#fee2e1", + "foreground": "#8f5f5f", + "border": "#eab0b0" + }, + "info": { + "background": "#f5e9d1", + "foreground": "#8f7f5f", + "border": "#d2bf9a" + } + }, + "emptyState": { + "icon": "#6f6f6f", + "title": "#333333", + "description": "#6f6f6f", + "border": "#efefe5" + }, + "table": { + "border": "#efefe5", + "headerBackground": "#f9f9ef", + "headerForeground": "#333333", + "rowHover": "#ecece2", + "rowSelected": "#d7eefa" + }, + "charts": { + "series": [ + "#5f7f8f", + "#8f7f5f", + "#5f8f5f", + "#8f8f5f", + "#8f5f5f" + ] + }, + "a11y": { + "focusRing": "#588094", + "selection": "#d7eefa", + "highContrast": false + }, + "shadows": { + "sm": "0 2px 8px rgba(15, 15, 15, 0.08)", + "md": "0 12px 32px rgba(15, 15, 15, 0.12)", + "lg": "0 24px 56px rgba(15, 15, 15, 0.16)", + "focus": "0 0 0 3px #5f7f8f40" + }, + "animation": { + "fast": "150ms ease", + "normal": "250ms ease", + "slow": "350ms ease", + "emphasis": "450ms cubic-bezier(0.2, 0.8, 0.2, 1)" } }, "config": { @@ -178,6 +419,13 @@ "xl": "0.75rem", "full": "9999px" }, + "spacing": { + "xs": "0.25rem", + "sm": "0.5rem", + "md": "0.75rem", + "lg": "1rem", + "xl": "1.5rem" + }, "transitions": { "fast": "150ms ease", "normal": "250ms ease", diff --git a/packages/ui/src/stores/sessionStore.ts b/packages/ui/src/stores/sessionStore.ts index c1a44c45..788bfd7e 100644 --- a/packages/ui/src/stores/sessionStore.ts +++ b/packages/ui/src/stores/sessionStore.ts @@ -728,16 +728,21 @@ export const useSessionStore = create()( try { const pageSize = 500; + const previousArchivedSessions = dedupeSessionsById(get().archivedSessions); const firstPage = await apiClient.experimental.session.list({ limit: pageSize, archived: false }); let liveSessions = dedupeSessionsById(Array.isArray(firstPage.data) ? firstPage.data as Session[] : []); let archivedSessions: Session[] = []; + let hasLoadedArchivedSessions = false; const apply = async () => { if (!isLatestRequest()) { return; } const projectResults = await buildProjectResults(liveSessions); - await applyProjectResults(projectResults, dedupeSessionsById(archivedSessions)); + const archivedForRender = hasLoadedArchivedSessions + ? dedupeSessionsById(archivedSessions) + : previousArchivedSessions; + await applyProjectResults(projectResults, archivedForRender); }; await apply(); @@ -770,6 +775,7 @@ export const useSessionStore = create()( ? (response.data as Session[]).filter((session) => Boolean(session.time?.archived)) : []; if (page.length > 0) { + hasLoadedArchivedSessions = true; archivedSessions = dedupeSessionsById([...archivedSessions, ...page]); await apply(); } @@ -779,6 +785,12 @@ export const useSessionStore = create()( } archivedCursor = next; } + + if (!hasLoadedArchivedSessions && isLatestRequest()) { + hasLoadedArchivedSessions = true; + archivedSessions = []; + await apply(); + } }; void backgroundLoad().catch((error) => { diff --git a/packages/vscode/package.json b/packages/vscode/package.json index dd0c7e11..6e1bacc5 100644 --- a/packages/vscode/package.json +++ b/packages/vscode/package.json @@ -229,7 +229,7 @@ }, "dependencies": { "@openchamber/ui": "workspace:*", - "@opencode-ai/sdk": "^1.2.20", + "@opencode-ai/sdk": "^1.2.26", "adm-zip": "^0.5.16", "jsonc-parser": "^3.3.1", "react": "^19.1.1", diff --git a/packages/vscode/src/bridge.ts b/packages/vscode/src/bridge.ts index a78e5aa6..0db67125 100644 --- a/packages/vscode/src/bridge.ts +++ b/packages/vscode/src/bridge.ts @@ -903,6 +903,7 @@ const execGit = async (args: string[], cwd: string): Promise<{ stdout: string; s cwd, stdio: ['ignore', 'pipe', 'pipe'], env, + windowsHide: true, }); let stdout = ''; diff --git a/packages/vscode/src/gitService.ts b/packages/vscode/src/gitService.ts index 4b7b8e8b..9757272e 100644 --- a/packages/vscode/src/gitService.ts +++ b/packages/vscode/src/gitService.ts @@ -219,6 +219,7 @@ async function execGit(args: string[], cwd: string): Promise<{ stdout: string; s const proc = spawn(gitPath, args, { cwd: normalizedCwd, env, + windowsHide: true, }); let stdout = ''; diff --git a/packages/vscode/src/opencode.ts b/packages/vscode/src/opencode.ts index 4139ddca..e1351e1f 100644 --- a/packages/vscode/src/opencode.ts +++ b/packages/vscode/src/opencode.ts @@ -359,6 +359,7 @@ async function spawnManagedOpenCodeServer( cwd: workingDirectory, env: { ...process.env }, stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, shell: shouldUseWindowsShell(binary), }); diff --git a/packages/vscode/webview/main.tsx b/packages/vscode/webview/main.tsx index 8670ede5..e9231876 100644 --- a/packages/vscode/webview/main.tsx +++ b/packages/vscode/webview/main.tsx @@ -971,10 +971,7 @@ onCommand('addToContext', (payload) => { // Import the store dynamically to avoid circular dependencies import('@/stores/useSessionStore').then(({ useSessionStore }) => { const store = useSessionStore.getState(); - const currentText = store.pendingInputText || ''; - // Append to existing text with double newline separator - const newText = currentText ? `${currentText}\n\n${text}` : text; - store.setPendingInputText(newText); + store.setPendingInputText(text, 'append'); }); }); diff --git a/packages/web/bin/cli.js b/packages/web/bin/cli.js index 99d05f11..5bc59cba 100644 --- a/packages/web/bin/cli.js +++ b/packages/web/bin/cli.js @@ -508,7 +508,11 @@ function isBunRuntime() { function isBunInstalled() { try { - const result = spawnSync(BUN_BIN, ['--version'], { stdio: 'ignore', env: process.env }); + const result = spawnSync(BUN_BIN, ['--version'], { + stdio: 'ignore', + env: process.env, + windowsHide: true, + }); return result.status === 0; } catch { return false; diff --git a/packages/web/package.json b/packages/web/package.json index 1702f5dc..3eb9b095 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -29,7 +29,7 @@ "@fontsource/ibm-plex-sans": "^5.1.1", "@ibm/plex": "^6.4.1", "@octokit/rest": "^22.0.1", - "@opencode-ai/sdk": "^1.2.20", + "@opencode-ai/sdk": "^1.2.26", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", diff --git a/packages/web/server/index.js b/packages/web/server/index.js index fb730830..1ec130a1 100644 --- a/packages/web/server/index.js +++ b/packages/web/server/index.js @@ -111,6 +111,101 @@ const normalizeDirectoryPath = (value) => { return trimmed; }; +const normalizePathForPersistence = (value) => { + if (typeof value !== 'string') { + return value; + } + + const normalized = normalizeDirectoryPath(value); + if (typeof normalized !== 'string') { + return normalized; + } + + const trimmed = normalized.trim(); + if (!trimmed) { + return trimmed; + } + + if (process.platform !== 'win32') { + return trimmed; + } + + return trimmed.replace(/\//g, '\\'); +}; + +const areStringArraysEqual = (a, b) => { + if (!Array.isArray(a) || !Array.isArray(b)) { + return false; + } + if (a.length !== b.length) { + return false; + } + for (let i = 0; i < a.length; i += 1) { + if (a[i] !== b[i]) { + return false; + } + } + return true; +}; + +const normalizeSettingsPaths = (input) => { + const settings = input && typeof input === 'object' ? input : {}; + let next = settings; + let changed = false; + + const ensureNext = () => { + if (next === settings) { + next = { ...settings }; + } + }; + + const normalizePathField = (key) => { + if (typeof settings[key] !== 'string' || settings[key].length === 0) { + return; + } + const normalized = normalizePathForPersistence(settings[key]); + if (normalized !== settings[key]) { + ensureNext(); + next[key] = normalized; + changed = true; + } + }; + + const normalizePathArrayField = (key) => { + if (!Array.isArray(settings[key])) { + return; + } + + const normalized = normalizeStringArray( + settings[key] + .map((entry) => (typeof entry === 'string' ? normalizePathForPersistence(entry) : entry)) + .filter((entry) => typeof entry === 'string' && entry.length > 0) + ); + + if (!areStringArraysEqual(normalized, settings[key])) { + ensureNext(); + next[key] = normalized; + changed = true; + } + }; + + normalizePathField('lastDirectory'); + normalizePathField('homeDirectory'); + normalizePathArrayField('approvedDirectories'); + normalizePathArrayField('pinnedDirectories'); + + if (Array.isArray(settings.projects)) { + const normalizedProjects = sanitizeProjects(settings.projects) || []; + if (JSON.stringify(normalizedProjects) !== JSON.stringify(settings.projects)) { + ensureNext(); + next.projects = normalizedProjects; + changed = true; + } + } + + return { settings: next, changed }; +}; + const OPENCHAMBER_USER_CONFIG_ROOT = path.join(os.homedir(), '.config', 'openchamber'); const OPENCHAMBER_USER_THEMES_DIR = path.join(OPENCHAMBER_USER_CONFIG_ROOT, 'themes'); @@ -562,7 +657,7 @@ const searchFilesystemFiles = async (rootPath, options) => { } const result = await new Promise((resolve) => { - const child = spawn('git', ['check-ignore', '--', ...pathsToCheck], { + const child = spawn(resolveGitBinaryForSpawn(), ['check-ignore', '--', ...pathsToCheck], { cwd: dir, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'], @@ -1136,7 +1231,11 @@ const buildTemplateVariables = async (payload, sessionId) => { if (worktreeDir) { try { const { simpleGit } = await import('simple-git'); - const git = simpleGit({ baseDir: worktreeDir, spawnOptions: { windowsHide: true } }); + const git = simpleGit({ + baseDir: worktreeDir, + spawnOptions: { windowsHide: true }, + binary: resolveGitBinaryForSpawn(), + }); branch = await Promise.race([ git.revparse(['--abbrev-ref', 'HEAD']), new Promise((_, reject) => setTimeout(() => reject(new Error('git timeout')), 3000)), @@ -1802,7 +1901,8 @@ const sanitizeProjects = (input) => { const candidate = entry; const id = typeof candidate.id === 'string' ? candidate.id.trim() : ''; const rawPath = typeof candidate.path === 'string' ? candidate.path.trim() : ''; - const normalizedPath = rawPath ? path.resolve(normalizeDirectoryPath(rawPath)) : ''; + const resolvedPath = rawPath ? path.resolve(normalizeDirectoryPath(rawPath)) : ''; + const normalizedPath = resolvedPath ? normalizePathForPersistence(resolvedPath) : ''; const label = typeof candidate.label === 'string' ? candidate.label.trim() : ''; const icon = typeof candidate.icon === 'string' ? candidate.icon.trim() : ''; const iconImage = candidate.iconImage && typeof candidate.iconImage === 'object' @@ -1912,10 +2012,16 @@ const sanitizeSettingsUpdate = (payload) => { result.splashFgDark = candidate.splashFgDark.trim(); } if (typeof candidate.lastDirectory === 'string' && candidate.lastDirectory.length > 0) { - result.lastDirectory = candidate.lastDirectory; + const normalized = normalizePathForPersistence(candidate.lastDirectory); + if (typeof normalized === 'string' && normalized.length > 0) { + result.lastDirectory = normalized; + } } if (typeof candidate.homeDirectory === 'string' && candidate.homeDirectory.length > 0) { - result.homeDirectory = candidate.homeDirectory; + const normalized = normalizePathForPersistence(candidate.homeDirectory); + if (typeof normalized === 'string' && normalized.length > 0) { + result.homeDirectory = normalized; + } } // Absolute path to the opencode CLI binary (optional override). @@ -1936,13 +2042,21 @@ const sanitizeSettingsUpdate = (payload) => { } if (Array.isArray(candidate.approvedDirectories)) { - result.approvedDirectories = normalizeStringArray(candidate.approvedDirectories); + result.approvedDirectories = normalizeStringArray( + candidate.approvedDirectories + .map((entry) => (typeof entry === 'string' ? normalizePathForPersistence(entry) : entry)) + .filter((entry) => typeof entry === 'string' && entry.length > 0) + ); } if (Array.isArray(candidate.securityScopedBookmarks)) { result.securityScopedBookmarks = normalizeStringArray(candidate.securityScopedBookmarks); } if (Array.isArray(candidate.pinnedDirectories)) { - result.pinnedDirectories = normalizeStringArray(candidate.pinnedDirectories); + result.pinnedDirectories = normalizeStringArray( + candidate.pinnedDirectories + .map((entry) => (typeof entry === 'string' ? normalizePathForPersistence(entry) : entry)) + .filter((entry) => typeof entry === 'string' && entry.length > 0) + ); } @@ -2732,10 +2846,11 @@ const readSettingsFromDiskMigrated = async () => { const migration3 = await migrateSettingsFromLegacyCollapsedProjects(migration2.settings); const migration4 = await migrateSettingsNotificationDefaults(migration3.settings); const migration5 = await migrateSettingsFromLegacyNamedTunnelKeys(migration4.settings); - if (migration1.changed || migration2.changed || migration3.changed || migration4.changed || migration5.changed) { - await writeSettingsToDisk(migration5.settings); + const migration6 = normalizeSettingsPaths(migration5.settings); + if (migration1.changed || migration2.changed || migration3.changed || migration4.changed || migration5.changed || migration6.changed) { + await writeSettingsToDisk(migration6.settings); } - return migration5.settings; + return migration6.settings; }; const getOrCreateVapidKeys = async () => { @@ -3401,6 +3516,11 @@ const persistSettings = async (changes) => { const sanitized = sanitizeSettingsUpdate(changes); let next = mergePersistedSettings(current, sanitized); + const normalizedState = normalizeSettingsPaths(next); + if (normalizedState.changed) { + next = normalizedState.settings; + } + if (Array.isArray(next.projects)) { console.log(`[persistSettings] Validating ${next.projects.length} projects...`); const validated = await validateProjectEntries(next.projects); @@ -3795,6 +3915,7 @@ function getLoginShellEnvSnapshot() { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], maxBuffer: 10 * 1024 * 1024, + windowsHide: true, }); if (result.status !== 0) { @@ -3833,6 +3954,7 @@ function getWindowsShellEnvSnapshot() { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], maxBuffer: 10 * 1024 * 1024, + windowsHide: true, }); if (result.status !== 0) { continue; @@ -3852,6 +3974,7 @@ function getWindowsShellEnvSnapshot() { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], maxBuffer: 10 * 1024 * 1024, + windowsHide: true, }); if (result.status === 0 && typeof result.stdout === 'string' && result.stdout.length > 0) { return parseNullSeparatedEnvSnapshot(result.stdout.replace(/\r?\n/g, '\0')); @@ -3921,11 +4044,88 @@ let resolvedOpencodeBinary = null; let resolvedOpencodeBinarySource = null; let resolvedNodeBinary = null; let resolvedBunBinary = null; +let resolvedGitBinary = null; let useWslForOpencode = false; let resolvedWslBinary = null; let resolvedWslOpencodePath = null; let resolvedWslDistro = null; +function resolveGitBinaryForSpawn() { + if (process.platform !== 'win32') { + return 'git'; + } + + if (resolvedGitBinary) { + return resolvedGitBinary; + } + + const explicit = [process.env.GIT_BINARY, process.env.OPENCHAMBER_GIT_BINARY] + .map((value) => (typeof value === 'string' ? value.trim() : '')) + .filter(Boolean); + for (const candidate of explicit) { + if (isExecutable(candidate)) { + resolvedGitBinary = candidate; + return resolvedGitBinary; + } + } + + const candidates = []; + const normalizeGitCandidate = (candidate) => { + if (typeof candidate !== 'string') { + return ''; + } + const trimmed = candidate.trim(); + if (!trimmed) { + return ''; + } + const ext = path.extname(trimmed).toLowerCase(); + if (ext === '.cmd' || ext === '.bat' || ext === '.com') { + const exeCandidate = trimmed.slice(0, -ext.length) + '.exe'; + if (isExecutable(exeCandidate)) { + return exeCandidate; + } + } + return trimmed; + }; + + const pathCandidate = normalizeGitCandidate(searchPathFor('git')); + if (pathCandidate && isExecutable(pathCandidate)) { + candidates.push(pathCandidate); + } + + const pathExeCandidate = normalizeGitCandidate(searchPathFor('git.exe')); + if (pathExeCandidate && isExecutable(pathExeCandidate)) { + candidates.push(pathExeCandidate); + } + + const programRoots = [ + process.env.ProgramFiles, + process.env['ProgramFiles(x86)'], + process.env.LocalAppData, + ] + .map((value) => (typeof value === 'string' ? value.trim() : '')) + .filter(Boolean); + for (const root of programRoots) { + const installCandidates = [ + path.join(root, 'Git', 'cmd', 'git.exe'), + path.join(root, 'Git', 'bin', 'git.exe'), + path.join(root, 'Git', 'mingw64', 'bin', 'git.exe'), + path.join(root, 'Programs', 'Git', 'cmd', 'git.exe'), + path.join(root, 'Programs', 'Git', 'bin', 'git.exe'), + ]; + for (const candidate of installCandidates) { + const normalized = normalizeGitCandidate(candidate); + if (normalized && isExecutable(normalized)) { + candidates.push(normalized); + } + } + } + + const preferredExe = candidates.find((candidate) => candidate.toLowerCase().endsWith('.exe')); + resolvedGitBinary = preferredExe || candidates[0] || 'git.exe'; + return resolvedGitBinary; +} + function isExecutable(filePath) { try { const stat = fs.statSync(filePath); @@ -3996,6 +4196,7 @@ function resolveWslExecutablePath() { const result = spawnSync('where', ['wsl'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, }); if (result.status === 0) { const lines = (result.stdout || '') @@ -4047,6 +4248,7 @@ function probeWslForOpencode() { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 6000, + windowsHide: true, }, ); @@ -4163,6 +4365,7 @@ function resolveOpencodeCliPath() { const result = spawnSync('where', ['opencode'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, }); if (result.status === 0) { const lines = (result.stdout || '') @@ -4198,6 +4401,7 @@ function resolveOpencodeCliPath() { const result = spawnSync(shell, ['-lic', 'command -v opencode'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, }); if (result.status === 0) { const found = (result.stdout || '').trim().split(/\s+/).pop() || ''; @@ -4248,6 +4452,7 @@ function resolveNodeCliPath() { const result = spawnSync('where', ['node'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, }); if (result.status === 0) { const lines = (result.stdout || '') @@ -4270,6 +4475,7 @@ function resolveNodeCliPath() { const result = spawnSync(shell, ['-lic', 'command -v node'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, }); if (result.status === 0) { const found = (result.stdout || '').trim().split(/\s+/).pop() || ''; @@ -4329,6 +4535,7 @@ function resolveBunCliPath() { const result = spawnSync('where', ['bun'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, }); if (result.status === 0) { const lines = (result.stdout || '') @@ -4351,6 +4558,7 @@ function resolveBunCliPath() { const result = spawnSync(shell, ['-lic', 'command -v bun'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, }); if (result.status === 0) { const found = (result.stdout || '').trim().split(/\s+/).pop() || ''; @@ -5677,7 +5885,7 @@ function killProcessOnPort(port) { if (!port) return; try { // Kill any process listening on our port to clean up orphaned children. - const result = spawnSync('lsof', ['-ti', `:${port}`], { encoding: 'utf8', timeout: 5000 }); + const result = spawnSync('lsof', ['-ti', `:${port}`], { encoding: 'utf8', timeout: 5000, windowsHide: true }); const output = result.stdout || ''; const myPid = process.pid; for (const pidStr of output.split(/\s+/)) { @@ -5761,6 +5969,7 @@ async function createManagedOpenCodeServerProcess({ const child = spawn(binary, args, { cwd, env, + windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'], }); @@ -12656,18 +12865,18 @@ async function main(options = {}) { // macOS: open -R selects the file in Finder; open opens a folder const stat = await fsPromises.stat(resolved); if (stat.isDirectory()) { - spawn('open', [resolved], { stdio: 'ignore', detached: true }).unref(); + spawn('open', [resolved], { windowsHide: true, stdio: 'ignore', detached: true }).unref(); } else { - spawn('open', ['-R', resolved], { stdio: 'ignore', detached: true }).unref(); + spawn('open', ['-R', resolved], { windowsHide: true, stdio: 'ignore', detached: true }).unref(); } } else if (platform === 'win32') { // Windows: explorer /select, highlights the file - spawn('explorer', ['/select,', resolved], { stdio: 'ignore', detached: true }).unref(); + spawn('explorer', ['/select,', resolved], { windowsHide: true, stdio: 'ignore', detached: true }).unref(); } else { // Linux: xdg-open opens the parent directory const stat = await fsPromises.stat(resolved); const dir = stat.isDirectory() ? resolved : path.dirname(resolved); - spawn('xdg-open', [dir], { stdio: 'ignore', detached: true }).unref(); + spawn('xdg-open', [dir], { windowsHide: true, stdio: 'ignore', detached: true }).unref(); } res.json({ success: true, path: resolved }); @@ -12718,6 +12927,7 @@ async function main(options = {}) { const child = spawn(shell, [shellFlag, command], { cwd: resolvedCwd, env: execEnv, + windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'], }); @@ -12988,7 +13198,7 @@ async function main(options = {}) { // Use git check-ignore with paths as arguments // Pass paths directly as arguments (works for reasonable directory sizes) const result = await new Promise((resolve) => { - const child = spawn('git', ['check-ignore', '--', ...pathsToCheck], { + const child = spawn(resolveGitBinaryForSpawn(), ['check-ignore', '--', ...pathsToCheck], { cwd: resolvedPath, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'], diff --git a/packages/web/server/lib/cloudflare-tunnel.js b/packages/web/server/lib/cloudflare-tunnel.js index 74d1c9a1..3d9ba5c6 100644 --- a/packages/web/server/lib/cloudflare-tunnel.js +++ b/packages/web/server/lib/cloudflare-tunnel.js @@ -56,7 +56,11 @@ export async function checkCloudflaredAvailable() { const cfPath = await searchPathFor('cloudflared'); if (cfPath) { try { - const result = spawnSync(cfPath, ['--version'], { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }); + const result = spawnSync(cfPath, ['--version'], { + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'], + windowsHide: true, + }); if (result.status === 0) { return { available: true, path: cfPath, version: result.stdout.trim() }; } @@ -96,6 +100,7 @@ Or visit: https://developers.cloudflare.com/cloudflare-one/networks/connectors/c const spawnCloudflared = (args, envOverrides = {}, resolvedBinaryPath = 'cloudflared') => spawn(resolvedBinaryPath, args, { stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, env: { ...process.env, CF_TELEMETRY_DISABLE: '1', diff --git a/packages/web/server/lib/git/service.js b/packages/web/server/lib/git/service.js index 073c5f5f..b9eb0750 100644 --- a/packages/web/server/lib/git/service.js +++ b/packages/web/server/lib/git/service.js @@ -8,6 +8,116 @@ import { promisify } from 'util'; const fsp = fs.promises; const execFileAsync = promisify(execFile); const gpgconfCandidates = ['gpgconf', '/opt/homebrew/bin/gpgconf', '/usr/local/bin/gpgconf']; +let resolvedGitBinary = null; + +const isExecutableFile = (candidate) => { + if (typeof candidate !== 'string' || candidate.trim().length === 0) { + return false; + } + try { + const stat = fs.statSync(candidate); + if (!stat.isFile()) { + return false; + } + if (process.platform === 'win32') { + const ext = path.extname(candidate).toLowerCase(); + return ext.length === 0 || ext === '.exe' || ext === '.cmd' || ext === '.bat' || ext === '.com'; + } + fs.accessSync(candidate, fs.constants.X_OK); + return true; + } catch { + return false; + } +}; + +const normalizeGitExecutableCandidate = (candidate) => { + if (typeof candidate !== 'string') { + return null; + } + const trimmed = candidate.trim(); + if (!trimmed) { + return null; + } + + const ext = path.extname(trimmed).toLowerCase(); + if (ext === '.cmd' || ext === '.bat' || ext === '.com') { + const exeCandidate = trimmed.slice(0, -ext.length) + '.exe'; + if (isExecutableFile(exeCandidate)) { + return exeCandidate; + } + } + + return trimmed; +}; + +const listPathExecutableCandidates = (binaryName) => { + const currentPath = process.env.PATH || ''; + const seen = new Set(); + const matches = []; + for (const segment of currentPath.split(path.delimiter)) { + const dir = typeof segment === 'string' ? segment.trim() : ''; + if (!dir || seen.has(dir)) { + continue; + } + seen.add(dir); + matches.push(path.join(dir, binaryName)); + } + return matches; +}; + +const listWindowsGitInstallCandidates = () => { + const roots = [ + process.env.ProgramFiles, + process.env['ProgramFiles(x86)'], + process.env.LocalAppData, + ] + .map((value) => (typeof value === 'string' ? value.trim() : '')) + .filter(Boolean); + + const candidates = []; + for (const root of roots) { + candidates.push(path.join(root, 'Git', 'cmd', 'git.exe')); + candidates.push(path.join(root, 'Git', 'bin', 'git.exe')); + candidates.push(path.join(root, 'Git', 'mingw64', 'bin', 'git.exe')); + candidates.push(path.join(root, 'Programs', 'Git', 'cmd', 'git.exe')); + candidates.push(path.join(root, 'Programs', 'Git', 'bin', 'git.exe')); + } + return candidates; +}; + +const resolveGitBinary = () => { + if (process.platform !== 'win32') { + return 'git'; + } + if (resolvedGitBinary) { + return resolvedGitBinary; + } + + const explicit = [process.env.GIT_BINARY, process.env.OPENCHAMBER_GIT_BINARY] + .map((value) => (typeof value === 'string' ? value.trim() : '')) + .filter(Boolean); + for (const candidate of explicit) { + if (isExecutableFile(candidate)) { + resolvedGitBinary = candidate; + return resolvedGitBinary; + } + } + + const discovered = [ + ...listPathExecutableCandidates('git.exe'), + ...listPathExecutableCandidates('git'), + ...listWindowsGitInstallCandidates(), + ] + .map(normalizeGitExecutableCandidate) + .filter(Boolean) + .filter((candidate) => isExecutableFile(candidate)); + + const preferredExe = discovered.find((candidate) => candidate.toLowerCase().endsWith('.exe')); + resolvedGitBinary = preferredExe || discovered[0] || 'git.exe'; + return resolvedGitBinary; +}; + +const getGitBinary = () => resolveGitBinary(); /** * Escape an SSH key path for use in core.sshCommand. @@ -126,10 +236,11 @@ const buildGitEnv = async () => { const createGit = async (directory) => { const env = await buildGitEnv(); const spawnOptions = { windowsHide: true }; + const binary = getGitBinary(); if (!directory) { - return simpleGit({ env, spawnOptions }); + return simpleGit({ env, spawnOptions, binary }); } - return simpleGit({ baseDir: normalizeDirectoryPath(directory), env, spawnOptions }); + return simpleGit({ baseDir: normalizeDirectoryPath(directory), env, spawnOptions, binary }); }; const normalizeDirectoryPath = (value) => { @@ -413,7 +524,7 @@ const parseGitErrorText = (error) => { const runGitCommand = async (cwd, args) => { try { - const { stdout, stderr } = await execFileAsync('git', args, { + const { stdout, stderr } = await execFileAsync(getGitBinary(), args, { cwd, env: await buildGitEnv(), windowsHide: true, @@ -623,6 +734,7 @@ const runWorktreeStartCommand = async (directory, command) => { const result = await execFileAsync('cmd', ['/c', text], { cwd: directory, env: await buildGitEnv(), + windowsHide: true, maxBuffer: 20 * 1024 * 1024, }).then(({ stdout, stderr }) => ({ success: true, stdout, stderr })).catch((error) => ({ success: false, @@ -1451,9 +1563,10 @@ export async function getFileDiff(directory, { path: filePath, staged = false } if (isImage) { // For images, use git show with raw output and convert to base64 try { - const { stdout } = await execFileAsync('git', ['show', `HEAD:${filePath}`], { + const { stdout } = await execFileAsync(getGitBinary(), ['show', `HEAD:${filePath}`], { cwd: directoryPath, encoding: 'buffer', + windowsHide: true, maxBuffer: 50 * 1024 * 1024, // 50MB max }); if (stdout && stdout.length > 0) { diff --git a/packages/web/server/lib/package-manager.js b/packages/web/server/lib/package-manager.js index cc4b21c3..070f61b0 100644 --- a/packages/web/server/lib/package-manager.js +++ b/packages/web/server/lib/package-manager.js @@ -11,6 +11,11 @@ const __dirname = path.dirname(__filename); const PACKAGE_NAME = '@openchamber/web'; const NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}`; const CHANGELOG_URL = 'https://raw.githubusercontent.com/btriapitsyn/openchamber/main/CHANGELOG.md'; +let cachedDetectedPm = null; + +function getSpawnSyncBaseOptions() { + return process.platform === 'win32' ? { windowsHide: true } : {}; +} const UPDATE_CHECK_URL = process.env.OPENCHAMBER_UPDATE_API_URL || 'https://api.openchamber.dev/v1/update/check'; function getOpenChamberConfigDir() { @@ -131,18 +136,24 @@ async function checkForUpdatesFromApi(currentVersion, options = {}) { * 4. Fall back to npm */ export function detectPackageManager() { + if (cachedDetectedPm) { + return cachedDetectedPm; + } + const forcedPm = process.env.OPENCHAMBER_PACKAGE_MANAGER?.trim(); if (forcedPm && ['npm', 'pnpm', 'yarn', 'bun'].includes(forcedPm)) { const forcedPmCommand = resolvePackageManagerCommand(forcedPm); if (isCommandAvailable(forcedPmCommand)) { - return forcedPm; + cachedDetectedPm = forcedPm; + return cachedDetectedPm; } } // Strategy 1: Detect from runtime executable path (reliable for server-side updates) const runtimePm = detectPackageManagerFromRuntimePath(process.execPath); if (runtimePm && isCommandAvailable(resolvePackageManagerCommand(runtimePm))) { - return runtimePm; + cachedDetectedPm = runtimePm; + return cachedDetectedPm; } // Strategy 2: Check user agent (most reliable during install) @@ -165,7 +176,8 @@ export function detectPackageManager() { // Strategy 4: Detect from invoked binary path (works for bun global symlink installs) const invokedPm = detectPackageManagerFromInvocationPath(process.argv?.[1]); if (invokedPm && isCommandAvailable(resolvePackageManagerCommand(invokedPm))) { - return invokedPm; + cachedDetectedPm = invokedPm; + return cachedDetectedPm; } if (!hintedPm) { hintedPm = invokedPm; @@ -176,7 +188,8 @@ export function detectPackageManager() { const pkgPath = path.resolve(__dirname, '..', '..'); const pmFromPath = detectPackageManagerFromInstallPath(pkgPath); if (pmFromPath && isCommandAvailable(resolvePackageManagerCommand(pmFromPath))) { - return pmFromPath; + cachedDetectedPm = pmFromPath; + return cachedDetectedPm; } if (!hintedPm) { hintedPm = pmFromPath; @@ -188,7 +201,8 @@ export function detectPackageManager() { // Validate the hinted PM actually owns the global install. // This avoids false positives (for example running via bunx while installed with npm). if (hintedPm && isCommandAvailable(resolvePackageManagerCommand(hintedPm)) && isPackageInstalledWith(hintedPm)) { - return hintedPm; + cachedDetectedPm = hintedPm; + return cachedDetectedPm; } // Strategy 6: Check which PM binaries are available and preferred @@ -203,12 +217,14 @@ export function detectPackageManager() { if (check()) { // Verify this PM actually has the package installed globally if (isPackageInstalledWith(name)) { - return name; + cachedDetectedPm = name; + return cachedDetectedPm; } } } - return 'npm'; + cachedDetectedPm = 'npm'; + return cachedDetectedPm; } function detectPackageManagerFromInstallPath(pkgPath) { @@ -285,6 +301,7 @@ function isCommandAvailable(command) { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 5000, + ...getSpawnSyncBaseOptions(), }); return result.status === 0; } catch { @@ -314,6 +331,7 @@ function isPackageInstalledWith(pm) { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 10000, + ...getSpawnSyncBaseOptions(), }); if (result.status !== 0) return false; @@ -444,7 +462,6 @@ export async function checkForUpdates(options = {}) { const currentNum = parseVersion(currentVersion); const latestNum = parseVersion(latestVersion); const available = latestNum > currentNum; - let changelog; if (available) { changelog = await fetchChangelogNotes(currentVersion, latestVersion); @@ -474,6 +491,7 @@ export function executeUpdate(pm = detectPackageManager(), options = {}) { const result = spawnSync(command, { stdio: 'inherit', shell: true, + ...getSpawnSyncBaseOptions(), }); return { diff --git a/packages/web/server/lib/skills-catalog/git.js b/packages/web/server/lib/skills-catalog/git.js index 10bb076b..5be7ddb3 100644 --- a/packages/web/server/lib/skills-catalog/git.js +++ b/packages/web/server/lib/skills-catalog/git.js @@ -45,6 +45,7 @@ export async function runGit(args, options = {}) { const { stdout, stderr } = await execFileAsync('git', normalizedArgs, { cwd, env, + windowsHide: true, timeout: timeoutMs, maxBuffer, }); diff --git a/scripts/port-opencode-theme.ts b/scripts/port-opencode-theme.ts new file mode 100644 index 00000000..78b6ccc1 --- /dev/null +++ b/scripts/port-opencode-theme.ts @@ -0,0 +1,1360 @@ +#!/usr/bin/env tsx + +/* + * Port OpenCode themes into full OpenChamber theme JSON files. + * + * Usage: + * bun run themes:port:opencode --list + * bun run themes:port:opencode github cursor lucent-orng --force + * bun run themes:port:opencode aura --out-dir /tmp/openchamber-theme-port-test --force + * bun run themes:port:opencode path/to/theme.json --stdout + * + * Expected result: + * - resolves theme colors from OpenCode desktop themes, TUI context themes, + * or existing OpenChamber theme JSON files + * - writes complete OpenChamber light/dark theme JSON output with solid core + * surfaces, interactive colors, syntax colors, and full schema coverage + * - produces files ready to register in presets without half-mapped tokens + */ + +import fs from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; + +type ColorValue = string; + +interface ThemePaletteColors { + neutral: string; + ink?: string; + primary: string; + success: string; + warning: string; + error: string; + info: string; + accent?: string; + interactive?: string; + diffAdd?: string; + diffDelete?: string; +} + +interface ThemeSeedColors { + neutral: string; + primary: string; + success: string; + warning: string; + error: string; + info: string; + interactive: string; + diffAdd: string; + diffDelete: string; +} + +type ThemeVariant = + | { palette: ThemePaletteColors; seeds?: never; overrides?: Record } + | { seeds: ThemeSeedColors; palette?: never; overrides?: Record }; + +interface DesktopTheme { + name: string; + id: string; + light: ThemeVariant; + dark: ThemeVariant; +} + +interface OpenChamberTheme { + metadata: { + id: string; + name: string; + description: string; + author?: string; + version: string; + variant: 'light' | 'dark'; + tags: string[]; + }; + colors: Record; + config: Record; +} + +type ContextThemeMode = 'light' | 'dark'; + +type ContextThemeColorRef = string | { dark: string; light: string }; + +interface ContextThemeJson { + $schema?: string; + defs?: Record; + theme: Record; +} + +type ResolvedContextTheme = Record & { + thinkingOpacity?: number; +}; + +type ThemeSource = DesktopTheme | ContextThemeJson | OpenChamberTheme; + +type ResolvedTheme = Record; + +type ParsedArgs = { + opencodeRoot: string; + outDir: string; + force: boolean; + stdout: boolean; + list: boolean; + specs: string[]; +}; + +const REPO_ROOT = path.resolve(import.meta.dirname, '..'); +const DEFAULT_OPENCODE_ROOT = path.join(os.homedir(), 'projects', 'opencode'); +const DEFAULT_DESKTOP_SOURCE_DIR = path.join(DEFAULT_OPENCODE_ROOT, 'packages', 'ui', 'src', 'theme', 'themes'); +const DEFAULT_CONTEXT_SOURCE_DIR = path.join( + DEFAULT_OPENCODE_ROOT, + 'packages', + 'opencode', + 'src', + 'cli', + 'cmd', + 'tui', + 'context', + 'theme', +); +const DEFAULT_OUT_DIR = path.join(REPO_ROOT, 'packages', 'ui', 'src', 'lib', 'theme', 'themes'); + +const DEFAULT_CONFIG = { + fonts: { + sans: '"IBM Plex Mono", monospace', + mono: '"IBM Plex Mono", monospace', + heading: '"IBM Plex Mono", monospace', + }, + radius: { + none: '0', + sm: '0.125rem', + md: '0.375rem', + lg: '0.5rem', + xl: '0.75rem', + full: '9999px', + }, + spacing: { + xs: '0.25rem', + sm: '0.5rem', + md: '0.75rem', + lg: '1rem', + xl: '1.5rem', + }, + transitions: { + fast: '150ms ease', + normal: '250ms ease', + slow: '350ms ease', + }, +}; + +const usage = () => { + console.error( + [ + 'Usage: tsx scripts/port-opencode-theme.ts [options] [...more]', + '', + 'Options:', + ' --opencode-root OpenCode repo root (default: ~/projects/opencode)', + ' --out-dir Output directory (default: packages/ui/src/lib/theme/themes)', + ' --stdout Print generated JSON instead of writing files', + ' --force Overwrite existing files', + ' --list List available OpenCode themes', + ].join('\n'), + ); +}; + +function parseArgs(argv: string[]): ParsedArgs { + const args: ParsedArgs = { + opencodeRoot: DEFAULT_OPENCODE_ROOT, + outDir: DEFAULT_OUT_DIR, + force: false, + stdout: false, + list: false, + specs: [], + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (!arg) continue; + + if (arg === '--opencode-root') { + const value = argv[index + 1]; + if (!value) throw new Error('Missing value for --opencode-root'); + args.opencodeRoot = expandHome(value); + index += 1; + continue; + } + + if (arg === '--out-dir') { + const value = argv[index + 1]; + if (!value) throw new Error('Missing value for --out-dir'); + args.outDir = path.resolve(expandHome(value)); + index += 1; + continue; + } + + if (arg === '--force') { + args.force = true; + continue; + } + + if (arg === '--stdout') { + args.stdout = true; + continue; + } + + if (arg === '--list') { + args.list = true; + continue; + } + + if (arg.startsWith('--')) { + throw new Error(`Unknown option: ${arg}`); + } + + args.specs.push(arg); + } + + return args; +} + +function expandHome(value: string): string { + if (value === '~') return os.homedir(); + if (value.startsWith('~/')) return path.join(os.homedir(), value.slice(2)); + return value; +} + +async function exists(filePath: string): Promise { + try { + await fs.access(filePath); + return true; + } catch { + return false; + } +} + +async function listThemes(opencodeRoot: string): Promise { + const sourceDirs = [ + path.join(opencodeRoot, 'packages', 'ui', 'src', 'theme', 'themes'), + path.join(opencodeRoot, 'packages', 'opencode', 'src', 'cli', 'cmd', 'tui', 'context', 'theme'), + ]; + + const names = new Set(); + for (const sourceDir of sourceDirs) { + if (!(await exists(sourceDir))) continue; + const entries = await fs.readdir(sourceDir); + for (const entry of entries) { + if (!entry.endsWith('.json')) continue; + names.add(entry.replace(/\.json$/u, '')); + } + } + + for (const entry of Array.from(names).sort((left, right) => left.localeCompare(right))) { + console.log(entry); + } +} + +async function resolveThemeSpec(spec: string, opencodeRoot: string): Promise { + const expanded = expandHome(spec); + const asAbsolute = path.isAbsolute(expanded) ? expanded : path.resolve(expanded); + if (await exists(asAbsolute)) { + return asAbsolute; + } + + const sourceDirs = [ + path.join(opencodeRoot, 'packages', 'ui', 'src', 'theme', 'themes'), + path.join(opencodeRoot, 'packages', 'opencode', 'src', 'cli', 'cmd', 'tui', 'context', 'theme'), + ]; + + for (const sourceDir of sourceDirs) { + const themedPath = path.join(sourceDir, spec.endsWith('.json') ? spec : `${spec}.json`); + if (await exists(themedPath)) { + return themedPath; + } + } + + throw new Error(`Theme not found: ${spec}`); +} + +async function loadThemeSource(themePath: string): Promise { + const raw = await fs.readFile(themePath, 'utf8'); + return JSON.parse(raw) as ThemeSource; +} + +function isDesktopTheme(value: ThemeSource): value is DesktopTheme { + return Boolean(value && typeof value === 'object' && 'light' in value && 'dark' in value && 'id' in value && 'name' in value); +} + +function isContextTheme(value: ThemeSource): value is ContextThemeJson { + return Boolean(value && typeof value === 'object' && 'theme' in value && !('light' in value) && !('metadata' in value)); +} + +function isOpenChamberTheme(value: ThemeSource): value is OpenChamberTheme { + return Boolean(value && typeof value === 'object' && 'metadata' in value && 'colors' in value); +} + +async function loadResolver(opencodeRoot: string): Promise<(variant: ThemeVariant, isDark: boolean) => ResolvedTheme> { + const resolvePath = path.join(opencodeRoot, 'packages', 'ui', 'src', 'theme', 'resolve.ts'); + if (!(await exists(resolvePath))) { + throw new Error(`OpenCode resolver not found: ${resolvePath}`); + } + + const mod = await import(pathToFileURL(resolvePath).href); + if (typeof mod.resolveThemeVariant !== 'function') { + throw new Error(`resolveThemeVariant export missing in ${resolvePath}`); + } + + return mod.resolveThemeVariant as (variant: ThemeVariant, isDark: boolean) => ResolvedTheme; +} + +function sourceVariantColor(variant: ThemeVariant, key: keyof ThemePaletteColors | keyof ThemeSeedColors): string | undefined { + if (variant.palette) { + return variant.palette[key as keyof ThemePaletteColors]; + } + if (variant.seeds) { + return variant.seeds[key as keyof ThemeSeedColors]; + } + return undefined; +} + +function sourceThemeName(themePath: string): string { + const base = path.basename(themePath, '.json'); + const knownNames: Record = { + github: 'GitHub', + rosepine: 'Rose Pine', + amoled: 'AMOLED', + 'oc-2': 'OC-2', + }; + if (knownNames[base]) { + return knownNames[base]; + } + return base + .split(/[-_]+/u) + .map((part) => (part ? part[0].toUpperCase() + part.slice(1) : part)) + .join(' '); +} + +function sourceThemeId(themePath: string): string { + return path.basename(themePath, '.json'); +} + +function resolveContextValue( + theme: ContextThemeJson, + value: ContextThemeColorRef | number, + mode: ContextThemeMode, + seen: Set = new Set(), +): string { + if (typeof value === 'number') { + return '#000000'; + } + + if (typeof value === 'object') { + return resolveContextValue(theme, value[mode], mode, seen); + } + + const normalized = value.trim(); + if (normalized === 'transparent' || normalized === 'none') { + return '#00000000'; + } + if (normalized.startsWith('#') || normalized.startsWith('rgb')) { + return normalized; + } + + if (seen.has(normalized)) { + throw new Error(`Circular theme reference: ${normalized}`); + } + + const defs = theme.defs ?? {}; + if (defs[normalized] !== undefined) { + seen.add(normalized); + return resolveContextValue(theme, defs[normalized], mode, seen); + } + + const themeValue = theme.theme[normalized]; + if (themeValue !== undefined) { + seen.add(normalized); + return resolveContextValue(theme, themeValue, mode, seen); + } + + throw new Error(`Unknown context theme reference: ${normalized}`); +} + +function resolveContextTheme(theme: ContextThemeJson, mode: ContextThemeMode): ResolvedContextTheme { + const resolved: ResolvedContextTheme = {}; + + for (const [key, value] of Object.entries(theme.theme)) { + if (key === 'thinkingOpacity') { + if (typeof value === 'number') { + resolved.thinkingOpacity = value; + } + continue; + } + + resolved[key] = resolveContextValue(theme, value, mode); + } + + return resolved; +} + +function syntheticVariantFromResolvedTheme(source: { + primary: string; + success: string; + warning: string; + error: string; + info: string; + accent: string; + interactive: string; + diffAdd: string; + diffDelete: string; + neutral: string; + ink?: string; +}): ThemeVariant { + return { + palette: { + neutral: source.neutral, + ink: source.ink, + primary: source.primary, + success: source.success, + warning: source.warning, + error: source.error, + info: source.info, + accent: source.accent, + interactive: source.interactive, + diffAdd: source.diffAdd, + diffDelete: source.diffDelete, + }, + }; +} + +function syntheticTokensFromContextTheme(resolved: ResolvedContextTheme, mode: ContextThemeMode): ResolvedTheme { + const isDark = mode === 'dark'; + const primary = resolved.primary ?? resolved.accent ?? resolved.info ?? resolved.borderActive ?? '#5A96BC'; + const warning = resolved.warning ?? '#DA702C'; + const error = resolved.error ?? '#AF3029'; + const success = resolved.success ?? '#66800B'; + const info = resolved.info ?? resolved.secondary ?? primary; + const borderActive = resolved.borderActive ?? primary; + const selection = withAlpha(primary, isDark ? 0.24 : 0.14); + const baseBackground = firstVisibleColor( + resolved.background, + resolved.backgroundPanel, + resolved.backgroundElement, + resolved.backgroundMenu, + isDark ? '#151313' : '#FFFCF0', + )!; + const panelBackground = firstVisibleColor( + resolved.backgroundPanel, + resolved.backgroundMenu, + resolved.backgroundElement, + resolved.background, + baseBackground, + )!; + const elementBackground = firstVisibleColor( + resolved.backgroundElement, + resolved.backgroundMenu, + resolved.backgroundPanel, + resolved.background, + panelBackground, + )!; + const menuBackground = firstVisibleColor( + resolved.backgroundMenu, + resolved.backgroundElement, + resolved.backgroundPanel, + resolved.background, + elementBackground, + )!; + const hover = firstVisibleColor( + resolved.backgroundElement, + resolved.backgroundPanel, + resolved.backgroundMenu, + resolved.background, + elementBackground, + )!; + const subtleBorder = resolved.borderSubtle ?? resolved.border ?? withAlpha(resolved.textMuted ?? resolved.text ?? '#000000', 0.2); + const diffAddedBackground = firstVisibleColor(resolved.diffAddedBg, withAlpha(success, isDark ? 0.16 : 0.12))!; + const diffRemovedBackground = firstVisibleColor(resolved.diffRemovedBg, withAlpha(error, isDark ? 0.16 : 0.12))!; + const diffContextBackground = firstVisibleColor(resolved.diffContextBg, withAlpha(info, isDark ? 0.1 : 0.08))!; + + return { + 'background-base': baseBackground, + 'background-weak': panelBackground, + 'surface-weak': panelBackground, + 'surface-raised-base': menuBackground, + 'surface-raised-base-hover': menuBackground, + 'surface-raised-base-active': menuBackground, + 'surface-base': elementBackground, + 'surface-base-hover': hover, + 'surface-base-active': hover, + 'surface-strong': menuBackground, + 'surface-brand-hover': primary, + 'surface-interactive-weak': selection, + 'surface-inset-base': panelBackground, + 'surface-success-weak': diffAddedBackground, + 'surface-warning-weak': withAlpha(warning, isDark ? 0.16 : 0.12), + 'surface-critical-weak': diffRemovedBackground, + 'surface-critical-base': firstVisibleColor(resolved.diffRemovedBg, withAlpha(error, isDark ? 0.22 : 0.16))!, + 'surface-info-weak': withAlpha(info, isDark ? 0.16 : 0.12), + 'surface-diff-add-weak': diffAddedBackground, + 'surface-diff-delete-weak': diffRemovedBackground, + 'surface-diff-hidden-weak': diffContextBackground, + 'border-base': resolved.border ?? subtleBorder, + 'border-hover': subtleBorder, + 'border-focus': borderActive, + 'border-interactive-selected': borderActive, + 'border-weak-base': subtleBorder, + 'border-weak-hover': resolved.border ?? subtleBorder, + 'border-weaker-base': subtleBorder, + 'border-success-base': resolved.diffAdded ?? success, + 'border-warning-base': warning, + 'border-critical-base': resolved.diffRemoved ?? error, + 'border-critical-selected': error, + 'border-info-base': info, + 'text-base': resolved.text ?? '#CECDC3', + 'text-weak': resolved.textMuted ?? resolved.text ?? '#878580', + 'text-weaker': resolved.diffContext ?? resolved.textMuted ?? resolved.text ?? '#878580', + 'text-strong': resolved.text ?? '#CECDC3', + 'text-on-brand-base': accessibleForeground(primary), + 'text-on-success-base': accessibleForeground(success), + 'text-on-warning-base': accessibleForeground(warning), + 'text-on-critical-base': accessibleForeground(error), + 'text-on-info-base': accessibleForeground(info), + 'text-interactive-base': resolved.markdownLink ?? primary, + 'icon-success-base': success, + 'icon-warning-base': warning, + 'icon-critical-base': error, + 'icon-info-base': info, + 'icon-base': resolved.textMuted ?? resolved.text ?? '#878580', + 'icon-weak-base': resolved.textMuted ?? resolved.text ?? '#878580', + 'icon-diff-modified-base': resolved.diffHunkHeader ?? warning, + 'input-base': menuBackground, + 'input-selected': selection, + 'input-disabled': panelBackground, + 'button-ghost-hover': hover, + 'button-ghost-hover2': hover, + 'syntax-comment': resolved.syntaxComment ?? resolved.textMuted ?? '#878580', + 'syntax-keyword': resolved.syntaxKeyword ?? resolved.primary ?? primary, + 'syntax-string': resolved.syntaxString ?? resolved.success ?? success, + 'syntax-property': resolved.syntaxFunction ?? resolved.primary ?? primary, + 'syntax-variable': resolved.syntaxVariable ?? resolved.text ?? '#CECDC3', + 'syntax-type': resolved.syntaxType ?? resolved.warning ?? warning, + 'syntax-operator': resolved.syntaxOperator ?? resolved.text ?? '#CECDC3', + 'syntax-regexp': resolved.syntaxString ?? resolved.success ?? success, + 'syntax-punctuation': resolved.syntaxPunctuation ?? resolved.textMuted ?? '#878580', + 'syntax-constant': resolved.syntaxNumber ?? resolved.info ?? info, + 'syntax-diff-add': resolved.diffHighlightAdded ?? resolved.diffAdded ?? success, + 'syntax-diff-delete': resolved.diffHighlightRemoved ?? resolved.diffRemoved ?? error, + }; +} + +function syntheticTokensFromOpenChamberTheme(theme: OpenChamberTheme): ResolvedTheme { + const colors = theme.colors as Record; + const primary = colors.primary ?? {}; + const surface = colors.surface ?? {}; + const interactive = colors.interactive ?? {}; + const status = colors.status ?? {}; + const syntax = colors.syntax ?? { base: {}, tokens: {}, highlights: {} }; + + return { + 'background-base': surface.background ?? '#151313', + 'background-weak': surface.muted ?? surface.background ?? '#1C1B1A', + 'surface-weak': surface.muted ?? surface.background ?? '#1C1B1A', + 'surface-raised-base': surface.elevated ?? surface.muted ?? surface.background ?? '#1C1B1A', + 'surface-raised-base-hover': interactive.hover ?? surface.elevated ?? surface.muted ?? surface.background ?? '#1C1B1A', + 'surface-raised-base-active': interactive.active ?? interactive.hover ?? surface.elevated ?? surface.muted ?? surface.background ?? '#1C1B1A', + 'surface-base': surface.muted ?? surface.background ?? '#1C1B1A', + 'surface-base-hover': interactive.hover ?? surface.elevated ?? surface.muted ?? surface.background ?? '#1C1B1A', + 'surface-base-active': interactive.active ?? interactive.hover ?? surface.elevated ?? surface.muted ?? surface.background ?? '#1C1B1A', + 'surface-strong': surface.elevated ?? surface.muted ?? surface.background ?? '#1C1B1A', + 'surface-brand-hover': primary.hover ?? primary.base ?? '#5A96BC', + 'surface-interactive-weak': interactive.selection ?? withAlpha(primary.base ?? '#5A96BC', 0.16), + 'surface-inset-base': surface.elevated ?? surface.muted ?? surface.background ?? '#1C1B1A', + 'surface-success-weak': status.successBackground ?? withAlpha(status.success ?? '#66800B', 0.12), + 'surface-warning-weak': status.warningBackground ?? withAlpha(status.warning ?? '#DA702C', 0.12), + 'surface-critical-weak': status.errorBackground ?? withAlpha(status.error ?? '#AF3029', 0.12), + 'surface-critical-base': status.errorBackground ?? withAlpha(status.error ?? '#AF3029', 0.16), + 'surface-info-weak': status.infoBackground ?? withAlpha(status.info ?? '#205EA6', 0.12), + 'surface-diff-add-weak': syntax.highlights?.diffAddedBackground ?? status.successBackground ?? withAlpha(status.success ?? '#66800B', 0.12), + 'surface-diff-delete-weak': syntax.highlights?.diffRemovedBackground ?? status.errorBackground ?? withAlpha(status.error ?? '#AF3029', 0.12), + 'surface-diff-hidden-weak': syntax.highlights?.diffModifiedBackground ?? status.infoBackground ?? withAlpha(status.info ?? '#205EA6', 0.12), + 'border-base': interactive.border ?? '#343331', + 'border-hover': interactive.borderHover ?? interactive.border ?? '#343331', + 'border-focus': interactive.borderFocus ?? interactive.focus ?? primary.base ?? '#5A96BC', + 'border-interactive-selected': interactive.borderFocus ?? interactive.focus ?? primary.base ?? '#5A96BC', + 'border-weak-base': interactive.border ?? '#343331', + 'border-weak-hover': interactive.borderHover ?? interactive.border ?? '#343331', + 'border-weaker-base': interactive.border ?? '#343331', + 'border-success-base': status.successBorder ?? status.success ?? '#66800B', + 'border-warning-base': status.warningBorder ?? status.warning ?? '#DA702C', + 'border-critical-base': status.errorBorder ?? status.error ?? '#AF3029', + 'border-critical-selected': status.error ?? '#AF3029', + 'border-info-base': status.infoBorder ?? status.info ?? '#205EA6', + 'text-base': surface.foreground ?? '#CECDC3', + 'text-weak': surface.mutedForeground ?? surface.foreground ?? '#878580', + 'text-weaker': surface.mutedForeground ?? surface.foreground ?? '#878580', + 'text-strong': surface.foreground ?? '#CECDC3', + 'text-on-brand-base': primary.foreground ?? accessibleForeground(primary.base ?? '#5A96BC'), + 'text-on-success-base': status.successForeground ?? accessibleForeground(status.success ?? '#66800B'), + 'text-on-warning-base': status.warningForeground ?? accessibleForeground(status.warning ?? '#DA702C'), + 'text-on-critical-base': status.errorForeground ?? accessibleForeground(status.error ?? '#AF3029'), + 'text-on-info-base': status.infoForeground ?? accessibleForeground(status.info ?? '#205EA6'), + 'text-interactive-base': colors.markdown?.link ?? primary.base ?? '#5A96BC', + 'icon-success-base': status.success ?? '#66800B', + 'icon-warning-base': status.warning ?? '#DA702C', + 'icon-critical-base': status.error ?? '#AF3029', + 'icon-info-base': status.info ?? '#205EA6', + 'icon-base': surface.mutedForeground ?? surface.foreground ?? '#878580', + 'icon-weak-base': surface.mutedForeground ?? surface.foreground ?? '#878580', + 'icon-diff-modified-base': syntax.highlights?.diffModified ?? status.warning ?? '#DA702C', + 'input-base': surface.elevated ?? surface.muted ?? surface.background ?? '#1C1B1A', + 'input-selected': interactive.selection ?? withAlpha(primary.base ?? '#5A96BC', 0.16), + 'input-disabled': surface.muted ?? surface.background ?? '#1C1B1A', + 'button-ghost-hover': interactive.hover ?? surface.muted ?? surface.background ?? '#1C1B1A', + 'button-ghost-hover2': interactive.active ?? interactive.hover ?? surface.muted ?? surface.background ?? '#1C1B1A', + 'syntax-comment': syntax.base?.comment ?? surface.mutedForeground ?? '#878580', + 'syntax-keyword': syntax.base?.keyword ?? primary.base ?? '#5A96BC', + 'syntax-string': syntax.base?.string ?? status.success ?? '#66800B', + 'syntax-property': syntax.tokens?.functionCall ?? syntax.base?.function ?? primary.base ?? '#5A96BC', + 'syntax-variable': syntax.base?.variable ?? surface.foreground ?? '#CECDC3', + 'syntax-type': syntax.base?.type ?? status.warning ?? '#DA702C', + 'syntax-operator': syntax.base?.operator ?? surface.foreground ?? '#CECDC3', + 'syntax-regexp': syntax.tokens?.regex ?? syntax.base?.string ?? status.success ?? '#66800B', + 'syntax-punctuation': syntax.tokens?.punctuation ?? surface.mutedForeground ?? '#878580', + 'syntax-constant': syntax.base?.number ?? status.info ?? '#205EA6', + 'syntax-diff-add': syntax.highlights?.diffAdded ?? status.success ?? '#66800B', + 'syntax-diff-delete': syntax.highlights?.diffRemoved ?? status.error ?? '#AF3029', + }; +} + +function formatOpacity(opacity: number): string { + return opacity.toFixed(3).replace(/0+$/u, '').replace(/\.$/u, ''); +} + +function withAlpha(color: string, opacity: number): string { + const value = color.trim(); + const alpha = Math.max(0, Math.min(1, opacity)); + const hex = value.replace(/^#/u, ''); + + if (/^[0-9a-f]{3}$/iu.test(hex)) { + const expanded = hex + .split('') + .map((part) => `${part}${part}`) + .join(''); + const alphaHex = Math.round(alpha * 255).toString(16).padStart(2, '0'); + return `#${expanded}${alphaHex}`; + } + + if (/^[0-9a-f]{6}$/iu.test(hex)) { + const alphaHex = Math.round(alpha * 255).toString(16).padStart(2, '0'); + return `#${hex}${alphaHex}`; + } + + const rgb = value.match( + /^rgba?\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})(?:\s*,\s*[0-9.]+)?\s*\)$/iu, + ); + if (rgb) { + return `rgba(${rgb[1]}, ${rgb[2]}, ${rgb[3]}, ${formatOpacity(alpha)})`; + } + + return color; +} + +function isTransparentColor(color: string | undefined | null): boolean { + if (!color) return true; + + const value = color.trim().toLowerCase(); + if (!value || value === 'transparent' || value === 'none') return true; + + const hex = value.replace(/^#/u, ''); + if (/^[0-9a-f]{4}$/iu.test(hex)) { + return hex[3] === '0'; + } + if (/^[0-9a-f]{8}$/iu.test(hex)) { + return hex.slice(6, 8) === '00'; + } + + const rgb = value.match(/^rgba\(\s*[0-9]{1,3}\s*,\s*[0-9]{1,3}\s*,\s*[0-9]{1,3}\s*,\s*([0-9.]+)\s*\)$/iu); + if (rgb) { + return Number(rgb[1]) === 0; + } + + return false; +} + +function firstVisibleColor(...colors: Array): string | undefined { + for (const color of colors) { + if (color && !isTransparentColor(color)) { + return color; + } + } + return undefined; +} + +function parseRgb(color: string): [number, number, number] | null { + const value = color.trim(); + const hex = value.replace(/^#/u, ''); + + if (/^[0-9a-f]{3}$/iu.test(hex)) { + return hex + .split('') + .map((part) => parseInt(`${part}${part}`, 16)) as [number, number, number]; + } + + if (/^[0-9a-f]{6}$/iu.test(hex) || /^[0-9a-f]{8}$/iu.test(hex)) { + const normalized = hex.slice(0, 6); + return [ + parseInt(normalized.slice(0, 2), 16), + parseInt(normalized.slice(2, 4), 16), + parseInt(normalized.slice(4, 6), 16), + ]; + } + + const rgb = value.match( + /^rgba?\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})(?:\s*,\s*[0-9.]+)?\s*\)$/iu, + ); + if (!rgb) return null; + + return [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])]; +} + +function relativeLuminance(color: string): number | null { + const rgb = parseRgb(color); + if (!rgb) return null; + + const [r, g, b] = rgb.map((channel) => { + const normalized = channel / 255; + if (normalized <= 0.03928) return normalized / 12.92; + return ((normalized + 0.055) / 1.055) ** 2.4; + }); + + return 0.2126 * r + 0.7152 * g + 0.0722 * b; +} + +function contrastRatio(foreground: string, background: string): number | null { + const fg = relativeLuminance(foreground); + const bg = relativeLuminance(background); + if (fg === null || bg === null) return null; + + const light = Math.max(fg, bg); + const dark = Math.min(fg, bg); + return (light + 0.05) / (dark + 0.05); +} + +function accessibleForeground(background: string, preferred?: string): string { + if (preferred) { + const ratio = contrastRatio(preferred, background); + if (ratio !== null && ratio >= 4.5) { + return preferred; + } + } + + const black = '#151313'; + const white = '#ffffff'; + const blackRatio = contrastRatio(black, background) ?? 0; + const whiteRatio = contrastRatio(white, background) ?? 0; + return blackRatio >= whiteRatio ? black : white; +} + +function interactionOverlay(foreground: string, opacity: number): string { + return withAlpha(foreground, opacity); +} + +function resolveTokenValue(value: string, tokens: ResolvedTheme, seen: Set = new Set()): string { + const match = value.trim().match(/^var\(--([a-z0-9-]+)\)$/iu); + if (!match) return value; + + const key = match[1]; + if (seen.has(key)) return value; + + const next = tokens[key]; + if (!next) return value; + + seen.add(key); + return resolveTokenValue(next, tokens, seen); +} + +function materializeTokens(tokens: ResolvedTheme): ResolvedTheme { + const out: ResolvedTheme = {}; + for (const [key, value] of Object.entries(tokens)) { + out[key] = resolveTokenValue(value, tokens); + } + return out; +} + +function token(tokens: ResolvedTheme, key: string, fallback: string): string { + return tokens[key] ?? fallback; +} + +function buildTheme( + desktopTheme: DesktopTheme, + variant: ThemeVariant, + resolved: ResolvedTheme, + mode: 'light' | 'dark', +): OpenChamberTheme { + const isDark = mode === 'dark'; + const background = token(resolved, 'background-base', isDark ? '#151313' : '#FFFCF0'); + const foreground = token(resolved, 'text-base', isDark ? '#CECDC3' : '#100F0F'); + const weakText = token(resolved, 'text-weak', token(resolved, 'text-weaker', foreground)); + const weakerText = token(resolved, 'text-weaker', weakText); + const strongText = token(resolved, 'text-strong', foreground); + const surfaceWeak = token(resolved, 'surface-weak', token(resolved, 'background-weak', background)); + const surfaceRaised = token(resolved, 'surface-raised-base', surfaceWeak); + const surfaceRaisedHover = token(resolved, 'surface-raised-base-hover', surfaceRaised); + const surfaceRaisedActive = token(resolved, 'surface-raised-base-active', surfaceRaisedHover); + const surfaceBase = token(resolved, 'surface-base', surfaceWeak); + const surfaceBaseHover = token(resolved, 'surface-base-hover', surfaceBase); + const surfaceBaseActive = token(resolved, 'surface-base-active', surfaceBaseHover); + const surfaceStrong = token(resolved, 'surface-strong', surfaceRaised); + const borderBase = token(resolved, 'border-base', withAlpha(foreground, isDark ? 0.2 : 0.16)); + const borderHover = token(resolved, 'border-hover', borderBase); + const borderFocus = token(resolved, 'border-interactive-selected', token(resolved, 'border-focus', borderHover)); + const interactiveSeed = sourceVariantColor(variant, 'interactive') ?? sourceVariantColor(variant, 'primary') ?? borderFocus; + const primaryBase = sourceVariantColor(variant, 'primary') ?? token(resolved, 'text-interactive-base', borderFocus); + const primaryHover = token(resolved, 'surface-brand-hover', primaryBase); + const primaryActive = token(resolved, 'border-interactive-selected', primaryHover); + const successBase = sourceVariantColor(variant, 'success') ?? token(resolved, 'icon-success-base', '#66800B'); + const warningBase = sourceVariantColor(variant, 'warning') ?? token(resolved, 'icon-warning-base', '#DA702C'); + const errorBase = sourceVariantColor(variant, 'error') ?? token(resolved, 'icon-critical-base', '#AF3029'); + const infoBase = sourceVariantColor(variant, 'info') ?? token(resolved, 'icon-info-base', '#205EA6'); + const accentBase = sourceVariantColor(variant, 'accent') ?? infoBase; + const diffAddBase = sourceVariantColor(variant, 'diffAdd') ?? token(resolved, 'syntax-diff-add', successBase); + const diffDeleteBase = sourceVariantColor(variant, 'diffDelete') ?? token(resolved, 'syntax-diff-delete', errorBase); + const primaryForeground = accessibleForeground(primaryBase, token(resolved, 'text-on-brand-base', isDark ? '#151313' : '#ffffff')); + const successForeground = accessibleForeground(successBase, token(resolved, 'text-on-success-base', '#ffffff')); + const warningForeground = accessibleForeground(warningBase, token(resolved, 'text-on-warning-base', '#ffffff')); + const errorForeground = accessibleForeground(errorBase, token(resolved, 'text-on-critical-base', '#ffffff')); + const infoForeground = accessibleForeground(infoBase, token(resolved, 'text-on-info-base', '#ffffff')); + const hoverOverlay = interactionOverlay(foreground, isDark ? 0.09 : 0.055); + const selectionOverlay = interactionOverlay(foreground, isDark ? 0.12 : 0.085); + const chartSeries = [primaryBase, infoBase, successBase, warningBase, errorBase]; + + return { + metadata: { + id: `${desktopTheme.id}-${mode}`, + name: desktopTheme.name, + description: `Ported from OpenCode ${desktopTheme.name} theme (${mode} variant)`, + author: 'OpenCode', + version: '1.0.0', + variant: mode, + tags: [mode, 'opencode', 'ported', desktopTheme.id], + }, + colors: { + primary: { + base: primaryBase, + hover: primaryHover, + active: primaryActive, + foreground: primaryForeground, + muted: withAlpha(primaryBase, 0.5), + emphasis: token(resolved, 'text-interactive-base', primaryHover), + }, + surface: { + background, + foreground, + muted: token(resolved, 'background-weak', surfaceWeak), + mutedForeground: weakText, + elevated: surfaceRaised, + elevatedForeground: foreground, + overlay: withAlpha(background, isDark ? 0.8 : 0.2), + subtle: surfaceWeak, + }, + interactive: { + border: borderBase, + borderHover: borderHover, + borderFocus: borderFocus, + selection: selectionOverlay, + selectionForeground: foreground, + focus: borderFocus, + focusRing: withAlpha(borderFocus, isDark ? 0.38 : 0.28), + cursor: strongText, + hover: hoverOverlay, + active: selectionOverlay, + }, + status: { + error: errorBase, + errorForeground: errorForeground, + errorBackground: token(resolved, 'surface-critical-weak', withAlpha(errorBase, isDark ? 0.16 : 0.12)), + errorBorder: token(resolved, 'border-critical-base', withAlpha(errorBase, isDark ? 0.45 : 0.35)), + warning: warningBase, + warningForeground: warningForeground, + warningBackground: token(resolved, 'surface-warning-weak', withAlpha(warningBase, isDark ? 0.16 : 0.12)), + warningBorder: token(resolved, 'border-warning-base', withAlpha(warningBase, isDark ? 0.45 : 0.35)), + success: successBase, + successForeground: successForeground, + successBackground: token(resolved, 'surface-success-weak', withAlpha(successBase, isDark ? 0.16 : 0.12)), + successBorder: token(resolved, 'border-success-base', withAlpha(successBase, isDark ? 0.45 : 0.35)), + info: infoBase, + infoForeground: infoForeground, + infoBackground: token(resolved, 'surface-info-weak', withAlpha(infoBase, isDark ? 0.16 : 0.12)), + infoBorder: token(resolved, 'border-info-base', withAlpha(infoBase, isDark ? 0.45 : 0.35)), + }, + pr: { + open: successBase, + draft: weakText, + blocked: warningBase, + merged: token(resolved, 'syntax-constant', accentBase), + closed: errorBase, + }, + syntax: { + base: { + background: surfaceRaised, + foreground, + comment: token(resolved, 'syntax-comment', weakText), + keyword: token(resolved, 'syntax-keyword', accentBase), + string: token(resolved, 'syntax-string', successBase), + number: token(resolved, 'syntax-constant', infoBase), + function: token(resolved, 'syntax-property', primaryBase), + variable: token(resolved, 'syntax-variable', foreground), + type: token(resolved, 'syntax-type', warningBase), + operator: token(resolved, 'syntax-operator', foreground), + }, + tokens: { + commentDoc: token(resolved, 'syntax-comment', weakText), + stringEscape: token(resolved, 'syntax-regexp', foreground), + keywordImport: token(resolved, 'syntax-keyword', accentBase), + storageModifier: token(resolved, 'syntax-keyword', accentBase), + functionCall: token(resolved, 'syntax-property', primaryBase), + method: token(resolved, 'syntax-property', primaryBase), + variableProperty: token(resolved, 'syntax-property', primaryBase), + variableOther: token(resolved, 'syntax-variable', foreground), + variableGlobal: token(resolved, 'syntax-constant', infoBase), + variableLocal: token(resolved, 'syntax-punctuation', weakText), + parameter: token(resolved, 'syntax-variable', foreground), + constant: token(resolved, 'syntax-constant', infoBase), + class: token(resolved, 'syntax-type', warningBase), + className: token(resolved, 'syntax-type', warningBase), + interface: token(resolved, 'syntax-type', warningBase), + struct: token(resolved, 'syntax-type', warningBase), + enum: token(resolved, 'syntax-type', warningBase), + typeParameter: token(resolved, 'syntax-type', warningBase), + namespace: token(resolved, 'syntax-type', warningBase), + module: token(resolved, 'syntax-keyword', accentBase), + tag: token(resolved, 'syntax-keyword', accentBase), + jsxTag: token(resolved, 'syntax-keyword', accentBase), + tagAttribute: token(resolved, 'syntax-property', primaryBase), + tagAttributeValue: token(resolved, 'syntax-string', successBase), + boolean: token(resolved, 'syntax-constant', infoBase), + decorator: token(resolved, 'syntax-keyword', accentBase), + label: token(resolved, 'syntax-property', primaryBase), + punctuation: token(resolved, 'syntax-punctuation', weakText), + macro: token(resolved, 'syntax-keyword', accentBase), + preprocessor: token(resolved, 'syntax-keyword', accentBase), + regex: token(resolved, 'syntax-regexp', foreground), + url: token(resolved, 'text-interactive-base', primaryBase), + key: token(resolved, 'syntax-property', primaryBase), + exception: errorBase, + }, + highlights: { + diffAdded: token(resolved, 'syntax-diff-add', diffAddBase), + diffAddedBackground: token(resolved, 'surface-diff-add-weak', withAlpha(diffAddBase, isDark ? 0.18 : 0.14)), + diffRemoved: token(resolved, 'syntax-diff-delete', diffDeleteBase), + diffRemovedBackground: token(resolved, 'surface-diff-delete-weak', withAlpha(diffDeleteBase, isDark ? 0.18 : 0.14)), + diffModified: token(resolved, 'icon-diff-modified-base', warningBase), + diffModifiedBackground: token(resolved, 'surface-diff-hidden-weak', withAlpha(infoBase, isDark ? 0.18 : 0.14)), + lineNumber: weakerText, + lineNumberActive: foreground, + }, + }, + header: { + background, + foreground, + border: borderBase, + icon: token(resolved, 'icon-base', weakText), + hover: surfaceBaseHover, + }, + sidebar: { + background: token(resolved, 'background-weak', surfaceWeak), + foreground: weakText, + border: borderBase, + icon: token(resolved, 'icon-weak-base', weakText), + hover: surfaceBaseHover, + active: token(resolved, 'surface-interactive-weak', surfaceBase), + accent: primaryBase, + accentForeground: primaryForeground, + }, + chat: { + background, + userMessage: foreground, + userMessageBackground: token(resolved, 'surface-inset-base', surfaceBase), + assistantMessage: foreground, + assistantMessageBackground: background, + timestamp: weakerText, + divider: token(resolved, 'border-weak-base', borderBase), + typing: weakText, + }, + markdown: { + heading1: token(resolved, 'markdown-heading', primaryBase), + heading2: token(resolved, 'markdown-heading', primaryBase), + heading3: strongText, + heading4: foreground, + link: token(resolved, 'markdown-link', primaryBase), + linkHover: token(resolved, 'markdown-link-text', primaryHover), + inlineCode: token(resolved, 'markdown-code', successBase), + inlineCodeBackground: surfaceBase, + blockquote: token(resolved, 'markdown-block-quote', weakText), + blockquoteBorder: borderBase, + listMarker: withAlpha(token(resolved, 'markdown-list-item', primaryBase), 0.6), + bold: token(resolved, 'markdown-strong', strongText), + italic: token(resolved, 'markdown-emph', weakText), + strikethrough: weakText, + hr: token(resolved, 'markdown-horizontal-rule', borderBase), + }, + tools: { + background: surfaceBase, + border: token(resolved, 'border-weak-base', borderBase), + headerHover: surfaceBaseHover, + icon: token(resolved, 'icon-weak-base', weakText), + title: foreground, + description: weakText, + edit: { + added: token(resolved, 'text-diff-add-base', diffAddBase), + addedBackground: token(resolved, 'surface-diff-add-weak', withAlpha(diffAddBase, isDark ? 0.16 : 0.12)), + removed: token(resolved, 'text-diff-delete-base', diffDeleteBase), + removedBackground: token(resolved, 'surface-diff-delete-weak', withAlpha(diffDeleteBase, isDark ? 0.16 : 0.12)), + modified: token(resolved, 'icon-diff-modified-base', warningBase), + modifiedBackground: token(resolved, 'surface-diff-hidden-weak', withAlpha(infoBase, isDark ? 0.16 : 0.12)), + lineNumber: weakerText, + }, + bash: { + background: token(resolved, 'surface-raised-base', surfaceRaised), + foreground: foreground, + info: infoBase, + warning: warningBase, + error: errorBase, + }, + lsp: { + background: token(resolved, 'surface-raised-base', surfaceRaised), + foreground: foreground, + info: infoBase, + warning: warningBase, + error: errorBase, + }, + }, + forms: { + inputBackground: token(resolved, 'input-base', surfaceRaised), + inputForeground: foreground, + inputBorder: token(resolved, 'border-weak-base', borderBase), + inputBorderHover: token(resolved, 'border-weak-hover', borderHover), + inputBorderFocus: borderFocus, + inputPlaceholder: weakerText, + inputDisabled: token(resolved, 'input-disabled', surfaceWeak), + inputSelection: token(resolved, 'input-selected', surfaceBase), + label: weakText, + helperText: weakerText, + }, + buttons: { + primary: { + bg: primaryBase, + fg: primaryForeground, + border: token(resolved, 'border-interactive-base', primaryBase), + hover: primaryHover, + active: primaryActive, + disabled: token(resolved, 'border-disabled', surfaceWeak), + }, + secondary: { + bg: surfaceRaised, + fg: foreground, + border: borderBase, + hover: surfaceRaisedHover, + active: surfaceRaisedActive, + disabled: token(resolved, 'input-disabled', surfaceWeak), + }, + ghost: { + bg: '#00000000', + fg: foreground, + border: '#00000000', + hover: token(resolved, 'button-ghost-hover', surfaceBaseHover), + active: token(resolved, 'button-ghost-hover2', surfaceBaseActive), + disabled: weakerText, + }, + destructive: { + bg: errorBase, + fg: errorForeground, + border: token(resolved, 'border-critical-base', errorBase), + hover: token(resolved, 'surface-critical-base', errorBase), + active: token(resolved, 'border-critical-selected', errorBase), + disabled: token(resolved, 'input-disabled', surfaceWeak), + }, + }, + modal: { + background: surfaceRaised, + foreground, + border: borderBase, + overlay: withAlpha(background, isDark ? 0.84 : 0.24), + }, + popover: { + background: surfaceRaised, + foreground, + border: borderBase, + shadow: isDark ? '0 18px 48px rgba(0, 0, 0, 0.45)' : '0 18px 48px rgba(15, 15, 15, 0.16)', + }, + commandPalette: { + background: surfaceRaised, + foreground, + border: borderBase, + inputBackground: token(resolved, 'input-base', surfaceBase), + selectedBackground: token(resolved, 'surface-interactive-weak', surfaceBase), + selectedForeground: foreground, + muted: weakText, + }, + fileAttachment: { + background: surfaceBase, + foreground, + border: token(resolved, 'border-weak-base', borderBase), + icon: token(resolved, 'icon-weak-base', weakText), + removeHover: token(resolved, 'surface-critical-weak', withAlpha(errorBase, 0.12)), + }, + sessions: { + background, + foreground, + mutedForeground: weakText, + border: token(resolved, 'border-weaker-base', borderBase), + hover: surfaceBaseHover, + active: token(resolved, 'surface-interactive-weak', surfaceBase), + }, + modelSelector: { + background: surfaceRaised, + foreground, + border: borderBase, + selectedBackground: token(resolved, 'surface-interactive-weak', surfaceBase), + selectedForeground: foreground, + }, + permissions: { + background: surfaceRaised, + foreground, + border: borderBase, + allow: successBase, + allowBackground: token(resolved, 'surface-success-weak', withAlpha(successBase, 0.12)), + deny: errorBase, + denyBackground: token(resolved, 'surface-critical-weak', withAlpha(errorBase, 0.12)), + }, + loading: { + spinner: primaryBase, + spinnerTrack: surfaceWeak, + skeleton: surfaceBase, + shimmer: surfaceBaseHover, + }, + scrollbar: { + track: 'transparent', + thumb: withAlpha(foreground, isDark ? 0.2 : 0.15), + thumbHover: withAlpha(foreground, isDark ? 0.34 : 0.25), + }, + badges: { + default: { + bg: surfaceBase, + fg: foreground, + border: token(resolved, 'border-weak-base', borderBase), + }, + info: { + bg: token(resolved, 'surface-info-weak', withAlpha(infoBase, 0.12)), + fg: infoBase, + border: token(resolved, 'border-info-base', withAlpha(infoBase, 0.35)), + }, + success: { + bg: token(resolved, 'surface-success-weak', withAlpha(successBase, 0.12)), + fg: successBase, + border: token(resolved, 'border-success-base', withAlpha(successBase, 0.35)), + }, + warning: { + bg: token(resolved, 'surface-warning-weak', withAlpha(warningBase, 0.12)), + fg: warningBase, + border: token(resolved, 'border-warning-base', withAlpha(warningBase, 0.35)), + }, + error: { + bg: token(resolved, 'surface-critical-weak', withAlpha(errorBase, 0.12)), + fg: errorBase, + border: token(resolved, 'border-critical-base', withAlpha(errorBase, 0.35)), + }, + }, + toast: { + background: surfaceRaised, + foreground, + border: borderBase, + success: { + background: token(resolved, 'surface-success-weak', withAlpha(successBase, 0.12)), + foreground: successBase, + border: token(resolved, 'border-success-base', withAlpha(successBase, 0.35)), + }, + warning: { + background: token(resolved, 'surface-warning-weak', withAlpha(warningBase, 0.12)), + foreground: warningBase, + border: token(resolved, 'border-warning-base', withAlpha(warningBase, 0.35)), + }, + error: { + background: token(resolved, 'surface-critical-weak', withAlpha(errorBase, 0.12)), + foreground: errorBase, + border: token(resolved, 'border-critical-base', withAlpha(errorBase, 0.35)), + }, + info: { + background: token(resolved, 'surface-info-weak', withAlpha(infoBase, 0.12)), + foreground: infoBase, + border: token(resolved, 'border-info-base', withAlpha(infoBase, 0.35)), + }, + }, + emptyState: { + icon: weakText, + title: foreground, + description: weakText, + border: token(resolved, 'border-weaker-base', borderBase), + }, + table: { + border: token(resolved, 'border-weaker-base', borderBase), + headerBackground: surfaceRaised, + headerForeground: foreground, + rowHover: surfaceBaseHover, + rowSelected: token(resolved, 'surface-interactive-weak', surfaceBase), + }, + charts: { + series: chartSeries, + }, + a11y: { + focusRing: borderFocus, + selection: token(resolved, 'surface-interactive-weak', surfaceBase), + highContrast: false, + }, + shadows: { + sm: isDark ? '0 2px 8px rgba(0, 0, 0, 0.22)' : '0 2px 8px rgba(15, 15, 15, 0.08)', + md: isDark ? '0 12px 32px rgba(0, 0, 0, 0.32)' : '0 12px 32px rgba(15, 15, 15, 0.12)', + lg: isDark ? '0 24px 56px rgba(0, 0, 0, 0.42)' : '0 24px 56px rgba(15, 15, 15, 0.16)', + focus: `0 0 0 3px ${withAlpha(interactiveSeed, isDark ? 0.35 : 0.25)}`, + }, + animation: { + fast: '150ms ease', + normal: '250ms ease', + slow: '350ms ease', + emphasis: '450ms cubic-bezier(0.2, 0.8, 0.2, 1)', + }, + }, + config: DEFAULT_CONFIG, + }; +} + +async function main(): Promise { + const args = parseArgs(process.argv.slice(2)); + + if (args.list) { + await listThemes(args.opencodeRoot); + return; + } + + if (args.specs.length === 0) { + usage(); + process.exitCode = 1; + return; + } + + const resolveThemeVariant = await loadResolver(args.opencodeRoot); + const generated: Array<{ fileName: string; theme: OpenChamberTheme }> = []; + + for (const spec of args.specs) { + const themePath = await resolveThemeSpec(spec, args.opencodeRoot); + const source = await loadThemeSource(themePath); + + if (isDesktopTheme(source)) { + const lightResolved = materializeTokens(resolveThemeVariant(source.light, false)); + const darkResolved = materializeTokens(resolveThemeVariant(source.dark, true)); + + generated.push( + { + fileName: `${source.id}-light.json`, + theme: buildTheme(source, source.light, lightResolved, 'light'), + }, + { + fileName: `${source.id}-dark.json`, + theme: buildTheme(source, source.dark, darkResolved, 'dark'), + }, + ); + continue; + } + + if (isContextTheme(source)) { + const id = sourceThemeId(themePath); + const name = sourceThemeName(themePath); + const syntheticTheme: DesktopTheme = { + id, + name, + light: { palette: { neutral: '#ffffff', primary: '#000000', success: '#000000', warning: '#000000', error: '#000000', info: '#000000' } }, + dark: { palette: { neutral: '#000000', primary: '#ffffff', success: '#ffffff', warning: '#ffffff', error: '#ffffff', info: '#ffffff' } }, + }; + + for (const mode of ['light', 'dark'] as const) { + const resolved = resolveContextTheme(source, mode); + const variant = syntheticVariantFromResolvedTheme({ + neutral: resolved.background ?? (mode === 'dark' ? '#151313' : '#FFFCF0'), + ink: resolved.text, + primary: resolved.primary ?? resolved.accent ?? resolved.info ?? '#5A96BC', + success: resolved.success ?? '#66800B', + warning: resolved.warning ?? '#DA702C', + error: resolved.error ?? '#AF3029', + info: resolved.info ?? resolved.secondary ?? resolved.primary ?? '#205EA6', + accent: resolved.accent ?? resolved.secondary ?? resolved.info ?? resolved.primary ?? '#205EA6', + interactive: resolved.borderActive ?? resolved.primary ?? '#5A96BC', + diffAdd: resolved.diffAdded ?? resolved.success ?? '#66800B', + diffDelete: resolved.diffRemoved ?? resolved.error ?? '#AF3029', + }); + + generated.push({ + fileName: `${id}-${mode}.json`, + theme: buildTheme(syntheticTheme, variant, syntheticTokensFromContextTheme(resolved, mode), mode), + }); + } + continue; + } + + if (isOpenChamberTheme(source)) { + const colors = source.colors as Record; + const variant = syntheticVariantFromResolvedTheme({ + neutral: colors.surface?.background ?? '#151313', + ink: colors.surface?.foreground, + primary: colors.primary?.base ?? '#5A96BC', + success: colors.status?.success ?? '#66800B', + warning: colors.status?.warning ?? '#DA702C', + error: colors.status?.error ?? '#AF3029', + info: colors.status?.info ?? '#205EA6', + accent: colors.syntax?.base?.keyword ?? colors.status?.info ?? colors.primary?.base ?? '#205EA6', + interactive: colors.interactive?.focus ?? colors.primary?.base ?? '#5A96BC', + diffAdd: colors.syntax?.highlights?.diffAdded ?? colors.status?.success ?? '#66800B', + diffDelete: colors.syntax?.highlights?.diffRemoved ?? colors.status?.error ?? '#AF3029', + }); + + const syntheticTheme: DesktopTheme = { + id: source.metadata.id.replace(/-(light|dark)$/u, ''), + name: source.metadata.name, + light: variant, + dark: variant, + }; + + generated.push({ + fileName: `${source.metadata.id}.json`, + theme: buildTheme( + syntheticTheme, + variant, + syntheticTokensFromOpenChamberTheme(source), + source.metadata.variant, + ), + }); + continue; + } + + throw new Error(`Unsupported theme source: ${themePath}`); + } + + if (args.stdout) { + const output = generated.length === 1 ? generated[0]?.theme : generated; + console.log(JSON.stringify(output, null, 2)); + return; + } + + await fs.mkdir(args.outDir, { recursive: true }); + + for (const { fileName, theme } of generated) { + const outputPath = path.join(args.outDir, fileName); + if (!args.force && (await exists(outputPath))) { + throw new Error(`Refusing to overwrite existing file without --force: ${outputPath}`); + } + await fs.writeFile(outputPath, `${JSON.stringify(theme, null, 2)}\n`, 'utf8'); + console.log(`wrote ${outputPath}`); + } +} + +main().catch((error: unknown) => { + const message = error instanceof Error ? error.message : String(error); + console.error(message); + process.exitCode = 1; +});