monoholic 1.2.0 → 1.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ee37aea1bd4ecf60b33567d582c4363961f49364bd2176f42e8b0de8aaa12ce
4
- data.tar.gz: a00389e09ed54a0d268694fc002614cd0eca0820555d6f888d4442d22e353a34
3
+ metadata.gz: 944d762c5b588ea620fe59093575adf3fe51488e84a04cbb31dd5b34619d9aed
4
+ data.tar.gz: 1ba6737b6d4e3b1e6e207f4cebadb2b51ea7f8608ff89cb139e89d1de8c25561
5
5
  SHA512:
6
- metadata.gz: 47a614360018402b6e397fb4e8f6d16cb267919176a479dbb3c6ac58c68d4c605af839e84379fc84eca2ffb36ab77ab77c546521cd5e77cb3366ac1e561fa868
7
- data.tar.gz: cd0c4518e8d0e39ddfe00c56a8311c63d375c5ee749313e15be1ad4a29316ec36321fd4219b2900b7475b9287a5e57811e8f2c685a4f3d2fbfeec85a8ffde0be
6
+ metadata.gz: 2051528bae7940745198bb450bf329d07f0e203230e05226735625a8da40d6b73bf726a58452f3d016fdefb4a052bd2d38e61655d07c828ec7d5c2adedef313a
7
+ data.tar.gz: 650a541107d5966c16485b3c483654ab3c5f9fa3ca7897401d92f00b423d8eadd4722107b8c97844bbf389879af30966c58a9649d625dc4dc082d52c5a3c3237
data/README.md CHANGED
@@ -48,16 +48,17 @@ plugins:
48
48
  - jekyll-remote-theme
49
49
  - jekyll-feed
50
50
  - jekyll-seo-tag
51
+ - jekyll-sitemap
51
52
  ```
52
53
 
53
- `jekyll-remote-theme` fetches the theme on Pages; `jekyll-feed` and `jekyll-seo-tag` are required by the theme's `head.html` (`{% feed_meta %}`, `{% seo %}`). For project sites, also set `baseurl` (e.g. `/your-repo`) and `url` (e.g. `https://<user>.github.io`). To pin a release: `remote_theme: stiermid/monoholic@v1.2.0`.
54
+ `jekyll-remote-theme` fetches the theme on Pages; `jekyll-feed` and `jekyll-seo-tag` are required by the theme's `head.html` (`{% feed_meta %}`, `{% seo %}`), and `jekyll-sitemap` generates `sitemap.xml` referenced by the theme's `robots.txt`. For project sites, also set `baseurl` (e.g. `/your-repo`) and `url` (e.g. `https://<user>.github.io`). To pin a release: `remote_theme: stiermid/monoholic@v1.3.0`.
54
55
 
55
56
  > **Pages note:** Native GitHub Pages builds run Jekyll 3.9. The `monoholic` RubyGem requires Jekyll 4.4, so on GitHub Pages use `remote_theme` only (not `theme:` + `gem "monoholic"`). SCSS intentionally uses `@import` for 3.9 compatibility.
56
57
 
57
58
  | Install method | Jekyll | How |
58
59
  | -------------------------------------------------------- | ------------- | --------------------------- |
59
60
  | RubyGems (`theme: monoholic`) | 4.4 | local / CI / non-Pages host |
60
- | GitHub Pages (`remote_theme: stiermid/monoholic@v1.2.0`) | 3.9 via Pages | Pages only |
61
+ | GitHub Pages (`remote_theme: stiermid/monoholic@v1.3.0`) | 3.9 via Pages | Pages only |
61
62
 
62
63
  Or, simply fork this repository, adapt the `_config.yml` according to your needs, and you're good to go!
63
64
 
@@ -67,6 +68,8 @@ Or, simply fork this repository, adapt the `_config.yml` according to your needs
67
68
 
68
69
  Once installed, build your site using the provided layouts (`default`, `home`, `page`, `post`).
69
70
 
71
+ On pages using the `home` layout, page content appears before the sections defined in `_data/menu.yml`.
72
+
70
73
  ### Configuration
71
74
 
