From 110cccb09cd7fcf15a4c65a6a4c32e1ad1cf16a3 Mon Sep 17 00:00:00 2001 From: Dayuan Jiang <34411969+DayuanJiang@users.noreply.github.com> Date: Wed, 3 Dec 2025 21:49:34 +0900 Subject: [PATCH] feat: refresh UI with new typography and edit diff display (#63) - Switch from Geist to Plus Jakarta Sans (body) and JetBrains Mono (code) - Add visual diff display for edit_diagram tool showing search/replace pairs - Update color palette to clean modern OKLCH-based scheme - Improve chat message display with better styling and animations - Add syntax-highlighted code blocks for XML/JSON output - Improve scrollbar and shadow utilities --- app/globals.css | 253 ++++++++++++++++++------- app/layout.tsx | 14 +- app/page.tsx | 73 ++++---- components/chat-example-panel.tsx | 131 ++++++++----- components/chat-input.tsx | 245 ++++++++++++------------ components/chat-message-display.tsx | 281 ++++++++++++++++++---------- components/chat-panel.tsx | 139 +++++++------- components/code-block.tsx | 39 ++++ package-lock.json | 20 ++ package.json | 1 + 10 files changed, 746 insertions(+), 450 deletions(-) create mode 100644 components/code-block.tsx diff --git a/app/globals.css b/app/globals.css index b70a101..d0cdabb 100644 --- a/app/globals.css +++ b/app/globals.css @@ -7,8 +7,8 @@ @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); + --font-sans: var(--font-sans); + --font-mono: var(--font-mono); --color-sidebar-ring: var(--sidebar-ring); --color-sidebar-border: var(--sidebar-border); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); @@ -45,72 +45,102 @@ } :root { - --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); + --radius: 0.75rem; + + /* Clean Light Modern Palette */ + --background: oklch(0.985 0.002 240); + --foreground: oklch(0.23 0.02 260); + --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); + --card-foreground: oklch(0.23 0.02 260); + --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.97 0 0); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.708 0 0); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.708 0 0); + --popover-foreground: oklch(0.23 0.02 260); + + /* Dark primary - slightly lighter */ + --primary: oklch(0.35 0.01 260); + --primary-foreground: oklch(0.99 0 0); + + /* Warm gray secondary */ + --secondary: oklch(0.96 0.005 260); + --secondary-foreground: oklch(0.35 0.02 260); + + /* Light muted tones */ + --muted: oklch(0.965 0.005 260); + --muted-foreground: oklch(0.50 0.02 260); + + /* Soft lavender accent */ + --accent: oklch(0.94 0.03 280); + --accent-foreground: oklch(0.35 0.08 270); + + /* Coral destructive */ + --destructive: oklch(0.60 0.20 25); + + /* Subtle borders */ + --border: oklch(0.92 0.01 260); + --input: oklch(0.94 0.01 260); + --ring: oklch(0.25 0.01 260); + + /* Chart colors - harmonious palette */ + --chart-1: oklch(0.55 0.18 265); + --chart-2: oklch(0.65 0.15 170); + --chart-3: oklch(0.70 0.18 45); + --chart-4: oklch(0.60 0.20 330); + --chart-5: oklch(0.50 0.15 200); + + /* Sidebar */ + --sidebar: oklch(0.99 0.002 260); + --sidebar-foreground: oklch(0.23 0.02 260); + --sidebar-primary: oklch(0.55 0.18 265); + --sidebar-primary-foreground: oklch(0.99 0 0); + --sidebar-accent: oklch(0.96 0.02 270); + --sidebar-accent-foreground: oklch(0.35 0.05 265); + --sidebar-border: oklch(0.93 0.01 260); + --sidebar-ring: oklch(0.55 0.18 265); } .dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.205 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.556 0 0); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.556 0 0); + --background: oklch(0.15 0.015 260); + --foreground: oklch(0.95 0.01 260); + + --card: oklch(0.20 0.015 260); + --card-foreground: oklch(0.95 0.01 260); + + --popover: oklch(0.20 0.015 260); + --popover-foreground: oklch(0.95 0.01 260); + + --primary: oklch(0.70 0.16 265); + --primary-foreground: oklch(0.15 0.02 260); + + --secondary: oklch(0.25 0.015 260); + --secondary-foreground: oklch(0.90 0.01 260); + + --muted: oklch(0.25 0.015 260); + --muted-foreground: oklch(0.65 0.02 260); + + --accent: oklch(0.30 0.04 280); + --accent-foreground: oklch(0.90 0.03 270); + + --destructive: oklch(0.65 0.22 25); + + --border: oklch(0.28 0.015 260); + --input: oklch(0.25 0.015 260); + --ring: oklch(0.70 0.16 265); + + --chart-1: oklch(0.70 0.16 265); + --chart-2: oklch(0.70 0.13 170); + --chart-3: oklch(0.75 0.16 45); + --chart-4: oklch(0.70 0.18 330); + --chart-5: oklch(0.60 0.13 200); + + --sidebar: oklch(0.18 0.015 260); + --sidebar-foreground: oklch(0.95 0.01 260); + --sidebar-primary: oklch(0.70 0.16 265); + --sidebar-primary-foreground: oklch(0.15 0.02 260); + --sidebar-accent: oklch(0.25 0.03 270); + --sidebar-accent-foreground: oklch(0.90 0.02 265); + --sidebar-border: oklch(0.28 0.015 260); + --sidebar-ring: oklch(0.70 0.16 265); } @layer base { @@ -118,6 +148,101 @@ @apply border-border outline-ring/50; } body { - @apply bg-background text-foreground; + @apply bg-background text-foreground font-sans; } } + +/* Custom scrollbar */ +@layer utilities { + .scrollbar-thin { + scrollbar-width: thin; + scrollbar-color: oklch(0.85 0.01 260) transparent; + } + + .scrollbar-thin::-webkit-scrollbar { + width: 6px; + } + + .scrollbar-thin::-webkit-scrollbar-track { + background: transparent; + } + + .scrollbar-thin::-webkit-scrollbar-thumb { + background-color: oklch(0.85 0.01 260); + border-radius: 3px; + } + + .scrollbar-thin::-webkit-scrollbar-thumb:hover { + background-color: oklch(0.75 0.01 260); + } +} + +/* Smooth page transitions */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideInRight { + from { + opacity: 0; + transform: translateX(16px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.animate-fade-in { + animation: fadeIn 0.3s ease-out forwards; +} + +.animate-slide-in-right { + animation: slideInRight 0.3s ease-out forwards; +} + +/* Message bubble animations */ +@keyframes messageIn { + from { + opacity: 0; + transform: translateY(12px) scale(0.98); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +.animate-message-in { + animation: messageIn 0.25s ease-out forwards; +} + +/* Subtle floating shadow for cards */ +.shadow-soft { + box-shadow: + 0 1px 2px oklch(0.23 0.02 260 / 0.04), + 0 4px 12px oklch(0.23 0.02 260 / 0.06), + 0 8px 24px oklch(0.23 0.02 260 / 0.04); +} + +.shadow-soft-lg { + box-shadow: + 0 2px 4px oklch(0.23 0.02 260 / 0.04), + 0 8px 20px oklch(0.23 0.02 260 / 0.08), + 0 16px 40px oklch(0.23 0.02 260 / 0.06); +} + +/* Gradient text utility */ +.text-gradient-primary { + background: linear-gradient(135deg, oklch(0.55 0.18 265), oklch(0.60 0.20 290)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} diff --git a/app/layout.tsx b/app/layout.tsx index bf028fc..8a5b84e 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,19 +1,21 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; +import { Plus_Jakarta_Sans, JetBrains_Mono } from "next/font/google"; import { Analytics } from "@vercel/analytics/react"; import { GoogleAnalytics } from "@next/third-parties/google"; import { DiagramProvider } from "@/contexts/diagram-context"; import "./globals.css"; -const geistSans = Geist({ - variable: "--font-geist-sans", +const plusJakarta = Plus_Jakarta_Sans({ + variable: "--font-sans", subsets: ["latin"], + weight: ["400", "500", "600", "700"], }); -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", +const jetbrainsMono = JetBrains_Mono({ + variable: "--font-mono", subsets: ["latin"], + weight: ["400", "500"], }); export const metadata: Metadata = { @@ -91,7 +93,7 @@ export default function RootLayout({ />
+ This application works best on desktop or laptop devices. Please open it on a larger screen for the full experience. +
- {" "} - Start a conversation to generate or modify diagrams. -
-- {" "} - You can also upload images to use as references. -
-- Try these examples{" "} - (cached for instant response): -
-+ Describe what you want to create or upload an image to replicate +
++ Quick Examples +
+ ++ Examples are cached for instant response +