Skip to content

Refresh the UI across the app and make improvements on mobile - #459

Merged
str1fe merged 1 commit into
mainfrom
design/ui-refresh
Sep 21, 2026
Merged

str1fe merged 1 commit into
mainfrom
design/ui-refresh

Conversation

@str1fe

@str1fe str1fe commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Refreshes the visual layer of the whole application around a coherent set of design tokens, and fixes the mobile layout problems that surfaced along the way.

The direction was picked from three mockups: this one keeps the indigo brand and the existing navigation, and modernises the execution — Inter instead of Montserrat, softer borders and shadows instead of hard 1px gray boxes, 40px controls instead of 48px, tabular figures for durations, and denser rows.

Time log

Before After

The week strip now shows hours per day, the toolbar is a segmented control, and the day/week totals are chips in the card footer.

Reports

Before After

One hero figure for total hours, a billable meter instead of two loose legend dots, underline tabs, and right-aligned numeric columns.

Clients & projects

Before After

A single table made the client boundaries invisible. Each client is now its own card with a tinted header, a project count and its own actions; projects are a plain list inside it.

Mobile

The detailed report overflowed the viewport by 202px, and the tables that did not overflow hid their action column behind a horizontal scrollbar. Below 768px data tables now collapse into stacked cards, using a data-label per cell as the key.

Detailed report before Detailed report after Clients & projects after

Every signed-in page was measured at 390px (document.scrollWidth vs viewport); all of them now come out clean.

Tokens and components

  • Colors are stored as raw RGB channels and mapped as rgb(var(--x) / <alpha-value>). Several tokens previously held bare HSL triplets, so border-border, bg-muted and hover:bg-accent emitted nothing at all, which is why every view hand-rolled border-gray-100. Opacity modifiers work now.
  • New shared classes: page-shell, page-head, surface-card, toolbar-segment, stat-chip, section-head, count-chip, form-label, form-input, form-error, table-stack, table-scroll, tnum.
  • ButtonComponent, CardComponent, SplitButtonComponent and the RubyUI primitives (button, link, input, badge, card, table, tabs, dialog, popover, dropdown, tooltip) were restyled through those tokens.

Fixes picked up on the way

  • dropdown_component.rb defined three classes in one file, which broke constant reloading in development — any reload made the detailed report and the project form fail with superclass mismatch for class DropdownComponentTrigger. Split into one class per file.
  • The cookie banner covered the sign-in button on phone-height viewports, and its full-width wrapper swallowed taps even where nothing was visible, so logging in on a phone looked like it was hanging. The wrapper is pointer-events-none now and the card is much more compact.
  • The week strip's per-day totals came from minutes_by_day_of_week, which queries user.time_regs without an organization scope. They are derived from the already authorized @time_regs_week scope instead.
  • Workspace::ClientsController did not include SetCurrency, so project rates on the client page rendered without their currency.
  • Tooltips are hidden below md. They are useless on touch, and their absolutely positioned w-max boxes were widening the document on phones.
  • Added a charset meta tag to the base layout.

Notes for the reviewer

  • No behaviour changes beyond the four fixes listed above; the rest is markup and CSS.
  • 250 runs, 794 assertions, 0 failures, 0 errors and rubocop clean.
  • Verified in a browser on desktop and at 390px, not only in tests.
  • The screenshots live on the image-only branch design/ui-refresh-screenshots so they stay out of this diff. That branch can be deleted once this is merged.

🤖 Generated with Claude Code

Rework the visual layer of the whole application around a coherent set of
design tokens, then fix the mobile layout problems that surfaced along the way.

Tokens and theme
- Store colors as raw RGB channels and map them in tailwind.config.js as
  rgb(var(--x) / <alpha-value>). Several tokens previously held bare HSL
  triplets, so border-border, bg-muted and hover:bg-accent emitted nothing and
  every view hand-rolled border-gray-100 instead. Opacity modifiers now work.
- Add canvas / surface-muted / brand tokens, a shadow scale and an xl radius.
- Switch the typeface from Montserrat to Inter.

Components
- Restyle ButtonComponent (40px instead of 48px, new variants, real focus
  rings), CardComponent, SplitButtonComponent and the RubyUI primitives:
  button, link, input, badge, card, table, tabs, dialog, popover, dropdown,
  tooltip.
- Add shared classes: page-shell, page-head, surface-card, toolbar-segment,
  stat-chip, section-head, count-chip, form-label, form-input, form-error,
  table-stack, table-scroll, tnum.
- Split dropdown_component.rb into one class per file. Three classes in one
  file broke constant reloading in development with "superclass mismatch for
  class DropdownComponentTrigger".

Screens
- Time log: sticky nav, page head with a segmented week control, week strip
  with per-day hours, denser entry rows, totals as chips.
- Reports and detailed report: stat tiles with a billable meter, underline
  tabs, right-aligned numeric columns, restyled filter bar.
- Workspace: clients and projects are now one card per client instead of a
  single table whose client boundaries were invisible; team members, settings,
  project and client pages follow the same patterns.
- Auth, onboarding wizard, modals, empty states, snackbar, banners and error
  pages follow the tokens.

Mobile
- Data tables collapse into stacked cards below 768px via table-stack and
  per-cell data-label. The detailed report overflowed the viewport by 202px.
- Tooltips are hidden below md: useless on touch, and their absolutely
  positioned w-max boxes widened the document.
- The cookie banner wrapper no longer swallows taps (pointer-events-none on
  the wrapper, auto on the card) and is far more compact on small screens. It
  covered the sign-in button on phone-height viewports, which made logging in
  look like it was hanging.

Also
- Derive the week strip's per-day totals from the authorized scope in
  TimeRegsController rather than the minutes_by_day_of_week helper, which
  queried user.time_regs across organizations.
- Include SetCurrency in Workspace::ClientsController so project rates on the
  client page render with their currency.
- Add a charset meta tag to the base layout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@str1fe str1fe changed the title Refresh the UI across the app and make it work on phones Refresh the UI across the app and make improvements on mobile Sep 21, 2026
@str1fe
str1fe merged commit 6e491b6 into main Sep 21, 2026
3 checks passed
@str1fe
str1fe deleted the design/ui-refresh branch September 21, 2026 19:48
str1fe added a commit that referenced this pull request Sep 21, 2026
The UI refresh moved the user's email into the account menu (the trigger
now shows the name) and turned the row's Edit into an icon-only button
with an aria-label. Both tests failed on main since #459.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.

1 participant