* chore: run Tailwind v4 upgrade tool (Phase 1) - Upgraded tailwindcss v3 → v4.2.1, postcss plugin to @tailwindcss/postcss - Deleted tailwind.config.js, migrated theme to CSS @theme block in index.css - Replaced @tailwind directives with @import 'tailwindcss' - Added @custom-variant dark, @utility blocks for custom utilities - Updated class names across 128 files (shadow-sm → shadow-xs, etc.) - Removed autoprefixer (built into v4) - Added migration plan doc Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: switch from @tailwindcss/postcss to @tailwindcss/vite (Phase 2) - Replaced @tailwindcss/postcss with @tailwindcss/vite plugin - Deleted postcss.config.js (no longer needed) - Tailwind now runs as a native Vite plugin for faster HMR Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: convert to OKLCH colors, move keyframes into @theme (Phase 3-4) - Replaced all HSL color indirection with direct OKLCH values in @theme - Moved all keyframes inside @theme block (v4 pattern) - Eliminated hsl(var(--x)) double-indirection across 17 component files - Replaced hsl() inline styles with var(--color-*) theme references - Cleaned up redundant rdp-* utility blocks - Fixed @custom-variant dark syntax to use :where() - Added sidebar/glass/shadow vars as OKLCH in :root Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
634 lines
21 KiB
Markdown
634 lines
21 KiB
Markdown
# ResolutionFlow — Tailwind v4 Migration & Feature Guide
|
||
**Claude Code Handoff Document · Pre-Investor Pitch Sprint**
|
||
|
||
---
|
||
|
||
## Purpose
|
||
|
||
This document gives Claude Code everything needed to:
|
||
1. Execute the mechanical Tailwind v3 → v4 upgrade
|
||
2. Know which new v4 features to use going forward so the ResolutionFlow UI looks and feels premium for the investor pitch demo
|
||
|
||
## Branch
|
||
|
||
This migration touches nearly every file in the frontend. **Always work on a dedicated branch:**
|
||
|
||
```bash
|
||
git checkout -b feat/tailwind-v4-upgrade
|
||
```
|
||
|
||
Do not merge to `main` until all phases are complete and the full visual QA pass is done.
|
||
|
||
---
|
||
|
||
## Stack Context
|
||
|
||
| | |
|
||
|---|---|
|
||
| Frontend | React 19.2 + Vite 7 + TypeScript 5.9 |
|
||
| Current Tailwind | v3.4.19 |
|
||
| Component Library | shadcn/ui (target: new-york style post-upgrade) |
|
||
| Canvas Editor | React Flow (@xyflow/react) |
|
||
| Brand Color | Cyan — `#06b6d4 → #22d3ee` (hsl 187 72% 43%) |
|
||
| Background | `hsl(228 12% 7%)` — dark theme only, no light mode |
|
||
| Body Font | IBM Plex Sans |
|
||
| Heading Font | Bricolage Grotesque |
|
||
| Label/Mono Font | JetBrains Mono |
|
||
| Brand Gradient | `linear-gradient(135deg, #06b6d4 0%, #22d3ee 100%)` |
|
||
| Animation Library | tailwindcss-animate → **replace with tw-animate-css** |
|
||
| Tailwind Plugins | None |
|
||
|
||
---
|
||
|
||
---
|
||
|
||
# PART 1: Mechanical Migration
|
||
|
||
Execute phases in order. Verify the app builds and renders correctly after each phase before proceeding.
|
||
|
||
---
|
||
|
||
## Phase 1 — Update Dependencies
|
||
|
||
Run the official Tailwind upgrade tool from the `/frontend` directory. It handles the majority of migration automatically:
|
||
|
||
```bash
|
||
# Run from /frontend
|
||
npx @tailwindcss/upgrade@latest
|
||
```
|
||
|
||
This tool will:
|
||
- Update `tailwindcss` to v4
|
||
- Install `@tailwindcss/vite` (replaces the PostCSS plugin)
|
||
- Migrate `tailwind.config.js` → CSS `@theme` block
|
||
- Update `@tailwind` directives to `@import`
|
||
- Handle renamed utility classes in template files
|
||
|
||
After running, verify `package.json` reflects:
|
||
|
||
```json
|
||
// devDependencies should now include:
|
||
"tailwindcss": "^4.x.x",
|
||
"@tailwindcss/vite": "^4.x.x"
|
||
|
||
// These are no longer needed and can be removed:
|
||
// "autoprefixer" (bundled in v4 via Lightning CSS)
|
||
// "postcss" (unless used for something other than Tailwind)
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 2 — Update Vite Config
|
||
|
||
Replace the PostCSS-based Tailwind setup with the first-party Vite plugin:
|
||
|
||
```ts
|
||
// vite.config.ts — BEFORE
|
||
import { defineConfig } from 'vite'
|
||
import react from '@vitejs/plugin-react'
|
||
|
||
export default defineConfig({
|
||
plugins: [react()],
|
||
})
|
||
|
||
// vite.config.ts — AFTER
|
||
import { defineConfig } from 'vite'
|
||
import react from '@vitejs/plugin-react'
|
||
import tailwindcss from '@tailwindcss/vite'
|
||
|
||
export default defineConfig({
|
||
plugins: [react(), tailwindcss()],
|
||
})
|
||
```
|
||
|
||
Remove `postcss.config.js` if it exists and was only used for Tailwind. Lightning CSS is now bundled inside Tailwind v4.
|
||
|
||
---
|
||
|
||
## Phase 3 — Migrate CSS Entry Point
|
||
|
||
Update `index.css`:
|
||
|
||
```css
|
||
/* BEFORE — v3 directives */
|
||
@tailwind base;
|
||
@tailwind components;
|
||
@tailwind utilities;
|
||
|
||
/* AFTER — v4 single import */
|
||
@import "tailwindcss";
|
||
@import "tw-animate-css";
|
||
|
||
/* ResolutionFlow is dark-only. Replace darkMode: ["class"] from tailwind.config.js
|
||
with this custom variant declaration. This is the v4 equivalent. */
|
||
@custom-variant dark (&:where(.dark, .dark *));
|
||
|
||
/* React Flow styles must now live in CSS, not imported in App.tsx */
|
||
@layer base {
|
||
@import "@xyflow/react/dist/style.css";
|
||
}
|
||
```
|
||
|
||
> **Important:** Remove `import '@xyflow/react/dist/style.css'` from `App.tsx` after adding it here.
|
||
> **Important:** Remove `darkMode: ["class"]` from `tailwind.config.js` — it is now handled by `@custom-variant dark` above. Since ResolutionFlow is dark-only with no light mode toggle, verify that the `.dark` class is still present on the `<html>` element in `index.html`.
|
||
|
||
---
|
||
|
||
## Phase 4 — Migrate Theme Configuration
|
||
|
||
The upgrade tool migrates `tailwind.config.js` automatically, but verify the ResolutionFlow design tokens are correctly expressed. The `@theme` block lives in `index.css` after the imports.
|
||
|
||
### OKLCH Color Values
|
||
|
||
Claude Code flagged that the cyan range benefits from OKLCH for better gradient interpolation. Use these OKLCH equivalents for brand colors inside `@theme` — they render more accurately on wide-gamut displays (MacBooks, modern monitors used in pitch settings):
|
||
|
||
| Hex | OKLCH |
|
||
|---|---|
|
||
| `#06b6d4` (brand-from) | `oklch(72% 0.15 195)` |
|
||
| `#22d3ee` (brand-to) | `oklch(82% 0.13 195)` |
|
||
| `#0891b2` (brand-dark) | `oklch(62% 0.14 195)` |
|
||
|
||
### Full `@theme` Block
|
||
|
||
```css
|
||
@import "tailwindcss";
|
||
@import "tw-animate-css";
|
||
|
||
@custom-variant dark (&:where(.dark, .dark *));
|
||
|
||
@theme {
|
||
/* ResolutionFlow Brand — Cyan system (OKLCH for wide-gamut accuracy) */
|
||
--color-brand-from: oklch(72% 0.15 195); /* #06b6d4 */
|
||
--color-brand-to: oklch(82% 0.13 195); /* #22d3ee */
|
||
--color-brand-dark: oklch(62% 0.14 195); /* #0891b2 */
|
||
|
||
/* Dark surface palette */
|
||
--color-dark-DEFAULT: #101114;
|
||
--color-dark-card: #14161a;
|
||
--color-dark-surface: #14161a;
|
||
|
||
/* Text palette */
|
||
--color-text-primary: #f8fafc;
|
||
--color-text-secondary: #8891a0;
|
||
--color-text-muted: #5a6170;
|
||
|
||
/* Typography */
|
||
--font-sans: 'IBM Plex Sans', system-ui, -apple-system, sans-serif;
|
||
--font-heading: 'Bricolage Grotesque', system-ui, sans-serif;
|
||
--font-label: 'JetBrains Mono', monospace;
|
||
|
||
/* Border radius */
|
||
--radius-lg: 0.75rem;
|
||
--radius-md: calc(0.75rem - 2px);
|
||
--radius-sm: calc(0.75rem - 4px);
|
||
|
||
/* Keyframe animations — move ALL @keyframes from index.css into @theme */
|
||
--animate-fade-in: fade-in 200ms ease-out;
|
||
--animate-fade-in-up: fade-in-up 200ms ease-out;
|
||
--animate-slide-in-left: slide-in-from-left 200ms ease-out;
|
||
--animate-slide-in-bottom: slide-in-from-bottom 200ms ease-out;
|
||
--animate-scale-in: scale-in 150ms ease-out;
|
||
--animate-breathe-glow: breatheGlow 3s ease-in-out infinite alternate;
|
||
--animate-bell-wobble: bellWobble 0.5s ease-in-out;
|
||
|
||
@keyframes fade-in {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
@keyframes fade-in-up {
|
||
from { opacity: 0; transform: translateY(4px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
@keyframes slide-in-from-left {
|
||
from { transform: translateX(-100%); }
|
||
to { transform: translateX(0); }
|
||
}
|
||
@keyframes slide-in-from-bottom {
|
||
from { opacity: 0; transform: translateY(16px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
@keyframes scale-in {
|
||
from { opacity: 0; transform: scale(0.95); }
|
||
to { opacity: 1; transform: scale(1); }
|
||
}
|
||
@keyframes breatheGlow {
|
||
from { box-shadow: 0 8px 32px rgba(0,0,0,0.3), 0 0 20px oklch(72% 0.15 195 / 0.04); }
|
||
to { box-shadow: 0 8px 32px rgba(0,0,0,0.3), 0 0 30px oklch(72% 0.15 195 / 0.12); }
|
||
}
|
||
@keyframes bellWobble {
|
||
0% { transform: rotate(0deg); }
|
||
20% { transform: rotate(8deg); }
|
||
40% { transform: rotate(-6deg); }
|
||
60% { transform: rotate(4deg); }
|
||
80% { transform: rotate(-2deg); }
|
||
100% { transform: rotate(0deg); }
|
||
}
|
||
}
|
||
```
|
||
|
||
> **Important:** Remove the loose `@keyframes` blocks from `index.css` after moving them into `@theme`. They should not exist in both places.
|
||
|
||
### shadcn/ui CSS Variable Bridge
|
||
|
||
Keep the existing `:root` block as-is — shadcn still uses HSL format for its variables:
|
||
|
||
```css
|
||
/* shadcn/ui CSS variable bridge — keep as-is from existing index.css */
|
||
@layer base {
|
||
:root {
|
||
--background: 228 12% 7%;
|
||
--foreground: 210 40% 98%;
|
||
--card: 220 10% 10%;
|
||
--card-foreground: 210 40% 98%;
|
||
--popover: 220 10% 10%;
|
||
--popover-foreground: 210 40% 98%;
|
||
--primary: 187 72% 43%;
|
||
--primary-foreground: 228 12% 7%;
|
||
--secondary: 220 8% 14%;
|
||
--secondary-foreground: 210 40% 98%;
|
||
--muted: 220 8% 14%;
|
||
--muted-foreground: 215 10% 58%;
|
||
--accent: 220 8% 14%;
|
||
--accent-foreground: 210 40% 98%;
|
||
--destructive: 350 81% 55%;
|
||
--destructive-foreground: 210 40% 98%;
|
||
--border: 220 8% 14%;
|
||
--input: 220 8% 14%;
|
||
--ring: 187 72% 43%;
|
||
--radius: 0.75rem;
|
||
/* ... rest of existing tokens ... */
|
||
}
|
||
}
|
||
|
||
---
|
||
|
||
## Phase 5 — Replace Animation Library
|
||
|
||
```bash
|
||
# Remove old plugin
|
||
npm uninstall tailwindcss-animate
|
||
|
||
# Install replacement
|
||
npm install -D tw-animate-css
|
||
```
|
||
|
||
Remove any `@plugin 'tailwindcss-animate'` references from CSS files. The `@import "tw-animate-css"` added in Phase 3 replaces it.
|
||
|
||
---
|
||
|
||
## Phase 7 — Consolidate Hardcoded Inline Colors
|
||
|
||
Claude Code identified **128 instances of `style={{}}` inline color values across 44 files**, including atmosphere orbs in `AppLayout.tsx` using hardcoded `rgba(6,182,212,...)`. Now that brand colors are proper CSS variables in `@theme`, replace all hardcoded cyan/brand references with variables.
|
||
|
||
**Search and replace targets:**
|
||
|
||
```ts
|
||
// FIND these hardcoded patterns:
|
||
rgba(6, 182, 212, ...) // brand-from with opacity
|
||
rgba(34, 211, 238, ...) // brand-to with opacity
|
||
#06b6d4 // brand-from hex
|
||
#22d3ee // brand-to hex
|
||
#0891b2 // brand-dark hex
|
||
|
||
// REPLACE with CSS variable equivalents:
|
||
oklch(72% 0.15 195 / 0.XX) // brand-from with opacity (XX = your alpha)
|
||
oklch(82% 0.13 195 / 0.XX) // brand-to with opacity
|
||
var(--color-brand-from) // brand-from solid
|
||
var(--color-brand-to) // brand-to solid
|
||
var(--color-brand-dark) // brand-dark solid
|
||
```
|
||
|
||
**Specifically in `AppLayout.tsx`** — atmosphere orbs should become:
|
||
|
||
```tsx
|
||
// BEFORE
|
||
style={{ background: 'rgba(6, 182, 212, 0.08)' }}
|
||
|
||
// AFTER — references the theme token, respects any future brand color changes
|
||
style={{ background: 'oklch(72% 0.15 195 / 0.08)' }}
|
||
|
||
// Or better yet, move to a CSS utility class entirely:
|
||
// .atmosphere-orb { background: oklch(72% 0.15 195 / 0.08); }
|
||
```
|
||
|
||
> This is the right time to do this cleanup — the theme is already being touched, and it means future brand color changes only require updating `@theme` instead of hunting through 44 files.
|
||
|
||
---
|
||
|
||
## Phase 8 — Reinstall shadcn/ui Components
|
||
|
||
shadcn/ui components have been updated for Tailwind v4 and React 19. Commit any custom component modifications first, then reinstall to get refreshed versions.
|
||
|
||
```bash
|
||
# Re-initialize with v4 defaults
|
||
npx shadcn@latest init
|
||
|
||
# When prompted:
|
||
# Style: new-york (more refined than 'default')
|
||
# Base color: cyan (matches ResolutionFlow brand)
|
||
|
||
# Reinstall actively used components:
|
||
npx shadcn@latest add button card dialog dropdown-menu
|
||
npx shadcn@latest add badge input label select textarea
|
||
npx shadcn@latest add table tabs tooltip separator
|
||
npx shadcn@latest add sheet command popover
|
||
```
|
||
|
||
**What's new in shadcn v4 components:**
|
||
- `forwardRef` removed from all components (React 19 handles ref natively)
|
||
- `data-slot` attributes added for easier CSS targeting
|
||
- HSL colors converted to OKLCH for wider color gamut
|
||
- Dark mode colors revisited for better accessibility
|
||
- `tailwindcss-animate` deprecated in favor of `tw-animate-css`
|
||
|
||
---
|
||
|
||
## Phase 9 — Visual QA Checklist
|
||
|
||
Work through the app after Phases 1–6. These are the most likely regression areas:
|
||
|
||
- [ ] **Borders** — default border color changed from `gray-200` to `currentColor`. Check all card, table, and input borders against the `hsl(var(--border))` token.
|
||
- [ ] **Focus rings** — default ring changed from `3px blue` to `1px currentColor`. Verify form fields and button focus states look intentional.
|
||
- [ ] **Placeholder text** — changed from `gray-400` to `currentColor` at 50% opacity. Check all inputs.
|
||
- [ ] **Button cursors** — now `cursor:default` (browser standard). Add `cursor-pointer` explicitly where desired.
|
||
- [ ] **React Flow canvas** — verify nodes, handles, edges, and controls render correctly with CSS import moved to `@layer base`.
|
||
- [ ] **Animations** — check dialog open/close, sheet slide, dropdown appear animations after the animation library swap.
|
||
- [ ] **Keyframe animations** — verify `breatheGlow` on stat cards, `bellWobble` on notification bell, and all `fade-in-*` utilities still work after moving keyframes into `@theme`.
|
||
- [ ] **Cyan brand gradient** — verify `bg-gradient-brand` still renders correctly. Check it looks at least as good (ideally better) with OKLCH values.
|
||
- [ ] **Atmosphere orbs** — verify `AppLayout.tsx` orbs render correctly after inline style replacement with OKLCH variables.
|
||
- [ ] **Glass morphism** — verify `.glass-card` and `.glass-card-static` backdrop blur still applies on all surfaces.
|
||
- [ ] **JetBrains Mono** — verify label/code elements still use mono font correctly.
|
||
- [ ] **Sonner toasts** — verify custom toast styling (card bg, border, icon colors) still applies.
|
||
- [ ] **Dark variant** — verify `.dark` class on `<html>` is present and the `@custom-variant dark` replacement behaves identically to the old `darkMode: ["class"]` config.
|
||
|
||
---
|
||
|
||
## Commit Strategy
|
||
|
||
```bash
|
||
git checkout -b feat/tailwind-v4-upgrade
|
||
|
||
git commit -m "chore: upgrade Tailwind v3 → v4, update Vite plugin"
|
||
git commit -m "chore: migrate CSS entry point — @import, @custom-variant dark"
|
||
git commit -m "chore: migrate theme to @theme block — OKLCH colors, keyframes"
|
||
git commit -m "chore: swap tailwindcss-animate for tw-animate-css"
|
||
git commit -m "chore: consolidate 128 hardcoded inline colors to CSS variables"
|
||
git commit -m "chore: reinstall shadcn/ui components for v4 (new-york style, cyan)"
|
||
git commit -m "fix: visual QA pass — borders, rings, placeholders, glass, animations"
|
||
git commit -m "feat: apply v4 feature enhancements across components"
|
||
|
||
# When complete and QA passes:
|
||
git checkout main
|
||
git merge feat/tailwind-v4-upgrade
|
||
```
|
||
|
||
---
|
||
|
||
---
|
||
|
||
# PART 2: Tailwind v4 Feature Guide
|
||
|
||
**These are new capabilities available after the upgrade. Apply them proactively when building or modifying components — do not default to v3 patterns when a v4 equivalent is listed here.**
|
||
|
||
---
|
||
|
||
## Feature 1 — Auto-Resizing Textareas (`field-sizing-content`)
|
||
|
||
Apply to every multi-line text input in the app. Engineers typing session notes and documentation should never fight a fixed-height box.
|
||
|
||
**Where to apply:** Session runner documentation field · step notes input · FlowPilot prompt input · any multi-line input in the flow editor
|
||
|
||
```tsx
|
||
// BEFORE — v3, fixed height or JS resize logic
|
||
<textarea
|
||
className="w-full resize-none h-32 rounded-md border p-3"
|
||
/>
|
||
|
||
// AFTER — v4, grows automatically as the engineer types
|
||
<textarea
|
||
className="w-full field-sizing-content min-h-[80px] max-h-[400px]
|
||
rounded-md border border-input bg-background p-3
|
||
text-sm focus-visible:ring-2 focus-visible:ring-ring"
|
||
/>
|
||
```
|
||
|
||
---
|
||
|
||
## Feature 2 — CSS-Native Enter Animations (`@starting-style`)
|
||
|
||
Use for elements that appear in the session runner — step transitions, panel reveals, status banners. No JavaScript animation library needed for these patterns.
|
||
|
||
**Where to apply:** Step cards appearing in session runner · status/alert banners · completion state reveals · FlowPilot suggestion panels
|
||
|
||
```css
|
||
/* index.css — define the utility */
|
||
@utility fade-in-up {
|
||
transition: opacity 300ms ease, transform 300ms ease;
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
|
||
@starting-style {
|
||
opacity: 0;
|
||
transform: translateY(8px);
|
||
}
|
||
}
|
||
|
||
@utility scale-in {
|
||
transition: opacity 150ms ease, transform 150ms ease;
|
||
opacity: 1;
|
||
transform: scale(1);
|
||
|
||
@starting-style {
|
||
opacity: 0;
|
||
transform: scale(0.97);
|
||
}
|
||
}
|
||
```
|
||
|
||
```tsx
|
||
// Component usage — animates in on mount with no JS
|
||
<div className="fade-in-up">
|
||
<StepCard step={currentStep} />
|
||
</div>
|
||
|
||
<div className="scale-in">
|
||
<FlowPilotPanel />
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## Feature 3 — Container Queries (`@container`)
|
||
|
||
Use for components that need to adapt based on where they are rendered — not the viewport. Critical for ResolutionFlow where the same component may appear in a sidebar, modal, or full-width panel.
|
||
|
||
**Where to apply:** StepCard (sidebar vs full-width) · FlowPilot panel (collapsed vs expanded) · documentation preview panel · step library items
|
||
|
||
```tsx
|
||
// Wrap the parent with @container
|
||
<div className="@container w-full">
|
||
<StepCard step={step} />
|
||
</div>
|
||
|
||
// Inside StepCard — responds to its container, not the viewport
|
||
function StepCard({ step }: { step: Step }) {
|
||
return (
|
||
<div className="
|
||
flex flex-col gap-2
|
||
@sm:flex-row @sm:items-center
|
||
@lg:gap-4
|
||
p-4 rounded-lg border border-border bg-card
|
||
">
|
||
<StepIcon type={step.type} />
|
||
<StepContent step={step} />
|
||
<div className="@sm:ml-auto">
|
||
<StepActions step={step} />
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Feature 4 — Enhanced Gradient APIs
|
||
|
||
The cyan brand gradient is ResolutionFlow's primary visual identity. v4 unlocks radial gradients, angle control, and OKLCH interpolation for richer rendering.
|
||
|
||
**Where to apply:** Hero/header sections · card hover states · active step indicators · FlowPilot branding elements · progress indicators
|
||
|
||
```tsx
|
||
// Linear — explicit angle control (v4)
|
||
<div className="bg-linear-135 from-[#06b6d4] to-[#22d3ee]">
|
||
|
||
// Radial — great for glow effects on active/highlighted elements (v4)
|
||
<div className="bg-radial from-[#06b6d4]/20 to-transparent">
|
||
|
||
// Radial with position — spotlight effect (v4)
|
||
<div className="bg-radial-[at_30%_50%] from-[#06b6d4]/15 via-[#22d3ee]/8 to-transparent">
|
||
|
||
// OKLCH interpolation — richer, more accurate gradient transition (v4)
|
||
<div className="bg-linear-to-r from-[#06b6d4] to-[#22d3ee] [color-interpolation-method:oklch]">
|
||
|
||
// Combine with glass card for the premium demo look
|
||
<div className="glass-card-static bg-radial-[at_top_left] from-[#06b6d4]/10 to-transparent">
|
||
```
|
||
|
||
---
|
||
|
||
## Feature 5 — Dynamic Utility Values
|
||
|
||
In v3, non-standard values required bracket notation. In v4 the scale is continuous — use values directly.
|
||
|
||
```tsx
|
||
// v3 — arbitrary brackets for anything off-scale
|
||
<div className="w-[18px] h-[18px] z-[60] grid-cols-[repeat(7,1fr)]">
|
||
|
||
// v4 — direct values work without brackets
|
||
<div className="w-4.5 h-4.5 z-60 grid-cols-7">
|
||
|
||
// Grid columns support any number directly
|
||
<div className="grid grid-cols-7"> // 7-column grid, no config needed
|
||
<div className="grid grid-cols-15"> // 15-column, works out of the box
|
||
```
|
||
|
||
---
|
||
|
||
## Feature 6 — `not-*` Variant
|
||
|
||
Style elements only when they don't match a condition. Useful in the session runner step list.
|
||
|
||
```tsx
|
||
// Bottom border on all steps except the last
|
||
<div className="not-last:border-b border-border pb-4 mb-4">
|
||
<StepCard />
|
||
</div>
|
||
|
||
// Dim inactive steps
|
||
<div className="not-[.active]:opacity-60 not-[.active]:hover:opacity-80 transition-opacity">
|
||
<StepCard />
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## Feature 7 — Theme Tokens as Native CSS Variables
|
||
|
||
After the v4 migration, all `@theme` tokens are exposed as native CSS custom properties. This means you can access ResolutionFlow design tokens in TypeScript — useful for React Flow node styling and Recharts chart colors.
|
||
|
||
```ts
|
||
// Access brand colors in JS/TS — no more hardcoded hex values
|
||
const style = getComputedStyle(document.documentElement)
|
||
const brandColor = style.getPropertyValue('--color-brand-from').trim() // '#06b6d4'
|
||
|
||
// Use directly in React Flow node styles
|
||
const nodeStyles = {
|
||
background: 'var(--color-dark-card)',
|
||
border: '1px solid var(--color-brand-from)',
|
||
boxShadow: '0 0 12px rgba(6, 182, 212, 0.15)',
|
||
}
|
||
|
||
// Use in Recharts chartConfig — no more hsl() wrapper needed
|
||
const chartConfig = {
|
||
sessions: {
|
||
label: 'Sessions',
|
||
color: 'var(--color-brand-from)',
|
||
},
|
||
resolved: {
|
||
label: 'Resolved',
|
||
color: 'var(--color-brand-to)',
|
||
},
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Feature 8 — Color Scheme Utilities
|
||
|
||
Control native browser UI element theming (scrollbars, form controls) to match the dark theme — previously required custom CSS.
|
||
|
||
```tsx
|
||
// Apply to the root html element in index.html or App.tsx
|
||
<html className="scheme-dark">
|
||
|
||
// This makes native browser scrollbars, select dropdowns,
|
||
// date inputs, and form controls render in dark mode automatically.
|
||
// ResolutionFlow is dark-only so this should be applied globally.
|
||
```
|
||
|
||
---
|
||
|
||
## Feature 9 — `inert` Utility
|
||
|
||
Disable interaction on an entire subtree without JavaScript. Useful for locking the flow editor or step list during FlowPilot AI generation.
|
||
|
||
```tsx
|
||
// Disable the step list while FlowPilot is generating
|
||
<div className={isGenerating ? 'inert' : ''}>
|
||
<StepList steps={steps} />
|
||
</div>
|
||
|
||
// The inert attribute disables all pointer events, focus, and
|
||
// accessibility interaction on the entire subtree at once.
|
||
```
|
||
|
||
---
|
||
|
||
## General Rules for v4 Going Forward
|
||
|
||
1. **Use `field-sizing-content` on every `<textarea>`** — no exceptions
|
||
2. **Use `@starting-style` animations** instead of adding/removing CSS classes for enter effects
|
||
3. **Wrap repeated components in `@container`** when they appear in variable-width contexts
|
||
4. **Use `not-last:` instead of custom `:not(:last-child)` selectors** in lists
|
||
5. **Reference `var(--color-brand-from)` and `var(--color-brand-to)`** in JS instead of hardcoded `#06b6d4` or `rgba(6,182,212,...)`
|
||
6. **Use OKLCH for any new color values** — `oklch(72% 0.15 195)` not `#06b6d4`
|
||
7. **All new keyframe animations go inside `@theme`** — not loose in `index.css`
|
||
8. **Do not use `tailwindcss-animate`** — replaced by `tw-animate-css`
|
||
9. **Do not add `@tailwind base/components/utilities` directives** — replaced by `@import "tailwindcss"`
|
||
10. **Do not add `darkMode: ["class"]` to any config** — replaced by `@custom-variant dark`
|
||
11. **Prefer `bg-linear-135` syntax** over `bg-gradient-to-r` for the brand gradient — more explicit and v4-native
|
||
|
||
---
|
||
|
||
*ResolutionFlow · Tailwind v4 Migration Doc · Pre-Investor Pitch Sprint*
|