Skip to content

Commit 076579b

Browse files
tyler-daneclaude
andauthored
refactor(web): migrate styled-components to Tailwind (#1873)
* docs: design tailwind migration * test(web): characterize theme tokens * refactor(web): migrate shared primitives to tailwind * refactor(web): migrate shared composites to tailwind * refactor(web): migrate event forms to tailwind * refactor(web): migrate planner sidebar to tailwind * refactor(web): migrate calendar grid to tailwind * refactor(web): remove styled theme provider * refactor(web): remove styled components dependency * fix(web): restore role=form on event forms The styled-to-tailwind migration replaced <StyledEventForm role="form"> with a bare <form>, dropping the explicit ARIA role. A <form> without an accessible name exposes no "form" role, so getByRole("form") stopped matching and broke the event-form e2e flows (19 specs). Restore role="form" on both the timed and someday event forms. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs: remove styled-components references from cursorrules Describe Tailwind as the sole styling system and document the hybrid inline-utility + c-* recipe convention. Note that semantic attributes (role, aria-*) must be preserved when restyling. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs: remove styled-components migration design spec Drop the internal design spec so it is not carried into the repo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: cleanup * test: delete temp styled-components tests * refactor(web): remove dead reminder CSS utilities The reminder feature was deleted (#1875); its c-reminder-* utilities and keyframes in index.css had no remaining consumers. Remove 7 utilities and 4 keyframes (~138 lines). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(web): inline one-off layout utilities Replace single-use c-* layout recipes with inline Tailwind utilities, removing the global-CSS indirection for styling used in exactly one place: c-floating-form-container, c-calendar-main-grid, c-calendar-grid-rows, c-calendar-timed-columns, c-week-columns, c-week-grid-track. No visual change; theme tokens and semantic attributes unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(web): inline variant-based someday utilities Convert single-use c-someday-event and c-someday-recurrence-value recipes to inline Tailwind utilities using data-[...]/hover: variants. Keep c-week-edge-zone (its dual data-position gradient variants are a coherent, complex treatment better expressed as a named recipe). No visual change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(web): inline calendar grid layout utilities Push descendant-selector recipes onto their child elements and inline the remaining single-use calendar grid layout: - c-week-day-labels: clamp font sizes moved onto the Text children - c-calendar-grid-row: inlined (its '& > span' rule was dead) - c-calendar-day-times: child height/display moved onto mapped children - c-calendar-now-line: inlined (trivial) - c-calendar-all-day-columns: inlined; pseudo grid-line via before: variant Keep c-calendar-date-column (2 consumers) and c-week-edge-zone (gradient variant set). No visual change; verified with web unit + 50/50 e2e. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs: encode the inline-first c-* decision test in styling rules Document that inline is the default and a c-* recipe is justified only when inline can't express it (third-party descendant selectors, pseudo-elements, keyframe bundles, or genuine reuse). Refresh stale examples. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(web): inline rarely-reused c-* utilities Move single-use (or feature-local) recipes out of index.css to their call sites as inline Tailwind, trading minor duplication for a leaner global stylesheet: c-actions-menu(-item), c-recurrence-row/weekday/interval/caret, c-week-grid-scroller, c-week-edge-zone, c-calendar-date-column. Pseudo-element and data-state styling use arbitrary/data- variants. Kept c-time-picker and c-planner-month-picker as global recipes: they style third-party DOM (react-select/react-datepicker) that can't take Tailwind classes, and the test harness already special-cases them. Verified: web unit (1041) + 50/50 e2e + type-check + lint + build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor: rename 'compass-scroll' to 'c-scroll' * refactor(web): inline c-not-found-back-button utility Single-use button recipe with no descendant selectors; inline at its call site in NotFound.tsx and drop from index.css. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(web): restore timepicker dropdown styling The styled-components migration moved the timepicker overrides into an @Utility (c-time-picker), which Tailwind places in @layer utilities. react-select injects its default styles unlayered at runtime, and unlayered rules beat any cascade layer regardless of specificity — so the dropdown rendered with react-select's defaults. Make .c-time-picker a plain (unlayered) rule so it competes with react-select on specificity again, as the original styled-component did. Verified the menu background now resolves to the themed --time-picker-bg. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style: fix datepicker widgets * docs(web): design event form actions row * fix(web): align event descriptions with actions * fix(web): align event titles with actions * docs(web): design inline event form styles * style: simplify form styles * fix(web): unlayer c-planner-month-picker datepicker recipe Same cascade-layer bug as the timepicker: as an @Utility it landed in @layer utilities and lost to react-datepicker's unlayered defaults. The recipe had worked around this with !important on nearly every rule. Make it a plain unlayered rule (defined after c-date-picker, so it wins on source order) and drop the now-redundant !important hacks. Verified the sidebar selected-day pill renders: ::before background resolves to the accent color and the day background is transparent as intended. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style: adjust datepicker styles * fix(web): restore role=form dropped by form-style simplification Commit 565e166 inlined c-event-form and dropped role="form" from both the timed and someday event forms (the same regression fixed earlier in 59091ce). A bare <form> exposes no ARIA form role without an accessible name, so getByRole("form") stopped matching and 16 event-form e2e specs failed in CI (create/update/delete for timed, allday, someday). Restore role="form" on both forms. Full e2e back to green apart from known timing flakes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ci: remove project from github templates * style: DayLabels * style: fix font sizes * refactor: cleanup grid, form, picker styles * chore: untrack superpowers specs from git docs/superpowers/ is already gitignored; these two spec files were force-added previously. Remove them from tracking so the directory stays local-only. Files remain on disk. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 614fb0b commit 076579b

131 files changed

Lines changed: 2122 additions & 2805 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cursorrules/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ You are an expert full-stack developer working on Compass, a calendar applicatio
1111

1212
This is a monorepo using Bun workspaces with the following packages:
1313

14-
- `@compass/web` - React/TypeScript frontend with Redux, styled-components, webpack
14+
- `@compass/web` - React/TypeScript frontend with Redux, Tailwind CSS
1515
- `@compass/backend` - Express.js REST API with MongoDB, Google Calendar sync, WebSocket support
1616
- `@compass/core` - Shared utilities, types, and business logic
1717
- `@compass/scripts` - CLI tools for building, database operations, user management
@@ -42,7 +42,7 @@ This directory contains focused rules for different aspects of development:
4242
```
4343
packages/
4444
├── backend/src/ # Express.js API, MongoDB, Google Calendar sync
45-
├── web/src/ # React frontend, Redux state, styled-components
45+
├── web/src/ # React frontend, Redux state, Tailwind CSS
4646
├── core/src/ # Shared utilities, types, business logic
4747
└── scripts/src/ # CLI tools for builds and operations
4848
```

.cursorrules/styling.md

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,45 @@ The pattern is: CSS variable `--color-{category}-{name}` → Tailwind class `{ca
6060

6161
### Styling Approach
6262

63-
- Use Tailwind utility classes directly in JSX
64-
- For complex styles, use styled-components (already configured)
65-
- Follow existing patterns in `packages/web/src/components/`
63+
Use a hybrid of inline utilities and `c-*` recipes. **Inline is the default.**
64+
65+
The deciding question for extracting a `c-*` recipe is *"can this be expressed
66+
inline at all?"***not** "is it long?" or "is it used twice?". Reach for a
67+
`c-*` recipe (Tailwind v4 `@utility c-...` in `packages/web/src/index.css`) only
68+
when inline utilities genuinely cannot do the job, i.e. it has any of:
69+
70+
1. **Third-party descendant selectors** you don't control — `.react-datepicker__*`,
71+
`.timepicker__*` (e.g. `c-date-picker`, `c-time-picker`).
72+
2. **Pseudo-elements / vendor scrollbars**`::before`, `::after`,
73+
`::-webkit-scrollbar` (e.g. `compass-scroll`). Prefer the Tailwind `before:` /
74+
`after:` variants inline first; only extract if that gets unreadable.
75+
3. **Keyframe-driven animation bundles** (e.g. `c-loader-spinner`).
76+
4. **Genuine reuse** across components, or a coherent variant set
77+
(e.g. `c-button*`, `c-event-form`).
78+
79+
Otherwise, **inline it**:
80+
81+
- **Inline Tailwind utilities** for one-off layout and state, in JSX directly
82+
(e.g. `className="mb-2.5 items-center justify-end gap-[30px]"`). Use `data-[…]:`
83+
and `hover:` variants instead of `&[data-…]`/`&:hover` recipe blocks. Arbitrary
84+
values are fine for runtime vars: `grid-cols-[repeat(7,minmax(80px,1fr))]`,
85+
`w-[calc(100%_-_50px)]`.
86+
- If a recipe exists only to reach into children via `& .child` / `& > *`, put
87+
the utilities **on the child elements** instead and delete the descendant rule.
88+
- **Do not** create one-off `c-*` recipes named after their implementation
89+
(`c-week-columns`, `c-calendar-grid-rows`); that just recreates a global CSS
90+
layer. Inline them.
91+
- **Semantic CSS-variable tokens** for all theme-dependent colors (see above),
92+
so a future `[data-theme="light"]` rollout needs no component changes.
93+
- **Inline CSS custom properties** only for runtime values that cannot be known
94+
at build time — event colors, positions, dynamic grid counts (e.g.
95+
`style={{ "--event-form-bg": color }}`).
96+
97+
Follow existing patterns in `packages/web/src/components/` and the recipes in
98+
`packages/web/src/index.css`.
99+
100+
Preserve semantic attributes (`role`, `aria-*`, `title`) when restyling — they
101+
are load-bearing for assistive tech and e2e selectors, not presentation.
66102

67103
## Module Imports
68104

.github/ISSUE_TEMPLATE/1-feature-request.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
name: Feature Request
22
description: You want something added to the app
33
labels: [enhancement]
4-
projects: [SwitchbackTech/4]
54

65
body:
76
- type: markdown

.github/ISSUE_TEMPLATE/2-bug-report.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
name: Bug Report
22
description: You found something wrong
3-
labels: [ bug ]
4-
projects: [ SwitchbackTech/4 ]
3+
labels: [bug]
54
type: bug
65

76
body:

CONTEXT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ during Import or Public watch notification handling.
271271
- Treat recurring event changes as changes to a **Recurring Series**, not just
272272
isolated event rows.
273273
- Do not use **Someday Event** and **Task** interchangeably.
274-
- Do not describe the frontend as Tailwind-only or styled-components-only.
274+
- Frontend styling uses Tailwind utilities and semantic runtime CSS variables.
275275
- Do not describe local self-hosting as proving continuous Google sync unless a
276276
public HTTPS webhook path has been configured and verified.
277277
- When changing a shared event, sync, API, or error contract, keep the web,

babel.config.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,4 @@ module.exports = {
44
["@babel/preset-env", { targets: { node: "current" } }],
55
"@babel/preset-typescript",
66
],
7-
plugins: [
8-
[
9-
"babel-plugin-styled-components",
10-
{
11-
meaninglessFileNames: ["index", "styled"],
12-
pure: true,
13-
},
14-
],
15-
],
167
};

0 commit comments

Comments
 (0)