#65 stack Files then README on code tab (#120)

mergedpassopened
details
branches
master ← fix/stack-files-readme
issues
3c809870-aded-459e-af30-af4bed618b27
updated
id
04406831-4cae-4e33-964c-5dec3df2a7ff

Patch

.forge/issues/3c809870-aded-459e-af30-af4bed618b27/issue.md+20 −0
diff --git a/.forge/issues/3c809870-aded-459e-af30-af4bed618b27/issue.md b/.forge/issues/3c809870-aded-459e-af30-af4bed618b27/issue.mdnew file mode 100644index 0000000..486e236--- /dev/null+++ b/.forge/issues/3c809870-aded-459e-af30-af4bed618b27/issue.md@@ -0,0 +1,20 @@1+---2+id: 3c809870-aded-459e-af30-af4bed618b273+title: Stack Files then README on the code tab at every width4+state: open5+labels:6+- area:render7+assignees: []8+milestone: null9+created: 2026-10-28T11:10:17.690517388Z10+updated: null11+---12+## Problem13+14+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.15+16+## Fix17+18+- Keep Files and README in one stacked column at every width, in that order.19+- Remove the `.cols-code` 7/5 desktop rule and the generic `.cols` two-column override.20+- Update `tests/code_cols.rs` to assert there is no side-by-side rule and the DOM order stays Files → README.
src/build.rs+3 −3
diff --git a/src/build.rs b/src/build.rsindex 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<BuildSu19331933     ));19341934 19351935     body.push_str("</div>\n");1936-    // Stacked below 1100px; files + README sit side by side only at1937-    // >=1100px via .cols-code (m6/code-cols, f0rge #45, 7/12 + 5/12).1936+    // Files then README in one stacked column at every width (f0rge #120);1937+    // no desktop sidebar split.19381938     // Code tab file TABLE (m6 code-gitea, f0rge #33, Gitea-style) plus the19391939     // language mix bar (bytes share, Tokyo Night hues, no JS).19401940     // 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<BuildSu19471947         gitx::ignored_paths(repo, &files).unwrap_or_default();19481948     let lang_files: Vec<(String, u64)> = lang_rows(&blobs, &ignored);19491949     let lang_section = language_bar(&lang_files);1950-    body.push_str("<div class=\"cols cols-code\"><section class=\"code-files\"><h2>Files</h2>\n");1950+    body.push_str("<div class=\"cols\"><section class=\"code-files\"><h2>Files</h2>\n");19511951     body.push_str(&file_table_html("", &root_entries, None, &history));19521952     body.push_str(&lang_section);19531953     body.push_str("</section>\n<section class=\"code-readme\"><h2>README</h2>\n");
static/style.css+3 −11
diff --git a/static/style.css b/static/style.cssindex 33982a6..ee5bf41 100644--- a/static/style.css+++ b/static/style.css@@ -137,7 +137,7 @@ td code,th code{word-break:break-all}137137 /* List tables (m6/tables): long titles/shas wrap inside the scroll box; the # column stays narrow. */138138 td.title,td.sha{overflow-wrap:anywhere}139139 td.num{width:1%;white-space:nowrap}140-/* Single column on mobile; side-by-side only when it fits (>=768px). */140+/* Single-column stack; children keep DOM order. */141141 .cols{display:grid;grid-template-columns:minmax(0,1fr);gap:1.5rem;min-width:0}142142 .cols>section,.cols>div{min-width:0}143143 /* 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-align203203 .brand-lockup:focus-visible,.site-header .site-nav.nav-scroll a:focus-visible{outline:2px solid var(--blue);outline-offset:2px}204204 .site-header .brand{flex:none}205205 @media (min-width:768px){206-  .cols{grid-template-columns:minmax(0,1fr) minmax(0,1.25fr)}207206   .site-nav .wrap{gap:.25rem 1.25rem}208207   :root{--gap-head:1.25rem;--gap-content:1.5rem}209208   main{padding:1.5rem 0 3rem}210209 }211-/* Code tab two columns (m6/code-cols, f0rge #45): files + README share212-   the existing .cols grid; the code variant stays stacked below 1100px213-   so 360px-1099px never squeezes the file table. At >=1100px files take214-   7/12 and README 5/12 for a readable line length. Stacked override first215-   so the later 1100px rule wins the cascade on desktop. */216-@media (min-width:768px){217-  .cols-code{grid-template-columns:minmax(0,1fr)}218-}210+/* The code tab is always one stacked column: Files, then README.211+   No desktop 7/5 split; the file table keeps the full content width. */219212 @media (min-width:1100px){220213   .wrap{max-width:72rem;padding:0 1.5rem}221-  .cols-code{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}222214 }223215 /* Code conventions (m6, f0rge #20): breadcrumbs, file meta, line anchors, clone block. */224216 .crumbs{margin:var(--gap-head) 0 .5rem;font-size:.95rem}
tests/code_cols.rs+23 −44
diff --git a/tests/code_cols.rs b/tests/code_cols.rsindex 73a3ccb..c73a045 100644--- a/tests/code_cols.rs+++ b/tests/code_cols.rs@@ -1,6 +1,6 @@1-//! Code tab two columns (m6, f0rge issue #45):2-//! files + README share the existing `.cols` grid, side by side only at3-//! >=1100px (files 7/12, README 5/12), stacked below.1+//! Code tab stack (f0rge issue #120):2+//! files and README share one stacked `.cols` column at every width, in3+//! DOM order Files then README. No desktop sidebar split.44 //!55 //! Builds a small fixture repo with the real binary and string-asserts on66 //! the emitted HTML + `static/style.css` (no rendering engine needed).@@ -76,15 +76,19 @@ fn css() -> String {7676 }7777 7878 #[test]79-fn code_tab_wraps_files_and_readme_in_cols_code() {79+fn code_tab_wraps_files_and_readme_in_stacked_column() {8080     let out = build_fixture();8181     let index = std::fs::read_to_string(out.join("index.html")).expect("index");82-    // Wrapper reuses the existing .cols pattern with the code variant.82+    // Wrapper is one plain stacked grid; no code-specific column variant.8383     assert!(84-        index.contains("<div class=\"cols cols-code\">"),85-        "code tab wraps files + README in .cols.cols-code"84+        index.contains("<div class=\"cols\">"),85+        "code tab wraps files + README in .cols"8686     );87-    // Two sections in order: files (table) left, README right.87+    assert!(88+        !index.contains("cols-code"),89+        "no dead side-by-side class in the markup"90+    );91+    // Two sections in order: files first, then README.8892     let files_pos = index8993         .find("<section class=\"code-files\">")9094         .expect("files section");@@ -102,7 +106,7 @@ fn code_tab_wraps_files_and_readme_in_cols_code() {102106     );103107     assert!(104108         files_block.contains("file-table"),105-        "file table lives in the files (left) column"109+        "file table lives in the files section"106110     );107111     let readme_block = &index[readme_pos..];108112     assert!(@@ -111,12 +115,12 @@ fn code_tab_wraps_files_and_readme_in_cols_code() {111115     );112116     assert!(113117         readme_block.contains("cols fixture"),114-        "README body renders in the right column"118+        "README body renders after the file table"115119     );116120 }117121 118122 #[test]119-fn code_cols_breakpoint_is_1100px_stacked_below() {123+fn code_tab_is_always_stacked() {120124     let css = css();121125     // Mobile-first base: .cols is a single stacked column.122126     let base = css.split("@media (min-width").next().expect("base css");@@ -124,42 +128,18 @@ fn code_cols_breakpoint_is_1100px_stacked_below() {124128         base.contains(".cols{display:grid;grid-template-columns:minmax(0,1fr)"),125129         "base .cols stays stacked single-column"126130     );127-    // The code variant stays stacked through the 768px breakpoint128-    // (overrides the generic .cols side-by-side there).131+    // No code-specific columns and no wide-screen split anywhere.132+    assert!(!css.contains(".cols-code"), "no code column variant");129133     assert!(130-        css.contains("@media (min-width:768px)"),131-        "768px breakpoint kept"134+        !css.contains("minmax(0,1.25fr)"),135+        "generic .cols no longer goes two-column"132136     );133137     assert!(134-        css.contains("@media (min-width:1100px)"),135-        "1100px breakpoint present"138+        !css.contains("minmax(0,7fr)") && !css.contains("minmax(0,5fr)"),139+        "no desktop 7/5 files+README split"136140     );137-    let stacked_rule = ".cols-code{grid-template-columns:minmax(0,1fr)}";138141     assert!(139-        css.contains(stacked_rule),140-        "cols-code stays stacked below 1100px, got no {stacked_rule:?}"141-    );142-    // Desktop: files 7/12 + README 5/12 inside the 1100px block.143-    let wide_rule = ".cols-code{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}";144-    assert!(145-        css.contains(wide_rule),146-        "cols-code is 7/12 + 5/12 at >=1100px, got no {wide_rule:?}"147-    );148-    let block_1100 = css149-        .split("@media (min-width:1100px)")150-        .nth(1)151-        .expect("1100px block");152-    let first_chunk = block_1100.split("@media").next().expect("1100 chunk");153-    assert!(154-        first_chunk.contains(".cols-code"),155-        "7/5 rule lives in the 1100px block"156-    );157-    // Cascade order: the stacked 768px override comes before the 1100px158-    // two-column rule, so desktop wins and 768px–1099px stays stacked.159-    let stacked_pos = css.find(stacked_rule).expect("stacked rule pos");160-    let wide_pos = css.find(wide_rule).expect("wide rule pos");161-    assert!(162-        stacked_pos < wide_pos,163-        "stacked override precedes the 1100px two-column rule"142+        css.contains("@media (min-width:1100px)") && css.contains(".wrap{max-width:72rem"),143+        "wide layout keeps the readable content width"164144     );165145 }166-- 2.56.0

Comments (0)

No comments yet.

Reviews (0)

No reviews yet.

all pulls