Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b222f02

Browse files
committedFeb 9, 2024
drustdoc: add three-column layout for large desktops
This commit adds a floating TOC box to the right, leaving the sibling/module/crate navigation on the left. This kicks in at a size a little below 1920x1080, where desktops with very wide monitors are: it's also around the point where the content area can be full width while allowing two sidebars. It only kicks in if the browser supports grid layouts, but that should be most of them, and we can't get rid of the two-column layout anyway, since it's the layout you get on something like a portrait iPad. This design, where it can be used, is meant to clearly split up the table of contents and the site navigation, so the right side floating box has the same color as the page while the left sidebar does not. It also pushes it down further, so that it's not as high as the search bar, though that's a bit more subtle than the color.
1 parent a1c1c10 commit b222f02

File tree

7 files changed

+190
-57
lines changed

7 files changed

+190
-57
lines changed
 

‎src/librustdoc/html/static/css/rustdoc.css

Lines changed: 122 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
--desktop-sidebar-width: 200px;
1616
--src-sidebar-width: 300px;
1717
--desktop-sidebar-z-index: 100;
18+
--width-limiter-width: 960px;
19+
--desktop-grid-column-gap: 45px;
1820
}
1921

2022
/* See FiraSans-LICENSE.txt for the Fira Sans license. */
@@ -317,7 +319,7 @@ button#toggle-all-docs {
317319
main {
318320
position: relative;
319321
flex-grow: 1;
320-
padding: 10px 15px 40px 45px;
322+
padding: 10px 15px 40px var(--desktop-grid-column-gap);
321323
min-width: 0; /* avoid growing beyond the size limit */
322324
}
323325

@@ -326,7 +328,7 @@ main {
326328
}
327329

328330
.width-limiter {
329-
max-width: 960px;
331+
max-width: var(--width-limiter-width);
330332
margin-right: auto;
331333
}
332334

