1
+ <!--
2
+ Copyright © 2024 The Hinode Team / Mark Dumay. All rights reserved.
3
+ Use of this source code is governed by The MIT License (MIT) that can be found in the LICENSE file.
4
+ Visit gethinode.com/license for more details.
5
+ -->
6
+
7
+ <!-- TODO: consider to drop style arg -->
8
+
9
+ {{ $error := false }}
10
+
11
+ <!-- Validate arguments -->
12
+ {{ if partial "utilities/IsInvalidArgs.html" (dict "structure" "navbar" "args" . "group" "partial") }}
13
+ {{ errorf "partial [assets/navbar.html] - Invalid arguments" -}}
14
+ {{ $error = true }}
15
+ {{ end }}
16
+
17
+ <!-- Inline partial to render the color mode switcher -->
18
+ {{- define "partials/navbar-mode.html" -}}
19
+ {{- $size := .size -}}
20
+ {{- $collapsed := .collapsed -}}
21
+ {{- $id := .id -}}
22
+
23
+ < li class ="nav-item dropdown {{ if $collapsed }}d-{{ $size }}-none{{ else }}d-none d-{{ $size }}-block{{ end }} ">
24
+ < a class ="nav-link dropdown-toggle " href ="#! " role ="button " data-bs-toggle ="dropdown " aria-label ="{{ T "colorMode " }}" aria-expanded="false " id ="{{ $id }}-theme{{ if $collapsed }}-collapsed{{ end }} ">
25
+ < span class ="theme-icon-active "> {{- partial "assets/icon.html" (dict "icon" "fas sun fa-fw") }}</ span > {{ if $collapsed }} {{ T "colorMode" }}{{ end }}
26
+ < span class ="d-md-none "> </ span >
27
+ </ a >
28
+ < ul class ="dropdown-menu dropdown-menu-end " aria-labelledby ="{{ $id }}-theme{{ if $collapsed }}-collapsed{{ end }} ">
29
+ < li >
30
+ < a class ="dropdown-item{{ if $collapsed }} switch-mode-collapsed{{ end }} " data-bs-theme-value ="light " href ="#! ">
31
+ < span class ="theme-icon "> {{- partial "assets/icon.html" (dict "icon" "fas sun fa-fw" "spacing" false) }}</ span >
32
+ {{- T "colorLight" }}
33
+ </ a >
34
+ </ li >
35
+ < li >
36
+ < a class ="dropdown-item{{ if $collapsed }} switch-mode-collapsed{{ end }} " data-bs-theme-value ="dark " href ="#! ">
37
+ < span class ="theme-icon "> {{- partial "assets/icon.html" (dict "icon" "fas moon fa-fw" "spacing" false) }}</ span >
38
+ {{- T "colorDark" }}
39
+ </ a >
40
+ </ li >
41
+ < li >
42
+ < a class ="dropdown-item{{ if $collapsed }} switch-mode-collapsed{{ end }} " data-bs-theme-value ="auto " href ="#! ">
43
+ < span class ="theme-icon "> {{- partial "assets/icon.html" (dict "icon" "fas circle-half-stroke fa-fw" "spacing" false) }}</ span >
44
+ {{- T "colorAuto" }}
45
+ </ a >
46
+ </ li >
47
+ </ ul >
48
+ </ li >
49
+ {{- end -}}
50
+
51
+ <!-- Inline partial to render the version switcher -->
52
+ {{- define "partials/navbar-versions.html" -}}
53
+ {{- $size := .size -}}
54
+ {{- $collapsed := .collapsed -}}
55
+ {{- $page := .page -}}
56
+ {{- $baseURL := .baseURL -}}
57
+ {{- $list := site.Params.docs.releases -}}
58
+ {{- $id := .id -}}
59
+ {{- $version := partial "utilities/GetVersion.html" (dict "page" $page) -}}
60
+
61
+ < li class ="nav-item dropdown {{ if $collapsed }}d-{{ $size }}-none{{ else }}d-none d-{{ $size }}-block{{ end }} ">
62
+ < a class ="nav-link dropdown-toggle " href ="#! " role ="button " data-bs-toggle ="dropdown " aria-expanded ="false " id ="{{ $id }}-version-switch ">
63
+ {{ if $collapsed }}{{ site.Title }} {{ end }}{{ $version }}
64
+ </ a >
65
+ < ul class ="dropdown-menu dropdown-menu-end " aria-labelledby ="{{ $id }}-version-switch ">
66
+ {{- range $index, $item := $list -}}
67
+ {{- $active := eq $item.label $version -}}
68
+ {{- $disabled := false -}}
69
+ {{- if hugo.IsServer }}
70
+ {{- $disabled = and $item.redirect (gt (len $item.redirect) 0) -}}
71
+ {{- end -}}
72
+ {{ if $item.url }}
73
+ < li >
74
+ {{- $url := (urls.JoinPath $baseURL $item.url) | relLangURL -}}
75
+ < a class ="pe-5 dropdown-item{{ if $collapsed }} switch-mode-collapsed{{ end }}{{ if $active }} active{{ end }}{{ if $disabled }} disabled{{ end }} " href ="{{ $url }} "> {{ $item.label }}
76
+ {{ if $item.latest }} ({{ T "latest" }}){{ end }}
77
+ {{ if $active }}
78
+ < span class ="position-absolute end-0 me-3 "> {{- partial "assets/icon.html" (dict "icon" "fas check fa-fw") }}</ span >
79
+ {{ end }}
80
+ </ a >
81
+ </ li >
82
+ {{ else }}
83
+ {{ if gt $index 0}}< li > < hr class ="dropdown-divider "> </ li > {{ end }}
84
+ < li > < span class ="dropdown-header fs-6 "> {{ $item.label }}</ span > </ li >
85
+ {{ end }}
86
+ {{- end -}}
87
+ {{- if site.Params.docs.overview -}}
88
+ {{ if gt (len $list) 0 }}< li > < hr class ="dropdown-divider "> </ li > {{ end }}
89
+ < li >
90
+ {{- $url := (urls.JoinPath $baseURL site.Params.docs.overview) | relLangURL -}}
91
+ < a class ="dropdown-item{{ if $collapsed }} switch-mode-collapsed{{ end }} " href ="{{ $url }} "> {{ T "allVersions" }}</ a >
92
+ </ li >
93
+ {{- end -}}
94
+ </ ul >
95
+ </ li >
96
+ {{- end -}}
97
+
98
+ <!-- Initialize arguments -->
99
+ {{- $absoluteURL := site.Params.main.canonifyAssetsURLs | default false -}}
100
+ {{- $id := .id | default (printf "navbar-%d" 0) -}}
101
+ {{- $page := .page -}}
102
+ {{- $baseURL := $page.Scratch.Get "baseURL" -}}
103
+
104
+ {{- $defaultMenu := "main" -}}
105
+ {{- $menuName := .menus | default $defaultMenu }}
106
+ {{- $menus := index site.Menus $menuName -}}
107
+ {{- if or (ne (printf "%T" $menus) "navigation.Menu") (ne (index $menus 0).Menu $menuName) -}}
108
+ {{- if ne $menuName $defaultMenu }}
109
+ {{- errorf "partial [assets/navbar.html] - Invalid value for param 'menus': %s" $menuName -}}
110
+ {{- end -}}
111
+ {{- end -}}
112
+
113
+ {{- $size := .size | default "md" -}}
114
+ {{- $fixed := .fixed | default false -}}
115
+ {{- $overlay := .overlay | default false -}}
116
+ {{- $overlayMode := .overlayMode | default "dark" -}}
117
+ {{- if eq $overlayMode "none" }}{{ $overlayMode = "" }}{{ end }}
118
+ {{- $color := .color | default "" -}}
119
+ {{- $search := .search | default site.Params.navigation.search -}}
120
+ {{- $searchModal := and $search site.Params.navigation.searchModal -}}
121
+ {{- $enableDarkMode := .mode | default site.Params.main.enableDarkMode -}}
122
+
123
+ {{- $enableVersions := false -}}
124
+ {{ $list := site.Params.docs.releases }}
125
+ {{ if $list }}
126
+ {{- $enableVersions = gt (len $list ) 1 -}}
127
+ {{ end }}
128
+
129
+ {{- $enableLanguage := or $page.IsTranslated site.IsMultiLingual -}}
130
+ {{- $horizontal := default false site.Params.navigation.horizontal -}}
131
+
132
+ {{- $logo := .logo | default site.Params.navigation.logo -}}
133
+ {{- $logoLight := "" -}}
134
+ {{- $logoDark := "" -}}
135
+ {{- if $enableDarkMode -}}
136
+ {{ $ext := path.Ext $logo -}}
137
+ {{- $logoLight = printf "%s-light%s" (strings.TrimSuffix $ext $logo) $ext -}}
138
+ {{- $logoDark = printf "%s-dark%s" (strings.TrimSuffix $ext $logo) $ext -}}
139
+ {{- $light := fileExists (path.Join "/static" $logoLight) -}}
140
+ {{- $dark := fileExists (path.Join "/static" $logoDark) -}}
141
+ {{- if and $light (not $dark) -}}
142
+ {{- warnf "partial [assets/navbar.html] - Missing file: %s" $logoDark -}}
143
+ {{- $logoLight = "" -}}
144
+ {{- $logoDark = "" -}}
145
+ {{- end -}}
146
+ {{- if and (not $light) $dark -}}
147
+ {{- warnf "partial [assets/navbar.html] - Missing file: %s" $logoLight -}}
148
+ {{- $logoLight = "" -}}
149
+ {{- $logoDark = "" -}}
150
+ {{- end -}}
151
+ {{- if not (or $light $dark) -}}
152
+ {{- $logoLight = "" -}}
153
+ {{- $logoDark = "" -}}
154
+ {{- end -}}
155
+ {{- end -}}
156
+
157
+ {{ if $logo }}{{ $logo = urls.JoinPath $baseURL $logo }}{{ end }}
158
+ {{ if $logoLight }}{{ $logoLight = urls.JoinPath $baseURL $logoLight }}{{ end }}
159
+ {{ if $logoDark }}{{ $logoDark = urls.JoinPath $baseURL $logoDark }}{{ end }}
160
+
161
+ {{- $title := site.Title -}}
162
+ {{- if .title -}}
163
+ {{- $title = .title -}}
164
+ {{- if not .logo }}{{ $logo = "" }}{{ end -}}
165
+ {{- end -}}
166
+
167
+ {{- $pre := .Pre -}}
168
+ {{- $post := .Post -}}
169
+
170
+ {{- $theme := "light" -}}
171
+ {{- if in (slice "primary" "secondary" "success" "danger" "black") $color }}{{ $theme = "dark" }}{{ end -}}
172
+ {{- if in (slice "body" "body-tertiary") $color }}{{ $theme = "" }}{{ end -}}
173
+ {{- if not $color }}{{ $theme = "" }}{{ end -}}
174
+ {{- $class := .class -}}
175
+
176
+ {{- $contrast := false -}}
177
+ {{- if in (slice "primary" "secondary" "success" "danger") $color }}{{ $contrast = true }}{{ end -}}
178
+
179
+ <!-- Main code -->
180
+ < div class ="container-fluid {{ if $fixed }}fixed-top{{ end }} p-0{{ with $class }} {{ . }}{{ end }} ">
181
+ {{- partial "assets/page-alert.html" (dict "page" $page) -}}
182
+ < nav class ="navbar p-4
183
+ {{- if not $overlay }}{{ with $color }} bg-{{ . }}{{ end }}{{ end -}}
184
+ {{ if $fixed }} navbar-fixed-top{{ end }} navbar-expand-{{ $size -}}
185
+ {{ if $contrast }} navbar-contrast{{ end }} "
186
+ {{ if $overlay }}
187
+ data-bs-theme ="{{ $overlayMode }} "
188
+ data-bs-overlay ="{{ $overlayMode }} "
189
+ {{ else }}{{ with $theme }}data-bs-theme ="{{ . }} "{{ end }}{{ end }}
190
+ {{ if $overlay }}data-navbar-color ="{{ $color }} "{{ end }}
191
+ >
192
+ < div class ="container-xxl p-0 ">
193
+ < div class ="d-flex navbar-container justify-content-center ">
194
+ <!-- Insert sidebar toggler when applicable -->
195
+ < div class ="d-flex align-items-center ">
196
+ {{- if $page.Scratch.Get "sidebar" -}}
197
+ < button class ="navbar-toggler collapsed p-0 mx-auto fw-30 " type ="button " data-bs-toggle ="offcanvas " data-bs-target ="#offcanvass-sidebar " aria-controls ="offcanvass-sidebar " aria-label ="{{ T "toggleSidebar " }}">
198
+ {{- partial "assets/icon.html" (dict "icon" "fas ellipsis fa-fw" "spacing" false) -}}
199
+ </ button >
200
+ {{- else -}}
201
+ <!-- Insert invisible sidebar toggler to center logo correctly on smaller screens -->
202
+ < button class ="navbar-toggler collapsed p-0 mx-auto invisible fw-30 " type ="button ">
203
+ {{- partial "assets/icon.html" (dict "icon" "fas ellipsis fa-fw" "spacing" false) -}}
204
+ </ button >
205
+ {{- end -}}
206
+ </ div >
207
+
208
+ <!-- Insert the brand logo or name -->
209
+ < div class ="{{ if (or $logoLight $logo) }}mx-auto{{ else }}flex-grow-1 flex-{{ $size }}-grow-0{{ end }} ">
210
+ < a class ="navbar-brand " href ="{{ site.Home.RelPermalink }} " aria-label ="{{ T "home " }}">
211
+ {{- if (and $logoLight $logoDark) -}}
212
+ {{ $width := partial "utilities/GetWidth.html" (dict "path" $logoLight "height" 30) }}
213
+ < img src ="{{if $absoluteURL }}{{ absURL $logoLight }}{{ else }}{{ $logoLight }}{{ end }} " class ="d-none-inline-dark " alt ="{{ $title }} logo " height ="30 "{{ with $width }} width ="{{ . }} "{{ end }} >
214
+ < img src ="{{if $absoluteURL }}{{ absURL $logoDark }}{{ else }}{{ $logoDark }}{{ end }} " class ="d-none-inline-light " alt ="{{ $title }} logo " height ="30 "{{ with $width }} width ="{{ . }} "{{ end }} >
215
+ {{- else if $logo -}}
216
+ {{ $width := partial "utilities/GetWidth.html" (dict "path" $logo "height" 30) }}
217
+ < img src ="{{if $absoluteURL }}{{ absURL $logo }}{{ else }}{{ $logo }}{{ end }} " alt ="{{ $title }} logo " height ="30 "{{ with $width }} width ="{{ . }} "{{ end }} > < small class ="ps-4 d-none d-{{ $size }}-inline "> {{ $title }}</ small >
218
+ {{- else -}}
219
+ < div class ="navbar-title fw-bold h-100 "> {{ $title }}</ div >
220
+ {{- end -}}
221
+ </ a >
222
+ </ div >
223
+
224
+ <!-- Insert main navigation toggler -->
225
+ < div class ="d-flex align-items-center ">
226
+ < button class ="navbar-toggler main-nav-toggler collapsed p-0 " type ="button " data-bs-toggle ="collapse " data-bs-target ="#{{ $id }}-collapse "
227
+ aria-controls ="{{ $id }} " aria-expanded ="false " aria-label ="{{ T "toggleMainNav " }}">
228
+ < span class ="toggler-icon top-bar emphasis{{ with $theme }}-{{ . }}{{ end }} "> </ span >
229
+ < span class ="toggler-icon middle-bar emphasis{{ with $theme }}-{{ . }}{{ end }} "> </ span >
230
+ < span class ="toggler-icon bottom-bar emphasis{{ with $theme }}-{{ . }}{{ end }} "> </ span >
231
+ </ button >
232
+ </ div >
233
+ </ div >
234
+
235
+ < div class ="navbar-collapse collapse " id ="{{ $id }}-collapse ">
236
+ <!-- Insert search input -->
237
+ {{- if and $search (not $searchModal) }}{{ partial "assets/search-input.html" }}{{ end -}}
238
+
239
+ <!-- Render top-menu items (maximum depth of 2) -->
240
+ < ul class ="navbar-nav ms-auto ">
241
+ {{- range $menu := $menus -}}
242
+ < li class ="nav-item{{ if .HasChildren }} dropdown{{ if $horizontal }} dropdown-horizontal-{{ $size }}{{ end }}{{ end }} ">
243
+ {{- partial "assets/navbar-item.html" (dict "menu" $menu "page" $page) -}}
244
+ {{- if .HasChildren -}}
245
+ < ul class ="dropdown-menu ">
246
+ {{- range .Children -}}
247
+ < li > {{- partial "assets/navbar-item.html" (dict "menu" . "parent" $menu "page" $page) -}}</ li >
248
+ {{- end -}}
249
+ </ ul >
250
+ {{- end -}}
251
+ </ li >
252
+ {{- end -}}
253
+
254
+ <!-- Insert divider if applicable -->
255
+ {{- if and $menus (or $enableLanguage $enableVersions) -}}
256
+ < li class ="nav-item py-2 py-md-1 col-12 col-md-auto d-none d-{{ $size }}-block ">
257
+ < div class ="vr d-none d-md-flex h-100 mx-md-2 "> </ div >
258
+ </ li >
259
+ < li > < hr class ="dropdown-divider-bg "> </ li >
260
+ {{- end -}}
261
+
262
+ <!-- Insert version switcher -->
263
+ {{- if $enableVersions -}}
264
+ {{- partial "partials/navbar-versions.html" (dict "page" $page "size" $size "collapsed" true "id" .id "baseURL" $baseURL) -}}
265
+ {{- partial "partials/navbar-versions.html" (dict "page" $page "size" $size "collapsed" false "id" .id "baseURL" $baseURL) -}}
266
+ {{- end -}}
267
+
268
+ <!-- Insert language switcher if applicable -->
269
+ {{- if $enableLanguage -}}
270
+ {{- $currentLang := $page.Language.Lang -}}
271
+ < li class ="nav-item dropdown ">
272
+ < a class ="nav-link dropdown-toggle d-{{ $size }}-none " href ="#! " role ="button " data-bs-toggle ="dropdown " aria-label ="{{ T "languageSwitcherLabel " }}" aria-expanded="false ">
273
+ {{- partial "assets/icon.html" (dict "icon" "fas globe fa-fw" "spacing" false) }} {{ T "languageSwitcherLabel" }}
274
+ </ a >
275
+ < a class ="nav-link dropdown-toggle d-none d-{{ $size }}-block " href ="#! " role ="button " data-bs-toggle ="dropdown " aria-label ="{{ T "languageSwitcherLabel " }}" aria-expanded="false ">
276
+ {{- partial "assets/icon.html" (dict "icon" "fas globe fa-fw" "spacing" false) }}
277
+ </ a >
278
+ < ul class ="dropdown-menu dropdown-menu-end ">
279
+ {{- if $page.IsTranslated -}}
280
+ {{- range $page.AllTranslations -}}
281
+ < li > < a class ="dropdown-item {{ if eq .Language.Lang $currentLang }}active{{ end }} " href ="{{ .RelPermalink }} "> {{ .Language.LanguageName }}</ a > </ li >
282
+ {{- end -}}
283
+ {{- else -}}
284
+ {{- range site.Languages -}}
285
+ < li > < a class ="dropdown-item " href ="{{ urls.JoinPath $baseURL .Lang }} "> {{ default .Lang .LanguageName }}</ a > </ li >
286
+ {{- end -}}
287
+ {{- end -}}
288
+ </ ul >
289
+ </ li >
290
+ {{- end -}}
291
+
292
+ <!-- Insert color mode switcher -->
293
+ {{- if $enableDarkMode -}}
294
+ {{- partial "partials/navbar-mode.html" (dict "size" $size "collapsed" true "id" .id) -}}
295
+ {{- partial "partials/navbar-mode.html" (dict "size" $size "collapsed" false "id" .id) -}}
296
+ {{- end -}}
297
+
298
+ <!-- Insert modal search button -->
299
+ {{- if $searchModal }}
300
+ < li class ="nav-item py-2 py-md-1 col-12 col-md-auto d-none d-{{ $size }}-block ">
301
+ < div class ="vr d-none d-md-flex h-100 mx-md-2 "> </ div >
302
+ </ li >
303
+ < li > < hr class ="dropdown-divider-bg "> </ li >
304
+
305
+ < a class ="nav-link d-{{ $size }}-none " href ="#! " role ="button " data-bs-toggle ="modal " data-bs-target ="#search-modal " aria-label ="{{ T "ui_search " }}" aria-expanded="false ">
306
+ {{ partial "assets/icon.html" (dict "icon" "fas magnifying-glass fa-fw") }} {{ T "ui_search" }}
307
+ </ a >
308
+ < a class ="nav-link d-none d-{{ $size }}-block " href ="#! " role ="button " data-bs-toggle ="modal " data-bs-target ="#search-modal " aria-label ="{{ T "ui_search " }}" aria-expanded="false ">
309
+ {{ partial "assets/icon.html" (dict "icon" "fas magnifying-glass fa-fw") }}
310
+ </ a >
311
+ {{ end -}}
312
+ </ ul >
313
+ </ div >
314
+ </ div >
315
+ </ nav >
316
+ </ div >
317
+
318
+ {{/* Insert modal search element */}}
319
+ {{- if $searchModal }}
320
+ < div class ="modal fade search-modal " tabindex ="-1 " id ="search-modal " aria-labelledby ="searchModalLabel " aria-hidden ="true ">
321
+ < div class ="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg ">
322
+ < div class ="modal-content h-50 ">
323
+ < div class ="modal-header ">
324
+ < div class ="w-100 ">
325
+ < form class ="search position-relative me-auto ">
326
+ < input id ="search-input-modal " class ="search-input form-control is-search " tabindex ="1 " type ="search " placeholder ="{{ T "ui_search " }}..." aria-label="{{ T "ui_search " }}" autocomplete="off ">
327
+ </ form >
328
+ </ div >
329
+ < button type ="button " class ="btn-close " data-bs-dismiss ="modal " aria-label ="{{ T "close " }}"> </ button >
330
+ </ div >
331
+ < div class ="modal-body p-2 search-background ">
332
+ < div class ="search-suggestions " data-no-results ="{{ T "ui_no_results " }}"> </ div >
333
+ </ div >
334
+ </ div >
335
+ </ div >
336
+ </ div >
337
+ {{ end -}}
0 commit comments