feat: modernize frontend UI with Tailwind v4 and professional design system

BREAKING CHANGE: Migrated to Tailwind CSS v4 configuration system

Key Changes:
- Migrated from Tailwind v3 to v4 configuration system
  - Removed tailwind.config.js (incompatible with v4)
  - Updated index.css with @theme directive and oklch color space
  - Defined all custom animations directly in CSS using @keyframes

- Redesigned LoginPage with modern, enterprise-grade UI:
  - Full-screen gradient background (blue → purple → pink)
  - Floating animated orbs with blur effects
  - Glass morphism white card with backdrop-blur
  - Gradient buttons with shadow effects
  - 7 custom animations: fade-in, slide-in-right, slide-in-left, scale-in, shimmer, pulse, float

- Added shadcn/ui components:
  - alert.tsx, dialog.tsx, input.tsx, label.tsx, select.tsx, tabs.tsx

- Updated dependencies:
  - Added class-variance-authority ^0.7.0
  - Added react-markdown ^9.0.1

- Updated frontend documentation:
  - Comprehensive README.md with feature list, tech stack, project structure
  - Quick start guide and deployment instructions

Technical Details:
- Tailwind v4 uses @import "tailwindcss" instead of @tailwind directives
- All theme customization now in @theme block with CSS variables
- Color system migrated to oklch for better perceptual uniformity
- Animation definitions moved from config to CSS @layer utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
beabigegg
2025-11-13 08:55:01 +08:00
parent 9cf36d8e21
commit 57cf91271c
12 changed files with 2134 additions and 419 deletions

View File

