Skip to content

New website layout #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cursorrules
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
* Use Remix V2 syntax
* Use TSDoc specification for docstrings
* Use TailwindCSS for styling
* Use DaisyUI for components
4 changes: 2 additions & 2 deletions app/components/atoms/Copyright.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*/
export const Copyright = () => {
return (
<div className="font-gill-sans mb-2 text-center">
<p>&copy; 2024 Gleb Khaykin</p>
<div className="mt-2 text-center text-sm">
<p>&copy; 2025 Gleb Khaykin</p>
</div>
);
};
12 changes: 0 additions & 12 deletions app/components/atoms/LoadingSpinner.tsx

This file was deleted.

113 changes: 113 additions & 0 deletions app/components/molecules/AsciiDonut.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { useEffect, useRef } from "react";

/**
* A component that renders an animated ASCII art donut
* Based on the donut math by Andy Sloane
* @see https://www.a1k0n.net/2011/07/20/donut-math.html
* @returns The ASCII art donut component
*/
export function AsciiDonut() {
const canvasRef = useRef<HTMLPreElement>(null);

useEffect(() => {
const theta_spacing = 0.07;
const phi_spacing = 0.02;

const R1 = 1;
const R2 = 2;
const K2 = 5;

/**
* Render a single frame of the ASCII art donut
* @param A - The angle for the torus rotation
* @param B - The angle for the torus rotation
* @returns The ASCII art string for the frame
*/
function renderFrame(A: number, B: number) {
const screenWidth = 100;
const screenHeight = 100;
const K1 = (screenWidth * K2 * 3) / (8 * (R1 + R2));

const cosA = Math.cos(A),
sinA = Math.sin(A);
const cosB = Math.cos(B),
sinB = Math.sin(B);

const chars = ".,-~:;=!*#$@".split("");
const output: string[] = new Array(screenWidth * screenHeight).fill(" ");
const zbuffer: number[] = new Array(screenWidth * screenHeight).fill(0);

for (let theta = 0; theta < 2 * Math.PI; theta += theta_spacing) {
const costheta = Math.cos(theta),
sintheta = Math.sin(theta);

for (let phi = 0; phi < 2 * Math.PI; phi += phi_spacing) {
const cosphi = Math.cos(phi),
sinphi = Math.sin(phi);

const circlex = R2 + R1 * costheta;
const circley = R1 * sintheta;

const x =
circlex * (cosB * cosphi + sinA * sinB * sinphi) -
circley * cosA * sinB;
const y =
circlex * (sinB * cosphi - sinA * cosB * sinphi) +
circley * cosA * cosB;
const z = K2 + cosA * circlex * sinphi + circley * sinA;
const ooz = 1 / z;

const xp = Math.floor(screenWidth / 2 + K1 * ooz * x);
const yp = Math.floor(screenHeight / 2 - K1 * ooz * y);

const L =
cosphi * costheta * sinB -
cosA * costheta * sinphi -
sinA * sintheta +
cosB * (cosA * sintheta - costheta * sinA * sinphi);

if (L > 0) {
const idx = xp + yp * screenWidth;
if (xp >= 0 && xp < screenWidth && yp >= 0 && yp < screenHeight) {
if (ooz > zbuffer[idx]) {
zbuffer[idx] = ooz;
const luminance_index = Math.floor(L * 8);
output[idx] =
chars[
Math.min(Math.max(luminance_index, 0), chars.length - 1)
];
}
}
}
}
}

return output.reduce((acc, char, i) => {
if (i % screenWidth === 0) return acc + "\n" + char;
return acc + char;
}, "");
}

let A_val = 0;
let B_val = 0;

const animate = () => {
if (canvasRef.current) {
canvasRef.current.textContent = renderFrame(A_val, B_val);
A_val += 0.005;
B_val += 0.003;
requestAnimationFrame(animate);
}
};

animate();
}, []);

return (
<pre
ref={canvasRef}
className="fixed left-[60%] top-1/2 -translate-x-1/2 -translate-y-1/2 font-mono text-[0.5rem] font-extralight leading-[0.5rem]"
style={{ fontFamily: "Courier New" }}
/>
);
}
42 changes: 0 additions & 42 deletions app/components/molecules/MenuItems.tsx

This file was deleted.

45 changes: 0 additions & 45 deletions app/components/molecules/MobileMenuItems.tsx

This file was deleted.

95 changes: 48 additions & 47 deletions app/components/molecules/SocialMedia.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,60 @@
import { AiFillInstagram } from "react-icons/ai";
import { FaGithub, FaLinkedin, FaTelegram } from "react-icons/fa";
import { FaSquareXTwitter } from "react-icons/fa6";
import { ImMail4 } from "react-icons/im";

interface SocialMediaProps {
size?: number;
displayLabels?: boolean;
}

/**
* Social media component
*
* @returns Social media component
*/
export const SocialMedia = () => {
export const SocialMedia = ({ size = 24 }: SocialMediaProps) => {
const links = [
{
href: "https://github.com/khaykingleb",
label: "khaykingleb",
icon: FaGithub,
},
{
href: "https://linkedin.com/in/khaykingleb",
label: "khaykingleb",
icon: FaLinkedin,
},
{
href: "https://twitter.com/khaykingleb",
label: "@khaykingleb",
icon: FaSquareXTwitter,
},
{
href: "https://t.me/khaykingleb_blog",
label: "@khaykingleb_blog",
icon: FaTelegram,
},
{
href: "mailto:[email protected]",
label: "[email protected]",
icon: ImMail4,
},
];

return (
<div className="mt-1 flex space-x-3">
<a
href="https://www.linkedin.com/in/khaykingleb"
target="_blank"
rel="noopener noreferrer"
aria-label="LinkedIn"
>
<FaLinkedin className="h-6 w-6" />
</a>
<a
href="https://github.com/khaykingleb"
target="_blank"
rel="noopener noreferrer"
aria-label="GitHub"
>
<FaGithub className="h-6 w-6" />
</a>
<a
href="https://t.me/khaykingleb_blog"
target="_blank"
rel="noopener noreferrer"
aria-label="Telegram"
>
<FaTelegram className="h-6 w-6" />
</a>
<a
href="https://x.com/khaykingleb"
target="_blank"
rel="noopener noreferrer"
aria-label="X"
>
<FaSquareXTwitter className="h-6 w-6" />
</a>
<a
href="https://instagram.com/khaykingleb"
target="_blank"
rel="noopener noreferrer"
aria-label="Instagram"
>
<AiFillInstagram className="-mt-0.5 h-7 w-7" />
</a>
<a href="mailto:[email protected]" aria-label="Email">
<ImMail4 className="h-6 w-6" />
</a>
</div>
<>
{links.map((link) => (
<a
key={link.href}
href={link.href}
className="flex items-center space-x-2 hover:text-primary"
target="_blank"
rel="noopener noreferrer"
>
<link.icon style={{ width: size, height: size }} />
<span className="text-base">{link.label}</span>
</a>
))}
</>
);
};
Loading
Loading