datalog-theme 0.6.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 (180) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +162 -0
  3. data/CITATION.cff +29 -0
  4. data/LICENSE +21 -0
  5. data/README.md +257 -0
  6. data/_data/academic.yml +217 -0
  7. data/_data/cdn-integrity.yml +51 -0
  8. data/_data/config/author.yml +121 -0
  9. data/_data/config/features.yml +262 -0
  10. data/_data/config/site.yml +42 -0
  11. data/_data/config/theme.yml +181 -0
  12. data/_data/datasets.yml +28 -0
  13. data/_data/i18n/en.yml +438 -0
  14. data/_data/i18n/es.yml +438 -0
  15. data/_data/i18n/pt.yml +438 -0
  16. data/_data/js_manifest.json +22 -0
  17. data/_data/js_meta.json +371 -0
  18. data/_data/navigation.yml +145 -0
  19. data/_data/projects.yml +41 -0
  20. data/_data/publications.yml +28 -0
  21. data/_data/social.yml +73 -0
  22. data/_data/visualizations.yml +51 -0
  23. data/_includes/analytics/dashboard.html +149 -0
  24. data/_includes/analytics.html +9 -0
  25. data/_includes/components/academic-dashboard.html +347 -0
  26. data/_includes/components/advanced-search.html +682 -0
  27. data/_includes/components/api-function.html +94 -0
  28. data/_includes/components/author-bio.html +166 -0
  29. data/_includes/components/bookmark-system.html +96 -0
  30. data/_includes/components/breadcrumbs.html +89 -0
  31. data/_includes/components/citation-tools.html +94 -0
  32. data/_includes/components/comments.html +244 -0
  33. data/_includes/components/content-provenance.html +43 -0
  34. data/_includes/components/content-recommendations.html +228 -0
  35. data/_includes/components/difficulty-badge.html +84 -0
  36. data/_includes/components/email-preferences.html +200 -0
  37. data/_includes/components/enhanced-code-block.html +212 -0
  38. data/_includes/components/enhanced-metadata.html +228 -0
  39. data/_includes/components/enhanced-toc.html +209 -0
  40. data/_includes/components/hero.html +15 -0
  41. data/_includes/components/language-switcher.html +396 -0
  42. data/_includes/components/math-fallback.html +19 -0
  43. data/_includes/components/navigation-enhancements.html +454 -0
  44. data/_includes/components/newsletter-signup.html +178 -0
  45. data/_includes/components/open-science-badges.html +16 -0
  46. data/_includes/components/package-install.html +194 -0
  47. data/_includes/components/performance-monitor.html +170 -0
  48. data/_includes/components/popular-posts.html +233 -0
  49. data/_includes/components/post-hero.html +62 -0
  50. data/_includes/components/reading-progress.html +133 -0
  51. data/_includes/components/reading-time.html +121 -0
  52. data/_includes/components/responsive-image.html +63 -0
  53. data/_includes/components/search-facets.html +307 -0
  54. data/_includes/components/series-navigation.html +124 -0
  55. data/_includes/components/social-proof.html +34 -0
  56. data/_includes/components/social-share.html +119 -0
  57. data/_includes/components/user-preferences.html +566 -0
  58. data/_includes/components/visualization-card.html +24 -0
  59. data/_includes/components/viz-table-fallback.html +19 -0
  60. data/_includes/critical-css/default.html +0 -0
  61. data/_includes/critical-css/home.html +0 -0
  62. data/_includes/critical-css/post.html +0 -0
  63. data/_includes/csp-meta.html +17 -0
  64. data/_includes/footer/nav-column.html +31 -0
  65. data/_includes/footer.html +76 -0
  66. data/_includes/head.html +337 -0
  67. data/_includes/header/navigation.html +48 -0
  68. data/_includes/header.html +70 -0
  69. data/_includes/helpers/array-to-sentence.html +21 -0
  70. data/_includes/helpers/date-format.html +16 -0
  71. data/_includes/helpers/link-with-icon.html +26 -0
  72. data/_includes/layouts/default/article.html +67 -0
  73. data/_includes/meta/language-attributes.html +25 -0
  74. data/_includes/meta/math-config.html +21 -0
  75. data/_includes/meta/schema.html +153 -0
  76. data/_includes/meta/scripts-loader.html +52 -0
  77. data/_includes/post/related-posts.html +63 -0
  78. data/_includes/scripts.html +72 -0
  79. data/_includes/skip-link.html +1 -0
  80. data/_includes/toc.html +2 -0
  81. data/_layouts/archive.html +282 -0
  82. data/_layouts/dataset.html +52 -0
  83. data/_layouts/default.html +33 -0
  84. data/_layouts/home.html +48 -0
  85. data/_layouts/notebook.html +173 -0
  86. data/_layouts/package.html +238 -0
  87. data/_layouts/page.html +16 -0
  88. data/_layouts/portfolio.html +41 -0
  89. data/_layouts/post-sidebar.html +183 -0
  90. data/_layouts/post.html +338 -0
  91. data/_layouts/project.html +252 -0
  92. data/_layouts/research.html +504 -0
  93. data/_plugins/analytics_dashboard.rb +315 -0
  94. data/_plugins/config_validator.rb +397 -0
  95. data/_plugins/csp_generator.rb +115 -0
  96. data/_plugins/datalog_bibliography.rb +19 -0
  97. data/_plugins/datalog_comments.rb +18 -0
  98. data/_plugins/datalog_slides.rb +20 -0
  99. data/_plugins/front_matter_compat.rb +109 -0
  100. data/_plugins/i18n.rb +160 -0
  101. data/_plugins/image_optimizer.rb +445 -0
  102. data/_plugins/math_preprocessor.rb +185 -0
  103. data/_plugins/notebook_converter.rb +1107 -0
  104. data/_plugins/plugin_loader.rb +185 -0
  105. data/_plugins/publications_generator.rb +234 -0
  106. data/_plugins/reading_time.rb +15 -0
  107. data/_plugins/search_normalizer.rb +74 -0
  108. data/_plugins/sri_filter.rb +18 -0
  109. data/_plugins/toc_filter.rb +68 -0
  110. data/_plugins/warning_filter.rb +3 -0
  111. data/_sass/_base.scss +142 -0
  112. data/_sass/_components.scss +2380 -0
  113. data/_sass/_header.scss +470 -0
  114. data/_sass/_interactive.scss +344 -0
  115. data/_sass/_layout.scss +1760 -0
  116. data/_sass/_mathematical.scss +368 -0
  117. data/_sass/_mixins.scss +99 -0
  118. data/_sass/_package-docs.scss +715 -0
  119. data/_sass/_phase1-enhancements.scss +721 -0
  120. data/_sass/_phase3-enhancements.scss +874 -0
  121. data/_sass/_phase4-enhancements.scss +1214 -0
  122. data/_sass/_phase5-enhancements.scss +414 -0
  123. data/_sass/_search.scss +654 -0
  124. data/_sass/_syntax-highlighting.scss +128 -0
  125. data/_sass/_theme.scss +79 -0
  126. data/_sass/_typography.scss +148 -0
  127. data/_sass/_utilities.scss +334 -0
  128. data/_sass/_variables.scss +153 -0
  129. data/_sass/_visualizations.scss +242 -0
  130. data/assets/css/main.scss +4 -0
  131. data/assets/img/20220607123041_detail.001.png +0 -0
  132. data/assets/img/favicons/android-chrome-192x192.png +0 -0
  133. data/assets/img/favicons/android-chrome-512x512.png +0 -0
  134. data/assets/img/favicons/apple-touch-icon.png +0 -0
  135. data/assets/img/favicons/favicon-16x16.png +0 -0
  136. data/assets/img/favicons/favicon-32x32.png +0 -0
  137. data/assets/img/favicons/favicon.ico +0 -0
  138. data/assets/img/favicons/site.webmanifest +21 -0
  139. data/assets/img/portfolio-placeholder.svg +20 -0
  140. data/assets/js/academic.js +262 -0
  141. data/assets/js/analytics-dashboard.js +382 -0
  142. data/assets/js/core/dark-mode.js +79 -0
  143. data/assets/js/core/github-cards.js +123 -0
  144. data/assets/js/core/language-filter.js +69 -0
  145. data/assets/js/core/navigation.js +184 -0
  146. data/assets/js/core/scroll-progress.js +45 -0
  147. data/assets/js/core/search-hotkeys.js +62 -0
  148. data/assets/js/core/skip-links.js +62 -0
  149. data/assets/js/loader.js +163 -0
  150. data/assets/js/main.js +23 -0
  151. data/assets/js/math.js +818 -0
  152. data/assets/js/notebook.js +158 -0
  153. data/assets/js/search/analytics.js +91 -0
  154. data/assets/js/search/app.js +271 -0
  155. data/assets/js/search/autocomplete.js +120 -0
  156. data/assets/js/search/engine.js +260 -0
  157. data/assets/js/search/filters.js +38 -0
  158. data/assets/js/search/render.js +217 -0
  159. data/assets/js/search/utils.js +99 -0
  160. data/assets/js/search.js +354 -0
  161. data/assets/js/visualizations.js +816 -0
  162. data/assets/publications/datalog-publications.bib +8 -0
  163. data/assets/publications/datalog-publications.ris +9 -0
  164. data/assets/publications/publications.bib +30 -0
  165. data/assets/templates/diogo-ribeiro-cv.md +31 -0
  166. data/assets/templates/diogo-ribeiro-cv.tex +32 -0
  167. data/bin/datalog +26 -0
  168. data/datalog-theme.gemspec +72 -0
  169. data/lib/datalog/cli.rb +563 -0
  170. data/lib/datalog/plugin_system/dependency_resolver.rb +223 -0
  171. data/lib/datalog/plugin_system.rb +237 -0
  172. data/lib/datalog/plugins/citations.rb +182 -0
  173. data/lib/datalog/plugins/comments.rb +183 -0
  174. data/lib/datalog/plugins/search.rb +45 -0
  175. data/lib/datalog/plugins/slides.rb +121 -0
  176. data/lib/datalog/theme/theme.rb +18 -0
  177. data/lib/datalog/theme/version.rb +7 -0
  178. data/lib/datalog/warning_filter.rb +28 -0
  179. data/lib/datalog-theme.rb +17 -0
  180. metadata +555 -0
