From 0bed757e739ef450d14d739ba5e453afaf737f82 Mon Sep 17 00:00:00 2001 From: gl0w Date: Wed, 28 Oct 2026 11:16:09 +0000 Subject: [PATCH] stack Files then README on code tab (#120) --- .../issue.md | 20 ++++++ src/build.rs | 6 +- static/style.css | 14 +--- tests/code_cols.rs | 66 +++++++------------ 4 files changed, 49 insertions(+), 57 deletions(-) create mode 100644 .forge/issues/3c809870-aded-459e-af30-af4bed618b27/issue.md diff --git a/.forge/issues/3c809870-aded-459e-af30-af4bed618b27/issue.md b/.forge/issues/3c809870-aded-459e-af30-af4bed618b27/issue.md new file mode 100644 index 0000000..486e236 --- /dev/null +++ b/.forge/issues/3c809870-aded-459e-af30-af4bed618b27/issue.md @@ -0,0 +1,20 @@ +--- +id: 3c809870-aded-459e-af30-af4bed618b27 +title: Stack Files then README on the code tab at every width +state: open +labels: +- area:render +assignees: [] +milestone: null +created: 2026-10-28T11:10:17.690517388Z +updated: null +--- +## Problem + +On wide screens the code tab switches to a two-column grid: Files on the left (7/12) and README on the right (5/12). The README becomes a narrow sidebar and the file table gets a different reading order from GitHub/Forgejo/GitLab-style code pages. + +## Fix + +- Keep Files and README in one stacked column at every width, in that order. +- Remove the `.cols-code` 7/5 desktop rule and the generic `.cols` two-column override. +- Update `tests/code_cols.rs` to assert there is no side-by-side rule and the DOM order stays Files → README. diff --git a/src/build.rs b/src/build.rs index 0604e87..3ab1ac8 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1933,8 +1933,8 @@ pub fn run_build(repo: &Path, out: &Path, opts: &BuildOptions) -> Result\n"); - // Stacked below 1100px; files + README sit side by side only at - // >=1100px via .cols-code (m6/code-cols, f0rge #45, 7/12 + 5/12). + // Files then README in one stacked column at every width (f0rge #120); + // no desktop sidebar split. // Code tab file TABLE (m6 code-gitea, f0rge #33, Gitea-style) plus the // language mix bar (bytes share, Tokyo Night hues, no JS). // Language math (m6, f0rge #37): tracked files only (via gitx, so @@ -1947,7 +1947,7 @@ pub fn run_build(repo: &Path, out: &Path, opts: &BuildOptions) -> Result = lang_rows(&blobs, &ignored); let lang_section = language_bar(&lang_files); - body.push_str("

Files

\n"); + body.push_str("

Files

\n"); body.push_str(&file_table_html("", &root_entries, None, &history)); body.push_str(&lang_section); body.push_str("
\n

README

\n"); diff --git a/static/style.css b/static/style.css index 33982a6..ee5bf41 100644 --- a/static/style.css +++ b/static/style.css @@ -137,7 +137,7 @@ td code,th code{word-break:break-all} /* List tables (m6/tables): long titles/shas wrap inside the scroll box; the # column stays narrow. */ td.title,td.sha{overflow-wrap:anywhere} td.num{width:1%;white-space:nowrap} -/* Single column on mobile; side-by-side only when it fits (>=768px). */ +/* Single-column stack; children keep DOM order. */ .cols{display:grid;grid-template-columns:minmax(0,1fr);gap:1.5rem;min-width:0} .cols>section,.cols>div{min-width:0} /* Forms: full-width on mobile, >=40px touch targets. */ @@ -203,22 +203,14 @@ footer.site-footer .footer-provenance{margin:0;font-size:var(--fs-sm);text-align .brand-lockup:focus-visible,.site-header .site-nav.nav-scroll a:focus-visible{outline:2px solid var(--blue);outline-offset:2px} .site-header .brand{flex:none} @media (min-width:768px){ - .cols{grid-template-columns:minmax(0,1fr) minmax(0,1.25fr)} .site-nav .wrap{gap:.25rem 1.25rem} :root{--gap-head:1.25rem;--gap-content:1.5rem} main{padding:1.5rem 0 3rem} } -/* Code tab two columns (m6/code-cols, f0rge #45): files + README share - the existing .cols grid; the code variant stays stacked below 1100px - so 360px-1099px never squeezes the file table. At >=1100px files take - 7/12 and README 5/12 for a readable line length. Stacked override first - so the later 1100px rule wins the cascade on desktop. */ -@media (min-width:768px){ - .cols-code{grid-template-columns:minmax(0,1fr)} -} +/* The code tab is always one stacked column: Files, then README. + No desktop 7/5 split; the file table keeps the full content width. */ @media (min-width:1100px){ .wrap{max-width:72rem;padding:0 1.5rem} - .cols-code{grid-template-columns:minmax(0,7fr) minmax(0,5fr)} } /* Code conventions (m6, f0rge #20): breadcrumbs, file meta, line anchors, clone block. */ .crumbs{margin:var(--gap-head) 0 .5rem;font-size:.95rem} diff --git a/tests/code_cols.rs b/tests/code_cols.rs index 73a3ccb..c73a045 100644 --- a/tests/code_cols.rs +++ b/tests/code_cols.rs @@ -1,6 +1,6 @@ -//! Code tab two columns (m6, f0rge issue #45): -//! files + README share the existing `.cols` grid, side by side only at -//! >=1100px (files 7/12, README 5/12), stacked below. +//! Code tab stack (f0rge issue #120): +//! files and README share one stacked `.cols` column at every width, in +//! DOM order Files then README. No desktop sidebar split. //! //! Builds a small fixture repo with the real binary and string-asserts on //! the emitted HTML + `static/style.css` (no rendering engine needed). @@ -76,15 +76,19 @@ fn css() -> String { } #[test] -fn code_tab_wraps_files_and_readme_in_cols_code() { +fn code_tab_wraps_files_and_readme_in_stacked_column() { let out = build_fixture(); let index = std::fs::read_to_string(out.join("index.html")).expect("index"); - // Wrapper reuses the existing .cols pattern with the code variant. + // Wrapper is one plain stacked grid; no code-specific column variant. assert!( - index.contains("
"), - "code tab wraps files + README in .cols.cols-code" + index.contains("
"), + "code tab wraps files + README in .cols" ); - // Two sections in order: files (table) left, README right. + assert!( + !index.contains("cols-code"), + "no dead side-by-side class in the markup" + ); + // Two sections in order: files first, then README. let files_pos = index .find("
") .expect("files section"); @@ -102,7 +106,7 @@ fn code_tab_wraps_files_and_readme_in_cols_code() { ); assert!( files_block.contains("file-table"), - "file table lives in the files (left) column" + "file table lives in the files section" ); let readme_block = &index[readme_pos..]; assert!( @@ -111,12 +115,12 @@ fn code_tab_wraps_files_and_readme_in_cols_code() { ); assert!( readme_block.contains("cols fixture"), - "README body renders in the right column" + "README body renders after the file table" ); } #[test] -fn code_cols_breakpoint_is_1100px_stacked_below() { +fn code_tab_is_always_stacked() { let css = css(); // Mobile-first base: .cols is a single stacked column. let base = css.split("@media (min-width").next().expect("base css"); @@ -124,42 +128,18 @@ fn code_cols_breakpoint_is_1100px_stacked_below() { base.contains(".cols{display:grid;grid-template-columns:minmax(0,1fr)"), "base .cols stays stacked single-column" ); - // The code variant stays stacked through the 768px breakpoint - // (overrides the generic .cols side-by-side there). + // No code-specific columns and no wide-screen split anywhere. + assert!(!css.contains(".cols-code"), "no code column variant"); assert!( - css.contains("@media (min-width:768px)"), - "768px breakpoint kept" + !css.contains("minmax(0,1.25fr)"), + "generic .cols no longer goes two-column" ); assert!( - css.contains("@media (min-width:1100px)"), - "1100px breakpoint present" + !css.contains("minmax(0,7fr)") && !css.contains("minmax(0,5fr)"), + "no desktop 7/5 files+README split" ); - let stacked_rule = ".cols-code{grid-template-columns:minmax(0,1fr)}"; assert!( - css.contains(stacked_rule), - "cols-code stays stacked below 1100px, got no {stacked_rule:?}" - ); - // Desktop: files 7/12 + README 5/12 inside the 1100px block. - let wide_rule = ".cols-code{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}"; - assert!( - css.contains(wide_rule), - "cols-code is 7/12 + 5/12 at >=1100px, got no {wide_rule:?}" - ); - let block_1100 = css - .split("@media (min-width:1100px)") - .nth(1) - .expect("1100px block"); - let first_chunk = block_1100.split("@media").next().expect("1100 chunk"); - assert!( - first_chunk.contains(".cols-code"), - "7/5 rule lives in the 1100px block" - ); - // Cascade order: the stacked 768px override comes before the 1100px - // two-column rule, so desktop wins and 768px–1099px stays stacked. - let stacked_pos = css.find(stacked_rule).expect("stacked rule pos"); - let wide_pos = css.find(wide_rule).expect("wide rule pos"); - assert!( - stacked_pos < wide_pos, - "stacked override precedes the 1100px two-column rule" + css.contains("@media (min-width:1100px)") && css.contains(".wrap{max-width:72rem"), + "wide layout keeps the readable content width" ); } -- 2.56.0