From bf1cbc2faf8465904cbb585ddabc993526f8526a Mon Sep 17 00:00:00 2001 From: dame Date: Fri, 3 Jul 2026 11:31:55 -0400 Subject: [PATCH] Improve mobile layout of trending lexicon rows and repo-glance tiles (#46) * Stack NSID over two lines on narrow trending rows On phones the trending/top lexicon rows truncated the NSID with an ellipsis because the fixed sparkline + count columns starved the flexible name column. Split the NSID into its top-2-segment namespace and the remainder and, on screens <=600px, stack them (app.bsky / feed.post) so the whole identifier stays readable. Wide screens keep the single truncating line, with the joining dot rendered via the tail's ::before so it only shows inline. The loading skeleton grows a matching second bar on mobile so row heights stay in lockstep when data lands. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01NyPVCrj1H472WPGMsT1uCZ * Keep "Repo at a glance" tiles on single lines on mobile In the 2-column mobile stat grid the tiles are narrow enough that the Created value broke mid-value ("Aug" / "2023") and two-word labels wrapped. Trim the created date to month + year (the relative-age sublabel already carries the finer detail), keep stat values on one line with white-space: nowrap, rename "Inbound links" to the shorter, app-consistent "Backlinks", and tighten the small-caps label tracking on mobile so labels like "Audit changes" fit on one line. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01NyPVCrj1H472WPGMsT1uCZ --------- Co-authored-by: Claude --- src/app/globals.css | 65 +++++++++++++++++++++ src/components/account/AccountStats.tsx | 9 ++- src/components/explore/TrendingLexicons.tsx | 42 ++++++++----- src/utils/ufos/nsid.ts | 12 ++++ 4 files changed, 112 insertions(+), 16 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index 7379a0d..6fa8e7e 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1988,6 +1988,29 @@ html { min-width: 0; } +/* NSID cell. Wide screens: one truncating line joined by a dot + (app.bsky.feed.post). The dot lives on the tail's ::before so it only + appears inline — see the mobile override that stacks the two segments. */ +.lexicon-row-nsid { + min-width: 0; + font-family: var(--font-mono); + font-size: 0.8125rem; + color: var(--text-primary); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.lexicon-row-nsid .lexicon-nsid-tail::before { + content: '.'; +} + +/* Skeleton NSID: single bar on wide screens; the tail bar only appears on + mobile (see override) to mirror the two-line loaded layout. */ +.lexicon-nsid-tail-skel { + display: none; +} + @media (max-width: 600px) { .lexicon-row-grid { grid-template-columns: 1.5rem minmax(0, 1fr) 3rem auto; @@ -1995,6 +2018,41 @@ html { padding: 0.625rem 0.75rem; } + /* Stack the top-2-segment namespace over the remainder so the whole NSID + stays readable instead of truncating: app.bsky / feed.post. */ + .lexicon-row-nsid { + display: flex; + flex-direction: column; + row-gap: 0.1rem; + white-space: normal; + line-height: 1.3; + } + + .lexicon-row-nsid .lexicon-nsid-head, + .lexicon-row-nsid .lexicon-nsid-tail { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + /* No inline joining dot when the segments are stacked. */ + .lexicon-row-nsid .lexicon-nsid-tail::before { + content: none; + } + + /* Match the loaded two-line cell so the skeleton reserves the same + height and data landing doesn't shift the row. */ + .lexicon-row-nsid-skel { + display: flex; + flex-direction: column; + row-gap: 0.35rem; + min-width: 0; + } + + .lexicon-nsid-tail-skel { + display: block; + } + /* Shrink the chart to fill the narrower column. Height stays at the svg's 24px box (the viewBox scales the line down proportionally and centers it) so loaded rows and the 24px skeleton block keep identical heights — @@ -2986,4 +3044,11 @@ html { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.4rem; } + + /* The tiles get narrow in the 2-column grid; tighten the small-caps + label tracking so two-word labels (Audit changes) sit on one line + instead of wrapping mid-phrase. The icon already eats into the width. */ + .account-stats-grid .explore-small-caps { + letter-spacing: 0.05em; + } } diff --git a/src/components/account/AccountStats.tsx b/src/components/account/AccountStats.tsx index 7698ebd..a26ef90 100644 --- a/src/components/account/AccountStats.tsx +++ b/src/components/account/AccountStats.tsx @@ -148,10 +148,12 @@ export default function AccountStats({ did, handle, interactive = true }: Props) if (!stats?.createdAt) return null; try { const d = new Date(stats.createdAt); + // Month + year only ("Aug 2023"). The tile is narrow in the 2-column + // mobile grid, and the relative age sublabel already carries the + // finer-grained "how long ago" — a full day-level date just wrapped. return d.toLocaleDateString(undefined, { year: 'numeric', month: 'short', - day: 'numeric', }); } catch { return null; @@ -209,7 +211,7 @@ export default function AccountStats({ did, handle, interactive = true }: Props) /> } - label="Inbound links" + label="Backlinks" hint="Records across the Atmosphere pointing at this DID" value={stats?.backlinks ?? undefined} unavailable={stats !== null && stats.backlinks === null} @@ -394,6 +396,9 @@ function StatTile({ color: 'var(--text-primary)', fontVariantNumeric: 'tabular-nums', lineHeight: 1.1, + // Keep short values (esp. the "Aug 2023" date) on one line instead + // of breaking at the space in the narrow mobile tiles. + whiteSpace: 'nowrap', }} > {display} diff --git a/src/components/explore/TrendingLexicons.tsx b/src/components/explore/TrendingLexicons.tsx index 27d402b..de86cc3 100644 --- a/src/components/explore/TrendingLexicons.tsx +++ b/src/components/explore/TrendingLexicons.tsx @@ -19,7 +19,7 @@ import { type Metric, } from '@/utils/ufos/config'; import { formatCount } from '@/utils/ufos/format'; -import { namespaceKey, schemaPathFor } from '@/utils/ufos/nsid'; +import { namespaceKey, schemaPathFor, splitNsid } from '@/utils/ufos/nsid'; import { WINDOWS, type Window } from '@/utils/ufos/windows'; type Mode = 'top' | 'trending'; @@ -276,7 +276,15 @@ function SkeletonRows({ mode }: { mode: Mode }) { >
- + {/* Mirror the NSID cell: a single bar on wide screens, two + stacked bars on mobile (matching the head/tail two-line + layout) so the skeleton and loaded rows keep equal heights. */} + + + + + + @@ -347,18 +355,7 @@ function Row({ > {rank.toString().padStart(2, '0')} - - {row.nsid} - + + {head} + {tail && {tail}} + + ); +} + function CountValue({ value, metric }: { value: number; metric: Metric }) { return ( `{ head: 'app.bsky', tail: 'feed.post' }`. NSIDs + * with two or fewer segments return an empty tail. + */ +export function splitNsid(nsid: string): { head: string; tail: string } { + const parts = nsid.split('.'); + if (parts.length <= 2) return { head: nsid, tail: '' }; + return { head: `${parts[0]}.${parts[1]}`, tail: parts.slice(2).join('.') }; +} + /** The parent lexicon group — everything before the final NSID segment. * `app.bsky.feed.post` -> `app.bsky.feed`. Used as the `/prefix` argument * to find sibling collections. */ -- 2.51.2