Skip to content

Commit

Permalink
Fix invalid output markup for “hover link” headings which contain the…
Browse files Browse the repository at this point in the history
…ir own links (#1767)

Avoids nested anchors.

Also:

- restores cheatsheet h3 hover link icons;
- slightly increases contrast of main link underlining.
  • Loading branch information
DavidOliver authored Sep 11, 2023
1 parent 960e2ef commit 3189db6
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 55 deletions.
12 changes: 5 additions & 7 deletions assets/css/content/cheatsheet.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,10 @@
color: var(--main);
margin: 0 0 1em;
font-weight: 400;
overflow: hidden;
}

.page-cheatmd .content-inner h3 :is(a, a:visited) {
color: var(--main);
text-decoration: none;
}

.page-cheatmd .content-inner h3.section-heading i {
display: none;
}

.page-cheatmd .content-inner section.h3 {
Expand All @@ -58,7 +52,11 @@
break-inside: avoid;
}

.page-cheatmd .content-inner h3::after {
.page-cheatmd .content-inner h3 .text {
overflow: hidden; /* Clips generated content horizontal rule */
}

.page-cheatmd .content-inner h3 .text::after {
content: "";
margin-left: calc(var(--horizontal-space) / 2);
vertical-align: baseline;
Expand Down
42 changes: 31 additions & 11 deletions assets/css/content/general.css
Original file line number Diff line number Diff line change
Expand Up @@ -131,30 +131,50 @@
vertical-align: top;
}

.content-inner .section-heading a {
.content-inner .section-heading {
--icon-size: 16px;
--icon-spacing: 5px;
display: grid;
grid-template: 1fr / 1fr;
}

.content-inner .section-heading > :is(.hover-link, .text) {
grid-row: 1;
grid-column: 1;
}

.content-inner .section-heading .hover-link {
text-decoration: none;
}

.content-inner .section-heading i {
font-size: 16px;
font-size: var(--icon-size);
margin-top: .1em;
margin-left: -21px;
margin-left: calc(-1 * (var(--icon-size) + var(--icon-spacing)));
padding-right: var(--icon-spacing); /* Avoids gap in hover area */
opacity: 0;
}

.content-inner .section-heading a:is(:hover, :focus) i {
opacity: 1;
@media screen and (max-width: 768px) {
.content-inner .section-heading i {
margin-left: calc(-1 * (var(--icon-size)));
}
}

blockquote .section-heading i {
.content-inner blockquote .section-heading i {
display: none;
}

@media screen and (max-width: 768px) {
.content-inner .section-heading i {
margin-left: -16px;
margin-right: -5px;
}
.content-inner .section-heading .hover-link:is(:hover, :focus) i {
opacity: 1;
}

/* Allow section link to be hovered and used “through” text */
.content-inner .section-heading .text {
pointer-events: none;
}
.content-inner .section-heading .text a {
pointer-events: all;
}

.content-inner .app-vsn {
Expand Down
1 change: 1 addition & 0 deletions assets/css/custom-props/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
--gray200: hsl(210, 29%, 88% );
--gray300: hsl(210, 26%, 84% );
--gray400: hsl(210, 21%, 64% );
--gray450: hsl(210, 21%, 49% );
--gray500: hsl(210, 21%, 34% );
--gray600: hsl(210, 27%, 26% );
--gray700: hsl(212, 35%, 17% );
Expand Down
2 changes: 1 addition & 1 deletion assets/css/custom-props/theme-dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ body.dark {
--linksVisited: var(--gray100);
--linksNoUnderline: var(--main-lightened-10);
--linksNoUnderlineVisited: var(--main-lightened-05);
--linksDecoration: var(--gray500);
--linksDecoration: var(--gray450);

--iconAction: var(--coldGray-lightened-10);
--iconActionHover: var(--white);
Expand Down
2 changes: 1 addition & 1 deletion assets/css/custom-props/theme-light.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
--linksVisited: var(--black);
--linksNoUnderline: var(--main-darkened-10);
--linksNoUnderlineVisited: var(--main-darkened-20);
--linksDecoration: var(--gray400);
--linksDecoration: var(--gray450);

--iconAction: var(--coldGray);
--iconActionHover: var(--gray800);
Expand Down
4 changes: 2 additions & 2 deletions lib/ex_doc/formatter/html/templates.ex
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,10 @@ defmodule ExDoc.Formatter.HTML.Templates do

"""
<#{tag} id="#{prefix}#{id}" class="#{class_attribute}">
<a href="##{prefix}#{id}">
<a href="##{prefix}#{id}" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
#{title}
</a>
<span class="text">#{title}</span>
</#{tag}>
"""
end
Expand Down
4 changes: 2 additions & 2 deletions lib/ex_doc/formatter/html/templates/module_template.eex
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
<h1 class="section-heading">
<a class="hover-link" href="#summary">
<i class="ri-link-m" aria-hidden="true"></i>
Summary
</a>
<span class="text">Summary</span>
</h1>
<%= for {name, nodes} <- summary, do: summary_template(name, nodes) %>
</section>
Expand All @@ -45,8 +45,8 @@
<h1 class="section-heading">
<a class="hover-link" href="#<%= key %>">
<i class="ri-link-m" aria-hidden="true"></i>
<%= name %>
</a>
<span class="text"><%= name %></span>
</h1>
<div class="<%= key %>-list">
<%= for node <- nodes, do: detail_template(node, module) %>
Expand Down
4 changes: 2 additions & 2 deletions test/ex_doc/formatter/epub/templates_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ defmodule ExDoc.Formatter.EPUB.TemplatesTest do
assert content =~ ~r{<h1 id="content">\s*CompiledWithDocs\s*}

assert content =~
~r{<h2 id="module-example-unicode-escaping" class="section-heading">.*<a href="#module-example-unicode-escaping">.*<i class="ri-link-m" aria-hidden="true"></i>.*Example.*</a>.*</h2>}ms
~r{<h2 id="module-example-unicode-escaping" class="section-heading">.*Example.*</h2>}ms

assert content =~
~r{<h3 id="module-example-h3-heading" class="section-heading">.*<a href="#module-example-h3-heading">.*<i class="ri-link-m" aria-hidden="true"></i>.*Example H3 heading.*</a>.*</h3>}ms
~r{<h3 id="module-example-h3-heading" class="section-heading">.*Example H3 heading.*</h3>}ms

assert content =~
~r{moduledoc.*Example.*<samp class="nc">CompiledWithDocs</samp><samp class="o">\.</samp><samp class="n">example</samp>.*}ms
Expand Down
54 changes: 27 additions & 27 deletions test/ex_doc/formatter/html/templates_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -47,101 +47,101 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
test "generates headers with hovers" do
assert Templates.link_headings("<h2>Foo</h2><h2>Bar</h2>") == """
<h2 id="foo" class="section-heading">
<a href="#foo">
<a href="#foo" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Foo
</a>
<span class="text">Foo</span>
</h2>
<h2 id="bar" class="section-heading">
<a href="#bar">
<a href="#bar" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Bar
</a>
<span class="text">Bar</span>
</h2>
"""

assert Templates.link_headings("<h2>Foo</h2>\n<h2>Bar</h2>") == """
<h2 id="foo" class="section-heading">
<a href="#foo">
<a href="#foo" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Foo
</a>
<span class="text">Foo</span>
</h2>
<h2 id="bar" class="section-heading">
<a href="#bar">
<a href="#bar" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Bar
</a>
<span class="text">Bar</span>
</h2>
"""

assert Templates.link_headings("<h2></h2><h2>Bar</h2>") == """
<h2></h2><h2 id="bar" class="section-heading">
<a href="#bar">
<a href="#bar" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Bar
</a>
<span class="text">Bar</span>
</h2>
"""

assert Templates.link_headings("<h2></h2>\n<h2>Bar</h2>") == """
<h2></h2>
<h2 id="bar" class="section-heading">
<a href="#bar">
<a href="#bar" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Bar
</a>
<span class="text">Bar</span>
</h2>
"""

assert Templates.link_headings("<h2>Foo</h2><h2></h2>") ==
String.trim_trailing("""
<h2 id="foo" class="section-heading">
<a href="#foo">
<a href="#foo" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Foo
</a>
<span class="text">Foo</span>
</h2>
<h2></h2>
""")

assert Templates.link_headings("<h2>Foo</h2>\n<h2></h2>") ==
String.trim_trailing("""
<h2 id="foo" class="section-heading">
<a href="#foo">
<a href="#foo" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Foo
</a>
<span class="text">Foo</span>
</h2>
<h2></h2>
""")

assert Templates.link_headings("<h3>Foo</h3>") == """
<h3 id="foo" class="section-heading">
<a href="#foo">
<a href="#foo" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Foo
</a>
<span class="text">Foo</span>
</h3>
"""
end

test "generates headers with unique id's" do
assert Templates.link_headings("<h3>Foo</h3>\n<h3>Foo</h3>") == """
<h3 id="foo" class="section-heading">
<a href="#foo">
<a href="#foo" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Foo
</a>
<span class="text">Foo</span>
</h3>
<h3 id="foo-1" class="section-heading">
<a href="#foo-1">
<a href="#foo-1" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Foo
</a>
<span class="text">Foo</span>
</h3>
"""
end
Expand All @@ -153,10 +153,10 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do

assert Templates.link_headings(admonition_block) == """
<blockquote><h3 id="foo" class="warning section-heading">
<a href="#foo">
<a href="#foo" class="hover-link">
<i class="ri-link-m" aria-hidden="true"></i>
Foo
</a>
<span class="text">Foo</span>
</h3>
</blockquote>
"""
Expand Down Expand Up @@ -471,10 +471,10 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
~r{moduledoc.*Example.*<span class="nc">CompiledWithDocs</span><span class="o">\.</span><span class="n">example</span>.*}ms

assert content =~
~r{<h2 id="module-example-unicode-escaping" class="section-heading">.*<a href="#module-example-unicode-escaping">.*<i class="ri-link-m" aria-hidden="true"></i>.*Example.*</a>.*</h2>}ms
~r{<h2 id="module-example-unicode-escaping" class="section-heading">.*<a href="#module-example-unicode-escaping" class="hover-link">.*<i class="ri-link-m" aria-hidden="true"></i>.*</a>.*<span class="text">Example ☃ Unicode &gt; escaping</span>.*</h2>}ms

assert content =~
~r{<h3 id="module-example-h3-heading" class="section-heading">.*<a href="#module-example-h3-heading">.*<i class="ri-link-m" aria-hidden="true"></i>.*Example H3 heading.*</a>.*</h3>}ms
~r{<h3 id="module-example-h3-heading" class="section-heading">.*<a href="#module-example-h3-heading" class="hover-link">.*<i class="ri-link-m" aria-hidden="true"></i>.*</a>.*<span class="text">Example H3 heading</span>.*</h3>}ms

# Summaries
assert content =~ ~r{example/2.*Some example}ms
Expand Down Expand Up @@ -567,7 +567,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
content = get_module_page([CompiledWithDocs], context)

assert content =~
~r{<h3 id="example_with_h3/0-examples" class="section-heading">.*<a href="#example_with_h3/0-examples">.*<i class="ri-link-m" aria-hidden="true"></i>.*Examples.*</a>.*</h3>}ms
~r{<h3 id="example_with_h3/0-examples" class="section-heading">.*<a href="#example_with_h3/0-examples" class="hover-link">.*<i class="ri-link-m" aria-hidden="true"></i>.*</a>.*<span class="text">Examples</span>.*</h3>}ms
end

test "do not output overlapping functions, causing duplicate IDs", context do
Expand Down
4 changes: 2 additions & 2 deletions test/ex_doc/formatter/html_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,10 @@ defmodule ExDoc.Formatter.HTMLTest do
assert content =~ ~r{<title>README [^<]*</title>}

assert content =~
~r{<h2 id="header-sample" class="section-heading">.*<a href="#header-sample">.*<i class="ri-link-m" aria-hidden="true"></i>.*<code(\sclass="inline")?>Header</code> sample.*</a>.*</h2>}ms
~r{<h2 id="header-sample" class="section-heading">.*<a href="#header-sample" class="hover-link">.*<i class="ri-link-m" aria-hidden="true"></i>.*</a>.*<span class="text"><code(\sclass="inline")?>Header</code> sample</span>.*</h2>}ms

assert content =~
~r{<h2 id="more-than" class="section-heading">.*<a href="#more-than">.*<i class="ri-link-m" aria-hidden="true"></i>.*more &gt; than.*</a>.*</h2>}ms
~r{<h2 id="more-than" class="section-heading">.*<a href="#more-than" class="hover-link">.*<i class="ri-link-m" aria-hidden="true"></i>.*</a>.*<span class="text">more &gt; than</span>.*</h2>}ms

assert content =~ ~r{<a href="RandomError.html"><code(\sclass="inline")?>RandomError</code>}

Expand Down

0 comments on commit 3189db6

Please sign in to comment.