enzostvs HF Staff commited on
Commit
e5d91d1
·
verified ·
1 Parent(s): 318e6f4

In the block code in the header, make it better, like add a typing animation for the code, like we are typing it live. Once its done, wait 5s, erase everything and restart animation

Browse files
Files changed (3) hide show
  1. index.html +5 -10
  2. script.js +204 -2
  3. style.css +58 -1
index.html CHANGED
@@ -186,15 +186,10 @@
186
  <div class="text-xs text-zinc-400">Design system + SSR with Next.js</div>
187
  </div>
188
  </div>
189
- <pre class="mt-6 rounded-xl bg-black/50 text-zinc-300 p-4 overflow-x-auto text-sm leading-relaxed">
190
- <span class="text-emerald-400">const</span> theme <span class="text-pink-400">=</span> <span class="text-amber-300">dark</span>
191
- <span class="text-emerald-400">function</span> <span class="text-sky-400">Button</span>({ children, ...props }) {
192
- <span class="text-emerald-400">return</span> (
193
- &lt;button className=<span class="text-amber-300">"btn-primary"</span> {...props}&gt;
194
- {children}
195
- &lt;/button&gt;
196
- )
197
- }</pre>
198
  <div class="mt-6 grid grid-cols-3 gap-3 text-center">
199
  <div class="rounded-xl bg-white/5 border border-white/10 p-3">
200
  <div class="text-2xl font-extrabold text-zinc-100">5+ yrs</div>
@@ -210,7 +205,7 @@
210
  </div>
211
  </div>
212
  </div>
213
- <!-- Floating card -->
214
  <div class="absolute -right-6 -bottom-6 hidden lg:block">
215
  <div class="glass-card rounded-2xl border border-white/10 bg-[color:rgb(var(--bg)_/_0.75)] p-4 shadow-soft">
216
  <div class="flex items-center gap-3">
 
186
  <div class="text-xs text-zinc-400">Design system + SSR with Next.js</div>
187
  </div>
188
  </div>
189
+ <div class="mt-6 rounded-xl bg-black/50 text-zinc-300 p-4 overflow-x-auto text-sm leading-relaxed font-mono relative min-h-[140px]">
190
+ <div id="typing-code"></div>
191
+ <div class="typing-cursor"></div>
192
+ </div>
 
 
 
 
 
193
  <div class="mt-6 grid grid-cols-3 gap-3 text-center">
194
  <div class="rounded-xl bg-white/5 border border-white/10 p-3">
195
  <div class="text-2xl font-extrabold text-zinc-100">5+ yrs</div>
 
205
  </div>
206
  </div>
207
  </div>
208
+ <!-- Floating card -->
209
  <div class="absolute -right-6 -bottom-6 hidden lg:block">
210
  <div class="glass-card rounded-2xl border border-white/10 bg-[color:rgb(var(--bg)_/_0.75)] p-4 shadow-soft">
211
  <div class="flex items-center gap-3">
script.js CHANGED
@@ -267,7 +267,6 @@ if (grid) {
267
  grid.appendChild(el);
268
  });
269
  }
270
-
271
  // Year
272
  document.getElementById('year').textContent = new Date().getFullYear();
273
 
@@ -281,4 +280,207 @@ document.getElementById('download-cv')?.addEventListener('click', (e) => {
281
  a.download = 'CoolDev-Resume.txt';
282
  a.click();
283
  URL.revokeObjectURL(url);
284
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  grid.appendChild(el);
268
  });
269
  }
 
270
  // Year
271
  document.getElementById('year').textContent = new Date().getFullYear();
272
 
 
280
  a.download = 'CoolDev-Resume.txt';
281
  a.click();
282
  URL.revokeObjectURL(url);
283
+ });
284
+
285
+ // Typing animation for code
286
+ function initTypingAnimation() {
287
+ const codeContainer = document.getElementById('typing-code');
288
+ if (!codeContainer) return;
289
+
290
+ const codeLines = [
291
+ {
292
+ text: 'const theme = "dark"',
293
+ chars: [
294
+ { type: 'keyword', text: 'const' },
295
+ { type: 'text', text: ' ' },
296
+ { type: 'text', text: 'theme ' },
297
+ { type: 'operator', text: '=' },
298
+ { type: 'text', text: ' ' },
299
+ { type: 'string', text: '"dark"' }
300
+ ]
301
+ },
302
+ {
303
+ text: 'function Button({ children, ...props }) {',
304
+ chars: [
305
+ { type: 'keyword', text: 'function' },
306
+ { type: 'text', text: ' ' },
307
+ { type: 'function', text: 'Button' },
308
+ { type: 'punctuation', text: '(' },
309
+ { type: 'punctuation', text: '{' },
310
+ { type: 'text', text: ' children, ' },
311
+ { type: 'operator', text: '...' },
312
+ { type: 'text', text: 'props ' },
313
+ { type: 'punctuation', text: '}' },
314
+ { type: 'punctuation', text: ')' },
315
+ { type: 'text', text: ' ' },
316
+ { type: 'punctuation', text: '{' }
317
+ ]
318
+ },
319
+ {
320
+ text: ' return (',
321
+ chars: [
322
+ { type: 'text', text: ' ' },
323
+ { type: 'keyword', text: 'return' },
324
+ { type: 'text', text: ' (' }
325
+ ]
326
+ },
327
+ {
328
+ text: ' <button className="btn-primary" {...props}>',
329
+ chars: [
330
+ { type: 'text', text: ' ' },
331
+ { type: 'tag', text: '<' },
332
+ { type: 'tag', text: 'button' },
333
+ { type: 'text', text: ' ' },
334
+ { type: 'attr', text: 'className' },
335
+ { type: 'operator', text: '=' },
336
+ { type: 'string', text: '"btn-primary"' },
337
+ { type: 'text', text: ' ' },
338
+ { type: 'operator', text: '{' },
339
+ { type: 'operator', text: '.' },
340
+ { type: 'operator', text: '.' },
341
+ { type: 'operator', text: '}' },
342
+ { type: 'tag', text: '>' }
343
+ ]
344
+ },
345
+ {
346
+ text: ' {children}',
347
+ chars: [
348
+ { type: 'text', text: ' ' },
349
+ { type: 'punctuation', text: '{' },
350
+ { type: 'text', text: 'children' },
351
+ { type: 'punctuation', text: '}' }
352
+ ]
353
+ },
354
+ {
355
+ text: ' </button>',
356
+ chars: [
357
+ { type: 'text', text: ' ' },
358
+ { type: 'tag', text: '<' },
359
+ { type: 'operator', text: '/' },
360
+ { type: 'tag', text: 'button' },
361
+ { type: 'tag', text: '>' }
362
+ ]
363
+ },
364
+ {
365
+ text: ' )',
366
+ chars: [
367
+ { type: 'text', text: ' ' },
368
+ { type: 'punctuation', text: ')' }
369
+ ]
370
+ },
371
+ {
372
+ text: '}',
373
+ chars: [
374
+ { type: 'punctuation', text: '}' }
375
+ ]
376
+ }
377
+ ];
378
+
379
+ let currentLine = 0;
380
+ let currentChar = 0;
381
+ let isTyping = true;
382
+ let timeoutId;
383
+
384
+ const cursor = document.querySelector('.typing-cursor');
385
+
386
+ function typeCharacter() {
387
+ if (currentLine >= codeLines.length) {
388
+ // Finished typing all lines
389
+ isTyping = false;
390
+
391
+ // Wait 5 seconds, then restart
392
+ setTimeout(() => {
393
+ restartTyping();
394
+ }, 5000);
395
+
396
+ return;
397
+ }
398
+
399
+ const line = codeLines[currentLine];
400
+ const char = line.chars[currentChar];
401
+
402
+ // Create and append the character element
403
+ const charElement = document.createElement('span');
404
+ charElement.className = char.type !== 'text' ? char.type : '';
405
+ charElement.textContent = char.text;
406
+ codeContainer.appendChild(charElement);
407
+
408
+ currentChar++;
409
+
410
+ // Calculate typing speed (varies by character type)
411
+ let delay = 50; // default delay
412
+
413
+ if (char.type === 'punctuation') delay = 100;
414
+ else if (char.type === 'operator') delay = 80;
415
+ else if (char.type === 'keyword' || char.type === 'function') delay = 120;
416
+ else if (char.type === 'string') delay = 150;
417
+ else if (char.text === ' ') delay = 30;
418
+ else if (char.text === '\n') delay = 500;
419
+
420
+ // Add some random variation
421
+ delay += Math.random() * 50;
422
+
423
+ timeoutId = setTimeout(typeCharacter, delay);
424
+
425
+ // If we finished the current line, move to next line
426
+ if (currentChar >= line.chars.length) {
427
+ // Add line break
428
+ const lineBreak = document.createElement('br');
429
+ codeContainer.appendChild(lineBreak);
430
+ currentLine++;
431
+ currentChar = 0;
432
+ }
433
+ }
434
+
435
+ function eraseCharacters() {
436
+ const lastChild = codeContainer.lastElementChild;
437
+ if (!lastChild || (lastChild.tagName === 'BR' && !lastChild.previousElementSibling)) {
438
+ // If only line breaks left, restart typing
439
+ if (!lastChild || !lastChild.previousElementSibling) {
440
+ restartTyping();
441
+ return;
442
+ }
443
+ }
444
+
445
+ if (lastChild) {
446
+ codeContainer.removeChild(lastChild);
447
+ setTimeout(eraseCharacters, 20); // Erase speed
448
+ } else {
449
+ setTimeout(eraseCharacters, 50);
450
+ }
451
+ }
452
+
453
+ function restartTyping() {
454
+ // Clear existing content
455
+ codeContainer.innerHTML = '';
456
+
457
+ // Reset counters
458
+ currentLine = 0;
459
+ currentChar = 0;
460
+ isTyping = true;
461
+
462
+ // Clear any existing timeout
463
+ if (timeoutId) {
464
+ clearTimeout(timeoutId);
465
+ }
466
+
467
+ // Start typing again
468
+ setTimeout(typeCharacter, 1000); // 1 second delay before restart
469
+ }
470
+
471
+ // Start the typing animation
472
+ setTimeout(typeCharacter, 2000); // 2 second initial delay
473
+
474
+ // Hide cursor when not typing (during wait periods)
475
+ setInterval(() => {
476
+ if (cursor && isTyping) {
477
+ cursor.classList.toggle('hide');
478
+ }
479
+ }, 500);
480
+ }
481
+
482
+ // Initialize typing animation when page loads
483
+ document.addEventListener('DOMContentLoaded', initTypingAnimation);
484
+
485
+ // Re-initialize when feather icons are replaced (since it might interfere)
486
+ setTimeout(initTypingAnimation, 100);
style.css CHANGED
@@ -165,10 +165,67 @@ input, textarea {
165
  z-index: 60;
166
  transition: width 0.1s linear;
167
  }
168
-
169
  /* Reduce motion for users who prefer it */
170
  @media (prefers-reduced-motion: reduce) {
171
  .animate-blob, .animate-float {
172
  animation: none !important;
173
  }
174
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  z-index: 60;
166
  transition: width 0.1s linear;
167
  }
 
168
  /* Reduce motion for users who prefer it */
169
  @media (prefers-reduced-motion: reduce) {
170
  .animate-blob, .animate-float {
171
  animation: none !important;
172
  }
173
  }
174
+
175
+ /* Typing animation styles */
176
+ .typing-cursor {
177
+ display: inline-block;
178
+ width: 2px;
179
+ height: 1.2em;
180
+ background: #a78bfa;
181
+ margin-left: 2px;
182
+ animation: blink 1s infinite;
183
+ vertical-align: bottom;
184
+ }
185
+
186
+ .typing-cursor.hide {
187
+ opacity: 0;
188
+ }
189
+
190
+ @keyframes blink {
191
+ 0%, 50% { opacity: 1; }
192
+ 51%, 100% { opacity: 0; }
193
+ }
194
+
195
+ /* Syntax highlighting for typing animation */
196
+ .typing-text {
197
+ white-space: pre-wrap;
198
+ word-break: break-word;
199
+ }
200
+
201
+ .keyword {
202
+ color: #10b981; /* emerald-400 */
203
+ }
204
+
205
+ .string {
206
+ color: #f59e0b; /* amber-500 */
207
+ }
208
+
209
+ .operator {
210
+ color: #ec4899; /* pink-400 */
211
+ }
212
+
213
+ .function {
214
+ color: #38bdf8; /* sky-400 */
215
+ }
216
+
217
+ .tag {
218
+ color: #f87171; /* red-400 */
219
+ }
220
+
221
+ .attr {
222
+ color: #f59e0b; /* amber-500 */
223
+ }
224
+
225
+ .comment {
226
+ color: #6b7280; /* gray-500 */
227
+ }
228
+
229
+ .punctuation {
230
+ color: #9ca3af; /* gray-400 */
231
+ }