Skip to content

Commit ba77713

Browse files
committed
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 ba77713

File tree

5 files changed

+166
-41
lines changed

5 files changed

+166
-41
lines changed

Diff for: src/librustdoc/html/static/css/rustdoc.css

+110-4
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

@@ -675,7 +677,7 @@ ul.block, .block li, .block ul {
675677
overflow-wrap: break-word;
676678
}
677679

678-
.sidebar-crate + .version {
680+
.sidebar > .version {
679681
margin-top: -1rem;
680682
margin-bottom: 1rem;
681683
}
@@ -1853,6 +1855,110 @@ However, it's not needed with smaller screen width because the doc/code block is
18531855

18541856
/* Media Queries */
18551857

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

Diff for: src/librustdoc/html/static/js/main.js

+19-5
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);

Diff for: src/librustdoc/html/templates/page.html

+17-15
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> {# #}

Diff for: src/librustdoc/html/templates/sidebar.html

+12-9
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>

Diff for: tests/rustdoc-gui/sidebar.goml

+8-8
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,15 +112,15 @@ 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:
@@ -137,7 +137,7 @@ 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")
142142
assert-text: (".sidebar > .sidebar-elems > #ModNav > h2", "In lib2::module::sub_module")
143143
assert-property: (".sidebar > .sidebar-elems > #ModNav > h2 > a", {
@@ -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|,

0 commit comments

Comments
 (0)