fix(repo-browse): keep tree and blob layout readable in narrow columns
The mounted server fragment is now a container-query root that owns its own horizontal pan; the tree table uses fixed layout with reserved lanes so name, commit and date stop trading places while panning.
ZhenYi committed
Modified web/src/entities/repo/ui/embed.css web/src/entities/repo/ui/embed.css +51 −0 View web/src/entities/repo/ui/embed.css
@@ -11,6 +11,15 @@
1111 color: var(--shell-ink, #1c1e22);
1212 word-break: break-word;
1313}
14/*
15 * Server fragments are laid out against the column they are mounted in, so
16 * that column is the query container; it also owns the horizontal pan when a
17 * fragment cannot fit at all.
18 */
19.repo-embed-scroll {
20 container-type: inline-size;
21 overflow-x: auto;
22}
1423
1524/* ---------- file tree -------------------------------------------------- */
1625.repo-embed [data-component='git-tree'] {
@@ -18,6 +27,10 @@
1827 border-radius: 10px;
1928 background: var(--shell-surface, #fff);
2029 overflow: hidden;
30 /* Fixed layout keeps the three lanes from trading places; the width itself
31 comes from the container query below so a squeezed desktop column and a
32 phone get the same readable result. */
33 table-layout: fixed;
2134}
2235.repo-embed [data-component='git-tree'] thead {
2336 background: var(--shell-field, #f2f3f6);
@@ -31,7 +44,35 @@
3144 letter-spacing: 1.2px;
3245 color: var(--shell-ink-muted, #8b8f99);
3346 padding: 8px 12px;
47 white-space: nowrap;
3448}
49/* Name keeps a share of the row, the commit column takes the rest and the
50 date stays a fixed lane so the three never trade places while scrolling. */
51.repo-embed [data-component='git-tree'] th:nth-child(1) { width: 34%; }
52.repo-embed [data-component='git-tree'] th:nth-child(3) { width: 88px; }
53.repo-embed [data-component='git-tree'] td:nth-child(2) a {
54 display: flex;
55 min-width: 0;
56 align-items: center;
57 gap: 8px;
58}
59.repo-embed [data-component='git-tree'] td:nth-child(2) a > span:last-child {
60 min-width: 0;
61 overflow: hidden;
62 text-overflow: ellipsis;
63 white-space: nowrap;
64}
65/* The short sha is a fixed chip: it must never be squeezed into a vertical stack. */
66.repo-embed [data-component='git-tree'] td:nth-child(2) code {
67 flex: none;
68 white-space: nowrap;
69}
70.repo-embed [data-component='git-tree'] td:nth-child(1) a {
71 display: block;
72 overflow: hidden;
73 text-overflow: ellipsis;
74 white-space: nowrap;
75}
3576.repo-embed [data-component='git-tree'] th:last-child {
3677 text-align: right;
3778}
@@ -272,6 +313,16 @@
272313.repo-embed pre { overflow-x: auto; font-family: ui-monospace, monospace; font-size: 12px; }
273314.repo-embed img { max-width: 100%; }
274315
316/* The tree adapts to the column it actually got, not the viewport: a desktop
317 window with the sidebar and info aside open can be narrower than a tablet
318 in full screen. Below the threshold the date lane is dropped so the file
319 list itself never needs a horizontal pan. */
320@container (max-width: 560px) {
321 .repo-embed [data-component='git-tree'] th:nth-child(3),
322 .repo-embed [data-component='git-tree'] td:nth-child(3) { display: none; }
323 .repo-embed [data-component='git-tree'] th:nth-child(1) { width: 44%; }
324}
325
275326/* ---------- media safety nets ---------------------------------------------
276327 * Server markup sizes icons with Tailwind utilities (`h-4 w-4`) that are not
277328 * shipped for fragments; an unsized inline <svg> would otherwise fall back to
Modified web/src/features/repo-browse/ui/code-tab.tsx web/src/features/repo-browse/ui/code-tab.tsx +2 −2 View web/src/features/repo-browse/ui/code-tab.tsx
@@ -275,7 +275,7 @@
275275 <ErrorPanel status={frag.status} what={t('repo.tree.what')} onRetry={() => setRetry(r => r + 1)} />
276276 )
277277 }
278 return <div className="repo-embed overflow-x-auto p-3" onClick={onClick} dangerouslySetInnerHTML={{ __html: frag.html }} />
278 return <div className="repo-embed repo-embed-scroll p-3" onClick={onClick} dangerouslySetInnerHTML={{ __html: frag.html }} />
279279}
280280
281281function JsonTree({
@@ -728,7 +728,7 @@
728728 if (!frag) return <PanelNote text={t('repo.file.loading')} />
729729 if (!frag.ok) return <ErrorPanel status={frag.status} what={t('repo.file.what')} onRetry={() => setRetry(r => r + 1)} />
730730 return (
731 <div ref={ref} className="repo-embed overflow-x-auto" onClick={onClick} dangerouslySetInnerHTML={{ __html: frag.html }} />
731 <div ref={ref} className="repo-embed repo-embed-scroll" onClick={onClick} dangerouslySetInnerHTML={{ __html: frag.html }} />
732732 )
733733}
734734
Modified web/src/pages/workspace/ui/repo/repo-polish.css web/src/pages/workspace/ui/repo/repo-polish.css +5 −2 View web/src/pages/workspace/ui/repo/repo-polish.css
@@ -59,6 +59,9 @@
5959
6060@media (max-width: 760px) {
6161 .repo-view-content { padding-top: 0; }
62 /* Rows stack: the actions take their own line instead of squeezing the
63 subject and meta down to a one-character column. */
64 .repo-commit-row, .repo-branch-row { flex-wrap: wrap; row-gap: 8px; }
6265 .repo-toolbar-tabs button, .repo-toolbar-tabs span { padding-inline: 10px; }
6366 .repo-clone { width: 100%; }
6467 .repo-file-toolbar { padding: 8px 10px; }
@@ -69,8 +72,8 @@
6972 .repo-code-header-clone > .repo-clone { width: 100%; }
7073 .repo-file-table th, .repo-file-table td { padding-left: 12px; padding-right: 12px; }
7174 .repo-commit-row { padding: 14px; }
72 .repo-commit-actions { width: 100%; margin-left: 28px; }
75 .repo-commit-actions { width: auto; flex: 1 1 100%; margin-left: 0; justify-content: flex-end; }
7376 .repo-branch-row { padding: 14px; }
74 .repo-branch-actions { width: 100%; margin-left: 0; }
77 .repo-branch-actions { width: auto; flex: 1 1 100%; margin-left: 0; }
7578 .repo-settings-content { padding: 18px; }
7679}