jekyll-theme-zer0 0.5.0 → 0.7.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 +186 -60
- data/README.md +225 -12
- data/_data/authors.yml +52 -0
- data/_data/navigation/posts.yml +13 -14
- data/_includes/analytics/posthog.html +281 -0
- data/_includes/components/author-card.html +177 -0
- data/_includes/components/cookie-consent.html +382 -0
- data/_includes/components/info-section.html +5 -0
- data/_includes/components/js-cdn.html +27 -22
- data/_includes/components/post-card.html +176 -0
- data/_includes/components/theme-info.html +312 -0
- data/_includes/core/branding.html +24 -12
- data/_includes/core/footer.html +16 -0
- data/_includes/core/head.html +8 -8
- data/_includes/navigation/sidebar-folders.html +63 -103
- data/_layouts/blog.html +424 -232
- data/_layouts/category.html +247 -0
- data/_layouts/journals.html +272 -23
- data/_layouts/root.html +6 -0
- data/_layouts/tag.html +111 -0
- data/assets/css/main.scss +5 -5
- metadata +15 -7
- /data/_sass/{it-journey → core}/_docs.scss +0 -0
- /data/_sass/{it-journey → core}/_syntax.scss +0 -0
- /data/_sass/{it-journey → core}/_theme.scss +0 -0
- /data/_sass/{it-journey → core}/_variables.scss +0 -0
- /data/_sass/{it-journey → core}/code-copy.scss +0 -0
data/_data/authors.yml
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Authors Data File
|
|
2
|
+
# =================
|
|
3
|
+
# Define author profiles for blog posts
|
|
4
|
+
#
|
|
5
|
+
# Usage in front matter:
|
|
6
|
+
# author: johndoe (references the key below)
|
|
7
|
+
#
|
|
8
|
+
# Fields:
|
|
9
|
+
# name: Display name (required)
|
|
10
|
+
# bio: Short biography (optional)
|
|
11
|
+
# avatar: Path to avatar image (optional)
|
|
12
|
+
# email: Contact email (optional)
|
|
13
|
+
# twitter: Twitter handle without @ (optional)
|
|
14
|
+
# github: GitHub username (optional)
|
|
15
|
+
# linkedin: LinkedIn profile ID (optional)
|
|
16
|
+
# website: Personal website URL (optional)
|
|
17
|
+
# role: Job title or role (optional)
|
|
18
|
+
|
|
19
|
+
default:
|
|
20
|
+
name: "Zer0-Mistakes Team"
|
|
21
|
+
bio: "The collective voice of the Zer0-Mistakes Jekyll theme development team."
|
|
22
|
+
avatar: "/images/default-avatar.png"
|
|
23
|
+
github: "bamr87"
|
|
24
|
+
website: "https://bamr87.github.io/zer0-mistakes/"
|
|
25
|
+
role: "Development Team"
|
|
26
|
+
|
|
27
|
+
bamr87:
|
|
28
|
+
name: "Amr Bakri"
|
|
29
|
+
bio: "Creator of Zer0-Mistakes Jekyll theme. Developer, automation enthusiast, and Docker advocate."
|
|
30
|
+
avatar: "/images/authors/bamr87.png"
|
|
31
|
+
github: "bamr87"
|
|
32
|
+
twitter: "bamr87"
|
|
33
|
+
role: "Lead Developer"
|
|
34
|
+
|
|
35
|
+
guest:
|
|
36
|
+
name: "Guest Author"
|
|
37
|
+
bio: "A valued contributor to our community."
|
|
38
|
+
avatar: "/images/default-avatar.png"
|
|
39
|
+
role: "Guest Contributor"
|
|
40
|
+
|
|
41
|
+
# Add more authors as needed:
|
|
42
|
+
#
|
|
43
|
+
# author_key:
|
|
44
|
+
# name: "Author Full Name"
|
|
45
|
+
# bio: "Short biography about the author."
|
|
46
|
+
# avatar: "/images/authors/author.png"
|
|
47
|
+
# email: "author@example.com"
|
|
48
|
+
# twitter: "twitterhandle"
|
|
49
|
+
# github: "githubuser"
|
|
50
|
+
# linkedin: "linkedinprofile"
|
|
51
|
+
# website: "https://example.com"
|
|
52
|
+
# role: "Writer"
|
data/_data/navigation/posts.yml
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
- title: Development
|
|
2
|
+
icon: code-slash
|
|
3
|
+
url: /posts/development/
|
|
4
4
|
- title: Technology
|
|
5
|
-
icon:
|
|
6
|
-
url: /posts/
|
|
5
|
+
icon: cpu
|
|
6
|
+
url: /posts/technology/
|
|
7
|
+
- title: Tutorial
|
|
8
|
+
icon: journal-code
|
|
9
|
+
url: /posts/tutorial/
|
|
10
|
+
- title: World
|
|
11
|
+
icon: globe
|
|
12
|
+
url: /posts/world/
|
|
7
13
|
- title: Business
|
|
8
|
-
icon:
|
|
14
|
+
icon: briefcase
|
|
9
15
|
url: /posts/business/
|
|
10
16
|
- title: Science
|
|
11
|
-
icon:
|
|
17
|
+
icon: mortarboard
|
|
12
18
|
url: /posts/science/
|
|
13
|
-
- title: Health
|
|
14
|
-
icon: heart
|
|
15
|
-
url: /posts/health/
|
|
16
|
-
- title: Politics
|
|
17
|
-
icon: politics
|
|
18
|
-
url: /posts/politics/
|
|
19
|
-
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
===================================================================
|
|
3
|
+
POSTHOG ANALYTICS - Privacy-First Web Analytics Integration
|
|
4
|
+
===================================================================
|
|
5
|
+
|
|
6
|
+
File: posthog.html
|
|
7
|
+
Path: _includes/analytics/posthog.html
|
|
8
|
+
Purpose: Configurable PostHog analytics implementation with comprehensive
|
|
9
|
+
privacy controls and GDPR/CCPA compliance
|
|
10
|
+
|
|
11
|
+
Template Logic:
|
|
12
|
+
- Conditionally loads only in production environment
|
|
13
|
+
- Respects Do Not Track (DNT) browser settings
|
|
14
|
+
- Integrates with cookie consent management system
|
|
15
|
+
- Provides Jekyll-specific event tracking and page properties
|
|
16
|
+
|
|
17
|
+
Dependencies:
|
|
18
|
+
- site.posthog configuration from _config.yml
|
|
19
|
+
- Cookie consent system for user permission management
|
|
20
|
+
- Jekyll environment detection for production loading
|
|
21
|
+
- PostHog CDN and JavaScript library
|
|
22
|
+
|
|
23
|
+
Privacy Features:
|
|
24
|
+
- Environment-specific loading (production only by default)
|
|
25
|
+
- Cookie consent integration with opt-in/opt-out mechanisms
|
|
26
|
+
- Do Not Track respect with automatic analytics disabling
|
|
27
|
+
- Session recording controls with input masking
|
|
28
|
+
- IP anonymization options for enhanced privacy
|
|
29
|
+
|
|
30
|
+
Custom Event Tracking:
|
|
31
|
+
- File downloads (PDFs, documents, archives)
|
|
32
|
+
- External link clicks and referral tracking
|
|
33
|
+
- Search queries and site navigation patterns
|
|
34
|
+
- Scroll depth analysis and reading engagement
|
|
35
|
+
- Jekyll-specific interactions (TOC, sidebar, code blocks)
|
|
36
|
+
===================================================================
|
|
37
|
+
-->
|
|
38
|
+
|
|
39
|
+
{% comment %}
|
|
40
|
+
PostHog Analytics Integration for Zer0-Mistakes Jekyll Theme
|
|
41
|
+
|
|
42
|
+
Features:
|
|
43
|
+
- Environment-specific loading (production only by default)
|
|
44
|
+
- Configurable privacy settings
|
|
45
|
+
- Custom event tracking for Jekyll-specific actions
|
|
46
|
+
- GDPR/CCPA compliance options
|
|
47
|
+
- Session recording controls
|
|
48
|
+
- Cookie consent integration
|
|
49
|
+
|
|
50
|
+
Configuration: Set posthog settings in _config.yml
|
|
51
|
+
Privacy: Respects Do Not Track and provides opt-out mechanisms
|
|
52
|
+
{% endcomment %}
|
|
53
|
+
|
|
54
|
+
{% if site.posthog.enabled and jekyll.environment == "production" %}
|
|
55
|
+
<script>
|
|
56
|
+
{% comment %} PostHog Configuration {% endcomment %}
|
|
57
|
+
window.posthogConfig = {
|
|
58
|
+
apiKey: '{{ site.posthog.api_key }}',
|
|
59
|
+
apiHost: '{{ site.posthog.api_host }}',
|
|
60
|
+
personProfiles: '{{ site.posthog.person_profiles | default: "identified_only" }}',
|
|
61
|
+
autocapture: {{ site.posthog.autocapture | default: true }},
|
|
62
|
+
capturePageview: {{ site.posthog.capture_pageview | default: true }},
|
|
63
|
+
capturePageleave: {{ site.posthog.capture_pageleave | default: true }},
|
|
64
|
+
disableCookie: {{ site.posthog.disable_cookie | default: false }},
|
|
65
|
+
respectDnt: {{ site.posthog.respect_dnt | default: true }},
|
|
66
|
+
crossSubdomainCookie: {{ site.posthog.cross_subdomain_cookie | default: false }},
|
|
67
|
+
secureCookie: {{ site.posthog.secure_cookie | default: true }},
|
|
68
|
+
persistence: '{{ site.posthog.persistence | default: "localStorage+cookie" }}',
|
|
69
|
+
sessionRecording: {
|
|
70
|
+
enabled: {{ site.posthog.session_recording | default: false }},
|
|
71
|
+
maskAllText: {{ site.posthog.privacy.mask_all_text | default: false }},
|
|
72
|
+
maskAllInputs: {{ site.posthog.privacy.mask_all_inputs | default: true }}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
{% comment %} Check for Do Not Track before loading {% endcomment %}
|
|
77
|
+
if (window.posthogConfig.respectDnt && navigator.doNotTrack === '1') {
|
|
78
|
+
console.log('PostHog: Respecting Do Not Track setting');
|
|
79
|
+
} else {
|
|
80
|
+
{% comment %} PostHog Loading Script {% endcomment %}
|
|
81
|
+
!function(t,e){var o,n,p,r;e.__SV||(window.posthog && window.posthog.__loaded)||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init Rr Mr fi Or Ar ci Tr Cr capture Mi calculateEventProperties Lr register register_once register_for_session unregister unregister_for_session Hr getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSurveysLoaded onSessionId getSurveys getActiveMatchingSurveys renderSurvey displaySurvey canRenderSurvey canRenderSurveyAsync identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty Ur jr createPersonProfile zr kr Br opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing get_explicit_consent_status is_capturing clear_opt_in_out_capturing Dr debug M Nr getPageViewId captureTraceFeedback captureTraceMetric $r".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
|
|
82
|
+
|
|
83
|
+
{% comment %} Initialize PostHog with configuration {% endcomment %}
|
|
84
|
+
posthog.init(window.posthogConfig.apiKey, {
|
|
85
|
+
api_host: window.posthogConfig.apiHost,
|
|
86
|
+
person_profiles: window.posthogConfig.personProfiles,
|
|
87
|
+
autocapture: window.posthogConfig.autocapture,
|
|
88
|
+
capture_pageview: window.posthogConfig.capturePageview,
|
|
89
|
+
capture_pageleave: window.posthogConfig.capturePageleave,
|
|
90
|
+
disable_cookie: window.posthogConfig.disableCookie,
|
|
91
|
+
cross_subdomain_cookie: window.posthogConfig.crossSubdomainCookie,
|
|
92
|
+
secure_cookie: window.posthogConfig.secureCookie,
|
|
93
|
+
persistence: window.posthogConfig.persistence,
|
|
94
|
+
session_recording: window.posthogConfig.sessionRecording,
|
|
95
|
+
{% if site.posthog.privacy.ip_anonymization %}
|
|
96
|
+
ip: false,
|
|
97
|
+
{% endif %}
|
|
98
|
+
loaded: function(posthog) {
|
|
99
|
+
{% comment %} PostHog loaded successfully {% endcomment %}
|
|
100
|
+
console.log('PostHog analytics loaded successfully');
|
|
101
|
+
|
|
102
|
+
{% comment %} Track Jekyll-specific page properties {% endcomment %}
|
|
103
|
+
posthog.register({
|
|
104
|
+
'site_title': '{{ site.title }}',
|
|
105
|
+
'site_description': '{{ site.description | strip_newlines | strip }}',
|
|
106
|
+
'jekyll_version': '{{ jekyll.version }}',
|
|
107
|
+
'theme': '{{ site.remote_theme | default: site.theme }}',
|
|
108
|
+
'page_layout': '{{ page.layout }}',
|
|
109
|
+
'page_collection': '{{ page.collection }}',
|
|
110
|
+
{% if page.categories %}
|
|
111
|
+
'page_categories': {{ page.categories | jsonify }},
|
|
112
|
+
{% endif %}
|
|
113
|
+
{% if page.tags %}
|
|
114
|
+
'page_tags': {{ page.tags | jsonify }},
|
|
115
|
+
{% endif %}
|
|
116
|
+
'page_url': window.location.pathname,
|
|
117
|
+
'page_title': '{{ page.title | strip_newlines | strip }}',
|
|
118
|
+
'page_author': '{{ page.author | default: site.author.name }}',
|
|
119
|
+
{% if page.date %}
|
|
120
|
+
'page_date': '{{ page.date | date: "%Y-%m-%d" }}',
|
|
121
|
+
{% endif %}
|
|
122
|
+
'user_agent': navigator.userAgent,
|
|
123
|
+
'screen_resolution': screen.width + 'x' + screen.height,
|
|
124
|
+
'viewport_size': window.innerWidth + 'x' + window.innerHeight
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
{% comment %} Initialize custom event tracking {% endcomment %}
|
|
128
|
+
initializeCustomTracking();
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
{% comment %} Custom Event Tracking Functions {% endcomment %}
|
|
134
|
+
function initializeCustomTracking() {
|
|
135
|
+
{% if site.posthog.custom_events.track_downloads %}
|
|
136
|
+
{% comment %} Track file downloads {% endcomment %}
|
|
137
|
+
document.addEventListener('click', function(e) {
|
|
138
|
+
var target = e.target.closest('a');
|
|
139
|
+
if (target && target.href) {
|
|
140
|
+
var href = target.href.toLowerCase();
|
|
141
|
+
var downloadExtensions = ['.pdf', '.zip', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.txt', '.csv'];
|
|
142
|
+
var isDownload = downloadExtensions.some(ext => href.includes(ext));
|
|
143
|
+
|
|
144
|
+
if (isDownload) {
|
|
145
|
+
posthog.capture('file_download', {
|
|
146
|
+
'file_url': target.href,
|
|
147
|
+
'file_name': target.innerText || target.href.split('/').pop(),
|
|
148
|
+
'page_url': window.location.pathname
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
{% endif %}
|
|
154
|
+
|
|
155
|
+
{% if site.posthog.custom_events.track_external_links %}
|
|
156
|
+
{% comment %} Track external link clicks {% endcomment %}
|
|
157
|
+
document.addEventListener('click', function(e) {
|
|
158
|
+
var target = e.target.closest('a');
|
|
159
|
+
if (target && target.href && target.hostname !== window.location.hostname) {
|
|
160
|
+
posthog.capture('external_link_click', {
|
|
161
|
+
'link_url': target.href,
|
|
162
|
+
'link_text': target.innerText,
|
|
163
|
+
'page_url': window.location.pathname
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
{% endif %}
|
|
168
|
+
|
|
169
|
+
{% if site.posthog.custom_events.track_search %}
|
|
170
|
+
{% comment %} Track search queries {% endcomment %}
|
|
171
|
+
var searchInputs = document.querySelectorAll('input[type="search"], .search-input, #search');
|
|
172
|
+
searchInputs.forEach(function(input) {
|
|
173
|
+
input.addEventListener('keypress', function(e) {
|
|
174
|
+
if (e.key === 'Enter' && this.value.trim()) {
|
|
175
|
+
posthog.capture('search_query', {
|
|
176
|
+
'search_term': this.value.trim(),
|
|
177
|
+
'page_url': window.location.pathname
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
{% endif %}
|
|
183
|
+
|
|
184
|
+
{% if site.posthog.custom_events.track_scroll_depth %}
|
|
185
|
+
{% comment %} Track scroll depth {% endcomment %}
|
|
186
|
+
var scrollDepths = [25, 50, 75, 90];
|
|
187
|
+
var triggeredDepths = [];
|
|
188
|
+
|
|
189
|
+
window.addEventListener('scroll', function() {
|
|
190
|
+
var scrollPercent = Math.round((window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100);
|
|
191
|
+
|
|
192
|
+
scrollDepths.forEach(function(depth) {
|
|
193
|
+
if (scrollPercent >= depth && !triggeredDepths.includes(depth)) {
|
|
194
|
+
triggeredDepths.push(depth);
|
|
195
|
+
posthog.capture('scroll_depth', {
|
|
196
|
+
'depth_percentage': depth,
|
|
197
|
+
'page_url': window.location.pathname,
|
|
198
|
+
'page_title': document.title
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
{% endif %}
|
|
204
|
+
|
|
205
|
+
{% comment %} Track Jekyll-specific events {% endcomment %}
|
|
206
|
+
|
|
207
|
+
{% comment %} Track code block interactions {% endcomment %}
|
|
208
|
+
document.addEventListener('click', function(e) {
|
|
209
|
+
if (e.target.closest('.highlight, pre, code')) {
|
|
210
|
+
posthog.capture('code_interaction', {
|
|
211
|
+
'interaction_type': 'click',
|
|
212
|
+
'page_url': window.location.pathname
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
{% comment %} Track table of contents clicks {% endcomment %}
|
|
218
|
+
document.addEventListener('click', function(e) {
|
|
219
|
+
if (e.target.closest('.toc, #TableOfContents, .table-of-contents')) {
|
|
220
|
+
var target = e.target.closest('a');
|
|
221
|
+
if (target && target.href) {
|
|
222
|
+
posthog.capture('toc_click', {
|
|
223
|
+
'toc_link': target.href,
|
|
224
|
+
'toc_text': target.innerText,
|
|
225
|
+
'page_url': window.location.pathname
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
{% comment %} Track sidebar navigation {% endcomment %}
|
|
232
|
+
document.addEventListener('click', function(e) {
|
|
233
|
+
if (e.target.closest('.sidebar, .bd-sidebar, nav[class*="sidebar"]')) {
|
|
234
|
+
var target = e.target.closest('a');
|
|
235
|
+
if (target && target.href) {
|
|
236
|
+
posthog.capture('sidebar_navigation', {
|
|
237
|
+
'nav_link': target.href,
|
|
238
|
+
'nav_text': target.innerText,
|
|
239
|
+
'page_url': window.location.pathname
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
{% comment %} Expose PostHog utilities globally for theme usage {% endcomment %}
|
|
247
|
+
window.zer0Analytics = {
|
|
248
|
+
track: function(eventName, properties) {
|
|
249
|
+
if (window.posthog && typeof window.posthog.capture === 'function') {
|
|
250
|
+
posthog.capture(eventName, properties);
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
identify: function(userId, properties) {
|
|
254
|
+
if (window.posthog && typeof window.posthog.identify === 'function') {
|
|
255
|
+
posthog.identify(userId, properties);
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
reset: function() {
|
|
259
|
+
if (window.posthog && typeof window.posthog.reset === 'function') {
|
|
260
|
+
posthog.reset();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
</script>
|
|
265
|
+
{% else %}
|
|
266
|
+
{% comment %} PostHog disabled or not in production environment {% endcomment %}
|
|
267
|
+
<script>
|
|
268
|
+
{% comment %} Provide no-op analytics functions for development {% endcomment %}
|
|
269
|
+
window.zer0Analytics = {
|
|
270
|
+
track: function(eventName, properties) {
|
|
271
|
+
console.log('Analytics (disabled):', eventName, properties);
|
|
272
|
+
},
|
|
273
|
+
identify: function(userId, properties) {
|
|
274
|
+
console.log('Analytics identify (disabled):', userId, properties);
|
|
275
|
+
},
|
|
276
|
+
reset: function() {
|
|
277
|
+
console.log('Analytics reset (disabled)');
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
</script>
|
|
281
|
+
{% endif %}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
===================================================================
|
|
3
|
+
AUTHOR CARD COMPONENT - Display author information
|
|
4
|
+
===================================================================
|
|
5
|
+
|
|
6
|
+
File: author-card.html
|
|
7
|
+
Path: _includes/components/author-card.html
|
|
8
|
+
Purpose: Reusable author profile display for posts and author pages
|
|
9
|
+
|
|
10
|
+
Parameters:
|
|
11
|
+
- author (required): Author key from _data/authors.yml OR author name string
|
|
12
|
+
- style (optional): "compact" | "full" | "inline" (default: "compact")
|
|
13
|
+
- show_bio (optional): Show author bio (default: true for full, false for compact)
|
|
14
|
+
- show_social (optional): Show social links (default: true for full, false for compact)
|
|
15
|
+
|
|
16
|
+
Usage:
|
|
17
|
+
{% include components/author-card.html author=page.author %}
|
|
18
|
+
{% include components/author-card.html author="bamr87" style="full" %}
|
|
19
|
+
{% include components/author-card.html author=page.author style="inline" %}
|
|
20
|
+
|
|
21
|
+
Dependencies:
|
|
22
|
+
- _data/authors.yml: Author data definitions
|
|
23
|
+
- Bootstrap 5 card and utility classes
|
|
24
|
+
- Bootstrap Icons
|
|
25
|
+
===================================================================
|
|
26
|
+
-->
|
|
27
|
+
|
|
28
|
+
{% comment %} Parameter defaults {% endcomment %}
|
|
29
|
+
{% assign style = include.style | default: "compact" %}
|
|
30
|
+
|
|
31
|
+
{% comment %}
|
|
32
|
+
Resolve author: can be a key to _data/authors.yml or a plain name string
|
|
33
|
+
{% endcomment %}
|
|
34
|
+
{% assign author_key = include.author %}
|
|
35
|
+
{% assign author_data = site.data.authors[author_key] %}
|
|
36
|
+
|
|
37
|
+
{% comment %} If no match in authors.yml, use string as display name {% endcomment %}
|
|
38
|
+
{% unless author_data %}
|
|
39
|
+
{% assign author_data = site.data.authors.default %}
|
|
40
|
+
{% if include.author and include.author != "" %}
|
|
41
|
+
{% capture author_name %}{{ include.author }}{% endcapture %}
|
|
42
|
+
{% else %}
|
|
43
|
+
{% assign author_name = author_data.name %}
|
|
44
|
+
{% endif %}
|
|
45
|
+
{% else %}
|
|
46
|
+
{% assign author_name = author_data.name %}
|
|
47
|
+
{% endunless %}
|
|
48
|
+
|
|
49
|
+
{% comment %} Style-specific defaults {% endcomment %}
|
|
50
|
+
{% if style == "full" %}
|
|
51
|
+
{% assign show_bio = include.show_bio | default: true %}
|
|
52
|
+
{% assign show_social = include.show_social | default: true %}
|
|
53
|
+
{% elsif style == "inline" %}
|
|
54
|
+
{% assign show_bio = false %}
|
|
55
|
+
{% assign show_social = false %}
|
|
56
|
+
{% else %}
|
|
57
|
+
{% assign show_bio = include.show_bio | default: false %}
|
|
58
|
+
{% assign show_social = include.show_social | default: false %}
|
|
59
|
+
{% endif %}
|
|
60
|
+
|
|
61
|
+
<!-- ========================== -->
|
|
62
|
+
<!-- INLINE STYLE -->
|
|
63
|
+
<!-- ========================== -->
|
|
64
|
+
{% if style == "inline" %}
|
|
65
|
+
<span class="author-inline d-inline-flex align-items-center">
|
|
66
|
+
{% if author_data.avatar %}
|
|
67
|
+
<img src="{{ site.baseurl }}/{{ site.public_folder }}{{ author_data.avatar }}"
|
|
68
|
+
alt="{{ author_name }}"
|
|
69
|
+
class="rounded-circle me-2"
|
|
70
|
+
width="24" height="24"
|
|
71
|
+
style="object-fit: cover;">
|
|
72
|
+
{% else %}
|
|
73
|
+
<i class="bi bi-person-circle me-1"></i>
|
|
74
|
+
{% endif %}
|
|
75
|
+
<span class="author-name">{{ author_name }}</span>
|
|
76
|
+
</span>
|
|
77
|
+
|
|
78
|
+
<!-- ========================== -->
|
|
79
|
+
<!-- COMPACT STYLE (default) -->
|
|
80
|
+
<!-- ========================== -->
|
|
81
|
+
{% elsif style == "compact" %}
|
|
82
|
+
<div class="author-card-compact d-flex align-items-center">
|
|
83
|
+
{% if author_data.avatar %}
|
|
84
|
+
<img src="{{ site.baseurl }}/{{ site.public_folder }}{{ author_data.avatar }}"
|
|
85
|
+
alt="{{ author_name }}"
|
|
86
|
+
class="rounded-circle me-3"
|
|
87
|
+
width="48" height="48"
|
|
88
|
+
style="object-fit: cover;">
|
|
89
|
+
{% else %}
|
|
90
|
+
<div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center me-3"
|
|
91
|
+
style="width: 48px; height: 48px;">
|
|
92
|
+
<i class="bi bi-person fs-5"></i>
|
|
93
|
+
</div>
|
|
94
|
+
{% endif %}
|
|
95
|
+
<div>
|
|
96
|
+
<strong class="d-block">{{ author_name }}</strong>
|
|
97
|
+
{% if author_data.role %}
|
|
98
|
+
<small class="text-muted">{{ author_data.role }}</small>
|
|
99
|
+
{% endif %}
|
|
100
|
+
{% if show_bio and author_data.bio %}
|
|
101
|
+
<p class="text-muted small mb-0 mt-1">{{ author_data.bio | truncate: 100 }}</p>
|
|
102
|
+
{% endif %}
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<!-- ========================== -->
|
|
107
|
+
<!-- FULL STYLE -->
|
|
108
|
+
<!-- ========================== -->
|
|
109
|
+
{% elsif style == "full" %}
|
|
110
|
+
<div class="author-card card border-0 shadow-sm">
|
|
111
|
+
<div class="card-body">
|
|
112
|
+
<div class="d-flex align-items-start">
|
|
113
|
+
{% if author_data.avatar %}
|
|
114
|
+
<img src="{{ site.baseurl }}/{{ site.public_folder }}{{ author_data.avatar }}"
|
|
115
|
+
alt="{{ author_name }}"
|
|
116
|
+
class="rounded-circle me-3"
|
|
117
|
+
width="80" height="80"
|
|
118
|
+
style="object-fit: cover;">
|
|
119
|
+
{% else %}
|
|
120
|
+
<div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center me-3"
|
|
121
|
+
style="width: 80px; height: 80px;">
|
|
122
|
+
<i class="bi bi-person fs-1"></i>
|
|
123
|
+
</div>
|
|
124
|
+
{% endif %}
|
|
125
|
+
<div class="flex-grow-1">
|
|
126
|
+
<h5 class="card-title mb-1">{{ author_name }}</h5>
|
|
127
|
+
{% if author_data.role %}
|
|
128
|
+
<p class="text-primary mb-2">{{ author_data.role }}</p>
|
|
129
|
+
{% endif %}
|
|
130
|
+
{% if show_bio and author_data.bio %}
|
|
131
|
+
<p class="card-text text-muted">{{ author_data.bio }}</p>
|
|
132
|
+
{% endif %}
|
|
133
|
+
|
|
134
|
+
{% if show_social %}
|
|
135
|
+
<div class="author-social d-flex gap-2 mt-2">
|
|
136
|
+
{% if author_data.github %}
|
|
137
|
+
<a href="https://github.com/{{ author_data.github }}"
|
|
138
|
+
class="btn btn-sm btn-outline-secondary"
|
|
139
|
+
target="_blank" rel="noopener" title="GitHub">
|
|
140
|
+
<i class="bi bi-github"></i>
|
|
141
|
+
</a>
|
|
142
|
+
{% endif %}
|
|
143
|
+
{% if author_data.twitter %}
|
|
144
|
+
<a href="https://twitter.com/{{ author_data.twitter }}"
|
|
145
|
+
class="btn btn-sm btn-outline-secondary"
|
|
146
|
+
target="_blank" rel="noopener" title="Twitter">
|
|
147
|
+
<i class="bi bi-twitter"></i>
|
|
148
|
+
</a>
|
|
149
|
+
{% endif %}
|
|
150
|
+
{% if author_data.linkedin %}
|
|
151
|
+
<a href="https://linkedin.com/in/{{ author_data.linkedin }}"
|
|
152
|
+
class="btn btn-sm btn-outline-secondary"
|
|
153
|
+
target="_blank" rel="noopener" title="LinkedIn">
|
|
154
|
+
<i class="bi bi-linkedin"></i>
|
|
155
|
+
</a>
|
|
156
|
+
{% endif %}
|
|
157
|
+
{% if author_data.website %}
|
|
158
|
+
<a href="{{ author_data.website }}"
|
|
159
|
+
class="btn btn-sm btn-outline-secondary"
|
|
160
|
+
target="_blank" rel="noopener" title="Website">
|
|
161
|
+
<i class="bi bi-globe"></i>
|
|
162
|
+
</a>
|
|
163
|
+
{% endif %}
|
|
164
|
+
{% if author_data.email %}
|
|
165
|
+
<a href="mailto:{{ author_data.email }}"
|
|
166
|
+
class="btn btn-sm btn-outline-secondary"
|
|
167
|
+
title="Email">
|
|
168
|
+
<i class="bi bi-envelope"></i>
|
|
169
|
+
</a>
|
|
170
|
+
{% endif %}
|
|
171
|
+
</div>
|
|
172
|
+
{% endif %}
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
{% endif %}
|