jekyll-theme-zer0 0.15.0 → 0.16.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 +84 -0
- data/README.md +56 -24
- data/_data/README.md +419 -17
- data/_data/generate_statistics.rb +216 -9
- data/_data/generate_statistics.sh +106 -0
- data/_data/github-actions-example.yml +210 -0
- data/_data/navigation/quickstart.yml +11 -3
- data/_data/posts_organization.yml +153 -0
- data/_data/prerequisites.yml +112 -0
- data/_data/statistics_config.yml +203 -0
- data/_data/ui-text.yml +321 -0
- data/_data/update_statistics.sh +126 -0
- data/_includes/components/preview-image.html +20 -3
- data/_includes/content/intro.html +15 -6
- data/_includes/content/seo.html +12 -1
- data/_layouts/notebook.html +3 -3
- data/_plugins/preview_image_generator.rb +29 -8
- data/assets/images/previews/site-personalization-configuration.png +0 -0
- data/scripts/README.md +11 -1
- data/scripts/lib/changelog.sh +89 -57
- data/scripts/lib/preview_generator.py +164 -8
- data/scripts/test/lib/run_tests.sh +1 -2
- data/scripts/update-preview-paths.sh +145 -0
- metadata +11 -2
data/_data/ui-text.yml
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# User interface text and labels
|
|
2
|
+
# Used by: Various includes and layouts throughout the theme
|
|
3
|
+
# Purpose: Multilingual UI strings for internationalization (i18n)
|
|
4
|
+
|
|
5
|
+
# English (default)
|
|
6
|
+
# -----------------
|
|
7
|
+
en: &DEFAULT_EN
|
|
8
|
+
skip_links : "Skip links"
|
|
9
|
+
skip_primary_nav : "Skip to primary navigation"
|
|
10
|
+
skip_content : "Skip to content"
|
|
11
|
+
skip_footer : "Skip to footer"
|
|
12
|
+
page : "Page"
|
|
13
|
+
pagination_previous : "Previous"
|
|
14
|
+
pagination_next : "Next"
|
|
15
|
+
breadcrumb_home_label : "Home"
|
|
16
|
+
breadcrumb_separator : "/"
|
|
17
|
+
menu_label : "Toggle menu"
|
|
18
|
+
search_label : "Toggle search"
|
|
19
|
+
toc_label : "On this page"
|
|
20
|
+
ext_link_label : "Direct link"
|
|
21
|
+
less_than : "less than"
|
|
22
|
+
minute_read : "minute read"
|
|
23
|
+
share_on_label : "Share on"
|
|
24
|
+
meta_label :
|
|
25
|
+
tags_label : "Tags:"
|
|
26
|
+
categories_label : "Categories:"
|
|
27
|
+
date_label : "Updated:"
|
|
28
|
+
author_label : "Author:"
|
|
29
|
+
comments_label : "Leave a comment"
|
|
30
|
+
comments_title : "Comments"
|
|
31
|
+
more_label : "Learn more"
|
|
32
|
+
related_label : "You may also enjoy"
|
|
33
|
+
follow_label : "Follow:"
|
|
34
|
+
feed_label : "Feed"
|
|
35
|
+
powered_by : "Powered by"
|
|
36
|
+
website_label : "Website"
|
|
37
|
+
email_label : "Email"
|
|
38
|
+
recent_posts : "Recent posts"
|
|
39
|
+
undefined_wpm : "Undefined parameter words_per_minute at _config.yml"
|
|
40
|
+
comment_form_info : "Your email address will not be published. Required fields are marked"
|
|
41
|
+
comment_form_comment_label : "Comment"
|
|
42
|
+
comment_form_md_info : "Markdown is supported."
|
|
43
|
+
comment_form_name_label : "Name"
|
|
44
|
+
comment_form_email_label : "Email address"
|
|
45
|
+
comment_form_website_label : "Website (optional)"
|
|
46
|
+
comment_btn_submit : "Submit comment"
|
|
47
|
+
comment_btn_submitted : "Submitted"
|
|
48
|
+
comment_success_msg : "Thanks for your comment! It will show on the site once it has been approved."
|
|
49
|
+
comment_error_msg : "Sorry, there was an error with your submission. Please make sure all required fields have been completed and try again."
|
|
50
|
+
loading_label : "Loading..."
|
|
51
|
+
search_label_text : "Enter your search term..."
|
|
52
|
+
search_placeholder_text : "Enter your search term..."
|
|
53
|
+
search_algolia_no_results : "No results"
|
|
54
|
+
results_found : "Result(s) found"
|
|
55
|
+
back_to_top : "Back to top"
|
|
56
|
+
# Statistics labels
|
|
57
|
+
stats_total_posts : "Total Posts"
|
|
58
|
+
stats_total_pages : "Total Pages"
|
|
59
|
+
stats_categories : "Categories"
|
|
60
|
+
stats_tags : "Tags"
|
|
61
|
+
stats_last_updated : "Last Updated"
|
|
62
|
+
stats_overview : "Overview"
|
|
63
|
+
stats_content_breakdown : "Content Breakdown"
|
|
64
|
+
# Theme-specific labels
|
|
65
|
+
theme_toggle : "Toggle theme"
|
|
66
|
+
dark_mode : "Dark mode"
|
|
67
|
+
light_mode : "Light mode"
|
|
68
|
+
view_source : "View source"
|
|
69
|
+
edit_page : "Edit this page"
|
|
70
|
+
report_issue : "Report an issue"
|
|
71
|
+
|
|
72
|
+
en-US:
|
|
73
|
+
<<: *DEFAULT_EN
|
|
74
|
+
en-CA:
|
|
75
|
+
<<: *DEFAULT_EN
|
|
76
|
+
en-GB:
|
|
77
|
+
<<: *DEFAULT_EN
|
|
78
|
+
en-AU:
|
|
79
|
+
<<: *DEFAULT_EN
|
|
80
|
+
|
|
81
|
+
# Spanish
|
|
82
|
+
# -------
|
|
83
|
+
es: &DEFAULT_ES
|
|
84
|
+
skip_links : "Saltar enlaces"
|
|
85
|
+
skip_primary_nav : "Saltar a navegación principal"
|
|
86
|
+
skip_content : "Saltar a contenido"
|
|
87
|
+
skip_footer : "Saltar a pie"
|
|
88
|
+
page : "Página"
|
|
89
|
+
pagination_previous : "Anterior"
|
|
90
|
+
pagination_next : "Siguiente"
|
|
91
|
+
breadcrumb_home_label : "Inicio"
|
|
92
|
+
breadcrumb_separator : "/"
|
|
93
|
+
menu_label : "Alternar menú"
|
|
94
|
+
search_label : "Alternar búsqueda"
|
|
95
|
+
toc_label : "En esta página"
|
|
96
|
+
ext_link_label : "Enlace directo"
|
|
97
|
+
less_than : "menos de"
|
|
98
|
+
minute_read : "minuto(s) de lectura"
|
|
99
|
+
share_on_label : "Compartir en"
|
|
100
|
+
meta_label :
|
|
101
|
+
tags_label : "Etiquetas:"
|
|
102
|
+
categories_label : "Categorías:"
|
|
103
|
+
date_label : "Actualizado:"
|
|
104
|
+
author_label : "Autor:"
|
|
105
|
+
comments_label : "Deja un comentario"
|
|
106
|
+
comments_title : "Comentarios"
|
|
107
|
+
more_label : "Ver más"
|
|
108
|
+
related_label : "Puede que también te interese"
|
|
109
|
+
follow_label : "Seguir:"
|
|
110
|
+
feed_label : "Feed"
|
|
111
|
+
powered_by : "Funciona con"
|
|
112
|
+
website_label : "Sitio web"
|
|
113
|
+
email_label : "Correo electrónico"
|
|
114
|
+
recent_posts : "Entradas recientes"
|
|
115
|
+
undefined_wpm : "El parámetro words_per_minute (palabras por minuto) no está definido en _config.yml"
|
|
116
|
+
comment_form_info : "Tu dirección de correo electrónico no se publicará. Los campos obligatorios están marcados"
|
|
117
|
+
comment_form_comment_label : "Comentario"
|
|
118
|
+
comment_form_md_info : "Puedes utilizar Markdown"
|
|
119
|
+
comment_form_name_label : "Nombre"
|
|
120
|
+
comment_form_email_label : "Dirección de correo electrónico"
|
|
121
|
+
comment_form_website_label : "Sitio web (opcional)"
|
|
122
|
+
comment_btn_submit : "Enviar comentario"
|
|
123
|
+
comment_btn_submitted : "Enviado"
|
|
124
|
+
comment_success_msg : "¡Gracias por tu comentario! Se mostrará en el sitio una vez que haya sido aprobado."
|
|
125
|
+
comment_error_msg : "Lo sentimos, ha habido un error con tu envío. Por favor, asegúrate de que todos los campos obligatorios se han completado e inténtalo de nuevo."
|
|
126
|
+
loading_label : "Cargando..."
|
|
127
|
+
search_label_text : "Introduce tu término de búsqueda..."
|
|
128
|
+
search_placeholder_text : "Introduce tu término de búsqueda..."
|
|
129
|
+
search_algolia_no_results : "Sin resultados"
|
|
130
|
+
results_found : "Resultado(s) encontrado(s)"
|
|
131
|
+
back_to_top : "Volver arriba"
|
|
132
|
+
# Statistics labels
|
|
133
|
+
stats_total_posts : "Total de Publicaciones"
|
|
134
|
+
stats_total_pages : "Total de Páginas"
|
|
135
|
+
stats_categories : "Categorías"
|
|
136
|
+
stats_tags : "Etiquetas"
|
|
137
|
+
stats_last_updated : "Última Actualización"
|
|
138
|
+
stats_overview : "Resumen"
|
|
139
|
+
stats_content_breakdown : "Desglose de Contenido"
|
|
140
|
+
# Theme-specific labels
|
|
141
|
+
theme_toggle : "Cambiar tema"
|
|
142
|
+
dark_mode : "Modo oscuro"
|
|
143
|
+
light_mode : "Modo claro"
|
|
144
|
+
view_source : "Ver código fuente"
|
|
145
|
+
edit_page : "Editar esta página"
|
|
146
|
+
report_issue : "Reportar un problema"
|
|
147
|
+
|
|
148
|
+
es-ES:
|
|
149
|
+
<<: *DEFAULT_ES
|
|
150
|
+
es-MX:
|
|
151
|
+
<<: *DEFAULT_ES
|
|
152
|
+
|
|
153
|
+
# French
|
|
154
|
+
# ------
|
|
155
|
+
fr: &DEFAULT_FR
|
|
156
|
+
skip_links : "Liens de saut"
|
|
157
|
+
skip_primary_nav : "Aller à la navigation principale"
|
|
158
|
+
skip_content : "Aller au contenu"
|
|
159
|
+
skip_footer : "Aller au pied de page"
|
|
160
|
+
page : "Page"
|
|
161
|
+
pagination_previous : "Précédent"
|
|
162
|
+
pagination_next : "Suivant"
|
|
163
|
+
breadcrumb_home_label : "Accueil"
|
|
164
|
+
breadcrumb_separator : "/"
|
|
165
|
+
menu_label : "Basculer le menu"
|
|
166
|
+
search_label : "Basculer la recherche"
|
|
167
|
+
toc_label : "Sur cette page"
|
|
168
|
+
ext_link_label : "Lien direct"
|
|
169
|
+
less_than : "moins de"
|
|
170
|
+
minute_read : "minute(s) de lecture"
|
|
171
|
+
share_on_label : "Partager sur"
|
|
172
|
+
meta_label :
|
|
173
|
+
tags_label : "Tags :"
|
|
174
|
+
categories_label : "Catégories :"
|
|
175
|
+
date_label : "Mis à jour :"
|
|
176
|
+
author_label : "Auteur :"
|
|
177
|
+
comments_label : "Laisser un commentaire"
|
|
178
|
+
comments_title : "Commentaires"
|
|
179
|
+
more_label : "En savoir plus"
|
|
180
|
+
related_label : "Vous pourriez aussi aimer"
|
|
181
|
+
follow_label : "Suivre :"
|
|
182
|
+
feed_label : "Flux"
|
|
183
|
+
powered_by : "Propulsé par"
|
|
184
|
+
website_label : "Site web"
|
|
185
|
+
email_label : "Email"
|
|
186
|
+
recent_posts : "Articles récents"
|
|
187
|
+
back_to_top : "Retour en haut"
|
|
188
|
+
# Statistics labels
|
|
189
|
+
stats_total_posts : "Total des Publications"
|
|
190
|
+
stats_total_pages : "Total des Pages"
|
|
191
|
+
stats_categories : "Catégories"
|
|
192
|
+
stats_tags : "Tags"
|
|
193
|
+
stats_last_updated : "Dernière Mise à Jour"
|
|
194
|
+
stats_overview : "Aperçu"
|
|
195
|
+
stats_content_breakdown : "Répartition du Contenu"
|
|
196
|
+
# Theme-specific labels
|
|
197
|
+
theme_toggle : "Changer de thème"
|
|
198
|
+
dark_mode : "Mode sombre"
|
|
199
|
+
light_mode : "Mode clair"
|
|
200
|
+
view_source : "Voir la source"
|
|
201
|
+
edit_page : "Modifier cette page"
|
|
202
|
+
report_issue : "Signaler un problème"
|
|
203
|
+
|
|
204
|
+
fr-FR:
|
|
205
|
+
<<: *DEFAULT_FR
|
|
206
|
+
fr-CA:
|
|
207
|
+
<<: *DEFAULT_FR
|
|
208
|
+
|
|
209
|
+
# German
|
|
210
|
+
# ------
|
|
211
|
+
de: &DEFAULT_DE
|
|
212
|
+
skip_links : "Links überspringen"
|
|
213
|
+
skip_primary_nav : "Zur Hauptnavigation springen"
|
|
214
|
+
skip_content : "Zum Inhalt springen"
|
|
215
|
+
skip_footer : "Zur Fußzeile springen"
|
|
216
|
+
page : "Seite"
|
|
217
|
+
pagination_previous : "Zurück"
|
|
218
|
+
pagination_next : "Weiter"
|
|
219
|
+
breadcrumb_home_label : "Startseite"
|
|
220
|
+
breadcrumb_separator : "/"
|
|
221
|
+
menu_label : "Menü umschalten"
|
|
222
|
+
search_label : "Suche umschalten"
|
|
223
|
+
toc_label : "Auf dieser Seite"
|
|
224
|
+
ext_link_label : "Direktlink"
|
|
225
|
+
less_than : "weniger als"
|
|
226
|
+
minute_read : "Minute(n) Lesezeit"
|
|
227
|
+
share_on_label : "Teilen auf"
|
|
228
|
+
meta_label :
|
|
229
|
+
tags_label : "Tags:"
|
|
230
|
+
categories_label : "Kategorien:"
|
|
231
|
+
date_label : "Aktualisiert:"
|
|
232
|
+
author_label : "Autor:"
|
|
233
|
+
comments_label : "Einen Kommentar hinterlassen"
|
|
234
|
+
comments_title : "Kommentare"
|
|
235
|
+
more_label : "Mehr erfahren"
|
|
236
|
+
related_label : "Das könnte Sie auch interessieren"
|
|
237
|
+
follow_label : "Folgen:"
|
|
238
|
+
feed_label : "Feed"
|
|
239
|
+
powered_by : "Betrieben mit"
|
|
240
|
+
website_label : "Webseite"
|
|
241
|
+
email_label : "E-Mail"
|
|
242
|
+
recent_posts : "Neueste Beiträge"
|
|
243
|
+
back_to_top : "Nach oben"
|
|
244
|
+
# Statistics labels
|
|
245
|
+
stats_total_posts : "Gesamte Beiträge"
|
|
246
|
+
stats_total_pages : "Gesamte Seiten"
|
|
247
|
+
stats_categories : "Kategorien"
|
|
248
|
+
stats_tags : "Tags"
|
|
249
|
+
stats_last_updated : "Zuletzt Aktualisiert"
|
|
250
|
+
stats_overview : "Übersicht"
|
|
251
|
+
stats_content_breakdown : "Inhaltsaufschlüsselung"
|
|
252
|
+
# Theme-specific labels
|
|
253
|
+
theme_toggle : "Thema wechseln"
|
|
254
|
+
dark_mode : "Dunkler Modus"
|
|
255
|
+
light_mode : "Heller Modus"
|
|
256
|
+
view_source : "Quelle ansehen"
|
|
257
|
+
edit_page : "Diese Seite bearbeiten"
|
|
258
|
+
report_issue : "Ein Problem melden"
|
|
259
|
+
|
|
260
|
+
de-DE:
|
|
261
|
+
<<: *DEFAULT_DE
|
|
262
|
+
de-AT:
|
|
263
|
+
<<: *DEFAULT_DE
|
|
264
|
+
de-CH:
|
|
265
|
+
<<: *DEFAULT_DE
|
|
266
|
+
|
|
267
|
+
# Arabic
|
|
268
|
+
# ------
|
|
269
|
+
ar: &DEFAULT_AR
|
|
270
|
+
skip_links : "تخطي الروابط"
|
|
271
|
+
skip_primary_nav : "انتقل إلى التنقل الرئيسي"
|
|
272
|
+
skip_content : "انتقل إلى المحتوى"
|
|
273
|
+
skip_footer : "انتقل إلى التذييل"
|
|
274
|
+
page : "صفحة"
|
|
275
|
+
pagination_previous : "السابق"
|
|
276
|
+
pagination_next : "التالي"
|
|
277
|
+
breadcrumb_home_label : "الرئيسية"
|
|
278
|
+
breadcrumb_separator : "/"
|
|
279
|
+
menu_label : "تبديل القائمة"
|
|
280
|
+
search_label : "تبديل البحث"
|
|
281
|
+
toc_label : "في هذه الصفحة"
|
|
282
|
+
ext_link_label : "رابط مباشر"
|
|
283
|
+
less_than : "أقل من"
|
|
284
|
+
minute_read : "دقيقة للقراءة"
|
|
285
|
+
share_on_label : "مشاركة على"
|
|
286
|
+
meta_label :
|
|
287
|
+
tags_label : "الوسوم:"
|
|
288
|
+
categories_label : "الأقسام:"
|
|
289
|
+
date_label : "تاريخ التحديث:"
|
|
290
|
+
author_label : "الكاتب:"
|
|
291
|
+
comments_label : "اترك تعليقاً"
|
|
292
|
+
comments_title : "التعليقات"
|
|
293
|
+
more_label : "اقرأ المزيد"
|
|
294
|
+
related_label : "قد يعجبك أيضاً"
|
|
295
|
+
follow_label : "تابعنا:"
|
|
296
|
+
feed_label : "الخلاصة"
|
|
297
|
+
powered_by : "يعمل بواسطة"
|
|
298
|
+
website_label : "الموقع"
|
|
299
|
+
email_label : "البريد الإلكتروني"
|
|
300
|
+
recent_posts : "المنشورات الأخيرة"
|
|
301
|
+
back_to_top : "العودة للأعلى"
|
|
302
|
+
# Statistics labels
|
|
303
|
+
stats_total_posts : "إجمالي المنشورات"
|
|
304
|
+
stats_total_pages : "إجمالي الصفحات"
|
|
305
|
+
stats_categories : "الأقسام"
|
|
306
|
+
stats_tags : "الوسوم"
|
|
307
|
+
stats_last_updated : "آخر تحديث"
|
|
308
|
+
stats_overview : "نظرة عامة"
|
|
309
|
+
stats_content_breakdown : "تفصيل المحتوى"
|
|
310
|
+
# Theme-specific labels
|
|
311
|
+
theme_toggle : "تبديل المظهر"
|
|
312
|
+
dark_mode : "الوضع الداكن"
|
|
313
|
+
light_mode : "الوضع الفاتح"
|
|
314
|
+
view_source : "عرض المصدر"
|
|
315
|
+
edit_page : "تحرير هذه الصفحة"
|
|
316
|
+
report_issue : "الإبلاغ عن مشكلة"
|
|
317
|
+
|
|
318
|
+
ar-SA:
|
|
319
|
+
<<: *DEFAULT_AR
|
|
320
|
+
ar-EG:
|
|
321
|
+
<<: *DEFAULT_AR
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Automated Content Statistics Update Script
|
|
4
|
+
# Used by: CI/CD pipelines for automatic statistics updates
|
|
5
|
+
# Purpose: Update statistics and optionally commit changes
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
# Configuration
|
|
10
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
|
+
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
12
|
+
STATS_FILE="$SCRIPT_DIR/content_statistics.yml"
|
|
13
|
+
|
|
14
|
+
# Colors for output (if terminal supports it)
|
|
15
|
+
if [[ -t 1 ]]; then
|
|
16
|
+
RED='\033[0;31m'
|
|
17
|
+
GREEN='\033[0;32m'
|
|
18
|
+
YELLOW='\033[1;33m'
|
|
19
|
+
BLUE='\033[0;34m'
|
|
20
|
+
NC='\033[0m'
|
|
21
|
+
else
|
|
22
|
+
RED=''
|
|
23
|
+
GREEN=''
|
|
24
|
+
YELLOW=''
|
|
25
|
+
BLUE=''
|
|
26
|
+
NC=''
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
echo -e "${BLUE}🤖 Automated Content Statistics Update${NC}"
|
|
30
|
+
echo "========================================"
|
|
31
|
+
|
|
32
|
+
# Check if this is a CI environment
|
|
33
|
+
if [[ "${CI:-false}" == "true" ]]; then
|
|
34
|
+
echo -e "${YELLOW}🔧 Running in CI environment${NC}"
|
|
35
|
+
# Set git user for automated commits
|
|
36
|
+
git config --global user.name "Content Statistics Bot"
|
|
37
|
+
git config --global user.email "bot@zer0-mistakes.dev"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Store current statistics hash if file exists
|
|
41
|
+
CURRENT_HASH=""
|
|
42
|
+
if [[ -f "$STATS_FILE" ]]; then
|
|
43
|
+
if command -v sha256sum &> /dev/null; then
|
|
44
|
+
CURRENT_HASH=$(sha256sum "$STATS_FILE" | cut -d' ' -f1)
|
|
45
|
+
elif command -v shasum &> /dev/null; then
|
|
46
|
+
CURRENT_HASH=$(shasum -a 256 "$STATS_FILE" | cut -d' ' -f1)
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Generate new statistics
|
|
51
|
+
echo -e "${YELLOW}🔄 Generating updated statistics...${NC}"
|
|
52
|
+
if bash "$SCRIPT_DIR/generate_statistics.sh"; then
|
|
53
|
+
echo -e "${GREEN}✅ Statistics generated successfully${NC}"
|
|
54
|
+
else
|
|
55
|
+
echo -e "${RED}❌ Failed to generate statistics${NC}"
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Check if statistics have changed
|
|
60
|
+
NEW_HASH=""
|
|
61
|
+
if [[ -f "$STATS_FILE" ]]; then
|
|
62
|
+
if command -v sha256sum &> /dev/null; then
|
|
63
|
+
NEW_HASH=$(sha256sum "$STATS_FILE" | cut -d' ' -f1)
|
|
64
|
+
elif command -v shasum &> /dev/null; then
|
|
65
|
+
NEW_HASH=$(shasum -a 256 "$STATS_FILE" | cut -d' ' -f1)
|
|
66
|
+
fi
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
if [[ "$CURRENT_HASH" == "$NEW_HASH" ]]; then
|
|
70
|
+
echo -e "${BLUE}ℹ️ No changes detected in content statistics${NC}"
|
|
71
|
+
echo "Statistics are up to date."
|
|
72
|
+
exit 0
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
echo -e "${GREEN}📊 Content statistics have been updated${NC}"
|
|
76
|
+
|
|
77
|
+
# If running in CI, commit the changes
|
|
78
|
+
if [[ "${CI:-false}" == "true" ]]; then
|
|
79
|
+
echo -e "${YELLOW}📝 Committing updated statistics...${NC}"
|
|
80
|
+
|
|
81
|
+
cd "$PROJECT_ROOT"
|
|
82
|
+
|
|
83
|
+
# Add the updated statistics file
|
|
84
|
+
git add "$STATS_FILE"
|
|
85
|
+
|
|
86
|
+
# Check if there are changes to commit
|
|
87
|
+
if git diff --staged --quiet; then
|
|
88
|
+
echo -e "${BLUE}ℹ️ No changes to commit${NC}"
|
|
89
|
+
else
|
|
90
|
+
# Create commit message with timestamp
|
|
91
|
+
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
|
92
|
+
|
|
93
|
+
# Try to get stats from yq, fallback to N/A
|
|
94
|
+
TOTAL_POSTS="N/A"
|
|
95
|
+
PUBLISHED="N/A"
|
|
96
|
+
CATEGORIES="N/A"
|
|
97
|
+
|
|
98
|
+
if command -v yq &> /dev/null; then
|
|
99
|
+
TOTAL_POSTS=$(yq '.overview.total_posts' "$STATS_FILE" 2>/dev/null || echo "N/A")
|
|
100
|
+
PUBLISHED=$(yq '.overview.published' "$STATS_FILE" 2>/dev/null || echo "N/A")
|
|
101
|
+
CATEGORIES=$(yq '.overview.total_categories' "$STATS_FILE" 2>/dev/null || echo "N/A")
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
COMMIT_MSG="🤖 Auto-update content statistics - $TIMESTAMP
|
|
105
|
+
|
|
106
|
+
- Total posts analyzed: $TOTAL_POSTS
|
|
107
|
+
- Published posts: $PUBLISHED
|
|
108
|
+
- Categories tracked: $CATEGORIES
|
|
109
|
+
|
|
110
|
+
[skip ci]"
|
|
111
|
+
|
|
112
|
+
git commit -m "$COMMIT_MSG"
|
|
113
|
+
echo -e "${GREEN}✅ Statistics committed successfully${NC}"
|
|
114
|
+
|
|
115
|
+
# Push if configured
|
|
116
|
+
if [[ "${AUTO_PUSH:-false}" == "true" ]]; then
|
|
117
|
+
echo -e "${YELLOW}🚀 Pushing changes...${NC}"
|
|
118
|
+
git push origin HEAD
|
|
119
|
+
echo -e "${GREEN}✅ Changes pushed to repository${NC}"
|
|
120
|
+
fi
|
|
121
|
+
fi
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
echo ""
|
|
125
|
+
echo "=========================="
|
|
126
|
+
echo -e "${GREEN}🎉 Statistics update complete!${NC}"
|
|
@@ -9,8 +9,12 @@
|
|
|
9
9
|
style="height: 180px; object-fit: cover;"
|
|
10
10
|
-%}
|
|
11
11
|
|
|
12
|
-
Convention:
|
|
13
|
-
|
|
12
|
+
Convention: Preview paths can omit the /assets/ prefix.
|
|
13
|
+
The component will auto-prepend the assets_prefix from _config.yml.
|
|
14
|
+
Examples:
|
|
15
|
+
- /images/previews/my-image.png → /assets/images/previews/my-image.png
|
|
16
|
+
- /assets/images/previews/my-image.png → unchanged
|
|
17
|
+
- https://example.com/image.png → unchanged (external URL)
|
|
14
18
|
{% endcomment %}
|
|
15
19
|
{% assign img = include.src | default: site.teaser %}
|
|
16
20
|
{% assign alt = include.alt | default: "Preview image" %}
|
|
@@ -18,9 +22,22 @@
|
|
|
18
22
|
{% assign style = include.style %}
|
|
19
23
|
{% assign loading = include.loading | default: "lazy" %}
|
|
20
24
|
|
|
21
|
-
{% comment %}
|
|
25
|
+
{% comment %} Get assets prefix configuration {% endcomment %}
|
|
26
|
+
{% assign assets_prefix = site.preview_images.assets_prefix | default: '/assets' %}
|
|
27
|
+
{% assign auto_prefix = site.preview_images.auto_prefix | default: true %}
|
|
28
|
+
|
|
29
|
+
{% comment %} Determine final image source {% endcomment %}
|
|
22
30
|
{% if img contains '://' %}
|
|
31
|
+
{% comment %} External URL - use as-is {% endcomment %}
|
|
23
32
|
{% assign final_src = img %}
|
|
33
|
+
{% elsif auto_prefix and img != blank %}
|
|
34
|
+
{% comment %} Check if path already has the assets prefix {% endcomment %}
|
|
35
|
+
{% if img contains assets_prefix %}
|
|
36
|
+
{% assign final_src = img | relative_url %}
|
|
37
|
+
{% else %}
|
|
38
|
+
{% comment %} Prepend assets prefix to the path {% endcomment %}
|
|
39
|
+
{% assign final_src = assets_prefix | append: img | relative_url %}
|
|
40
|
+
{% endif %}
|
|
24
41
|
{% else %}
|
|
25
42
|
{% assign final_src = img | relative_url %}
|
|
26
43
|
{% endif %}
|
|
@@ -16,12 +16,21 @@
|
|
|
16
16
|
<!-- Intro Section -->
|
|
17
17
|
|
|
18
18
|
{% comment %}
|
|
19
|
-
Determine the preview image path.
|
|
20
|
-
|
|
19
|
+
Determine the preview image path. Preview paths can omit the /assets/ prefix.
|
|
20
|
+
The component will auto-prepend the assets_prefix from _config.yml.
|
|
21
21
|
{% endcomment %}
|
|
22
22
|
{% assign preview_image = page.preview | default: site.info_banner %}
|
|
23
|
+
{% assign assets_prefix = site.preview_images.assets_prefix | default: '/assets' %}
|
|
24
|
+
{% assign auto_prefix = site.preview_images.auto_prefix | default: true %}
|
|
25
|
+
|
|
23
26
|
{% if preview_image contains '://' %}
|
|
24
27
|
{% assign preview_path = preview_image %}
|
|
28
|
+
{% elsif auto_prefix and preview_image != blank %}
|
|
29
|
+
{% if preview_image contains assets_prefix %}
|
|
30
|
+
{% assign preview_path = preview_image | relative_url %}
|
|
31
|
+
{% else %}
|
|
32
|
+
{% assign preview_path = assets_prefix | append: preview_image | relative_url %}
|
|
33
|
+
{% endif %}
|
|
25
34
|
{% else %}
|
|
26
35
|
{% assign preview_path = preview_image | relative_url %}
|
|
27
36
|
{% endif %}
|
|
@@ -45,23 +54,23 @@
|
|
|
45
54
|
</button>
|
|
46
55
|
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="shareDropdownBottom">
|
|
47
56
|
<li>
|
|
48
|
-
<a class="dropdown-item" href="https://reddit.com/submit?url={{
|
|
57
|
+
<a class="dropdown-item" href="https://reddit.com/submit?url={{ site.url | append: page.url | url_encode }}&title={{ page.title | url_encode }}" target="_blank">
|
|
49
58
|
<i class="bi bi-reddit me-2"></i>Share on Reddit
|
|
50
59
|
</a>
|
|
51
60
|
</li>
|
|
52
61
|
<li>
|
|
53
|
-
<a class="dropdown-item" href="https://www.linkedin.com/sharing/share-offsite/?url={{
|
|
62
|
+
<a class="dropdown-item" href="https://www.linkedin.com/sharing/share-offsite/?url={{ site.url | append: page.url | url_encode }}" target="_blank">
|
|
54
63
|
<i class="bi bi-linkedin me-2"></i>Share on LinkedIn
|
|
55
64
|
</a>
|
|
56
65
|
</li>
|
|
57
66
|
<li>
|
|
58
|
-
<a class="dropdown-item" href="https://twitter.com/intent/tweet?url={{
|
|
67
|
+
<a class="dropdown-item" href="https://twitter.com/intent/tweet?url={{ site.url | append: page.url | url_encode }}&text={{ page.title | url_encode }}" target="_blank">
|
|
59
68
|
<i class="bi bi-twitter me-2"></i>Share on Twitter
|
|
60
69
|
</a>
|
|
61
70
|
</li>
|
|
62
71
|
<li><hr class="dropdown-divider"></li>
|
|
63
72
|
<li>
|
|
64
|
-
<button class="dropdown-item" onclick='navigator.clipboard.writeText("{{
|
|
73
|
+
<button class="dropdown-item" onclick='navigator.clipboard.writeText("{{ site.url | append: page.url }}"); alert("Link copied to clipboard!");'>
|
|
65
74
|
<i class="bi bi-clipboard me-2"></i>Copy Link
|
|
66
75
|
</button>
|
|
67
76
|
</li>
|
data/_includes/content/seo.html
CHANGED
|
@@ -23,8 +23,19 @@
|
|
|
23
23
|
{%- assign page_large_image = page.header.og_image | default: page.header.overlay_image | default: page.header.image | absolute_url -%}
|
|
24
24
|
{%- assign page_large_image = page_large_image | escape -%}
|
|
25
25
|
|
|
26
|
+
{%- comment -%} Handle preview image with configurable assets prefix {%- endcomment -%}
|
|
26
27
|
{%- assign page_teaser_image = page.preview | default: site.og_image -%}
|
|
27
|
-
{%- assign
|
|
28
|
+
{%- assign assets_prefix = site.preview_images.assets_prefix | default: '/assets' -%}
|
|
29
|
+
{%- assign auto_prefix = site.preview_images.auto_prefix | default: true -%}
|
|
30
|
+
|
|
31
|
+
{%- if page_teaser_image contains '://' -%}
|
|
32
|
+
{%- comment -%} External URL - use as-is {%- endcomment -%}
|
|
33
|
+
{%- elsif auto_prefix and page_teaser_image != blank -%}
|
|
34
|
+
{%- unless page_teaser_image contains assets_prefix -%}
|
|
35
|
+
{%- assign page_teaser_image = assets_prefix | append: page_teaser_image -%}
|
|
36
|
+
{%- endunless -%}
|
|
37
|
+
{%- endif -%}
|
|
38
|
+
{%- assign page_teaser_image = page_teaser_image | absolute_url | escape -%}
|
|
28
39
|
|
|
29
40
|
{%- assign site_og_image = site.og_image | absolute_url -%}
|
|
30
41
|
{%- assign site_og_image = site_og_image | escape -%}
|
data/_layouts/notebook.html
CHANGED
|
@@ -140,15 +140,15 @@ layout: default
|
|
|
140
140
|
<div class="share-buttons mb-4">
|
|
141
141
|
<h5 class="mb-3">Share this notebook</h5>
|
|
142
142
|
<div class="d-flex gap-2">
|
|
143
|
-
<a href="https://twitter.com/intent/tweet?text={{ page.title | uri_escape }}&url={{
|
|
143
|
+
<a href="https://twitter.com/intent/tweet?text={{ page.title | uri_escape }}&url={{ site.url | append: page.url | uri_escape }}"
|
|
144
144
|
class="btn btn-outline-primary btn-sm" target="_blank" rel="noopener noreferrer">
|
|
145
145
|
<i class="bi bi-twitter"></i> Twitter
|
|
146
146
|
</a>
|
|
147
|
-
<a href="https://www.linkedin.com/sharing/share-offsite/?url={{
|
|
147
|
+
<a href="https://www.linkedin.com/sharing/share-offsite/?url={{ site.url | append: page.url | uri_escape }}"
|
|
148
148
|
class="btn btn-outline-primary btn-sm" target="_blank" rel="noopener noreferrer">
|
|
149
149
|
<i class="bi bi-linkedin"></i> LinkedIn
|
|
150
150
|
</a>
|
|
151
|
-
<a href="mailto:?subject={{ page.title | uri_escape }}&body={{
|
|
151
|
+
<a href="mailto:?subject={{ page.title | uri_escape }}&body={{ site.url | append: page.url | uri_escape }}"
|
|
152
152
|
class="btn btn-outline-primary btn-sm">
|
|
153
153
|
<i class="bi bi-envelope"></i> Email
|
|
154
154
|
</a>
|
|
@@ -33,6 +33,8 @@ module Jekyll
|
|
|
33
33
|
'style' => 'retro pixel art, 8-bit video game aesthetic, vibrant colors, nostalgic, clean pixel graphics',
|
|
34
34
|
'style_modifiers' => 'pixelated, retro gaming style, CRT screen glow effect, limited color palette',
|
|
35
35
|
'output_dir' => 'assets/images/previews',
|
|
36
|
+
'assets_prefix' => '/assets',
|
|
37
|
+
'auto_prefix' => true,
|
|
36
38
|
'auto_generate' => false,
|
|
37
39
|
'collections' => ['posts', 'docs', 'quickstart']
|
|
38
40
|
}.freeze
|
|
@@ -52,18 +54,37 @@ module Jekyll
|
|
|
52
54
|
site = doc.site
|
|
53
55
|
config = self.config(site)
|
|
54
56
|
|
|
57
|
+
# Normalize the preview path using assets_prefix
|
|
58
|
+
normalized_preview = normalize_preview_path(preview, config)
|
|
59
|
+
|
|
55
60
|
# Build the full path
|
|
56
|
-
preview_path = if
|
|
57
|
-
File.join(site.source,
|
|
58
|
-
elsif
|
|
61
|
+
preview_path = if normalized_preview.start_with?('/')
|
|
62
|
+
File.join(site.source, normalized_preview.sub(/^\//, ''))
|
|
63
|
+
elsif normalized_preview.start_with?('http')
|
|
59
64
|
return true # External URL, assume it exists
|
|
60
65
|
else
|
|
61
|
-
File.join(site.source, config['output_dir'],
|
|
66
|
+
File.join(site.source, config['output_dir'], normalized_preview)
|
|
62
67
|
end
|
|
63
68
|
|
|
64
69
|
File.exist?(preview_path)
|
|
65
70
|
end
|
|
66
71
|
|
|
72
|
+
# Normalize a preview path by adding assets_prefix if needed
|
|
73
|
+
def self.normalize_preview_path(preview, config)
|
|
74
|
+
return preview if preview.nil? || preview.to_s.strip.empty?
|
|
75
|
+
return preview if preview.start_with?('http')
|
|
76
|
+
|
|
77
|
+
assets_prefix = config['assets_prefix'] || '/assets'
|
|
78
|
+
auto_prefix = config['auto_prefix'] != false # Default to true
|
|
79
|
+
|
|
80
|
+
# If auto_prefix is enabled and path doesn't already contain assets_prefix
|
|
81
|
+
if auto_prefix && !preview.include?(assets_prefix)
|
|
82
|
+
"#{assets_prefix}#{preview}"
|
|
83
|
+
else
|
|
84
|
+
preview
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
67
88
|
# Get the preview image path for a document
|
|
68
89
|
def self.preview_path(doc)
|
|
69
90
|
preview = doc.data['preview']
|
|
@@ -72,11 +93,11 @@ module Jekyll
|
|
|
72
93
|
site = doc.site
|
|
73
94
|
config = self.config(site)
|
|
74
95
|
|
|
75
|
-
# If it's
|
|
76
|
-
return preview if preview.start_with?('
|
|
96
|
+
# If it's an external URL, return as-is
|
|
97
|
+
return preview if preview.start_with?('http')
|
|
77
98
|
|
|
78
|
-
#
|
|
79
|
-
|
|
99
|
+
# Normalize path with assets_prefix
|
|
100
|
+
normalize_preview_path(preview, config)
|
|
80
101
|
end
|
|
81
102
|
|
|
82
103
|
# Get list of documents missing preview images
|
|
Binary file
|