jekyll-documents 0.1.2 → 0.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 +4 -4
- data/CHANGELOG.md +67 -0
- data/README.md +24 -51
- data/_includes/category_list.html +3 -1
- data/_includes/documents_list.html +1 -1
- data/_includes/documents_search.html +2 -0
- data/_includes/latest_documents.html +2 -2
- data/_layouts/document.html +1 -1
- data/jekyll-documents.gemspec +19 -11
- data/lib/jekyll/documents/file_type_icons.rb +20 -11
- data/lib/jekyll/documents/filters.rb +9 -8
- data/lib/jekyll/documents/generator.rb +34 -21
- data/lib/jekyll/documents/json_index_generator.rb +9 -8
- data/lib/jekyll/documents/tags/latest_documents.rb +21 -18
- data/lib/jekyll/documents/utils.rb +3 -0
- data/lib/jekyll/documents/version.rb +1 -1
- metadata +76 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3865d4ab22aa0cf85e53ad31d222e4e4d025f7f53fb1271a949d326ee8ad60a3
|
|
4
|
+
data.tar.gz: 483721501a072d99ade0088e958b52e02583b4d13de7ee26ecd74bc7141b9c87
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c923ebb2b6e801ab1449b76ed999e8408d234ddb03c03c5b6bf21086c54a49a6fbc7d74b258049248ae53c159c81814d7f23ee44e1f590d9c89f49814bf56630
|
|
7
|
+
data.tar.gz: 639afd3c1abce1196a31b7fb7e34acc197d681f5dc863c53b480f7d127b104db0e27c9adb02c88889dcc62977f4d86162bfade3a077ea269f811e0f24a6da3da
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,72 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## [0.3.0] - 2026-07-23
|
|
5
|
+
|
|
6
|
+
### Added
|
|
7
|
+
- **Baked icon data**: Generator now bakes `icon_url` and `icon_set` into each document's data at build time, eliminating the need for Liquid context in filters
|
|
8
|
+
- **`FileTypeIcons.icon_for` class method**: Allows icon URL resolution without a Liquid context (used by generator)
|
|
9
|
+
- **Search JavaScript wired up**: `_includes/documents_search.html` now loads Lunr.js and `documents-search.js` for out-of-the-box client-side search
|
|
10
|
+
- **jekyll-sitemap integration**: `TextStaticFile` exposes `sitemap: false` data to exclude generated JSON index from sitemap
|
|
11
|
+
- **Unit tests for `FileTypeIcons.icon_for`**: 5 new tests covering all icon sets, fallbacks, and nil handling
|
|
12
|
+
- **Generator tests for icon data**: Tests verifying `icon_url` and `icon_set` are correctly baked into document data
|
|
13
|
+
- **System test for full build pipeline**: End-to-end test covering generator → JSON index → tag rendering
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- **Minimum Ruby version**: Bumped from `>= 2.7` to `>= 3.1` (Ruby 2.7 EOL March 2023, 3.0 EOL April 2024)
|
|
17
|
+
- **RuboCop `TargetRubyVersion`**: Updated from `2.7` to `3.1` to match gemspec
|
|
18
|
+
- **Templates use baked icon data**: `latest_documents.html`, `documents_list.html`, `document.html` now use `{{ doc.icon_url }}` instead of the broken `file_type_icon_tag` filter
|
|
19
|
+
- **`category_list.html` icon set**: Now reads `icon_set` from first document's baked data instead of non-functional `site.documents.icon_set`
|
|
20
|
+
- **`latest_documents.html` count fallback**: Simplified to `| default: 5` since `site.config` is inaccessible in Liquid
|
|
21
|
+
- **Reek configuration**: Updated `.reek.yml` with targeted exclusions for design-inherent warnings
|
|
22
|
+
- **Code quality**: Renamed uncommunicative variables (`s` → `slug`/`result`, `d` → `doc`, `m` → `match`, `y/m/d` → `year/month/day`) across all source files
|
|
23
|
+
- **Reduced duplicate method calls**: Extracted `data = doc.data` locals in generator, JSON index generator, and latest documents tag
|
|
24
|
+
- **Simplified `get_icon_set`**: Reduced from 6 statements to 3 using safe navigation with `dig`
|
|
25
|
+
- **Test suite**: 167 examples (up from 79), 100% line coverage (212/212 lines)
|
|
26
|
+
- **RuboCop**: 0 offenses (24 files inspected)
|
|
27
|
+
- **Reek**: 0 warnings (7 files inspected)
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- **Icon set config ignored in templates** (High): `file_type_icon_tag` filter never received Liquid context, causing `icon_set` config to be silently ignored — always fell back to `"color"`. Fixed by baking icon URLs into document data at generation time
|
|
31
|
+
- **`rel_path` slicing** (Low): Replaced fragile `path[(site.source.length + 1)..]` with `String#delete_prefix` for robustness
|
|
32
|
+
- **`Date.parse` in `parse_filename`** (Low): Replaced with `Date.new(year, month, day)` using integer-converted regex captures for clarity
|
|
33
|
+
- **`category_list.html` folder icon** (Low): `site.documents.icon_set` always resolved to `nil` since `site.documents` is an array — now reads from baked document data
|
|
34
|
+
- **Search include missing JavaScript** (Medium): `documents_search.html` had input/results elements but no script tags — now loads Lunr.js and search JS
|
|
35
|
+
- **No active jekyll-sitemap integration** (Low): JSON index file now flagged with `sitemap: false` to exclude it from sitemap
|
|
36
|
+
|
|
37
|
+
## [0.2.0] - 2026-03-12
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- **Comprehensive code quality tools** (RuboCop, Reek, Bundler Audit, SimpleCov)
|
|
41
|
+
- **98.99% test coverage** with integration tests for Liquid tags
|
|
42
|
+
- **Enhanced release automation** with 10 safety checks and validations
|
|
43
|
+
- **Pre-commit hooks** for automatic quality checks
|
|
44
|
+
- **Dry-run mode** for release preview
|
|
45
|
+
- **Rollback capability** for undoing releases
|
|
46
|
+
- **Automated CHANGELOG templates** when bumping versions
|
|
47
|
+
- **Release notes generator** with clipboard integration
|
|
48
|
+
- **Git status and dependency checks** before release
|
|
49
|
+
- **Version consistency validation** across files
|
|
50
|
+
- **Post-release verification** with helpful links
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
- **Consolidated documentation** (README.Development.md combines all dev docs)
|
|
54
|
+
- **Simplified README.md** with KISS approach
|
|
55
|
+
- **Improved Rake tasks** with better organization and help system
|
|
56
|
+
- **Enhanced test suite** with 79 passing tests
|
|
57
|
+
- **Better error handling** in release scripts
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
- **Liquid tag testing** through integration tests (resolves 98% coverage)
|
|
61
|
+
- **Keyword argument compatibility** in filters
|
|
62
|
+
- **Release script safety** with comprehensive validation
|
|
63
|
+
- **Documentation consistency** across all markdown files
|
|
64
|
+
|
|
65
|
+
### Development
|
|
66
|
+
- **Quality metrics**: 98.99% coverage • 0 vulnerabilities • 3 RuboCop offenses
|
|
67
|
+
- **Release workflow**: Fully automated with rollback capability
|
|
68
|
+
- **Testing**: 79 examples, 0 failures, integration tests for all features
|
|
69
|
+
|
|
3
70
|
## [0.1.2] - 2026-03-09
|
|
4
71
|
|
|
5
72
|
### Added
|
data/README.md
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
# jekyll-documents
|
|
2
2
|
|
|
3
|
-
Turn files in `assets/documents/` into browsable document pages
|
|
3
|
+
Turn files in `assets/documents/` into browsable document pages.
|
|
4
4
|
|
|
5
|
-
**Features
|
|
6
|
-
- Auto-collection from files
|
|
7
|
-
- File type icons (4 styles)
|
|
8
|
-
- Categories from folders
|
|
9
|
-
- Client-side search
|
|
10
|
-
- Strict validation
|
|
5
|
+
**Features**: Auto-collection • File icons • Categories • Search
|
|
11
6
|
|
|
12
7
|
## Quick Start
|
|
13
8
|
|
|
@@ -38,89 +33,67 @@ assets/documents/minutes/2026-02-15_Board_Meeting.docx
|
|
|
38
33
|
{% include category_list.html %}
|
|
39
34
|
```
|
|
40
35
|
|
|
41
|
-
## Requirements
|
|
42
|
-
|
|
43
|
-
Ruby >= 2.7, Jekyll >= 4.0
|
|
44
36
|
## File Naming
|
|
45
37
|
|
|
46
|
-
**Format
|
|
38
|
+
**Format**: `YYYY-MM-DD_Title.ext`
|
|
47
39
|
|
|
48
40
|
```
|
|
49
41
|
assets/documents/reports/2026-03-01_Annual_Report.pdf
|
|
50
|
-
assets/documents/minutes/2026-02-15_Board_Meeting.docx
|
|
51
42
|
```
|
|
52
43
|
|
|
53
|
-
|
|
54
|
-
- Title: Underscores → spaces
|
|
55
|
-
- Category: From folder name
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
## File Type Icons
|
|
60
|
-
|
|
61
|
-
The plugin automatically displays file type icons for all supported formats. Icons are included in the gem and based on designs from [svgrepo.com](https://www.svgrepo.com/).
|
|
44
|
+
Date → `YYYY-MM-DD` • Title → underscores to spaces • Category → folder name
|
|
62
45
|
|
|
63
|
-
|
|
46
|
+
## Icons
|
|
64
47
|
|
|
65
|
-
|
|
48
|
+
4 icon sets: `color` (default), `lines`, `minimal`, `ultra-minimal`
|
|
66
49
|
|
|
67
|
-
**Configuration:**
|
|
68
50
|
```yaml
|
|
69
51
|
documents:
|
|
70
|
-
icon_set: "color"
|
|
52
|
+
icon_set: "color"
|
|
71
53
|
```
|
|
72
54
|
|
|
73
|
-
**Icons appear in:** document pages, lists, search results, category folders
|
|
74
|
-
|
|
75
|
-
**Liquid filters:**
|
|
76
55
|
```liquid
|
|
77
56
|
{{ page.file_type | file_type_icon_tag }}
|
|
78
|
-
{{ page.file_type | file_type_icon }}
|
|
79
57
|
```
|
|
80
58
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
## Includes
|
|
59
|
+
## Usage
|
|
84
60
|
|
|
85
61
|
```liquid
|
|
86
62
|
{% include latest_documents.html count=5 %}
|
|
87
63
|
{% include documents_list.html %}
|
|
88
|
-
{% include category_list.html %}
|
|
89
64
|
{% include documents_search.html %}
|
|
90
65
|
```
|
|
91
66
|
|
|
92
|
-
## Search
|
|
93
|
-
|
|
94
|
-
```html
|
|
95
|
-
<script src="https://unpkg.com/lunr/lunr.js"></script>
|
|
96
|
-
<script src="{{ '/assets/js/documents-search.js' | relative_url }}"></script>
|
|
97
|
-
```
|
|
98
67
|
## Configuration
|
|
99
68
|
|
|
100
69
|
```yaml
|
|
101
70
|
documents:
|
|
102
71
|
root: "assets/documents"
|
|
103
|
-
|
|
104
|
-
icon_set: "color" # color, lines, minimal, ultra-minimal
|
|
105
|
-
include_extensions: [".pdf", ".docx", ".pptx", ".xlsx"]
|
|
72
|
+
icon_set: "color"
|
|
106
73
|
strict_filename: true
|
|
107
|
-
json_index: true
|
|
108
74
|
```
|
|
109
75
|
|
|
110
76
|
See [configuration.rb](lib/jekyll/documents/configuration.rb) for all options.
|
|
77
|
+
|
|
111
78
|
## Development
|
|
112
79
|
|
|
113
80
|
```bash
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
cd example && bundle exec jekyll serve # Example site
|
|
81
|
+
rake # All quality checks
|
|
82
|
+
rake quick # Fast check
|
|
83
|
+
rake help # Show commands
|
|
118
84
|
```
|
|
119
85
|
|
|
120
|
-
|
|
86
|
+
**Quality**: 98.99% coverage • 0 vulnerabilities • RuboCop • Reek
|
|
87
|
+
|
|
88
|
+
See [README.Development.md](README.Development.md) for details.
|
|
121
89
|
|
|
122
|
-
|
|
90
|
+
## Release
|
|
123
91
|
|
|
124
|
-
|
|
92
|
+
```bash
|
|
93
|
+
./bump_version.sh patch
|
|
94
|
+
./release.sh
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## License
|
|
125
98
|
|
|
126
|
-
Icons by [SVG Repo](https://www.svgrepo.com)
|
|
99
|
+
AGPL-3.0-only • Icons by [SVG Repo](https://www.svgrepo.com)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
{% assign first_doc = site.documents | first %}
|
|
2
|
+
{% assign icon_set = first_doc.icon_set | default: 'color' %}
|
|
1
3
|
{% assign cats = site.documents | map: "category" | uniq | sort %}
|
|
2
4
|
<ul class="documents-category-list">
|
|
3
5
|
{% for cat in cats %}
|
|
4
6
|
<li>
|
|
5
|
-
<img src="/assets/icons/
|
|
7
|
+
<img src="{{ '/assets/icons/' | append: icon_set | append: '/folder-svgrepo-com.svg' | relative_url }}" alt="Folder" class="folder-icon" />
|
|
6
8
|
<span class="category-name">{{ cat }}</span>
|
|
7
9
|
<span class="category-count">({{ site.documents | where: "category", cat | size }})</span>
|
|
8
10
|
</li>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<ul class="documents-list">
|
|
3
3
|
{% for doc in docs %}
|
|
4
4
|
<li>
|
|
5
|
-
{{ doc.file_type |
|
|
5
|
+
<img src="{{ doc.icon_url | relative_url }}" alt="{{ doc.file_type | upcase }} file" class="file-icon" />
|
|
6
6
|
<a href="{{ doc.url | relative_url }}">{{ doc.title }}</a>
|
|
7
7
|
<small>({{ doc.date | date: "%Y-%m-%d" }}, {{ doc.category }})</small>
|
|
8
8
|
</li>
|
|
@@ -2,3 +2,5 @@
|
|
|
2
2
|
<input id="doc-search-input" type="search" placeholder="Search documents…" aria-label="Search documents" />
|
|
3
3
|
<div id="doc-search-results" class="documents-search-results"></div>
|
|
4
4
|
</div>
|
|
5
|
+
<script src="https://unpkg.com/lunr/lunr.js"></script>
|
|
6
|
+
<script src="{{ '/assets/js/documents-search.js' | relative_url }}"></script>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
{% assign count = include.count | default:
|
|
1
|
+
{% assign count = include.count | default: 5 %}
|
|
2
2
|
{% assign docs = site.documents | sort: "date" | reverse | slice: 0, count %}
|
|
3
3
|
<ul class="latest-documents">
|
|
4
4
|
{% for doc in docs %}
|
|
5
5
|
<li>
|
|
6
|
-
{{ doc.file_type |
|
|
6
|
+
<img src="{{ doc.icon_url | relative_url }}" alt="{{ doc.file_type | upcase }} file" class="file-icon" />
|
|
7
7
|
<a href="{{ doc.url | relative_url }}">{{ doc.title }}</a>
|
|
8
8
|
<small>({{ doc.date | date: "%Y-%m-%d" }}, {{ doc.category }})</small>
|
|
9
9
|
</li>
|
data/_layouts/document.html
CHANGED
|
@@ -13,7 +13,7 @@ layout: default
|
|
|
13
13
|
|
|
14
14
|
<p>
|
|
15
15
|
<a href="{{ page.file_url | relative_url }}" class="document-download">
|
|
16
|
-
{{ page.file_type |
|
|
16
|
+
<img src="{{ page.icon_url | relative_url }}" alt="{{ page.file_type | upcase }} file" class="file-icon" />
|
|
17
17
|
Download ({{ page.extension | remove: "." | upcase }})
|
|
18
18
|
</a>
|
|
19
19
|
</p>
|
data/jekyll-documents.gemspec
CHANGED
|
@@ -3,34 +3,42 @@
|
|
|
3
3
|
Gem::Specification.new do |spec|
|
|
4
4
|
spec.name = "jekyll-documents"
|
|
5
5
|
spec.version = File.read(File.expand_path("lib/jekyll/documents/version.rb", __dir__))
|
|
6
|
-
|
|
6
|
+
.match(/VERSION\s*=\s*"([^"]+)"/)[1]
|
|
7
7
|
spec.authors = ["Svend Gundestrup"]
|
|
8
8
|
spec.email = ["no-reply@borg-collective.eu"]
|
|
9
9
|
|
|
10
|
-
spec.summary = "Auto-generate Jekyll pages for documents (PDF/DOCX/...)
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
spec.summary = "Auto-generate Jekyll pages for documents (PDF/DOCX/...) " \
|
|
11
|
+
"with category/date/title parsing."
|
|
12
|
+
spec.description = "A Jekyll plugin + theme that scans assets/documents/**, " \
|
|
13
|
+
"creates a collection item per file, adds metadata " \
|
|
14
|
+
"(title/date/category), outputs pages, generates " \
|
|
15
|
+
"a JSON index for Lunr, and integrates with jekyll-sitemap."
|
|
13
16
|
spec.homepage = "https://github.com/gundestrup/jekyll-documents"
|
|
14
17
|
spec.license = "AGPL-3.0-only"
|
|
15
18
|
|
|
16
19
|
spec.metadata = {
|
|
17
|
-
"source_code_uri"
|
|
18
|
-
"bug_tracker_uri"
|
|
19
|
-
"changelog_uri"
|
|
20
|
+
"source_code_uri" => "https://github.com/gundestrup/jekyll-documents",
|
|
21
|
+
"bug_tracker_uri" => "https://github.com/gundestrup/jekyll-documents/issues",
|
|
22
|
+
"changelog_uri" => "https://github.com/gundestrup/jekyll-documents/blob/main/CHANGELOG.md",
|
|
20
23
|
"documentation_uri" => "https://github.com/gundestrup/jekyll-documents",
|
|
21
|
-
"homepage_uri"
|
|
24
|
+
"homepage_uri" => "https://github.com/gundestrup/jekyll-documents",
|
|
22
25
|
"rubygems_mfa_required" => "true"
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
spec.required_ruby_version = ">=
|
|
28
|
+
spec.required_ruby_version = ">= 3.1"
|
|
26
29
|
|
|
27
30
|
spec.files = Dir.glob("{lib,assets,_includes,_layouts}/**/*") +
|
|
28
31
|
["README.md", "CHANGELOG.md", "LICENSE", "jekyll-documents.gemspec"]
|
|
29
32
|
spec.require_paths = ["lib"]
|
|
30
33
|
|
|
31
34
|
spec.add_dependency "jekyll", ">= 4.0"
|
|
32
|
-
|
|
33
|
-
spec.add_development_dependency "
|
|
35
|
+
|
|
36
|
+
spec.add_development_dependency "bundler-audit", "~> 0.9"
|
|
34
37
|
spec.add_development_dependency "rake", "~> 13.0"
|
|
38
|
+
spec.add_development_dependency "reek", "~> 6.1"
|
|
39
|
+
spec.add_development_dependency "rspec", "~> 3.12"
|
|
40
|
+
spec.add_development_dependency "rubocop", "~> 1.60"
|
|
41
|
+
spec.add_development_dependency "rubocop-performance", "~> 1.20"
|
|
42
|
+
spec.add_development_dependency "simplecov", "~> 1.0"
|
|
35
43
|
spec.add_development_dependency "yard", "~> 0.9"
|
|
36
44
|
end
|
|
@@ -95,6 +95,18 @@ module Jekyll
|
|
|
95
95
|
}
|
|
96
96
|
}.freeze
|
|
97
97
|
|
|
98
|
+
# Returns the icon URL for a given file type and explicit icon set
|
|
99
|
+
# @param file_type [String] the file extension (e.g., 'pdf', 'docx')
|
|
100
|
+
# @param icon_set [String] the icon set name (defaults to 'color')
|
|
101
|
+
# @return [String] the icon file URL
|
|
102
|
+
# @example
|
|
103
|
+
# FileTypeIcons.icon_for('pdf', 'lines') #=> "/assets/icons/lines/pdf-svgrepo-com.svg"
|
|
104
|
+
def self.icon_for(file_type, icon_set = "color")
|
|
105
|
+
icons = ICON_MAP[icon_set] || ICON_MAP["color"]
|
|
106
|
+
icons[file_type.to_s.downcase] ||
|
|
107
|
+
"/assets/icons/#{icon_set}/unknown-document-svgrepo-com.svg"
|
|
108
|
+
end
|
|
109
|
+
|
|
98
110
|
# Returns the icon URL for a given file type using configured icon set
|
|
99
111
|
# @param file_type [String] the file extension (e.g., 'pdf', 'docx')
|
|
100
112
|
# @param context [Liquid::Context] the Liquid context for accessing site config
|
|
@@ -102,9 +114,7 @@ module Jekyll
|
|
|
102
114
|
# @example
|
|
103
115
|
# file_type_icon('pdf') #=> "/assets/icons/color/pdf.svg"
|
|
104
116
|
def file_type_icon(file_type, context = nil)
|
|
105
|
-
|
|
106
|
-
icons = ICON_MAP[icon_set] || ICON_MAP["color"]
|
|
107
|
-
icons[file_type.to_s.downcase] || "/assets/icons/#{icon_set}/unknown-document-svgrepo-com.svg"
|
|
117
|
+
Jekyll::Documents::FileTypeIcons.icon_for(file_type, get_icon_set(context))
|
|
108
118
|
end
|
|
109
119
|
|
|
110
120
|
# Returns an HTML img tag for the file type icon
|
|
@@ -114,10 +124,11 @@ module Jekyll
|
|
|
114
124
|
# @param context [Liquid::Context] the Liquid context for accessing site config
|
|
115
125
|
# @return [String] HTML img tag
|
|
116
126
|
# @example
|
|
117
|
-
# file_type_icon_tag('pdf') #=>
|
|
127
|
+
# file_type_icon_tag('pdf') #=> \
|
|
128
|
+
# '<img src="/assets/icons/color/pdf.svg" alt="PDF file" class="file-icon" />'
|
|
118
129
|
def file_type_icon_tag(file_type, css_class: "file-icon", alt: nil, context: nil)
|
|
119
130
|
url = file_type_icon(file_type, context)
|
|
120
|
-
alt_text = alt || "#{file_type.upcase} file"
|
|
131
|
+
alt_text = alt || "#{file_type.to_s.upcase} file"
|
|
121
132
|
%(<img src="#{url}" alt="#{alt_text}" class="#{css_class}" />)
|
|
122
133
|
end
|
|
123
134
|
|
|
@@ -128,13 +139,11 @@ module Jekyll
|
|
|
128
139
|
# @return [String] the icon set name
|
|
129
140
|
def get_icon_set(context)
|
|
130
141
|
return "color" unless context
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
icon_set = documents_config["icon_set"] if documents_config
|
|
135
|
-
|
|
136
|
-
# Validate icon set exists
|
|
142
|
+
|
|
143
|
+
site = context.registers[:site]
|
|
144
|
+
icon_set = site&.config&.dig("documents", "icon_set")
|
|
137
145
|
return "color" unless icon_set && ICON_MAP.key?(icon_set)
|
|
146
|
+
|
|
138
147
|
icon_set
|
|
139
148
|
end
|
|
140
149
|
end
|
|
@@ -9,18 +9,19 @@ module Jekyll
|
|
|
9
9
|
}.freeze
|
|
10
10
|
|
|
11
11
|
# Slugify while handling Danish letters and basic punctuation cleanup.
|
|
12
|
-
def documents_slugify(input, downcase
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
def documents_slugify(input, downcase: true, danish_map: true)
|
|
13
|
+
result = input.to_s.dup
|
|
14
|
+
result = result.gsub(/[æøåÆØÅ]/) { |ch| DANISH_MAP[ch] } if danish_map
|
|
15
|
+
result = result.strip.gsub(/[^\p{Alnum}\-_\s]/u, "")
|
|
16
|
+
result = result.tr(" ", "-").squeeze("-")
|
|
17
|
+
result = result.gsub(/[æøåÆØÅ]/, "") unless danish_map
|
|
18
|
+
result = result.downcase if downcase
|
|
19
|
+
result
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
# Title from filename e.g. "2026-03-01_Title_Here" -> "Title Here"
|
|
23
23
|
def documents_title_from_filename(basename)
|
|
24
|
+
basename = basename.to_s
|
|
24
25
|
if basename =~ /^\d{4}-\d{2}-\d{2}_(.+)$/
|
|
25
26
|
Regexp.last_match(1).tr("_", " ")
|
|
26
27
|
else
|
|
@@ -35,17 +35,19 @@ module Jekyll
|
|
|
35
35
|
end
|
|
36
36
|
next unless @config["include_extensions"].include?(ext)
|
|
37
37
|
|
|
38
|
-
rel_path = path.
|
|
38
|
+
rel_path = path.delete_prefix("#{site.source}/")
|
|
39
39
|
category = infer_category_from(rel_path)
|
|
40
40
|
basename = File.basename(path, ext)
|
|
41
41
|
|
|
42
42
|
date, title, valid = parse_filename(basename)
|
|
43
43
|
if !valid && @config["strict_filename"]
|
|
44
44
|
::Jekyll.logger.abort_with "jekyll-documents",
|
|
45
|
-
|
|
45
|
+
"Filename must be 'YYYY-MM-DD_Title.ext' → #{rel_path}"
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
slug = build_slug(basename)
|
|
49
|
+
file_type = ext.sub(".", "").downcase
|
|
50
|
+
icon_set = @config["icon_set"]
|
|
49
51
|
|
|
50
52
|
doc = ::Jekyll::Document.new(
|
|
51
53
|
source_stub_for(basename, category),
|
|
@@ -53,17 +55,20 @@ module Jekyll
|
|
|
53
55
|
collection: collection
|
|
54
56
|
)
|
|
55
57
|
|
|
56
|
-
doc.data
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
data = doc.data
|
|
59
|
+
data["layout"] = @config["layout"]
|
|
60
|
+
data["title"] = title
|
|
61
|
+
data["date"] = date || File.mtime(path)
|
|
62
|
+
data["category"] = remap_category(category)
|
|
63
|
+
data["file_url"] = "/#{rel_path}"
|
|
64
|
+
data["extension"] = ext
|
|
65
|
+
data["file_type"] = file_type
|
|
66
|
+
data["icon_set"] = icon_set
|
|
67
|
+
data["icon_url"] = Jekyll::Documents::FileTypeIcons.icon_for(file_type, icon_set)
|
|
68
|
+
data["slug"] = slug
|
|
69
|
+
data["permalink"] = @config["permalink"]
|
|
70
|
+
.gsub(":category", data["category"].to_s)
|
|
71
|
+
.gsub(":slug", slug)
|
|
67
72
|
|
|
68
73
|
doc.content = "Auto-generated document page."
|
|
69
74
|
|
|
@@ -99,7 +104,8 @@ module Jekyll
|
|
|
99
104
|
# @return [String] the category name
|
|
100
105
|
def infer_category_from(rel_path)
|
|
101
106
|
return "uncategorized" unless @config["categories_from_path"]
|
|
102
|
-
|
|
107
|
+
|
|
108
|
+
category_dir = File.dirname(rel_path).sub(@config["root"].to_s, "")
|
|
103
109
|
category_dir.split("/").reject(&:empty?).last || "uncategorized"
|
|
104
110
|
end
|
|
105
111
|
|
|
@@ -116,7 +122,10 @@ module Jekyll
|
|
|
116
122
|
# @return [Array<Date, String, Boolean>] date, title, and validity flag
|
|
117
123
|
def parse_filename(basename)
|
|
118
124
|
if basename =~ /^(\d{4})-(\d{2})-(\d{2})_(.+)$/
|
|
119
|
-
|
|
125
|
+
year = Regexp.last_match(1).to_i
|
|
126
|
+
month = Regexp.last_match(2).to_i
|
|
127
|
+
day = Regexp.last_match(3).to_i
|
|
128
|
+
date = Date.new(year, month, day)
|
|
120
129
|
title = Regexp.last_match(4).tr("_", " ")
|
|
121
130
|
[date, title, true]
|
|
122
131
|
else
|
|
@@ -130,12 +139,16 @@ module Jekyll
|
|
|
130
139
|
# @param basename [String] the filename without extension
|
|
131
140
|
# @return [String] the generated slug
|
|
132
141
|
def build_slug(basename)
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
142
|
+
slug = basename.sub(/^\d{4}-\d{2}-\d{2}_/, "")
|
|
143
|
+
if @config["slug_danish_map"]
|
|
144
|
+
slug = slug.gsub(/[æøåÆØÅ]/,
|
|
145
|
+
{ "æ" => "ae", "ø" => "oe", "å" => "aa", "Æ" => "Ae", "Ø" => "Oe",
|
|
146
|
+
"Å" => "Aa" })
|
|
147
|
+
end
|
|
148
|
+
slug = slug.downcase if @config["slug_downcase"]
|
|
149
|
+
slug = slug.gsub(/[^\p{Alnum}\-_\s]/u, "").tr("_ ", "--").squeeze("-")
|
|
150
|
+
slug = slug.sub(/^-+/, "").sub(/-+$/, "")
|
|
151
|
+
slug.empty? ? "untitled" : slug
|
|
139
152
|
end
|
|
140
153
|
end
|
|
141
154
|
end
|
|
@@ -16,15 +16,16 @@ module Jekyll
|
|
|
16
16
|
docs = site.collections["documents"]&.docs || []
|
|
17
17
|
return if docs.empty?
|
|
18
18
|
|
|
19
|
-
items = docs.map do |
|
|
19
|
+
items = docs.map do |doc|
|
|
20
|
+
data = doc.data
|
|
20
21
|
{
|
|
21
|
-
"url"
|
|
22
|
-
"title"
|
|
23
|
-
"category"
|
|
24
|
-
"date"
|
|
25
|
-
"slug"
|
|
26
|
-
"file_type" =>
|
|
27
|
-
"extension" =>
|
|
22
|
+
"url" => doc.url,
|
|
23
|
+
"title" => data["title"],
|
|
24
|
+
"category" => data["category"],
|
|
25
|
+
"date" => (data["date"] || Time.at(0)).strftime("%Y-%m-%d"),
|
|
26
|
+
"slug" => data["slug"],
|
|
27
|
+
"file_type" => data["file_type"],
|
|
28
|
+
"extension" => data["extension"]
|
|
28
29
|
}
|
|
29
30
|
end
|
|
30
31
|
|
|
@@ -7,7 +7,7 @@ module Jekyll
|
|
|
7
7
|
super
|
|
8
8
|
@args = parse_args(markup)
|
|
9
9
|
end
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
public_class_method :new
|
|
12
12
|
|
|
13
13
|
def render(context)
|
|
@@ -17,14 +17,15 @@ module Jekyll
|
|
|
17
17
|
category = @args["category"]
|
|
18
18
|
|
|
19
19
|
docs = site.collections["documents"]&.docs || []
|
|
20
|
-
docs = docs.select { |
|
|
21
|
-
docs = docs.sort_by { |
|
|
20
|
+
docs = docs.select { |doc| doc.data["category"] == category } if category
|
|
21
|
+
docs = docs.sort_by { |doc| doc.data["date"] || Time.at(0) }.reverse.first(count)
|
|
22
22
|
|
|
23
23
|
out = +"<ul class=\"latest-documents\">\n"
|
|
24
|
-
docs.each do |
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
docs.each do |doc|
|
|
25
|
+
data = doc.data
|
|
26
|
+
title = escape_html(data["title"])
|
|
27
|
+
url = escape_html(doc.url)
|
|
28
|
+
date = (data["date"] || Time.at(0)).strftime("%Y-%m-%d")
|
|
28
29
|
out << %(<li><a href="#{url}">#{title}</a> <small>(#{date})</small></li>\n)
|
|
29
30
|
end
|
|
30
31
|
out << "</ul>\n"
|
|
@@ -35,23 +36,26 @@ module Jekyll
|
|
|
35
36
|
|
|
36
37
|
def escape_html(text)
|
|
37
38
|
return "" unless text
|
|
39
|
+
|
|
38
40
|
text.to_s.gsub(/[&<>"']/, {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
"&" => "&",
|
|
42
|
+
"<" => "<",
|
|
43
|
+
">" => ">",
|
|
44
|
+
'"' => """,
|
|
45
|
+
"'" => "'"
|
|
46
|
+
})
|
|
45
47
|
end
|
|
46
48
|
|
|
47
49
|
def parse_args(markup)
|
|
48
50
|
# supports: count:5 category:'referat'
|
|
49
51
|
args = {}
|
|
50
|
-
markup
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
# Safe: markup comes from Jekyll template authors (trusted), not end users
|
|
53
|
+
# Runs only during static site generation, not on user requests
|
|
54
|
+
markup.scan(/(\w+)\s*:\s*'([^']*)'|(\w+)\s*:\s*([^\s]+)/).each do |match|
|
|
55
|
+
if match[0]
|
|
56
|
+
args[match[0]] = match[1]
|
|
53
57
|
else
|
|
54
|
-
args[
|
|
58
|
+
args[match[2]] = match[3]
|
|
55
59
|
end
|
|
56
60
|
end
|
|
57
61
|
args
|
|
@@ -61,4 +65,3 @@ module Jekyll
|
|
|
61
65
|
end
|
|
62
66
|
|
|
63
67
|
Liquid::Template.register_tag("latest_documents", Jekyll::Documents::LatestDocumentsTag)
|
|
64
|
-
|
|
@@ -4,12 +4,15 @@ module Jekyll
|
|
|
4
4
|
module Documents
|
|
5
5
|
# A tiny StaticFile subclass for writing text files during build.
|
|
6
6
|
class TextStaticFile < ::Jekyll::StaticFile
|
|
7
|
+
attr_reader :data
|
|
8
|
+
|
|
7
9
|
def initialize(site, base, rel_dest, content)
|
|
8
10
|
@site = site
|
|
9
11
|
@base = base
|
|
10
12
|
@dir = File.dirname(rel_dest)
|
|
11
13
|
@name = File.basename(rel_dest)
|
|
12
14
|
@content = content
|
|
15
|
+
@data = { "sitemap" => false }
|
|
13
16
|
super(site, base, @dir, @name)
|
|
14
17
|
end
|
|
15
18
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jekyll-documents
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Svend Gundestrup
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: jekyll
|
|
@@ -25,19 +25,19 @@ dependencies:
|
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '4.0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: bundler-audit
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '0.9'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '0.9'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rake
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,6 +52,76 @@ dependencies:
|
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '13.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: reek
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '6.1'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '6.1'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rspec
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '3.12'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '3.12'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rubocop
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '1.60'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '1.60'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rubocop-performance
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '1.20'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '1.20'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: simplecov
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '1.0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - "~>"
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '1.0'
|
|
55
125
|
- !ruby/object:Gem::Dependency
|
|
56
126
|
name: yard
|
|
57
127
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -209,7 +279,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
209
279
|
requirements:
|
|
210
280
|
- - ">="
|
|
211
281
|
- !ruby/object:Gem::Version
|
|
212
|
-
version: '
|
|
282
|
+
version: '3.1'
|
|
213
283
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
214
284
|
requirements:
|
|
215
285
|
- - ">="
|