Skip to content

Commit d101ca0

Browse files
committed
feat: command palette, digital rain
1 parent d7025c3 commit d101ca0

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed

src/components/CommandPalette.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useToast } from '../hooks/useToast';
77
import { SIDEBAR_KEYS, remove as removeLocalStorageItem } from '../utils/LocalStorageManager';
88
import { version } from '../version'; // Import the version
99
import LiveClock from './LiveClock'; // Import LiveClock
10+
import DigitalRain from './DigitalRain'; // Import DigitalRain
1011
import { filterItems } from '../utils/search'; // Import the search utility
1112

1213
const CommandPalette = ({ isOpen, setIsOpen, openGenericModal }) => {
@@ -126,6 +127,10 @@ const CommandPalette = ({ isOpen, setIsOpen, openGenericModal }) => {
126127
openGenericModal('Current Time', <LiveClock />);
127128
break;
128129
}
130+
case 'digitalRain': {
131+
openGenericModal('Digital Rain', <DigitalRain />);
132+
break;
133+
}
129134
default:
130135
break;
131136
}

src/components/DigitalRain.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import React, { useRef, useEffect } from 'react';
2+
3+
const DigitalRain = () => {
4+
const canvasRef = useRef(null);
5+
6+
useEffect(() => {
7+
const canvas = canvasRef.current;
8+
const ctx = canvas.getContext('2d');
9+
10+
// Set canvas to full width and height of its container
11+
canvas.width = canvas.offsetWidth;
12+
canvas.height = canvas.offsetHeight;
13+
14+
const katakana = 'アァカサタナハマヤャラワガザダバパイィキシチニヒミリヰギジヂビピウゥクスツヌフムユュルグズブヅプエェケセテネヘメレヱゲゼデベペオォコソトノホモヨョロヲゴゾドボポヴッン';
15+
const latin = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
16+
const nums = '0123456789';
17+
const alphabet = katakana + latin + nums;
18+
19+
const fontSize = 16;
20+
const columns = canvas.width / fontSize;
21+
const rainDrops = Array.from({ length: columns }).map(() => 1);
22+
23+
let animationFrameId;
24+
let frameCount = 0;
25+
const slowdownFactor = 3; // Higher number = slower rain
26+
27+
const draw = () => {
28+
ctx.fillStyle = 'rgba(21, 21, 21, 0.05)'; // Semi-transparent black for fading effect
29+
ctx.fillRect(0, 0, canvas.width, canvas.height);
30+
31+
ctx.fillStyle = '#0F0'; // Green text
32+
ctx.font = `${fontSize}px monospace`;
33+
34+
frameCount++;
35+
36+
for (let i = 0; i < rainDrops.length; i++) {
37+
const text = alphabet.charAt(Math.floor(Math.random() * alphabet.length));
38+
ctx.fillText(text, i * fontSize, rainDrops[i] * fontSize);
39+
40+
if (frameCount % slowdownFactor === 0) {
41+
if (rainDrops[i] * fontSize > canvas.height && Math.random() > 0.975) {
42+
rainDrops[i] = 0;
43+
}
44+
rainDrops[i]++;
45+
}
46+
}
47+
animationFrameId = requestAnimationFrame(draw);
48+
};
49+
draw();
50+
return () => {
51+
cancelAnimationFrame(animationFrameId);
52+
};
53+
}, []);
54+
55+
// Style for the canvas to fill the modal body
56+
const canvasStyle = {
57+
display: 'block',
58+
width: '100%',
59+
height: '60vh', // Make it tall inside the modal
60+
};
61+
62+
return (
63+
<canvas ref={canvasRef} style={canvasStyle}></canvas>
64+
);
65+
};
66+
67+
export default DigitalRain;

src/hooks/useSearchableData.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ const useSearchableData = () => {
7777
{ title: 'Go to Latest Log', type: 'command', commandId: 'latestLog' },
7878
{ title: 'Her Daim', type: 'command', commandId: 'herDaim' },
7979
{ title: 'Show Current Time', type: 'command', commandId: 'showTime' },
80+
{ title: 'Start Digital Rain', type: 'command', commandId: 'digitalRain' },
8081
];
8182

8283
setItems([...staticRoutes, ...customCommands, ...allPosts, ...allProjects, ...allLogs, ...allApps]);

0 commit comments

Comments
 (0)