72
75
  Override the default settings in your `_config.yml`. Key theme configuration options:
@@ -133,6 +136,15 @@ entries:
133
136
 
134
137
  Nesting can go as deep as needed — `menu.html` includes itself recursively for each `entries` array it encounters.
135
138
 
139
+ Top-level titles use `h2`. Each titled parent advances its children by one heading level, capped at `h6`. Entries with missing, empty, or whitespace-only titles are unlabelled groups: they render no heading and do not advance the heading level. Later siblings always retain their own level, regardless of the depth of earlier branches.
140
+
141
+ Each titled section is labelled by its heading. Heading IDs include the ancestor path and sibling index, so repeated titles remain distinct. When including multiple copies of a menu on the same page, give each copy a distinct `id_prefix` to avoid overlapping IDs:
142
+
143
+ ```liquid
144
+ {% include menu.html collection=site.data.menu.entries level=2 id_prefix='primary' %}
145
+ {% include menu.html collection=site.data.menu.entries level=2 id_prefix='secondary' %}
146
+ ```
147
+
136
148
  #### Using External Content Files
137
149
 
138
150
  You can reference external markdown files instead of inline content:
@@ -171,6 +183,23 @@ Note: the theme uses `@import` (not `@use`) to stay compatible with GitHub Pages
171
183
 
172
184
  To override CSS custom properties (colors, spacing, fonts) without touching SCSS, redeclare the variables in your own stylesheet — they are exposed under `:root` in `_sass/_variables.scss`.
173
185
 
186
+ ### Responsive Content
187
+
188
+ Long words, URLs, and inline code wrap when necessary. Plain and highlighted code blocks preserve indentation and source lines, scrolling horizontally inside the block instead of expanding the page.
189
+
190
+ The small, dependency-free `assets/js/content-scroll.js` script progressively enhances tables with scroll containers while preserving native table semantics. Overflowing tables and code blocks receive a keyboard tab stop, an accessible name, and a visible scrolling hint. These are updated when the viewport, content dimensions, or fonts change; fitting content does not add automatic tab stops.
191
+
192
+ Table captions are used as accessible names when available. Existing author-provided labels, descriptions, and tab indices are preserved. You can translate the default labels and hint in `_config.yml`:
193
+
194
+ ```yaml
195
+ theme_config:
196
+ table_scroll_label: "Table"
197
+ code_scroll_label: "Code block"
198
+ scroll_hint: "Scroll horizontally to see more."
199
+ ```
200
+
201
+ Without JavaScript, tables use fixed-layout, wrapping cells, and code blocks still scroll. For especially wide tables that should scroll even without JavaScript, supply a `.table-scroll` wrapper with `tabindex="0"`, `role="region"`, and an accessible name (`aria-label` or `aria-labelledby`). The enhancement reuses that wrapper rather than nesting another one.
202
+
174
203
  ### Per-Page JavaScript
175
204
 
176
205
  To load custom JavaScript files on a specific page, add a `custom_js` list to the page's front matter:
@@ -188,6 +217,52 @@ Each entry is a filename (without `.js`) relative to `assets/js/`. The example a
188
217
 
189
218
  ## Contributing
190
219
 
