Skip to content

Commit

Permalink
Replace navigation tree
Browse files Browse the repository at this point in the history
The current navigation tree suffers from several problems:

* From a UX perspective, when a navigation tree has many levels,
  interacting with the tree becomes tedious.  Likewise, when a tree is
  very long, scanning becomes more difficult and it is easy to lose
  track of where you are in the hierarchy.  For projects like Rails, the
  navigation tree has many levels and is very long.

* The navigation tree uses JavaScript to navigate to pages instead of
  actual links.  From a UX perspective, this can be frustrating when the
  user expects the entries to behave like links, such as when
  right-clicking or Ctrl+clicking.  From an SEO perspective, it can be
  harmful because search engines cannot crawl the entries.

* The CSS for the navigation tree is very brittle.  The tree uses a
  repeating background image to achieve its striping effect, and
  requires entries to be a specific height to align with the background.
  This makes it difficult to change anything related to size, such as
  font size or even font family.

* In terms of page rendering costs, the navigation tree can be very
  heavy for large projects.  For Rails, the navigation tree adds several
  thousand nodes to the DOM.  Furthermore, the tree is rendered entirely
  via JavaScript -- no static HTML -- which compounds the cost.

This commit replaces the navigation tree with a static sidebar per page.
For the main page, the sidebar will display a list of top-level modules
and a heading-based outline for the main page content.  For other prose
files (such as `README` files), the sidebar will similarly display a
heading-based outline.  For modules, the sidebar will display a list of
their methods, as well as a heading-based outline if the module has a
top-level comment that includes headings.

The `filter.svg` file is from [Feather icons][feather] v4.29.0, and is
[licensed under the MIT license][license].

[feather]: https://feathericons.com/
[license]: https://github.com/feathericons/feather/blob/v4.29.0/LICENSE
  • Loading branch information
jonathanhefner committed Oct 5, 2023
1 parent 8e3384e commit d0e2ead
Show file tree
Hide file tree
Showing 24 changed files with 375 additions and 724 deletions.
20 changes: 0 additions & 20 deletions lib/rdoc/generator/template/rails/_context.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,6 @@
</ul>
<% end %>

<% unless @context.method_list.empty? %>
<!-- Method ref -->
<div class="content__divider">Methods</div>
<dl class="methods">
<% group_by_first_letter(@context.method_list).each do |letter, methods| %>
<dt><%= letter %></dt>
<dd>
<ul>
<% methods.each_with_index do |method, i| %>
<%
comma = methods.size == i+1 ? '' : ','
%>
<li><%= link_to short_name(method), method %><%= comma %></li>
<% end %>
</ul>
</dd>
<% end %>
</dl>
<% end %>



<% @context.each_section do |section, constants, attributes| %>
Expand Down
11 changes: 11 additions & 0 deletions lib/rdoc/generator/template/rails/_file_nav.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<% if @context.text? %>
<div class="nav__outline">
<%= outline(@context) %>
</div>
<% else %>
<ul class="nav__list">
<% @context.each_classmodule do |rdoc_module| %>
<li><%= button_to_search rdoc_module %></li>
<% end %>
</ul>
<% end %>
4 changes: 0 additions & 4 deletions lib/rdoc/generator/template/rails/_head.rhtml
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
<%= base_tag_for_context(@context) %>

<link rel="stylesheet" href="/css/panel.css" type="text/css" media="screen" />
<link rel="stylesheet" href="/css/main.css" type="text/css" media="screen" />
<link rel="stylesheet" href="/css/highlight.css" type="text/css" media="screen" />

<script src="/js/jquery-3.5.1.min.js" type="text/javascript"></script>
<script src="/js/main.js" type="module"></script>
<script src="/js/@hotwired--turbo.js" type="module"></script>
<script src="/panel/tree.js" type="text/javascript"></script>
<script src="/js/searchdoc.js" type="text/javascript"></script>
<meta name="data-tree-keys" content='<%= tree_keys %>'>

<% if canonical = canonical_url(@context) %>
<link rel="canonical" href="<%= canonical %>" />
Expand Down
10 changes: 10 additions & 0 deletions lib/rdoc/generator/template/rails/_index_nav.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div class="nav__outline">
<%= outline(@context) %>
</div>

