jw-search / docs /APP_CSS_REDUCTION_PLAN.md
jw-tools's picture
deploy: latest main (lazy-ML cold start, durable launcher, web-image search, scene search) + full-app data refresh
7ea1851 verified
# App.css reduction plan
This document tracks the work to retire the legacy `frontend/src/App.css`
in favour of the redesign's design tokens (`styles/design.css`),
shared utilities (`styles/page-shared.css`, `styles/clip-grid.css`),
and per-page CSS files (`styles/persons-page.css`,
`styles/download-page.css`).
## Where we are now
| Snapshot | Lines | Notes |
|---|---|---|
| Pre-redesign baseline (main) | 6,401 | Single mega-file with mixed concerns. |
| After first orphan sweep (`09c416c`) | 5,892 | Removed 78 classes tied to deleted UI (.tab-bar-*, .results-*, .grid-*, etc.). |
| After deeper sweep (`1c47412`) | 4,695 | 145 more classes (details-panel cluster, frame thumbnails, batch forms, etc.). |
| After persons extraction (`be7f4cd`) | 3,828 | 144 rule blocks moved to `styles/persons-page.css`. |
| After download extraction (`3ef5161`) | 2,183 | 303 rule blocks moved to `styles/download-page.css`. |
| After iterative orphan scrub (`497e72c`) | **2,161** | **Current.** Eight passes of comma-orphan removal until stable. |
Net reduction so far: **6,401 β†’ 2,161 lines (βˆ’66 %)**.
Other CSS files at the same date:
| File | Lines | Purpose |
|---|---|---|
| `App.css` | 2,161 | Mostly legacy, see breakdown below. |
| `styles/design.css` | 342 | Tokens, topbar, layout, buttons, status pills, frame gradients. |
| `styles/clip-grid.css` | 421 | Search clip grid + inline player + Open Subtitles modal. |
| `styles/page-shared.css` | 109 | page-shell, page-head, card-section, settings rows, error banner. |
| `styles/persons-page.css` | 878 | All PersonsPage-only chrome. |
| `styles/download-page.css` | 1,625 | All DownloadPage-only chrome. |
## What's left in App.css
Roughly 83 unique base classes remain, falling into four buckets:
### 1. Legacy SearchPage controls (~28 classes, ~580 lines)
Used only by `SearchPage.jsx`'s in-page Search Mode / Sort By /
Filters strip. The redesign already lifted the search input,
language picker, and method toggle into the topbar; the page-local
controls below it still ride on these legacy class names:
`.search-controls`, `.controls-row`, `.control-group`, `.control-label`,
`.control-select`, `.search-input`, `.filter-toggle-button`,
`.filter-panel`, `.filter-row`, `.filter-group`, `.filter-group-wide`,
`.filter-label`, `.filter-date-inputs`, `.filter-duration-inputs`,
`.filter-input`, `.filter-separator`, `.filter-select`, `.filter-hint`,
`.filter-actions`, `.filter-clear-button`, `.image-drop-overlay`,
`.smart-search-info` (+ children), `.scripture-input` (+ children).
### 2. Legacy SearchPage face / image / scripture / save-person panels (~18 classes, ~350 lines)
Used by the empty-state panels rendered when the corresponding
search method is selected. Most of these moved into
`components/FaceSearchPanel`, `ImageUploadPanel`,
`ScriptureSearchPanel`, `SavePersonBanner` during the panel
extraction, but their CSS still lives in `App.css`:
`.face-drop-zone`, `.face-drop-hint`, `.face-search-controls`,
`.face-search-divider`, `.face-search-hint`, `.face-quick-actions`,
`.drop-indicator`, `.upload-image-button`, `.scripture-search-form`,
`.scripture-search-button`, `.scripture-hint`, `.scripture-colon`,
`.scripture-inputs`, `.save-person-banner`, `.save-person-form`,
`.save-person-input`, `.save-person-confirm`, `.save-person-cancel`,
`.save-person-text`, `.save-person-button`, `.person-select`,
`.empty-state.face-drop-zone.dragging`.
### 3. Truly shared utilities (~5 classes, ~60 lines)
Consumed by more than one page or component:
`.empty-state` (Search/Download/Persons + 3 panel components),
`.error-message` (Search/Download/Persons), `.toast` and `.toast-message`
(DownloadPage Toast + PersonsPage toast renderer). `.app` and
`.main-content` are wrappers used by the mockup-viewer branch in
`App.jsx`.
(`.face-crop-container` was previously listed here but already lives
in `styles/persons-page.css` β€” only PersonsPage references it.)
### 4. Genuinely orphan / dead (~30 classes, ~350 lines)
Rules with no current consumer; survived prior sweeps because their
last selector was paired with a still-active class via comma list.
Includes `.add-person-button`, `.assign-button` and several
`.appearance-thumbnail*` modifiers that were superseded by
persons-page.css equivalents.
## Sweep order for the rest
Each step is its own atomic commit, each verified with a 3-agent QC
panel (completeness + cross-page safety + runtime regression).
### Step 1 β€” Move SearchPage in-page controls into a new `styles/search-page.css`
Bucket #1 above. The SearchPage component is finally under the
600-line cap and its inner JSX is stable, so an extraction now is
low-risk. Expected impact: App.css β‰ˆ **βˆ’320 lines** β†’ ~1,840 (the
controls cluster spans App.css:22–283 plus the scripture sub-cluster
near 1011–1037 plus the small drag-overlay rule near 1484).
### Step 2 β€” Move SearchPage panel-specific styles into the panel components
Bucket #2 above. Each empty-state panel component
(FaceSearchPanel.jsx, ImageUploadPanel.jsx, ScriptureSearchPanel.jsx,
SavePersonBanner.jsx) gains its own `.css` sibling and CSS module
import. Expected impact: β‰ˆ **βˆ’200 lines** β†’ ~1,640 (the face-drop /
save-person / image-upload clusters span roughly App.css:858–1037).
### Step 3 β€” Promote the `.toast`, `.error-message`, `.empty-state` rules into `styles/page-shared.css`
Bucket #3. These are the truly shared utilities. Once they're in
the shared file, App.css can drop them. Expected impact: β‰ˆ **βˆ’60
lines** β†’ ~1,580.
### Step 4 β€” Sweep the remaining orphans
Bucket #4. Confirm with a per-class JSX grep that every selector in
the file has a current consumer before deleting. Expected impact:
β‰ˆ **βˆ’350 lines** β†’ ~1,230.
### Step 5 β€” Audit what remains
Whatever survives Step 4 is genuinely shared between the redesign
and a legacy page that hasn't been refactored yet. Decide for each
remaining rule whether it (a) graduates into design tokens, (b)
stays in App.css as a temporary holding area, or (c) is dead and
removable.
## Ground rules during the sweep
- **Never delete the last selector of a multi-selector list without
also moving its rule body somewhere.** The bug pattern that
reviewer #1 caught on 3ef5161 (orphan trailing-comma silently
extending into the next rule) is real β€” every extraction that
touches a comma-list must move both the relevant selectors AND the
rule body in one operation.
- **Run the iterative orphan-comma sweep after every extraction.**
Sweeping once isn't always enough β€” removing a trailing-comma
orphan can leave the line above it freshly orphaned.
- **Each commit must pass a three-reviewer QC panel** (completeness
+ cross-page safety + runtime regression check) before the next
step starts.
## Final target
`App.css` removed entirely; everything lives in:
- `styles/design.css` β€” tokens + global resets + topbar + buttons
- `styles/clip-grid.css` β€” search results layout
- `styles/page-shared.css` β€” page-head, card-section, error-banner,
toast, empty-state
- `styles/persons-page.css` β€” PersonsPage chrome
- `styles/download-page.css` β€” DownloadPage chrome
- `styles/search-page.css` β€” SearchPage chrome (created in Step 1)
- `components/<Panel>.css` β€” panel-specific styles (created in Step 2)
Estimated final state: **App.css = 0 lines (file deleted)**.
Cumulative deltas across Steps 1-4: β‰ˆ βˆ’930 lines, leaving ~1,230
lines that need a Step 5 audit before the file can be removed
entirely.