Skip to content
Development

"Looks the same to me"

By Victor Da Luz
railsrubytailwinddev-logblog-manager

I set out to redesign blog-manager’s UI. A previous pass had pulled the inline styles into Tailwind and ViewComponents, but it was a refactor: same look, same bugs. Tables ran off the right edge, spacing was loose, and the per-post syndication panel was a confusing stack of statuses and actions. I wanted to actually fix the design and fold in a blog switcher for the multi-blog case.

The thing I did right, before writing any code, was split it into four small phases and agree to look at a rendered screenshot after each one. The thing I got wrong happened anyway. This is mostly about that.

Phase 1, the easy win

The post detail page had a right-aligned column that mixed everything together: “Medium, Published”, “Dev.to, Draft”, “Draft staged in Postiz”, “Postiz, Scheduled”, a couple of links, and a “Share to social” action. You couldn’t tell a status from a button. I replaced it with one Syndication section: a row per target laid out as name, status pill, one primary action. Medium, Dev.to, Social, each consistent.

I rendered it with a real browser (cuprite driving headless Chrome) and screenshotted it at the actual content width. It read cleanly. Approved on the first try. I got comfortable.

Phase 2, where I stopped paying attention

The posts list. The complaint was specific: “spacing/padding issues,” plus dates wrapping to two lines and a “Not imported” column that said “Not imported” on basically every row. I fixed the wrapping (whitespace-nowrap on the date cells), replaced the low-signal Medium column with a compact syndication indicator, and let the page use the window’s full width instead of being boxed into an 820px column. Tests green. I shipped a screenshot.

The reply: “looks the same to me.”

I widened the container more and tried again. “same just wider…”

That second response is the whole post. It’s not vague dissatisfaction, it’s a precise bug report. I had changed the container width and the column contents. I had not changed a single thing about row density. The .data-table cell padding was still 12px, the rows were still tall, the meta still floated in the vertical middle of each row. The one word used, “spacing,” was the one property I never touched. I had fixed everything around the complaint and nothing at it.

What made it worse is that my own checks had passed. “Column visible? Yes. No wrapping? Yes. Tests green? Yes.” None of those check “is the spacing actually different.” So I shipped a diff that provably didn’t address the report and felt confident doing it.

The fix, once I actually aimed at it: the rows were tall because every row carried a description line under the title, doubling its height. I dropped the description to a hover tooltip (it’s on the detail page anyway) and made the rows single-line. Same data, roughly 40% shorter rows. I put the loose “before” and the dense “after” side by side so the difference was undeniable this time. Then, separately, the table header still read as cramped flat labels jammed against the card’s top edge, so it got a grounded band: a page-tone background and real padding. That one earned a blunter review, “the header still looks like this,” which, fair.

Phases 3 and 4

The blog switcher was the calmest part. A workspace-style control at the top of the sidebar, session-persisted, scoping the posts list and dashboard. A ?blog_id= link still takes over and persists into the switcher, so bookmarked URLs keep their scope, and a deleted blog falls back to “all blogs.” It’s a <details> element, so the dropdown needs no JavaScript.

Phase 4 was the boring, satisfying kind of work: pull the repeated form-section card and the four hand-rolled flash blocks into components, roll the page header out everywhere, and run the blogs table through the same table component the posts list now uses. The seven-column blogs table was the original “runs off the edge” complaint in the issue, and it finally stopped clipping once it got the wider container and a horizontal-scroll fallback.

What I took from it

Fix the exact thing named. When someone says “spacing,” changing width and column contents is not an answer, even if those were also worth doing. The named word is the target.

Self-checks have to test the complaint, not adjacent facts. “Tests pass” and “column is visible” said nothing about density. If the report is about spacing, the verification has to be a before/after of the spacing. For visual work that means actually rendering it and looking, not asserting in a unit test.

Phasing subjective work is worth it. Four small PRs with a screenshot checkpoint each meant the “looks the same” miss cost one iteration, not a giant reveal that needed unwinding. The reviewer is the arbiter of “does this look better,” and the only way to use that well is to show them the rendered thing early and often.

Next up is dark mode, which I punted to its own issue. The design already runs on CSS custom properties, so it’s mostly a second token set rather than touching every component, but that’s a different post.

Related reading

Development

The editor commit button is a deploy button

Committing a draft to main auto-deploys the blog. Once that clicked, sync-vs-async stopped being a style question - plus the legacy-affiliate carve-out a new validator almost broke.

Read