rawfeed 0.1.3 → 0.2.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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +20 -21
  3. data/README.md +13 -112
  4. data/_data/options.yml +270 -0
  5. data/_data/resume.yml +8 -9
  6. data/_includes/alert +3 -1
  7. data/_includes/chart +13 -32
  8. data/_includes/details +1 -57
  9. data/_includes/image +12 -4
  10. data/_includes/layout/blog_search.html +7 -5
  11. data/_includes/layout/data.liquid +21 -3
  12. data/_includes/layout/disqus.html +12 -26
  13. data/_includes/layout/footer.html +34 -16
  14. data/_includes/layout/giscus.html +27 -19
  15. data/_includes/layout/head.html +58 -19
  16. data/_includes/layout/header.html +127 -101
  17. data/_includes/layout/maintenance.html +8 -12
  18. data/_includes/layout/paginator.html +6 -4
  19. data/_includes/socials +7 -5
  20. data/_includes/tabs +1 -94
  21. data/_includes/toc +12 -152
  22. data/_includes/video +4 -1
  23. data/_layouts/blog.html +8 -7
  24. data/_layouts/contact.html +90 -196
  25. data/_layouts/default.html +42 -339
  26. data/_layouts/error.html +6 -4
  27. data/_layouts/home.html +45 -36
  28. data/_layouts/licenses.html +10 -0
  29. data/_layouts/page.html +4 -6
  30. data/_layouts/pixel.html +48 -0
  31. data/_layouts/pixels.html +71 -0
  32. data/_layouts/post.html +28 -31
  33. data/_layouts/resume.html +43 -36
  34. data/_layouts/tag.html +14 -3
  35. data/_layouts/tag_posts.html +3 -3
  36. data/_sass/base/_index.scss +39 -3
  37. data/_sass/components/_badges.scss +10 -0
  38. data/_sass/components/_markdown.scss +20 -17
  39. data/_sass/includes/_footer.scss +18 -8
  40. data/_sass/includes/_header.scss +24 -19
  41. data/_sass/includes/_highlight.scss +20 -7
  42. data/_sass/includes/_maintenance.scss +2 -3
  43. data/_sass/includes/_terminal.scss +35 -12
  44. data/_sass/layouts/_blog.scss +13 -9
  45. data/_sass/layouts/_contact.scss +6 -5
  46. data/_sass/layouts/_default.scss +5 -5
  47. data/_sass/layouts/_index.scss +3 -0
  48. data/_sass/layouts/_licenses.scss +7 -0
  49. data/_sass/layouts/_page.scss +1 -0
  50. data/_sass/layouts/_pixel.scss +61 -0
  51. data/_sass/layouts/_pixels.scss +86 -0
  52. data/_sass/layouts/_post.scss +4 -11
  53. data/_sass/layouts/_resume.scss +17 -7
  54. data/_sass/layouts/_tag-posts.scss +1 -2
  55. data/_sass/layouts/_tag.scss +12 -1
  56. data/_sass/main.scss +16 -1
  57. data/_sass/theme/_dark.scss +15 -5
  58. data/_sass/theme/_light.scss +9 -2
  59. data/assets/images/blog/.keep +0 -0
  60. data/assets/images/pixels/luffy.jpg +0 -0
  61. data/assets/js/blog.coffee +102 -0
  62. data/assets/js/contact.coffee +105 -0
  63. data/assets/js/default.coffee +172 -0
  64. data/assets/js/discus.coffee +30 -0
  65. data/assets/js/fallback/README.md +3 -0
  66. data/assets/js/fallback/blog.js +113 -0
  67. data/assets/js/fallback/contact.js +116 -0
  68. data/assets/js/{default.js → fallback/default.js} +50 -0
  69. data/assets/js/fallback/discus.js +32 -0
  70. data/{_includes/layout/google_analytics.html → assets/js/fallback/google_analytics.js} +7 -3
  71. data/assets/js/fallback/home.js +275 -0
  72. data/assets/js/fallback/no_inframe.js +4 -0
  73. data/assets/js/fallback/page.js +423 -0
  74. data/assets/js/fallback/pixels.js +1 -0
  75. data/assets/js/fallback/resume.js +13 -0
  76. data/assets/js/fallback/tags.js +1 -0
  77. data/assets/js/fallback/theme_load.js +4 -0
  78. data/assets/js/google_analytics.coffee +24 -0
  79. data/assets/js/home.coffee +250 -0
  80. data/assets/js/no_inframe.coffee +9 -0
  81. data/assets/js/page.coffee +379 -0
  82. data/assets/js/pixels.coffee +2 -0
  83. data/assets/js/resume.coffee +9 -0
  84. data/assets/js/tags.coffee +2 -0
  85. data/assets/js/theme_load.coffee +6 -0
  86. data/assets/json/blog_search.json +2 -2
  87. data/lib/rawfeed/author.rb +59 -0
  88. data/lib/rawfeed/csp_filters.rb +19 -0
  89. data/lib/rawfeed/draft.rb +1 -1
  90. data/lib/rawfeed/layout.rb +7 -0
  91. data/lib/rawfeed/page.rb +4 -2
  92. data/lib/rawfeed/pixel.rb +32 -0
  93. data/lib/rawfeed/post.rb +2 -2
  94. data/lib/rawfeed/resume.rb +1 -0
  95. data/lib/rawfeed/typescript_liquid.rb +172 -0
  96. data/lib/rawfeed/utils.rb +1 -0
  97. data/lib/rawfeed/version.rb +1 -1
  98. data/lib/rawfeed/with_class.rb +20 -0
  99. data/lib/rawfeed.rb +5 -0
  100. metadata +46 -12
  101. data/assets/js/avatar.js +0 -50
  102. data/assets/js/terminal.js +0 -18
  103. data/assets/js/toc.js +0 -22
