tangled
alpha
login
or
join now
safwanyp.com
/
website
0
fork
atom
Code for my personal website
0
fork
atom
overview
issues
pulls
pipelines
feat: just some fun stuff lol
Safwan Parker
1 year ago
8fae6446
ad8c1699
+115
4 changed files
expand all
collapse all
unified
split
package.json
pnpm-lock.yaml
src
components
Fun
Confetti.astro
layouts
Layout.astro
+2
package.json
···
22
22
"@fontsource/lora": "^5.1.0",
23
23
"@tailwindcss/typography": "^0.5.15",
24
24
"astro": "^4.15.6",
25
25
+
"canvas-confetti": "^1.9.3",
25
26
"clsx": "^2.1.1",
26
27
"sharp": "^0.33.5",
27
28
"tailwind-merge": "^2.5.2",
···
29
30
"typescript": "^5.6.2"
30
31
},
31
32
"devDependencies": {
33
33
+
"@types/canvas-confetti": "^1.6.4",
32
34
"@typescript-eslint/eslint-plugin": "^8.5.0",
33
35
"@typescript-eslint/parser": "^8.5.0",
34
36
"eslint": "^9.10.0",
+14
pnpm-lock.yaml
···
32
32
astro:
33
33
specifier: ^4.15.6
34
34
version: 4.15.6(typescript@5.6.2)
35
35
+
canvas-confetti:
36
36
+
specifier: ^1.9.3
37
37
+
version: 1.9.3
35
38
clsx:
36
39
specifier: ^2.1.1
37
40
version: 2.1.1
···
49
52
version: 5.6.2
50
53
51
54
devDependencies:
55
55
+
'@types/canvas-confetti':
56
56
+
specifier: ^1.6.4
57
57
+
version: 1.6.4
52
58
'@typescript-eslint/eslint-plugin':
53
59
specifier: ^8.5.0
54
60
version: 8.5.0(@typescript-eslint/parser@8.5.0)(eslint@9.10.0)(typescript@5.6.2)
···
1302
1308
'@babel/types': 7.25.6
1303
1309
dev: false
1304
1310
1311
1311
+
/@types/canvas-confetti@1.6.4:
1312
1312
+
resolution: {integrity: sha512-fNyZ/Fdw/Y92X0vv7B+BD6ysHL4xVU5dJcgzgxLdGbn8O3PezZNIJpml44lKM0nsGur+o/6+NZbZeNTt00U1uA==}
1313
1313
+
dev: true
1314
1314
+
1305
1315
/@types/cookie@0.6.0:
1306
1316
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
1307
1317
dev: false
···
1973
1983
1974
1984
/caniuse-lite@1.0.30001660:
1975
1985
resolution: {integrity: sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==}
1986
1986
+
dev: false
1987
1987
+
1988
1988
+
/canvas-confetti@1.9.3:
1989
1989
+
resolution: {integrity: sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==}
1976
1990
dev: false
1977
1991
1978
1992
/ccount@2.0.1:
+97
src/components/Fun/Confetti.astro
···
1
1
+
---
2
2
+
3
3
+
---
4
4
+
5
5
+
<script>
6
6
+
import confetti from 'canvas-confetti';
7
7
+
8
8
+
let typedKeys = '';
9
9
+
const confettiWord = 'confetti';
10
10
+
const trixaWord = 'trixa';
11
11
+
12
12
+
// Create a div for the Trixa message
13
13
+
const trixaMessageDiv = document.createElement('div');
14
14
+
trixaMessageDiv.style.position = 'fixed';
15
15
+
trixaMessageDiv.style.top = '50%';
16
16
+
trixaMessageDiv.style.left = '50%';
17
17
+
trixaMessageDiv.style.transform = 'translate(-50%, -50%)';
18
18
+
trixaMessageDiv.style.fontSize = '4rem';
19
19
+
trixaMessageDiv.style.fontWeight = 'bold';
20
20
+
trixaMessageDiv.style.color = '#FF1493';
21
21
+
trixaMessageDiv.style.textAlign = 'center';
22
22
+
trixaMessageDiv.style.zIndex = '9999';
23
23
+
trixaMessageDiv.style.display = 'none';
24
24
+
document.body.appendChild(trixaMessageDiv);
25
25
+
26
26
+
document.addEventListener('keydown', (event) => {
27
27
+
if (
28
28
+
(event.target as Element)?.tagName.toLowerCase() === 'input' ||
29
29
+
(event.target as Element)?.tagName.toLowerCase() === 'textarea'
30
30
+
) {
31
31
+
return;
32
32
+
}
33
33
+
34
34
+
typedKeys += event.key.toLowerCase();
35
35
+
36
36
+
// Keep only the last 8 characters (length of the longer word 'confetti')
37
37
+
if (typedKeys.length > confettiWord.length) {
38
38
+
typedKeys = typedKeys.slice(-confettiWord.length);
39
39
+
}
40
40
+
41
41
+
if (typedKeys.endsWith(confettiWord)) {
42
42
+
confetti({
43
43
+
particleCount: 100,
44
44
+
spread: 70,
45
45
+
origin: { y: 0.6 }
46
46
+
});
47
47
+
typedKeys = '';
48
48
+
} else if (typedKeys.endsWith(trixaWord)) {
49
49
+
showTrixaMessage();
50
50
+
confetti({
51
51
+
particleCount: 100,
52
52
+
spread: 70,
53
53
+
origin: { y: 0.6 }
54
54
+
});
55
55
+
typedKeys = '';
56
56
+
}
57
57
+
});
58
58
+
59
59
+
function showTrixaMessage() {
60
60
+
trixaMessageDiv.textContent = 'TRIXA IS THE BEST!';
61
61
+
trixaMessageDiv.style.display = 'block';
62
62
+
trixaMessageDiv.style.backgroundColor = 'rgba(255, 20, 147, 0.1)';
63
63
+
64
64
+
// Animate the message
65
65
+
trixaMessageDiv.animate(
66
66
+
[
67
67
+
{ transform: 'translate(-50%, -50%) scale(0)', opacity: 0 },
68
68
+
{
69
69
+
transform: 'translate(-50%, -50%) scale(1.2)',
70
70
+
opacity: 1,
71
71
+
offset: 0.8
72
72
+
},
73
73
+
{ transform: 'translate(-50%, -50%) scale(1)', opacity: 1 }
74
74
+
],
75
75
+
{
76
76
+
duration: 500,
77
77
+
easing: 'ease-out'
78
78
+
}
79
79
+
);
80
80
+
81
81
+
// Hide the message after 3 seconds with a smooth exit animation
82
82
+
setTimeout(() => {
83
83
+
trixaMessageDiv.animate(
84
84
+
[
85
85
+
{ transform: 'translate(-50%, -50%) scale(1)', opacity: 1 },
86
86
+
{ transform: 'translate(-50%, -50%) scale(0)', opacity: 0 }
87
87
+
],
88
88
+
{
89
89
+
duration: 500,
90
90
+
easing: 'ease-in'
91
91
+
}
92
92
+
).onfinish = () => {
93
93
+
trixaMessageDiv.style.display = 'none';
94
94
+
};
95
95
+
}, 2000);
96
96
+
}
97
97
+
</script>
+2
src/layouts/Layout.astro
···
1
1
---
2
2
+
import Confetti from '@/components/Fun/Confetti.astro';
2
3
import Head from '@/components/Head.astro';
3
4
import Header from '@/components/Header.astro';
4
5
import Footer from '@/components/Footer.astro';
···
22
23
<main>
23
24
<slot />
24
25
</main>
26
26
+
<Confetti />
25
27
<Footer />
26
28
</body>
27
29
</html>