.claude/skills/tailwind/SKILL.md
Tailwind CSS styling for FTC Metrics with official FIRST colors and component patterns. Use when styling React components, creating responsive layouts, or implementing dark mode.
npx skillsauth add ftc8569/ftcmetrics tailwindInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill provides Tailwind CSS patterns and the FTC branding color palette for the FTC Metrics scouting platform.
Custom colors defined in packages/web/tailwind.config.ts:
colors: {
ftc: {
orange: "#f57e25", // Primary brand - buttons, links, accents
blue: "#0066b3", // Secondary brand - teleop scores, alt actions
dark: "#1a1a2e", // Dark backgrounds
},
}
| Element | Light Mode | Dark Mode |
|---------|------------|-----------|
| Primary button | bg-ftc-orange text-white | Same |
| Secondary button | bg-ftc-blue text-white | Same |
| Accent icon bg | bg-ftc-orange/10 | Same |
| Accent text | text-ftc-orange | Same |
| Positive value | text-green-500 | Same |
| Negative value | text-red-500 | Same |
The project uses prefers-color-scheme media query for automatic dark mode. CSS variables in globals.css:
:root {
--foreground: #171717;
--background: #ffffff;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground: #ededed;
--background: #0a0a0a;
}
}
Always pair light and dark variants:
// Backgrounds
className="bg-white dark:bg-gray-900"
className="bg-gray-50 dark:bg-gray-950"
className="bg-gray-100 dark:bg-gray-800"
// Text
className="text-gray-600 dark:text-gray-400"
className="text-gray-700 dark:text-gray-200"
// Borders
className="border-gray-200 dark:border-gray-800"
className="border-gray-300 dark:border-gray-700"
// Hover states
className="hover:bg-gray-100 dark:hover:bg-gray-800"
Standard Tailwind breakpoints used in the project:
| Breakpoint | Min Width | Usage |
|------------|-----------|-------|
| sm: | 640px | Padding adjustments |
| md: | 768px | 2-3 column grids, nav visibility |
| lg: | 1024px | 4 column grids, larger padding |
// Container with responsive padding
className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"
// Responsive grid
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"
className="grid grid-cols-2 md:grid-cols-4 gap-4"
className="grid gap-6 md:grid-cols-2"
className="grid gap-4 md:grid-cols-3"
// Hide on mobile, show on desktop
className="hidden md:flex"
// Responsive text
className="text-2xl font-bold" // Same across breakpoints (common pattern)
<div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-800 p-6">
{/* Card content */}
</div>
With hover state for clickable cards:
<Link className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-800 p-6 hover:border-ftc-orange dark:hover:border-ftc-orange transition-colors">
<div className="min-h-screen bg-gray-50 dark:bg-gray-950">
<Header />
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{children}
</main>
</div>
<div className="mb-8">
<h1 className="text-2xl font-bold">Page Title</h1>
<p className="text-gray-600 dark:text-gray-400 mt-1">
Description text
</p>
</div>
<button className="px-4 py-2 bg-ftc-orange text-white rounded-lg font-medium hover:opacity-90 transition-opacity disabled:opacity-50">
Button Text
</button>
// Full width variant
<button className="w-full py-4 bg-ftc-orange text-white rounded-xl font-medium hover:opacity-90 transition-opacity disabled:opacity-50 text-lg">
<button className="px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-white rounded-lg font-medium hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
<button className="px-8 py-4 border border-gray-300 dark:border-gray-700 rounded-lg font-semibold text-lg hover:bg-gray-100 dark:hover:bg-gray-900 transition-colors">
<input
className="w-full px-4 py-2 bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-ftc-orange focus:border-transparent"
/>
<select className="w-full px-4 py-3 bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-ftc-orange">
<button
className={`px-4 py-2 rounded-lg font-medium transition-colors ${
isActive
? "bg-ftc-orange text-white"
: "bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700"
}`}
>
<div className="flex gap-2">
<button
className={`flex-1 py-2 rounded-lg font-medium transition-colors ${
selected === "A"
? "bg-red-500 text-white"
: "bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-300"
}`}
>
Option A
</button>
<button
className={`flex-1 py-2 rounded-lg font-medium transition-colors ${
selected === "B"
? "bg-blue-500 text-white"
: "bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-300"
}`}
>
Option B
</button>
</div>
<button
className={`w-12 h-7 rounded-full transition-colors ${
enabled ? "bg-ftc-orange" : "bg-gray-300 dark:bg-gray-600"
}`}
>
<div
className={`w-5 h-5 bg-white rounded-full transition-transform mx-1 ${
enabled ? "translate-x-5" : ""
}`}
/>
</button>
// For feature icons
<div className="w-16 h-16 bg-ftc-orange/10 rounded-2xl flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-ftc-orange" />
</div>
// For smaller action icons
<div className="w-12 h-12 bg-ftc-orange/10 rounded-lg flex items-center justify-center">
<svg className="w-6 h-6 text-ftc-orange" />
</div>
<div className="flex items-center gap-3">
<button className="w-10 h-10 bg-gray-200 dark:bg-gray-700 rounded-lg flex items-center justify-center text-xl font-bold hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors">
-
</button>
<span className="w-8 text-center text-xl font-bold">{count}</span>
<button className="w-10 h-10 bg-ftc-orange text-white rounded-lg flex items-center justify-center text-xl font-bold hover:opacity-90 transition-opacity">
+
</button>
</div>
// Success
<div className="p-4 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg text-green-600 dark:text-green-400">
Success message
</div>
// Error
<div className="p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg text-red-600 dark:text-red-400">
Error message
</div>
<div className="animate-spin rounded-full h-8 w-8 border-2 border-ftc-orange border-t-transparent" />
<div className="h-12 bg-gray-100 dark:bg-gray-800 rounded-lg animate-pulse" />
// Role badges
<span className="px-3 py-1 rounded-full text-sm font-medium bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300">
Admin
</span>
// Status indicators
<span className="px-3 py-1 rounded-full text-xs bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300">
Public
</span>
<div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-800 overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-gray-50 dark:bg-gray-800">
<tr>
<th className="px-4 py-3 text-left text-sm font-medium text-gray-600 dark:text-gray-300">
Column
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 dark:divide-gray-800">
<tr className="hover:bg-gray-50 dark:hover:bg-gray-800/50">
<td className="px-4 py-3 text-sm">Data</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="bg-gradient-to-r from-ftc-orange to-ftc-blue rounded-2xl p-8 text-white text-center">
<h2 className="text-3xl font-bold mb-2">Title</h2>
<p className="text-white/80 text-lg">Subtitle text</p>
</div>
<div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-800 p-4 text-center">
<p className="text-2xl font-bold text-ftc-orange">{value}</p>
<p className="text-sm text-gray-600 dark:text-gray-400">Label</p>
</div>
<div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-800 p-12 text-center">
<svg className="w-16 h-16 mx-auto mb-4 text-gray-300 dark:text-gray-600" />
<h3 className="text-lg font-semibold mb-2">No data</h3>
<p className="text-gray-600 dark:text-gray-400 mb-6">Description</p>
<button className="px-4 py-2 bg-ftc-orange text-white rounded-lg">
Action
</button>
</div>
<Link
href="/previous"
className="text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white flex items-center gap-2 mb-4"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
Back
</Link>
<Link className="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors">
Nav Item
</Link>
<div className="absolute right-0 mt-2 w-56 bg-white dark:bg-gray-900 rounded-lg shadow-lg border border-gray-200 dark:border-gray-800 py-1 z-20">
<div className="px-4 py-2 border-b border-gray-200 dark:border-gray-800">
<p className="font-medium truncate">Title</p>
<p className="text-sm text-gray-500 dark:text-gray-400 truncate">Subtitle</p>
</div>
<button className="block w-full text-left px-4 py-2 text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800">
Menu Item
</button>
</div>
| Element | Classes |
|---------|---------|
| Page title | text-2xl font-bold or text-5xl font-bold tracking-tight (hero) |
| Section title | text-lg font-semibold |
| Card title | font-semibold text-lg |
| Body text | Default or text-sm |
| Label | text-sm font-medium |
| Helper text | text-sm text-gray-500 dark:text-gray-400 |
| Tiny text | text-xs text-gray-500 |
py-8 for main contentmb-8 for page sections, mb-6 for cardsp-6 standard, p-4 for compact, p-8 or p-12 for empty statesgap-4 standard, gap-6 for larger cardsspace-y-4 for form fields, space-y-2 for listsAlways include transitions for interactive elements:
transition-colorstransition-opacitytransition-transformSystem font stack defined in globals.css:
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, sans-serif;
Use font-mono for numeric data displays (scores, statistics).
development
Configure TypeScript in a Bun/npm workspaces monorepo with shared base config, package-specific overrides, path aliases, and cross-package type sharing. Use when setting up tsconfig files, configuring path aliases, resolving module errors, or sharing types between packages.
development
Configure and integrate Soketi WebSocket server with FTC Metrics for real-time updates. Use when setting up WebSocket connections, broadcasting scouting data changes, implementing presence channels for team collaboration, or debugging real-time features.
development
Create, structure, and optimize skills for the FTC Metrics project. Use when creating a new skill, improving an existing skill, or needing guidance on skill design patterns, triggers, frontmatter, and progressive disclosure.
data-ai
Configure and use Prisma 7 ORM with PostgreSQL driver adapters in the FTC Metrics project. Use when setting up database schemas, running migrations, troubleshooting Prisma configuration, or working with the packages/db package.