<div class="nav__heading">Modules</div>
<ul class="nav__list">
<% top_modules(@context.store).each do |rdoc_module| %>
<li><%= link_to rdoc_module %></li>
<% end %>
</ul>
17 changes: 17 additions & 0 deletions lib/rdoc/generator/template/rails/_module_nav.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<%= button_to_search @context, display_name: short_name(@context) %>

<% if outline = outline(@context) %>
<div class="nav__outline">
<%= outline %>
</div>
<% end %>

<% unless (methods = module_methods(@context)).empty? %>
<div class="nav__heading">Methods</div>
<ul class="nav__list">
<% methods.each do |rdoc_method| %>
<li><%= link_to short_name(rdoc_method), rdoc_method,
class: "nav__method-link#{"--singleton" if rdoc_method.singleton}" %></li>
<% end %>
</ul>
<% end %>
14 changes: 6 additions & 8 deletions lib/rdoc/generator/template/rails/_panel.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,16 @@

<input id="panel__state" type="checkbox">

<div id="panel__tray" class="panel__tray" data-turbo-permanent>
<div class="panel__tray">
<input id="search" class="panel__search" type="text"
tabindex="-1" autocomplete="off" autosave="searchdoc"
placeholder="Search (/) for a class, method, ...">
placeholder="Search (/) for a class, method, ..."
data-turbo-permanent>

<div id="results" class="panel__results"></div>
<div id="results" class="panel__results" data-turbo-permanent></div>

<div class="panel__tree">
<div class="tree">
<ul>
</ul>
</div>
<div class="panel__nav content">
<% yield if block_given? %>
</div>

<a id="links" href="/panel/file_links.html">index</a>
Expand Down
6 changes: 3 additions & 3 deletions lib/rdoc/generator/template/rails/class.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="<%= @options.charset %>">
<title><%= page_title @context.full_name %></title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<% inline "_head.rhtml", { :tree_keys => @context.full_name.split('::') } %>
<% inline "_head.rhtml" %>

<meta property="og:title" value="<%= og_title @context.full_name %>">
</head>
Expand All @@ -13,9 +13,9 @@
<a class="sr-only sr-only-focusable" href="#context" data-turbo="false">Skip to Content</a>
<a class="sr-only sr-only-focusable" href="#search" data-turbo="false">Skip to Search</a>

<% inline "_panel.rhtml" %>
<% inline("_panel.rhtml") { inline("_module_nav.rhtml") } %>

<main id="content">
<main id="content" class="content">
<hgroup class="content__title">
<h1><span class="kind"><%= @context.type %></span> <%= module_breadcrumbs @context %></h1>
</hgroup>
Expand Down
6 changes: 3 additions & 3 deletions lib/rdoc/generator/template/rails/file.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="<%= @options.charset %>">
<title><%= page_title @context.name %></title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<% inline "_head.rhtml", { :tree_keys => [] } %>
<% inline "_head.rhtml" %>

<meta property="og:title" value="<%= og_title @context.name %>">
</head>
Expand All @@ -13,9 +13,9 @@
<a class="sr-only sr-only-focusable" href="#context" data-turbo="false">Skip to Content</a>
<a class="sr-only sr-only-focusable" href="#search" data-turbo="false">Skip to Search</a>

<% inline "_panel.rhtml" %>
<% inline("_panel.rhtml") { inline("_file_nav.rhtml") } %>

<main id="content">
<main id="content" class="content">
<div class="content__title">
<%= "<h1>" if @context.comment.empty? %>
<%= full_name @context %>
Expand Down
6 changes: 3 additions & 3 deletions lib/rdoc/generator/template/rails/index.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
<meta charset="<%= @options.charset %>">
<title><%= page_title %></title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<% inline "_head.rhtml", {tree_keys: []} %>
<% inline "_head.rhtml" %>
</head>

<body>
<a class="sr-only sr-only-focusable" href="#context" data-turbo="false">Skip to Content</a>
<a class="sr-only sr-only-focusable" href="#search" data-turbo="false">Skip to Search</a>

<% inline "_panel.rhtml" %>
<% inline("_panel.rhtml") { inline("_index_nav.rhtml") } %>

<main id="content">
<main id="content" class="content">
<% inline "_context.rhtml" %>
</main>
</body>
Expand Down
134 changes: 95 additions & 39 deletions lib/rdoc/generator/template/rails/resources/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,27 @@ a code {
background-size: 1.1em;
}

