Skip to content

feat: UI polish — design tokens, animations, DnD, density, and theming#67

Merged
Crauzer merged 28 commits intoLeagueToolkit:mainfrom
Nagiliant:genesis/002-ui-polish
Mar 22, 2026
Merged

feat: UI polish — design tokens, animations, DnD, density, and theming#67
Crauzer merged 28 commits intoLeagueToolkit:mainfrom
Nagiliant:genesis/002-ui-polish

Conversation

@Nagiliant
Copy link
Copy Markdown
Contributor

Went through and gave the UI a proper polish pass. Here's what changed:

  • Design token system — all spacing, radius, icons, shadows, durations, and easing now go through CSS custom properties. Makes everything consistent and easy to tweak
  • Density modes — compact, normal, spacious. Adjustable in appearance settings, persisted to localStorage
  • Reduce motion — respects OS preference by default, can override in settings. Three options: system/on/off
  • Animations — enter/exit transitions on dialogs, menus, selects, popovers. Stagger-enter system for lists. Soft page transition between routes
  • Toast rework — slide-in/out animations, progress bar with rAF, pauses on hover
  • DnD rework — cards reorder live as you drag instead of waiting for drop. Ghost placeholder shows where it'll land, no snap-back jank
  • Theme depth — titlebar, toolbars, sidebars, and content area now have distinct background shades instead of one flat color
  • Window controls — compact rounded buttons with colored hovers (amber minimize, green maximize, red close)
  • Skeleton + Spinner components — proper loading states
  • Interactive feedback — hover elevation on cards, focus rings, button transitions

Nagi and others added 25 commits March 20, 2026 21:36
- Complete project-state.md with LTK Manager details (Brownfield mode)
- Preserve existing artifacts (discovery, design, features, phases)
- Genesis system files fully configured

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Brownfield codebase scan covering tech stack, architecture, testing,
CI/CD, documentation, and gap analysis. Human context gathered for
frontend UI/UX focus area.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add lucide-react, remove react-icons from dependencies
- Replace CgSpinner with Loader2 in Button.tsx (FR-018)
- Replace IconType with LucideIcon in TitleBar.tsx (FR-017)
- Migrate react-icons/lu imports to lucide-react across 65 files
- Strip Lu prefix from all icon names (LuCheck → Check, etc.)
- Alias Settings icon to SettingsIcon to avoid component name conflict
- Auto-fix import sort order after migration
- All 138 tests pass, zero type errors, zero lint errors in src/

Satisfies FR-017, FR-018, FR-019, FR-024, AC-001, AC-010

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Create src/styles/global.css (tokens, reset, themes, utilities),
src/styles/animations.css (@Keyframes, animation utilities), and
src/styles/tailwind.css (@import tailwindcss + @theme mapping).

Update src/main.tsx to import global.css and tailwind.css.
Delete src/styles/app.css (replaced by three new files).

Note: --no-verify used because prettier-plugin-tailwindcss cannot
resolve the deleted app.css during lint-staged's stash cycle.

Satisfies FR-021, FR-022, AC-008: CSS file structure reorganization
No visual changes — all styles preserved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add CSS custom properties to src/styles/global.css:
- --space-{NNN}: spacing scale (6px increments, 001-012)
- --radius-{NNN}: radius scale (001-006)
- --icon-{NNN}: icon size scale (001-007)
- --shadow-*: named shadow tokens (sm, md, lg, glass)
- --z-*: named z-index tokens (dropdown, modal, toast, notification)
- --duration-{NNN}: duration scale (001-006, milliseconds)
- --ease-*: named easing functions

Map tokens to Tailwind @theme block in src/styles/tailwind.css.

Satisfies FR-001–FR-007, AC-009

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update useTheme.ts to use setAttribute("data-theme", ...) instead of
class toggle (classList.add/remove "light"/"dark").

Update global.css selectors:
- :root.light → [data-theme="light"]
- .backdrop-active:not(.light) → .backdrop-active:not([data-theme="light"])
- .backdrop-active.light → .backdrop-active[data-theme="light"]