@@ -441,7 +443,7 @@ img {
441443
.sidebar-resizing .sidebar {
442444
position: fixed;
443445
}
444-
.sidebar-resizing > body {
446+
.sidebar-resizing .rustdoc {
445447
padding-left: var(--resizing-sidebar-width);
446448
}
447449

@@ -515,7 +517,7 @@ img {
515517
scrollbar-width: initial;
516518
scrollbar-color: var(--scrollbar-color);
517519
}
518-
.sidebar {
520+
.sidebar, #TOC section, #ModNav section {
519521
scrollbar-width: thin;
520522
scrollbar-color: var(--scrollbar-color);
521523
}
@@ -524,17 +526,24 @@ img {
524526
::-webkit-scrollbar {
525527
width: 12px;
526528
}
527-
.sidebar::-webkit-scrollbar {
529+
.sidebar::-webkit-scrollbar,
530+
#TOC section::-webkit-scrollbar,
531+
#ModNav section::-webkit-scrollbar {
528532
width: 8px;
529533
}
530534
::-webkit-scrollbar-track {
531535
-webkit-box-shadow: inset 0;
532536
background-color: var(--scrollbar-track-background-color);
533537
}
534-
.sidebar::-webkit-scrollbar-track {
538+
.sidebar::-webkit-scrollbar-track,
539+
#TOC section::-webkit-scrollbar-track,
540+
#ModNav section::-webkit-scrollbar-track {
535541
background-color: var(--scrollbar-track-background-color);
536542
}
537-
::-webkit-scrollbar-thumb, .sidebar::-webkit-scrollbar-thumb {
543+
::-webkit-scrollbar-thumb,
544+
.sidebar::-webkit-scrollbar-thumb,
545+
#TOC section::-webkit-scrollbar-thumb,
546+
#ModNav section::-webkit-scrollbar-thumb {
538547
background-color: var(--scrollbar-thumb-background-color);
539548
}
540549

@@ -675,7 +684,7 @@ ul.block, .block li, .block ul {
675684
overflow-wrap: break-word;
676685
}
677686

678-
.sidebar-crate + .version {
687+
.sidebar > .version {
679688
margin-top: -1rem;
680689
margin-bottom: 1rem;
681690
}
@@ -1853,6 +1862,111 @@ However, it's not needed with smaller screen width because the doc/code block is
18531862

18541863
/* Media Queries */
18551864

1865+
/* Very-large-screen mode. */
1866+
@supports (display: grid) and (display: contents) {
1867+
@media (min-width: 1600px) and (min-height: 800px) {
1868+
.rustdoc:not(.src) {
1869+
display: grid;
1870+
grid-template-columns:
1871+
var(--desktop-sidebar-width)
1872+
var(--width-limiter-width)
1873+
minmax(0, 1fr);
1874+
grid-template-rows: min-content 1fr;
1875+
grid-template-areas:
1876+
"sidebar-title main sidebar-cratenav"
1877+
"sidebar-modnav main sidebar-toc";
1878+
grid-column-gap: var(--desktop-grid-column-gap);
1879+
}
1880+
.sidebar-resizing .rustdoc:not(.src) {
1881+
padding-left: 0;
1882+
}
1883+
.hide-sidebar .rustdoc:not(.src) {
1884+
grid-template-columns:
1885+
var(--width-limiter-width)
1886+
minmax(0, 1fr);
1887+
grid-template-rows: minmax(min-content, calc(64px + 0.75rem)) 1fr;
1888+
grid-template-areas:
1889+
"main sidebar-cratenav"
1890+
"main sidebar-toc";
1891+
padding-left: var(--desktop-grid-column-gap);
1892+
}
1893+
.rustdoc:not(.src) .sidebar,
1894+
.rustdoc:not(.src) main {
1895+
display: contents;
1896+
}
1897+
.width-limiter {
1898+
grid-area: main;
1899+
width: var(--width-limiter-width);
1900+
--desktop-sidebar-width: 0;
1901+
}
1902+
.rustdoc:not(.src) nav.sub {
1903+
padding-top: 10px;
1904+
}
1905+
.rustdoc:not(.src) .doc-sidebar-title {
1906+
grid-area: sidebar-title;
1907+
background: var(--sidebar-background-color);
1908+
position: sticky;
1909+
top: 0;
1910+
}
1911+
.rustdoc:not(.src) .sidebar-crate {
1912+
margin-bottom: 0.5rem;
1913+
}
1914+
.rustdoc:not(.src) #TOC,
1915+
.rustdoc:not(.src) #CrateNav {
1916+
grid-area: sidebar-toc;
1917+
background: var(--main-background-color);
1918+
padding-left: 0;
1919+
}
1920+
.rustdoc:not(.src) #CrateNav {
1921+
grid-area: sidebar-cratenav;
1922+
align-self: middle;
1923+
}
1924+
.rustdoc:not(.src) #ModNav {
1925+
grid-area: sidebar-modnav;
1926+
background: var(--sidebar-background-color);
1927+
padding-left: 0;
1928+
}
1929+
.rustdoc:not(.src) #ModNav .in-crate {
1930+
display: none;
1931+
}
1932+
.rustdoc:not(.src) #TOC section,
1933+
.rustdoc:not(.src) #ModNav section {
1934+
position: sticky;
1935+
top: 0;
1936+
bottom: 0;
1937+
overflow-y: scroll;
1938+
overscroll-behavior: contain;
1939+
max-height: 100vh;
1940+
padding-left: 24px;
1941+
}
1942+
.rustdoc:not(.src) #TOC .location,
1943+
.rustdoc:not(.src) #ModNav h2 {
1944+
margin-top: 0;
1945+
}
1946+
.rustdoc:not(.src) #ModNav section {
1947+
top: calc(64px + 0.75rem);
1948+
max-height: calc(100vh - 64px - 0.75rem);
1949+
background: var(--sidebar-background-color);
1950+
border-top: solid 1px var(--border-color);
1951+
}
1952+
.rustdoc:not(.src) #TOC section {
1953+
max-height: calc(100vh - 0.5rem);
1954+
top: 0.25rem;
1955+
margin: 0 var(--desktop-grid-column-gap) var(--desktop-grid-column-gap) 0;
1956+
border: solid 1px var(--border-color);
1957+
padding: 0.25rem;
1958+
}
1959+
.rustdoc:not(.src) #CrateNav .block:last-child,
1960+
.rustdoc:not(.src) #TOC .block:last-child {
1961+
margin-bottom: 0;
1962+
}
1963+
.rustdoc:not(.src) #CrateNav a:hover,
1964+
.rustdoc:not(.src) #TOC a:hover {
1965+
background-color: var(--sidebar-background-color);
1966+
}
1967+
}
1968+
}
1969+
18561970
/* Make sure all the buttons line wrap at the same time */
18571971
@media (max-width: 850px) {
18581972
#search-tabs .count {

‎src/librustdoc/html/static/js/main.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ function preLoadCss(cssUrl) {
460460
if (!window.SIDEBAR_ITEMS) {
461461
return;
462462
}
463-
const sidebar = document.getElementById("ModNav");
463+
const sidebar = document.querySelector("#ModNav section");
464464

465465
/**
466466
* Append to the sidebar a "block" of links - a heading along with a list (`<ul>`) of items.
@@ -496,11 +496,12 @@ function preLoadCss(cssUrl) {
496496
}
497497
const link = document.createElement("a");
498498
link.href = path;
499-
if (path === current_page) {
500-
link.className = "current";
501-
}
502499
link.textContent = name;
503500
const li = document.createElement("li");
501+
if (link.href.toString() === current_page) {
502+
link.className = "current";
503+
li.className = "current";
504+
}
504505
li.appendChild(link);
505506
ul.appendChild(li);
506507
}
@@ -845,7 +846,7 @@ function preLoadCss(cssUrl) {
845846
if (!window.ALL_CRATES) {
846847
return;
847848
}
848-
const sidebarElems = document.getElementById("ModNav");
849+
const sidebarElems = document.querySelector("#ModNav section");
849850
if (!sidebarElems) {
850851
return;
851852
}
@@ -1511,6 +1512,15 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
15111512
// At half-way past the minimum size, vanish the sidebar entirely
15121513
const SIDEBAR_VANISH_THRESHOLD = SIDEBAR_MIN / 2;
15131514

1515+
// When running in grid layout mode, we have to change sizes
1516+
// on the parent element. Otherwise, we can resize the sidebar
1517+
// independently.
1518+
//
1519+
// This is less bad than it otherwise would be, since if you are in grid
1520+
// mode, resizing the sidebar will resize the floating TOC, not the huge
1521+
// content area.
1522+
let gridMode = window.getComputedStyle(document.querySelector(".rustdoc")).display === "grid";
1523+
15141524
// Toolbar button to show the sidebar.
15151525
//
15161526
// On small, "mobile-sized" viewports, it's not persistent and it
@@ -1631,6 +1641,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
16311641
updateLocalStorage("desktop-sidebar-width", size);
16321642
sidebar.style.setProperty("--desktop-sidebar-width", size + "px");
16331643
resizer.style.setProperty("--desktop-sidebar-width", size + "px");
1644+
if (gridMode) {
1645+
document.documentElement.style.setProperty("--desktop-sidebar-width", size + "px");
1646+
}
16341647
}
16351648
}
16361649

@@ -1682,6 +1695,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
16821695
if (window.innerWidth < RUSTDOC_MOBILE_BREAKPOINT) {
16831696
return;
16841697
}
1698+
gridMode = window.getComputedStyle(document.querySelector(".rustdoc")).display === "grid";
16851699
stopResize();
16861700
if (desiredSidebarSize >= (window.innerWidth - BODY_MIN)) {
16871701
changeSidebarSize(window.innerWidth - BODY_MIN);

‎src/librustdoc/html/templates/page.html

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -91,22 +91,24 @@
9191
{% endif %}
9292
<nav class="sidebar"> {# #}
9393
{% if page.css_class != "src" %}
94-
<div class="sidebar-crate">
95-
{% if !layout.logo.is_empty() || page.rust_logo %}
96-
<a class="logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #}
97-
{% if page.rust_logo %}
98-
<img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
99-
{% else if !layout.logo.is_empty() %}
100-
<img src="{{layout.logo}}" alt="logo"> {# #}
94+
<div class="doc-sidebar-title">
95+
<div class="sidebar-crate">
96+
{% if !layout.logo.is_empty() || page.rust_logo %}
97+
<a class="logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #}
98+
{% if page.rust_logo %}
99+
<img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
100+
{% else if !layout.logo.is_empty() %}
101+
<img src="{{layout.logo}}" alt="logo"> {# #}
102+
{% endif %}
103+
</a> {# #}
101104
{% endif %}
102-
</a> {# #}
103-
{% endif %}
104-
<h2> {# #}
105-
<a href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">{{display_krate}}</a> {# #}
106-
{% if !display_krate_version_number.is_empty() %}
107-
<span class="version">{{+ display_krate_version_number}}</span>
108-
{% endif %}
109-
</h2> {# #}
105+
<h2> {# #}
106+
<a href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">{{display_krate}}</a> {# #}
107+
{% if !display_krate_version_number.is_empty() %}
108+
<span class="version">{{+ display_krate_version_number}}</span>
109+
{% endif %}
110+
</h2> {# #}
111+
</div> {# #}
110112
</div> {# #}
111113
{% if !display_krate_version_extra.is_empty() %}
112114
<div class="version">{{+ display_krate_version_extra}}</div> {# #}

‎src/librustdoc/html/templates/sidebar.html

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
<div class="sidebar-elems">
2-
{% if is_crate %}
1+
{% if is_crate %}
2+
<div class="sidebar-elems" id="CrateNav">
33
<ul class="block">
44
<li><a id="all-types" href="all.html">All Items</a></li> {# #}
55
</ul>
6-
{% endif %}
7-
8-
{% if self.should_render_blocks() %}
9-
<section id="TOC">
6+
</div>
7+
{% endif %}
8+
{% if self.should_render_blocks() %}
9+
<div class="sidebar-elems" id="TOC">
10+
<section>
1011
{% if !title.is_empty() %}
1112
<h2 class="location"> {# #}
1213
<a href="#">{{title_prefix}}{{title}}</a> {# #}
@@ -38,12 +39,14 @@ <h3> {# #}
3839
{% endif %}
3940
{% endfor %}
4041
</section>
41-
{% endif %}
42-
<div id="ModNav">
42+
</div>
43+
{% endif %}
44+
<div class="sidebar-elems" id="ModNav">
45+
<section>
4346
{% if !path.is_empty() %}
4447
<h2{% if parent_is_crate +%} class="in-crate"{% endif %}> {# #}
4548
<a href="{% if is_mod %}../{% endif %}index.html">In {{+ path}}</a> {# #}
4649
</h2> {# #}
4750
{% endif %}
48-
</div> {# #}
51+
</section> {# #}
4952
</div>

‎tests/rustdoc-gui/sidebar.goml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ set-local-storage: {"rustdoc-theme": "light"}
5050
// We reload the page so the local storage settings are being used.
5151
reload:
5252

53-
assert-text: (".sidebar > .sidebar-crate > h2 > a", "test_docs")
53+
assert-text: (".sidebar-crate > h2 > a", "test_docs")
5454
// Crate root has no "location" element
5555
assert-count: (".sidebar .location", 0)
5656
assert-count: (".sidebar h2", 1)
@@ -74,7 +74,7 @@ assert-text: ("#structs + .item-table .item-name > a", "Foo")
7474
click: "#structs + .item-table .item-name > a"
7575

7676
// PAGE: struct.Foo.html
77-
assert-count: (".sidebar .sidebar-crate", 1)
77+
assert-count: (".sidebar-crate", 1)
7878
assert-count: (".sidebar .location", 1)
7979
assert-count: (".sidebar h2", 3)
8080
// We check that there is no crate listed outside of the top level.
@@ -95,7 +95,7 @@ click: ".sidebar-elems ul.crate > li:first-child > a"
9595
// PAGE: lib2/index.html
9696
go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
9797
assert-property: (".sidebar", {"clientWidth": "200"})
98-
assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
98+
assert-text: (".sidebar-crate > h2 > a", "lib2")
9999
assert-count: (".sidebar .location", 0)
100100
// We check that we have the crates list and that the "current" on is now "lib2".
101101
assert-text: (".sidebar-elems ul.crate > li.current > a", "lib2")
@@ -112,35 +112,35 @@ click: "#functions + .item-table .item-name > a"
112112
// In items containing no items (like functions or constants) and in modules, we have no
113113
// "location" elements. Only the crate and optional parent module.
114114
// This page, being directly below the crate, only has its heading.
115-
assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
115+
assert-text: (".sidebar-crate > h2 > a", "lib2")
116116
assert-count: (".sidebar .location", 0)
117117
assert-count: (".sidebar h2", 1)
118118
// We check that we don't have the crate list.
119119
assert-false: ".sidebar-elems > .crate"
120120

121121
go-to: "./module/index.html"
122122
assert-property: (".sidebar", {"clientWidth": "200"})
123-
assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
123+
assert-text: (".sidebar-crate > h2 > a", "lib2")
124124
assert-text: (".sidebar .location", "Module module")
125125
assert-count: (".sidebar .location", 1)
126126
// Module page requires three headings:
127127
// - Presistent crate branding (name and version)
128128
// - Module name, followed by TOC for module headings
129129
// - "In crate [name]" parent pointer, followed by sibling navigation
130130
assert-count: (".sidebar h2", 3)
131-
assert-text: (".sidebar > .sidebar-elems > #ModNav > h2", "In crate lib2")
132-
assert-property: (".sidebar > .sidebar-elems > #ModNav > h2 > a", {
131+
assert-text: ("#ModNav > section > h2", "In crate lib2")
132+
assert-property: ("#ModNav > section > h2 > a", {
133133
"href": "/lib2/index.html",
134134
}, ENDS_WITH)
135135
// We check that we don't have the crate list.
136136
assert-false: ".sidebar-elems > .crate"
137137

138138
go-to: "./sub_module/sub_sub_module/index.html"
139139
assert-property: (".sidebar", {"clientWidth": "200"})
140-
assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2")
140+
assert-text: (".sidebar-crate > h2 > a", "lib2")
141141
assert-text: (".sidebar .location", "Module sub_sub_module")
142-
assert-text: (".sidebar > .sidebar-elems > #ModNav > h2", "In lib2::module::sub_module")
143-
assert-property: (".sidebar > .sidebar-elems > #ModNav > h2 > a", {
142+
assert-text: ("#ModNav > section > h2", "In lib2::module::sub_module")
143+
assert-property: ("#ModNav > section > h2 > a", {
144144
"href": "/module/sub_module/index.html",
145145
}, ENDS_WITH)
146146
// We check that we don't have the crate list.
@@ -171,14 +171,14 @@ assert-property: (".sidebar", {"clientWidth": "200"})
171171

172172
// Checks that all.html and index.html have their sidebar link in the same place.
173173
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
174-
store-property: (".sidebar .sidebar-crate h2 a", {
174+
store-property: (".sidebar-crate h2 a", {
175175
"clientWidth": index_sidebar_width,
176176
"clientHeight": index_sidebar_height,
177177
"offsetTop": index_sidebar_y,
178178
"offsetLeft": index_sidebar_x,
179179
})
180180
go-to: "file://" + |DOC_PATH| + "/test_docs/all.html"
181-
assert-property: (".sidebar .sidebar-crate h2 a", {
181+
assert-property: (".sidebar-crate h2 a", {
182182
"clientWidth": |index_sidebar_width|,
183183
"clientHeight": |index_sidebar_height|,
184184
"offsetTop": |index_sidebar_y|,

‎tests/rustdoc/sidebar/top-toc-html.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
1515
// @has foo/index.html
1616
// User header
17-
// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]' 'Basic link and emphasis'
18-
// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/em' 0
19-
// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/a' 0
17+
// @has - '//ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]' 'Basic link and emphasis'
18+
// @count - '//ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/em' 0
19+
// @count - '//ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/a' 0

‎tests/rustdoc/sidebar/top-toc-idmap.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
1717
// @has foo/index.html
1818
// User header
19-
// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs'
19+
// @has - '//ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs'
2020
// @has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="structs"]' 'Structs'
2121
// Built-in header
22-
// @has - '//section[@id="TOC"]/ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs'
22+
// @has - '//ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs'
2323
// @has - '//section[@id="main-content"]/h2[@id="structs-1"]' 'Structs'
2424

2525
/// # Fields
@@ -31,12 +31,12 @@
3131
3232
// @has foo/struct.MyStruct.html
3333
// User header
34-
// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields'
34+
// @has - '//ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields'
3535
// @has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="fields-1"]' 'Fields'
3636
// Only one level of nesting
37-
// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]//a' 2
37+
// @count - '//ul[@class="block top-toc"]//a' 2
3838
// Built-in header
39-
// @has - '//section[@id="TOC"]/h3/a[@href="#fields"]' 'Fields'
39+
// @has - '//*[@id="TOC"]/section/h3/a[@href="#fields"]' 'Fields'
4040
// @has - '//section[@id="main-content"]/h2[@id="fields"]' 'Fields'
4141

4242
pub struct MyStruct {

0 commit comments

Comments
 (0)
Please sign in to comment.