datalog-theme 0.6.1 → 0.8.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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +175 -0
  3. data/CITATION.cff +2 -2
  4. data/README.md +26 -19
  5. data/_data/cdn-integrity.yml +0 -30
  6. data/_includes/analytics/dashboard.html +3 -1
  7. data/_includes/components/api-function.html +20 -1
  8. data/_includes/components/author-bio.html +2 -2
  9. data/_includes/components/enhanced-code-block.html +1 -1
  10. data/_includes/components/hero.html +19 -1
  11. data/_includes/csp-meta.html +115 -11
  12. data/_includes/footer.html +19 -20
  13. data/_includes/head.html +61 -29
  14. data/_includes/header/navigation.html +12 -15
  15. data/_includes/header.html +29 -20
  16. data/_includes/layouts/default/article.html +5 -1
  17. data/_includes/meta/math-config.html +27 -1
  18. data/_includes/meta/schema.html +5 -2
  19. data/_includes/meta/scripts-loader.html +16 -31
  20. data/_includes/post/related-posts.html +4 -7
  21. data/_includes/scripts.html +1 -9
  22. data/_includes/search/index-data.json +131 -0
  23. data/_includes/search/page.html +136 -0
  24. data/_layouts/dataset.html +1 -0
  25. data/_layouts/default.html +16 -8
  26. data/_layouts/home.html +6 -0
  27. data/_layouts/notebook.html +1 -0
  28. data/_layouts/package.html +1 -0
  29. data/_layouts/portfolio.html +1 -0
  30. data/_layouts/post.html +20 -5
  31. data/_layouts/project.html +2 -1
  32. data/_plugins/analytics_dashboard.rb +9 -3
  33. data/_plugins/config_validator.rb +12 -7
  34. data/_plugins/csp_generator.rb +18 -28
  35. data/_plugins/datalog_bibliography.rb +9 -7
  36. data/_plugins/datalog_comments.rb +8 -5
  37. data/_plugins/datalog_slides.rb +9 -8
  38. data/_plugins/i18n.rb +7 -8
  39. data/_plugins/image_optimizer.rb +17 -6
  40. data/_plugins/math_preprocessor.rb +36 -3
  41. data/_plugins/notebook_converter.rb +23 -43
  42. data/_plugins/plugin_loader.rb +3 -1
  43. data/_plugins/publications_generator.rb +8 -2
  44. data/_plugins/rouge_highlight_filter.rb +42 -0
  45. data/_plugins/search_code_blocks.rb +30 -0
  46. data/_plugins/search_normalizer.rb +15 -53
  47. data/_plugins/search_pages.rb +72 -0
  48. data/_sass/_academic-dashboard.scss +262 -0
  49. data/_sass/_base.scss +19 -1
  50. data/_sass/_components.scss +77 -1144
  51. data/_sass/_features.scss +17 -0
  52. data/_sass/_font-fallbacks.scss +43 -0
  53. data/_sass/_header.scss +10 -0
  54. data/_sass/_layout.scss +18 -12
  55. data/_sass/_mathematical.scss +1 -1
  56. data/_sass/_notebooks.scss +322 -0
  57. data/_sass/_open-science-badges.scss +56 -0
  58. data/_sass/{_phase1-enhancements.scss → _post-components.scss} +46 -1
  59. data/_sass/_search-page.scss +530 -0
  60. data/_sass/_search.scss +47 -1
  61. data/_sass/_syntax-highlighting.scss +212 -97
  62. data/_sass/_theme.scss +42 -18
  63. data/_sass/_typography.scss +14 -0
  64. data/_sass/_variables.scss +7 -4
  65. data/assets/css/main.scss +14 -0
  66. data/assets/img/hero-detail-640.webp +0 -0
  67. data/assets/img/hero-detail.webp +0 -0
  68. data/assets/img/social-card.png +0 -0
  69. data/assets/js/dist/academic.js +1 -0
  70. data/assets/js/dist/analytics-dashboard.js +1 -0
  71. data/assets/js/dist/chunks/chunk-225H5YXE.js +1 -0
  72. data/assets/js/dist/core.js +1 -0
  73. data/assets/js/dist/loader.js +1 -0
  74. data/assets/js/dist/math.js +1 -0
  75. data/assets/js/dist/notebook.js +1 -0
  76. data/assets/js/dist/search.js +1 -0
  77. data/assets/js/dist/visualizations.js +11 -0
  78. data/assets/js/loader.js +3 -1
  79. data/datalog-theme.gemspec +43 -22
  80. data/lib/datalog/cli.rb +53 -15
  81. data/lib/datalog/plugin_system/dependency_resolver.rb +0 -2
  82. data/lib/datalog/theme/package.rb +57 -0
  83. data/lib/datalog/theme/repository_checkout.rb +90 -0
  84. data/lib/datalog/theme/version.rb +1 -1
  85. data/lib/datalog/warning_filter.rb +5 -11
  86. data/lib/datalog-theme.rb +21 -0
  87. metadata +75 -146
  88. data/_data/academic.yml +0 -217
  89. data/_data/config/author.yml +0 -121
  90. data/_data/config/features.yml +0 -262
  91. data/_data/config/site.yml +0 -42
  92. data/_data/config/theme.yml +0 -181
  93. data/_data/datasets.yml +0 -28
  94. data/_data/js_meta.json +0 -371
  95. data/_data/navigation.yml +0 -145
  96. data/_data/projects.yml +0 -41
  97. data/_data/publications.yml +0 -28
  98. data/_data/social.yml +0 -73
  99. data/_data/visualizations.yml +0 -51
  100. data/_includes/components/advanced-search.html +0 -682
  101. data/_includes/components/bookmark-system.html +0 -96
  102. data/_includes/components/comments.html +0 -244
  103. data/_includes/components/content-recommendations.html +0 -228
  104. data/_includes/components/email-preferences.html +0 -200
  105. data/_includes/components/enhanced-metadata.html +0 -228
  106. data/_includes/components/language-switcher.html +0 -396
  107. data/_includes/components/navigation-enhancements.html +0 -454
  108. data/_includes/components/newsletter-signup.html +0 -178
  109. data/_includes/components/popular-posts.html +0 -233
  110. data/_includes/components/reading-progress.html +0 -133
  111. data/_includes/components/reading-time.html +0 -121
  112. data/_includes/components/series-navigation.html +0 -124
  113. data/_includes/components/social-proof.html +0 -34
  114. data/_includes/components/user-preferences.html +0 -566
  115. data/_layouts/archive.html +0 -282
  116. data/_layouts/post-sidebar.html +0 -183
  117. data/_sass/_phase3-enhancements.scss +0 -874
  118. data/_sass/_phase4-enhancements.scss +0 -1214
  119. data/_sass/_phase5-enhancements.scss +0 -414
  120. data/assets/img/20220607123041_detail.001.png +0 -0
  121. data/assets/js/academic.js +0 -262
  122. data/assets/js/analytics-dashboard.js +0 -382
  123. data/assets/js/core/dark-mode.js +0 -79
  124. data/assets/js/core/github-cards.js +0 -123
  125. data/assets/js/core/language-filter.js +0 -69
  126. data/assets/js/core/navigation.js +0 -184
  127. data/assets/js/core/scroll-progress.js +0 -45
  128. data/assets/js/core/search-hotkeys.js +0 -62
  129. data/assets/js/core/skip-links.js +0 -62
  130. data/assets/js/main.js +0 -23
  131. data/assets/js/math.js +0 -818
  132. data/assets/js/notebook.js +0 -158
  133. data/assets/js/search/analytics.js +0 -91
  134. data/assets/js/search/app.js +0 -271
  135. data/assets/js/search/autocomplete.js +0 -120
  136. data/assets/js/search/engine.js +0 -260
  137. data/assets/js/search/filters.js +0 -38
  138. data/assets/js/search/render.js +0 -217
  139. data/assets/js/search/utils.js +0 -99
  140. data/assets/js/search.js +0 -354
  141. data/assets/js/visualizations.js +0 -816
  142. data/assets/publications/datalog-publications.bib +0 -8
  143. data/assets/publications/datalog-publications.ris +0 -9
  144. data/assets/publications/publications.bib +0 -30
  145. data/assets/templates/diogo-ribeiro-cv.md +0 -31
  146. data/assets/templates/diogo-ribeiro-cv.tex +0 -32
  147. data/lib/datalog/theme/theme.rb +0 -18
