-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rustdoc: add three-column layout for large desktops #120818
base: master
Are you sure you want to change the base?
Conversation
This comment has been minimized.
This comment has been minimized.
ba77713
to
c0f7d2a
Compare
This comment has been minimized.
This comment has been minimized.
c0f7d2a
to
cf5d33a
Compare
This comment has been minimized.
This comment has been minimized.
cf5d33a
to
b222f02
Compare
The UI is very weird, it adds new lines in the left sidebar and a floating menu on the right. Wouldn't it be possible to not make it stand out as much? Like just having a border on the left and making it take the "full space" on the right and top? |
I'm not sure what to add that I didn't already mention in the Rationale and Alternatives section:
The line in the left sidebar could be removed, but is mostly meant to work like the one in the Source Files viewer, since its scroll behavior is the same. |
Isn't it possible to "cheat" in order to make it look like a plain sidebar while keeping it in the same scroll interactions? |
You could hide the scollbar of the sidebar and then manually scroll it via javascript to keep it in sync with the section the main page is showing. This would only be necessary if the TOC is longer than a screen height anyway. |
Let's not. The content of the TOC can be part of the main page (so sharing the same scroll). |
Are you thinking of having it work like this? Screencast.from.2024-02-12.10-31-32.webmI'm not sure that's useful. The page is so much longer than the TOC. If you click anything in the TOC, it's basically guaranteed to disappear, and you have to scroll back to the top to get to it.
That doesn't seem unusual, since trait implementations and methods are listed in there. That's not a SpidersGeorg type. Those are all very basic, normall error-ish trait implementations, and there's enough of them to fill the page. |
Yeah I think vertical menus that only show the name and nothing else just take up way too much space for the limited value they provide. They just don't strike the right balance imo. But if one doesn't already know what one is looking for then a summary that's more verbose than just the name but more concise than the full docs would help. For an alternative design look at javadocs. For interfaces they have a horizontal list: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Map.html I'm not saying javadocs strike the perfect balance on everything, but imo in at least those two aspects they're doing better than rustdoc |
I haven't reviewed this yet because I'm assuming this is effectively
S-waiting-on-team
|
☔ The latest upstream changes (presumably #123725) made this pull request unmergeable. Please resolve the merge conflicts. |
b222f02
to
ed2a442
Compare
This comment has been minimized.
This comment has been minimized.
ed2a442
to
8c4f552
Compare
Looking at it again, apart from some small UI tweaks (like more padding and rounded corners), it seems fine to me. The more I look at this feature, the more I like it :D |
Radius and padding look good! For the top position, I'd put it at the same level as the search input. Like that it's not fully at the top but also doesn't stand out too much (although, the second image's position would be ok for me too). |
8c4f552
to
c8be2ae
Compare
Okay, I pushed up a new version, but I put it at the same level as the item-decl. That is, I made it look like this (dash line added for visibility; there's also a goml test for it), and also gave them the same border-radius: |
Looks all good to me now, thanks! |
☔ The latest upstream changes (presumably #128252) made this pull request unmergeable. Please resolve the merge conflicts. |
c8be2ae
to
1d9c998
Compare
rustdoc: add header map to the table of contents ## Summary Add header sections to the sidebar TOC. ### Preview ![image](https://github.com/user-attachments/assets/eae4df02-86aa-4df4-8c61-a95685cd8829) * http://notriddle.com/rustdoc-html-demo-9/toc/rust/std/index.html * http://notriddle.com/rustdoc-html-demo-9/toc/rust-derive-builder/derive_builder/index.html ## Motivation Some pages are very wordy, like these. | crate | word count | |--|--| | [std::option](https://doc.rust-lang.org/stable/std/option/index.html) | 2,138 | [derive_builder](https://docs.rs/derive_builder/0.13.0/derive_builder/index.html) | 2,403 | [tracing](https://docs.rs/tracing/0.1.40/tracing/index.html) | 3,912 | [regex](https://docs.rs/regex/1.10.3/regex/index.html) | 8,412 This kind of very long document is more navigable with a table of contents, like Wikipedia's or the one [GitHub recently added](https://github.blog/changelog/2021-04-13-table-of-contents-support-in-markdown-files/) for READMEs. In fact, the use case is so compelling, that it's been requested multiple times and implemented in an extension: * rust-lang#80858 * rust-lang#28056 * rust-lang#14475 * https://rust.extension.sh/#show-table-of-content (Some of these issues ask for more than this, so don’t close them.) It's also been implemented by hand in some crates, because the author really thought it was needed. Protip: for a more exhaustive list, run [`site:docs.rs table of contents`](https://duckduckgo.com/?t=ffab&q=site%3Adocs.rs+table+of+contents&ia=web), though some of them are false positives. * https://docs.rs/figment/0.10.14/figment/index.html#table-of-contents * https://docs.rs/csv/1.3.0/csv/tutorial/index.html#table-of-contents * https://docs.rs/axum/0.7.4/axum/response/index.html#table-of-contents * https://docs.rs/regex-automata/0.4.5/regex_automata/index.html#table-of-contents Unfortunately for these hand-built ToCs, because they're just part of the docs, there's no consistent way to turn them off if the reader doesn't want them. It's also more complicated to ensure they stay in sync with the docs they're supposed to describe, and they don't stay with you when you scroll like Wikipedia's [does now](https://uxdesign.cc/design-notes-on-the-2023-wikipedia-redesign-d6573b9af28d). ## Guide-level explanation When writing docs for a top-level item, the first and second level of headers will be shown in an outline in the sidebar. In this context, "top level" means "not associated". This means, if you're writing very long guides or explanations, and you want it to have a table of contents in the sidebar for its headings, the ideal place to attach it is usually the *module* or *crate*, because this page has fewer other things on it (and is the ideal place to describe "cross-cutting concerns" for its child items). If you're reading documentation, and want to get rid of the table of contents, open the ![image](https://github.com/rust-lang/rust/assets/1593513/2ad82466-5fe3-4684-b1c2-6be4c99a8666) Settings panel and checkmark "Hide table of contents." ## Reference-level explanation Top-level items have an outline generated. This works for potentially-malformed header trees by pairing a header with the nearest header with a higher level. For example: ```markdown ## A # B # C ## D ## E ``` A, B, and C are all siblings, and D and E are children of C. Rustdoc only presents two layers of tree, but it tracks up to the full depth of 6 while preparing it. That means that these two doc comment both generate the same outline: ```rust /// # First /// ## Second struct One; /// ## First /// ### Second struct Two; ``` ## Drawbacks The biggest drawback is adding more stuff to the sidebar. My crawl through docs.rs shows this to, surprisingly, be less of a problem than I thought. The manually-built tables of contents, and the pages with dozens of headers, usually seem to be modules or crates, not types (where extreme scrolling would become a problem, since they already have methods to deal with). The best example of a type with many headers is [vec::Vec](https://doc.rust-lang.org/1.75.0/std/vec/struct.Vec.html), which still only has five headers, not dozens like [axum::extract](https://docs.rs/axum/0.7.4/axum/extract/index.html). ## Rationale and alternatives ### Why in the existing sidebar? The method links and the top-doc header links have more in common with each other than either of them do with the "In [parent module]" links, and should go together. ### Why limited to two levels? The sidebar is pretty narrow, and I don't want too much space used by indentation. Making the sidebar wider, while it has some upsides, also takes up more space on middling-sized screens or tiled WMs. ### Why not line wrap? That behaves strangely when resizing. ## Prior art ### Doc generators that have TOC for headers https://hexdocs.pm/phoenix/Phoenix.Controller.html is very close, in the sense that it also has header sections directly alongside functions and types. Another example, referenced as part of the [early sidebar discussion](rust-lang#37856) that added methods, Ruby will show a table of contents in the sidebar (for example, on the [ARGF](https://docs.ruby-lang.org/en/master/ARGF.html) class). According to their changelog, [they added it in 2013](https://github.com/ruby/rdoc/blob/06137bde8ccc48cd502bc28178bcd8f2dfe37624/History.rdoc#400--2013-02-24-). Haskell seems to mix text and functions even more freely than Elixir. For example, this [Naming conventions](https://hackage.haskell.org/package/base-4.19.0.0/docs/Control-Monad.html#g:3) is plain text, and is immediately followed by functions. And the [Pandoc top level](https://hackage.haskell.org/package/pandoc-3.1.11.1/docs/Text-Pandoc.html) has items split up by function, rather than by kind. Their TOC matches exactly with the contents of the page. ### Doc generators that don't have header TOC, but still have headers Elm, interestingly enough, seems to have the same setup that Rust used to have: sibling navigation between modules, and no index within a single page. [They keep Haskell's habit of named sections with machine-generated type signatures](https://package.elm-lang.org/packages/elm/browser/latest/Browser-Dom), though. [PHP](https://www.php.net/manual/en/book.datetime.php), like elm, also has a right-hand sidebar with sibling navigation. However, PHP has a single page for a single method, unlike Rust's page for an entire "class." So even though these pages have headers, it's never more than ten at most. And when they have guides, those guides are also multi-page. ## Unresolved questions * Writing recommendations for anyone who wants to take advantage of this. * Right now, it does not line wrap. That might be a bad idea: a lot of these are getting truncated. * Split sidebars, which I [tried implementing](https://rust-lang.zulipchat.com/#narrow/stream/266220-t-rustdoc/topic/Table.20of.20contents), are not required. The TOC can be turned off, if it's really a problem. Implemented in rust-lang#120818, but needs more, separate, discussion. ## Future possibilities I would like to do a better job of distinguishing global navigation from local navigation. Rustdoc has a pretty reasonable information architecture, if only we did a better job of communicating it. This PR aims, mostly, to help doc authors help their users by writing docs that can be more effectively skimmed. But it doesn't do anything to make it easier to tell the TOC and the Module Nav apart.
rustdoc: add header map to the table of contents ## Summary Add header sections to the sidebar TOC. ### Preview ![image](https://github.com/user-attachments/assets/eae4df02-86aa-4df4-8c61-a95685cd8829) * http://notriddle.com/rustdoc-html-demo-9/toc/rust/std/index.html * http://notriddle.com/rustdoc-html-demo-9/toc/rust-derive-builder/derive_builder/index.html ## Motivation Some pages are very wordy, like these. | crate | word count | |--|--| | [std::option](https://doc.rust-lang.org/stable/std/option/index.html) | 2,138 | [derive_builder](https://docs.rs/derive_builder/0.13.0/derive_builder/index.html) | 2,403 | [tracing](https://docs.rs/tracing/0.1.40/tracing/index.html) | 3,912 | [regex](https://docs.rs/regex/1.10.3/regex/index.html) | 8,412 This kind of very long document is more navigable with a table of contents, like Wikipedia's or the one [GitHub recently added](https://github.blog/changelog/2021-04-13-table-of-contents-support-in-markdown-files/) for READMEs. In fact, the use case is so compelling, that it's been requested multiple times and implemented in an extension: * rust-lang#80858 * rust-lang#28056 * rust-lang#14475 * https://rust.extension.sh/#show-table-of-content (Some of these issues ask for more than this, so don’t close them.) It's also been implemented by hand in some crates, because the author really thought it was needed. Protip: for a more exhaustive list, run [`site:docs.rs table of contents`](https://duckduckgo.com/?t=ffab&q=site%3Adocs.rs+table+of+contents&ia=web), though some of them are false positives. * https://docs.rs/figment/0.10.14/figment/index.html#table-of-contents * https://docs.rs/csv/1.3.0/csv/tutorial/index.html#table-of-contents * https://docs.rs/axum/0.7.4/axum/response/index.html#table-of-contents * https://docs.rs/regex-automata/0.4.5/regex_automata/index.html#table-of-contents Unfortunately for these hand-built ToCs, because they're just part of the docs, there's no consistent way to turn them off if the reader doesn't want them. It's also more complicated to ensure they stay in sync with the docs they're supposed to describe, and they don't stay with you when you scroll like Wikipedia's [does now](https://uxdesign.cc/design-notes-on-the-2023-wikipedia-redesign-d6573b9af28d). ## Guide-level explanation When writing docs for a top-level item, the first and second level of headers will be shown in an outline in the sidebar. In this context, "top level" means "not associated". This means, if you're writing very long guides or explanations, and you want it to have a table of contents in the sidebar for its headings, the ideal place to attach it is usually the *module* or *crate*, because this page has fewer other things on it (and is the ideal place to describe "cross-cutting concerns" for its child items). If you're reading documentation, and want to get rid of the table of contents, open the ![image](https://github.com/rust-lang/rust/assets/1593513/2ad82466-5fe3-4684-b1c2-6be4c99a8666) Settings panel and checkmark "Hide table of contents." ## Reference-level explanation Top-level items have an outline generated. This works for potentially-malformed header trees by pairing a header with the nearest header with a higher level. For example: ```markdown ## A # B # C ## D ## E ``` A, B, and C are all siblings, and D and E are children of C. Rustdoc only presents two layers of tree, but it tracks up to the full depth of 6 while preparing it. That means that these two doc comment both generate the same outline: ```rust /// # First /// ## Second struct One; /// ## First /// ### Second struct Two; ``` ## Drawbacks The biggest drawback is adding more stuff to the sidebar. My crawl through docs.rs shows this to, surprisingly, be less of a problem than I thought. The manually-built tables of contents, and the pages with dozens of headers, usually seem to be modules or crates, not types (where extreme scrolling would become a problem, since they already have methods to deal with). The best example of a type with many headers is [vec::Vec](https://doc.rust-lang.org/1.75.0/std/vec/struct.Vec.html), which still only has five headers, not dozens like [axum::extract](https://docs.rs/axum/0.7.4/axum/extract/index.html). ## Rationale and alternatives ### Why in the existing sidebar? The method links and the top-doc header links have more in common with each other than either of them do with the "In [parent module]" links, and should go together. ### Why limited to two levels? The sidebar is pretty narrow, and I don't want too much space used by indentation. Making the sidebar wider, while it has some upsides, also takes up more space on middling-sized screens or tiled WMs. ### Why not line wrap? That behaves strangely when resizing. ## Prior art ### Doc generators that have TOC for headers https://hexdocs.pm/phoenix/Phoenix.Controller.html is very close, in the sense that it also has header sections directly alongside functions and types. Another example, referenced as part of the [early sidebar discussion](rust-lang#37856) that added methods, Ruby will show a table of contents in the sidebar (for example, on the [ARGF](https://docs.ruby-lang.org/en/master/ARGF.html) class). According to their changelog, [they added it in 2013](https://github.com/ruby/rdoc/blob/06137bde8ccc48cd502bc28178bcd8f2dfe37624/History.rdoc#400--2013-02-24-). Haskell seems to mix text and functions even more freely than Elixir. For example, this [Naming conventions](https://hackage.haskell.org/package/base-4.19.0.0/docs/Control-Monad.html#g:3) is plain text, and is immediately followed by functions. And the [Pandoc top level](https://hackage.haskell.org/package/pandoc-3.1.11.1/docs/Text-Pandoc.html) has items split up by function, rather than by kind. Their TOC matches exactly with the contents of the page. ### Doc generators that don't have header TOC, but still have headers Elm, interestingly enough, seems to have the same setup that Rust used to have: sibling navigation between modules, and no index within a single page. [They keep Haskell's habit of named sections with machine-generated type signatures](https://package.elm-lang.org/packages/elm/browser/latest/Browser-Dom), though. [PHP](https://www.php.net/manual/en/book.datetime.php), like elm, also has a right-hand sidebar with sibling navigation. However, PHP has a single page for a single method, unlike Rust's page for an entire "class." So even though these pages have headers, it's never more than ten at most. And when they have guides, those guides are also multi-page. ## Unresolved questions * Writing recommendations for anyone who wants to take advantage of this. * Right now, it does not line wrap. That might be a bad idea: a lot of these are getting truncated. * Split sidebars, which I [tried implementing](https://rust-lang.zulipchat.com/#narrow/stream/266220-t-rustdoc/topic/Table.20of.20contents), are not required. The TOC can be turned off, if it's really a problem. Implemented in rust-lang#120818, but needs more, separate, discussion. ## Future possibilities I would like to do a better job of distinguishing global navigation from local navigation. Rustdoc has a pretty reasonable information architecture, if only we did a better job of communicating it. This PR aims, mostly, to help doc authors help their users by writing docs that can be more effectively skimmed. But it doesn't do anything to make it easier to tell the TOC and the Module Nav apart.
Rollup merge of rust-lang#120736 - notriddle:notriddle/toc, r=t-rustdoc rustdoc: add header map to the table of contents ## Summary Add header sections to the sidebar TOC. ### Preview ![image](https://github.com/user-attachments/assets/eae4df02-86aa-4df4-8c61-a95685cd8829) * http://notriddle.com/rustdoc-html-demo-9/toc/rust/std/index.html * http://notriddle.com/rustdoc-html-demo-9/toc/rust-derive-builder/derive_builder/index.html ## Motivation Some pages are very wordy, like these. | crate | word count | |--|--| | [std::option](https://doc.rust-lang.org/stable/std/option/index.html) | 2,138 | [derive_builder](https://docs.rs/derive_builder/0.13.0/derive_builder/index.html) | 2,403 | [tracing](https://docs.rs/tracing/0.1.40/tracing/index.html) | 3,912 | [regex](https://docs.rs/regex/1.10.3/regex/index.html) | 8,412 This kind of very long document is more navigable with a table of contents, like Wikipedia's or the one [GitHub recently added](https://github.blog/changelog/2021-04-13-table-of-contents-support-in-markdown-files/) for READMEs. In fact, the use case is so compelling, that it's been requested multiple times and implemented in an extension: * rust-lang#80858 * rust-lang#28056 * rust-lang#14475 * https://rust.extension.sh/#show-table-of-content (Some of these issues ask for more than this, so don’t close them.) It's also been implemented by hand in some crates, because the author really thought it was needed. Protip: for a more exhaustive list, run [`site:docs.rs table of contents`](https://duckduckgo.com/?t=ffab&q=site%3Adocs.rs+table+of+contents&ia=web), though some of them are false positives. * https://docs.rs/figment/0.10.14/figment/index.html#table-of-contents * https://docs.rs/csv/1.3.0/csv/tutorial/index.html#table-of-contents * https://docs.rs/axum/0.7.4/axum/response/index.html#table-of-contents * https://docs.rs/regex-automata/0.4.5/regex_automata/index.html#table-of-contents Unfortunately for these hand-built ToCs, because they're just part of the docs, there's no consistent way to turn them off if the reader doesn't want them. It's also more complicated to ensure they stay in sync with the docs they're supposed to describe, and they don't stay with you when you scroll like Wikipedia's [does now](https://uxdesign.cc/design-notes-on-the-2023-wikipedia-redesign-d6573b9af28d). ## Guide-level explanation When writing docs for a top-level item, the first and second level of headers will be shown in an outline in the sidebar. In this context, "top level" means "not associated". This means, if you're writing very long guides or explanations, and you want it to have a table of contents in the sidebar for its headings, the ideal place to attach it is usually the *module* or *crate*, because this page has fewer other things on it (and is the ideal place to describe "cross-cutting concerns" for its child items). If you're reading documentation, and want to get rid of the table of contents, open the ![image](https://github.com/rust-lang/rust/assets/1593513/2ad82466-5fe3-4684-b1c2-6be4c99a8666) Settings panel and checkmark "Hide table of contents." ## Reference-level explanation Top-level items have an outline generated. This works for potentially-malformed header trees by pairing a header with the nearest header with a higher level. For example: ```markdown ## A # B # C ## D ## E ``` A, B, and C are all siblings, and D and E are children of C. Rustdoc only presents two layers of tree, but it tracks up to the full depth of 6 while preparing it. That means that these two doc comment both generate the same outline: ```rust /// # First /// ## Second struct One; /// ## First /// ### Second struct Two; ``` ## Drawbacks The biggest drawback is adding more stuff to the sidebar. My crawl through docs.rs shows this to, surprisingly, be less of a problem than I thought. The manually-built tables of contents, and the pages with dozens of headers, usually seem to be modules or crates, not types (where extreme scrolling would become a problem, since they already have methods to deal with). The best example of a type with many headers is [vec::Vec](https://doc.rust-lang.org/1.75.0/std/vec/struct.Vec.html), which still only has five headers, not dozens like [axum::extract](https://docs.rs/axum/0.7.4/axum/extract/index.html). ## Rationale and alternatives ### Why in the existing sidebar? The method links and the top-doc header links have more in common with each other than either of them do with the "In [parent module]" links, and should go together. ### Why limited to two levels? The sidebar is pretty narrow, and I don't want too much space used by indentation. Making the sidebar wider, while it has some upsides, also takes up more space on middling-sized screens or tiled WMs. ### Why not line wrap? That behaves strangely when resizing. ## Prior art ### Doc generators that have TOC for headers https://hexdocs.pm/phoenix/Phoenix.Controller.html is very close, in the sense that it also has header sections directly alongside functions and types. Another example, referenced as part of the [early sidebar discussion](rust-lang#37856) that added methods, Ruby will show a table of contents in the sidebar (for example, on the [ARGF](https://docs.ruby-lang.org/en/master/ARGF.html) class). According to their changelog, [they added it in 2013](https://github.com/ruby/rdoc/blob/06137bde8ccc48cd502bc28178bcd8f2dfe37624/History.rdoc#400--2013-02-24-). Haskell seems to mix text and functions even more freely than Elixir. For example, this [Naming conventions](https://hackage.haskell.org/package/base-4.19.0.0/docs/Control-Monad.html#g:3) is plain text, and is immediately followed by functions. And the [Pandoc top level](https://hackage.haskell.org/package/pandoc-3.1.11.1/docs/Text-Pandoc.html) has items split up by function, rather than by kind. Their TOC matches exactly with the contents of the page. ### Doc generators that don't have header TOC, but still have headers Elm, interestingly enough, seems to have the same setup that Rust used to have: sibling navigation between modules, and no index within a single page. [They keep Haskell's habit of named sections with machine-generated type signatures](https://package.elm-lang.org/packages/elm/browser/latest/Browser-Dom), though. [PHP](https://www.php.net/manual/en/book.datetime.php), like elm, also has a right-hand sidebar with sibling navigation. However, PHP has a single page for a single method, unlike Rust's page for an entire "class." So even though these pages have headers, it's never more than ten at most. And when they have guides, those guides are also multi-page. ## Unresolved questions * Writing recommendations for anyone who wants to take advantage of this. * Right now, it does not line wrap. That might be a bad idea: a lot of these are getting truncated. * Split sidebars, which I [tried implementing](https://rust-lang.zulipchat.com/#narrow/stream/266220-t-rustdoc/topic/Table.20of.20contents), are not required. The TOC can be turned off, if it's really a problem. Implemented in rust-lang#120818, but needs more, separate, discussion. ## Future possibilities I would like to do a better job of distinguishing global navigation from local navigation. Rustdoc has a pretty reasonable information architecture, if only we did a better job of communicating it. This PR aims, mostly, to help doc authors help their users by writing docs that can be more effectively skimmed. But it doesn't do anything to make it easier to tell the TOC and the Module Nav apart.
rustdoc: add header map to the table of contents ## Summary Add header sections to the sidebar TOC. ### Preview ![image](https://github.com/user-attachments/assets/eae4df02-86aa-4df4-8c61-a95685cd8829) * http://notriddle.com/rustdoc-html-demo-9/toc/rust/std/index.html * http://notriddle.com/rustdoc-html-demo-9/toc/rust-derive-builder/derive_builder/index.html ## Motivation Some pages are very wordy, like these. | crate | word count | |--|--| | [std::option](https://doc.rust-lang.org/stable/std/option/index.html) | 2,138 | [derive_builder](https://docs.rs/derive_builder/0.13.0/derive_builder/index.html) | 2,403 | [tracing](https://docs.rs/tracing/0.1.40/tracing/index.html) | 3,912 | [regex](https://docs.rs/regex/1.10.3/regex/index.html) | 8,412 This kind of very long document is more navigable with a table of contents, like Wikipedia's or the one [GitHub recently added](https://github.blog/changelog/2021-04-13-table-of-contents-support-in-markdown-files/) for READMEs. In fact, the use case is so compelling, that it's been requested multiple times and implemented in an extension: * rust-lang/rust#80858 * rust-lang/rust#28056 * rust-lang/rust#14475 * https://rust.extension.sh/#show-table-of-content (Some of these issues ask for more than this, so don’t close them.) It's also been implemented by hand in some crates, because the author really thought it was needed. Protip: for a more exhaustive list, run [`site:docs.rs table of contents`](https://duckduckgo.com/?t=ffab&q=site%3Adocs.rs+table+of+contents&ia=web), though some of them are false positives. * https://docs.rs/figment/0.10.14/figment/index.html#table-of-contents * https://docs.rs/csv/1.3.0/csv/tutorial/index.html#table-of-contents * https://docs.rs/axum/0.7.4/axum/response/index.html#table-of-contents * https://docs.rs/regex-automata/0.4.5/regex_automata/index.html#table-of-contents Unfortunately for these hand-built ToCs, because they're just part of the docs, there's no consistent way to turn them off if the reader doesn't want them. It's also more complicated to ensure they stay in sync with the docs they're supposed to describe, and they don't stay with you when you scroll like Wikipedia's [does now](https://uxdesign.cc/design-notes-on-the-2023-wikipedia-redesign-d6573b9af28d). ## Guide-level explanation When writing docs for a top-level item, the first and second level of headers will be shown in an outline in the sidebar. In this context, "top level" means "not associated". This means, if you're writing very long guides or explanations, and you want it to have a table of contents in the sidebar for its headings, the ideal place to attach it is usually the *module* or *crate*, because this page has fewer other things on it (and is the ideal place to describe "cross-cutting concerns" for its child items). If you're reading documentation, and want to get rid of the table of contents, open the ![image](https://github.com/rust-lang/rust/assets/1593513/2ad82466-5fe3-4684-b1c2-6be4c99a8666) Settings panel and checkmark "Hide table of contents." ## Reference-level explanation Top-level items have an outline generated. This works for potentially-malformed header trees by pairing a header with the nearest header with a higher level. For example: ```markdown ## A # B # C ## D ## E ``` A, B, and C are all siblings, and D and E are children of C. Rustdoc only presents two layers of tree, but it tracks up to the full depth of 6 while preparing it. That means that these two doc comment both generate the same outline: ```rust /// # First /// ## Second struct One; /// ## First /// ### Second struct Two; ``` ## Drawbacks The biggest drawback is adding more stuff to the sidebar. My crawl through docs.rs shows this to, surprisingly, be less of a problem than I thought. The manually-built tables of contents, and the pages with dozens of headers, usually seem to be modules or crates, not types (where extreme scrolling would become a problem, since they already have methods to deal with). The best example of a type with many headers is [vec::Vec](https://doc.rust-lang.org/1.75.0/std/vec/struct.Vec.html), which still only has five headers, not dozens like [axum::extract](https://docs.rs/axum/0.7.4/axum/extract/index.html). ## Rationale and alternatives ### Why in the existing sidebar? The method links and the top-doc header links have more in common with each other than either of them do with the "In [parent module]" links, and should go together. ### Why limited to two levels? The sidebar is pretty narrow, and I don't want too much space used by indentation. Making the sidebar wider, while it has some upsides, also takes up more space on middling-sized screens or tiled WMs. ### Why not line wrap? That behaves strangely when resizing. ## Prior art ### Doc generators that have TOC for headers https://hexdocs.pm/phoenix/Phoenix.Controller.html is very close, in the sense that it also has header sections directly alongside functions and types. Another example, referenced as part of the [early sidebar discussion](rust-lang/rust#37856) that added methods, Ruby will show a table of contents in the sidebar (for example, on the [ARGF](https://docs.ruby-lang.org/en/master/ARGF.html) class). According to their changelog, [they added it in 2013](https://github.com/ruby/rdoc/blob/06137bde8ccc48cd502bc28178bcd8f2dfe37624/History.rdoc#400--2013-02-24-). Haskell seems to mix text and functions even more freely than Elixir. For example, this [Naming conventions](https://hackage.haskell.org/package/base-4.19.0.0/docs/Control-Monad.html#g:3) is plain text, and is immediately followed by functions. And the [Pandoc top level](https://hackage.haskell.org/package/pandoc-3.1.11.1/docs/Text-Pandoc.html) has items split up by function, rather than by kind. Their TOC matches exactly with the contents of the page. ### Doc generators that don't have header TOC, but still have headers Elm, interestingly enough, seems to have the same setup that Rust used to have: sibling navigation between modules, and no index within a single page. [They keep Haskell's habit of named sections with machine-generated type signatures](https://package.elm-lang.org/packages/elm/browser/latest/Browser-Dom), though. [PHP](https://www.php.net/manual/en/book.datetime.php), like elm, also has a right-hand sidebar with sibling navigation. However, PHP has a single page for a single method, unlike Rust's page for an entire "class." So even though these pages have headers, it's never more than ten at most. And when they have guides, those guides are also multi-page. ## Unresolved questions * Writing recommendations for anyone who wants to take advantage of this. * Right now, it does not line wrap. That might be a bad idea: a lot of these are getting truncated. * Split sidebars, which I [tried implementing](https://rust-lang.zulipchat.com/#narrow/stream/266220-t-rustdoc/topic/Table.20of.20contents), are not required. The TOC can be turned off, if it's really a problem. Implemented in rust-lang/rust#120818, but needs more, separate, discussion. ## Future possibilities I would like to do a better job of distinguishing global navigation from local navigation. Rustdoc has a pretty reasonable information architecture, if only we did a better job of communicating it. This PR aims, mostly, to help doc authors help their users by writing docs that can be more effectively skimmed. But it doesn't do anything to make it easier to tell the TOC and the Module Nav apart.
1d9c998
to
b39772f
Compare
Some changes occurred in HTML/CSS/JS. cc @GuillaumeGomez, @jsha Some changes occurred in GUI tests. |
{% if is_crate %} | ||
<ul class="block"> {# #} | ||
{% if is_crate %} | ||
<div class="sidebar-elems" id="rustdoc-cratenav"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please fix the indent and also add the missing {# #}
(here and below).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch.
Any idea how we could automate this? Make it a tidy
check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea! Opening an issue for this.
b39772f
to
5249a4b
Compare
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.
5249a4b
to
48a944a
Compare
☔ The latest upstream changes (presumably #130768) made this pull request unmergeable. Please resolve the merge conflicts. |
CC @the8472 @GuillaumeGomez
Dependent on #120736
Summary
On very large displays, use a three-column layout, splitting up the TOC and ModNav.
Preview
Motivation
Multiple people have asked for a doc layout that makes better use of the larger screens that Rust development itself is usually done on.
More importantly, people have asked for the navigation aids that rustdoc already has, but buries underneath the list of Methods and such. This is a side-effect of mixing together lateral navigation with the table of contents.
It's not quite this simple, unfortunately. Because ModNav is loaded by JS, it populates after the TOC, which means if we put it on top we get a content jump. It cannot go above anything else.
The three-column layout avoids this no-no, and also does a better job of communicating the information hierarchy.
The module navigation is grey in an otherwise-white page, but the floating TOC is not. It's also paired with the logo, while the TOC is paired with the page's name. These are both meant to communicate the difference between the TOC and the ModNav.
By exposing the ModNav more easily, the You Are Here highlighted item name is more commonly visible. Look at the left sidebar in the screenshot.
That tabbed-out
HashMap
struct name under theStructs
header underIn std::collections
is great.Also, this is how MDN does it. Presumably, they know what they're doing.
Drawbacks
This is, really, a pretty serious backslide on the decluttering. If someone really needs to get rid of these things, they can. Click the Settings button, the hide the TOC. But that's probably not a great first impression.
Rationale and alternatives
Why are Sections and Methods both here
Clicking on a ModNav entry shouldn’t cause it to move at all.
That’s not easy to avoid on a narrow screen with one sidebar, but on a split layout it can (or if the TOC is hidden, as in this video).
Screencast.from.2024-07-23.08-48-15.webm
Since it’s not scrolling off every time you click it, “browsing” is a lot less an annoyance. It’s not as convenient as hashing all the information there, but there’s no space trade-off, and it’s less cluttered.
Why is the TOC in a box?
It's a scrollbar thing.
An earlier version of this feature divided the browser into three equally-tall sections. It's the way I wanted the feature to work. But, in doing so, I would have to pick between two bad options for the main document's scrolling behavior:
body
tag. Doing this breaks a bunch of built-in browser behaviors.To side-step this problem, the box helps telegraph what's actually going on. The one inside the box scrolls the box that contains it, while the one outside the box scrolls the page.
Why isn't there a configuration switch to force the one-sidebar view?
Does anybody want this? There's already an option to turn the TOC off entirely, if it's distracting.
Why isn't there a way to resize the TOC box?
It fills all available space. What you'd get would be a way to resize the content area.
Resizing the content area, while it sounds nice, would require a bunch of layout optimization, because right now, resizing it requires too much layout work and is very very slow.
Prior art
This layout is very similar to MDN.
Unresolved questions