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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +18 -0
- data/LICENSE.txt +22 -0
- data/README.md +313 -0
- data/_includes/archive_versions.html +36 -0
- data/_includes/footer.html +5 -0
- data/_includes/head.html +9 -0
- data/_includes/icon.html +10 -0
- data/_includes/nav_tree.html +38 -0
- data/_includes/navbar.html +55 -0
- data/_includes/search_slot.html +19 -0
- data/_includes/shells/bare.html +5 -0
- data/_includes/shells/sidebar-left.html +18 -0
- data/_includes/shells/sidebar-right.html +18 -0
- data/_includes/shells/topnav.html +8 -0
- data/_includes/sidebar.html +10 -0
- data/_layouts/archive-index.html +26 -0
- data/_layouts/archive.html +14 -0
- data/_layouts/bare.html +5 -0
- data/_layouts/default.html +14 -0
- data/_layouts/search.html +15 -0
- data/_layouts/sidebar-left.html +5 -0
- data/_layouts/sidebar-right.html +5 -0
- data/_layouts/topnav.html +5 -0
- data/_sass/bulma/_index.scss +10 -0
- data/_sass/bulma/base/_index.scss +6 -0
- data/_sass/bulma/base/animations.scss +15 -0
- data/_sass/bulma/base/generic.scss +240 -0
- data/_sass/bulma/base/minireset.scss +92 -0
- data/_sass/bulma/base/skeleton.scss +114 -0
- data/_sass/bulma/components/_index.scss +13 -0
- data/_sass/bulma/components/breadcrumb.scss +139 -0
- data/_sass/bulma/components/card.scss +162 -0
- data/_sass/bulma/components/dropdown.scss +188 -0
- data/_sass/bulma/components/menu.scss +165 -0
- data/_sass/bulma/components/message.scss +183 -0
- data/_sass/bulma/components/modal.scss +164 -0
- data/_sass/bulma/components/navbar.scss +799 -0
- data/_sass/bulma/components/pagination.scss +379 -0
- data/_sass/bulma/components/panel.scss +218 -0
- data/_sass/bulma/components/tabs.scss +273 -0
- data/_sass/bulma/elements/_index.scss +16 -0
- data/_sass/bulma/elements/block.scss +6 -0
- data/_sass/bulma/elements/box.scss +59 -0
- data/_sass/bulma/elements/button.scss +659 -0
- data/_sass/bulma/elements/content.scss +289 -0
- data/_sass/bulma/elements/delete.scss +6 -0
- data/_sass/bulma/elements/icon.scss +67 -0
- data/_sass/bulma/elements/image.scss +64 -0
- data/_sass/bulma/elements/loader.scss +15 -0
- data/_sass/bulma/elements/notification.scss +105 -0
- data/_sass/bulma/elements/progress.scss +115 -0
- data/_sass/bulma/elements/table.scss +261 -0
- data/_sass/bulma/elements/tag.scss +219 -0
- data/_sass/bulma/elements/title.scss +130 -0
- data/_sass/bulma/form/_index.scss +9 -0
- data/_sass/bulma/form/checkbox-radio.scss +36 -0
- data/_sass/bulma/form/file.scss +330 -0
- data/_sass/bulma/form/input-textarea.scss +115 -0
- data/_sass/bulma/form/select.scss +144 -0
- data/_sass/bulma/form/shared.scss +178 -0
- data/_sass/bulma/form/tools.scss +352 -0
- data/_sass/bulma/grid/_index.scss +5 -0
- data/_sass/bulma/grid/columns.scss +961 -0
- data/_sass/bulma/grid/grid.scss +209 -0
- data/_sass/bulma/helpers/_index.scss +15 -0
- data/_sass/bulma/helpers/aspect-ratio.scss +12 -0
- data/_sass/bulma/helpers/border.scss +15 -0
- data/_sass/bulma/helpers/color.scss +344 -0
- data/_sass/bulma/helpers/flexbox.scss +62 -0
- data/_sass/bulma/helpers/float.scss +28 -0
- data/_sass/bulma/helpers/gap.scss +24 -0
- data/_sass/bulma/helpers/other.scss +19 -0
- data/_sass/bulma/helpers/overflow.scss +21 -0
- data/_sass/bulma/helpers/position.scss +19 -0
- data/_sass/bulma/helpers/spacing.scss +64 -0
- data/_sass/bulma/helpers/typography.scss +174 -0
- data/_sass/bulma/helpers/visibility.scss +221 -0
- data/_sass/bulma/layout/_index.scss +9 -0
- data/_sass/bulma/layout/container.scss +59 -0
- data/_sass/bulma/layout/footer.scss +23 -0
- data/_sass/bulma/layout/hero.scss +273 -0
- data/_sass/bulma/layout/level.scss +107 -0
- data/_sass/bulma/layout/media.scss +106 -0
- data/_sass/bulma/layout/section.scss +38 -0
- data/_sass/bulma/themes/_index.scss +36 -0
- data/_sass/bulma/themes/dark.scss +57 -0
- data/_sass/bulma/themes/light.scss +147 -0
- data/_sass/bulma/themes/setup.scss +174 -0
- data/_sass/bulma/utilities/_index.scss +7 -0
- data/_sass/bulma/utilities/controls.scss +85 -0
- data/_sass/bulma/utilities/css-variables.scss +502 -0
- data/_sass/bulma/utilities/derived-variables.scss +112 -0
- data/_sass/bulma/utilities/extends.scss +34 -0
- data/_sass/bulma/utilities/functions.scss +310 -0
- data/_sass/bulma/utilities/initial-variables.scss +157 -0
- data/_sass/bulma/utilities/mixins.scss +462 -0
- data/_sass/flow.scss +131 -0
- data/assets/css/theme.scss +3 -0
- data/assets/js/alpine.min.js +21 -0
- data/lib/jekyll-theme-flow.rb +38 -0
- 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
|
+
[](https://github.com/gundestrup/jekyll-theme-flow/actions/workflows/ci.yml)
|
|
4
|
+
[](https://deepwiki.com/gundestrup/jekyll-theme-flow)
|
|
5
|
+
[](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 -%}
|
data/_includes/head.html
ADDED
|
@@ -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>
|
data/_includes/icon.html
ADDED
|
@@ -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,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,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
|
+
— {{ 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 %}
|