.query-button {
border: none;
text-align: left;
font-family: inherit;
font-size: 1em;

background: url('../i/filter.svg') no-repeat;
background-position-y: 1px;
background-size: 1.1em;
padding: 0 0 0 1.3em;
color: var(--link-color);

word-break: break-word;
}

@media (hover: hover) {
.query-button:hover {
color: var(--link-hover-color);
}
}

.kind {
font-family: monospace;
}
Expand All @@ -89,30 +110,6 @@ th
font-weight: bold;
}

.methods dt
{
width: 1em;
font-size: 1.5em;
color:#AAA;
position: absolute;
}

.methods dd
{
margin-top: var(--space);
min-height: 1.8em;
-height: 1.8em;
}


.methods ul li
{
margin-right: 0.7em;
margin-left: 0;
list-style: none;
display: inline;
}

.attr-rw {
padding-right: 1em;
text-align: center;
Expand Down Expand Up @@ -289,7 +286,7 @@ html {
box-shadow: 1px 1px 4px color-mix(in srgb, currentColor 50%, transparent) inset;
}

.panel__results, .panel__tree {
.panel__results, .panel__nav {
position: relative;
height: calc(100dvh - var(--banner-height) - var(--search-height));
width: var(--panel-width);
Expand All @@ -300,7 +297,7 @@ html {
}

/* Force scrolling in order to always contain scroll events (on mobile) */
:is(.panel__results, .panel__tree)::after {
:is(.panel__results, .panel__nav)::after {
content: "";
height: 1px;
width: 1px;
Expand All @@ -311,7 +308,7 @@ html {

.panel__results:not(.active),
.panel__search:placeholder-shown ~ .panel__results,
.panel__search:not(:placeholder-shown) ~ .panel__results.active ~ .panel__tree {
.panel__search:not(:placeholder-shown) ~ .panel__results.active ~ .panel__nav {
/* `display: none` disables animations, so simulate it instead */
max-height: 0;
max-width: 0;
Expand All @@ -320,10 +317,6 @@ html {
opacity: 0;
}

.panel__tree {
overflow-x: hidden;
}


/*
* Navigation panel - Search results
Expand Down Expand Up @@ -388,6 +381,69 @@ html {
}


/*
* Navigation panel - Page nav
*/

.panel__nav {
padding: var(--space);
font-size: 0.95em;
line-height: calc(0.85 * var(--line-height));
}


* + .nav__outline {
margin-top: var(--space-lg);
}

.nav__outline ul {
margin-top: var(--space-sm);
padding-left: 1em;
}

.nav__outline ul ul ul {
display: none; /* Only show two levels deep */
}

.nav__outline li {
word-break: break-word;
}

.nav__outline a {
text-decoration: underline;
}


.nav__heading {
margin-top: var(--space-lg);
font-size: 1.3em;
}

.nav__heading + .nav__list {
margin-top: var(--space-sm);
}


.nav__list {
padding: 0;
list-style: none;
}

.nav__list li {
overflow: hidden;
text-overflow: ellipsis;
}


.nav__method-link code::before {
content: "#";
}

.nav__method-link--singleton code::before {
content: "::";
}


/*
* Navigation panel on desktop
*/
Expand All @@ -411,7 +467,7 @@ html {
width: 60ch;
}

:is(.panel__results, .panel__tree)::after {
:is(.panel__results, .panel__nav)::after {
display: none;
}
}
Expand All @@ -434,29 +490,29 @@ html {
}
}

:where(#content) *,
:where(#content) :is(br, wbr) {
:where(.content) *,
:where(.content) :is(br, wbr) {
margin: 0;
}

:where(#content) * + * {
:where(.content) * + * {
margin-top: var(--space);
}

:where(#content) :is(ol, ul, dd) {
:where(.content) :is(ol, ul, dd) {
padding: 0 0 0 1.25em;
}

:where(#content) * + :is(li, dd) {
:where(.content) * + :is(li, dd) {
margin-top: var(--space-sm);
}

/* Increase top margin for list items when any item has more than one paragraph */
:where(#content :is(ol, ul):has(> li > p:not(:only-child))) * + li {
:where(.content :is(ol, ul):has(> li > p:not(:only-child))) * + li {
margin-top: var(--space);
}

:where(#content) code {
:where(.content) code {
font-style: normal;
}

Expand Down
Loading

0 comments on commit d0e2ead

Please sign in to comment.