220
+ ### Running Tests
221
+
222
+ ```sh
223
+ bundle install
224
+ npm ci
225
+ npx playwright install --with-deps chromium firefox webkit
226
+ bundle exec ruby _tests/release_workflow_test.rb
227
+ bundle exec ruby _tests/release_tag_test.rb
228
+ bundle exec ruby _tests/home_layout_test.rb
229
+ bundle exec ruby _tests/menu_layout_test.rb
230
+ JEKYLL_SAFE=1 bundle exec ruby _tests/menu_layout_test.rb
231
+ npm run test:browser
232
+ ```
233
+
234
+ Browser tests build and serve an isolated fixture site. They cover Chromium, Firefox, and WebKit at 320px, 375px, 768px, and 1280px, including long text, plain and highlighted code, Markdown and HTML tables, keyboard scrolling, resizing, and JavaScript-disabled layouts. External fonts are blocked so the tests do not depend on Google Fonts being available.
235
+
236
+ Menu rendering checks cover branching recursion, deep nesting, untitled groups, repeated titles, unique IDs, escaped labels, and independent menu instances in normal and Jekyll safe mode. Browser tests also verify native heading and section semantics with JavaScript disabled.
237
+
238
+ To run one browser, use `npm run test:browser -- --project=chromium`. You can also set `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` to use a locally installed Chromium binary. Generated sites, screenshots, and traces are ignored by Git; CI retains failure diagnostics for seven days.
239
+
240
+ ### Release Validation
241
+
242
+ Both pull requests and release-tag pushes run the build and test checks. Publishing depends on all checks succeeding and is restricted to pushed `v*` tags; pull requests never publish. The tag must be `v` followed by the exact gem version in `monoholic.gemspec`, including any RubyGems prerelease suffix. Update the version metadata and lockfiles together before tagging.
243
+
244
+ CI builds the gem once and installs it into a temporary gem home. A clean consumer site uses that installed package with the existing lockfile dependencies, without downloading gems or falling back to repository theme files. The checks build root and `/blog` sites and verify layouts, compiled CSS, scripts, favicons, feeds, and URLs. Negative tests reject broken packages and invalid versions.
245
+
246
+ After validation, tag runs upload the gem and its SHA-256 manifest as a seven-day artifact. The publishing job downloads those same bytes, verifies the checksum and package name/version, and pushes the same gem to GitHub Packages and RubyGems—without checking out or rebuilding the source. Rerunning validation replaces the artifact only after checks succeed; if it has expired, rerun validation rather than just the publishing job.
247
+
248
+ Publishing keeps the existing authentication: `GITHUB_TOKEN` with package-write permission for GitHub Packages, and the repository's `RUBYGEMS_API_KEY` secret for RubyGems. Validation has read-only repository permissions; registry credentials are used only by publishing steps.
249
+
250
+ To exercise package checks locally without publishing (publisher verification requires Bash and `sha256sum` from GNU coreutils, matching the Linux CI runner):
251
+
252
+ ```sh
253
+ mkdir -p _tests/.release
254
+ bundle exec gem build monoholic.gemspec --output _tests/.release/monoholic.gem
255
+ bundle exec ruby _tests/package_consumer_test.rb _tests/.release/monoholic.gem
256
+ bundle exec ruby _tests/package_consumer_negative_test.rb _tests/.release/monoholic.gem
257
+ (
258
+ cd _tests/.release
259
+ sha256sum monoholic.gem > monoholic.gem.sha256
260
+ )
261
+ bundle exec ruby _tests/package_integrity_test.rb _tests/.release/monoholic.gem _tests/.release/monoholic.gem.sha256
262
+ ```
263
+
264
+ `package_integrity_test.rb` exercises the actual publisher verification recipe with valid, tampered, missing, and malformed inputs, plus a mismatched release tag. It never runs registry publishing commands. Release outputs are ignored by Git, and temporary package installations are removed after the checks finish.
265
+
191
266
  Bug reports and pull requests are welcome on GitHub at [https://github.com/stiermid/monoholic](https://github.com/stiermid/monoholic). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://www.contributor-covenant.org/) code of conduct.
192
267
 
193
268
  ## License
data/_includes/menu.html CHANGED
@@ -1,21 +1,25 @@
1
- {%- assign _level = include.level | default: 2 | plus: 0 -%}
2
- {%- if _level < 2 -%}
3
- {%- assign _level = 2 -%}
4
- {%- elsif _level > 6 -%}
5
- {%- assign _level = 6 -%}
6
- {%- endif -%}
7
- {%- assign _next_level = _level | plus: 1 -%}
8
- {%- if _next_level > 6 -%}
9
- {%- assign _next_level = 6 -%}
10
- {%- endif -%}
11
1
  {%- for item in include.collection -%}
2
+ {%- comment -%}
3
+ Liquid assigns are shared across recursive includes. Recompute each entry
4
+ from the scoped include parameters before rendering its heading or children.
5
+ {%- endcomment -%}
6
+ {%- assign _level = include.level | default: 2 | plus: 0 -%}
7
+ {%- if _level < 2 -%}
8
+ {%- assign _level = 2 -%}
9
+ {%- elsif _level > 6 -%}
10
+ {%- assign _level = 6 -%}
11
+ {%- endif -%}
12
12
  {%- assign _title_stripped = item.title | strip -%}
13
13
  {%- assign _has_title = true -%}
14
- {%- if item.title == nil or _title_stripped == empty -%}
14
+ {%- if item.title == null or _title_stripped == empty -%}
15
15
  {%- assign _has_title = false -%}
16
16
  {%- endif -%}
17
+ {%- assign _next_level = _level -%}
18
+ {%- if _has_title and _level < 6 -%}
19
+ {%- assign _next_level = _level | plus: 1 -%}
20
+ {%- endif -%}
17
21
  {%- assign _title_slug = item.title | slugify -%}
18
- {%- if _title_slug == empty or _title_slug == nil -%}
22
+ {%- if _title_slug == empty or _title_slug == null -%}
19
23
  {%- assign _title_slug = 'section' -%}
20
24
  {%- endif -%}
21
25
  {%- if include.parent_id -%}
@@ -38,32 +42,34 @@
38
42
  | append: forloop.index
39
43
  -%}
