jekyll-theme-flow 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +18 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +313 -0
  5. data/_includes/archive_versions.html +36 -0
  6. data/_includes/footer.html +5 -0
  7. data/_includes/head.html +9 -0
  8. data/_includes/icon.html +10 -0
  9. data/_includes/nav_tree.html +38 -0
  10. data/_includes/navbar.html +55 -0
  11. data/_includes/search_slot.html +19 -0
  12. data/_includes/shells/bare.html +5 -0
  13. data/_includes/shells/sidebar-left.html +18 -0
  14. data/_includes/shells/sidebar-right.html +18 -0
  15. data/_includes/shells/topnav.html +8 -0
  16. data/_includes/sidebar.html +10 -0
  17. data/_layouts/archive-index.html +26 -0
  18. data/_layouts/archive.html +14 -0
  19. data/_layouts/bare.html +5 -0
  20. data/_layouts/default.html +14 -0
  21. data/_layouts/search.html +15 -0
  22. data/_layouts/sidebar-left.html +5 -0
  23. data/_layouts/sidebar-right.html +5 -0
  24. data/_layouts/topnav.html +5 -0
  25. data/_sass/bulma/_index.scss +10 -0
  26. data/_sass/bulma/base/_index.scss +6 -0
  27. data/_sass/bulma/base/animations.scss +15 -0
  28. data/_sass/bulma/base/generic.scss +240 -0
  29. data/_sass/bulma/base/minireset.scss +92 -0
  30. data/_sass/bulma/base/skeleton.scss +114 -0
  31. data/_sass/bulma/components/_index.scss +13 -0
  32. data/_sass/bulma/components/breadcrumb.scss +139 -0
  33. data/_sass/bulma/components/card.scss +162 -0
  34. data/_sass/bulma/components/dropdown.scss +188 -0
  35. data/_sass/bulma/components/menu.scss +165 -0
  36. data/_sass/bulma/components/message.scss +183 -0
  37. data/_sass/bulma/components/modal.scss +164 -0
  38. data/_sass/bulma/components/navbar.scss +799 -0
  39. data/_sass/bulma/components/pagination.scss +379 -0
  40. data/_sass/bulma/components/panel.scss +218 -0
  41. data/_sass/bulma/components/tabs.scss +273 -0
  42. data/_sass/bulma/elements/_index.scss +16 -0
  43. data/_sass/bulma/elements/block.scss +6 -0
  44. data/_sass/bulma/elements/box.scss +59 -0
  45. data/_sass/bulma/elements/button.scss +659 -0
  46. data/_sass/bulma/elements/content.scss +289 -0
  47. data/_sass/bulma/elements/delete.scss +6 -0
  48. data/_sass/bulma/elements/icon.scss +67 -0
  49. data/_sass/bulma/elements/image.scss +64 -0
  50. data/_sass/bulma/elements/loader.scss +15 -0
  51. data/_sass/bulma/elements/notification.scss +105 -0
  52. data/_sass/bulma/elements/progress.scss +115 -0
  53. data/_sass/bulma/elements/table.scss +261 -0
  54. data/_sass/bulma/elements/tag.scss +219 -0
  55. data/_sass/bulma/elements/title.scss +130 -0
  56. data/_sass/bulma/form/_index.scss +9 -0
  57. data/_sass/bulma/form/checkbox-radio.scss +36 -0
  58. data/_sass/bulma/form/file.scss +330 -0
  59. data/_sass/bulma/form/input-textarea.scss +115 -0
  60. data/_sass/bulma/form/select.scss +144 -0
  61. data/_sass/bulma/form/shared.scss +178 -0
  62. data/_sass/bulma/form/tools.scss +352 -0
  63. data/_sass/bulma/grid/_index.scss +5 -0
  64. data/_sass/bulma/grid/columns.scss +961 -0
  65. data/_sass/bulma/grid/grid.scss +209 -0
  66. data/_sass/bulma/helpers/_index.scss +15 -0
  67. data/_sass/bulma/helpers/aspect-ratio.scss +12 -0
  68. data/_sass/bulma/helpers/border.scss +15 -0
  69. data/_sass/bulma/helpers/color.scss +344 -0
  70. data/_sass/bulma/helpers/flexbox.scss +62 -0
  71. data/_sass/bulma/helpers/float.scss +28 -0
  72. data/_sass/bulma/helpers/gap.scss +24 -0
  73. data/_sass/bulma/helpers/other.scss +19 -0
  74. data/_sass/bulma/helpers/overflow.scss +21 -0
  75. data/_sass/bulma/helpers/position.scss +19 -0
  76. data/_sass/bulma/helpers/spacing.scss +64 -0
  77. data/_sass/bulma/helpers/typography.scss +174 -0
  78. data/_sass/bulma/helpers/visibility.scss +221 -0
  79. data/_sass/bulma/layout/_index.scss +9 -0
  80. data/_sass/bulma/layout/container.scss +59 -0
  81. data/_sass/bulma/layout/footer.scss +23 -0
  82. data/_sass/bulma/layout/hero.scss +273 -0
  83. data/_sass/bulma/layout/level.scss +107 -0
  84. data/_sass/bulma/layout/media.scss +106 -0
  85. data/_sass/bulma/layout/section.scss +38 -0
  86. data/_sass/bulma/themes/_index.scss +36 -0
  87. data/_sass/bulma/themes/dark.scss +57 -0
  88. data/_sass/bulma/themes/light.scss +147 -0
  89. data/_sass/bulma/themes/setup.scss +174 -0
  90. data/_sass/bulma/utilities/_index.scss +7 -0
  91. data/_sass/bulma/utilities/controls.scss +85 -0
  92. data/_sass/bulma/utilities/css-variables.scss +502 -0
  93. data/_sass/bulma/utilities/derived-variables.scss +112 -0
  94. data/_sass/bulma/utilities/extends.scss +34 -0
  95. data/_sass/bulma/utilities/functions.scss +310 -0
  96. data/_sass/bulma/utilities/initial-variables.scss +157 -0
  97. data/_sass/bulma/utilities/mixins.scss +462 -0
  98. data/_sass/flow.scss +131 -0
  99. data/assets/css/theme.scss +3 -0
  100. data/assets/js/alpine.min.js +21 -0
  101. data/lib/jekyll-theme-flow.rb +38 -0
  102. metadata +209 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4d919f0246c8224ef02548c7798c4af1233a7efeeb3dff6bde85b1508666d5e5
