Compare commits

...

3 commits

Author SHA1 Message Date
liyunze
f862d50668 updated mobile navbar 2026-10-26 19:17:43 +08:00
liyunze
11b5b7eca4 updated profile picture on light mode 2026-10-26 17:38:15 +08:00
liyunze
55792cf72b updated text, formatted files 2026-10-26 17:19:19 +08:00
13 changed files with 270 additions and 87 deletions

View file

@ -1,21 +1,21 @@
<a <a
class="sticky left-5 top-5 ml-10 flex w-fit items-center justify-center gap-2 rounded-lg bg-white py-1 pl-2 pr-5 text-xl" class="sticky top-5 left-5 ml-10 flex w-fit items-center justify-center gap-2 rounded-lg bg-white py-1 pr-5 pl-2 text-xl"
href="/blog" href="/blog"
style="color: black; text-decoration: none;" style="color: black; text-decoration: none;"
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
fill="none" fill="none"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke-width="1.5" stroke-width="1.5"
stroke="currentColor" stroke="currentColor"
class="size-5" class="size-5"
> >
<path <path
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
d="M15.75 19.5 8.25 12l7.5-7.5"></path> d="M15.75 19.5 8.25 12l7.5-7.5"></path>
</svg> </svg>
Back Back
</a> </a>

View file

