← All work

Case study · Good Hustle Media

Good Hustle Design System

Client
Good Hustle Media
Role
Sole product designer: research, design system, UI mockups, dev handoff
Team
1 designer + 2 developers
Timeline
1 month · Summer 2025
Status
System delivered, product in development
Agencies table screen, split between light mode and dark mode

01 — Problem

A working platform that felt robotic

Good Hustle Media helps agencies buy out-of-home advertising: billboards, transit, street furniture, and more than 40 other media types. Its platform worked, but it looked and felt dated. The brief was blunt: make it less robotic, "really push the envelope," and don't feel tied to the existing branding.

1

month to build a system that two developers could use for every screen that came after.

Goal

Give a small dev team a modern, accessible, themeable design system whose names match their code exactly, so they can rebuild the platform screen by screen without waiting on a designer.

Balsamiq wireframe of the legacy login page
Where we started: Balsamiq wireframes of the existing appClick to enlarge

02 — Research

Four users, one crowded category

The platform sits between three businesses, and each one comes to it with a different job. I mapped who logs in and what they need from their first screen.

Primary user

Agency sales

  • Creates and manages campaigns
  • Oversees inventory, vendors, and clients
  • Generates proposals and invoices
Our customer

Vendor

  • The outdoor media company that owns the boards
  • Maintains inventory and answers RFPs
  • Uploads proof of performance
Their customer

Client (advertiser)

  • Reviews and approves proposals and proofs
  • Uploads creative
  • Tracks campaign stats and billing
Behind the scenes

System admin

  • Sets up new agencies and global settings
  • Maintains code tables and media types

Competitive teardown

I walked through the products of four companies in the space and noted each one's palette and vibe. Do Media is Good Hustle's biggest competitor. Blip and Adstruc (Vistar Media) sell billboard space with self-serve tools.

Do Media homepage and software screenshots with color palette notes
Do Media: bold, high-contrast, digital-forwardClick to enlarge
Blip homepage and campaign builder screenshots with color palette notes
Blip: modern, energetic, with sharp highlights ✓Click to enlarge
Finding 01

Everyone wears navy and orange

Deep navy, red-orange, bright cyan, and pure black on white showed up again and again. To stand out, we'd need a different palette.

Finding 02

Blip had the right energy

Of the four vibes, Blip's modern, energetic feel was the one the client wanted. Vistar felt friendly but corporate, and Good Hustle's own site felt confident and approachable.

Finding 03

Hide the complexity

The work is data-heavy: dozens of media types, long inventory lists, and campaign plans. Users need filtering, sorting, and quick actions much more than they need decoration.

03 — Foundation

Why shadcn, not a blank canvas

One designer, two developers, one month. Designing every button from scratch wasn't an option. I compared Chakra UI and shadcn/ui as a starting point and built on top of the shadcn community Figma kit.

Reason 01

It fits the devs' stack

The developers were already working in React and Tailwind. shadcn tokens map straight to Tailwind classes, so the Figma file and the code use the same words.

Reason 02

We own the code

shadcn components are copied into the repo instead of installed as a dependency. The team can customize anything without fighting a library or getting locked into one.

Reason 03

Accessible by default

The components are built on Radix primitives, so keyboard navigation, focus handling, and ARIA come built in. A two-person team gets that without extra work.

Reason 04

It pairs with TanStack Table

shadcn's data table is built on TanStack Table. In an app that's mostly tables, that was a deciding factor.

04 — Tokens

One name in Figma, the same name in code

Every color in the system is documented three ways: the shadcn token, the Tailwind class behind it, and a swatch. A developer never has to guess what "that teal" is.

Semantic color tokens for light mode and dark mode, with form validation colors
Semantic color tokens, light and darkClick to enlarge
Typography scale set in Space Grotesk
Type scale in Space GroteskClick to enlarge
Color

Teal on slate

  • Teal-500 as the primary color, on slate neutrals, stays away from the navy and orange every competitor uses.
  • Full light and dark modes from the same token names.
  • Success, warning, destructive, and info sets for form validation.
  • Dedicated table tokens for row hover, selected, header, focus, empty, and loading states.
Type

Space Grotesk

  • One Google font with enough character to feel less robotic.
  • h1–h6, paragraph, lead, large, small, subtle, blockquote, and inline code styles.
Motion

Three speeds

  • Fast 150ms, default 300ms, slow 500ms.
  • Ease-in, ease-out, and ease-in-out curves.
  • Shared by drawers, dialogs, tabs, and the date picker.

05 — Components

24 components, every state spelled out

Buttons, badges, breadcrumbs, context menu, date picker, dialog, drawer, dropdown, grid, form groups, form validation, icons, inputs, navigation, read-only labels, radio buttons, switches, table, tabs, text area, tooltip, typography, page header, and animations. Each one has its own documented page.

Button documentation showing default, outline and subtle variants across states with token names
Buttons

States as tokens, not pictures

Every variant shows four states (default, hover, focus, disabled) with the exact token behind each one. Developers copy the class names straight across.

  • Default, outline, subtle, ghost, destructive, text link, icon, and loading variants
  • Hover is bg-primary/70, focus is ring, and disabled is bg-muted
  • The same pattern repeats across inputs, tabs, and switches
TanStack table component with filters, bulk select, row actions and pagination
Table

The workhorse

Agencies, users, vendors, inventory, and audit logs all live in tables. I designed one TanStack table component to cover all of them.

  • Global search plus facet filters for status, role, and agency
  • Per-column filter row with a single "Reset filters"
  • Bulk select, inline edit/assign/delete, and pagination
Explore the Figma file →

06 — Screens

Putting the system to work

To prove the system, I designed the screens everyone touches first: login, user maintenance, agency administration, and the campaign plan detail page. Every screen exists in light and dark mode, and the drawers, dialogs, tabs, and date picker have clickable, animated prototypes.

Legacy login wireframe
Before: the legacy loginClick to enlarge
New Good Hustle Systems login, split between light and dark mode
After: Good Hustle Systems, light and darkClick to enlarge
Users list screen built from the table component
User maintenance

List, add, edit, audit

  • One table component handles the users list and the audit log.
  • Add and edit share the same form groups, with read-only labels for created and modified info.
Campaign plan detail page with tabs, split between light and dark mode
Campaign plan detail

Forty fields, eight tabs

  • I grouped fields into Overview, Location, Inventory, Billing, Production, Performance, Creative, and Assets.
  • Each tab uses the same form-group grid, so a new section is just a new tab.

07 — Outcome

Where it landed, and what it taught me

Where it landed

Delivered in a month, built from day one

  • The full system, from tokens and components to light/dark themes and core screens, shipped to the dev team in one month.
  • Because the Figma names match shadcn and Tailwind, handoff got faster. The developers build screens without custom CSS or back-and-forth over naming.
  • The product is in development. Next on the roadmap: dashboards, campaigns and proposals, inventory and vendors, artwork, billing, and vendor users.
What I learned

Don't rebuild the button

  • Starting from shadcn instead of a blank canvas let me spend the month on what was unique to this product: data tables, validation, and dark mode.
  • Naming tokens the way developers already name things is the cheapest handoff tool there is.