Hugo – How to add different class names based on counter - loops

Using Hugo, I need add unique class names to the first few posts. How can this be done?
My code that's obviously not working…
// if the first post
{{ if eq .Site.GetPage 1 }}
{{ $classname := "class-one" }}
// else the second post
{{ elseif eq .Site.GetPage 2 }}
{{ $classname := "class-two" }}
// else the third post
{{ elseif eq .Site.GetPage 3 }}
{{ $classname := "class-three" }}
{{ else }}
{{ end }}
<li class="{{ $classname }}">
…
</li>

Maybe there's some more efficient way, but this works:
{{ $paginator := .Paginate (where .Data.Pages.ByDate.Reverse "Type" "post") }}
{{ range $index, $element := $paginator.Pages }}
{{ if (eq $index 0) }}
{{ $.Scratch.Set "classname" "class-one" }}
{{ else if (eq $index 1) }}
{{ $.Scratch.Set "classname" "class-two" }}
{{ else }}
{{ $.Scratch.Set "classname" "" }}
{{ end }}
<li class="{{ $.Scratch.Get "classname" | safeHTML }}">
…
</li>
{{ end }}

Related

three or more level submenu in hugo

I want to create three or more levels menu like
- Category_main
- Category_sub1
- Category_sub1_sub1
- Category_sub1_sub2
- Category_sub2
- category_sub2_sub1
- Category_sub2_sub2
I try to edit two files; config.toml and header.html
config.toml is
[[menu.main]]
URL = "main"
name = "main"
identifier = "main"
weight = 1
[[menu.main]]
URL = "sub1"
name = "sub1"
identifier = "sub1"
weight = 1
parent = "main"
[[menu.main]]
URL = "sub2"
name = "sub2"
identifier = "sub2"
weight = 2
parent = "main"
[[menu.main]]
URL = "sub1sub1"
name = "sub1sub1"
identifier = "sub1sub1"
parent = "sub1"
weight = 1
[[menu.main]]
URL = "sub1sub2"
name = "sub1sub2"
identifier = "sub1sub2"
parent = "sub1"
weight = 2
[[menu.main]]
URL = "sub2sub1"
name = "sub2sub1"
identifier = "sub2sub1"
parent = "sub2"
weight = 1
[[menu.main]]
URL = "sub2sub2"
name = "sub2sub2"
identifier = "sub2sub2"
parent = "sub2"
weight = 2
header.html is
<header class="navigation fixed-top">
<nav class="navbar navbar-expand-lg navbar-dark">
<a class="navbar-brand" href="{{ site.BaseURL }}">
{{ if site.Params.logo }}
<img src="{{ site.Params.logo | absURL }}" alt="{{site.Title}}">
{{ else }}
<h3 class="text-white font-secondary">{{site.Title}}</h3>
{{ end }}
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navigation"
aria-controls="navigation" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse text-center" id="navigation">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="{{ site.BaseURL }}">{{ with site.Params.Home }} {{ . }} {{ end }}</a>
</li>
{{ $current := . }}
{{ range site.Menus.main }}
{{ $active := or ($current.IsMenuCurrent "nav" .) ($current.HasMenuCurrent "nav" .) }}
{{ $active = or $active (eq .Name $current.Title) }}
{{ if .HasChildren }}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ .Name }}
</a>
<div class="dropdown-menu">
{{ range .Children }}
<a class="dropdown-item dropdown-toggle" href="{{ .URL | absURL }}" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> {{ .Name }} </a>
<div class="dropdown-menu">
{{ range .Children }}
<a class="dropdown-item"> {{ .Name }} </a>
{{ end }}
</div>
{{ end }}
</div>
</li>
{{ else }}
<li class="nav-item {{ if $active }}active{{ end }}">
<a class="nav-link" href="{{ .URL | absURL }}">{{ .Name }}</a>
</li>
{{ end }}
{{ end }}
</ul>
</div>
</nav>
</header>
Result I want is here.
Whatever I press sub1 or sub2, always show sub1 dropdown.
Link is result when i click "sub2".
When I press F12, html source does not have problem.
I guess that javascript or jquery has problem.
What should I edit in code?
Or What can I do for multi-level (three or more) menus in Hugo.
Auto-collapsing menu
A lot of websites use an auto-collapsing menu. It is a great and compact way to show a lot of content in a structured way, but it requires a hierarchical view of all your pages. This post explains how to do that.
Different approaches
I tried some different approaches. I started out with the assumption that I was not allowed to use folders in sections. I was under the impression that a folder in a section would create a subsection. Therefore I started with a parent reference in the front matter. Once I found out that I actually WAS allowed to use subfolders, as long as I refrained from using an ‘index.md’ or an ‘_index.md’ file, I rewrote the script. I assumed that the folder structure would be reflected in my permalinks. This, however, turned out to be a false assumption as well. Therefore I rewrote the script a second time. This time I made it look at the filepath. It is fully independent of the permalinks used and therefore works in a multilingual setup with custom permalinks defined in the config file and the front matter.
The code
First we start with a list of the pages that have children. This allows us to set the correct classname. We do this by looping over all pages and ‘collecting’ their path in a scratch variable. Then we create our unordered list that uses a recursive partial to loop over the items.
{{ with .Site.GetPage (print "/" .Section "/_index.md") }}
{{ $.Scratch.Set "haschildren" "" }}
{{ range .RegularPages }}
{{ $urlparts := split (print .File.Dir .File.BaseFileName) "/" }}
{{ range $index, $value := (first (len $urlparts) $urlparts) }}
{{ $.Scratch.Add "haschildren" (print " " (delimit (first $index $urlparts) "/") "/") }}
{{ end }}
{{ end }}
{{ $.Scratch.Set "haschildren" (uniq (split ($.Scratch.Get "haschildren") " ")) }}
<ul class="nestedmenu">
{{ partial "nested-menu-partial.html" (dict "context" . "pagecontext" $.Page "regularpages" .RegularPages) }}
</ul>
{{ end }}
The recursive partial
The recursive partial loops over the items in the list (all items in the section, also called ‘regular pages’).
{{ range .regularpages }}
{{ $filepath := replace (print .File.Dir (replace .File.BaseFileName "_index" "") "/") "//" "/" }}
{{ $contextfilepath := replace (print $.context.File.Dir (replace $.context.File.BaseFileName "_index" "") "/") "//" "/" }}
{{ $pagecontextfilepath := replace (print $.pagecontext.File.Dir (replace $.pagecontext.File.BaseFileName "_index" "") "/") "//" "/" }}
{{ if eq (len (split $filepath "/")) (add (len (split $contextfilepath "/")) 1) }}
{{ if and (in $filepath $contextfilepath) (ne $contextfilepath $filepath) }}
<li class="{{ if in $pagecontextfilepath $filepath }}active{{ end }} {{ if in ($.pagecontext.Scratch.Get `haschildren`) $filepath }}haschildren{{ end }}">
{{ .Title }}
<ul>
{{ partial "nested-menu-partial.html" (dict "context" . "pagecontext" $.pagecontext "regularpages" $.regularpages) }}
</ul>
</li>
{{ end }}
{{ end }}
{{ end }}
Adding some CSS
I have added some CSS to make it look good (and for the auto-collapsing to work):
ul.nestedmenu {margin-left: 0;}
ul.nestedmenu li {list-style: none;}
ul.nestedmenu li > ul {display: none;}
ul.nestedmenu li > a::before {
content: "•";
display: inline-block;
margin-right: 0.25rem;
width: 0.5rem;
text-align: center;
}
ul.nestedmenu li.haschildren > a::before {content: "›";}
ul.nestedmenu li.haschildren.active > a::before {transform: rotate(90deg);}
ul.nestedmenu li.active > ul {display: block;}
ul.nestedmenu li > a {color: #444444!important;}
ul.nestedmenu li.active > a {color: rgb(247, 44, 114)!important;}
If you want to see this in action, you can view a demo here: https://hugocodex.org/blog/creating-a-menu-with-nested-pages/

How to display the html-tag through the condition if hugo?

I have a code in the hugo template engine that should add a script if the parameter in the article is equal to the desired value.
Front Matter articles. Here I need the header_class parameter
---
title: "Replaced header"
header_class: "replaced-header"
---
If header_class = "replaces-header" output the code. I tried to implement it like this:
{{ if isset .Params.header_class "replaced-header" }}
<script>
let replacedHeader = document.querySelector('.replaced-header');
window.onscroll = function() {
let breakPoint = 100;
let scroll = window.pageYOffset || document.documentElement.scrollTop;
if(scroll > breakPoint) {
replacedHeader.classList.add('replaced-header--scrolled');
}
};
</script>
{{ end }}
The code doesn't work. How should a condition be set in this case?
Got a reply on another forum, post it here. Any of these three methods will work:
{{ if isset .Params "header_class" }}
{{ .Params.header_class }}
{{ end }}
{{ with .Params.header_class }}
{{ . }}
{{ end }}
{{ with .Param "header_class" }}
{{ . }}
{{ end }}
Or like this:
{{ with $.Param "header_class" }}
{{ if ( eq . "replaced-header") }}
My script
{{ end }}
{{ end }}

Angularjs : add multiple ng_if condition in with haml syntax

I'm working on an item_selector directive, I want to add an indicator for archived element, this is the item selector template .haml :
.directive-items-selector{ ng_click: "openItemsSelector( $event )" }
.wrapper
%ui_select.ui-select{ ng: { model: "input.model", disabled: "disabled",
change: "itemSelectModelChanged()" },
search_enabled: "{{ options.searchable }}" }
%ui_select_match.ui-select-match{ items_selector_match: '',
placeholder: "{{ input.placeholder }} ",
allow_clear: "{{ options.clearable }}",
title: "{{ $select.selected.label }}" }
%i.fa{ ng_class: 'icon' }
%span{'ng': {'class': "{'is-archived': $select.selected.object.is_archived === true}"}}
{{ $select.selected.label }}
%ui_select_choices.ui-select-choices{ repeat: "item.id as item in input.filteredItems track by item.id",
refresh: "reloadItems( $select.search )",
refresh_delay: '{{ input.filterDelay }}' }
.item{ ng_attr_title: "{{ ::item.label }}" }
.item-label {{ ::item.label }}
%small.item-details {{ ::item.details }}
.items-selector-actions
%a.pointer.action{ ng: { if: 'linkToModal', click: 'openDetails()', disabled: "!model" }}
{{ 'btn.details' | translate }}
%a.pointer.action{ ng: { if: 'createButton && klassName && !disabled', click: 'createItem()' }}
{{ 'btn.new' | translate }}
I've add a through line css propoerty to archived element by :
%span{'ng': {'class': "{'is-archived': $select.selected.object.is_archived === true}"}}
{{ $select.selected.label }
and I want to add a mouse hover indicator that tell user "this element is archived", I thought about ng_if multiple condition in this attribute of ui_select.ui-select : title: "{{ $select.selected.label }}"
*
if $select.selected.object.is_archived return true : costume message
else {{ $select.selected.label }
*

How to concat 2 expressions in interpolate

I have directive where I want to render a list from various objects.
Controller:
$scope.propertyName = 'price';
View:
<div ng-repeat="item in obj">
<a>{{ 'item.' + propertyName }}</a>
</div>
Objects obj will have various properties and I can't use static property name.
{{ 'item.' + propertyName }} return string 'item.price' - I want expression like {{ item.price }}.
Just like you would do in JavaScript:
{{ item[propertyName] }}

How can I put a condition inside a data binding in AngularJS?

I would like to do the following:
<div>
<div ng-repeat="row in test.active">
<div>{{ row.id }}</div>
<div>
{{ if (row.testTypeId == 1) { test.exams.dataMap[row.examId].name; } }}
{{ if (row.testTypeId == 2) { test.topics.topicNameMap[row.topicId] } }}
</div>
</div>
</div>
However this is giving me an error with the { inside of the {{ }}. Is there another way I could make this work?
#jack.the.ripper is correct. Move the logic to a function in the $scope and call that instead.
$scope.name = function (row) {
if (row.testTypeId == 1) {
return test.exams.dataMap[row.examId].name;
} else {
return '';
}
}
In the HTML:
{{ name(row) }}
Ternary operators certainly work, plnkr.
{{ (row.testTypeId == 1) ? test.exams.dataMap[row.examId].name : '' }}
{{ (row.testTypeId == 2) ? test.topics.topicNameMap[row.topicId] : '' }}
You can use ng-show to do this:
<div>
<div ng-repeat="row in test.active">
<div>{{ row.id }}</div>
<div ng-show="row.testTypeId == 1">
{{test.exams.dataMap[row.examId].name }}
</div>
<div ng-show="row.testTypeId == 2">
{{ test.topics.topicNameMap[row.topicId] }}
</div>
</div>
</div>
Why does it need to be in the databinding itself? Couldn't you just use the ng-if directive?
<div ng-if="row.testTypeId == 1">stuff</div>
<div ng-if="row.testTypeId == 2">otherstuff</div>

Resources