@@ -0,0 +1,124 @@
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 -%}
@@ -0,0 +1,34 @@
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 -%}
@@ -0,0 +1,119 @@
1
+ {%- comment -%}
2
+ Enhanced social sharing buttons with icons and analytics tracking
3
+ Parameters:
4
+ - url: URL to share (default: page.url)
5
+ - title: Title to share (default: page.title)
6
+ - description: Description for sharing (default: page.excerpt)
7
+ - show_count: Show share count (default: false)
8
+ {%- endcomment -%}
9
+
10
+ {%- assign share_url = include.url | default: page.url | absolute_url -%}
11
+ {%- assign share_title = include.title | default: page.title -%}
12
+ {%- assign share_description = include.description | default: page.excerpt | strip_html | truncate: 200 -%}
13
+ {%- assign show_count = include.show_count | default: false -%}
14
+
15
+ <div class="social-share" aria-label="Share this article">
16
+ <h3 class="social-share__heading">Share this article</h3>
17
+ <div class="social-share__buttons">
18
+ {%- comment -%} Twitter/X Share {%- endcomment -%}
19
+ <a href="https://twitter.com/intent/tweet?url={{ share_url | uri_escape }}&text={{ share_title | uri_escape }}"
20
+ class="social-share__button social-share__button--twitter"
21
+ target="_blank"
22
+ rel="noopener noreferrer"
23
+ aria-label="Share on Twitter"
24
+ data-share-platform="twitter">
25
+ <svg class="social-share__icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
26
+ <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
27
+ </svg>
28
+ <span class="social-share__label">Twitter</span>
29
+ </a>
30
+
31
+ {%- comment -%} LinkedIn Share {%- endcomment -%}
32
+ <a href="https://www.linkedin.com/sharing/share-offsite/?url={{ share_url | uri_escape }}"
33
+ class="social-share__button social-share__button--linkedin"
34
+ target="_blank"
35
+ rel="noopener noreferrer"
36
+ aria-label="Share on LinkedIn"
37
+ data-share-platform="linkedin">
38
+ <svg class="social-share__icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
39
+ <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
40
+ </svg>
41
+ <span class="social-share__label">LinkedIn</span>
42
+ </a>
43
+
44
+ {%- comment -%} Facebook Share {%- endcomment -%}
45
+ <a href="https://www.facebook.com/sharer/sharer.php?u={{ share_url | uri_escape }}"
46
+ class="social-share__button social-share__button--facebook"
47
+ target="_blank"
48
+ rel="noopener noreferrer"
49
+ aria-label="Share on Facebook"
50
+ data-share-platform="facebook">
51
+ <svg class="social-share__icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
52
+ <path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/>
53
+ </svg>
54
+ <span class="social-share__label">Facebook</span>
55
+ </a>
56
+
57
+ {%- comment -%} Reddit Share {%- endcomment -%}
58
+ <a href="https://www.reddit.com/submit?url={{ share_url | uri_escape }}&title={{ share_title | uri_escape }}"
59
+ class="social-share__button social-share__button--reddit"
60
+ target="_blank"
61
+ rel="noopener noreferrer"
62
+ aria-label="Share on Reddit"
63
+ data-share-platform="reddit">
64
+ <svg class="social-share__icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
65
+ <path d="M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm5.01 4.744c.688 0 1.25.561 1.25 1.249a1.25 1.25 0 0 1-2.498.056l-2.597-.547-.8 3.747c1.824.07 3.48.632 4.674 1.488.308-.309.73-.491 1.207-.491.968 0 1.754.786 1.754 1.754 0 .716-.435 1.333-1.01 1.614a3.111 3.111 0 0 1 .042.52c0 2.694-3.13 4.87-7.004 4.87-3.874 0-7.004-2.176-7.004-4.87 0-.183.015-.366.043-.534A1.748 1.748 0 0 1 4.028 12c0-.968.786-1.754 1.754-1.754.463 0 .898.196 1.207.49 1.207-.883 2.878-1.43 4.744-1.487l.885-4.182a.342.342 0 0 1 .14-.197.35.35 0 0 1 .238-.042l2.906.617a1.214 1.214 0 0 1 1.108-.701zM9.25 12C8.561 12 8 12.562 8 13.25c0 .687.561 1.248 1.25 1.248.687 0 1.248-.561 1.248-1.249 0-.688-.561-1.249-1.249-1.249zm5.5 0c-.687 0-1.248.561-1.248 1.25 0 .687.561 1.248 1.249 1.248.688 0 1.249-.561 1.249-1.249 0-.687-.562-1.249-1.25-1.249zm-5.466 3.99a.327.327 0 0 0-.231.094.33.33 0 0 0 0 .463c.842.842 2.484.913 2.961.913.477 0 2.105-.056 2.961-.913a.361.361 0 0 0 .029-.463.33.33 0 0 0-.464 0c-.547.533-1.684.73-2.512.73-.828 0-1.979-.196-2.512-.73a.326.326 0 0 0-.232-.095z"/>
66
+ </svg>
67
+ <span class="social-share__label">Reddit</span>
68
+ </a>
69
+
70
+ {%- comment -%} Email Share {%- endcomment -%}
71
+ <a href="mailto:?subject={{ share_title | uri_escape }}&body={{ share_description | uri_escape }}%0A%0A{{ share_url | uri_escape }}"
72
+ class="social-share__button social-share__button--email"
73
+ aria-label="Share via email"
74
+ data-share-platform="email">
75
+ <svg class="social-share__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">
76
+ <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
77
+ <polyline points="22,6 12,13 2,6"></polyline>
78
+ </svg>
79
+ <span class="social-share__label">Email</span>
80
+ </a>
81
+
82
+ {%- comment -%} Copy Link {%- endcomment -%}
83
+ <button type="button"
84
+ class="social-share__button social-share__button--copy"
85
+ aria-label="Copy link to clipboard"
86
+ data-share-platform="copy"
87
+ data-copy-url="{{ share_url }}">
88
+ <svg class="social-share__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">
89
+ <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
90
+ <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
91
+ </svg>
92
+ <span class="social-share__label">Copy link</span>
93
+ </button>
94
+ </div>
95
+ </div>
96
+
97
+ <script>
98
+ // Copy link functionality
99
+ document.addEventListener('DOMContentLoaded', function() {
100
+ const copyButton = document.querySelector('[data-share-platform="copy"]');
101
+ if (copyButton && navigator.clipboard) {
102
+ copyButton.addEventListener('click', function() {
103
+ const url = this.getAttribute('data-copy-url');
104
+ navigator.clipboard.writeText(url).then(function() {
105
+ const label = copyButton.querySelector('.social-share__label');
106
+ const originalText = label.textContent;
107
+ label.textContent = 'Copied!';
108
+ copyButton.classList.add('is-copied');
109
+ setTimeout(function() {
110
+ label.textContent = originalText;
111
+ copyButton.classList.remove('is-copied');
112
+ }, 2000);
113
+ }).catch(function(err) {
114
+ console.error('Failed to copy:', err);
115
+ });
116
+ });
117
+ }
118
+ });
119
+ </script>