Create new page layout layouts/page/filterdemo.html
Create an empty content file.
hugo new filterdemo.md
Set to use the layout created above in the frontmatter of filterdemo.md
:
layout: filterdemo
draft: false
.Grab hugotagsfilter-...js
and put it somewhere in your static
directory.
In your filterdemo.html
file:
<script src="{{ "vendor/htf/hugotagsfilter-...js" | relURL}}"></script>
Initialize HTF, passing an optional config object. This demo uses the following:
var htfConfig = {
filters: [
{
name: 'section',
prefix: 'sect-',
buttonClass: 'sect-button',
allSelector: '#selectAllSections',
attrName: 'data-section',
selectedPrefix: 'ssect-',
countPrefix: 'csect-'
},
{
name: 'tags',
prefix: 'tag-',
buttonClass: 'tag-button',
allSelector: '#selectAllTags',
attrName: 'data-tags',
selectedPrefix: 'stags-',
countPrefix: 'ctags-'
},
{
name: 'authors',
prefix: 'auth-',
buttonClass: 'auth-button',
allSelector: '#selectAllAuthors',
attrName: 'data-authors',
selectedPrefix: 'sauth-',
countPrefix: 'cauth-'
}
],
showItemClass: "show-item",
filterItemClass: "tf-filter-item",
activeButtonClass: "active",
counterSelector: "selectedItemCount",
populateCount: true,
setDisabledButtonClass: "disable-button"
}
var htf = new HugoTagsFilter(htfConfig);
filters
: array of config for each filter set. Each config object needs:
name
: filter identifierprefix
: Each term toggler button needs to be assigned a unique ID. The prefix is used to identify terms belonging to the same filter set, e.g. tags-post
, tags-weather
, tags-random
are tag filters, sect-post
, sect-documentation
are section filters.buttonClass
: Class attribute applied to button togglers. Must start with the prefix.allSelector
: Selector for the Select All X
button.attrName
: Data attribute name to use to identify items.selectedPrefix
: Specify prefix to use to identify the element containing a count of items selected by the tag.countPrefix
: Specify prefix to use to identify the element containing a count of all items with tag.showItemClass
: class to apply to items to signify that they should be visible.filterItemClass
: class applied to items to indicate that it is included in items to be filtered.activeButtonClass
: class to apply to button toggler to signify active statuscounterSelector
: optional selector for element to display count of items displayed.populateCount
: set to true if you want to keep a counter of tags and items associated. Must define selectedPrefix
or countPrefix
on each filter item.setDisabledButtonClass
: Specify a class name to denote disabled button, e.g. when there are no items displayed that have the button’s tag.
You can use as many filter categories as needed.
Tags and section filters are configured by default. If no config object is passed in initialising HTF, the following will be used:
var defaultFilters = [
{
name: 'tag',
prefix: 'tft-',
buttonClass: 'tft-button',
allSelector: '#tfSelectAllTags',
attrName: 'data-tags'
},
{
name: 'section',
prefix: 'tfs-',
buttonClass: 'tfs-button',
allSelector: '#tfSelectAllSections',
attrName: 'data-section'
}
]
This demo uses the following styles (in addition to bare.css)
/*** Important ***/
.tf-filter-item {
display: none;
}
button.active {
background-color: #ddd;
}
button.disable-button {
border-style: dashed;
}
.show-item {
display: inline-block;
/* or whatever display style is appropriate
* for tf-filter-item when it is showing;
*/
}
/*** Aesthetics ***/
.tf-items-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.tf-item {
width: 250px;
margin: 8px;
background: #fff;
padding: 2rem;
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, .2);
border-radius: 2px;
margin-bottom: 2rem
}
pre code {
overflow-x: auto;
}
$pages
and $sections
should be fairly straight-forward.
{{ $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections }}
{{ $sections := .Site.Params.mainSections }}
I don’t have authors
configured in my config.toml
, only on the front matter of the content, which is why I have to get all authors declared for all content. You may need to do this differently depending on your own setup.
{{ $.Scratch.Set "authors" (slice ) }}
{{ range where .Site.RegularPages "Type" "in" .Site.Params.mainSections }}
{{ with .Params.author }}
{{ if eq ( printf "%T" . ) "string" }}
{{ if ( not ( in ($.Scratch.Get "authors") . ) ) }}
{{ $.Scratch.Add "authors" . }}
{{ end }}
{{ else if ( printf "%T" . ) "[]string" }}
{{ range . }}
{{ if ( not ( in ($.Scratch.Get "authors") . ) ) }}
{{ $.Scratch.Add "authors" . }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
Counting and tracking untagged
is not required.
{{ $tags := $.Site.Taxonomies.tags.ByCount }}
{{ $.Scratch.Set "untagged" 0 }}
{{ range $pages }}
{{ with .Params.tags }}{{ else }}{{ $.Scratch.Add "untagged" 1 }}{{ end }}
{{ end }}
For each filter set you want to use, generate buttons (or your preferred element) to use as toggles. For each button:
Assign an id beginning with the prefix
defined in its config.
Assign the class defined as buttonClass
.
Set onclick="htf.checkFilter()"
, passing as parameters the term and the prefix
Add a ‘Select All x’ button as well.
onclick="htf.showAll('x')"
allSelector
If you want to keep a counter of
you also need to add an element inside the button to contain its count (see examples)
<span id="ssect-{{ . | urlize }}"> -count-</span>
<div><h2><span id="selectedItemCount"></span> Items</h2></div>
<div class="tf-items-container">
{{ range $pages.ByPublishDate.Reverse }}
<div class="tf-filter-item tf-item"
data-tags="{{ with .Params.tags }}{{ range . }}{{ . | replaceRE "[.]" "_" | urlize }} {{ end }}{{ else }} tfuntagged{{ end }}"
data-section="{{ .Section }}"
data-authors="{{ with .Params.author }}{{ if eq ( printf "%T" . ) "string" }}{{ . | replaceRE "[.]" "_" | urlize }}{{ else if eq ( printf "%T" . ) "[]string" }}{{ range . }}{{ . | replaceRE "[.]" "_" | urlize }} {{end}}{{end}}{{else}}no-author{{end}}"
>
<h6>{{.Section}}</h6>
<h5>{{ with .Params.author }}{{ if eq ( printf "%T" . ) "string" }}{{.|humanize|title}}{{ else if eq ( printf "%T" . ) "[]string" }}{{ range . }}{{.|humanize|title}} {{end}}{{end}}{{else}}No Author{{end}}</h5>
<h4><a href="{{ .RelPermalink }}">{{ .Title }}</a></h4>
<div>{{ with .Params.tags }}{{ range . }}<tag>{{ . | humanize | title }}</tag> {{ end }}{{ else }}<tag>untagged</tag>{{ end }}</div>
</div>
{{ end }}
</div>