4
+ data.tar.gz: f64181028f7b27fbfc7b328087666c334fdcbed90a9961b0f500c5981ee3e3ee
5
+ SHA512:
6
+ metadata.gz: 96d99612ad38828cf394dcb62c8cf65eac4c8c7c43b8dd886e00298645fc73cba02ee0132ba7f6b15a03ae9795a458fd13f3a966e325786de73fc54a37d072f3
7
+ data.tar.gz: 18b8ca31782b7dfda56ad0e38c7bad277fb93c98338773676b6fb5f94f26b4f6628e16b8151268dc11b1fc6096edbae4c60bdfdb94eacbd43cf659b1dfe22508
data/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - 2026-10-04
4
+
5
+ - Bulma and Alpine.js theme with sidebar-left, sidebar-right, topnav and bare layouts.
6
+ - Navigation, search and icon integration with jekyll-client-search and jekyll-icon-flow.
7
+ - Real Jekyll consumer-site integration tests and Ruby 3.3/3.4 CI.
8
+ - Escape site and page metadata, keep theme controls on Lucide, and provide a search form fallback.
9
+ - Archive support: `archive` and `archive-index` layouts, `archive_versions` include,
10
+ automatic `noindex` for archived/`noindex: true` pages, and a documented
11
+ scoped-defaults convention for sitemap exclusion.
12
+ - Navigation: `is-active` on the current item and its direct parent in the sidebar
13
+ tree and topnav dropdown; optional `icon:` front matter rendered in both branches.
14
+ - Theme lib (`lib/jekyll-theme-flow.rb`): bundling `jekyll-sitemap` as a runtime
15
+ dependency (auto-loaded with the theme), a `flow.sitemap` disable switch, and a
16
+ hook that excludes archived pages from sitemap.xml when the theme is plugin-loaded.
17
+ - Config defaults injection: plugin-loaded consumers get `sass.quiet_deps: true`
18
+ (silences vendored Bulma deprecation warnings) unless they set it themselves.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ GNU AFFERO GENERAL PUBLIC LICENSE
2
+ Version 3, 19 November 2007
3
+
4
+ Copyright (C) 2026 Svend Gundestrup
5
+
6
+ This project is free software: you can redistribute it and/or modify it under
7
+ the terms of the GNU Affero General Public License as published by the Free
8
+ Software Foundation, either version 3 of the License, or (at your option) any
9
+ later version.
10
+
11
+ This project is distributed in the hope that it will be useful, but WITHOUT
12
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
14
+ details.
15
+
16
+ You should have received a copy of the GNU Affero General Public License along
17
+ with this project. If not, see <https://www.gnu.org/licenses/agpl-3.0.html>.
18
+
19
+ The complete license text is available from the Free Software Foundation at:
20
+ https://www.gnu.org/licenses/agpl-3.0.txt
21
+
22
+ SPDX-License-Identifier: AGPL-3.0-or-later
data/README.md ADDED
@@ -0,0 +1,313 @@
1
+ # jekyll-theme-flow
2
+
3
+ [![CI](https://github.com/gundestrup/jekyll-theme-flow/actions/workflows/ci.yml/badge.svg)](https://github.com/gundestrup/jekyll-theme-flow/actions/workflows/ci.yml)
4
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/gundestrup/jekyll-theme-flow)
5
+ [![SonarCloud: setup pending](https://img.shields.io/badge/SonarCloud-setup%20pending-orange)](https://sonarcloud.io/dashboard?id=gundestrup_jekyll-theme-flow)
6
+
7
+ A Jekyll theme built on [Bulma](https://bulma.io) (CSS) and
8
+ [Alpine.js](https://alpinejs.dev) (interactivity), offering several
9
+ standard layout shells you can switch per site or per page.
10
+
11
+ No Node toolchain required — Bulma compiles through Jekyll's own Sass
12
+ pipeline, and Alpine is vendored into the theme.
13
+
14
+ ## Installation
15
+
16
+ ```ruby
17
+ # Gemfile
18
+ gem "jekyll-theme-flow"
19
+ ```
20
+
21
+ ```yaml
22
+ # _config.yml
23
+ theme: jekyll-theme-flow
24
+ ```
25
+
26
+ `theme:` alone gives you layouts, includes, Sass and assets — Jekyll
27
+ also auto-requires the theme's runtime dependencies
28
+ (`jekyll-client-search`, `jekyll-icon-flow`, `jekyll-sitemap`), so the
29
+ tags, search assets and `sitemap.xml` work without listing them.
30
+
31
+ Every `flow.*`/`icon_flow.*`/`client_search.*` option has a sensible
32
+ default — the theme renders with zero config beyond `theme:`, and each
33
+ key can be overridden individually. When the theme is plugin-loaded it
34
+ also injects one config-level default that Liquid defaults can't reach:
35
+ `sass.quiet_deps: true`, which silences deprecation noise from the
36
+ vendored Bulma Sass while keeping warnings from *your* Sass visible
37
+ (set it explicitly to `false` to opt out).
38
+
39
+ To additionally enable the theme's own hooks (automatic sitemap/noindex
40
+ exclusion for archived pages and the `flow.sitemap` switch), load it as
41
+ a plugin too — either list it under `plugins:`:
42
+
43
+ ```yaml
44
+ plugins:
45
+ - jekyll-theme-flow
46
+ ```
47
+
48
+ or move the gem into the `:jekyll_plugins` group in your Gemfile.
49
+
50
+ ## Layouts
51
+
52
+ Set a site-wide default in `_config.yml`:
53
+
54
+ ```yaml
55
+ flow:
56
+ layout: sidebar-left # sidebar-left | sidebar-right | topnav | bare
57
+ ```
58
+
59
+ Or per page via front matter:
60
+
61
+ ```yaml
62
+ layout: default
63
+ flow_layout: topnav # overrides the site default for this page
64
+ ```
65
+
66
+ Named layouts (`sidebar-left`, `sidebar-right`, `topnav`, `bare`) also
67
+ work directly in front matter.
68
+
69
+ | Shell | What you get |
70
+ |---|---|
71
+ | `sidebar-left` | Sticky left sidebar with expandable nav tree + content column (default) |
72
+ | `sidebar-right` | Same, sidebar on the right |
73
+ | `topnav` | Bulma navbar with hover dropdowns for children, no sidebar |
74
+ | `bare` | Content only — no nav chrome |
75
+
76
+ On mobile, sidebars collapse into a burger-toggled drawer (Alpine).
77
+
78
+ ## Navigation model
79
+
80
+ The nav tree is driven by front matter — same convention as
81
+ just-the-docs:
82
+
83
+ ```yaml
84
+ title: Child Page
85
+ parent: Section # title of the parent page
86
+ nav_order: 3 # optional ordering
87
+ nav_exclude: true # optional: hide from nav
88
+ ```
89
+
90
+ `grand_parent:` is honoured for auto-opening the tree on grandchildren.
91
+ The current page's branch opens automatically; parents get a chevron
92
+ toggle. The current page and its direct parent are marked `is-active`
93
+ in both the sidebar tree and the topnav dropdown.
94
+
95
+ An optional `icon:` front matter key renders an icon next to the title —
96
+ in the flat branch *and* the dropdown branch (resolved by the configured
97
+ default `icon_flow.pack`):
98
+
99
+ ```yaml
100
+ title: Home
101
+ icon: home
102
+ ```
103
+
104
+ ## Search (jekyll-client-search)
105
+
106
+ The theme integrates
107
+ [jekyll-client-search](https://github.com/gundestrup/jekyll-client-search)
108
+ (a runtime dependency — it's pulled in automatically). Enable it:
109
+
110
+ ```yaml
111
+ client_search:
112
+ enabled: true
113
+ engine: minisearch # or elasticlunr / semantic
114
+ collections: [posts] # and/or include_pages: true
115
+ dropdown:
116
+ enabled: true
117
+ redirect_url: /search/
118
+ ```
119
+
120
+ When enabled:
121
+
122
+ - **sidebar layouts** render a search bar in a top bar above the content
123
+ - **topnav** renders a smaller search field on the right of the navbar
124
+ - **bare** renders no search chrome
125
+ - the theme ships a **`search` layout** (`_layouts/search.html`) — add a
126
+ page to your site to use it, since theme gems only ship
127
+ `_layouts`/`_includes`/`_sass`/`assets`, not root pages:
128
+
129
+ ```markdown
130
+ ---
131
+ layout: search
132
+ title: Search
133
+ permalink: /search/
134
+ nav_exclude: true
135
+ ---
136
+ ```
137
+
138
+ All `client_search` options (fuzzy MiniSearch, Ollama embeddings, related
139
+ results, …) work as documented in the gem.
140
+
141
+ ## Icons (jekyll-icon-flow)
142
+
143
+ Icons are provided by the
144
+ [jekyll-icon-flow](https://github.com/gundestrup/jekyll-icon-flow) gem
145
+ (a runtime dependency — pulled in automatically). Per-pack Liquid tags
146
+ emit normalized inline SVGs (`icon icon-<name>` classes, `currentColor`,
147
+ `1em` scaling):
148
+
149
+ ```liquid
150
+ {% icon search %} → default pack (icon_flow.pack)
151
+ {% icon_lucide "file-text" size:1.5em class:"has-text-link" %}
152
+ {% icon_simple github %} → brand icons
153
+ {% icon_custom logo %} → your site's own SVGs
154
+ ```
155
+
156
+ Theme chrome uses `{% icon_lucide %}` for its search icon and navigation
157
+ chevrons, so switching the site's default pack to a brand/custom pack cannot
158
+ silently remove those controls. Set `icon_flow.enabled: false` to hide all
159
+ icons. `{% include icon.html %}` remains a thin wrapper for site icons that
160
+ should follow `icon_flow.pack`.
161
+
162
+ ```yaml
163
+ icon_flow:
164
+ pack: lucide # lucide | simple | custom
165
+ enabled: true # false = icon tags render nothing
166
+ custom_dir: assets/icons/custom # for icon_custom (e.g. svgrepo.com SVGs)
167
+ ```
168
+
169
+ See the gem's README for the full styling contract and adapter model.
170
+
171
+ ## Archiving pages
172
+
173
+ Superseded pages can stay live at their permalink under `/archive/`, get
174
+ a warning banner, and cross-link to their replacement — all driven by
175
+ one front matter key, `archive_link_current`.
176
+
177
+ **Archive a page** — set `layout: archive` and point it at the current
178
+ version:
179
+
180
+ ```yaml
181
+ title: Section (2020)
182
+ layout: archive
183
+ permalink: /archive/section-2020.html # convention: /archive/ + original path
184
+ archive_link_current: /section.html # the page that replaced this one
185
+ nav_exclude: true
186
+ ```
187
+
188
+ The `archive` layout renders a Bulma warning banner ("This is an
189
+ archived version" + link to the current page), then a "Versions of this
190
+ page" footer listing the current version and sibling archives. Archived
191
+ pages also get `<meta name="robots" content="noindex">` automatically —
192
+ `noindex: true` works standalone on any page (e.g. a search page).
193
+
194
+ **Cross-link from the current page** — add one line at the bottom of the
195
+ current version:
196
+
197
+ ```liquid
198
+ {% include archive_versions.html %}
199
+ ```
200
+
201
+ It renders a "Previous versions" footer listing every page whose
202
+ `archive_link_current` points back. Archiving a future version then
203
+ needs zero link maintenance.
204
+
205
+ **Archive index** — ship your own page using the `archive-index` layout:
206
+
207
+ ```yaml
208
+ ---
209
+ layout: archive-index
210
+ title: Archive
211
+ permalink: /archive/
212
+ nav_exclude: true
213
+ ---
214
+ ```
215
+
216
+ It lists every `layout: archive` page sorted by `archive_link_current`.
217
+
218
+ **Sitemap exclusion** — when the theme is also loaded as a plugin
219
+ (`plugins:` list or the `:jekyll_plugins` Gemfile group — see
220
+ Installation), `jekyll-sitemap` is pulled in automatically and archived
221
+ pages are excluded from `sitemap.xml` by a built-in hook. No config or
222
+ front matter needed beyond `layout: archive`. Both switches:
223
+
224
+ ```yaml
225
+ flow:
226
+ sitemap: false # drop the sitemap generator entirely
227
+ archive:
228
+ sitemap_exclude: false # keep archived pages in sitemap.xml
229
+ ```
230
+
231
+ If the theme is consumed via `theme:` only (no plugin load), the hook
232
+ can't run — the equivalent convention is scoped front-matter defaults:
233
+
234
+ ```yaml
235
+ defaults:
236
+ - scope:
237
+ path: "archive"
238
+ values:
239
+ layout: archive
240
+ sitemap: false # excluded from sitemap.xml
241
+ nav_exclude: true
242
+ ```
243
+
244
+ Files under `archive/` then need only `title`, `permalink` and
245
+ `archive_link_current`. (Without the defaults, set `sitemap: false` in
246
+ each page's front matter.)
247
+
248
+ **Strings** — all archive text is configurable:
249
+
250
+ ```yaml
251
+ flow:
252
+ archive:
253
+ banner: "Dette er en arkiveret version."
254
+ current_link: "Se den gældende version"
255
+ versions_heading: "Versioner af denne side"
256
+ previous_heading: "Tidligere versioner"
257
+ current_label: "gældende"
258
+ archived_label: "arkiveret"
259
+ replaced_by: "erstattet af"
260
+ index_empty: "Ingen arkiverede sider."
261
+ ```
262
+
263
+ The demo site shows the convention: `archive/demo-2020.md` is archived
264
+ via the scoped defaults above, `demo-section.md` is its current version,
265
+ and `arkiv.md` uses `archive-index` at `/archive/`.
266
+
267
+ ## Other config
268
+
269
+ ```yaml
270
+ flow:
271
+ layout: sidebar-left
272
+ logo: /assets/logo.svg # brand icon next to site.title (all pages)
273
+ logo_enabled: true # set false to hide without removing logo
274
+ favicon: /assets/favicon.ico # <link rel="icon">
275
+ favicon_enabled: true # set false to disable
276
+ search_placeholder: "Search" # placeholder text in the search field
277
+
278
+ footer_text: "Powered by ..." # optional footer line
279
+ # archive: # banner/footer strings, see "Archiving pages"
280
+ ```
281
+
282
+ ## Customization surface
283
+
284
+ Intentionally small — the theme relies on Bulma components and helpers
285
+ (`menu`, `navbar`, `columns`, `is-hidden-*`, spacing helpers) rather
286
+ than bespoke CSS. The only custom CSS is the app shell (~50 lines in
287
+ `_sass/flow.scss`): fixed/sticky sidebar, drawer positioning, chevron
288
+ rotation, brand icon sizing.
289
+
290
+ Override the usual Jekyll way: same-named files in your site win
291
+ (`_includes/`, `_layouts/`, `_sass/`). Bulma Sass variables can be
292
+ re-themed via `@use "bulma" with (...)`.
293
+
294
+ ## Development
295
+
296
+ ```bash
297
+ bundle install
298
+ bundle exec rake ci # RuboCop, audit, Semgrep, real-site tests and gem contents
299
+ bundle exec jekyll serve # demo pages in repo root
300
+ ```
301
+
302
+ The theme has no project Ruby runtime to instrument with SimpleCov; its
303
+ coverage comes from real consumer-site Jekyll builds, not a misleading Ruby
304
+ percentage. A Codecov badge should be added only with measurable, non-vendored
305
+ browser or template coverage. The SonarCloud badge remains pending until the
306
+ repository is onboarded; the scanner excludes vendored Bulma and Alpine.
307
+ Use `bundle exec rake "version:bump[patch]"` to bump the gemspec and lockfile,
308
+ add a dated changelog entry, and run `bundle exec rake version:pre_release`
309
+ before tagging. GitHub `release` environment and RubyGems trusted publishing
310
+ must be configured before publishing.
311
+
312
+ Known upstream noise: Bulma 1.0.x emits a handful of Sass `if()`
313
+ deprecation warnings during build — harmless, fixed upstream eventually.
@@ -0,0 +1,36 @@
1
+ {% comment %}
2
+ Cross-links a page with its archived versions via the shared
3
+ `archive_link_current` front matter key (set on archived pages).
4
+
5
+ Archived page -> links the current version + sibling archives
6
+ Current page -> lists pages whose archive_link_current == page.url
7
+ (include this file manually at the bottom of the current page)
8
+ {% endcomment %}
9
+
10
+ {%- if page.layout == "archive" and page.archive_link_current -%}
11
+ {%- assign current = site.pages | where: "url", page.archive_link_current | first -%}
12
+ {%- assign siblings = site.pages | where: "archive_link_current", page.archive_link_current -%}
13
+ <hr>
14
+ <p><strong>{{ site.flow.archive.versions_heading | default: "Versions of this page" | escape }}</strong></p>
15
+ <ul>
16
+ <li><a href="{{ page.archive_link_current | relative_url | escape }}">{{ current.title | default: page.archive_link_current | escape }}</a>
17
+ ({{ site.flow.archive.current_label | default: "current" | escape }})</li>
18
+ {%- for v in siblings -%}
19
+ {%- if v.url != page.url %}
20
+ <li><a href="{{ v.url | relative_url | escape }}">{{ v.title | escape }}</a>
21
+ ({{ site.flow.archive.archived_label | default: "archived" | escape }})</li>
22
+ {%- endif -%}
23
+ {%- endfor %}
24
+ </ul>
25
+ {%- elsif page.layout != "archive" -%}
26
+ {%- assign versions = site.pages | where: "archive_link_current", page.url -%}
27
+ {%- if versions.size > 0 %}
28
+ <hr>
29
+ <p><strong>{{ site.flow.archive.previous_heading | default: "Previous versions" | escape }}</strong></p>
30
+ <ul>
31
+ {%- for v in versions %}
32
+ <li><a href="{{ v.url | relative_url | escape }}">{{ v.title | escape }}</a></li>
33
+ {%- endfor %}
34
+ </ul>
35
+ {%- endif %}
36
+ {%- endif -%}
@@ -0,0 +1,5 @@
1
+ <footer class="footer py-4">
2
+ <div class="content has-text-centered is-size-7">
3
+ <p>{{ site.title | escape }}{% if site.flow.footer_text %} · {{ site.flow.footer_text | escape }}{% endif %}</p>
4
+ </div>
5
+ </footer>
@@ -0,0 +1,9 @@
1
+ <head>
2
+ <meta charset="utf-8">
3
+ <meta name="viewport" content="width=device-width, initial-scale=1">
4
+ <title>{% if page.title %}{{ page.title | escape }} · {% endif %}{{ site.title | escape }}</title>
5
+ <meta name="description" content="{{ page.description | default: site.description | strip_html | strip | escape }}">
6
+ {% if page.noindex or page.layout == "archive" %}<meta name="robots" content="noindex">{% endif %}
7
+ <link rel="stylesheet" href="{{ '/assets/css/theme.css' | relative_url }}">
8
+ {% if site.flow.favicon and site.flow.favicon_enabled != false %}<link rel="icon" href="{{ site.flow.favicon | relative_url | escape }}">{% endif %}
9
+ </head>
@@ -0,0 +1,10 @@
1
+ {%- comment -%}
2
+ Thin wrapper over the {% icon %} tag from jekyll-icon-flow, kept for
3
+ sites/includes that prefer the include calling convention:
4
+ {% include icon.html name="search" %}
5
+ {% include icon.html name="github" pack="simple" size="1.5em" %}
6
+ Bracket access on include[...] avoids Hash method collisions and lets
7
+ unset optional params resolve to nil — the tag drops them.
8
+ Configure via icon_flow: in _config.yml (pack, enabled, custom_dir).
9
+ {%- endcomment -%}
10
+ {% icon include.name pack: include["pack"] size: include["size"] class: include["class"] title: include["title"] %}
@@ -0,0 +1,38 @@
1
+ {%- comment -%}
2
+ Recursive nav tree. include.pages = array of pages at this level.
3
+ Children are matched via `parent: <parent title>` front matter.
4
+ Auto-opens when the current page is this node, a child (`parent`),
5
+ or a grandchild (`grand_parent`).
6
+ {%- endcomment -%}
7
+ <ul class="menu-list">
8
+ {%- for p in include.pages -%}
9
+ {%- assign kids = site.html_pages | where: "parent", p.title | where_exp: "k", "k.nav_exclude != true" | sort: "nav_order" -%}
10
+ {%- assign is_active = false -%}
11
+ {%- if p.url == page.url or page.parent == p.title -%}{%- assign is_active = true -%}{%- endif -%}
12
+ {%- if kids.size > 0 -%}
13
+ {%- assign start_open = false -%}
14
+ {%- if is_active or page.parent == p.title or page.grand_parent == p.title -%}{%- assign start_open = true -%}{%- endif %}
15
+ <li x-data="{ open: {{ start_open }} }">
16
+ <div class="is-flex is-justify-content-space-between is-align-items-center">
17
+ <a href="{{ p.url | relative_url | escape }}"{% if is_active %} class="is-active"{% endif %}>
18
+ {%- if p.icon %}<span class="icon">{% icon p.icon %}</span> {% endif -%}
19
+ {{- p.title | escape -}}
20
+ </a>
21
+ <button class="button is-ghost is-small px-2" @click="open = !open" :aria-expanded="open" aria-label="Toggle {{ p.title | escape }}">
22
+ <span class="icon flow-chevron" :class="{ 'is-open': open }">
23
+ {% icon_lucide chevron-right %}
24
+ </span>
25
+ </button>
26
+ </div>
27
+ <div x-show="open" x-cloak>
28
+ {% include nav_tree.html pages=kids %}
29
+ </div>
30
+ </li>
31
+ {%- else -%}
32
+ <li><a href="{{ p.url | relative_url | escape }}"{% if is_active %} class="is-active"{% endif %}>
33
+ {%- if p.icon %}<span class="icon">{% icon p.icon %}</span> {% endif -%}
34
+ {{- p.title | escape -}}
35
+ </a></li>
36
+ {%- endif -%}
37
+ {%- endfor %}
38
+ </ul>
@@ -0,0 +1,55 @@
1
+ {%- assign nav_roots = site.html_pages | where_exp: "p", "p.title" | where_exp: "p", "p.nav_exclude != true" | where_exp: "p", "p.parent == nil" | sort: "nav_order" -%}
2
+ <nav class="navbar{% if include.mode == "mobile-only" %} is-hidden-desktop{% endif %}" role="navigation" aria-label="main navigation" x-data="{ open: false }">
3
+ <div class="navbar-brand">
4
+ <a class="navbar-item has-text-weight-semibold" href="{{ '/' | relative_url }}">
5
+ {%- if site.flow.logo and site.flow.logo_enabled != false %}<img class="flow-brand-icon" src="{{ site.flow.logo | relative_url | escape }}" alt="">{% endif %}
6
+ {{- site.title | escape -}}
7
+ </a>
8
+ {% if include.mode == "mobile-only" -%}
9
+ <button class="navbar-burger" :class="{ 'is-active': menu }" @click="menu = !menu" :aria-expanded="menu" aria-label="menu">
10
+ {%- else -%}
11
+ <button class="navbar-burger" :class="{ 'is-active': open }" @click="open = !open" :aria-expanded="open" aria-label="menu">
12
+ {%- endif %}
13
+ <span aria-hidden="true"></span><span aria-hidden="true"></span><span aria-hidden="true"></span><span aria-hidden="true"></span>
14
+ </button>
15
+ </div>
16
+ {% unless include.mode == "mobile-only" -%}
17
+ <div class="navbar-menu" :class="{ 'is-active': open }">
18
+ <div class="navbar-start">
19
+ {% for p in nav_roots -%}
20
+ {%- assign kids = site.html_pages | where: "parent", p.title | where_exp: "k", "k.nav_exclude != true" | sort: "nav_order" -%}
21
+ {%- assign p_active = false -%}
22
+ {%- if p.url == page.url or page.parent == p.title %}{% assign p_active = true %}{% endif -%}
23
+ {%- if kids.size > 0 %}
24
+ <div class="navbar-item has-dropdown is-hoverable">
25
+ <a class="navbar-link{% if p_active %} is-active{% endif %}" href="{{ p.url | relative_url | escape }}">
26
+ {%- if p.icon %}<span class="icon">{% icon p.icon %}</span> {% endif -%}
27
+ {{- p.title | escape -}}
28
+ </a>
29
+ <div class="navbar-dropdown">
30
+ {% for c in kids -%}
31
+ <a class="navbar-item{% if c.url == page.url %} is-active{% endif %}" href="{{ c.url | relative_url | escape }}">
32
+ {%- if c.icon %}<span class="icon">{% icon c.icon %}</span> {% endif -%}
33
+ {{- c.title | escape -}}
34
+ </a>
35
+ {% endfor -%}
36
+ </div>
37
+ </div>
38
+ {%- else %}
39
+ <a class="navbar-item{% if p_active %} is-active{% endif %}" href="{{ p.url | relative_url | escape }}">
40
+ {%- if p.icon %}<span class="icon">{% icon p.icon %}</span> {% endif -%}
41
+ {{- p.title | escape -}}
42
+ </a>
43
+ {%- endif -%}
44
+ {% endfor %}
45
+ </div>
46
+ {% if site.client_search.enabled -%}
47
+ <div class="navbar-end">
48
+ <div class="navbar-item">
49
+ {% include search_slot.html input_size=" is-small" %}
50
+ </div>
51
+ </div>
52
+ {%- endif %}
53
+ </div>
54
+ {%- endunless %}
55
+ </nav>
@@ -0,0 +1,19 @@
1
+ {%- comment -%}
2
+ Search slot for jekyll-client-search. Renders nothing unless
3
+ site.client_search.enabled. include.input_size: "" or " is-small".
4
+ {%- endcomment -%}
5
+ {%- if site.client_search.enabled -%}
6
+ {%- assign slot_id = include.input_size | default: "full" | slugify -%}
7
+ <div class="flow-search" data-client-search-dropdown>
8
+ <form class="control has-icons-left" role="search" action="{{ '/search/' | relative_url }}" method="get" autocomplete="off" data-cs-dropdown-form>
9
+ <label class="is-sr-only" for="flow-search-input-{{ slot_id }}">{{ site.flow.search_placeholder | default: "Search" | escape }}</label>
10
+ <input id="flow-search-input-{{ slot_id }}" class="input{{ include.input_size }}" type="search" name="q" autocomplete="off"
11
+ placeholder="{{ site.flow.search_placeholder | default: "Search" | escape }}"
12
+ aria-expanded="false" aria-controls="flow-search-results-{{ slot_id }}"
13
+ data-cs-dropdown-input>
14
+ <span class="icon is-left" aria-hidden="true">{% icon_lucide search size:"0.875em" %}</span>
15
+ </form>
16
+ <ul id="flow-search-results-{{ slot_id }}" class="flow-search-results"
17
+ role="listbox" aria-hidden="true" data-cs-dropdown-results></ul>
18
+ </div>
19
+ {%- endif %}
@@ -0,0 +1,5 @@
1
+ <main class="section">
2
+ <div class="content">
3
+ {{ content }}
4
+ </div>
5
+ </main>
@@ -0,0 +1,18 @@
1
+ <div class="columns is-gapless m-0 flow-shell" x-data="{ menu: false }">
2
+ <aside class="column is-narrow flow-sidebar has-background-light" :class="{ 'is-hidden-mobile': !menu }" @click.outside="menu = false">
3
+ {% include sidebar.html %}
4
+ </aside>
5
+ <div class="column">
6
+ {% include navbar.html mode="mobile-only" %}
7
+ {% if site.client_search.enabled %}
8
+ <div class="flow-topbar">
9
+ {% include search_slot.html %}
10
+ </div>
11
+ {% endif %}
12
+ <main class="section">
13
+ <div class="content">
14
+ {{ content }}
15
+ </div>
16
+ </main>
17
+ </div>
18
+ </div>
@@ -0,0 +1,18 @@
1
+ <div class="columns is-gapless m-0 flow-shell" x-data="{ menu: false }">
2
+ <div class="column">
3
+ {% include navbar.html mode="mobile-only" %}
4
+ {% if site.client_search.enabled %}
5
+ <div class="flow-topbar">
6
+ {% include search_slot.html %}
7
+ </div>
8
+ {% endif %}
9
+ <main class="section">
10
+ <div class="content">
11
+ {{ content }}
12
+ </div>
13
+ </main>
14
+ </div>
15
+ <aside class="column is-narrow flow-sidebar flow-right has-background-light" :class="{ 'is-hidden-mobile': !menu }" @click.outside="menu = false">
16
+ {% include sidebar.html %}
17
+ </aside>
18
+ </div>
@@ -0,0 +1,8 @@
1
+ {% include navbar.html %}
2
+ <main class="section">
3
+ <div class="container">
4
+ <div class="content">
5
+ {{ content }}
6
+ </div>
7
+ </div>
8
+ </main>
@@ -0,0 +1,10 @@
1
+ <div class="p-4">
2
+ <a class="is-size-5 has-text-weight-semibold" href="{{ '/' | relative_url }}">
3
+ {%- if site.flow.logo and site.flow.logo_enabled != false %}<img class="flow-brand-icon" src="{{ site.flow.logo | relative_url | escape }}" alt="">{% endif %}
4
+ {{- site.title | escape -}}
5
+ </a>
6
+ </div>
7
+ <nav class="menu px-4 pb-4" aria-label="site navigation">
8
+ {%- assign nav_roots = site.html_pages | where_exp: "p", "p.title" | where_exp: "p", "p.nav_exclude != true" | where_exp: "p", "p.parent == nil" | sort: "nav_order" -%}
9
+ {% include nav_tree.html pages=nav_roots %}
10
+ </nav>
@@ -0,0 +1,26 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+
5
+ <section class="section">
6
+ <div class="container">
7
+ <h1 class="title">{{ page.title | default: "Archive" | escape }}</h1>
8
+ {{ content }}
9
+ {%- assign archived = site.pages | where: "layout", "archive" | sort: "archive_link_current" -%}
10
+ {%- if archived.size > 0 %}
11
+ <ul class="flow-archive-index">
12
+ {%- for p in archived %}
13
+ <li>
14
+ <a href="{{ p.url | relative_url | escape }}">{{ p.title | escape }}</a>
15
+ {%- if p.archive_link_current %}
16
+ &mdash; {{ site.flow.archive.replaced_by | default: "replaced by" | escape }}
17
+ <a href="{{ p.archive_link_current | relative_url | escape }}">{{ site.flow.archive.current_link | default: "current version" | escape }}</a>
18
+ {%- endif %}
19
+ </li>
20
+ {%- endfor %}
21
+ </ul>
22
+ {%- else %}
23
+ <p>{{ site.flow.archive.index_empty | default: "No archived pages." | escape }}</p>
24
+ {%- endif %}
25
+ </div>
26
+ </section>
@@ -0,0 +1,14 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+
5
+ <div class="notification is-warning is-light flow-archive-banner">
6
+ {{ site.flow.archive.banner | default: "This is an archived version." | escape }}
7
+ {%- if page.archive_link_current %}
8
+ <a href="{{ page.archive_link_current | relative_url | escape }}">{{ site.flow.archive.current_link | default: "See the current version" | escape }}</a>
9
+ {%- endif %}
10
+ </div>
11
+
12
+ {{ content }}
13
+
14
+ {% include archive_versions.html %}
@@ -0,0 +1,5 @@
1
+ ---
2
+ layout: default
3
+ flow_layout: bare
4
+ ---
5
+ {{ content }}