Files
autocoder/ui/src/styles/globals.css
Auto c917582a64 refactor(ui): migrate to shadcn/ui components and fix scroll issues
Migrate UI component library from custom implementations to shadcn/ui:
- Add shadcn/ui primitives (Button, Card, Dialog, Input, etc.)
- Replace custom styles with Tailwind CSS v4 theme configuration
- Remove custom-theme.css in favor of globals.css with @theme directive

Fix scroll overflow issues in multiple components:
- ProjectSelector: "New Project" button no longer overlays project list
- FolderBrowser: folder list now scrolls properly within modal
- AgentCard: log modal content stays within bounds
- ConversationHistory: conversation list scrolls correctly
- KanbanColumn: feature cards scroll within fixed height
- ScheduleModal: schedule form content scrolls properly

Key technical changes:
- Replace ScrollArea component with native overflow-y-auto divs
- Add min-h-0 to flex containers to allow proper shrinking
- Restructure dropdown layouts with flex-col for fixed footers

New files:
- ui/components.json (shadcn/ui configuration)
- ui/src/components/ui/* (20 UI primitive components)
- ui/src/lib/utils.ts (cn utility for class merging)
- ui/tsconfig.app.json (app-specific TypeScript config)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 18:25:55 +02:00

522 lines
12 KiB
CSS

@import "tailwindcss";
@import "tw-animate-css";
/* Enable class-based dark mode in Tailwind v4 */
@custom-variant dark (&:where(.dark, .dark *));
/* ============================================================================
ShadCN Theme - Clean Twitter-Style Design
============================================================================ */
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(0.9784 0.0011 197.1387);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.6723 0.1606 244.9955);
--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.6188 0.2376 25.7658);
--destructive-foreground: oklch(0.985 0 0);
--border: oklch(0.9317 0.0118 231.6594);
--input: oklch(0.922 0 0);
--ring: oklch(0.6723 0.1606 244.9955);
--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.6723 0.1606 244.9955);
--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);
/* Log level colors (kept for Terminal/Debug components) */
--color-log-error: #ef4444;
--color-log-warning: #f59e0b;
--color-log-info: #3b82f6;
--color-log-debug: #6b7280;
--color-log-success: #22c55e;
/* Status colors for Kanban */
--color-status-pending: oklch(0.9392 0.0166 250.8453);
--color-status-progress: oklch(0.85 0.08 245);
--color-status-done: oklch(0.85 0.08 245);
/* Font stacks */
--font-sans: 'Open Sans', -apple-system, BlinkMacSystemFont, sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
/* Transitions */
--transition-fast: 150ms;
--transition-normal: 250ms;
--ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
}
.dark {
--background: oklch(0.08 0 0);
--foreground: oklch(0.95 0 0);
--card: oklch(0.16 0.005 250);
--card-foreground: oklch(0.95 0 0);
--popover: oklch(0.16 0.005 250);
--popover-foreground: oklch(0.95 0 0);
--primary: oklch(0.6692 0.1607 245.0110);
--primary-foreground: oklch(0.985 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);
--destructive-foreground: oklch(0.985 0 0);
--border: oklch(0.30 0 0);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.6692 0.1607 245.0110);
--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);
/* Log level colors for dark mode */
--color-log-error: #f87171;
--color-log-warning: #fbbf24;
--color-log-info: #60a5fa;
--color-log-debug: #9ca3af;
--color-log-success: #4ade80;
/* Status colors for Kanban - dark mode */
--color-status-pending: oklch(0.25 0.02 250);
--color-status-progress: oklch(0.25 0.05 245);
--color-status-done: oklch(0.25 0.05 245);
}
/* ShadCN Tailwind v4 Theme Integration */
@theme inline {
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--radius-2xl: calc(var(--radius) + 8px);
--radius-3xl: calc(var(--radius) + 12px);
--radius-4xl: calc(var(--radius) + 16px);
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--font-sans: var(--font-sans);
--font-mono: var(--font-mono);
}
/* ============================================================================
Base Layer
============================================================================ */
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
font-family: var(--font-sans);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
/* Form elements inherit colors */
button,
input,
textarea,
select {
color: inherit;
font-family: inherit;
}
}
/* ============================================================================
Animations
============================================================================ */
@keyframes popIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-10px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes shimmer {
0% {
background-position: 200% center;
}
100% {
background-position: -200% center;
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-4px);
}
}
/* Agent mascot animations */
@keyframes thinking {
0%, 100% {
transform: translateY(0) scale(1);
}
25% {
transform: translateY(-2px) scale(1.02);
}
50% {
transform: translateY(0) scale(1);
}
75% {
transform: translateY(-2px) scale(0.98);
}
}
@keyframes working {
0%, 100% {
transform: translateX(0);
}
25% {
transform: translateX(-1px);
}
75% {
transform: translateX(1px);
}
}
@keyframes testing {
0%, 100% {
transform: rotate(0deg);
}
25% {
transform: rotate(-3deg);
}
75% {
transform: rotate(3deg);
}
}
@keyframes celebrate {
0%, 100% {
transform: scale(1) rotate(0deg);
}
25% {
transform: scale(1.1) rotate(-5deg);
}
50% {
transform: scale(1.15) rotate(0deg);
}
75% {
transform: scale(1.1) rotate(5deg);
}
}
@keyframes shake {
0%, 100% {
transform: translateX(0);
}
20%, 60% {
transform: translateX(-2px);
}
40%, 80% {
transform: translateX(2px);
}
}
@keyframes confetti {
0% {
transform: translateY(0) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(720deg);
opacity: 0;
}
}
/* Orchestrator (Maestro) animations */
@keyframes conducting {
0%, 100% {
transform: rotate(-10deg);
}
25% {
transform: rotate(5deg);
}
50% {
transform: rotate(-5deg);
}
75% {
transform: rotate(10deg);
}
}
@keyframes batonTap {
0%, 100% {
transform: translateY(0) rotate(0deg);
}
25% {
transform: translateY(-3px) rotate(-2deg);
}
50% {
transform: translateY(0) rotate(0deg);
}
75% {
transform: translateY(-3px) rotate(2deg);
}
}
/* ============================================================================
Utility Classes
============================================================================ */
@layer utilities {
.animate-pop-in {
animation: popIn 0.2s ease-out;
}
.animate-slide-in {
animation: slideIn 0.2s ease-out;
}
.animate-slide-in-up {
animation: slideInUp 0.2s ease-out;
}
.animate-slide-in-down {
animation: slideInDown 0.2s ease-out;
}
.animate-fade-in {
animation: fadeIn 0.2s ease-out;
}
.animate-shimmer {
background: linear-gradient(
90deg,
var(--foreground) 0%,
var(--foreground) 40%,
var(--primary) 50%,
var(--foreground) 60%,
var(--foreground) 100%
);
background-size: 200% 100%;
background-clip: text;
-webkit-background-clip: text;
color: transparent;
animation: shimmer 2s ease-in-out infinite;
}
.animate-spin {
animation: spin 1s linear infinite;
}
.animate-pulse {
animation: pulse 2s ease-in-out infinite;
}
.animate-bounce {
animation: bounce 2s ease-in-out infinite;
}
/* Agent mascot animation utilities */
.animate-thinking {
animation: thinking 1.5s ease-in-out infinite;
}
.animate-working {
animation: working 0.3s ease-in-out infinite;
}
.animate-testing {
animation: testing 0.8s ease-in-out infinite;
}
.animate-celebrate {
animation: celebrate 0.6s ease-in-out;
}
.animate-shake {
animation: shake 0.5s ease-in-out infinite;
}
.animate-confetti {
animation: confetti 2s ease-out forwards;
}
/* Orchestrator (Maestro) animation utilities */
.animate-conducting {
animation: conducting 1s ease-in-out infinite;
}
.animate-baton-tap {
animation: batonTap 0.6s ease-in-out infinite;
}
.animate-maestro-idle {
animation: bounce 2s ease-in-out infinite;
}
.animate-maestro-complete {
animation: celebrate 0.8s ease-in-out;
}
/* Stagger delays for sequential animations */
.stagger-1 { animation-delay: 50ms; }
.stagger-2 { animation-delay: 100ms; }
.stagger-3 { animation-delay: 150ms; }
.stagger-4 { animation-delay: 200ms; }
.stagger-5 { animation-delay: 250ms; }
/* Font utilities */
.font-sans {
font-family: var(--font-sans);
}
.font-mono {
font-family: var(--font-mono);
}
}
/* ============================================================================
Scrollbar Styling
============================================================================ */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: var(--radius);
}
::-webkit-scrollbar-thumb:hover {
background: var(--muted-foreground);
}