@@ -0,0 +1,423 @@
1
+ ---
2
+ ---
3
+
4
+
5
+ document.addEventListener("DOMContentLoaded", () => {
6
+
7
+ /* details
8
+ # ------------------------------------------------------------------------------------------------
9
+ */
10
+ const detailsStart = document.getElementById("details-start");
11
+
12
+ if (detailsStart) {
13
+ if (window.__jekyll_details_setup) return;
14
+ window.__jekyll_details_setup = true;
15
+
16
+ function initDetails(){
17
+ const starts = document.querySelectorAll('.details-start');
18
+ starts.forEach(start => {
19
+ const summary = start.getAttribute('data-summary') || 'Detalhes';
20
+
21
+ let end = start.nextSibling;
22
+ while(end && !(end.nodeType === 1 && end.classList.contains('details-end'))){
23
+ end = end.nextSibling;
24
+ }
25
+ if(!end) return;
26
+
27
+ let node = start.nextSibling;
28
+ const content = [];
29
+ while(node && node !== end){
30
+ const next = node.nextSibling;
31
+ if(node.nodeType === Node.ELEMENT_NODE || (node.nodeType === Node.TEXT_NODE && node.textContent.trim())){
32
+ content.push(node.cloneNode(true));
33
+ }
34
+ node = next;
35
+ }
36
+
37
+ const details = document.createElement('details');
38
+ const sum = document.createElement('summary');
39
+ sum.textContent = summary;
40
+ details.appendChild(sum);
41
+
42
+ const wrapper = document.createElement('div');
43
+ wrapper.className = 'details-content-wrapper';
44
+
45
+ content.forEach(el => wrapper.appendChild(el));
46
+
47
+ details.appendChild(wrapper);
48
+
49
+ start.parentNode.insertBefore(details, start);
50
+ let cur = start;
51
+ while(cur){
52
+ const next = cur.nextSibling;
53
+ cur.remove();
54
+ if(cur === end) break;
55
+ cur = next;
56
+ }
57
+ });
58
+ }
59
+
60
+ if(document.readyState === 'loading')
61
+ document.addEventListener('DOMContentLoaded', initDetails);
62
+ else
63
+ initDetails();
64
+ }
65
+
66
+ /* tabs
67
+ # ------------------------------------------------------------------------------------------------
68
+ */
69
+ const tabsStart = document.getElementById("tabs-start");
70
+
71
+ if (tabsStart) {
72
+ if (window.__simple_tabs_installed) return;
73
+ window.__simple_tabs_installed = true;
74
+
75
+ function processTabs() {
76
+ var starts = Array.from(document.querySelectorAll('.tabs-start'));
77
+ starts.forEach(function (start) {
78
+ var end = start.nextSibling;
79
+ while (end && !(end.nodeType === 1 && end.classList && end.classList.contains('tabs-end'))) {
80
+ end = end.nextSibling;
81
+ }
82
+ if (!end) return;
83
+
84
+ var node = start.nextSibling;
85
+ var tabs = [];
86
+ var currentTab = null;
87
+ while (node && node !== end) {
88
+ var next = node.nextSibling;
89
+ if (node.nodeType === Node.TEXT_NODE && !node.textContent.trim()) {
90
+ node = next; continue;
91
+ }
92
+ var text = (node.textContent || '').trim();
93
+ var m = text.match(/^\s*tab\d*\s*:\s*(.+)$/i);
94
+ if (m) {
95
+ currentTab = { title: m[1].trim(), nodes: [] };
96
+ tabs.push(currentTab);
97
+ if (node.parentNode) node.parentNode.removeChild(node);
98
+ } else if (currentTab) {
99
+ currentTab.nodes.push(node);
100
+ } else {
101
+ }
102
+ node = next;
103
+ }
104
+
105
+ if (tabs.length === 0) {
106
+ return;
107
+ }
108
+
109
+ var wrap = document.createElement('div');
110
+ wrap.className = 'tabs-wrap';
111
+
112
+ var nav = document.createElement('div');
113
+ nav.className = 'tabs-nav';
114
+
115
+ var panels = document.createElement('div');
116
+ panels.className = 'tabs-panels';
117
+
118
+ tabs.forEach(function (tab, i) {
119
+ var btn = document.createElement('button');
120
+ btn.type = 'button';
121
+ btn.className = 'tab-btn' + (i === 0 ? ' active' : '');
122
+ btn.setAttribute('data-idx', i);
123
+ btn.textContent = tab.title;
124
+ btn.addEventListener('click', function () {
125
+ var idx = +this.getAttribute('data-idx');
126
+ wrap.querySelectorAll('.tab-btn').forEach(function (b) {
127
+ b.classList.toggle('active', +b.getAttribute('data-idx') === idx);
128
+ });
129
+ wrap.querySelectorAll('.tab-panel').forEach(function (p, pi) {
130
+ p.classList.toggle('active', pi === idx);
131
+ });
132
+ });
133
+ nav.appendChild(btn);
134
+
135
+ var panel = document.createElement('div');
136
+ panel.className = 'tab-panel' + (i === 0 ? ' active' : '');
137
+ tab.nodes.forEach(function (n) {
138
+ panel.appendChild(n.cloneNode(true));
139
+ });
140
+ panels.appendChild(panel);
141
+ });
142
+
143
+ wrap.appendChild(nav);
144
+ wrap.appendChild(panels);
145
+
146
+ start.parentNode.insertBefore(wrap, start);
147
+
148
+ var cur = start;
149
+ while (cur) {
150
+ var nx = cur.nextSibling;
151
+ if (cur.parentNode) cur.parentNode.removeChild(cur);
152
+ if (cur === end) break;
153
+ cur = nx;
154
+ }
155
+ });
156
+ }
157
+
158
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', processTabs);
159
+ else processTabs();
160
+ }
161
+
162
+ /* chart
163
+ # ------------------------------------------------------------------------------------------------
164
+ */
165
+
166
+ const chart_elements = document.querySelectorAll('[id^="chart-"]');
167
+
168
+ for (const ctx of chart_elements) {
169
+ const data = ctx.dataset;
170
+
171
+ new Chart(ctx, {
172
+ type: data.type,
173
+ data: {
174
+ labels: data.labels.split(","),
175
+ datasets: [
176
+ {
177
+ label: data.label,
178
+ data: data.data.split(",").map(Number),
179
+ borderColor: data.color,
180
+ backgroundColor: `${data.color}33`,
181
+ fill: true,
182
+ tension: 0.3,
183
+ borderWidth: 2,
184
+ pointRadius: 4,
185
+ pointHoverRadius: 6
186
+ }
187
+ ]
188
+ },
189
+ options: {
190
+ responsive: true,
191
+ plugins: {
192
+ legend: {
193
+ display: true,
194
+ labels: {
195
+ color: "#444444"
196
+ }
197
+ }
198
+ },
199
+ scales: {
200
+ x: {
201
+ ticks: {
202
+ color: "#131313"
203
+ },
204
+ grid: {
205
+ color: "#111111"
206
+ }
207
+ },
208
+ y: {
209
+ ticks: {
210
+ color: "#131313"
211
+ },
212
+ grid: {
213
+ color: "#111111"
214
+ }
215
+ }
216
+ }
217
+ }
218
+ });
219
+ }
220
+
221
+ /* TOC
222
+ # ------------------------------------------------------------------------------------------------
223
+ */
224
+
225
+ const toc = document.getElementById('toc');
226
+ if (toc) {
227
+ // Variável global de largura minima do TOC
228
+ const minLayoutWidth = 1830;
229
+
230
+ const sentinel = document.createElement('div');
231
+ toc.parentNode.insertBefore(sentinel, toc);
232
+
233
+ const shouldApplyFixed = () => window.innerWidth > minLayoutWidth;
234
+
235
+ const observer = new IntersectionObserver(([entry]) => {
236
+ if (shouldApplyFixed()) {
237
+ if (!entry.isIntersecting) {
238
+ toc.classList.add('toc-fixed');
239
+ } else {
240
+ toc.classList.remove('toc-fixed');
241
+ }
242
+ } else {
243
+ toc.classList.remove('toc-fixed');
244
+ }
245
+ }, { threshold: 0 });
246
+
247
+ observer.observe(sentinel);
248
+
249
+ window.addEventListener('resize', () => {
250
+ if (!shouldApplyFixed()) toc.classList.remove('toc-fixed');
251
+ });
252
+
253
+ const slugify = (text) => {
254
+ if (!text) return '';
255
+ return text.toString().toLowerCase().trim()
256
+ .normalize('NFKD').replace(/[\u0300-\u036f]/g, '')
257
+ .replace(/[^\w\s-]/g, '')
258
+ .replace(/\s+/g, '-')
259
+ .replace(/--+/g, '-');
260
+ };
261
+
262
+ const buildTOC = (tocEl) => {
263
+ const selector = tocEl.dataset.tocSelector || '.post-content' || '.page-content';
264
+ const maxLevel = parseInt(tocEl.dataset.tocMaxLevel || '3', 10);
265
+ const offset = parseInt(tocEl.dataset.tocScrollOffset || '20', 10);
266
+
267
+ const root = document.querySelector(selector);
268
+
269
+ if (!root) {
270
+ tocEl.querySelector('.toc-empty').textContent = `Content not found (${selector})`;
271
+ tocEl.querySelector('.toc-empty').style.display = 'block';
272
+ return;
273
+ }
274
+
275
+ const headings = Array.from(
276
+ root.querySelectorAll(Array(maxLevel).fill(0).map((_, i) => `h${i + 1}`).join(','))
277
+ )
278
+ .filter((h) => !tocEl.contains(h))
279
+ .filter((h) => parseInt(h.tagName.substring(1)) <= maxLevel);
280
+
281
+ if (headings.length === 0) return;
282
+
283
+ const tocRoot = tocEl.querySelector('.toc-list');
284
+ tocRoot.innerHTML = '';
285
+
286
+ const idCounts = {};
287
+ for (const h of headings) {
288
+ if (!h.id) {
289
+ let id = slugify(h.textContent);
290
+ if (!id) id = 'section';
291
+
292
+ if (idCounts[id]) {
293
+ idCounts[id] += 1;
294
+ id = `${id}-${idCounts[id]}`;
295
+ } else {
296
+ idCounts[id] = 1;
297
+ }
298
+
299
+ h.id = id;
300
+ }
301
+ }
302
+
303
+ const stack = [{ level: 0, ul: tocRoot }];
304
+ for (let i = 0; i < headings.length; i++) {
305
+ const h = headings[i];
306
+ const level = parseInt(h.tagName.substring(1));
307
+ const li = document.createElement('li');
308
+ const a = document.createElement('a');
309
+ a.href = `#${h.id}`;
310
+ a.textContent = h.textContent.trim();
311
+
312
+ a.addEventListener('click', (e) => {
313
+ e.preventDefault();
314
+ window.scrollTo({
315
+ top: h.getBoundingClientRect().top + window.scrollY - offset,
316
+ behavior: 'smooth'
317
+ });
318
+ history.replaceState(null, '', `#${h.id}`);
319
+ });
320
+
321
+ li.appendChild(a);
322
+
323
+ while (stack.length > 1 && level <= stack[stack.length - 1].level) {
324
+ stack.pop();
325
+ }
326
+
327
+ const parent = stack[stack.length - 1].ul;
328
+ parent.appendChild(li);
329
+
330
+ const next = headings[i + 1];
331
+ if (next) {
332
+ const nextLevel = parseInt(next.tagName.substring(1));
333
+ if (nextLevel > level) {
334
+ const newUl = document.createElement('ul');
335
+ li.appendChild(newUl);
336
+ stack.push({ level, ul: newUl });
337
+ }
338
+ }
339
+ }
340
+
341
+ const links = tocRoot.querySelectorAll('a');
342
+ const onScroll = () => {
343
+ const fromTop = window.scrollY + offset + 1;
344
+ let current = headings[0];
345
+
346
+ for (const h of headings) {
347
+ if (h.offsetTop <= fromTop) current = h;
348
+ }
349
+
350
+ for (const l of links) {
351
+ l.classList.toggle('active', l.getAttribute('href') === `#${current.id}`);
352
+ }
353
+ };
354
+
355
+ window.addEventListener('scroll', onScroll, { passive: true });
356
+ onScroll();
357
+ };
358
+
359
+ for (const tocEl of document.querySelectorAll('.toc')) {
360
+ // Obtém os textos dos botões do dataset (agora dinâmicos)
361
+ const btnShowText = tocEl.dataset.btnShow || 'Show';
362
+ const btnHiddenText = tocEl.dataset.btnHidden || 'Hide';
363
+
364
+ buildTOC(tocEl);
365
+
366
+ const toggle = tocEl.querySelector('.toc-toggle');
367
+ const wrapper = tocEl.querySelector('.toc-list-wrapper');
368
+
369
+ wrapper.style.display = 'none';
370
+ toggle.setAttribute('aria-expanded', 'false');
371
+ toggle.textContent = btnShowText;
372
+
373
+ toggle.addEventListener('click', () => {
374
+ const expanded = toggle.getAttribute('aria-expanded') === 'true';
375
+ wrapper.style.display = expanded ? 'none' : 'block';
376
+ toggle.setAttribute('aria-expanded', (!expanded).toString());
377
+ // Define o texto dinamicamente
378
+ toggle.textContent = expanded ? btnShowText : btnHiddenText;
379
+ });
380
+
381
+ const tocTop = tocEl.offsetTop;
382
+
383
+ const handleScrollFix = () => {
384
+ if (window.innerWidth <= minLayoutWidth) {
385
+ tocEl.classList.remove('fixed');
386
+ tocEl.style.position = '';
387
+ tocEl.style.top = '';
388
+ tocEl.style.zIndex = '';
389
+ tocEl.style.width = '';
390
+ return;
391
+ }
392
+
393
+ const scrollTop = window.scrollY || document.documentElement.scrollTop;
394
+
395
+ if (scrollTop >= tocTop) {
396
+ tocEl.classList.add('fixed');
397
+ tocEl.style.position = 'fixed';
398
+ tocEl.style.top = '0';
399
+ tocEl.style.zIndex = '9999';
400
+ } else {
401
+ tocEl.classList.remove('fixed');
402
+ tocEl.style.position = '';
403
+ tocEl.style.top = '';
404
+ tocEl.style.width = '';
405
+ }
406
+ };
407
+
408
+ // fechar TOC ao pressionar 'Esc'
409
+ document.addEventListener('keydown', (e) => {
410
+ if (e.key === 'Escape') {
411
+ wrapper.style.display = 'none';
412
+ toggle.setAttribute('aria-expanded', 'false');
413
+ toggle.textContent = btnShowText;
414
+ }
415
+ });
416
+
417
+ window.addEventListener('scroll', handleScrollFix, { passive: true });
418
+ window.addEventListener('resize', handleScrollFix);
419
+ handleScrollFix();
420
+ }
421
+ }
422
+
423
+ });
@@ -0,0 +1 @@
1
+ document.addEventListener("DOMContentLoaded", () => {});
@@ -0,0 +1,13 @@
1
+ document.addEventListener("DOMContentLoaded", () => {
2
+
3
+ /* resume: button print
4
+ # -------------------------------------------------------------------------------------------------
5
+ */
6
+ const btnPrint = document.getElementById("btn-print");
7
+
8
+ if (btnPrint) {
9
+ btnPrint.addEventListener("click", () => {
10
+ window.print();
11
+ });
12
+ }
13
+ });
@@ -0,0 +1 @@
1
+ document.addEventListener("DOMContentLoaded", () => {});
@@ -0,0 +1,4 @@
1
+ (function() {
2
+ const savedTheme = localStorage.getItem('theme') || 'light';
3
+ document.documentElement.setAttribute('data-theme', savedTheme);
4
+ })();
@@ -0,0 +1,24 @@
1
+ ---
2
+ ---
3
+
4
+ {%- include layout/data.liquid -%}
5
+
6
+ is_dnt_active = window.doNotTrack is "1" or navigator.doNotTrack is "1" or navigator.doNotTrack is "yes" or navigator.msDoNotTrack is "1"
7
+
8
+ unless is_dnt_active
9
+ gaLoader = (i,s,o,g,r,a,m) ->
10
+ i[r] = i[r] or ->
11
+ (i[r].q = i[r].q or []).push arguments
12
+ i['GoogleAnalyticsObject'] = r
13
+ i[r].l = 1 * new Date()
14
+ a = s.createElement o
15
+ m = s.getElementsByTagName(o)[0]
16
+ a.async = 1
17
+ a.src = g
18
+ m.parentNode.insertBefore a, m
19
+
20
+ gaLoader window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga'
21
+
22
+ # envio dos comandos de rastreamento
23
+ ga 'create', '{{ head_.google.analytics.id }}', 'auto'
24
+ ga 'send', 'pageview'