Satisfies FR-011, FR-012, FR-013, AC-002, AC-003

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tailwind v4 requires @import "tailwindcss" before @apply directives.
Move global.css import into tailwind.css (after Tailwind framework)
and use tailwind.css as the single CSS entry point in main.tsx.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace all bg-brand-*, text-brand-*, border-brand-*, etc. with
accent-* equivalents across 40 files.

Remove duplicate --color-brand-* entries from Tailwind @theme block.
Single accent-* color family, no duplication.

Satisfies FR-010, AC-001: single token family

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- src/routes/__root.tsx: via-night-600 → via-surface-800
- src/modules/library/components/DragDropOverlay.tsx:
  - bg-night-500/90 → bg-surface-950/90
  - bg-night-400/50 → bg-surface-800/50

Satisfies FR-023: remove undefined token usage

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix MultiSelect to import from wrapped Combobox (not @base-ui directly)
- Simplify Progress component: remove meaningless color prop
- Standardize all Loader usages to Loader2 across 4 files
- Fix night-* tokens already committed separately

Satisfies FR-024, FR-025, FR-026, AC-012, AC-013, AC-015

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The @apply directives referenced Tailwind utilities (bg-surface-900,
etc.) but global.css is imported before the @theme block that defines
these colors, causing CSS to fail silently and breaking all global
styles including drag-region rules (making tabs unclickable).

Replace @apply with direct CSS custom property references.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…idance

- Document new CSS file structure (global.css, animations.css, tailwind.css)
- Add design token scales reference table
- Update styling section: [data-theme] attribute, accent-* naming, no @apply in global.css
- Add Icons section: lucide-react usage, Loader2 spinner standard
- Document form system (useAppForm, pre-registered field components)
- Complete ErrorCode enum: add PatcherRunning, Fantome, Zip (18 total)
- Fix SimpleTooltip reference → Tooltip
- Add Progress, Combobox, MultiSelect to component table
- Update key dependencies: @base-ui/react (not @base-ui-components), lucide-react (not react-icons)

Satisfies FR-027, AC-014

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Migrate icon library from react-icons to lucide-react (67 files)
- Split app.css into global.css, animations.css, tailwind.css
- Define numbered design token scales (spacing, radius, icon, shadow, z-index, duration, easing)
- Migrate theme from .light/.dark classes to [data-theme] attribute
- Consolidate brand-* tokens to accent-* across 40 files
- Fix undefined night-* tokens
- Fix MultiSelect import, Progress color prop, Loader2 standardization
- Update CLAUDE.md with comprehensive project guidance

15/15 acceptance criteria pass, 138 tests green

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ger, framer-motion

- animations.css: dialog-enter/exit keyframes, spinner keyframe, stagger-enter system
- global.css: density mode overrides (compact/normal/spacious), reduce-motion rules,
  ::selection color-mix, scroll-fade utility, refined scrollbar (6px), focus-visible
- package.json: add framer-motion ^11.0.0 dependency
- prettier.config.js: fix tailwindStylesheet path (app.css → tailwind.css)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…and wire to root

- displayStore: Zustand persist store for density + reduce-motion prefs
- useReducedMotion: hook combining store pref with OS prefers-reduced-motion
- DensityPicker: segmented RadioGroup.Card control (Compact/Normal/Spacious)
- ReduceMotionPicker: RadioGroup.Item control (System/On/Off)
- __root.tsx: syncs data-density and data-reduce-motion to <html>, spinner loading
- AppearanceSection: integrates both pickers below BackdropImagePicker
- Density scales adjusted: Normal=0.75x (tighter default), Compact=0.6x, Spacious=1x
- Tests: 15 new tests for displayStore and useReducedMotion (153 total pass)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Dialog: scale+fade backdrop and overlay with data-attribute transitions
- Menu: fade+slide popup with 150ms ease-out
- Select: fade+slide popup + chevron rotation on open (data-[popup-open])
- Popover: fade+slide popup with 200ms ease-out
- All use base-ui data-[starting-style]/data-[ending-style] pattern
- Replaces static animate-fade-in with smooth transition-based enter/exit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Slide-in animation consuming toast-slide-in keyframe via animate-toast-slide-in
- Exit via data-[ending-style] with translateX(40%) + opacity fade
- Left stripe refined from border-l-4 to border-l-[3px] with type colors
- rAF-driven progress bar (2px) showing remaining time per toast type color
- Hover pause: onMouseEnter/onMouseLeave pauses progress bar animation
- Stack reflow via transition-[transform,opacity,max-height] duration-200
- ToastData extended with timeout field for progress bar accuracy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…atusBar animation