@@ -1,233 +0,0 @@
1
- {%- comment -%}
2
- Popular Posts Widget Component
3
- Displays trending and most popular content
4
-
5
- Parameters:
6
- - max_posts: Maximum posts to display (default: 5)
7
- - sort_by: Sorting method (recent, comments, trending) (default: recent)
8
- - show_stats: Show reading stats (default: true)
9
- - show_thumbnail: Show post thumbnail (default: true)
10
- - layout: Display layout (list, grid, compact) (default: list)
11
- - heading: Custom heading (default: "Popular Posts")
12
- {%- endcomment -%}
13
-
14
- {%- assign max_posts = include.max_posts | default: 5 -%}
15
- {%- assign sort_by = include.sort_by | default: "recent" -%}
16
- {%- assign show_stats = include.show_stats | default: true -%}
17
- {%- assign show_thumbnail = include.show_thumbnail | default: true -%}
18
- {%- assign layout = include.layout | default: "list" -%}
19
- {%- assign heading = include.heading | default: "Popular Posts" -%}
20
-
21
- {%- comment -%} Get posts and apply basic filtering {%- endcomment -%}
22
- {%- assign all_posts = site.posts -%}
23
-
24
- {%- comment -%} Simulate popularity scoring (in real app, use analytics data) {%- endcomment -%}
25
- {%- assign scored_posts = "" | split: "" -%}
26
-
27
- {%- for post in all_posts limit: 20 -%}
28
- {%- assign score = 0 -%}
29
-
30
- {%- comment -%} Recency score (prefer recent content) {%- endcomment -%}
31
- {%- assign days_old = "now" | date: "%s" | minus: post.date | date: "%s" | divided_by: 86400 -%}
32
- {%- if days_old < 7 -%}
33
- {%- assign score = score | plus: 50 -%}
34
- {%- elsif days_old < 30 -%}
35
- {%- assign score = score | plus: 30 -%}
36
- {%- elsif days_old < 90 -%}
37
- {%- assign score = score | plus: 10 -%}
38
- {%- endif -%}
39
-
40
- {%- comment -%} Tag count (more tags = more discoverable) {%- endcomment -%}
41
- {%- assign tag_score = post.tags.size | times: 5 -%}
42
- {%- assign score = score | plus: tag_score -%}
43
-
44
- {%- comment -%} Featured posts bonus {%- endcomment -%}
45
- {%- if post.featured -%}
46
- {%- assign score = score | plus: 25 -%}
47
- {%- endif -%}
48
-
49
- {%- comment -%} Difficulty-based scoring (beginner posts might be more popular) {%- endcomment -%}
50
- {%- if post.difficulty == "beginner" -%}
51
- {%- assign score = score | plus: 15 -%}
52
- {%- endif -%}
53
-
54
- {%- comment -%} Add randomness for variety (simulates view counts) {%- endcomment -%}
55
- {%- assign random_bonus = post.title | size | modulo: 30 -%}
56
- {%- assign score = score | plus: random_bonus -%}
57
-
58
- {%- comment -%} Store post with score {%- endcomment -%}
59
- {%- assign post_with_score = post.url | append: "||" | append: score -%}
60
- {%- assign scored_posts = scored_posts | push: post_with_score -%}
61
- {%- endfor -%}
62
-
63
- {%- comment -%} Simple bubble sort by score {%- endcomment -%}
64
- {%- assign sorted_posts = scored_posts -%}
65
- {%- for i in (1..scored_posts.size) -%}
66
- {%- for j in (1..scored_posts.size) -%}
67
- {%- assign current = sorted_posts[j] | split: "||" -%}
68
- {%- assign prev = sorted_posts[j-1] | split: "||" -%}
69
- {%- if current[1] and prev[1] -%}
70
- {%- assign current_score = current[1] | plus: 0 -%}
71
- {%- assign prev_score = prev[1] | plus: 0 -%}
72
- {%- if current_score > prev_score -%}
73
- {%- assign temp = sorted_posts[j] -%}
74
- {%- assign sorted_posts[j] = sorted_posts[j-1] -%}
75
- {%- assign sorted_posts[j-1] = temp -%}
76
- {%- endif -%}
77
- {%- endif -%}
78
- {%- endfor -%}
79
- {%- endfor -%}
80
-
81
- {%- comment -%} Build popular posts array {%- endcomment -%}
82
- {%- assign popular_posts = "" | split: "" -%}
83
- {%- for item in sorted_posts limit: max_posts -%}
84
- {%- assign item_parts = item | split: "||" -%}
85
- {%- assign post_url = item_parts[0] -%}
86
-
87
- {%- for post in site.posts -%}
88
- {%- if post.url == post_url -%}
89
- {%- assign popular_posts = popular_posts | push: post -%}
90
- {%- break -%}
91
- {%- endif -%}
92
- {%- endfor -%}
93
- {%- endfor -%}
94
-
95
- <aside class="popular-posts popular-posts--{{ layout }}"
96
- data-popular-posts
97
- aria-label="{{ heading }}">
98
-
99
- <div class="popular-posts__header">
100
- <h3 class="popular-posts__title">
101
- <svg xmlns="http://www.w3.org/2000/svg"
102
- width="20"
103
- height="20"
104
- viewBox="0 0 24 24"
105
- fill="none"
106
- stroke="currentColor"
107
- stroke-width="2"
108
- stroke-linecap="round"
109
- stroke-linejoin="round"
110
- aria-hidden="true">
111
- <polyline points="23 6 13.5 15.5 8.5 10.5 1 18"></polyline>
112
- <polyline points="17 6 23 6 23 12"></polyline>
113
- </svg>
114
- {{ heading }}
115
- </h3>
116
-
117
- {%- if show_stats -%}
118
- <span class="popular-posts__subtitle">
119
- Trending this month
120
- </span>
121
- {%- endif -%}
122
- </div>
123
-
124
- <div class="popular-posts__list">
125
- {%- for post in popular_posts -%}
126
- {%- assign loop_index = forloop.index -%}
127
-
128
- <article class="popular-post"
129
- itemscope
130
- itemtype="https://schema.org/BlogPosting">
131
-
132
- <div class="popular-post__rank" aria-label="Rank {{ loop_index }}">
133
- {{ loop_index }}
134
- </div>
135
-
136
- {%- if show_thumbnail and post.featured_image or post.image -%}
137
- <div class="popular-post__thumbnail">
138
- <a href="{{ post.url | relative_url }}"
139
- tabindex="-1"
140
- aria-hidden="true">
141
- <img src="{{ post.featured_image | default: post.image | relative_url }}"
142
- alt=""
143
- loading="lazy"
144
- itemprop="image">
145
- </a>
146
- </div>
147
- {%- endif -%}
148
-
149
- <div class="popular-post__content">
150
- <h4 class="popular-post__title" itemprop="headline">
151
- <a href="{{ post.url | relative_url }}"
152
- class="popular-post__link">
153
- {{ post.title }}
154
- </a>
155
- </h4>
156
-
157
- {%- if show_stats -%}
158
- <div class="popular-post__meta">
159
- {%- if post.date -%}
160
- <time class="popular-post__date"
161
- datetime="{{ post.date | date_to_xmlschema }}"
162
- itemprop="datePublished">
163
- {{ post.date | date: "%b %d, %Y" }}
164
- </time>
165
- {%- endif -%}
166
-
167
- <span class="popular-post__separator" aria-hidden="true">•</span>
168
-
169
- {%- comment -%} Reading time {%- endcomment -%}
170
- {% include components/reading-time.html
171
- content=post.content
172
- variant="inline"
173
- show_icon=false %}
174
-
175
- {%- comment -%} View count removed — was simulated. Re-enable with real analytics data. {%- endcomment -%}
176
- </div>
177
- {%- endif -%}
178
-
179
- {%- if post.excerpt and layout != "compact" -%}
180
- <p class="popular-post__excerpt" itemprop="description">
181
- {{ post.excerpt | strip_html | truncatewords: 15 }}
182
- </p>
183
- {%- endif -%}
184
-
185
- {%- if post.tags.size > 0 and layout == "grid" -%}
186
- <div class="popular-post__tags">
187
- {%- for tag in post.tags limit: 2 -%}
188
- <span class="popular-post__tag">{{ tag }}</span>
189
- {%- endfor -%}
190
- </div>
191
- {%- endif -%}
192
- </div>
193
-
194
- {%- comment -%} Trending indicator for top 3 {%- endcomment -%}
195
- {%- if loop_index <= 3 -%}
196
- <div class="popular-post__badge" aria-label="Trending">
197
- <svg xmlns="http://www.w3.org/2000/svg"
198
- width="16"
199
- height="16"
200
- viewBox="0 0 24 24"
201
- fill="none"
202
- stroke="currentColor"
203
- stroke-width="2"
204
- aria-hidden="true">
205
- <polyline points="23 6 13.5 15.5 8.5 10.5 1 18"></polyline>
206
- <polyline points="17 6 23 6 23 12"></polyline>
207
- </svg>
208
- </div>
209
- {%- endif -%}
210
- </article>
211
- {%- endfor -%}
212
- </div>
213
-
214
- {%- if site.phase4_features.popular_posts.show_view_all -%}
215
- <div class="popular-posts__footer">
216
- <a href="{{ '/archive/' | relative_url }}"
217
- class="popular-posts__view-all">
218
- View all posts
219
- <svg xmlns="http://www.w3.org/2000/svg"
220
- width="16"
221
- height="16"
222
- viewBox="0 0 24 24"
223
- fill="none"
224
- stroke="currentColor"
225
- stroke-width="2"
226
- aria-hidden="true">
227
- <line x1="5" y1="12" x2="19" y2="12"></line>
228
- <polyline points="12 5 19 12 12 19"></polyline>
229
- </svg>
230
- </a>
231
- </div>
232
- {%- endif -%}
233
- </aside>
@@ -1,133 +0,0 @@
1
- {%- comment -%}
2
- Reading Progress Tracker
3
- Displays a visual indicator of reading progress with time estimate
4
-
5
- Parameters:
6
- - position: Position on page (top, bottom, sticky)
7
- - show_time: Show time remaining estimate (default: true)
8
- - show_percentage: Show percentage complete (default: true)
9
- {%- endcomment -%}
10
-
11
- {%- assign position = include.position | default: "top" -%}
12
- {%- assign show_time = include.show_time | default: true -%}
13
- {%- assign show_percentage = include.show_percentage | default: true -%}
14
-
15
- <div class="reading-progress reading-progress--{{ position }}" data-reading-progress aria-label="Reading progress">
16
- {%- comment -%} Progress bar {%- endcomment -%}
17
- <div class="reading-progress__bar">
18
- <div class="reading-progress__fill"
19
- data-progress-fill
20
- role="progressbar"
21
- aria-valuenow="0"
22
- aria-valuemin="0"
23
- aria-valuemax="100"
24
- aria-label="Reading progress percentage">
25
- </div>
26
- </div>
27
-
28
- {%- comment -%} Progress stats {%- endcomment -%}
29
- <div class="reading-progress__stats">
30
- {%- if show_percentage -%}
31
- <span class="reading-progress__percentage" data-progress-percentage aria-live="polite">
32
- <span data-percentage-value>0</span>% complete
33
- </span>
34
- {%- endif -%}
35
-
36
- {%- if show_time -%}
37
- <span class="reading-progress__time" data-progress-time aria-live="polite">
38
- <svg class="reading-progress__icon" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
39
- <circle cx="12" cy="12" r="10"></circle>
40
- <polyline points="12 6 12 12 16 14"></polyline>
41
- </svg>
42
- <span data-time-value>...</span> remaining
43
- </span>
44
- {%- endif -%}
45
- </div>
46
- </div>
47
-
48
- <script>
49
- (function() {
50
- 'use strict';
51
-
52
- document.addEventListener('DOMContentLoaded', function() {
53
- const progressContainer = document.querySelector('[data-reading-progress]');
54
- if (!progressContainer) return;
55
-
56
- const progressFill = progressContainer.querySelector('[data-progress-fill]');
57
- const percentageValue = progressContainer.querySelector('[data-percentage-value]');
58
- const timeValue = progressContainer.querySelector('[data-time-value]');
59
-
60
- // Get article content for calculation
61
- const articleContent = document.querySelector('.post-content, .article-content, article, main');
62
- if (!articleContent) return;
63
-
64
- // Calculate reading time (words per minute)
65
- const wordsPerMinute = 200;
66
- const text = articleContent.textContent || articleContent.innerText;
67
- const wordCount = text.trim().split(/\s+/).length;
68
- const totalReadingTime = Math.ceil(wordCount / wordsPerMinute);
69
-
70
- // Track scroll position
71
- let ticking = false;
72
-
73
- function updateProgress() {
74
- // Get scroll position
75
- const windowHeight = window.innerHeight;
76
- const documentHeight = document.documentElement.scrollHeight;
77
- const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
78
-
79
- // Calculate progress percentage
80
- const scrollableDistance = documentHeight - windowHeight;
81
- const scrollPercentage = scrollableDistance > 0
82
- ? Math.min(Math.max((scrollTop / scrollableDistance) * 100, 0), 100)
83
- : 0;
84
-
85
- // Update progress bar
86
- if (progressFill) {
87
- progressFill.style.width = scrollPercentage + '%';
88
- progressFill.setAttribute('aria-valuenow', Math.round(scrollPercentage));
89
- }
90
-
91
- // Update percentage text
92
- if (percentageValue) {
93
- percentageValue.textContent = Math.round(scrollPercentage);
94
- }
95
-
96
- // Update time remaining
97
- if (timeValue) {
98
- const timeRemaining = Math.max(
99
- Math.ceil(totalReadingTime * (1 - scrollPercentage / 100)),
100
- 0
101
- );
102
-
103
- if (timeRemaining === 0) {
104
- timeValue.textContent = 'Complete!';
105
- } else if (timeRemaining === 1) {
106
- timeValue.textContent = '1 min';
107
- } else {
108
- timeValue.textContent = timeRemaining + ' min';
109
- }
110
- }
111
-
112
- ticking = false;
113
- }
114
-
115
- function requestTick() {
116
- if (!ticking) {
117
- window.requestAnimationFrame(updateProgress);
118
- ticking = true;
119
- }
120
- }
121
-
122
- // Listen to scroll events
123
- window.addEventListener('scroll', requestTick, { passive: true });
124
- window.addEventListener('resize', requestTick, { passive: true });
125
-
126
- // Initial update
127
- updateProgress();
128
-
129
- // Update when images load
130
- window.addEventListener('load', updateProgress);
131
- });
132
- })();
133
- </script>
@@ -1,121 +0,0 @@
1
- {%- comment -%}
2
- Reading Time Estimate Component
3
- Calculates and displays estimated reading time with metadata
4
-
5
- Parameters:
6
- - content: Content to analyze (default: page.content)
7
- - words_per_minute: Reading speed (default: 200)
8
- - show_word_count: Show word count (default: false)
9
- - show_icon: Show clock icon (default: true)
10
- - variant: Display variant (inline, badge, detailed) (default: inline)
11
- {%- endcomment -%}
12
-
13
- {%- assign content_to_analyze = include.content | default: page.content -%}
14
- {%- assign words_per_minute = include.words_per_minute | default: 200 -%}
15
- {%- assign show_word_count = include.show_word_count | default: false -%}
16
- {%- assign show_icon = include.show_icon | default: true -%}
17
- {%- assign variant = include.variant | default: "inline" -%}
18
-
19
- {%- comment -%} Calculate word count {%- endcomment -%}
20
- {%- assign words = content_to_analyze | strip_html | number_of_words -%}
21
-
22
- {%- comment -%} Calculate reading time in minutes {%- endcomment -%}
23
- {%- assign reading_time_float = words | divided_by: words_per_minute | plus: 0.0 -%}
24
- {%- assign reading_time = reading_time_float | ceil -%}
25
-
26
- {%- comment -%} Handle edge cases {%- endcomment -%}
27
- {%- if reading_time < 1 -%}
28
- {%- assign reading_time = 1 -%}
29
- {%- endif -%}
30
-
31
- {%- comment -%} Format reading time display {%- endcomment -%}
32
- {%- if reading_time == 1 -%}
33
- {%- assign time_label = "1 min read" -%}
34
- {%- else -%}
35
- {%- assign time_label = reading_time | append: " min read" -%}
36
- {%- endif -%}
37
-
38
- {%- comment -%} Calculate additional metrics for detailed variant {%- endcomment -%}
39
- {%- if variant == "detailed" -%}
40
- {%- assign hours = reading_time | divided_by: 60 -%}
41
- {%- assign remaining_minutes = reading_time | modulo: 60 -%}
42
-
43
- {%- comment -%} Estimate based on different reading speeds {%- endcomment -%}
44
- {%- assign slow_reading_time = words | divided_by: 150 | ceil -%}
45
- {%- assign fast_reading_time = words | divided_by: 250 | ceil -%}
46
- {%- endif -%}
47
-
48
- <span class="reading-time reading-time--{{ variant }}"
49
- data-reading-time
50
- data-words="{{ words }}"
51
- data-minutes="{{ reading_time }}"
52
- itemscope
53
- itemtype="https://schema.org/Article">
54
-
55
- {%- if show_icon -%}
56
- <svg class="reading-time__icon"
57
- xmlns="http://www.w3.org/2000/svg"
58
- width="16"
59
- height="16"
60
- viewBox="0 0 24 24"
61
- fill="none"
62
- stroke="currentColor"
63
- stroke-width="2"
64
- stroke-linecap="round"
65
- stroke-linejoin="round"
66
- aria-hidden="true">
67
- <circle cx="12" cy="12" r="10"></circle>
68
- <polyline points="12 6 12 12 16 14"></polyline>
69
- </svg>
70
- {%- endif -%}
71
-
72
- {%- if variant == "detailed" -%}
73
- <span class="reading-time__details">
74
- <span class="reading-time__primary">
75
- <strong class="reading-time__time" itemprop="timeRequired" content="PT{{ reading_time }}M">
76
- {{ time_label }}
77
- </strong>
78
- </span>
79
-
80
- <span class="reading-time__secondary">
81
- <span class="reading-time__word-count">
82
- {{ words }} words
83
- </span>
84
-
85
- {%- if hours >= 1 -%}
86
- <span class="reading-time__alternative">
87
- ({{ hours }}h {{ remaining_minutes }}m)
88
- </span>
89
- {%- endif -%}
90
- </span>
91
-
92
- <span class="reading-time__range">
93
- <small>{{ fast_reading_time }}-{{ slow_reading_time }} min depending on speed</small>
94
- </span>
95
- </span>
96
-
97
- {%- elsif variant == "badge" -%}
98
- <span class="reading-time__badge">
99
- <span class="reading-time__time" itemprop="timeRequired" content="PT{{ reading_time }}M">
100
- {{ time_label }}
101
- </span>
102
- {%- if show_word_count -%}
103
- <span class="reading-time__word-count">
104
- {{ words }} words
105
- </span>
106
- {%- endif -%}
107
- </span>
108
-
109
- {%- else -%}
110
- {%- comment -%} Inline variant (default) {%- endcomment -%}
111
- <span class="reading-time__time" itemprop="timeRequired" content="PT{{ reading_time }}M">
112
- {{ time_label }}
113
- </span>
114
- {%- if show_word_count -%}
115
- <span class="reading-time__separator" aria-hidden="true">•</span>
116
- <span class="reading-time__word-count">
117
- {{ words }} words
118
- </span>
119
- {%- endif -%}
120
- {%- endif -%}
121
- </span>
@@ -1,124 +0,0 @@
1
- {%- comment -%}
2
- Series/Collection Navigation Component
3
- Displays navigation for multi-part content series
4
-
5
- Parameters:
6
- - series: Series name/ID
7
- - show_progress: Show progress indicator (default: true)
8
- - compact: Compact layout (default: false)
9
- {%- endcomment -%}
10
-
11
- {%- assign series_name = include.series | default: page.series -%}
12
- {%- assign show_progress = include.show_progress | default: true -%}
13
- {%- assign compact = include.compact | default: false -%}
14
-
15
- {%- if series_name -%}
16
- {%- comment -%} Get all posts in this series {%- endcomment -%}
17
- {%- assign series_posts = site.posts | where: "series", series_name | sort: "series_order" -%}
18
- {%- assign series_count = series_posts | size -%}
19
-
20
- {%- if series_count > 0 -%}
21
- {%- comment -%} Find current post position {%- endcomment -%}
22
- {%- assign current_index = 0 -%}
23
- {%- for post in series_posts -%}
24
- {%- if post.url == page.url -%}
25
- {%- assign current_index = forloop.index -%}
26
- {%- endif -%}
27
- {%- endfor -%}
28
-
29
- <nav class="series-nav{% if compact %} series-nav--compact{% endif %}"
30
- aria-label="Series navigation: {{ series_name }}">
31
- <div class="series-nav__header">
32
- <svg class="series-nav__icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
33
- <path d="M12 2v20M2 12h20"></path>
34
- <path d="M16 8l4 4-4 4M8 16l-4-4 4-4"></path>
35
- </svg>
36
- <h3 class="series-nav__title">
37
- <span class="series-nav__label">Series:</span>
38
- {{ series_name }}
39
- </h3>
40
- </div>
41
-
42
- {%- if show_progress -%}
43
- <div class="series-nav__progress" aria-label="Series progress">
44
- <div class="series-nav__progress-bar">
45
- <div class="series-nav__progress-fill"
46
- style="width: {{ current_index | times: 100 | divided_by: series_count }}%"
47
- role="progressbar"
48
- aria-valuenow="{{ current_index }}"
49
- aria-valuemin="0"
50
- aria-valuemax="{{ series_count }}"
51
- aria-label="Part {{ current_index }} of {{ series_count }}">
52
- </div>
53
- </div>
54
- <span class="series-nav__progress-text">
55
- Part {{ current_index }} of {{ series_count }}
56
- </span>
57
- </div>
58
- {%- endif -%}
59
-
60
- <ol class="series-nav__list">
61
- {%- for post in series_posts -%}
62
- {%- assign is_current = false -%}
63
- {%- if post.url == page.url -%}
64
- {%- assign is_current = true -%}
65
- {%- endif -%}
66
-
67
- <li class="series-nav__item{% if is_current %} series-nav__item--current{% endif %}">
68
- <div class="series-nav__number">{{ forloop.index }}</div>
69
- {%- if is_current -%}
70
- <div class="series-nav__content">
71
- <strong class="series-nav__post-title">{{ post.title }}</strong>
72
- <span class="series-nav__badge">Current</span>
73
- </div>
74
- {%- else -%}
75
- <a href="{{ post.url | relative_url }}" class="series-nav__content">
76
- <span class="series-nav__post-title">{{ post.title }}</span>
77
- {%- if post.excerpt -%}
78
- <span class="series-nav__excerpt">{{ post.excerpt | strip_html | truncate: 80 }}</span>
79
- {%- endif -%}
80
- </a>
81
- {%- endif -%}
82
- </li>
83
- {%- endfor -%}
84
- </ol>
85
-
86
- {%- comment -%} Previous/Next navigation {%- endcomment -%}
87
- <div class="series-nav__controls">
88
- {%- if current_index > 1 -%}
89
- {%- assign prev_post = series_posts[current_index | minus: 2] -%}
90
- <a href="{{ prev_post.url | relative_url }}" class="series-nav__button series-nav__button--prev">
91
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
92
- <polyline points="15 18 9 12 15 6"></polyline>
93
- </svg>
94
- Previous
95
- </a>
96
- {%- else -%}
97
- <div class="series-nav__button series-nav__button--disabled">
98
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
99
- <polyline points="15 18 9 12 15 6"></polyline>
100
- </svg>
101
- Previous
102
- </div>
103
- {%- endif -%}
104
-
105
- {%- if current_index < series_count -%}
106
- {%- assign next_post = series_posts[current_index] -%}
107
- <a href="{{ next_post.url | relative_url }}" class="series-nav__button series-nav__button--next">
108
- Next
109
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
110
- <polyline points="9 18 15 12 9 6"></polyline>
111
- </svg>
112
- </a>
113
- {%- else -%}
114
- <div class="series-nav__button series-nav__button--disabled">
115
- Next
116
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
117
- <polyline points="9 18 15 12 9 6"></polyline>
118
- </svg>
119
- </div>
120
- {%- endif -%}
121
- </div>
122
- </nav>
123
- {%- endif -%}
124
- {%- endif -%}
@@ -1,34 +0,0 @@
1
- {%- comment -%}
2
- Social Proof Indicators Component
3
-
4
- This component requires REAL metrics passed via include parameters.
5
- It does NOT generate simulated/fabricated data.
6
-
7
- Usage (only when real analytics data is available):
8
- {% include components/social-proof.html views=page_views %}
9
-
10
- To enable real data, configure GA4 analytics and use the analytics
11
- dashboard plugin to fetch actual page view counts.
12
-
13
- See: https://github.com/DiogoRibeiro7/analytics-blog-jekyll/issues/23
14
- {%- endcomment -%}
15
-
16
- {%- if include.views or include.readers -%}
17
- <div class="social-proof{% if include.compact %} social-proof--compact{% endif %}"
18
- data-social-proof>
19
- <div class="social-proof__metrics">
20
- {%- if include.views -%}
21
- <div class="social-proof__metric" data-metric="views">
22
- <span class="social-proof__value">{{ include.views }}</span>
23
- <span class="social-proof__label">views</span>
24
- </div>
25
- {%- endif -%}
26
- {%- if include.readers -%}
27
- <div class="social-proof__metric" data-metric="readers">
28
- <span class="social-proof__value">{{ include.readers }}</span>
29
- <span class="social-proof__label">reading now</span>
30
- </div>
31
- {%- endif -%}
32
- </div>
33
- </div>
34
- {%- endif -%}