diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 38154dee3e287..602a80c69b46f 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -34,6 +34,13 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\ '); --button-left-margin: 4px; --button-border-radius: 2px; + /* Used to manage the big screen three column layout */ + --width-limiter-width: 960px; + --desktop-grid-column-gap: 45px; + --container-border-radius: 6px; + /* height of header, plus header margin, plus top logo section */ + --desktop-grid-toc-top: calc((1.25 * 1.5rem) + 76px + 23px); + --desktop-grid-toc-max-width: 512px; } /* See FiraSans-LICENSE.txt for the Fira Sans license. */ @@ -336,7 +343,7 @@ button#toggle-all-docs { main { position: relative; flex-grow: 1; - padding: 10px 15px 40px 45px; + padding: 10px 15px 40px var(--desktop-grid-column-gap); min-width: 0; /* avoid growing beyond the size limit */ } @@ -345,7 +352,7 @@ main { } .width-limiter { - max-width: 960px; + max-width: var(--width-limiter-width); margin-right: auto; } @@ -369,6 +376,7 @@ pre { } pre.item-decl { overflow-x: auto; + border-radius: var(--container-border-radius); } /* This rule allows to have scrolling on the X axis. */ .item-decl .type-contents-toggle { @@ -460,7 +468,7 @@ img { .sidebar-resizing .sidebar { position: fixed; } -.sidebar-resizing > body { +.sidebar-resizing .rustdoc { padding-left: var(--resizing-sidebar-width); } @@ -534,7 +542,7 @@ img { scrollbar-width: initial; scrollbar-color: var(--scrollbar-color); } -.sidebar { +.sidebar, #rustdoc-toc section, #rustdoc-modnav section { scrollbar-width: thin; scrollbar-color: var(--scrollbar-color); } @@ -543,17 +551,24 @@ img { ::-webkit-scrollbar { width: 12px; } -.sidebar::-webkit-scrollbar { +.sidebar::-webkit-scrollbar, +#rustdoc-toc section::-webkit-scrollbar, +#rustdoc-modnav section::-webkit-scrollbar { width: 8px; } ::-webkit-scrollbar-track { -webkit-box-shadow: inset 0; background-color: var(--scrollbar-track-background-color); } -.sidebar::-webkit-scrollbar-track { +.sidebar::-webkit-scrollbar-track, +#rustdoc-toc section::-webkit-scrollbar-track, +#rustdoc-modnav section::-webkit-scrollbar-track { background-color: var(--scrollbar-track-background-color); } -::-webkit-scrollbar-thumb, .sidebar::-webkit-scrollbar-thumb { +::-webkit-scrollbar-thumb, +.sidebar::-webkit-scrollbar-thumb, +#rustdoc-toc section::-webkit-scrollbar-thumb, +#rustdoc-modnav section::-webkit-scrollbar-thumb { background-color: var(--scrollbar-thumb-background-color); } @@ -742,7 +757,7 @@ ul.block, .block li, .block ul { overflow-wrap: break-word; } -.sidebar-crate + .version { +.sidebar > .version { margin-top: -1rem; margin-bottom: 1rem; } @@ -760,7 +775,7 @@ ul.block, .block li, .block ul { .rustdoc .example-wrap > pre, .rustdoc .scraped-example .src-line-numbers, .rustdoc .scraped-example .src-line-numbers > pre { - border-radius: 6px; + border-radius: var(--container-border-radius); } /* @@ -2078,6 +2093,115 @@ However, it's not needed with smaller screen width because the doc/code block is /* Media Queries */ +/* Very-large-screen mode. */ +@supports (display: grid) and (display: contents) { + @media (min-width: 1600px) { + .rustdoc:not(.src) { + display: grid; + grid-template-columns: + var(--desktop-sidebar-width) + var(--width-limiter-width) + minmax(0, 1fr); + grid-template-rows: min-content 1fr; + grid-template-areas: + "sidebar-title main sidebar-cratenav" + "sidebar-modnav main sidebar-toc"; + grid-column-gap: var(--desktop-grid-column-gap); + } + .sidebar-resizing .rustdoc:not(.src) { + padding-left: 0; + } + .hide-sidebar .rustdoc:not(.src) { + grid-template-columns: + var(--width-limiter-width) + minmax(0, 1fr); + grid-template-rows: minmax(min-content, calc(64px + 0.75rem)) 1fr; + grid-template-areas: + "main sidebar-cratenav" + "main sidebar-toc"; + padding-left: var(--desktop-grid-column-gap); + } + .rustdoc:not(.src) .sidebar, + .rustdoc:not(.src) main { + display: contents; + } + .width-limiter { + grid-area: main; + width: var(--width-limiter-width); + --desktop-sidebar-width: 0; + } + .rustdoc:not(.src) nav.sub { + padding-top: 10px; + } + .rustdoc:not(.src) .doc-sidebar-title { + grid-area: sidebar-title; + background: var(--sidebar-background-color); + position: sticky; + top: 0; + } + .rustdoc:not(.src) .sidebar-crate { + margin-bottom: 0.5rem; + } + .rustdoc:not(.src) #rustdoc-toc, + .rustdoc:not(.src) #rustdoc-cratenav { + grid-area: sidebar-toc; + background: var(--main-background-color); + padding-left: 0; + } + .rustdoc:not(.src) #rustdoc-cratenav { + grid-area: sidebar-cratenav; + align-self: middle; + } + .rustdoc:not(.src) #rustdoc-modnav { + grid-area: sidebar-modnav; + background: var(--sidebar-background-color); + padding-left: 0; + } + .rustdoc:not(.src) #rustdoc-modnav .in-crate { + display: none; + } + .rustdoc:not(.src) #rustdoc-toc section, + .rustdoc:not(.src) #rustdoc-modnav section { + position: sticky; + top: 0; + bottom: 0; + overflow-y: scroll; + overscroll-behavior: contain; + max-height: 100vh; + padding-left: 24px; + } + .rustdoc:not(.src) #rustdoc-toc .location, + .rustdoc:not(.src) #rustdoc-modnav h2 { + margin-top: 0; + } + .rustdoc:not(.src) #rustdoc-modnav section { + top: calc(64px + 0.75rem); + height: calc(100vh - 64px - 0.75rem); + background: var(--sidebar-background-color); + } + .rustdoc:not(.src) #rustdoc-modnav section.scrolled { + border-top: solid 1px var(--border-color); + } + .rustdoc:not(.src) #rustdoc-toc section { + max-height: calc(100vh - (2 * var(--desktop-grid-toc-top))); + top: var(--desktop-grid-toc-top); + margin: 0 var(--desktop-grid-column-gap) var(--desktop-grid-column-gap) 0; + border: solid 1px var(--border-color); + padding: 14px 0 14px var(--sidebar-elems-left-padding); + border-radius: var(--container-border-radius); + max-width: var(--desktop-grid-toc-max-width); + } + .rustdoc:not(.src) #rustdoc-cratenav .block:last-child, + .rustdoc:not(.src) #rustdoc-toc .block:last-child { + margin-bottom: 0; + } + .rustdoc:not(.src) #rustdoc-cratenav a:hover, + .rustdoc:not(.src) #rustdoc-toc a:hover { + background-color: var(--sidebar-background-color); + } + } +} + /* Make sure all the buttons line wrap at the same time */ @media (max-width: 850px) { #search-tabs .count { diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 858753a1917d8..40ca61ff90782 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -499,7 +499,7 @@ function preLoadCss(cssUrl) { if (!window.SIDEBAR_ITEMS) { return; } - const sidebar = document.getElementById("rustdoc-modnav"); + const sidebar = document.querySelector("#rustdoc-modnav section"); /** * Append to the sidebar a "block" of links - a heading along with a list (` {# #} + +{% endif %} +{% if self.should_render_blocks() %} + diff --git a/tests/rustdoc-gui/sidebar-modnav-position.goml b/tests/rustdoc-gui/sidebar-modnav-position.goml index eb86d118ab22d..47a8da5c8a2af 100644 --- a/tests/rustdoc-gui/sidebar-modnav-position.goml +++ b/tests/rustdoc-gui/sidebar-modnav-position.goml @@ -9,7 +9,9 @@ // because the sibling module nav is in exactly the same place every time, // it's very easy to find and switch between pages that way. +// First, in tablet-ish mode go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" +set-window-size: (1280, 800) show-text: true set-local-storage: {"rustdoc-hide-toc": "true"} @@ -19,9 +21,9 @@ define-function: ( block { go-to: "file://" + |DOC_PATH| + |url| // Checking results colors. - assert-position: ("#rustdoc-modnav > h2", {"x": |h2_x|, "y": |h2_y|}) + assert-position: ("#rustdoc-modnav > section > h2", {"x": |h2_x|, "y": |h2_y|}) assert-position: ( - "#rustdoc-modnav > ul:first-of-type > li:first-of-type", + "#rustdoc-modnav > section > ul:first-of-type > li:first-of-type", {"x": |x|, "y": |y|} ) }, @@ -29,16 +31,33 @@ define-function: ( // First, at test_docs root go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" -store-position: ("#rustdoc-modnav > h2", {"x": h2_x, "y": h2_y}) -store-position: ("#rustdoc-modnav > ul:first-of-type > li:first-of-type", {"x": x, "y": y}) +store-position: ("#rustdoc-modnav > section > h2", {"x": h2_x, "y": h2_y}) +store-position: ("#rustdoc-modnav > section > ul:first-of-type > li:first-of-type", {"x": x, "y": y}) call-function: ("check-positions", {"url": "/test_docs/enum.WhoLetTheDogOut.html"}) call-function: ("check-positions", {"url": "/test_docs/struct.StructWithPublicUndocumentedFields.html"}) call-function: ("check-positions", {"url": "/test_docs/codeblock_sub/index.html"}) // Now in a submodule go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html" -store-position: ("#rustdoc-modnav > h2", {"x": h2_x, "y": h2_y}) -store-position: ("#rustdoc-modnav > ul:first-of-type > li:first-of-type", {"x": x, "y": y}) +store-position: ("#rustdoc-modnav > section > h2", {"x": h2_x, "y": h2_y}) +store-position: ("#rustdoc-modnav > section > ul:first-of-type > li:first-of-type", {"x": x, "y": y}) call-function: ("check-positions", {"url": "/test_docs/fields/struct.Struct.html"}) call-function: ("check-positions", {"url": "/test_docs/fields/union.Union.html"}) call-function: ("check-positions", {"url": "/test_docs/fields/enum.Enum.html"}) + +// Now try similar, but in desktop-ish mode +// Unlike in tablet mode, desktop mode pulls the TOC out of the main left sidebar into its own pane, +// so modnav (which remains in the left sidebar) doesn't move regardless. +// It also has the same position as the item-decl. +set-local-storage: {"rustdoc-hide-toc": "false"} +set-window-size: (1920, 1080) +go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" +store-position: ("#rustdoc-modnav > section > h2", {"x": h2_x, "y": h2_y}) +store-position: ("#rustdoc-modnav > section > ul:first-of-type > li:first-of-type", {"x": x, "y": y}) +call-function: ("check-positions", {"url": "/test_docs/enum.WhoLetTheDogOut.html"}) +compare-elements-position: ("#rustdoc-toc > section", ".item-decl", ["y"]) +compare-elements-css: ("#rustdoc-toc > section", ".item-decl", ["border-radius"]) +call-function: ("check-positions", {"url": "/test_docs/struct.StructWithPublicUndocumentedFields.html"}) +compare-elements-position: ("#rustdoc-toc > section", ".item-decl", ["y"]) +compare-elements-css: ("#rustdoc-toc > section", ".item-decl", ["border-radius"]) +call-function: ("check-positions", {"url": "/test_docs/codeblock_sub/index.html"}) diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index 7794cdbe9e264..2c42e84fed6b1 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -45,7 +45,7 @@ call-function: ( call-function: ("switch-theme", {"theme": "light"}) -assert-text: (".sidebar > .sidebar-crate > h2 > a", "test_docs") +assert-text: (".sidebar-crate > h2 > a", "test_docs") // Crate root has no "location" element assert-count: (".sidebar .location", 0) assert-count: (".sidebar h2", 1) @@ -69,7 +69,7 @@ assert-text: ("#structs + .item-table .item-name > a", "Foo") click: "#structs + .item-table .item-name > a" // PAGE: struct.Foo.html -assert-count: (".sidebar .sidebar-crate", 1) +assert-count: (".sidebar-crate", 1) assert-count: (".sidebar .location", 1) assert-count: (".sidebar h2", 3) assert-text: (".sidebar-elems ul.block > li.current > a", "Foo") @@ -91,7 +91,7 @@ click: ".sidebar-elems ul.crate > li:first-child > a" // PAGE: lib2/index.html go-to: "file://" + |DOC_PATH| + "/lib2/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) -assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") +assert-text: (".sidebar-crate > h2 > a", "lib2") assert-count: (".sidebar .location", 0) // We check that we have the crates list and that the "current" on is now "lib2". assert-text: (".sidebar-elems ul.crate > li.current > a", "lib2") @@ -108,7 +108,7 @@ click: "#functions + .item-table .item-name > a" // In items containing no items (like functions or constants) and in modules, we have no // "location" elements. Only the crate and optional parent module. // This page, being directly below the crate, only has its heading. -assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") +assert-text: (".sidebar-crate > h2 > a", "lib2") assert-count: (".sidebar .location", 0) assert-count: (".sidebar h2", 1) assert-text: (".sidebar-elems ul.block > li.current > a", "foobar") @@ -117,7 +117,7 @@ assert-false: ".sidebar-elems > .crate" go-to: "./module/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) -assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") +assert-text: (".sidebar-crate > h2 > a", "lib2") assert-text: (".sidebar .location", "Module module") assert-count: (".sidebar .location", 1) assert-text: (".sidebar-elems ul.block > li.current > a", "module") @@ -126,8 +126,8 @@ assert-text: (".sidebar-elems ul.block > li.current > a", "module") // - Module name, followed by TOC for module headings // - "In crate [name]" parent pointer, followed by sibling navigation assert-count: (".sidebar h2", 3) -assert-text: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2", "In crate lib2") -assert-property: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2 > a", { +assert-text: ("#rustdoc-modnav > section > h2", "In crate lib2") +assert-property: ("#rustdoc-modnav > section > h2 > a", { "href": "/lib2/index.html", }, ENDS_WITH) // We check that we don't have the crate list. @@ -135,10 +135,10 @@ assert-false: ".sidebar-elems > .crate" go-to: "./sub_module/sub_sub_module/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) -assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") +assert-text: (".sidebar-crate > h2 > a", "lib2") assert-text: (".sidebar .location", "Module sub_sub_module") -assert-text: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2", "In lib2::module::sub_module") -assert-property: (".sidebar > .sidebar-elems > #rustdoc-modnav > h2 > a", { +assert-text: ("#rustdoc-modnav > section > h2", "In lib2::module::sub_module") +assert-property: ("#rustdoc-modnav > section > h2 > a", { "href": "/module/sub_module/index.html", }, ENDS_WITH) assert-text: (".sidebar-elems ul.block > li.current > a", "sub_sub_module") @@ -170,14 +170,14 @@ assert-property: (".sidebar", {"clientWidth": "200"}) // Checks that all.html and index.html have their sidebar link in the same place. go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -store-property: (".sidebar .sidebar-crate h2 a", { +store-property: (".sidebar-crate h2 a", { "clientWidth": index_sidebar_width, "clientHeight": index_sidebar_height, "offsetTop": index_sidebar_y, "offsetLeft": index_sidebar_x, }) go-to: "file://" + |DOC_PATH| + "/test_docs/all.html" -assert-property: (".sidebar .sidebar-crate h2 a", { +assert-property: (".sidebar-crate h2 a", { "clientWidth": |index_sidebar_width|, "clientHeight": |index_sidebar_height|, "offsetTop": |index_sidebar_y|, diff --git a/tests/rustdoc/sidebar/module.rs b/tests/rustdoc/sidebar/module.rs index b5bcb9f232c75..c0a0df9616ea3 100644 --- a/tests/rustdoc/sidebar/module.rs +++ b/tests/rustdoc/sidebar/module.rs @@ -1,16 +1,16 @@ #![crate_name = "foo"] //@ has 'foo/index.html' -//@ has - '//section[@id="rustdoc-toc"]/h3' 'Crate Items' +//@ has - '//div[@id="rustdoc-toc"]/section/h3' 'Crate Items' //@ has 'foo/bar/index.html' -//@ has - '//section[@id="rustdoc-toc"]/h3' 'Module Items' +//@ has - '//div[@id="rustdoc-toc"]/section/h3' 'Module Items' pub mod bar { //@ has 'foo/bar/struct.Baz.html' - //@ !has - '//section[@id="rustdoc-toc"]/h3' 'Module Items' + //@ !has - '//div[@id="rustdoc-toc"]/section/h3' 'Module Items' pub struct Baz; } //@ has 'foo/baz/index.html' -//@ !has - '//section[@id="rustdoc-toc"]/h3' 'Module Items' +//@ !has - '//div[@id="rustdoc-toc"]/section/h3' 'Module Items' pub mod baz {} diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc/sidebar/top-toc-html.rs index 0f60396043475..e63f56c149973 100644 --- a/tests/rustdoc/sidebar/top-toc-html.rs +++ b/tests/rustdoc/sidebar/top-toc-html.rs @@ -14,10 +14,10 @@ //@ has foo/index.html // User header -//@ has - '//section[@id="rustdoc-toc"]/h3' 'Sections' -//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/@title' 'Basic link, emphasis, very emphasis and `code`' -//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]' 'Basic link, emphasis, very emphasis and code' -//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/em' 0 -//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/a' 0 -//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 1 -//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 'code' +//@ has - '//div[@id="rustdoc-toc"]//h3' 'Sections' +//@ has - '//div[@id="rustdoc-toc"]//ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/@title' 'Basic link, emphasis, very emphasis and `code`' +//@ has - '//div[@id="rustdoc-toc"]//ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]' 'Basic link, emphasis, very emphasis and code' +//@ count - '//div[@id="rustdoc-toc"]//ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/em' 0 +//@ count - '//div[@id="rustdoc-toc"]//ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/a' 0 +//@ count - '//div[@id="rustdoc-toc"]//ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 1 +//@ has - '//div[@id="rustdoc-toc"]//ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 'code' diff --git a/tests/rustdoc/sidebar/top-toc-idmap.rs b/tests/rustdoc/sidebar/top-toc-idmap.rs index af07cb4179b1f..a1b475ecf5b33 100644 --- a/tests/rustdoc/sidebar/top-toc-idmap.rs +++ b/tests/rustdoc/sidebar/top-toc-idmap.rs @@ -16,11 +16,11 @@ //@ has foo/index.html // User header -//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs' +//@ has - '//div[@id="rustdoc-toc"]//ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs' //@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="structs"]' 'Structs' // Built-in header -//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs' -//@ has - '//section[@id="main-content"]/h2[@id="structs-1"]' 'Structs' +//@ has - '//div[@id="rustdoc-toc"]//ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs' +//@ has - '//section[@id="main-content"]//h2[@id="structs-1"]' 'Structs' /// # Fields /// ## Fields @@ -31,12 +31,12 @@ //@ has foo/struct.MyStruct.html // User header -//@ has - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields' +//@ has - '//div[@id="rustdoc-toc"]//ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields' //@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="fields-1"]' 'Fields' // Only one level of nesting -//@ count - '//section[@id="rustdoc-toc"]/ul[@class="block top-toc"]//a' 2 +//@ count - '//div[@id="rustdoc-toc"]//ul[@class="block top-toc"]//a' 2 // Built-in header -//@ has - '//section[@id="rustdoc-toc"]/h3/a[@href="#fields"]' 'Fields' +//@ has - '//div[@id="rustdoc-toc"]//h3/a[@href="#fields"]' 'Fields' //@ has - '//section[@id="main-content"]/h2[@id="fields"]' 'Fields' pub struct MyStruct {