🎨 TutorConnect UC - Design System & Style Guide
📐 Principios de Diseño
Core Values
- Universitario & Profesional: Refleja la seriedad académica de la UC
- Accesible & Inclusivo: Usable para todos los estudiantes
- Eficiente: Mínimos clicks para completar acciones
- Confiable: Transmite seguridad y verificación
- Mobile-First: Optimizado para estudiantes en movimiento
🎨 Paleta de Colores
Colores Primarios (UC Brand)
/* Azul UC - Color principal */
--uc-blue: #002D5E;
--uc-blue-light: #1E4A7A;
--uc-blue-dark: #001B3D;
/* Dorado UC - Acentos */
--uc-gold: #D4AF37;
--uc-gold-light: #E5C766;
--uc-gold-dark: #B89520;Colores Secundarios (Aplicación)
/* Grises (Neutrales) */
--gray-50: #F9FAFB;
--gray-100: #F3F4F6;
--gray-200: #E5E7EB;
--gray-300: #D1D5DB;
--gray-400: #9CA3AF;
--gray-500: #6B7280;
--gray-600: #4B5563;
--gray-700: #374151;
--gray-800: #1F2937;
--gray-900: #111827;
/* Colores Funcionales */
--success: #10B981; /* Verde - confirmado, completado */
--warning: #F59E0B; /* Amarillo - pendiente, advertencia */
--error: #EF4444; /* Rojo - urgente, error */
--info: #3B82F6; /* Azul claro - información */Estados de Tutorías (Semánticos)
--status-pending: #F59E0B; /* 🟡 Pendiente */
--status-confirmed: #10B981; /* 🟢 Confirmada */
--status-completed: #6B7280; /* ✅ Completada */
--status-cancelled: #EF4444; /* ❌ Cancelada */Uso de Colores
| Elemento | Color | Cuándo Usar |
|---|---|---|
| Botones primarios | uc-blue | Acciones principales (Agendar, Enviar) |
| Botones secundarios | gray-600 | Acciones secundarias (Cancelar, Ver más) |
| Badges destacados | uc-gold | Premium, destacado, verificado |
| Links | uc-blue-light | Enlaces de texto |
| Backgrounds | gray-50 | Fondos de secciones alternadas |
| Borders | gray-200 | Bordes de cards, inputs |
📝 Tipografía
Font Stack
/* Sans-serif (Principal) */
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI',
'Roboto', sans-serif;
/* Monospace (Código de ramos) */
font-family: 'JetBrains Mono', 'Fira Code', 'Courier New', monospace;Escala Tipográfica
/* Headings */
--text-h1: 2.5rem; /* 40px - Títulos principales */
--text-h2: 2rem; /* 32px - Secciones */
--text-h3: 1.5rem; /* 24px - Subsecciones */
--text-h4: 1.25rem; /* 20px - Cards headers */
--text-h5: 1.125rem; /* 18px - Pequeños headers */
/* Body */
--text-base: 1rem; /* 16px - Texto normal */
--text-sm: 0.875rem; /* 14px - Texto secundario */
--text-xs: 0.75rem; /* 12px - Metadata, badges */
/* Font Weights */
--font-light: 300;
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;Jerarquía Visual
// Ejemplo en componentes
<h1 className="text-4xl font-bold text-gray-900">
Encuentra tu tutor UC
</h1>
<h2 className="text-3xl font-bold text-gray-800">
Tutores Destacados
</h2>
<p className="text-base text-gray-600">
Descripción normal del contenido
</p>
<span className="text-sm text-gray-500">
Metadata o información secundaria
</span>
<code className="text-sm font-mono text-uc-blue bg-gray-100 px-2 py-1 rounded">
IIC2233
</code>📏 Espaciado (Spacing Scale)
Sistema de 8pt Grid
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
--space-20: 5rem; /* 80px */Reglas de Espaciado
/* Entre elementos relacionados */
gap: 1rem; /* 16px */
/* Entre secciones */
margin-bottom: 2rem; /* 32px */
/* Padding de containers */
padding: 1.5rem; /* 24px desktop */
padding: 1rem; /* 16px mobile */
/* Padding de cards */
padding: 1.5rem; /* 24px */🔲 Componentes Base
Buttons
// Primary Button
<button className="
px-6 py-3
bg-uc-blue hover:bg-uc-blue-light
text-white font-medium
rounded-lg
transition-colors duration-200
focus:outline-none focus:ring-2 focus:ring-uc-blue focus:ring-offset-2
">
Agendar Tutoría →
</button>
// Secondary Button
<button className="
px-6 py-3
bg-gray-100 hover:bg-gray-200
text-gray-700 font-medium
rounded-lg
transition-colors duration-200
">
Cancelar
</button>
// Ghost Button
<button className="
px-4 py-2
text-uc-blue hover:bg-blue-50
font-medium
rounded-lg
transition-colors duration-200
">
Ver más
</button>
// Destructive Button
<button className="
px-6 py-3
bg-red-500 hover:bg-red-600
text-white font-medium
rounded-lg
transition-colors duration-200
">
Eliminar
</button>Cards
// TutorCard
<div className="
bg-white
border border-gray-200
rounded-xl
p-6
shadow-sm hover:shadow-md
transition-shadow duration-200
">
{/* Content */}
</div>
// OfertaCard (con badge)
<div className="
bg-white
border-l-4 border-l-green-500
border border-gray-200
rounded-lg
p-4
">
<span className="
inline-block
px-2 py-1
bg-green-100 text-green-700
text-xs font-semibold
rounded-full
">
🟢 OFERTA
</span>
</div>Inputs
// Text Input
<input
type="text"
className="
w-full
px-4 py-2
border border-gray-300
rounded-lg
focus:outline-none focus:ring-2 focus:ring-uc-blue focus:border-transparent
placeholder:text-gray-400
"
placeholder="Buscar ramo..."
/>
// Select
<select className="
w-full
px-4 py-2
border border-gray-300
rounded-lg
bg-white
focus:outline-none focus:ring-2 focus:ring-uc-blue
">
<option>Selecciona un campus</option>
</select>Badges
// Status Badge
<span className="
inline-flex items-center
px-2.5 py-0.5
rounded-full
text-xs font-medium
bg-yellow-100 text-yellow-800
">
🟡 Pendiente
</span>
// Rating Badge
<span className="
inline-flex items-center
gap-1
text-sm font-medium
">
⭐ 4.9
</span>
// Campus Badge
<span className="
inline-block
px-2 py-1
bg-uc-blue text-white
text-xs font-medium
rounded
">
📍 San Joaquín
</span>🧩 Componentes Compuestos
TutorCard (Reutilizable)
// components/tutor-card.tsx
interface TutorCardProps {
tutor: {
id: string
full_name: string
avatar_url?: string
avg_rating: number
total_reviews: number
campus: string
tarifa: number
ramos: { codigo: string; nota: number }[]
}
}
export function TutorCard({ tutor }: TutorCardProps) {
return (
<Link href={`/tutor/${tutor.id}`}>
<div className="
bg-white
border border-gray-200
rounded-xl
p-6
hover:shadow-lg
transition-all duration-200
cursor-pointer
hover:border-uc-blue
">
{/* Avatar */}
<div className="flex items-center gap-4 mb-4">
<Avatar className="h-16 w-16">
<AvatarImage src={tutor.avatar_url} />
<AvatarFallback className="bg-uc-blue text-white">
{tutor.full_name[0]}
</AvatarFallback>
</Avatar>
<div>
<h3 className="font-semibold text-gray-900">
{tutor.full_name}
</h3>
<div className="flex items-center gap-1 text-sm">
<span className="text-yellow-500">⭐</span>
<span className="font-medium">{tutor.avg_rating}</span>
<span className="text-gray-500">({tutor.total_reviews})</span>
</div>
</div>
</div>
{/* Ramo principal */}
{tutor.ramos[0] && (
<div className="mb-3">
<code className="
text-sm font-mono
bg-gray-100 text-uc-blue
px-2 py-1 rounded
">
{tutor.ramos[0].codigo}
</code>
<span className="ml-2 text-sm text-gray-600">
Nota: {tutor.ramos[0].nota}
</span>
</div>
)}
{/* Footer */}
<div className="flex items-center justify-between pt-4 border-t">
<span className="text-lg font-bold text-gray-900">
${tutor.tarifa.toLocaleString()}
<span className="text-sm font-normal text-gray-500">/módulo</span>
</span>
<Badge variant="outline">{tutor.campus}</Badge>
</div>
</div>
</Link>
)
}SessionCard (Estado de tutoría)
interface SessionCardProps {
session: {
tutor_name: string
ramo: string
fecha_hora: string
modalidad: 'presencial' | 'online'
ubicacion: string
precio_total: number
estado: 'pendiente' | 'confirmada' | 'completada' | 'cancelada'
}
}
export function SessionCard({ session }: SessionCardProps) {
const statusConfig = {
pendiente: {
badge: '🟡 PENDIENTE',
bgColor: 'bg-yellow-50',
borderColor: 'border-yellow-200'
},
confirmada: {
badge: '🟢 CONFIRMADA',
bgColor: 'bg-green-50',
borderColor: 'border-green-200'
},
completada: {
badge: '✅ COMPLETADA',
bgColor: 'bg-gray-50',
borderColor: 'border-gray-200'
},
cancelada: {
badge: '❌ CANCELADA',
bgColor: 'bg-red-50',
borderColor: 'border-red-200'
}
}
const config = statusConfig[session.estado]
return (
<div className={`
${config.bgColor}
border ${config.borderColor}
rounded-lg
p-6
`}>
<div className="flex items-start justify-between mb-4">
<Badge variant="secondary">{config.badge}</Badge>
<span className="text-lg font-bold">
${session.precio_total.toLocaleString()}
</span>
</div>
<h3 className="font-semibold text-gray-900 mb-2">
{session.ramo} con {session.tutor_name}
</h3>
<div className="space-y-2 text-sm text-gray-600">
<p>📅 {new Date(session.fecha_hora).toLocaleString('es-CL')}</p>
<p>
{session.modalidad === 'presencial' ? '📍' : '🌐'}
{' '}
{session.ubicacion}
</p>
</div>
{/* Actions basadas en estado */}
{session.estado === 'pendiente' && (
<div className="flex gap-2 mt-4">
<Button variant="outline" size="sm">Ver detalles</Button>
<Button variant="destructive" size="sm">Cancelar</Button>
</div>
)}
</div>
)
}📱 Responsive Design
Breakpoints
/* Mobile First */
--screen-sm: 640px; /* Tablet portrait */
--screen-md: 768px; /* Tablet landscape */
--screen-lg: 1024px; /* Desktop */
--screen-xl: 1280px; /* Large desktop */Grid System
// Landing Grid
<div className="
grid
grid-cols-1 /* Mobile: 1 columna */
md:grid-cols-2 /* Tablet: 2 columnas */
lg:grid-cols-3 /* Desktop: 3 columnas */
gap-6
">
{tutores.map(tutor => <TutorCard key={tutor.id} tutor={tutor} />)}
</div>
// Sidebar Layout (Búsqueda)
<div className="
grid
grid-cols-1 /* Mobile: stack */
lg:grid-cols-4 /* Desktop: sidebar + content */
gap-8
">
<aside className="lg:col-span-1">
<Filters />
</aside>
<main className="lg:col-span-3">
<Results />
</main>
</div>Mobile Patterns
// Mobile: Drawer para filtros
// Desktop: Sidebar fijo
{isMobile ? (
<Sheet>
<SheetTrigger asChild>
<Button>Filtros</Button>
</SheetTrigger>
<SheetContent side="left">
<Filters />
</SheetContent>
</Sheet>
) : (
<aside className="sticky top-20">
<Filters />
</aside>
)}
// Mobile: Bottom Navigation
<nav className="
lg:hidden
fixed bottom-0 inset-x-0
bg-white border-t
flex justify-around
py-2
">
<NavItem icon="🏠" label="Inicio" />
<NavItem icon="🔍" label="Buscar" />
<NavItem icon="💼" label="Ofertas" />
<NavItem icon="👤" label="Perfil" />
</nav>⚡ Interacciones & Animaciones
Transiciones
/* Hover states */
transition: all 200ms ease-in-out;
/* Color changes */
transition-property: background-color, border-color;
transition-duration: 200ms;
/* Transform (scale, translate) */
transition: transform 150ms ease-out;Hover Effects
// Cards
<div className="
hover:shadow-lg
hover:-translate-y-1
transition-all duration-200
">
// Buttons
<button className="
hover:scale-105
active:scale-95
transition-transform
">
// Images
<img className="
hover:opacity-80
transition-opacity
">Loading States
// Skeleton Loader
<div className="animate-pulse space-y-4">
<div className="h-4 bg-gray-200 rounded w-3/4"></div>
<div className="h-4 bg-gray-200 rounded"></div>
<div className="h-4 bg-gray-200 rounded w-5/6"></div>
</div>
// Spinner
<div className="
animate-spin
rounded-full
h-8 w-8
border-b-2 border-uc-blue
"></div>♿ Accesibilidad
Contraste de Colores
- WCAG AA: Mínimo 4.5:1 para texto normal
- WCAG AAA: Mínimo 7:1 para texto normal
// ✅ Buen contraste
<p className="text-gray-900 bg-white"> {/* 21:1 */}
<p className="text-white bg-uc-blue"> {/* 12:1 */}
// ❌ Mal contraste
<p className="text-gray-400 bg-white"> {/* 2.5:1 - ❌ */}Focus States
// Todos los elementos interactivos
<button className="
focus:outline-none
focus:ring-2
focus:ring-uc-blue
focus:ring-offset-2
">Semantic HTML
// ✅ Usar elementos semánticos
<nav>
<main>
<article>
<section>
<aside>
// ✅ ARIA labels cuando sea necesario
<button aria-label="Cerrar modal">
<X className="h-4 w-4" />
</button>
// ✅ Alt text en imágenes
<img src="..." alt="Foto de perfil de María González" />Keyboard Navigation
// Tab order lógico
tabIndex={0} // Elemento focusable
tabIndex={-1} // Elemento no focusable pero accesible programáticamente
// Atajos de teclado
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleClick()
}
}}🎯 Iconografía
Icons Library
Usar Lucide React (ya instalado con shadcn/ui):
import {
Search,
Calendar,
MapPin,
Star,
User,
Bell,
CheckCircle,
XCircle,
Clock
} from 'lucide-react'
// Uso
<Search className="h-5 w-5 text-gray-400" />
<Star className="h-4 w-4 text-yellow-500 fill-current" />Tamaños Consistentes
// Small (16px)
<Icon className="h-4 w-4" />
// Medium (20px)
<Icon className="h-5 w-5" />
// Large (24px)
<Icon className="h-6 w-6" />
// Extra Large (32px)
<Icon className="h-8 w-8" />Emojis como Complemento
// Estados de tutoría
🟡 Pendiente
🟢 Confirmada
✅ Completada
❌ Cancelada
// Modalidad
📍 Presencial
🌐 Online
// Otros
⭐ Rating
💰 Precio
📅 Fecha
🎓 Ramo📐 Layout Patterns
Container
<div className="
container
mx-auto
px-4 sm:px-6 lg:px-8
max-w-7xl
">
{/* Content */}
</div>Section Spacing
<section className="py-16 lg:py-24">
{/* Content */}
</section>Sticky Navigation
<nav className="
sticky top-0 z-50
bg-white border-b
backdrop-blur-sm bg-white/95
">
{/* Nav content */}
</nav>🧪 Testing Checklist
Visual Testing
- Todas las páginas se ven bien en 375px (iPhone)
- Todas las páginas se ven bien en 768px (Tablet)
- Todas las páginas se ven bien en 1440px (Desktop)
- Todos los estados hover funcionan
- Todos los focus states son visibles
- Contraste WCAG AA cumplido
Functional Testing
- Todos los botones hacen algo
- Todos los links van a algún lado
- Todos los forms se pueden enviar
- Todos los modals se pueden cerrar
- Navigation keyboard funciona
✅ Component Checklist
Antes de crear un componente nuevo, preguntate:
- ¿Ya existe? - Revisa shadcn/ui primero
- ¿Es reutilizable? - Si solo se usa 1 vez, no lo components
- ¿Tiene props claras? - Define TypeScript interface
- ¿Es accesible? - Focus, ARIA, semantic HTML
- ¿Es responsive? - Funciona en mobile y desktop
🎨 Brand Assets
Logo
// Logo completo (desktop)
<div className="flex items-center gap-2">
<span className="text-2xl font-bold text-uc-blue">
TutorConnect
</span>
<span className="text-sm font-medium text-uc-gold">
UC
</span>
</div>
// Logo reducido (mobile)
<span className="text-xl font-bold text-uc-blue">TC</span>Favicon
- Color: UC Blue (#002D5E)
- Icon: “T” + “C” monogram
- Sizes: 16x16, 32x32, 180x180 (Apple), 192x192 (Android)
📚 Resources
Design Tools
- Figma: [TutorConnect UC Mockups] (crear si es necesario)
- shadcn/ui: https://ui.shadcn.com/
- Tailwind: https://tailwindcss.com/docs
Inspiration
- Airbnb (marketplace)
- Calendly (booking)
- LinkedIn (profiles)
- Notion (clean UI)
Este design system es tu única fuente de verdad. Síguelo religiosamente durante el hackathon para mantener consistencia visual. 🎨