40
44
  {%- endif -%}
41
- {%- if _has_title -%}
42
- <section aria-labelledby="{{ _heading_id }}">
45
+ <section
46
+ {% if _has_title %}
47
+ aria-labelledby="{{ _heading_id | escape }}"
48
+ {% endif %}
49
+ >
50
+ {%- if _has_title -%}
43
51
  {%- if _level == 3 -%}
44
- <h3 class="section-title" id="{{ _heading_id }}">
52
+ <h3 class="section-title" id="{{ _heading_id | escape }}">
45
53
  {{ item.title | escape }}
46
54
  </h3>
47
55
  {%- elsif _level == 4 -%}
48
- <h4 class="section-title" id="{{ _heading_id }}">
56
+ <h4 class="section-title" id="{{ _heading_id | escape }}">
49
57
  {{ item.title | escape }}
50
58
  </h4>
51
59
  {%- elsif _level == 5 -%}
52
- <h5 class="section-title" id="{{ _heading_id }}">
60
+ <h5 class="section-title" id="{{ _heading_id | escape }}">
53
61
  {{ item.title | escape }}
54
62
  </h5>
55
63
  {%- elsif _level >= 6 -%}
56
- <h6 class="section-title" id="{{ _heading_id }}">
64
+ <h6 class="section-title" id="{{ _heading_id | escape }}">
57
65
  {{ item.title | escape }}
58
66
  </h6>
59
67
  {%- else -%}
60
- <h2 class="section-title" id="{{ _heading_id }}">
68
+ <h2 class="section-title" id="{{ _heading_id | escape }}">
61
69
  {{ item.title | escape }}
62
70
  </h2>
63
71
  {%- endif -%}
64
- {%- else -%}
65
- <section>
66
- {%- endif -%}
72
+ {%- endif -%}
67
73
  {%- if item.content_file -%}