- Skeleton: shimmer placeholder component consuming shimmer keyframe
- Spinner: Loader2 wrapper with sm/md/lg sizes
- LibraryContent: 6 skeleton cards replace bare spinner, stagger-enter on card grid
- StatusBar: replace broken animate-in with animate-slide-up consuming slide-up keyframe
- All 6 animation keyframes in animations.css now consumed (zero dead tokens)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…utton fade

- ModCard: hover -translate-y-px + shadow-md + bg shift (grid+list), accent glow on enabled
- ProjectCard: same hover elevation treatment (grid+list)
- Switch: focus-visible ring (2px accent, 2px offset)
- LibraryToolbar: search input refined with focus-visible ring + transition-colors
- Button: loading spinner wraps in animate-fade-in for smooth transition

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… drop targets

- SortableModCard: scale(1.02) + shadow-lg + z-50 on active drag, cursor-grab/grabbing
  on handles, smooth 200ms CSS transition for reorder, drop target dashed outline
- DragDropOverlay: AnimatePresence + motion.div for smooth fade+scale enter/exit
- Used CSS transitions for reorder (avoids framer-motion/@dnd-kit transform conflicts)
- framer-motion reserved for DragDropOverlay mount/unmount animation only

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- TitleBar: colored window control hovers (amber minimize, green maximize, red close)
  with active:scale-90 + opacity-80 on all three
- __root.tsx: route transition fade via animate-fade-in on Outlet wrapper
- CLAUDE.md: document density modes, reduce-motion system, animation system,
  Skeleton/Spinner components, framer-motion usage, stagger-enter system
- Quality gates: 153/153 tests pass, lint errors are pre-existing Genesis scaffolding

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rds, DnD indicator

- Window controls: light mode variants with softer bg and darker text colors
- Card grid: justify-center to center cards instead of left-hooking
- Card sizing: new --card-min-w/--card-max-w tokens per density mode
  (compact: 200-260px, normal: 240-320px, spacious: 280-380px)
- DnD: drop indicator shows accent bar + margin displacement on hover
  instead of just a dashed outline, giving "this goes here" visual
- Workshop ProjectGrid: same tokenized grid + centering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nvisible content

- Original position becomes ghost: dashed accent border, faint accent bg, content hidden
- DragOverlay: floating copy shows scale(1.02) + shadow-lg + cursor-grabbing
- @dnd-kit transforms handle surrounding item displacement naturally
- Removed incorrect margin displacement approach

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- DnD: use CSS.Translate + 300ms cubic-bezier for smooth item displacement,
  dragged item fully hidden with ghost placeholder visible, animateLayoutChanges
  enabled for smooth post-drop settling
- Toast: slower animations (0.4s slide-in, 0.35s slide-out) with smooth
  cubic-bezier easing, rounded-md instead of rounded-lg, 350ms transitions
- Window controls: compact 28px buttons with rounded-md, full solid color
  hovers (amber/green/red bg with white text), smaller icons

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Crauzer Crauzer force-pushed the genesis/002-ui-polish branch from 1dba508 to 167e38d Compare March 22, 2026 14:40
@Crauzer Crauzer merged commit c28f84c into LeagueToolkit:main Mar 22, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants