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.
- checksums.yaml +4 -4
- data/LICENSE.txt +20 -21
- data/README.md +13 -112
- data/_data/options.yml +270 -0
- data/_data/resume.yml +8 -9
- data/_includes/alert +3 -1
- data/_includes/chart +13 -32
- data/_includes/details +1 -57
- data/_includes/image +12 -4
- data/_includes/layout/blog_search.html +7 -5
- data/_includes/layout/data.liquid +21 -3
- data/_includes/layout/disqus.html +12 -26
- data/_includes/layout/footer.html +34 -16
- data/_includes/layout/giscus.html +27 -19
- data/_includes/layout/head.html +58 -19
- data/_includes/layout/header.html +127 -101
- data/_includes/layout/maintenance.html +8 -12
- data/_includes/layout/paginator.html +6 -4
- data/_includes/socials +7 -5
- data/_includes/tabs +1 -94
- data/_includes/toc +12 -152
- data/_includes/video +4 -1
- data/_layouts/blog.html +8 -7
- data/_layouts/contact.html +90 -196
- data/_layouts/default.html +42 -339
- data/_layouts/error.html +6 -4
- data/_layouts/home.html +45 -36
- data/_layouts/licenses.html +10 -0
- data/_layouts/page.html +4 -6
- data/_layouts/pixel.html +48 -0
- data/_layouts/pixels.html +71 -0
- data/_layouts/post.html +28 -31
- data/_layouts/resume.html +43 -36
- data/_layouts/tag.html +14 -3
- data/_layouts/tag_posts.html +3 -3
- data/_sass/base/_index.scss +39 -3
- data/_sass/components/_badges.scss +10 -0
- data/_sass/components/_markdown.scss +20 -17
- data/_sass/includes/_footer.scss +18 -8
- data/_sass/includes/_header.scss +24 -19
- data/_sass/includes/_highlight.scss +20 -7
- data/_sass/includes/_maintenance.scss +2 -3
- data/_sass/includes/_terminal.scss +35 -12
- data/_sass/layouts/_blog.scss +13 -9
- data/_sass/layouts/_contact.scss +6 -5
- data/_sass/layouts/_default.scss +5 -5
- data/_sass/layouts/_index.scss +3 -0
- data/_sass/layouts/_licenses.scss +7 -0
- data/_sass/layouts/_page.scss +1 -0
- data/_sass/layouts/_pixel.scss +61 -0
- data/_sass/layouts/_pixels.scss +86 -0
- data/_sass/layouts/_post.scss +4 -11
- data/_sass/layouts/_resume.scss +17 -7
- data/_sass/layouts/_tag-posts.scss +1 -2
- data/_sass/layouts/_tag.scss +12 -1
- data/_sass/main.scss +16 -1
- data/_sass/theme/_dark.scss +15 -5
- data/_sass/theme/_light.scss +9 -2
- data/assets/images/blog/.keep +0 -0
- data/assets/images/pixels/luffy.jpg +0 -0
- data/assets/js/blog.coffee +102 -0
- data/assets/js/contact.coffee +105 -0
- data/assets/js/default.coffee +172 -0
- data/assets/js/discus.coffee +30 -0
- data/assets/js/fallback/README.md +3 -0
- data/assets/js/fallback/blog.js +113 -0
- data/assets/js/fallback/contact.js +116 -0
- data/assets/js/{default.js → fallback/default.js} +50 -0
- data/assets/js/fallback/discus.js +32 -0
- data/{_includes/layout/google_analytics.html → assets/js/fallback/google_analytics.js} +7 -3
- data/assets/js/fallback/home.js +275 -0
- data/assets/js/fallback/no_inframe.js +4 -0
- data/assets/js/fallback/page.js +423 -0
- data/assets/js/fallback/pixels.js +1 -0
- data/assets/js/fallback/resume.js +13 -0
- data/assets/js/fallback/tags.js +1 -0
- data/assets/js/fallback/theme_load.js +4 -0
- data/assets/js/google_analytics.coffee +24 -0
- data/assets/js/home.coffee +250 -0
- data/assets/js/no_inframe.coffee +9 -0
- data/assets/js/page.coffee +379 -0
- data/assets/js/pixels.coffee +2 -0
- data/assets/js/resume.coffee +9 -0
- data/assets/js/tags.coffee +2 -0
- data/assets/js/theme_load.coffee +6 -0
- data/assets/json/blog_search.json +2 -2
- data/lib/rawfeed/author.rb +59 -0
- data/lib/rawfeed/csp_filters.rb +19 -0
- data/lib/rawfeed/draft.rb +1 -1
- data/lib/rawfeed/layout.rb +7 -0
- data/lib/rawfeed/page.rb +4 -2
- data/lib/rawfeed/pixel.rb +32 -0
- data/lib/rawfeed/post.rb +2 -2
- data/lib/rawfeed/resume.rb +1 -0
- data/lib/rawfeed/typescript_liquid.rb +172 -0
- data/lib/rawfeed/utils.rb +1 -0
- data/lib/rawfeed/version.rb +1 -1
- data/lib/rawfeed/with_class.rb +20 -0
- data/lib/rawfeed.rb +5 -0
- metadata +46 -12
- data/assets/js/avatar.js +0 -50
- data/assets/js/terminal.js +0 -18
- 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
|
-
|
|
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', '{{
|
|
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
|
+
});
|