68
74
  {%- assign _menu_page = site.pages
69
75
  | where: 'path', item.content_file
@@ -77,7 +83,8 @@
77
83
  {%- endif -%}
78
84
  {%- if item.post_list -%}{%- include post_list.html -%}{%- endif -%}
79
85
  {%- if item.entries -%}
80
- {%- include menu.html
86
+ {%-
87
+ include menu.html
81
88
  collection=item.entries
82
89
  level=_next_level
83
90
  parent_id=_heading_id
@@ -16,6 +16,14 @@
16
16
  {%- include footer.html -%}
17
17
  {%- endunless -%}
18
18
 
19
+ <script
20
+ defer
21
+ src="{{ '/assets/js/content-scroll.js' | relative_url }}"
22
+ data-table-label="{{ site.theme_config.table_scroll_label | default: 'Table' | escape }}"
23
+ data-code-label="{{ site.theme_config.code_scroll_label | default: 'Code block' | escape }}"
24
+ data-scroll-hint="{{ site.theme_config.scroll_hint | default: 'Scroll horizontally to see more.' | escape }}"
25
+ ></script>
26
+
19
27
  {% if page.custom_js %}
20
28
  {% for js_file in page.custom_js %}
21
29
  <script
data/_layouts/home.html CHANGED
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  layout: default
3
3
  ---
4
+ {{ content }}
5
+
4
6
  <nav aria-label="Site sections">
5
7
  {%- include menu.html collection=site.data.menu.entries level=2 -%}
6
8
  </nav>
data/_sass/_base.scss CHANGED
@@ -8,6 +8,8 @@ body {
8
8
  font-family: var(--font-family);
9
9
  font-size: var(--font-size-base);
10
10
  line-height: 1.5;
11
+ // Break unusually long words and URLs only when they cannot fit.
12
+ overflow-wrap: anywhere;
11
13
  min-height: 100vh;
12
14
  margin: 0;
13
15
  padding: 0;
data/_sass/_content.scss CHANGED
@@ -4,20 +4,22 @@
4
4
  color: var(--bg-color);
5
5
  }
6
6
 
7
- div.highlighter-rouge {
8
- code {
9
- display: block;
10
- overflow-x: auto;
11
- white-space: pre-wrap;
12
- }
7
+ .page-content pre {
8
+ max-width: 100%;
9
+ overflow-x: auto;
10
+ // Keep indentation and source lines intact; scroll the block, not the page.
11
+ white-space: pre;
12
+ overflow-wrap: normal;
13
+ }
13
14
 
14
- pre.highlight {
15
- padding: var(--space-md);
16
- }
15
+ div.highlighter-rouge pre.highlight {
16
+ padding: var(--space-md);
17
17
  }
18
18
 
19
19
  table {
20
20
  width: 100%;
21
+ // Readable wrapping is the fallback when scripts are unavailable.
22
+ table-layout: fixed;
21
23
  margin-bottom: var(--space-md);
22
24
 
23
25
  &,
@@ -29,6 +31,26 @@ table {
29
31
  }
30
32
  }
31
33
 
34
+ .table-scroll {
35
+ max-width: 100%;
36
+ overflow-x: auto;
37
+ margin-bottom: var(--space-md);
38
+
39
+ table {
40
+ // Keep native table layout and semantics inside the scroll container.
41
+ table-layout: auto;
42
+ overflow-wrap: normal;
43
+ margin-bottom: 0;
44
+ }
45
+ }
46
+
47
+ .scroll-hint {
48
+ color: var(--meta-color);
49
+ font-size: var(--font-size-sm);
50
+ margin-top: calc(-1 * var(--space-sm));
51
+ margin-bottom: var(--space-md);
52
+ }
53
+
32
54
  blockquote {
33
55
  font-style: italic;
34
56
  border: thin solid var(--border-color);
@@ -0,0 +1,109 @@
1
+ (() => {
2
+ const settings = document.currentScript?.dataset || {};
3
+ const updates = [];
4
+ let hintIndex = 0;
5
+
6
+ const updateAll = () => updates.forEach((update) => update());
7
+ const observer =
8
+ typeof ResizeObserver === "function" ? new ResizeObserver(updateAll) : null;
9
+ const contentObserver =
10
+ typeof MutationObserver === "function"
11
+ ? new MutationObserver(updateAll)
12
+ : null;
13
+
14
+ function enhance(region, content, hintAnchor, label, labelledBy) {
15
+ // Also respect author-provided wrappers and repeated script inclusion.
16
+ if (region.hasAttribute("data-scroll-enhanced")) return;
17
+ region.setAttribute("data-scroll-enhanced", "");
18
+ const originalAttributes = new Set(region.getAttributeNames());
19
+ const hint = document.createElement("p");
20
+ do {
21
+ hint.id = `monoholic-scroll-hint-${++hintIndex}`;
22
+ } while (document.getElementById(hint.id));
23
+ hint.className = "scroll-hint";
24
+ hint.textContent =
25
+ settings.scrollHint || "Scroll horizontally to see more.";
26
+ hint.hidden = true;
27
+ hintAnchor.after(hint);
28
+
29
+ function setAutomaticAttribute(name, value) {
30
+ if (originalAttributes.has(name)) return;
31
+ if (value === null) region.removeAttribute(name);
32
+ else region.setAttribute(name, value);
33
+ }
34
+
35
+ function update() {
36
+ const overflows = region.scrollWidth > region.clientWidth + 1;
37
+ hint.hidden = !overflows;
38
+ setAutomaticAttribute("tabindex", overflows ? "0" : null);
39
+ setAutomaticAttribute("role", overflows ? "region" : null);
40
+ if (
41
+ !originalAttributes.has("aria-label") &&
42
+ !originalAttributes.has("aria-labelledby")
43
+ ) {
44
+ setAutomaticAttribute(
45
+ labelledBy ? "aria-labelledby" : "aria-label",
46
+ overflows ? labelledBy || label : null,
47
+ );
48
+ }
49
+
50
+ // Preserve descriptions supplied by the author or other scripts.
51
+ const descriptions = new Set(
52
+ (region.getAttribute("aria-describedby") || "")
53
+ .split(/\s+/)
54
+ .filter(Boolean),
55
+ );
56
+ if (overflows) descriptions.add(hint.id);
57
+ else descriptions.delete(hint.id);
58
+ if (descriptions.size) {
59
+ region.setAttribute("aria-describedby", [...descriptions].join(" "));
60
+ } else {
61
+ region.removeAttribute("aria-describedby");
62
+ }
63
+ }
64
+
65
+ updates.push(update);
66
+ update();
67
+ observer?.observe(region);
68
+ if (content !== region) observer?.observe(content);
69
+ contentObserver?.observe(content, {
70
+ childList: true,
71
+ characterData: true,
72
+ subtree: true,
73
+ });
74
+ }
75
+
76
+ document.querySelectorAll(".page-content table").forEach((table) => {
77
+ let wrapper = table.parentElement;
78
+ if (!wrapper.classList.contains("table-scroll")) {
79
+ wrapper = document.createElement("div");
80
+ wrapper.className = "table-scroll";
81
+ table.before(wrapper);
82
+ wrapper.append(table);
83
+ }
84
+ const label =
85
+ table.getAttribute("aria-label") ||
86
+ table.caption?.textContent.trim() ||
87
+ settings.tableLabel ||
88
+ "Table";
89
+ enhance(
90
+ wrapper,
91
+ table,
92
+ wrapper,
93
+ label,
94
+ table.getAttribute("aria-labelledby"),
95
+ );
96
+ });
97
+
98
+ document.querySelectorAll(".page-content pre").forEach((block) => {
99
+ const hintAnchor = block.closest("div.highlighter-rouge") || block;
100
+ enhance(block, block, hintAnchor, settings.codeLabel || "Code block");
101
+ });
102
+
103
+ window.addEventListener("resize", updateAll);
104
+ // A font swap can change overflow without resizing the container itself.
105
+ if (document.fonts) {
106
+ document.fonts.ready.then(updateAll);
107
+ document.fonts.addEventListener("loadingdone", updateAll);
108
+ }
109
+ })();
data/robots.txt ADDED
@@ -0,0 +1,8 @@
1
+ ---
2
+ layout: null
3
+ sitemap: false
4
+ ---
5
+ User-agent: *
6
+ Allow: /
7
+
8
+ Sitemap: {{ site.url }}{{ site.baseurl }}/sitemap.xml
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monoholic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Agil Mammadov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-16 00:00:00.000000000 Z
11
+ date: 2026-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: jekyll-sitemap
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.4'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.4'
69
83
  description:
70
84
  email:
71
85
  - mammadovagil@proton.me
@@ -96,6 +110,8 @@ files:
96
110
  - assets/favicon.ico
97
111
  - assets/favicon.svg
98
112
  - assets/js/.keep
113
+ - assets/js/content-scroll.js
114
+ - robots.txt
99
115
  homepage: https://github.com/stiermid/monoholic
100
116
  licenses:
101
117
  - GPL-3.0-only