Last active
August 18, 2019 12:41
-
-
Save percygrunwald/043e577beb90db72e09727a3ed3053c3 to your computer and use it in GitHub Desktop.
Yet another Hugo partial for generating a Table of Contents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{{ $headers := findRE "<h[2-4].*?>(.|\n])+?</h[2-4]>" .Content }} | |
{{ $numHeaders := len $headers }} | |
{{ $hasHeaders := ge $numHeaders 1 }} | |
{{ if $hasHeaders }} | |
<nav id="toc" data-toggle="toc"> | |
<!-- TOC header --> | |
<h4 class="text-muted toc-heading">Table of Contents</h4> | |
<ol class="toc"> | |
{{ range $i, $header := $headers }} | |
{{ $currentHeaderLevelString := index (findRE "[2-4]" $header 1) 0 }} | |
{{ $currentHeaderLevel := len (seq $currentHeaderLevelString) }} | |
{{ $anchorId := (replaceRE "[’/_]" "-" ($header | htmlUnescape | plainify | htmlEscape)) | urlize }} | |
{{ $listItemTitle := $header | htmlUnescape | plainify | htmlEscape }} | |
{{ $listItemOpen := safeHTML (printf "<li><a href='#%s'>%s</a>" $anchorId $listItemTitle) }} | |
{{ $lastItemIndex := sub $numHeaders 1 }} | |
{{/* case: there is only one header */}} | |
{{ if lt $numHeaders 2 }} | |
{{ $listItemOpen }}</li> | |
{{ else }} | |
{{/* case: more than 1 header, first header */}} | |
{{ if lt $i 1 }} | |
{{ $listItemOpen }} | |
{{/* case: more than 1 header, not first header */}} | |
{{ else }} | |
{{ $previousHeader := index $headers (sub $i 1) }} | |
{{ $previousHeaderLevelString := index (findRE "[2-4]" $previousHeader 1) 0 }} | |
{{ $previousHeaderLevel := len (seq $previousHeaderLevelString) }} | |
{{/* case: header is at the same level as the previous header */}} | |
{{ if eq $currentHeaderLevel $previousHeaderLevel }} | |
</li> | |
{{ $listItemOpen }} | |
{{/* case: header is higher than the previous header (e.g. h3 where previous header is h2) */}} | |
{{/* a header should never be more than 1 higher than the previous h2 -> h3 -> h4 */}} | |
{{ else if gt $currentHeaderLevel $previousHeaderLevel }} | |
<ol> | |
{{ $listItemOpen }} | |
{{/* case: header level is lower than the previous header (e.g. h2 where previous header is h4) */}} | |
{{/* the previous header may be multiple levels different, h2 can legitimately follow a h4 */}} | |
{{ else if lt $currentHeaderLevel $previousHeaderLevel }} | |
{{/* close the <li> of the previous header */}} | |
</li> | |
{{/* close the <ol>s and <li>s of the previous headers */}} | |
{{ $headerLevelDifference := sub $previousHeaderLevel $currentHeaderLevel }} | |
{{ range (seq $headerLevelDifference) }} | |
</ol></li> | |
{{ end }} | |
{{ $listItemOpen }} | |
{{ end }} | |
{{ end }} | |
{{/* end if based on first or not first header */}} | |
{{/* case: last header, time to close any open <li> and <ol> */}} | |
{{ if eq $i $lastItemIndex }} | |
{{ $firstHeader := index $headers 0 }} | |
{{ $firstHeaderLevelString := index (findRE "[2-4]" $firstHeader 1) 0 }} | |
{{ $firstHeaderLevel := len (seq $firstHeaderLevelString) }} | |
{{/* close the <li> of the previous header */}} | |
</li> | |
{{/* close the <ol>s and <li>s of the previous headers */}} | |
{{ $differenceWithFirstHeader := sub $firstHeaderLevel $currentHeaderLevel }} | |
{{ range (seq $differenceWithFirstHeader) }} | |
</ol></li> | |
{{ end }} | |
{{ end }} | |
{{/* end if last item */}} | |
{{ end }} | |
{{/* end if numhHeaders > 1 */}} | |
{{ end }} | |
{{/* end range headers */}} | |
{{ if isset .Params "comments_uuid" }} | |
<li><a href='#comments'>Comments</a></li> | |
{{ end }} | |
</ol> | |
</nav> | |
{{ end }} | |
{{/* end if has headers */}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
article .article__body nav#toc { | |
background: #f8f9fa; | |
border: 1px solid #a2a9b1; | |
padding: 7px 15px 7px 15px; | |
& .toc-heading { | |
margin-bottom: 10px; | |
} | |
& .toc { | |
margin-left: 0; | |
margin-bottom: 10px; | |
font-size: 15px; | |
font-weight: 600; | |
list-style: none; | |
& ol { | |
list-style: none; | |
} | |
& li { | |
margin-top: 15px; | |
line-height: 1.3em; | |
padding: 0; | |
& a { | |
display: inline-block; | |
} | |
} | |
& li > ol { | |
margin-left: 30px; | |
font-size: inherit; | |
} | |
} | |
} | |
@include media-breakpoint-down(sm) { | |
article .article__body { | |
& .toc { | |
font-size: 13px; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Live demo here
Original issue thread: gohugoio/hugo#1778 (comment)