@@ -1,115 +1,172 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "tailwindcss";
@layer base {
:root {
/* Clean, modern color palette */
--background: 220 15% 97%;
--foreground: 220 15% 15%;
--card: 0 0% 100%;
--card-foreground: 220 15% 15%;
--popover: 0 0% 100%;
--popover-foreground: 220 15% 15%;
@theme {
/* Clean, modern color palette */
--color-background: oklch(95% 0.02 220);
--color-foreground: oklch(20% 0.02 220);
--color-card: oklch(100% 0 0);
--color-card-foreground: oklch(20% 0.02 220);
--color-popover: oklch(100% 0 0);
--color-popover-foreground: oklch(20% 0.02 220);
/* Primary: Professional blue */
--primary: 217 91% 60%;
--primary-foreground: 0 0% 100%;
--primary-hover: 217 91% 50%;
/* Primary: Professional blue */
--color-primary: oklch(65% 0.25 250);
--color-primary-foreground: oklch(100% 0 0);
--color-primary-hover: oklch(60% 0.25 250);
/* Secondary: Subtle gray-blue */
--secondary: 220 15% 95%;
--secondary-foreground: 220 15% 25%;
/* Secondary: Subtle gray-blue */
--color-secondary: oklch(95% 0.02 220);
--color-secondary-foreground: oklch(30% 0.02 220);
/* Accent: Vibrant teal */
--accent: 173 80% 50%;
--accent-foreground: 0 0% 100%;
/* Accent: Vibrant teal */
--color-accent: oklch(65% 0.20 180);
--color-accent-foreground: oklch(100% 0 0);
/* Sidebar */
--sidebar: 220 25% 12%;
--sidebar-foreground: 220 10% 90%;
--sidebar-active: 217 91% 60%;
/* Muted */
--color-muted: oklch(93% 0.02 220);
--color-muted-foreground: oklch(50% 0.02 220);
/* Muted */
--muted: 220 15% 93%;
--muted-foreground: 220 10% 45%;
/* Destructive */
--color-destructive: oklch(60% 0.22 25);
--color-destructive-foreground: oklch(100% 0 0);
/* Destructive */
--destructive: 0 85% 60%;
--destructive-foreground: 0 0% 100%;
/* Success */
--color-success: oklch(55% 0.20 150);
--color-success-foreground: oklch(100% 0 0);
/* Success */
--success: 142 72% 45%;
--success-foreground: 0 0% 100%;
/* Warning */
--color-warning: oklch(65% 0.22 60);
--color-warning-foreground: oklch(100% 0 0);
/* Warning */
--warning: 38 92% 50%;
--warning-foreground: 0 0% 100%;
/* Borders and inputs */
--color-border: oklch(88% 0.02 220);
--color-input: oklch(88% 0.02 220);
--color-ring: oklch(65% 0.25 250);
/* Borders and inputs */
--border: 220 13% 88%;
--input: 220 13% 88%;
--ring: 217 91% 60%;
--radius: 0.5rem;
/* Border radius */
--radius-lg: 0.5rem;
--radius-md: calc(0.5rem - 2px);
--radius-sm: calc(0.5rem - 4px);
/* Shadows */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
}
.dark {
/* Dark mode with rich colors */
--background: 240 20% 8%;
--foreground: 240 5% 95%;
--card: 240 15% 12%;
--card-foreground: 240 5% 95%;
--popover: 240 15% 12%;
--popover-foreground: 240 5% 95%;
/* Primary: Brighter in dark mode */
--primary: 250 85% 65%;
--primary-foreground: 240 20% 8%;
--primary-glow: 250 85% 65%;
/* Secondary */
--secondary: 240 15% 18%;
--secondary-foreground: 240 5% 95%;
/* Accent */
--accent: 190 85% 55%;
--accent-foreground: 240 20% 8%;
/* Muted */
--muted: 240 15% 15%;
--muted-foreground: 240 5% 65%;
/* Destructive */
--destructive: 0 80% 60%;
--destructive-foreground: 0 0% 100%;
/* Success */
--success: 142 70% 50%;
--success-foreground: 0 0% 100%;
/* Borders */
--border: 240 15% 20%;
--input: 240 15% 20%;
--ring: 250 85% 65%;
}
/* Animations */
--animate-fade-in: fade-in 0.5s ease-out;
--animate-slide-in-right: slide-in-right 0.5s ease-out;
--animate-slide-in-left: slide-in-left 0.5s ease-out;
--animate-scale-in: scale-in 0.3s ease-out;
--animate-shimmer: shimmer 2s linear infinite;
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
--animate-float: float 3s ease-in-out infinite;
}
@layer base {
body {
background-color: hsl(var(--background));
color: hsl(var(--foreground));
background-color: var(--color-background);
color: var(--color-foreground);
font-feature-settings: "rlig" 1, "calt" 1;
}
}
@layer utilities {
/* Animations */
@keyframes fade-in {
0% {
opacity: 0;
transform: translateY(10px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slide-in-right {
0% {
opacity: 0;
transform: translateX(20px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slide-in-left {
0% {
opacity: 0;
transform: translateX(-20px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
@keyframes scale-in {
0% {
opacity: 0;
transform: scale(0.95);
}
100% {
opacity: 1;
transform: scale(1);
}
}
@keyframes shimmer {
0% {
background-position: -1000px 0;
}
100% {
background-position: 1000px 0;
}
}
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.8;
}
}
@keyframes float {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
}
.animate-fade-in {
animation: fade-in 0.5s ease-out;
}
.animate-slide-in-right {
animation: slide-in-right 0.5s ease-out;
}
.animate-slide-in-left {
animation: slide-in-left 0.5s ease-out;
}
.animate-scale-in {
animation: scale-in 0.3s ease-out;
}
.animate-shimmer {
animation: shimmer 2s linear infinite;
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
/* Custom scrollbar */
.scrollbar-thin::-webkit-scrollbar {
width: 6px;
@@ -117,17 +174,17 @@
}
.scrollbar-thin::-webkit-scrollbar-track {
background: hsl(var(--muted));
background: var(--color-muted);
border-radius: 3px;
}
.scrollbar-thin::-webkit-scrollbar-thumb {
background: hsl(var(--muted-foreground) / 0.3);
background: color-mix(in oklch, var(--color-muted-foreground) 30%, transparent);
border-radius: 3px;
}
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
background: hsl(var(--muted-foreground) / 0.5);
background: color-mix(in oklch, var(--color-muted-foreground) 50%, transparent);
}
.scrollbar-hide::-webkit-scrollbar {
@@ -149,31 +206,31 @@
.page-title {
font-size: 1.875rem;
font-weight: 700;
color: hsl(var(--foreground));
color: var(--color-foreground);
margin-bottom: 0.5rem;
}
.page-description {
color: hsl(var(--muted-foreground));
color: var(--color-muted-foreground);
font-size: 0.875rem;
}
/* Section */
.section {
background: hsl(var(--card));
border: 1px solid hsl(var(--border));
border-radius: var(--radius);
background: var(--color-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: 1.5rem;
box-shadow: var(--shadow-sm);
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
.section-header {
font-size: 1.125rem;
font-weight: 600;
color: hsl(var(--foreground));
color: var(--color-foreground);
margin-bottom: 1rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid hsl(var(--border));
border-bottom: 1px solid var(--color-border);
}
/* Status badge */
@@ -187,22 +244,22 @@
}
.status-badge-success {
background: hsl(var(--success) / 0.1);
color: hsl(var(--success));
background: color-mix(in oklch, var(--color-success) 10%, transparent);
color: var(--color-success);
}
.status-badge-warning {
background: hsl(var(--warning) / 0.1);
color: hsl(var(--warning));
background: color-mix(in oklch, var(--color-warning) 10%, transparent);
color: var(--color-warning);
}
.status-badge-error {
background: hsl(var(--destructive) / 0.1);
color: hsl(var(--destructive));
background: color-mix(in oklch, var(--color-destructive) 10%, transparent);
color: var(--color-destructive);
}
.status-badge-info {
background: hsl(var(--primary) / 0.1);
color: hsl(var(--primary));
background: color-mix(in oklch, var(--color-primary) 10%, transparent);
color: var(--color-primary);
}
}