-
Notifications
You must be signed in to change notification settings - Fork 96
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
Sidebar and index overhaul #1220
Conversation
This commit includes multiple modifications: Trees ---------- Odoc used to have several representations of trees: one for the page sidebar in the model, one for the document sidebar, and (in a squashed commit) one for the unit sidebar. All trees now have the same type, making the different passes (eg model -> document for pages and units) much easier, at a small cost (the type is less tailored to the usecase, eg the payload cannot be different in leafs than in node, which was the case before in the page hierarchy). Trees (and forests) have basic iterators defined. The index for units ------------------------ The index for the units values used to be a hashtable from ID to entry. The problem was that you cannot rebuild a sidebar from that: you lose the order between children. The index for units now is a tree of index entries. The sidebar for units ------------------------- The sidebar for units finally shows more than just the root module. However, it does not show the full hierarchy either, as that would be overwhelming in the case of big modules. The sidebar shows: - Only entries that could have had an expansion: modules, modules types, classes and class types. - The current page (highlighted), - The children of the current page, (highlighted differently), - The ancestors of the current page, - The children of the ancestors of the current page, - Nothing else. If you allow me, I like to use the github syntax for mathematics 😄. The sidebar has the property that it displays the smallest set $S$ that: - Contains only modules, modules types, classes and class types. - Contains the current page: $current\_page\in S$, - Is ancestor-closed: if $e\in S$ then $parent(e)\in S$, - Is sibling-closed: if $e\in S$ and $parent(e)=parent(f)$, then $f\in S$ The last property is important to avoid displaying only part of the children of a parent, requiring to display some `...` to show that some entries were omitted. Organization in directories and libraries ----------------------------------------------------- The `search/` folder and its associated `odoc_search` library was separated in two: the original one and the new `index/` and `odoc_index` which contains everything that an index should contain: both the info for the sidebar and for the search index.
One can have a quick look to how the sidebar feels here. |
Not sure I fully grasped the your description of the side bar. But bear in mind that predictability is paramount, so I'd avoid changing it too much depending on the context (except for the local content part of course). In fact I'm not sure that detailing contents in the GLOBAL CONTENT is a good idea. But first a few comments regardless of that idea. Having a look at the GLOBAL CONTENT on this page:
TL;DR I think the outline of GLOBAL CONTENT should be simplified to:
Rendered as:
Now I don't think that the
So that I can navigate it extremely predictably. Especially its geometry should not change depending on the page I'm perusing. Now for detailing the content of a unit it would perhaps (needs testing) be preferable to have a new So basically you have there |
Also I think it would be nice to have an
Rather than:
|
ac2599b
to
2806237
Compare
2806237
to
1677caa
Compare
Thanks for the comments!
I agree my description is unnecessarily convoluted. In short, from a page, the sidebar shows the direct children, the ancestors, and the direct children of the ancestors.
That is one valid use of a sidebar. Other people like to use it to identify more easily where they are in the global hierarchy of modules, or to navigate with less clicks. In particular, the ocaml.org sidebar is popular to some people (and unpopular for others). It is hard to decide exactly what should go in the sidebar, because of the different valid ways it can be used for. I personally think that this is a good middleground, but there is no absolute argument to validate that.
It's true that I have not (yet) put a lot of efforts in how the sidebar is displayed, more in what it contains. I'll try to correct that now, taking your many suggestions into account.
I'm not sure which order is the best, since I think most of the times the pages will take much less space and will be the first thing you want to read when you discover a library. However, I'm happy to put the libraries first to try and see how it feels.
Yes, you are right that with many pages organized in a hierarchy (as in dune or ocaml's docs for instance), that is not going to scale. However, I think it is better to show the uncle pages. For instance, this readthedocs page show the uncle pages, and to me that is a nicer user experience than only seeing the toplevel pages. In other words, I would like for pages to show the same things as in the doc API case: The direct children, the ancestors, and the direct children of the ancestors.
I believe the sidebar is predictable enough, even though it still depending on the page. When I use it, I am not surprised something is shown/hidden. But since I know how it works, I'm not the best person to be surprised. Did something felt unpredictable when you used it?
If I were to add an index of structure items, I would rather add it to the "topical headings" nav, in the order given in the .mli. In
I would not know where to put a third nav, and I think the mli has been written in some order for a good reason. If the goal is only to jump to some value/type you know the name, a "search" in the browser is as efficient. However, this is just my personal, untested, opinion. It might be overwhelming in some cases, and would require testings!
That could be a good idea. Maybe |
Well you have the breadcrumbs for that. The problem is that you can't have both. If you try to show where you are too precisely in that navigation widget then it becomes unusable for navigation (see below for explanations). Also modules and document hierarchies should most of the time be rather shallow (at most 2-3 levels after the namespace) don't try to cater for arbitrary deep ones. The deeper you are the more anecdotic the module is likely to be and the less important it is to provide direct efficient access or the need to contextualize it in the module hierarchy; and again if you need to know where you are, look at the breadcrumbs. For library module indexes I think you should rather try to simply follow what has bee done in the "LOCAL CONTENT" part which works extremely well now; IIRC it consistently shows at most three levels. So I would simply consistently show up to two levels of module/functor implementations (or three if
Again you have the breadcrumbs. I think if you really want this you should rather try to put them in a closed details element or for a given manual in a separate navigation element. Also bear in mind that readthedocs basically shows one linear manual so don't necessary try to copy-cat their design. You are designing something for efficiently navigating among multiple manuals and APIs.
I'm not sure either (i.e. I'd need to test it to come to an answer) but this is not a good argument: do not optimize for newcomers, optimize for the proficient library user. Using this as a guide I would tend to say that you want the library indexes first (in the future manuals may become more plentiful, e.g. there are at least 10 planned here). The newcomer will likely go through the landing page where a guide to the available manuals should be provided.
To me it is totally unusable. Since its content is constantly changing you cannot use it for navigation. When you click on something, as it expands on the destination page, the next item that was below your cursor when I clicked is no longer there, I'm lost and I may have to skip an arbitrary amount of data in order to find it again. And when I'm on an arbitrary page the fact that there may be a huge expansion doesn't allow me to quickly move among the toplevel entries and prevents me from building any muscle memory ("I know this item is just after that one"). In general on a website if, when you move from one page to another, the navigation is constantly jumping around, you don't have a very good website :–) I would really suggest you try what I mentioned above. That is for each library consistent list of up to 2 level of module implementations, list of toplevel manuals (with possibly their children in a details).
No don't do that. It becomes totally redundant with the page and is going to be unusable. The topical headings should provide a quick scannable outline that allows to jump you to a part of the page1 without having to scroll when you land on the page. It's perfectly fine as it is now, don't touch it! Personally I was never convinced that page-level indexes of structure items are that useful (but I'm still adamant we need global ones, at least at the package level, see #577). In any case if you'd add one then I think it should be ordered alphabetically and in a closed detail. Footnotes
|
I agree that having parts moving when you click on something is not ideal. I'd hope that highlighting well the current item would alleviate the issue. For me, it is working: I don't feel I lose the ability to navigate quickly nor feel lost due to the sidebar having moving parts, in the current implementation. I really feel the usability of the sidebar depend on the people (some people have spatial memory, some people remember the name, some people do well with high density of info, some prefer more minimalist UI, ...) and it is hard to give arguments that something is objectively better. (In some sense, we will always have moving parts, just more or less often: if you had to scroll on the sidebar to click on an item, the sidebar's will be back on top on the next page.)
I can experiment with that. I'll "publish" several libraries docs using each version of the sidebar, so we can compare.
Don't worry, I'm not doing it :)
Sometimes, having the uncles helps orienting you. In the "dune docs" example above, the breadcrumbs would only tell me I'm under "Reference Manual". However, to me it is easier with all the examples of things that fall into the "Reference manual": Back to the "readthedocs" example:
I'm not sure to understand. Each package gets its own sidebar, so a sidebar only show one manual, the one for the package? In a global sidebar, it seems to me that everything ends up linearized in the end, if only because things have to be shown from top to bottom. |
Well yes it's also totally unpredictable. I don't think readthedocs is a good design.
I don't think so. For users having predictable and consistent structures for navigation is objectively better than something that is constantly changing and spatially twitching. Also bear in mind that if you are looking that on a 23'' screen the experience may be quite different on a laptop screen whose vertical size is rather short.
I'm not so sure. For example if you take the menu on ocaml.org of core. There is actually little to be gained in hiding the modules of
But you could also simply go in the I think the problem of your approach is that you are trying to show everything. But having a good an efficient navigation structure is about abstracting the details, be mindful of showing the essentials that allow you to efficiently get to any other part from where you are in quick (count the clicks) and predictable (fixed structures) manners, without overwhelming users with choices and all the (sub)details of what exists (screen estate is often very limited and scrolling is annoying). Now for a given manual with child pages you may want to have an outline with all the sibling pages but as already mentioned it doesn't have to be in the global content part and/or can be hidden in a details by default.
I think the model should be this, in a package:
And I think the global side bars should show the following fixed structure :
With submodules shown in case of a namespacing module and in manuals possibly having the children in a details. |
let p_hierarchy = | ||
let page_toc_input = | ||
(* To create a page toc, we need a list with id, title and children | ||
order. We generate this list from *) |
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.
Finish the sentence
(* let url = *) | ||
(* match doc with *) | ||
(* | Odoc_document.Types.Document.Page { url; _ } -> url *) | ||
(* | Source_page { url; _ } -> url *) | ||
(* in *) | ||
(* let sidebar = *) | ||
(* Odoc_utils.Option.map *) | ||
(* (fun sb -> Odoc_document.Sidebar.to_block sb url) *) | ||
(* sidebar *) | ||
(* in *) |
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.
Remove
@@ -0,0 +1 @@ | |||
A reference to an {!} |
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.
Remove this file!
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.
Remove this file
Thanks for your ideas. We discussed a bit the review of this PR. It was decided to split it in smaller chunks, review and merge them: anyway, the final design will only slightly alter the code. Once the feature is in, we will revisit the "how to prune the sidebar" question, experimenting with the various ideas. One option I would find sensible would be to give options to the driver to decide how the sidebar is pruned. |
4296adf
to
4ce8e07
Compare
Superceded by #1244 |
This PR includes multiple modifications. It is best reviewed commit by commit (there is only one commit).
Trees
Odoc used to have several representations of trees: one for the page sidebar in the model, one for the document sidebar, and (in a squashed commit) one for the unit sidebar.
All trees now have the same type, making the different passes (eg model -> document for pages and units) much easier, at a small cost (the type is less tailored to the usecase, eg the payload cannot be different in leafs than in node, which was the case before in the page hierarchy).
Trees (and forests) have basic iterators defined.
The index for units
The index for the units values used to be a hashtable from ID to entry. The problem was that you cannot rebuild a sidebar from that: you lose the order between children.
The index for units now is a tree of index entries.
The sidebar for units
The sidebar for units finally shows more than just the root module.
However, it does not show the full hierarchy either, as that would be overwhelming in the case of big modules.
The sidebar (as suggested by @Julow, thanks!) shows:
If you allow me, I like to use the github syntax for mathematics 😄. The sidebar has the property that it displays the smallest set$S$ that:
The last property is important to avoid displaying only part of the children of a parent, requiring to display some
...
to show that some entries were omitted.Organization in directories and libraries
The
search/
folder and its associatedodoc_search
library was separated in two: the original one and the newindex/
andodoc_index
which contains everything that an index should contain: both the info for the sidebar and for the search index.