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
@@ -1,9 +1,59 @@
1
+ ---
2
+ ---
3
+
1
4
  document.addEventListener("DOMContentLoaded", () => {
2
5
  /* lock menu context (click right mouse)
3
6
  --------------------------------------------------------------------------------------------------
4
7
  */
5
8
  document.addEventListener('contextmenu', e => e.preventDefault());
6
9
 
10
+ /* avatar
11
+ -------------------------------------------------------------------------------------------------
12
+ */
13
+ const modalEl = document.getElementById('avatarModal');
14
+ if (modalEl) {
15
+ const flipperAvatars = document.querySelectorAll('.avatar-flipper__open-true');
16
+ const modalAvatar = document.getElementById('modalAvatar');
17
+ const header = document.querySelector('.header');
18
+ const bsModal = new bootstrap.Modal(modalEl);
19
+
20
+ flipperAvatars.forEach((flipper) => {
21
+ flipper.addEventListener("click", () => {
22
+ const card = flipper.querySelector('.avatar-card');
23
+ const backImage = flipper.querySelector('.avatar-back img');
24
+ const backImageSrc = backImage.src;
25
+
26
+ card.classList.add("flip-avatar");
27
+
28
+ card.addEventListener(
29
+ "animationend",
30
+ () => {
31
+ card.classList.remove("flip-avatar");
32
+
33
+ modalAvatar.src = backImageSrc;
34
+
35
+ bsModal.show();
36
+ },
37
+ { once: true }
38
+ );
39
+ });
40
+ });
41
+
42
+ modalEl.addEventListener("shown.bs.modal", () => {
43
+ modalAvatar.classList.remove("modal-avatar");
44
+ void modalAvatar.offsetWidth;
45
+ modalAvatar.classList.add("modal-avatar");
46
+ header.classList.remove("modal-active");
47
+
48
+ flipperAvatars.forEach((flipper) => flipper.classList.add("hidden"));
49
+ });
50
+
51
+ modalEl.addEventListener("hidden.bs.modal", () => {
52
+ flipperAvatars.forEach((flipper) => flipper.classList.remove("hidden"));
53
+ });
54
+ }
55
+
56
+
7
57
  /* Show/disappear top button
8
58
  --------------------------------------------------------------------------------------------------
9
59
  */
@@ -0,0 +1,32 @@
1
+ ---
2
+ ---
3
+
4
+ {%- include layout/data.liquid -%}
5
+
6
+
7
+ document.addEventListener("DOMContentLoaded", () => {
8
+ const discus = document.getElementById('disqus_thread');
9
+
10
+ if (discus) {
11
+ /**
12
+ * RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES
13
+ */
14
+ var disqus_shortname = '{{ blog_.post.comments.disqus.shortname }}';
15
+
16
+ // The unique URL for the discussion, usually the post's permalink.
17
+ var disqus_config = function () {
18
+ this.page.url = '{{ page.url | absolute_url }}'; // Replace with your full permalink
19
+ this.page.identifier = '{{ page.id }}'; // Unique ID for the discussion, use page.id or page.url
20
+ this.page.disable_ads = true; // disabled ads
21
+ this.page.recommendations = false; // disabled recommendations
22
+ };
23
+
24
+ (function() {
25
+ var d = document, s = d.createElement('script');
26
+ s.src = '//' + disqus_shortname + '.disqus.com/embed.js';
27
+ s.setAttribute('data-timestamp', +new Date());
28
+ (d.head || d.body).appendChild(s);
29
+ })();
30
+ }
31
+ });
32
+
@@ -1,11 +1,15 @@
1
- <script>
1
+ ---
2
+ ---
3
+
4
+ {%- include layout/data.liquid -%}
5
+
6
+
2
7
  if(!(window.doNotTrack === "1" || navigator.doNotTrack === "1" || navigator.doNotTrack === "yes" || navigator.msDoNotTrack === "1")) {
3
8
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
4
9
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
5
10
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
6
11
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
7
12
 
8
- ga('create', '{{ site.google.analytics.id }}', 'auto');
13
+ ga('create', '{{ head_.google.analytics.id }}', 'auto');
9
14
  ga('send', 'pageview');
10
15
  }
11
- </script>
@@ -0,0 +1,275 @@
1
+ ---
2
+ ---
3
+
4
+ {%- include layout/data.liquid -%}
5
+
6
+ document.addEventListener("DOMContentLoaded", () => {
7
+
8
+ const terminal = document.getElementById("terminal");
9
+
10
+ if (terminal) {
11
+
12
+ // effects terminal: maximize
13
+ // ----------------------------------------------------------------------------------------------
14
+ const btnMax = terminal.querySelector(".terminal-header__max");
15
+
16
+ let isFullscreen = false;
17
+
18
+ // maximize/restore
19
+ btnMax.addEventListener("click", () => {
20
+ isFullscreen = !isFullscreen;
21
+ terminal.classList.toggle("terminal-fullscreen", isFullscreen);
22
+ });
23
+
24
+ // populate the terminal
25
+ // ----------------------------------------------------------------------------------------------
26
+ const socialsEl = document.getElementById("terminal-screen--socials");
27
+ const screen = document.getElementById("screen");
28
+
29
+ const commands = {
30
+ // Multiple string is the same as using ` in Javascript
31
+ help: `{{ home_.terminal.help.menu }}`,
32
+ about: document.getElementById("home-content").innerHTML,
33
+ socials: socialsEl ? socialsEl.innerHTML : "{{ home_.terminal.no_socials }}"
34
+ };
35
+
36
+ const createInputLine = () => {
37
+ const line = document.createElement("div");
38
+ line.className = "line";
39
+
40
+ const prompt = document.createElement("span");
41
+ prompt.className = "prompt";
42
+ prompt.textContent = "[{{ home_.terminal.user }}@{{ home_.terminal.hostname }} ~]$";
43
+
44
+ // wrapper para conter input, cursor e measure
45
+ const wrapper = document.createElement("span");
46
+ wrapper.className = "input-wrapper";
47
+
48
+ const input = document.createElement("input");
49
+ input.type = "text";
50
+ input.className = "input";
51
+ input.placeholder = `{{ home_.terminal.welcome }}`;
52
+ input.spellcheck = false;
53
+ input.autocomplete = "off";
54
+ input.autocorrect = "off";
55
+ input.autocapitalize = "off";
56
+
57
+ const cursor = document.createElement("span");
58
+ cursor.className = "cursor";
59
+
60
+ const measure = document.createElement("span");
61
+ measure.className = "measure";
62
+
63
+ wrapper.appendChild(input);
64
+ wrapper.appendChild(cursor);
65
+ wrapper.appendChild(measure);
66
+
67
+ line.appendChild(prompt);
68
+ line.appendChild(wrapper);
69
+ screen.appendChild(line);
70
+
71
+ input.focus();
72
+ screen.scrollTop = screen.scrollHeight;
73
+
74
+ // Updates the fake cursor position based on the input"s selectionStart
75
+ const updateCursor = () => {
76
+ const sel = input.selectionStart || 0;
77
+ // measure the text to the position of the caret
78
+ measure.textContent = input.value.slice(0, sel);
79
+ const textWidth = measure.offsetWidth; // largura do texto sem scroll
80
+ const visibleLeft = textWidth - input.scrollLeft;
81
+ cursor.style.left = `${visibleLeft}px`;
82
+
83
+ // ensure the caret is visible (for long texts): adjust input"s scrollLeft
84
+ const paddingRight = 10;
85
+ if (textWidth - input.scrollLeft > input.clientWidth - paddingRight) {
86
+ input.scrollLeft = textWidth - input.clientWidth + paddingRight;
87
+ cursor.style.left = `${textWidth - input.scrollLeft}px`;
88
+ } else if (textWidth < input.scrollLeft) {
89
+ input.scrollLeft = textWidth;
90
+ cursor.style.left = `${textWidth - input.scrollLeft}px`;
91
+ }
92
+ };
93
+
94
+ // show/hide cursor animation as focus changes
95
+ const onFocus = () => {
96
+ cursor.style.opacity = "1";
97
+ updateCursor();
98
+ };
99
+
100
+ const onBlur = () => {
101
+ cursor.style.opacity = "0";
102
+ };
103
+
104
+ input.addEventListener("input", updateCursor);
105
+
106
+ input.addEventListener("keydown", (e) => {
107
+ // Update position on keys that do not trigger input immediately (arrows, delete, etc.)
108
+ setTimeout(updateCursor, 0);
109
+
110
+ if (e.key === "Enter") {
111
+ e.preventDefault();
112
+ const cmd = input.value.trim().toLowerCase();
113
+ if (cmd) {
114
+ // remove input/cursor/measure and place fixed text
115
+ wrapper.removeChild(input);
116
+ wrapper.removeChild(cursor);
117
+ wrapper.removeChild(measure);
118
+ const cmdText = document.createElement("span");
119
+ cmdText.textContent = cmd;
120
+ wrapper.appendChild(cmdText);
121
+ processCommand(cmd);
122
+ } else {
123
+ // if you enter without command, it just creates a new empty line (with prompt)
124
+ wrapper.removeChild(input);
125
+ wrapper.removeChild(cursor);
126
+ wrapper.removeChild(measure);
127
+ const blank = document.createElement("span");
128
+ blank.textContent = "";
129
+ wrapper.appendChild(blank);
130
+ }
131
+
132
+ // New line input
133
+ createInputLine();
134
+
135
+ } else if (e.key === "Escape") {
136
+ e.preventDefault();
137
+ screen.innerHTML = "";
138
+ createInputLine();
139
+ }
140
+ });
141
+
142
+ // arrows, mouse click, mouseup (position caret), etc.
143
+ input.addEventListener("keyup", updateCursor);
144
+ input.addEventListener("click", () => setTimeout(updateCursor, 0));
145
+ input.addEventListener("mouseup", () => setTimeout(updateCursor, 0));
146
+ input.addEventListener("focus", onFocus);
147
+ input.addEventListener("blur", onBlur);
148
+
149
+ updateCursor();
150
+ };
151
+
152
+ // function show date
153
+ function dateShow() {
154
+ const langBrowser = navigator.language || navigator.userLanguage;
155
+
156
+ const options = {
157
+ weekday: 'long',
158
+ year: 'numeric',
159
+ month: 'long',
160
+ day: 'numeric',
161
+ hour: '2-digit',
162
+ minute: '2-digit'
163
+ };
164
+
165
+ let brMessage = "";
166
+
167
+ if (langBrowser === "pt-BR" ) {
168
+ brMessage = " (Horário de Brasília)";
169
+ }
170
+
171
+ try {
172
+ return new Date().toLocaleString(langBrowser, options) + brMessage;
173
+ } catch (e) {
174
+ // Fallback for en-US
175
+ return new Date().toLocaleString('en-US', options) + brMessage;
176
+ }
177
+ }
178
+
179
+ // processes commands
180
+ const processCommand = (cmd) => {
181
+ if (cmd === "help") {
182
+ helpWriteHTML(commands.help, "html");
183
+ } else if (cmd === "date") {
184
+ commandsPrint(dateShow(), "text");
185
+ // else if (cmd.startsWith("echo "))
186
+ // commandsPrint(cmd.split(" ").slice(1).join(" "))
187
+ } else if (cmd === "about") {
188
+ aboutWriteHTML(commands.about);
189
+ } else if (cmd === "socials") {
190
+ socialsWriteHTML(commands.socials);
191
+ } else if (cmd === "clear") {
192
+ screen.innerHTML = "";
193
+ } else if (cmd) {
194
+ commandsPrint(cmd + `{{ home_.terminal.error }}`, "text");
195
+ }
196
+ };
197
+
198
+ const helpWriteHTML = (text, mode = "html") => {
199
+ const wrapper = document.createElement("div");
200
+ wrapper.className = "line-wrapper";
201
+ const helpDescription = document.createElement("span");
202
+ helpDescription.className = "help-description";
203
+ helpDescription.innerHTML = `{{ home_.terminal.help.description | markdownify }}`;
204
+ const helpCommandTitle = document.createElement("span");
205
+ helpCommandTitle.className = "help-commands__title";
206
+ helpCommandTitle.textContent = "{{ home_.terminal.help.commands.title }}";
207
+ const helpCommandDesc = document.createElement("span");
208
+ helpCommandDesc.className = "help-commands__desc";
209
+ helpCommandDesc.textContent = `{{ home_.terminal.help.commands.description }}`;
210
+
211
+ wrapper.appendChild(helpDescription);
212
+ wrapper.appendChild(helpCommandTitle);
213
+ wrapper.appendChild(helpCommandDesc);
214
+
215
+ text.split("\n").forEach((t) => {
216
+ const line = document.createElement("div");
217
+ line.className = "line";
218
+ if (mode === "html") line.innerHTML = t; else line.textContent = t;
219
+ wrapper.appendChild(line);
220
+ });
221
+
222
+ screen.appendChild(wrapper);
223
+ screen.scrollTop = screen.scrollHeight;
224
+ };
225
+
226
+ const socialsWriteHTML = (content, mode = "html") => {
227
+ const wrapper = document.createElement("div");
228
+ wrapper.className = "line-wrapper";
229
+ const socialsCommandDesc = document.createElement("span");
230
+ socialsCommandDesc.className = "socials-command__desc";
231
+ socialsCommandDesc.textContent = `{{ socials_.description.terminal.command.description }}`;
232
+
233
+ screen.appendChild(socialsCommandDesc);
234
+
235
+ if (mode === "html") wrapper.innerHTML = content; else wrapper.textContent = content;
236
+
237
+ screen.appendChild(wrapper);
238
+ screen.scrollTop = screen.scrollHeight;
239
+ };
240
+
241
+ const aboutWriteHTML = (content, mode = "html") => {
242
+ const wrapper = document.createElement("div");
243
+ wrapper.className = "line-wrapper";
244
+ if (mode === "html") wrapper.innerHTML = content; else wrapper.textContent = content;
245
+ screen.appendChild(wrapper);
246
+ screen.scrollTop = screen.scrollHeight;
247
+ };
248
+
249
+ const commandsPrint = (text, mode = "html") => {
250
+ // creates the wrapper to group all the lines
251
+ const wrapper = document.createElement("div");
252
+ wrapper.className = "line-wrapper";
253
+
254
+ text.split("\n").forEach((t) => {
255
+ const line = document.createElement("div");
256
+ line.className = "line";
257
+ if (mode === "html") line.innerHTML = t; else line.textContent = t;
258
+ wrapper.appendChild(line);
259
+ });
260
+
261
+ screen.appendChild(wrapper);
262
+ screen.scrollTop = screen.scrollHeight;
263
+ };
264
+
265
+ // start terminal
266
+ createInputLine();
267
+
268
+ // when clicking on the terminal, it always focuses on the last existing input
269
+ terminal.addEventListener("click", (e) => {
270
+ // avoids focusing when clicking a header button, etc.
271
+ const lastInput = screen.querySelector(".input:last-of-type");
272
+ if (lastInput) lastInput.focus();
273
+ });
274
+ }
275
+ });
@@ -0,0 +1,4 @@
1
+ if (window.top !== window.self) {
2
+ // Prevents the site from being displayed inside an <iframe>
3
+ window.top.location = window.self.location;
4
+ }