From a6c924c82be425b571b5e3e44b0297a56eea1896 Mon Sep 17 00:00:00 2001 From: Livia Holanda Date: Sat, 27 Jun 2026 11:05:52 -0300 Subject: [PATCH 1/6] style: restyle theme with new fonts and color palette - add self-hosted fonts: Mona Sans (body), Mozilla Text (headings), Space Mono (code) - introduce full light and dark color palette with a cohesive slate dark theme - fix dark-mode border visibility across form controls (input, select, switch, toggle, etc.) - make chat-input font size responsive and match its background/outline to slate - darken the user message bubble slightly in light mode - remove sidebar section dividers --- bun.lock | 12 ++ package.json | 4 + src/components/chat/chat-prompt-input.tsx | 4 + src/components/chat/message-bubbles.tsx | 24 ++-- src/components/sidebar-footer.tsx | 2 +- src/components/ui/combobox.tsx | 2 +- src/components/ui/input.tsx | 2 +- src/components/ui/prompt-input.tsx | 4 +- src/components/ui/select.tsx | 2 +- src/components/ui/switch.tsx | 2 +- src/components/ui/textarea.tsx | 2 +- src/components/ui/toggle.tsx | 2 +- src/index.css | 134 +++++++++++++--------- src/index.tsx | 7 ++ src/layout/sidebar/chat-sidebar.tsx | 11 +- src/layout/sidebar/settings-sidebar.tsx | 3 - src/layout/sidebar/sidebar-header.tsx | 2 +- 17 files changed, 125 insertions(+), 94 deletions(-) diff --git a/bun.lock b/bun.lock index 9f92e9dff..7dac045cd 100644 --- a/bun.lock +++ b/bun.lock @@ -14,6 +14,10 @@ "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", + "@fontsource-variable/dm-sans": "^5.2.8", + "@fontsource-variable/mona-sans": "^5.2.8", + "@fontsource-variable/mozilla-text": "^5.2.2", + "@fontsource/space-mono": "^5.2.9", "@hookform/resolvers": "^5.2.1", "@icons-pack/react-simple-icons": "^13.13.0", "@journeyapps/wa-sqlite": "^1.7.0", @@ -355,6 +359,14 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], + "@fontsource-variable/dm-sans": ["@fontsource-variable/dm-sans@5.2.8", "", {}, "sha512-AxkvMTvNWgfrmlyjiV05vlHYJa+nRQCf1EfvIrQAPBpFJW0O9VTz7oAFr9S3lvbWdmnFoBk7yFqQL86u64nl2g=="], + + "@fontsource-variable/mona-sans": ["@fontsource-variable/mona-sans@5.2.8", "", {}, "sha512-8OWdTcP8KvRxkU1Skkk+tX3D5XHN9buejxSDwrT7teRfGnpKBYxQUApV/+zS8TzeHiSU8H5Tc0HfBr57ahgcvA=="], + + "@fontsource-variable/mozilla-text": ["@fontsource-variable/mozilla-text@5.2.2", "", {}, "sha512-lIXYrFG2SHIOd4HMM9XYxgzscIUG2rcVjeDSlqJ8gfMg6cRMFwXvUe5m2L3fU/tB2nmp12+ut8sGCSjJEdimEw=="], + + "@fontsource/space-mono": ["@fontsource/space-mono@5.2.9", "", {}, "sha512-b61faFOHEISQ/pD25G+cfGY9o/WW6lRv6hBQQfpWvEJ4y1V+S4gmth95EVyBE2VL3qDYHeVQ8nBzrplzdXTDDg=="], + "@freedomofpress/crypto-browser": ["@freedomofpress/crypto-browser@0.1.7", "", { "dependencies": { "@noble/curves": "^1.6.0" } }, "sha512-zjWmZDKdAu8g0Zq1IjBQ+sKQ/NpfzStBDFjy/qHUSMVEL4wNlNGtA7lhtw8v8asXa0yqF2QTYQ3rq6xCTQeADw=="], "@freedomofpress/sigstore-browser": ["@freedomofpress/sigstore-browser@0.1.13", "", { "dependencies": { "@freedomofpress/crypto-browser": "^0.1.7", "@freedomofpress/tuf-browser": "^0.1.11", "@noble/curves": "^2.0.1" } }, "sha512-3YfmP9JQ5h8CAO/vKJEGYrFdzss6xWxYi5ZkbR4KoHlxIaLGrnu+5TQDoZVWhuhyfDBdLQqj6ypdN0W6PsH3Jw=="], diff --git a/package.json b/package.json index 1441ba8f8..b72c6c95b 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,10 @@ "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", + "@fontsource-variable/dm-sans": "^5.2.8", + "@fontsource-variable/mona-sans": "^5.2.8", + "@fontsource-variable/mozilla-text": "^5.2.2", + "@fontsource/space-mono": "^5.2.9", "@hookform/resolvers": "^5.2.1", "@icons-pack/react-simple-icons": "^13.13.0", "@journeyapps/wa-sqlite": "^1.7.0", diff --git a/src/components/chat/chat-prompt-input.tsx b/src/components/chat/chat-prompt-input.tsx index de54b1669..986ecbbb2 100644 --- a/src/components/chat/chat-prompt-input.tsx +++ b/src/components/chat/chat-prompt-input.tsx @@ -650,7 +650,11 @@ export const ChatPromptInput = forwardRef>>>>>> 2a33ea40 (style: restyle theme with new fonts and color palette) footerStartElements={footerStartElements} renderOverlay={(value) => renderHighlightedSkillTokens(value, classifySkill)} popoverSlot={ diff --git a/src/components/chat/message-bubbles.tsx b/src/components/chat/message-bubbles.tsx index c8d275e69..958795da2 100644 --- a/src/components/chat/message-bubbles.tsx +++ b/src/components/chat/message-bubbles.tsx @@ -1,18 +1,15 @@ /* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { hasTransformer } from '@/files/transformers' -import { useShowSideview } from '@/content-view/context' -import { getAttachments } from '@/lib/attachments' -import type { ThunderboltUIMessage } from '@/types' -import { buildDocumentSideviewId } from '@/types/citation' +import { getAttachments } from '@/chats/message-utils' +import { useShowSideview } from '@/sideview/sideview-store' +import type { ThunderboltUIMessage } from '@/chats/types' +import { buildDocumentSideviewId } from '@/sideview/sideview-id-builder' import type { UIMessage } from 'ai' -import { FileCard } from './file-card' import { MemoizedMarkdown } from './memoized-markdown' - -/** Re-deliver a single attachment as text/images and re-run the turn. */ -export type ResendAttachmentHandler = (localFileId: string, target: 'text' | 'images') => void +import { FileCard } from './file-card' +import type { ResendAttachmentHandler } from './file-card' type MessageBubblesProps = { message: UIMessage @@ -28,9 +25,6 @@ export const MessageBubbles = ({ message, onResendAttachment }: MessageBubblesPr {attachments.length > 0 && (
{attachments.map((attachment) => { - // Alternative delivery modes to offer, but only on the latest turn and - // only once a non-native mode is in effect (i.e. remediation already - // converted this file) — so a clean native send shows no resend noise. const resendTargets = onResendAttachment && attachment.deliverAs ? (['text', 'images'] as const).filter( @@ -65,7 +59,7 @@ export const MessageBubbles = ({ message, onResendAttachment }: MessageBubblesPr {message.parts .filter((part) => part.type === 'text') .map((part, j) => ( -
+
diff --git a/src/components/sidebar-footer.tsx b/src/components/sidebar-footer.tsx index bf26f0506..44ed5c0ae 100644 --- a/src/components/sidebar-footer.tsx +++ b/src/components/sidebar-footer.tsx @@ -128,7 +128,7 @@ export const SidebarFooter = ({ className }: SidebarFooterProps) => { return ( - + {isPending ? ( diff --git a/src/components/ui/combobox.tsx b/src/components/ui/combobox.tsx index 7706830c0..71e8bab2c 100644 --- a/src/components/ui/combobox.tsx +++ b/src/components/ui/combobox.tsx @@ -105,7 +105,7 @@ export const Combobox = ({ disabled={disabled} {...triggerProps} className={cn( - "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-full items-center justify-between gap-2 rounded-lg border bg-transparent px-3 py-2 text-[length:var(--font-size-body)] whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 h-[var(--touch-height-default)] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + "border-border data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-full items-center justify-between gap-2 rounded-lg border bg-transparent px-3 py-2 text-[length:var(--font-size-body)] whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 h-[var(--touch-height-default)] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", !triggerLabel && 'text-muted-foreground', className, )} diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index 81d3b1760..34a094a49 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -8,7 +8,7 @@ import { forwardRef, type InputHTMLAttributes } from 'react' import { cn } from '@/lib/utils' const inputVariants = cva( - 'border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex min-w-0 rounded-lg border bg-transparent px-3 py-1 text-[length:var(--font-size-body)] outline-none file:inline-flex file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50', + 'border-border file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex min-w-0 rounded-lg border bg-transparent px-3 py-1 text-[length:var(--font-size-body)] outline-none file:inline-flex file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50', { variants: { variant: { diff --git a/src/components/ui/prompt-input.tsx b/src/components/ui/prompt-input.tsx index 694587c02..c0dec670f 100644 --- a/src/components/ui/prompt-input.tsx +++ b/src/components/ui/prompt-input.tsx @@ -169,7 +169,7 @@ export const PromptInput = forwardRef( @@ -185,7 +185,7 @@ export const PromptInput = forwardRef( maxHeight={240} autoFocus={autoFocus} className={cn( - 'w-full border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 resize-none px-1 py-2 text-base leading-5', + 'w-full border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 resize-none px-1 py-2 text-[length:var(--font-size-body)] leading-5', renderOverlay && 'text-transparent caret-foreground', )} /> diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx index 1a8348c23..33f908790 100644 --- a/src/components/ui/select.tsx +++ b/src/components/ui/select.tsx @@ -33,7 +33,7 @@ const SelectTrigger = ({ data-slot="select-trigger" data-size={size} className={cn( - "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-[length:var(--font-size-body)] whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[var(--touch-height-default)] data-[size=sm]:h-[var(--touch-height-sm)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + "border-border data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-[length:var(--font-size-body)] whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[var(--touch-height-default)] data-[size=sm]:h-[var(--touch-height-sm)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className, )} {...props} diff --git a/src/components/ui/switch.tsx b/src/components/ui/switch.tsx index c7b2de358..03fca5b04 100644 --- a/src/components/ui/switch.tsx +++ b/src/components/ui/switch.tsx @@ -23,7 +23,7 @@ const Switch = ({ className, onCheckedChange, ...props }: ComponentProps) => {