@ -3,6 +3,7 @@ import { Image } from "astro:assets";
import Socials from "../socials/Socials.astro"; import Socials from "../socials/Socials.astro";
import pfp_new from "../images/pfp_new_medium.webp"; import pfp_new from "../images/pfp_new_medium.webp";
import pfp_light from "../images/pfp_light.webp";
import Card from "../global/Card.astro"; import Card from "../global/Card.astro";
--- ---
@ -17,7 +18,13 @@ import Card from "../global/Card.astro";
<Image <Image
src={pfp_new} src={pfp_new}
alt="Profile picture" alt="Profile picture"
class="border-accent aspect-square rounded-full border-2 border-solid object-cover" class="profile-image-dark border-accent aspect-square rounded-full border-2 border-solid object-cover"
width={150}
/>
<Image
src={pfp_light}
alt="Profile picture"
class="profile-image-light border-accent hidden aspect-square rounded-full border-2 border-solid object-cover"
width={150} width={150}
/> />
</div> </div>
@ -58,6 +65,14 @@ import Card from "../global/Card.astro";
</div> </div>
<style> <style>
:global(html[data-theme="light"]) .profile-image-dark {
display: none;
}
:global(html[data-theme="light"]) .profile-image-light {
display: block;
}
#title { #title {
background: linear-gradient( background: linear-gradient(
90deg, 90deg,

View file

@ -3,6 +3,7 @@ import Card from "../global/Card.astro";
import Socials from "../socials/Socials.astro"; import Socials from "../socials/Socials.astro";
import Greeting from "./Greeting.svelte"; import Greeting from "./Greeting.svelte";
import pfp_new from "../images/pfp_new.webp"; import pfp_new from "../images/pfp_new.webp";
import pfp_light from "../images/pfp_light.webp";
import { Image } from "astro:assets"; import { Image } from "astro:assets";
--- ---
@ -20,7 +21,15 @@ import { Image } from "astro:assets";
alt="Ryan" alt="Ryan"
width="80" width="80"
height="80" height="80"
class="max-w-full rounded-full bg-[#505050]" class="profile-image-dark max-w-full rounded-full bg-[#505050]"
loading="eager"
/>
<Image
src={pfp_light}
alt="Ryan"
width="80"
height="80"
class="profile-image-light hidden max-w-full rounded-full bg-[#505050]"
loading="eager" loading="eager"
/> />
</div> </div>
@ -31,7 +40,53 @@ import { Image } from "astro:assets";
> >
Ryan Lee Ryan Lee
</div> </div>
<div class="w-full text-xl">Full Stack Developer</div> <div
class="flex flex-row items-start justify-start gap-3 text-sm"
>
<div
class="flex flex-row items-center justify-start gap-1"
>
<svg
class="size-4"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M20.25 14.15v4.25c0 1.094-.787 2.036-1.872 2.18-2.087.277-4.216.42-6.378.42s-4.291-.143-6.378-.42c-1.085-.144-1.872-1.086-1.872-2.18v-4.25m16.5 0a2.18 2.18 0 0 0 .75-1.661V8.706c0-1.081-.768-2.015-1.837-2.175a48.114 48.114 0 0 0-3.413-.387m4.5 8.006c-.194.165-.42.295-.673.38A23.978 23.978 0 0 1 12 15.75c-2.648 0-5.195-.429-7.577-1.22a2.016 2.016 0 0 1-.673-.38m0 0A2.18 2.18 0 0 1 3 12.489V8.706c0-1.081.768-2.015 1.837-2.175a48.111 48.111 0 0 1 3.413-.387m7.5 0V5.25A2.25 2.25 0 0 0 13.5 3h-3a2.25 2.25 0 0 0-2.25 2.25v.894m7.5 0a48.667 48.667 0 0 0-7.5 0M12 12.75h.008v.008H12v-.008Z"
></path>
</svg>
<div>Full Stack Developer</div>
</div>
<div
class="flex flex-row items-center justify-start gap-1"
>
<svg
class="size-4"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15 10.5a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
></path>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1 1 15 0Z"
></path>
</svg>
<div>Malaysia</div>
</div>
</div>
</div> </div>
</div> </div>
<div id="uwu" class="hidden items-center justify-center"> <div id="uwu" class="hidden items-center justify-center">
@ -46,12 +101,12 @@ import { Image } from "astro:assets";
<Greeting client:load />! <Greeting client:load />!
</div> </div>
<p class="text-left"> <p class="text-left">
I am a Malaysian computer science graduate working I am a content creator and software developer, building
on various projects in Malaysia. I develop software software for 100+ content creators, garnering 4,000+
for streamers and content creators, while also followers across platforms. I worked as a developer at 3+
making tech tutorials in programming. companies in Malaysia and Australia, and looking for my next
role after graduation.
</p> </p>
<div class="mt-8 flex flex-row items-center justify-center"> <div class="mt-8 flex flex-row items-center justify-center">
<Socials /> <Socials />
</div> </div>
@ -61,6 +116,14 @@ import { Image } from "astro:assets";
</div> </div>
<style> <style>
:global(html[data-theme="light"]) .profile-image-dark {
display: none;
}
:global(html[data-theme="light"]) .profile-image-light {
display: block;
}
#name { #name {
background: linear-gradient( background: linear-gradient(
90deg, 90deg,

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View file

@ -7,18 +7,18 @@ import GoRyve from "../images/projects/goryve.webp";
<div class="flex h-fit flex-col items-center pt-20 [perspective:1000px]"> <div class="flex h-fit flex-col items-center pt-20 [perspective:1000px]">
<div class="w-full max-w-[1440px]"> <div class="w-full max-w-[1440px]">
<Project <Project
position="left" position="left"
image={TwitchPlays} image={TwitchPlays}
alt="Twitch Plays X" alt="Twitch Plays X"
href="https://git.rython.dev/rythondev/TwitchPlaysX" href="https://git.rython.dev/rythondev/TwitchPlaysX"
title="Twitch Plays X" title="Twitch Plays X"
description={`Allow Twitch chatters to play games such as Pokemon! description={`Allow Twitch chatters to play games such as Pokemon!
Chatters can enter messages such as "up up down down left Chatters can enter messages such as "up up down down left
right B A" and the Python program will trigger the right B A" and the Python program will trigger the
corresponding keypresses.`} corresponding keypresses.`}
tags={["win32API", "Python"]} tags={["win32API", "Python"]}
/> />
<VideoProject <VideoProject
image_src="/images/projects/chess-opencv.webp" image_src="/images/projects/chess-opencv.webp"
image_alt="computer vision chess bot" image_alt="computer vision chess bot"
@ -35,15 +35,15 @@ import GoRyve from "../images/projects/goryve.webp";
client:visible client:visible
/> />
<Project <Project
position="left" position="left"
image={GoRyve} image={GoRyve}
alt="GoRyve" alt="GoRyve"
href="https://goryve.app/" href="https://goryve.app/"
title="GoRyve" title="GoRyve"
label="Visit Site" label="Visit Site"
description={`Notify your community when you or your friends go live, configured separately! Share a pool of 10 free slots between your Twitch accounts and your friends'.`} description={`Notify your community when you or your friends go live, configured separately! Share a pool of 10 free slots between your Twitch accounts and your friends'.`}
tags={["Rust", "Poise", "SQLite", "Forgejo Actions"]} tags={["Rust", "Poise", "SQLite", "Forgejo Actions"]}
/> />
<VideoProject <VideoProject
client:visible client:visible
image_src="/images/projects/aim-lab.webp" image_src="/images/projects/aim-lab.webp"

View file

@ -44,7 +44,9 @@ const renderLayer = (
isLight isLight
? "project-image-light hidden border-gray-300" ? "project-image-light hidden border-gray-300"
: "project-image-dark border-gray-800", : "project-image-dark border-gray-800",
isBackground ? "background-img opacity-40" : "frontfacing-img opacity-100", isBackground
? "background-img opacity-40"
: "frontfacing-img opacity-100",
isBackground && isLight ? "brightness-75" : "", isBackground && isLight ? "brightness-75" : "",
side, side,
] ]

View file

@ -87,7 +87,11 @@
{/if} {/if}
{/snippet} {/snippet}
{@render renderLayer("image", "background-img", "opacity-40 brightness-75")} {@render renderLayer(
"image",
"background-img",
"opacity-40 brightness-75",
)}
{@render renderLayer("video", "frontfacing-vid", "opacity-100")} {@render renderLayer("video", "frontfacing-vid", "opacity-100")}
</div> </div>
<div <div

View file

@ -1,7 +1,7 @@
<div class="flex flex-row items-center justify-center gap-3"> <div class="flex flex-row items-center justify-center gap-3">
<a href="https://git.rython.dev/" target="_blank"> <a href="https://git.rython.dev/" target="_blank">
<div <div
class="flex h-8 w-8 items-center justify-center rounded-full bg-white transition-[filter,background-color] duration-150 hover:invert hover:bg-[#089cff]" class="flex h-8 w-8 items-center justify-center rounded-full bg-white transition-[filter,background-color] duration-150 hover:bg-[#089cff] hover:invert"
> >
<img <img
src="/images/socials/forgejo.svg" src="/images/socials/forgejo.svg"

View file

@ -1,6 +1,5 @@
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { AnimatePresence, motion } from "motion/react"; import { AnimatePresence, motion } from "motion/react";
import { Cross as HamburgerCross } from "hamburger-react";
import { useEffect, useState, useRef } from "react"; import { useEffect, useState, useRef } from "react";
declare module "react" { declare module "react" {
@ -23,7 +22,7 @@ export const HoverNavigation = ({
const [activeIndex, setActiveIndex] = useState<number | null>(null); const [activeIndex, setActiveIndex] = useState<number | null>(null);
const [hamburgerOpen, setHamburgerOpen] = useState(false); const [hamburgerOpen, setHamburgerOpen] = useState(false);
const [theme, setTheme] = useState<"light" | "dark">("dark"); const [theme, setTheme] = useState<"light" | "dark">("dark");
const hamburgerRef = useRef<HTMLDivElement>(null); const hamburgerRef = useRef<HTMLButtonElement>(null);
const menuRef = useRef<HTMLDivElement>(null); const menuRef = useRef<HTMLDivElement>(null);
useEffect(() => { useEffect(() => {
@ -117,9 +116,26 @@ export const HoverNavigation = ({
} }
}; };
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "Escape") setHamburgerOpen(false);
};
document.addEventListener("mousedown", handleClickOutside); document.addEventListener("mousedown", handleClickOutside);
document.addEventListener("keydown", handleKeyDown);
return () => { return () => {
document.removeEventListener("mousedown", handleClickOutside); document.removeEventListener("mousedown", handleClickOutside);
document.removeEventListener("keydown", handleKeyDown);
};
}, [hamburgerOpen]);
useEffect(() => {
if (!hamburgerOpen) return;
const previousOverflow = document.body.style.overflow;
document.body.style.overflow = "hidden";
return () => {
document.body.style.overflow = previousOverflow;
}; };
}, [hamburgerOpen]); }, [hamburgerOpen]);
@ -187,16 +203,63 @@ export const HoverNavigation = ({
</div> </div>
</div> </div>
</div> </div>
<div className="theme-surface bg-secondary/50 fixed top-5 left-1/2 z-50 flex w-4/5 -translate-x-1/2 items-center justify-end rounded-full border-2 border-solid border-gray-700 pr-5 backdrop-blur-xl lg:hidden"> <div
<ThemeToggle theme={theme} onToggle={toggleTheme} /> className={cn(
<div "fixed top-4 right-4 left-4 z-50 flex h-16 items-center justify-between rounded-[1.25rem] border px-3 shadow-[0_12px_40px_rgba(0,0,0,0.16)] backdrop-blur-2xl transition-colors md:hidden",
ref={hamburgerRef} theme === "dark"
className="flex rounded-full px-1 py-1 md:hidden [&>div]:rounded-full [&>div_div]:bg-current!" ? "border-white/10 bg-neutral-950/85 text-white"
: "border-black/10 bg-white/85 text-neutral-950",
)}
>
<a
href="/#home"
onClick={() => setHamburgerOpen(false)}
className="flex items-center gap-2.5 rounded-xl px-2 py-2 font-semibold tracking-tight"
aria-label="Go to home"
> >
<HamburgerCross <span
toggle={setHamburgerOpen} className={cn(
toggled={hamburgerOpen} "grid size-8 place-items-center rounded-lg text-sm font-black",
></HamburgerCross> theme === "dark"
? "bg-white text-neutral-950"
: "bg-neutral-950 text-white",
)}
>
RL
</span>
<span className="text-sm opacity-65">Portfolio</span>
</a>
<div className="flex items-center gap-1">
<ThemeToggle theme={theme} onToggle={toggleTheme} />
<button
ref={hamburgerRef}
type="button"
onClick={() => setHamburgerOpen((open) => !open)}
aria-expanded={hamburgerOpen}
aria-controls="mobile-navigation"
aria-label={hamburgerOpen ? "Close menu" : "Open menu"}
className={cn(
"group grid size-11 cursor-pointer place-items-center rounded-xl transition-all active:scale-95",
theme === "dark"
? "bg-white text-neutral-950"
: "bg-neutral-950 text-white",
)}
>
<span
className="relative block h-4 w-5"
aria-hidden="true"
>
<span
className={`absolute top-0 right-0 h-0.5 w-5 rounded-full bg-current transition-all duration-300 ${hamburgerOpen ? "translate-y-[7px] -rotate-45" : ""}`}
/>
<span
className={`absolute top-[7px] right-0 h-0.5 rounded-full bg-current transition-all duration-300 ${hamburgerOpen ? "w-0 opacity-0" : "w-3.5"}`}
/>
<span
className={`absolute top-[14px] right-0 h-0.5 w-5 rounded-full bg-current transition-all duration-300 ${hamburgerOpen ? "-translate-y-[7px] rotate-45" : ""}`}
/>
</span>
</button>
</div> </div>
</div> </div>
@ -205,33 +268,68 @@ export const HoverNavigation = ({
{hamburgerOpen && ( {hamburgerOpen && (
<motion.div <motion.div
ref={menuRef} ref={menuRef}
initial={{ opacity: 0, scale: 0.95 }} id="mobile-navigation"
animate={{ opacity: 1, scale: 1 }} initial={{ opacity: 0, y: -12 }}
exit={{ opacity: 0, scale: 0.95 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.2 }} exit={{ opacity: 0, y: -12 }}
className="theme-surface bg-secondary/50 fixed top-24 right-0 left-1/2 z-40 w-4/5 -translate-x-1/2 rounded-2xl py-2 backdrop-blur-xl md:hidden" transition={{
duration: 0.25,
ease: [0.22, 1, 0.36, 1],
}}
className={cn(
"fixed inset-0 z-40 flex flex-col overflow-hidden px-5 pt-28 pb-7 transition-colors md:hidden",
theme === "dark"
? "bg-neutral-950 text-white"
: "bg-[#f4f3ef] text-neutral-950",
)}
> >
<nav aria-label="Mobile Navigation"> <nav
<ul className="flex flex-col gap-2"> aria-label="Mobile Navigation"
className="relative flex flex-1 items-center"
>
<ul className="w-full">
{items.map((item, idx) => ( {items.map((item, idx) => (
<motion.li <motion.li
key={item?.link} key={item?.link}
initial={{ opacity: 0, y: -20 }} initial={{ opacity: 0, x: -24 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, x: 0 }}
transition={{ transition={{
delay: idx * 0.1, delay: 0.06 + idx * 0.055,
duration: 0.3, duration: 0.35,
}} }}
className="rounded-2xl px-3" className={cn(
"border-b last:border-b-0",
theme === "dark"
? "border-white/10"
: "border-black/10",
)}
> >
<a <a
href={item?.link} href={item?.link}
className="block rounded-lg px-4 py-3 text-center text-lg transition-colors" className="group flex items-center gap-4 py-4"
onClick={() => onClick={() =>
setHamburgerOpen(false) setHamburgerOpen(false)
} }
> >
{item.label} <span className="w-6 text-xs font-medium opacity-35">
{String(idx + 1).padStart(
2,
"0",
)}
</span>
<span className="flex-1 text-[clamp(2rem,11vw,3.25rem)] leading-none font-semibold tracking-[-0.055em]">
{item.label}
</span>
<span
className={cn(
"grid size-9 place-items-center rounded-full border text-lg transition-all group-hover:rotate-[-45deg]",
theme === "dark"
? "border-white/20 group-hover:bg-white group-hover:text-neutral-950"
: "border-black/20 group-hover:bg-neutral-950 group-hover:text-white",
)}
>
↗
</span>
</a> </a>
</motion.li> </motion.li>
))} ))}

View file

@ -28,7 +28,8 @@ import { ClientRouter } from "astro:transitions";
const theme = const theme =
savedTheme === "light" || savedTheme === "dark" savedTheme === "light" || savedTheme === "dark"
? savedTheme ? savedTheme
: window.matchMedia("(prefers-color-scheme: light)").matches : window.matchMedia("(prefers-color-scheme: light)")
.matches
? "light" ? "light"
: "dark"; : "dark";

View file

@ -3,11 +3,11 @@ import InfoLayout from "../layouts/InfoLayout.astro";
--- ---
<InfoLayout <InfoLayout
title="RythonDev Discord Server" title="RythonDev Discord Server"
description="Come join Ryan's Room for tech support or chaotic vibes!" description="Come join Ryan's Room for tech support or chaotic vibes!"
metaURL="https://rython.dev/discord" metaURL="https://rython.dev/discord"
/> />
<script is:inline> <script is:inline>
window.location.href = "https://discord.gg/F5efU63Prz"; window.location.href = "https://discord.gg/F5efU63Prz";
</script> </script>

View file

@ -3,12 +3,12 @@ import InfoLayout from "../layouts/InfoLayout.astro";
--- ---
<InfoLayout <InfoLayout
title="RythonDev's Software Dev + Coworking Stream" title="RythonDev's Software Dev + Coworking Stream"
description="Come sit at the table with us! We can chill, nerd out, and enjoy good vibes together!" description="Come sit at the table with us! We can chill, nerd out, and enjoy good vibes together!"
thumbnail="/images/stream-live-thumbnail.webp" thumbnail="/images/stream-live-thumbnail.webp"
metaURL="https://rython.dev/live" metaURL="https://rython.dev/live"
/> />
<script is:inline> <script is:inline>
window.location.href = "https://www.twitch.tv/rythondev"; window.location.href = "https://www.twitch.tv/rythondev";
</script> </script>

View file

@ -3,12 +3,12 @@ import InfoLayout from "../layouts/InfoLayout.astro";
--- ---
<InfoLayout <InfoLayout
title="OnlyFans" title="OnlyFans"
description="UWU 💦 NYA MEOW SEXY TIME 🕓 ! RYAN IS 😗♻ HERE 🚢💪 TO 💦✌ EAT 😩🗣 YOUR 👉 TOES 👣 NOM NOM JUST KIDDING UWU 💦" description="UWU 💦 NYA MEOW SEXY TIME 🕓 ! RYAN IS 😗♻ HERE 🚢💪 TO 💦✌ EAT 😩🗣 YOUR 👉 TOES 👣 NOM NOM JUST KIDDING UWU 💦"
metaURL="https://rython.dev/onlyfans" metaURL="https://rython.dev/onlyfans"
thumbnail="/images/of-logo-b.webp" thumbnail="/images/of-logo-b.webp"
/> />
<script is:inline> <script is:inline>
window.location.href = "https://youtu.be/dQw4w9WgXcQ"; window.location.href = "https://youtu.be/dQw4w9WgXcQ";
</script> </script>