Merge pull request #1 from liyunze-coding/project-component

Project and Skills component
This commit is contained in:
RythonDev 2025-06-21 23:17:23 +10:00 committed by GitHub
commit d6bc248543
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 1273 additions and 1390 deletions

16
package-lock.json generated
View file

@ -11,7 +11,7 @@
"@astrojs/mdx": "^4.3.0",
"@astrojs/svelte": "^7.1.0",
"@tailwindcss/vite": "^4.1.8",
"astro": "^5.9.1",
"astro": "^5.10.0",
"caniuse-lite": "^1.0.30001698",
"moment": "^2.30.1",
"moment-timezone": "^0.6.0",
@ -38,9 +38,9 @@
}
},
"node_modules/@astrojs/compiler": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.12.1.tgz",
"integrity": "sha512-WDSyVIiz7sNcJcCJxJFITu6XjfGhJ50Z0auyaWsrM+xb07IlhBLFtQuDkNy0caVHWNcKTM2LISAaHhgkRqGAVg==",
"version": "2.12.2",
"resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.12.2.tgz",
"integrity": "sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw==",
"license": "MIT"
},
"node_modules/@astrojs/internal-helpers": {
@ -1587,12 +1587,12 @@
}
},
"node_modules/astro": {
"version": "5.9.1",
"resolved": "https://registry.npmjs.org/astro/-/astro-5.9.1.tgz",
"integrity": "sha512-wxoJcTbuDZNFSv6EaL0PAlrp0Wx6VnOAULCXvy0scsV70oWMeUkdxuBxfO54JxO5Qgyvwj9h99y6E0elqOpGtA==",
"version": "5.10.0",
"resolved": "https://registry.npmjs.org/astro/-/astro-5.10.0.tgz",
"integrity": "sha512-g/t54kVzQnFVijs+GbbbX/NBAFTl/3yNAEA/AQYq4FumLLVv7n4BIF+jKhcPGn9iFGyT1Cjvr7KB/qYyNvHEIg==",
"license": "MIT",
"dependencies": {
"@astrojs/compiler": "^2.12.1",
"@astrojs/compiler": "^2.12.2",
"@astrojs/internal-helpers": "0.6.1",
"@astrojs/markdown-remark": "6.3.2",
"@astrojs/telemetry": "3.3.0",

View file

@ -13,7 +13,7 @@
"@astrojs/mdx": "^4.3.0",
"@astrojs/svelte": "^7.1.0",
"@tailwindcss/vite": "^4.1.8",
"astro": "^5.9.1",
"astro": "^5.10.0",
"caniuse-lite": "^1.0.30001698",
"moment": "^2.30.1",
"moment-timezone": "^0.6.0",

View file

@ -1,12 +1,12 @@
<script lang="ts">
import Socials from "../elements/Socials.svelte";
import Socials from "../socials/Socials.svelte";
</script>
<div class="relative flex h-fit w-full flex-col items-center justify-center">
<div class="flex flex-col items-center justify-center">
<div
id="title"
class="mb-3 animate-gradient text-center text-3xl font-bold"
class="animate-gradient mb-3 text-center text-3xl font-bold"
>
Get in Touch with me!
</div>

View file

@ -1,6 +1,6 @@
---
import Card from "../elements/Card.astro";
import Line from "../elements/NetworkLine.astro";
import Card from "../global/Card.astro";
import Line from "../global/NetworkLine.astro";
---
<div id="Experience" class="h-fit">

View file

@ -1,6 +1,6 @@
---
import Card from "../elements/Card.astro";
import Line from "../elements/NetworkLine.astro";
import Card from "../global/Card.astro";
import Line from "../global/NetworkLine.astro";
---
<div id="Experience" class="h-fit">

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { onMount } from "svelte";
import Socials from "../elements/Socials.svelte";
import Socials from "../socials/Socials.svelte";
// Roles
let roles = $state(["Developer", "Streamer", "Content creator", "Student"]);

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 230 KiB

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View file

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -0,0 +1,65 @@
<script lang="ts">
import VideoProject from "./VideoProject.svelte";
</script>
<div class="flex h-fit flex-col items-center pt-20 [perspective:1000px]">
<div class="w-full max-w-[1440px]">
<VideoProject
image_src="/images/projects/chess-opencv.webp"
image_alt="computer vision chess bot"
position="left"
video_src="/videos/chess_opencv_demo.webm"
title="Computer Vision Chess Bot"
description={`
A script that plays against opponents on lichess. Uses
OpenCV to detect the board and pieces, and the Stockfish
chess engine to determine the best moves. Then uses
PyAutoGUI to play the moves on the browser.
`}
tags={[
{
text: "Python",
textColor: "white",
bgColor: "var(--color-python)",
},
{
text: "OpenCV",
textColor: "white",
bgColor: "var(--color-opencv)",
},
{
text: "PyAutoGUI",
textColor: "white",
bgColor: "black",
},
]}
></VideoProject>
<VideoProject
image_src="/images/projects/aim-lab.webp"
image_alt="Computer Vision AimLab Bot"
position="right"
video_src="/videos/aim_lab_demo.webm"
title="Computer Vision AimLab Bot"
description={`
A script that plays AimLab, a game that helps improve your aim in FPS games. Uses OpenCV to detect the targets and win32API to move the mouse and click.
`}
tags={[
{
text: "Python",
textColor: "white",
bgColor: "var(--color-python)",
},
{
text: "OpenCV",
textColor: "white",
bgColor: "var(--color-opencv)",
},
{
text: "win32API",
textColor: "white",
bgColor: "var(--color-win32api)",
},
]}
></VideoProject>
</div>
</div>

View file

@ -0,0 +1,144 @@
---
import { Image } from "astro:assets";
interface Tag {
text: string;
textColor: string;
bgColor: string;
}
interface Props {
position?: "left" | "right";
image?: ImageMetadata;
alt?: string;
href: string;
title: string;
description: string;
label?: string;
tags?: Tag[];
}
const {
image,
alt,
href,
title,
description,
label = "View Repository",
tags = [],
position = "left",
} = Astro.props;
const leftProject = position == "left";
---
<div
class="flex h-fit w-full flex-col justify-center px-10 lg:px-20"
class:list={leftProject ? "lg:flex-row" : "lg:flex-row-reverse"}
>
<div
class="image-container relative mb-5 flex aspect-video w-full [perspective:200px] lg:mr-5 lg:mb-0 lg:ml-auto lg:w-1/2"
>
<slot />
{
image && alt &&
(
<Image
src={image}
alt={alt}
class={`absolute max-w-full
aspect-video
opacity-40
border-2 border-solid border-white rounded-xl`}
class:list={leftProject
? "[transform:translateX(50px)_translateY(5px)_rotateY(5deg)_rotateX(0deg)_translateZ(-50px)]"
: "[transform:translateX(10px)_translateY(5px)_translateZ(-50px)_rotateY(-3deg)]"}
width="700"
/>
<Image
src={image}
alt={alt}
width="700"
class={`absolute max-w-full
aspect-video
opacity-100
border-2 border-solid border-white rounded-xl`}
class:list={leftProject
? "[transform:rotateY(5deg)_rotateX(0deg)_translateX(60px)_translateZ(-50px)]"
: "[transform:translateZ(-50px)_rotateY(-3deg)]"}
/>
)
}
<div
class="visit-div absolute top-1/2 left-1/2 aspect-video w-[700px] max-w-full [transform:translateX(-50%)_translateY(-50%)] rounded-xl border-2 border-solid border-white bg-[rgba(0,0,0,0.5)] opacity-0"
>
<a
href={href}
target="_blank"
class="absolute top-1/2 left-1/2 hidden [transform:translateX(-50%)_translateY(-50%)] rounded-xl bg-blue-600 px-5 py-3 font-bold opacity-100 transition-colors duration-300 hover:bg-white hover:text-blue-500 lg:block"
>{label}</a
>
</div>
</div>
<div class="mb-10 flex items-center justify-center lg:hidden">
<a
href={href}
target="_blank"
class="rounded-xl bg-blue-600 px-5 py-3 font-bold opacity-100 transition-colors duration-300 hover:bg-white hover:text-blue-500"
>{label}</a
>
</div>
<div
class="flex h-fit w-full flex-col items-center justify-center lg:h-[340px] lg:w-1/2 lg:px-10"
class:list={leftProject ? "lg:items-start" : "lg:items-end"}
>
<h2
class="mb-5 text-center text-3xl font-bold"
class:list={leftProject ? "lg:text-left" : "lg:text-right"}
>
{title}
</h2>
<p
class="max-w-lg text-center text-xl text-balance lg:max-w-none"
class:list={leftProject ? "lg:text-left" : "lg:text-right"}
>
{description}
</p>
<div
class="mt-5 flex w-full flex-row flex-wrap justify-center"
class:list={leftProject ? "lg:justify-start" : "lg:justify-end"}
>
{
tags.map((tag) => (
<div
class="my-1 mr-1 w-fit rounded-full px-3 py-1 transition-colors duration-300"
style={`
background-color: ${tag.bgColor || "black"};
color: ${tag.textColor || "white"};
`}
>
{tag.text}
</div>
))
}
</div>
</div>
</div>
<style>
.image-container img {
transition: transform 0.5s ease-in-out;
}
@media (min-width: 1025px) {
.image-container:hover > img {
transform: rotateY(0deg) rotateX(0deg) translateZ(0px);
}
.image-container:hover > .visit-div {
opacity: 100%;
transition: opacity 0.3s ease-in-out;
transition-delay: 0.3s;
}
}
</style>

View file

@ -0,0 +1,156 @@
---
import TaskWidget from "./TaskWidget.svelte";
import CoworkingGuide from "../images/projects/coworking-guide.webp";
import Wnrs from "../images/projects/wnrs.webp";
import TwitchPlays from "../images/projects/twitchplays.webp";
import Project from "./Project.astro";
---
<div
id="projects"
class="flex h-fit flex-col items-center [perspective:1000px]"
>
<div class="w-full max-w-[1440px]">
<Project
position="left"
image={CoworkingGuide}
alt="coworking guide"
href="https://coworking-guide.vercel.app/"
title="Coworking Guide"
label="Visit Site"
description="A guide to coworking streams for streamers, covers wide range of topics from tips on how to get started with setting up stream to how to grow your audience!"
tags={[
{
text: "Astro",
bgColor: "white",
textColor: "black",
},
{
text: "TypeScript",
bgColor: "#3178C6",
textColor: "white",
},
{
text: "Markdown",
bgColor: "black",
textColor: "white",
},
]}
/>
<Project
position="right"
href="https://github.com/liyunze-coding/chat-task-tic-overlay-infinity"
title="Chat-task-tic widget"
label="View Repository"
description={`
Used by 100+ Twitch streamers, allow viewers and streamers
to add their own tasks to the widget for accountability!
Easy to setup and the customization possibilities are
endless!`}
tags={[
{
text: "HTML",
bgColor: "var(--color-html)",
textColor: "white",
},
{
text: "CSS",
bgColor: "var(--color-blue-600)",
textColor: "white",
},
{
text: "Javascript",
bgColor: "var(--color-yellow-500)",
textColor: "black",
},
]}
>
<TaskWidget
classList={`
widget
[perspective:200px] absolute [transform:translateX(-10px)_translateY(5px)_translateZ(-40px)_rotateY(-3deg)]
w-full h-full
opacity-10
`}
client:visible
/>
<TaskWidget
classList={`
widget
[perspective:200px] absolute
[transform:translateX(-20px)_translateZ(-40px)_rotateY(-3deg)]
w-full h-full
hover:[transform:translateX(0)_translateY(0)_translateZ(0)_rotateY(0)]`}
client:visible
/>
</Project>
<Project
position="left"
image={Wnrs}
alt="We're not really strangers"
href="https://liyunze-coding.github.io/wnrs/"
label="Visit Site"
title="We're not really strangers"
description="Otherwise abbreviated as 'WNRS', this is a digitaladaptation of the popular card game designed to foster meaningful connections through engaging questions and prompts."
tags={[
{
text: "React",
bgColor: "var(--color-react)",
textColor: "black",
},
{
text: "TypeScript",
bgColor: "var(--color-typescript)",
textColor: "white",
},
]}
/>
<Project
position="right"
image={TwitchPlays}
alt="Twitch Plays X"
href="https://github.com/liyunze-coding/TwitchPlaysX"
title="Twitch Plays X"
description={`Allow Twitch chatters to play games such as Pokemon!
Chatters can enter messages such as "up up down down left
right B A" and the Python program will trigger the
corresponding keypresses.`}
tags={[
{
text: "win32API",
bgColor: "var(--color-win32api)",
textColor: "white",
},
{
text: "Python",
bgColor: "var(--color-python)",
textColor: "white",
},
]}
/>
</div>
</div>
<style is:global>
.image-container img,
.image-container .widget,
.image-container video {
transition: transform 0.5s ease-in-out;
}
@media (min-width: 1025px) {
.image-container:hover > img,
.image-container:hover .widget,
.image-container:hover video {
transform: rotateY(0deg) rotateX(0deg) translateZ(0px) translateX(0)
translateY(0);
}
.image-container:hover > .visit-div {
opacity: 100%;
transition: opacity 0.3s ease-in-out;
transition-delay: 0.3s;
}
}
</style>

View file

@ -113,24 +113,24 @@
task: "anki flashcards",
},
];
interface Props {
classList: string;
}
let { classList }: Props = $props();
</script>
<div
class="image-container relative mr-0 mb-3 ml-0 aspect-video [perspective:200px] md:mr-5 lg:mr-0 lg:mb-0 lg:ml-1 lg:w-1/2"
>
<div class={`${classList} aspect-video`}>
<!-- task bot -->
<div
class="task-widget absolute top-1/2 left-1/2 flex
h-[99%] w-full
[transform:translateX(-50%)_translateY(-49%)_translateZ(-50px)_rotateY(-3deg)] flex-col opacity-30"
>
<div class="task-widget absolute flex h-[99%] w-full flex-col">
<div
class="flex w-full flex-row items-center justify-between
rounded-lg
border-2 border-solid
border-white bg-black
px-5 py-2 font-['Fredoka',_sans-serif] text-xl
text-white"
rounded-lg
border-2 border-solid
border-white bg-black
px-5 py-2 font-['Fredoka',_sans-serif] text-xl
text-white"
>
<span>Hover here!</span>
<span>0/100+</span>
@ -160,84 +160,9 @@
</div>
</div>
</div>
<div
class="task-widget absolute top-1/2 left-1/2
flex h-[99%]
w-full [transform:translateX(-51%)_translateY(-50%)_translateZ(-50px)_rotateY(-3deg)] flex-col"
>
<div
class="flex w-full flex-row items-center justify-between
rounded-lg
border-2 border-solid
border-white bg-black
px-5 py-2 font-['Fredoka',_sans-serif] text-xl
text-white"
>
<span>Hover here!</span>
<span>0/100+</span>
</div>
<div
class="scroll-parent relative h-full overflow-hidden font-['Fredoka',_sans-serif]"
>
<div class="scroll-element primary absolute w-full px-1">
{#each streamers as { streamer, task }}
<div
class="my-2 w-full overflow-hidden rounded-md bg-[#404040] px-5 py-1
overflow-ellipsis whitespace-nowrap text-white"
>
O {streamer} : {task}
</div>
{/each}
</div>
<div class="scroll-element secondary absolute w-full px-1">
{#each streamers as { streamer, task }}
<div
class="my-2 w-full overflow-hidden rounded-md bg-[#404040] px-5 py-1
overflow-ellipsis whitespace-nowrap text-white"
>
O {streamer} : {task}
</div>
{/each}
</div>
</div>
</div>
<div
class="visit-div absolute top-1/2 left-1/2 h-full w-full
[transform:translateX(-50%)_translateY(-50%)]
overflow-hidden rounded-md border-2
border-solid border-white bg-[rgba(0,0,0,0.5)]
opacity-0"
>
<a
href="https://github.com/liyunze-coding/chat-task-tic-overlay-infinity"
target="_blank"
class="absolute top-1/2 left-1/2 hidden
[transform:translateX(-50%)_translateY(-50%)] rounded-xl bg-blue-500 px-5 py-3
font-bold
opacity-100 transition-colors
duration-300 hover:bg-white
hover:text-blue-500 lg:block">View repository</a
>
</div>
</div>
<style>
.image-container .task-widget {
transition: transform 0.5s ease-in-out;
}
@media (min-width: 1025px) {
.image-container:hover > .task-widget {
transform: rotateY(0deg) rotateX(0deg) translateZ(0px)
translateX(-50%) translateY(-50%);
}
.image-container:hover > .visit-div {
opacity: 100%;
transition: opacity 0.3s ease-in-out;
transition-delay: 0.3s;
}
}
.primary {
animation: primary 20s linear infinite;
}

View file

@ -0,0 +1,149 @@
<script lang="ts">
import { onMount } from "svelte";
interface Tag {
text: string;
textColor: string;
bgColor: string;
}
interface Props {
position?: "left" | "right";
image_src: string;
image_alt: string;
video_src: string;
title: string;
description: string;
tags?: Tag[];
}
let {
position = "left",
image_src,
image_alt,
video_src,
title,
description,
tags = [],
}: Props = $props();
const positionLeft = position == "left";
onMount(() => {
const videos = document.querySelectorAll<HTMLVideoElement>(".playable");
let userInteracted = false;
const handleUserInteraction = () => {
userInteracted = true;
document.removeEventListener("click", handleUserInteraction);
document.removeEventListener("keydown", handleUserInteraction);
};
document.addEventListener("click", handleUserInteraction);
document.addEventListener("keydown", handleUserInteraction);
videos.forEach((video) => {
// Ensure the video element supports play and pause methods
if (
typeof video.play === "function" &&
typeof video.pause === "function"
) {
video.addEventListener("mouseenter", () => {
if (userInteracted) {
video.volume = 0.2;
video.muted = false;
video.play();
} else {
video.volume = 0;
video.muted = true;
video.play();
}
});
video.addEventListener("mouseleave", () => {
video.pause();
video.currentTime = 0;
});
// Check if the screen width is less than or equal to 768px (mobile screen size)
if (window.innerWidth <= 768) {
video.muted = true;
video.autoplay = true;
video.loop = true;
video.play();
}
}
});
});
</script>
<div
class="flex h-fit w-full flex-col justify-center px-10 lg:flex-row lg:px-20"
class:lg:flex-row={positionLeft}
class:lg:flex-row-reverse={!positionLeft}
>
<div
class="image-container relative mb-5 flex aspect-video w-full [perspective:200px] lg:mr-5 lg:mb-0 lg:ml-auto lg:w-1/2"
>
<img
src={image_src}
alt={image_alt}
class="absolute max-w-full
rounded-xl
border-2 border-solid border-white opacity-40
{positionLeft
? '[transform:rotateY(5deg)_translateX(50px)_translateY(5px)_translateZ(-50px)]'
: '[transform:rotateY(-5deg)_translateX(-20px)_translateY(5px)_translateZ(-50px)]'}"
width="700"
/>
<!-- svelte-ignore a11y_media_has_caption -->
<video
width="700"
class="playable absolute max-w-full
rounded-xl border-2 border-solid border-white
opacity-100
{positionLeft
? '[transform:rotateY(5deg)_translateX(60px)_translateZ(-50px)]'
: '[transform:rotateY(-5deg)_translateX(-30px)_translateZ(-50px)]'}"
>
<source src={video_src} type="video/webm" />
</video>
</div>
<div
class="flex h-fit w-full flex-col items-center justify-center lg:h-[340px] lg:w-1/2 lg:px-10
{positionLeft ? 'lg:items-start' : 'lg:items-end'}"
>
<h2
class="mb-5 text-center text-3xl font-bold
{positionLeft ? 'lg:text-left' : 'lg:text-right'}"
>
{title}
</h2>
<p
class="max-w-lg text-center text-xl text-balance lg:max-w-none
{positionLeft ? 'lg:text-left' : 'lg:text-right'}"
>
{description}
</p>
<div
class="mt-5 flex w-full flex-row flex-wrap justify-center
{positionLeft ? 'lg:justify-start' : 'lg:justify-end'}"
>
{#each tags as tag}
<div
class="my-1 mr-1 w-fit
rounded-full px-3 py-1
transition-colors duration-300"
style={`
background-color: ${tag.bgColor || "black"};
color: ${tag.textColor || "white"};
`}
>
{tag.text}
</div>
{/each}
</div>
</div>
</div>

View file

@ -1,206 +0,0 @@
<script lang="ts">
import { onMount } from "svelte";
onMount(() => {
const videos = document.querySelectorAll<HTMLVideoElement>(".playable");
let userInteracted = false;
const handleUserInteraction = () => {
userInteracted = true;
document.removeEventListener("click", handleUserInteraction);
document.removeEventListener("keydown", handleUserInteraction);
};
document.addEventListener("click", handleUserInteraction);
document.addEventListener("keydown", handleUserInteraction);
videos.forEach((video) => {
// Ensure the video element supports play and pause methods
if (
typeof video.play === "function" &&
typeof video.pause === "function"
) {
video.addEventListener("mouseenter", () => {
if (userInteracted) {
video.volume = 0.2;
video.muted = false;
video.play();
} else {
video.volume = 0;
video.muted = true;
video.play();
}
});
video.addEventListener("mouseleave", () => {
video.pause();
video.currentTime = 0;
});
// Check if the screen width is less than or equal to 768px (mobile screen size)
if (window.innerWidth <= 768) {
video.muted = true;
video.autoplay = true;
video.loop = true;
video.play();
}
}
});
});
</script>
<div class="flex h-fit flex-col items-center pt-20 [perspective:1000px]">
<div class="w-full max-w-[1440px]">
<div
class="flex h-fit w-full flex-col justify-center px-10 lg:flex-row lg:px-20"
>
<div
class="image-container relative mb-5 flex aspect-video w-full [perspective:200px] lg:mr-5 lg:mb-0 lg:ml-auto lg:w-1/2"
>
<img
src="/images/projects/chess-opencv.webp"
alt="computer vision chess bot"
class="absolute top-1/2
left-1/2 max-w-full
[transform:rotateY(5deg)_rotateX(0deg)_translateZ(-50px)_translateX(-45%)_translateY(-50%)] rounded-xl
border-2 border-solid border-white opacity-40"
width="700"
/>
<!-- svelte-ignore a11y-media-has-caption -->
<video
width="700"
class="playable absolute top-1/2
left-1/2 max-w-full
[transform:rotateY(5deg)_rotateX(0deg)_translateZ(-50px)_translateX(-43%)_translateY(-52%)] rounded-xl
border-2 border-solid border-white opacity-100"
>
<source
src="/videos/chess_opencv_demo.webm"
type="video/webm"
/>
</video>
</div>
<div
class="flex h-fit w-full flex-col items-center justify-center lg:h-[340px] lg:w-1/2 lg:items-start lg:px-10"
>
<h2 class="mb-5 text-center text-3xl font-bold lg:text-left">
Computer Vision Chess bot
</h2>
<p
class="max-w-lg text-center text-xl text-balance lg:max-w-none lg:text-left"
>
A script that plays against opponents on lichess. Uses
OpenCV to detect the board and pieces, and the Stockfish
chess engine to determine the best moves. Then uses
PyAutoGUI to play the moves on the browser.
</p>
<div
class="mt-5 flex w-full flex-row flex-wrap justify-center lg:justify-start"
>
<div
class="my-1 mr-1 w-fit
rounded-full bg-[#3776AB] px-3 py-1 text-white
transition-colors duration-300"
>
Python
</div>
<div
class="my-1 mr-1 w-fit
rounded-full bg-[#3178C6] px-3 py-1 text-white
transition-colors duration-300"
>
OpenCV
</div>
<div
class="my-1 mr-1 w-fit
rounded-full bg-black px-3 py-1 text-white
transition-colors duration-300"
>
PyAutoGUI
</div>
</div>
</div>
</div>
<div
class="mt-10 flex h-fit w-full flex-col-reverse justify-center px-10 lg:flex-row lg:px-16"
>
<div
class="flex h-fit w-full flex-col items-center justify-center lg:h-[340px] lg:w-1/2 lg:items-end lg:px-10"
>
<h2 class="mb-5 text-center text-3xl font-bold lg:text-right">
Computer Vision AimLab Bot
</h2>
<p
class="max-w-lg text-center text-xl text-balance lg:max-w-none lg:text-right"
>
A script that plays AimLab, a game that helps improve your
aim in FPS games. Uses OpenCV to detect the targets and
win32API to move the mouse and click.
</p>
<div
class="mt-5 mb-10 flex w-full flex-row flex-wrap justify-center lg:mb-0 lg:justify-end"
>
<div
class="my-1 mr-1 w-fit
rounded-full bg-[#3776AB] px-3 py-1 text-white
transition-colors duration-300"
>
Python
</div>
<div
class="my-1 mr-1 w-fit
rounded-full bg-[#3178C6] px-3 py-1 text-white
transition-colors duration-300"
>
OpenCV
</div>
<div
class="my-1 mr-1 w-fit
rounded-full bg-[#0078D4] px-3 py-1 text-white
transition-colors duration-300"
>
win32API
</div>
</div>
</div>
<div
class="image-container relative mb-5 flex aspect-video w-full [perspective:200px] lg:mr-5 lg:mb-0 lg:ml-auto lg:w-1/2"
>
<img
src="/images/projects/aim-lab.webp"
alt="aim lab"
class="absolute top-1/2
left-1/2 max-w-full [transform:translateX(-48%)_translateY(-48%)_translateZ(-50px)_rotateY(-3deg)] rounded-xl
border-2 border-solid border-white opacity-40"
width="700"
/>
<!-- svelte-ignore a11y-media-has-caption -->
<video
width="700"
class="playable absolute top-1/2
left-1/2 max-w-full
[transform:translateX(-50%)_translateY(-50%)_translateZ(-50px)_rotateY(-3deg)] rounded-xl
border-2 border-solid border-white opacity-100"
><source src="/videos/aim_lab_demo.webm" /></video
>
</div>
</div>
</div>
</div>
<style>
.image-container img,
.image-container video {
transition: transform 0.5s ease-in-out;
}
@media (min-width: 1025px) {
.image-container:hover > img,
.image-container:hover > video {
transform: rotateY(0deg) rotateX(0deg) translateZ(0px)
translateX(-50%) translateY(-50%);
}
}
</style>

View file

@ -1,103 +0,0 @@
---
import Card from "../elements/Card.astro";
import Line from "../elements/NetworkLine.astro";
---
<div id="Experience" class="h-fit">
<div class="flex flex-col items-center">
<div class="w-[90%] md:w-[600px]">
<Line height="50px" />
<div class="mx-auto w-[90%] md:w-[600px]">
<Card primaryColor="#9D76C1">
<div class="px-8 py-8">
<div class="justify-left flex w-full flex-col">
<h2 class="text-2xl font-bold">Content Creation</h2>
</div>
<hr class="my-3 w-full" />
<p class="text-left">
Since I was little, I loved watching YouTube videos
and the idea of bringing joy and laughter to a wider
audience. Thus, I began my journey in content
creation through YouTube videos and Twitch
streaming. I typically do coworking & study streams
to keep myself accountable and encourage
productivity amongst viewers. I also do software and
game development streams where I showcase my
workflow.
</p>
<div
class="flex w-full flex-row flex-wrap justify-start"
>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-[#141414] px-3 py-1 text-white transition-colors duration-300 hover:bg-[#141414] hover:text-white md:bg-gray-500"
>
OBS
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-gray-50 px-3 py-1 text-black transition-colors duration-300 hover:bg-gray-50 hover:text-black md:bg-gray-500 md:text-white"
>
DaVinci Resolve
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-purple-500 px-3 py-1 text-white transition-colors duration-300 hover:bg-purple-500 md:bg-gray-500"
>
Twitch
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-[#ff0000] px-3 py-1 text-white transition-colors duration-300 hover:bg-[#ff0000] hover:text-white md:bg-gray-500"
>
YouTube
</div>
</div>
</div>
</Card>
</div>
<Line height="50px" />
<div class="mx-auto w-[90%] md:w-[600px]">
<Card primaryColor="#9D76C1">
<div class="px-8 py-8">
<div class="justify-left flex w-full flex-col">
<h2 class="text-2xl font-bold">
Mobile Development
</h2>
</div>
<hr class="my-3 w-full" />
<p class="text-left">
In my Mobile App Development unit in University, I
am tasked to develop Android apps using Android
Studio. The final app project I had developed was a
LLM-powered quiz app with features such as choosing
your own topics, viewing your question attempt
history afterwards, and upgrading your tier with
Google Pay.
</p>
<p class="text-left">
The marking tutor was impressed with my work, and
offered me to join a research lab because I had good
potential.
</p>
<div
class="mt-5 flex w-full flex-row flex-wrap justify-start"
>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-[#106539] px-3 py-1 text-white transition-colors duration-300 hover:bg-[#106539] hover:text-white md:bg-gray-500"
>
Android
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-[#ED8B00] px-3 py-1 text-white transition-colors duration-300 hover:bg-[#ED8B00] md:bg-gray-500"
>
Java
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-[#7F52FF] px-3 py-1 text-white transition-colors duration-300 hover:bg-[#7F52FF] md:bg-gray-500"
>
Kotlin
</div>
</div>
</div>
</Card>
</div>
</div>
</div>
</div>

View file

@ -1,306 +0,0 @@
---
import TaskWidget from "./TaskWidget.svelte";
import { Image } from "astro:assets";
import CoworkingGuide from "./images/projects/coworking-guide.webp";
import Wnrs from "./images/projects/wnrs.webp";
import TwitchPlays from "./images/projects/twitchplays.webp";
---
<div
id="projects"
class="flex h-fit flex-col items-center [perspective:1000px]"
>
<div class="w-full max-w-[1440px]">
<div
class="flex h-fit w-full flex-col justify-center px-10 lg:flex-row lg:px-20"
>
<div
class="image-container relative mb-5 flex aspect-video w-full [perspective:200px] lg:mr-5 lg:mb-0 lg:ml-auto lg:w-1/2"
>
<Image
src={CoworkingGuide}
alt="coworking guide"
class=`absolute max-w-full
top-1/2 left-1/2
[transform:rotateY(5deg)_rotateX(0deg)_translateZ(-50px)_translateX(-45%)_translateY(-50%)] opacity-40
border-2 border-solid border-white rounded-xl`
width="700"
/>
<Image
src={CoworkingGuide}
alt="coworking guide"
width="700"
class=`absolute max-w-full
top-1/2 left-1/2
[transform:rotateY(5deg)_rotateX(0deg)_translateZ(-50px)_translateX(-43%)_translateY(-52%)] opacity-100
border-2 border-solid border-white rounded-xl`
/>
<div
class="visit-div absolute top-1/2 left-1/2 aspect-video w-[700px] max-w-full [transform:translateX(-50%)_translateY(-50%)] rounded-xl border-2 border-solid border-white bg-[rgba(0,0,0,0.5)] opacity-0"
>
<a
href="https://coworking-guide.vercel.app/"
target="_blank"
class="absolute top-1/2 left-1/2 hidden [transform:translateX(-50%)_translateY(-50%)] rounded-xl bg-blue-600 px-5 py-3 font-bold opacity-100 transition-colors duration-300 hover:bg-white hover:text-blue-500 lg:block"
>Visit site</a
>
</div>
</div>
<div class="mb-10 flex items-center justify-center lg:hidden">
<a
href="https://coworking-guide.vercel.app/"
target="_blank"
class="rounded-xl bg-blue-600 px-5 py-3 font-bold opacity-100 transition-colors duration-300 hover:bg-white hover:text-blue-500"
>View repository</a
>
</div>
<div
class="flex h-fit w-full flex-col items-center justify-center lg:h-[340px] lg:w-1/2 lg:items-start lg:px-10"
>
<h2 class="mb-5 text-center text-3xl font-bold lg:text-left">
Coworking Guide
</h2>
<p
class="max-w-lg text-center text-xl text-balance lg:max-w-none lg:text-left"
>
A guide to coworking streams for streamers, covers wide
range of topics from tips on how to get started with setting
up stream to how to grow your audience!
</p>
<div
class="mt-5 flex w-full flex-row flex-wrap justify-center lg:justify-start"
>
<div
class="my-1 mr-1 w-fit rounded-full bg-white px-3 py-1 text-black transition-colors duration-300"
>
Astro
</div>
<div
class="my-1 mr-1 w-fit rounded-full bg-[#3178C6] px-3 py-1 text-white transition-colors duration-300"
>
TypeScript
</div>
<div
class="my-1 mr-1 w-fit rounded-full bg-black px-3 py-1 text-white transition-colors duration-300"
>
Markdown
</div>
</div>
</div>
</div>
<div
class="mt-10 flex h-fit w-full flex-col-reverse justify-center px-10 lg:flex-row lg:px-16"
>
<div
class="flex h-fit w-full flex-col items-center justify-center lg:h-[340px] lg:w-1/2 lg:items-end lg:px-10"
>
<h2 class="mb-5 text-center text-3xl font-bold lg:text-right">
Chat-Task-Tic Widget
</h2>
<p
class="max-w-lg text-center text-xl text-balance lg:max-w-none lg:text-right"
>
Used by 100+ Twitch streamers, allow viewers and streamers
to add their own tasks to the widget for accountability!
Easy to setup and the customization possibilities are
endless!
</p>
<div
class="mt-5 flex w-full flex-row flex-wrap justify-center lg:justify-end"
>
<div
class="bg-html my-1 mr-1 w-fit rounded-full px-3 py-1 text-white transition-colors duration-300"
>
HTML
</div>
<div
class="my-1 mr-1 w-fit rounded-full bg-blue-700 px-3 py-1 text-white transition-colors duration-300"
>
CSS
</div>
<div
class="my-1 mr-1 w-fit rounded-full bg-yellow-400 px-3 py-1 text-black transition-colors duration-300"
>
Javascript
</div>
</div>
</div>
<div class="mb-10 flex items-center justify-center lg:hidden">
<a
href="https://github.com/liyunze-coding/chat-task-tic-overlay-infinity"
target="_blank"
class="rounded-xl bg-blue-600 px-5 py-3 font-bold opacity-100 transition-colors duration-300 hover:bg-white hover:text-blue-600"
>View repository</a
>
</div>
<TaskWidget client:visible />
</div>
<div
class="mt-5 flex h-fit w-full flex-col justify-center px-10 lg:mt-0 lg:flex-row lg:px-20"
>
<div
class="image-container relative mb-5 flex aspect-video w-full [perspective:200px] lg:mr-5 lg:mb-0 lg:ml-auto lg:w-1/2"
>
<Image
src={Wnrs}
alt="Hex Guess"
class=`absolute max-w-full
top-1/2 left-1/2
[transform:rotateY(5deg)_rotateX(0deg)_translateZ(-50px)_translateX(-45%)_translateY(-50%)] opacity-40
border-2 border-solid border-white rounded-xl
aspect-video`
width="700"
/>
<Image
src={Wnrs}
alt="Hex Guess"
width="700"
class=`absolute max-w-full
top-1/2 left-1/2
[transform:rotateY(5deg)_rotateX(0deg)_translateZ(-50px)_translateX(-43%)_translateY(-52%)] opacity-100
border-2 border-solid border-white rounded-xl
aspect-video`
/>
<div
class="visit-div absolute top-1/2 left-1/2 aspect-video w-[700px] max-w-full [transform:translateX(-50%)_translateY(-50%)] rounded-xl border-2 border-solid border-white bg-[rgba(0,0,0,0.5)] opacity-0"
>
<a
href="https://liyunze-coding.github.io/wnrs/"
target="_blank"
class="absolute top-1/2 left-1/2 hidden [transform:translateX(-50%)_translateY(-50%)] rounded-xl bg-blue-600 px-5 py-3 font-bold opacity-100 transition-colors duration-300 hover:bg-white hover:text-blue-500 lg:block"
>Visit site</a
>
</div>
</div>
<div class="mb-10 flex items-center justify-center lg:hidden">
<a
href="https://hex-guess.vercel.app/"
target="_blank"
class="rounded-xl bg-blue-600 px-5 py-3 font-bold opacity-100 transition-colors duration-300 hover:bg-white hover:text-blue-500"
>View repository</a
>
</div>
<div
class="flex h-fit w-full flex-col items-center justify-center lg:h-[340px] lg:w-1/2 lg:items-start lg:px-10"
>
<h2 class="mb-5 text-center text-3xl font-bold">
We're Not Really Strangers
</h2>
<p
class="max-w-lg text-center text-xl text-balance lg:max-w-none lg:text-left"
>
Otherwise abbreviated as "WNRS", this is a digital
adaptation of the popular card game designed to foster
meaningful connections through engaging questions and
prompts.
</p>
<div
class="mt-5 flex w-full flex-row flex-wrap justify-center lg:justify-start"
>
<div
class="bg-react my-1 mr-1 w-fit rounded-full px-3 py-1 text-black transition-colors duration-300"
>
React
</div>
<div
class="bg-typescript my-1 mr-1 w-fit rounded-full px-3 py-1 text-white transition-colors duration-300"
>
Typescript
</div>
</div>
</div>
</div>
<div
class="mt-10 flex h-fit w-full flex-col-reverse justify-center px-10 lg:flex-row lg:px-16"
>
<div
class="flex h-fit w-full flex-col items-center justify-center lg:h-[340px] lg:w-1/2 lg:items-end lg:px-10"
>
<h2 class="mb-5 text-center text-3xl font-bold lg:text-right">
Twitch Plays X
</h2>
<p
class="max-w-lg text-center text-xl text-balance lg:max-w-none lg:text-right"
>
Allow Twitch chatters to play games such as Pokemon!
Chatters can enter messages such as "up up down down left
right B A" and the Python program will trigger the
corresponding keypresses.
</p>
<div
class="mt-5 flex w-full flex-row flex-wrap justify-center lg:justify-end"
>
<div
class="bg-python my-1 mr-1 w-fit rounded-full px-3 py-1 text-white transition-colors duration-300"
>
Python
</div>
<div
class="bg-win32api my-1 mr-1 w-fit rounded-full px-3 py-1 text-white transition-colors duration-300"
>
win32API
</div>
</div>
</div>
<div class="mb-10 flex items-center justify-center lg:hidden">
<a
href="https://github.com/liyunze-coding/TwitchPlaysX"
target="_blank"
class="rounded-xl bg-blue-600 px-5 py-3 font-bold opacity-100 transition-colors duration-300 hover:bg-white hover:text-blue-500"
>View repository</a
>
</div>
<div
class="image-container relative mb-5 flex aspect-video w-full [perspective:200px] lg:mr-5 lg:mb-0 lg:ml-auto lg:w-1/2"
>
<Image
src={TwitchPlays}
alt="Twitch Plays X"
class=`absolute max-w-full
top-1/2 left-1/2 [transform:translateX(-48%)_translateY(-48%)_translateZ(-50px)_rotateY(-3deg)] opacity-40
border-2 border-solid border-white rounded-xl`
`
width="700"
/>
<Image
src={TwitchPlays}
alt="Twitch Plays X"
width="700"
class=`absolute max-w-full
top-1/2 left-1/2
[transform:translateX(-50%)_translateY(-50%)_translateZ(-50px)_rotateY(-3deg)] opacity-100
border-2 border-solid border-white rounded-xl`
/>
<div
class="visit-div absolute top-1/2 left-1/2 aspect-video w-[700px] max-w-full [transform:translateX(-50%)_translateY(-50%)] rounded-xl border-2 border-solid border-white bg-[rgba(0,0,0,0.5)] opacity-0"
>
<a
href="https://github.com/liyunze-coding/TwitchPlaysX"
target="_blank"
class="absolute top-1/2 left-1/2 hidden [transform:translateX(-50%)_translateY(-50%)] rounded-xl bg-blue-600 px-5 py-3 font-bold opacity-100 transition-colors duration-300 hover:bg-white hover:text-blue-500 lg:block"
>View repository</a
>
</div>
</div>
</div>
</div>
</div>
<style>
.image-container img {
transition: transform 0.5s ease-in-out;
}
@media (min-width: 1025px) {
.image-container:hover > img {
transform: rotateY(0deg) rotateX(0deg) translateZ(0px)
translateX(-50%) translateY(-50%);
}
.image-container:hover > .visit-div {
opacity: 100%;
transition: opacity 0.3s ease-in-out;
transition-delay: 0.3s;
}
}
</style>

View file

@ -1,217 +0,0 @@
---
import Card from "../elements/Card.astro";
import Line from "../elements/NetworkLine.astro";
---
<div class="h-fit w-full pt-20">
<h1 class="text-center text-5xl">Skills</h1>
<div class="flex flex-col items-center">
<div class="w-[90%] pt-10 md:w-[600px]">
<Card primaryColor="#19a7ce">
<div class="px-8 py-8">
<div class="justify-left flex w-full flex-col">
<h2 class="text-2xl font-bold">Frontend Development</h2>
</div>
<hr class="my-3 w-full" />
<p class="text-left">
I started my web development journey by building
websites and widgets using vanilla HTML, CSS, Javascript
and Express. As I learnt more about the fundamentals of
web development, I delved into frontend frameworks such
as Svelte, React and Astro.
</p>
<div
class="mt-4 flex w-full flex-row flex-wrap justify-start"
>
<div
class="bg-html hover:bg-html my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
HTML
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-blue-700 px-3 py-1 text-white transition-colors duration-300 hover:bg-blue-700 md:bg-gray-500"
>
CSS
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-yellow-400 px-3 py-1 text-black transition-colors duration-300 hover:bg-yellow-400 md:bg-gray-500 md:text-white md:hover:text-black"
>
Javascript
</div>
<div
class="bg-typescript hover:bg-typescript my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500 md:text-white md:hover:text-white"
>
TypeScript
</div>
<div
class="hover:bg-svelte bg-svelte my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
Svelte
</div>
<div
class="bg-react hover:bg-react my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-black transition-colors duration-300 md:bg-gray-500 md:text-white md:hover:text-black"
>
React
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-green-500 px-3 py-1 text-black transition-colors duration-300 hover:bg-green-500 md:bg-gray-500 md:text-white md:hover:text-black"
>
Vue
</div>
<div
class="bg-wordpress hover:bg-wordpress my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
WordPress
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-white px-3 py-1 text-black transition-colors duration-300 hover:bg-white md:bg-gray-500 md:text-white md:hover:text-black"
>
Astro
</div>
<div
class="bg-htmx hover:bg-htmx my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 hover:text-white md:bg-gray-500"
>
HTMX
</div>
<div
class="bg-tailwind hover:bg-tailwind my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-black transition-colors duration-300 md:bg-gray-500 md:text-white md:hover:text-black"
>
TailwindCSS
</div>
</div>
</div>
</Card>
<Line height="50px" />
<Card primaryColor="#474F7A">
<div class="px-8 py-8">
<div class="justify-left flex w-full flex-col">
<h2 class="text-2xl font-bold">Backend Development</h2>
</div>
<hr class="my-3 w-full" />
<p class="text-left">
With experience in various programming languages, I
learnt to setup databases, implement routing and
organized my code to ensure maintainability and
scalability.
</p>
<div
class="mt-4 flex w-full flex-row flex-wrap justify-start"
>
<div
class="bg-python hover:bg-python my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
Python
</div>
<div
class="bg-csharp hover:bg-csharp my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
C#
</div>
<div
class="bg-java hover:bg-java my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
Java
</div>
<div
class="bg-kotlin hover:bg-kotlin my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
Kotlin
</div>
<div
class="bg-php hover:bg-php my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
PHP
</div>
<div
class="bg-go hover:bg-go my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-30 md:bg-gray-500"
>
Go
</div>
<div
class="bg-rust hover:bg-rust my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
Rust
</div>
<div
class="bg-postgresql hover:bg-postgresql my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
PostgreSQL
</div>
<div
class="bg-mysql hover:bg-mysql my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
MySQL
</div>
<div
class="bg-mongodb hover:bg-mongodb my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
MongoDB
</div>
</div>
</div>
</Card>
<Line height="50px" />
<Card primaryColor="#a1eebd">
<div class="px-8 py-8">
<div class="justify-left flex w-full flex-col">
<h2 class="text-2xl font-bold">Data Science</h2>
</div>
<hr class="my-3 w-full" />
<p class="text-left">
My first exposure to data science was through learning
Computer Vision. I learn how to use OpenCV in Python to
open a webcam and detect faces. Later on, I took a
Diploma course that is focused in data science, where I
learnt how to do the fundamentals of data science such
as extracting, transforming and loading data, as well as
data visualisation.
</p>
<div
class="mt-4 flex w-full flex-row flex-wrap justify-start"
>
<div
class="bg-python hover:bg-python my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
Python
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-cyan-500 px-3 py-1 text-white transition-colors duration-300 hover:bg-cyan-500 md:bg-gray-500"
>
R
</div>
<div
class="bg-opencv hover:bg-opencv my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
OpenCV
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-blue-500 px-3 py-1 text-black transition-colors duration-300 hover:bg-blue-500 md:bg-gray-500 md:text-white md:hover:text-black"
>
SAS
</div>
<div
class="bg-mysql hover:bg-mysql my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 text-white transition-colors duration-300 md:bg-gray-500"
>
MySQL
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-blue-800 px-3 py-1 text-white transition-colors duration-300 hover:bg-blue-800 md:bg-gray-500"
>
Pandas
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-green-700 px-3 py-1 text-white transition-colors duration-300 hover:bg-green-700 md:bg-gray-500"
>
Selenium
</div>
<div
class="my-1 mr-1 w-fit cursor-default rounded-full bg-gray-200 px-3 py-1 text-black transition-colors duration-300 hover:bg-gray-200 md:bg-gray-500 md:text-white md:hover:text-black"
>
BeautifulSoup4
</div>
</div>
</div>
</Card>
</div>
</div>
</div>

View file

@ -0,0 +1,72 @@
---
import Card from "../global/Card.astro";
import Line from "../global/NetworkLine.astro";
import Skill from "./Skill.astro";
---
<div id="Experience" class="h-fit">
<div class="flex flex-col items-center">
<div class="w-[90%] md:w-[600px]">
<Line height="50px" />
<Skill
title="Content Creation"
primaryColor="#9D76C1"
tags={[
{ text: "OBS", bgColor: "#141414" },
{
text: "DaVinci Resolve",
bgColor: "white",
hoverTextColor: "black",
},
{
text: "Twitch",
bgColor: "var(--color-purple-500)",
},
{
text: "YouTube",
bgColor: "red",
},
]}
>
Since I was little, I loved watching YouTube videos and the idea
of bringing joy and laughter to a wider audience. Thus, I began
my journey in content creation through YouTube videos and Twitch
streaming. I typically do coworking & study streams to keep
myself accountable and encourage productivity amongst viewers. I
also do software and game development streams where I showcase
my workflow.
</Skill>
<Line height="50px" />
<Skill
primaryColor="#9D76C1"
title="Mobile Development"
tags={[
{
text: "Android",
bgColor: "#106539",
},
{
text: "Java",
bgColor: "var(--color-java)",
},
{
text: "Kotlin",
bgColor: "var(--color-kotlin)",
},
]}
><p class="text-left">
In my Mobile App Development unit in University, I am tasked
to develop Android apps using Android Studio. The final app
project I had developed was a LLM-powered quiz app with
features such as choosing your own topics, viewing your
question attempt history afterwards, and upgrading your tier
with Google Pay.
</p>
<p class="text-left">
The marking tutor was impressed with my work, and offered me
to join a research lab because I had good potential.
</p>
</Skill>
</div>
</div>
</div>

View file

@ -0,0 +1,63 @@
---
import Card from "../global/Card.astro";
interface Tag {
text: string;
bgColor: string;
textColor?: string;
hoverTextColor?: string;
}
interface Props {
title: string;
tags?: Tag[];
primaryColor: string;
}
const { title, tags, primaryColor } = Astro.props;
---
<div class="mx-auto w-[90%] md:w-[600px]">
<Card primaryColor={primaryColor}>
<div class="px-8 py-8">
<div class="flex w-full flex-col">
<h2 class="text-2xl font-bold">{title}</h2>
</div>
<hr class="my-3 w-full" />
<p class="text-left">
<slot />
</p>
<div class="mt-5 flex w-full flex-row flex-wrap justify-start">
{
tags?.map((tag, index) => (
<div
class={`tag-${index} my-1 mr-1 w-fit cursor-default rounded-full px-3 py-1 transition-colors duration-300`}
style={`--tag-bg: ${tag.bgColor || "#000"}; --tag-text: ${tag.textColor || "#ffffff"};
--tag-hover-text: ${tag.hoverTextColor || "#ffffff"}`}
>
{tag.text}
</div>
))
}
</div>
</div>
</Card>
</div>
<style>
[class*="tag-"] {
background-color: var(--tag-bg);
color: var(--tag-text);
@media (width >= 48rem /* 768px */) {
background-color: var(--color-gray-500);
}
&:hover {
@media (hover: hover) {
background-color: var(--tag-bg);
color: var(--tag-hover-text);
}
}
}
</style>

View file

@ -0,0 +1,172 @@
---
import Card from "../global/Card.astro";
import Line from "../global/NetworkLine.astro";
import Skill from "./Skill.astro";
---
<div class="h-fit w-full pt-20">
<h1 class="text-center text-5xl">Skills</h1>
<div class="flex flex-col items-center">
<div class="w-[90%] pt-10 md:w-[600px]">
<Skill
title="Frontend Development"
primaryColor="#19a7ce"
tags={[
{
text: "HTML",
bgColor: "var(--color-html)",
},
{
text: "CSS",
bgColor: "var(--color-blue-700)",
},
{
text: "Javascript",
bgColor: "var(--color-yellow-400)",
hoverTextColor: "black",
},
{
text: "Typescript",
bgColor: "var(--color-typescript)",
},
{
text: "Svelte",
bgColor: "var(--color-svelte)",
},
{
text: "React",
bgColor: "var(--color-react)",
hoverTextColor: "black",
},
{
text: "Vue",
bgColor: "var(--color-green-500)",
hoverTextColor: "black",
},
{
text: "WordPress",
bgColor: "var(--color-wordpress)",
},
{
text: "Astro",
bgColor: "white",
hoverTextColor: "black",
},
{
text: "HTMX",
bgColor: "var(--color-htmx)",
},
{
text: "TailwindCSS",
bgColor: "var(--color-tailwind)",
hoverTextColor: "black",
},
]}
>
I started my web development journey by building websites and
widgets using vanilla HTML, CSS, Javascript and Express. As I
learnt more about the fundamentals of web development, I delved
into frontend frameworks such as Svelte, React and Astro.
</Skill>
<Line height="50px" />
<Skill
title="Backend Development"
primaryColor="#474F7A"
tags={[
{
text: "Python",
bgColor: "var(--color-python)",
},
{
text: "C#",
bgColor: "var(--color-csharp)",
},
{
text: "Java",
bgColor: "var(--color-java)",
},
{
text: "Kotlin",
bgColor: "var(--color-kotlin)",
},
{
text: "PHP",
bgColor: "var(--color-php)",
},
{
text: "Go",
bgColor: "var(--color-go)",
},
{
text: "Rust",
bgColor: "var(--color-rust)",
},
{
text: "PostgreSQL",
bgColor: "var(--color-postgresql)",
},
{
text: "MySQL",
bgColor: "var(--color-mysql)",
},
{
text: "MongoDB",
bgColor: "var(--color-mongodb)",
},
]}
>
With experience in various programming languages, I learnt to
setup databases, implement routing and organized my code to
ensure maintainability and scalability.
</Skill>
<Line height="50px" />
<Skill
title="Data Science"
primaryColor="#a1eebd"
tags={[
{
text: "Python",
bgColor: "var(--color-python)",
},
{
text: "R",
bgColor: "var(--color-cyan-500)",
},
{
text: "OpenCV",
bgColor: "var(--color-opencv)",
},
{
text: "SAS",
bgColor: "var(--color-blue-500)",
},
{
text: "MySQL",
bgColor: "var(--color-mysql)",
},
{
text: "Pandas",
bgColor: "var(--color-blue-800)",
},
{
text: "Selenium",
bgColor: "var(--color-green-700)",
},
{
text: "BeautifulSoup4",
bgColor: "white",
hoverTextColor: "black",
},
]}
>
My first exposure to data science was through learning Computer
Vision. I learn how to use OpenCV in Python to open a webcam and
detect faces. Later on, I took a Diploma course that is focused
in data science, where I learnt how to do the fundamentals of
data science such as extracting, transforming and loading data,
as well as data visualisation.
</Skill>
</div>
</div>
</div>

View file

@ -1,5 +1,5 @@
---
import Card from "../elements/Card.astro";
import Card from "../global/Card.astro";
---
<div class="flex w-full flex-col items-center justify-center">

View file

@ -1,15 +1,15 @@
---
import { getCollection } from "astro:content";
import BackToBlogs from "../../components/sections/BackToBlogs.astro";
import BackToBlogs from "../../components/blog/BackToBlogs.astro";
import Layout from "../../layouts/Layout.astro";
import Footer from "../../components/sections/FooterComponent.astro";
import Footer from "../../components/global/FooterComponent.astro";
export async function getStaticPaths() {
const blogEntries = await getCollection("blog");
return blogEntries.map((entry) => ({
params: { slug: entry.slug },
props: { entry },
}));
const blogEntries = await getCollection("blog");
return blogEntries.map((entry) => ({
params: { slug: entry.slug },
props: { entry },
}));
}
const { entry } = Astro.props;
@ -17,118 +17,118 @@ const { Content } = await entry.render();
---
<Layout
title="Blog"
description="Find out how to contact RythonDev, for sponsorship offers or collaboration opportunities!"
title="Blog"
description="Find out how to contact RythonDev, for sponsorship offers or collaboration opportunities!"
>
<BackToBlogs />
<div id="blog-content-component" class="mx-auto mt-10 pt-10">
<h1 class="text-left text-4xl">{entry.data.title}</h1>
<p class="mt-3 text-lg text-gray-200">
Published
{
new Date(entry.data.pubDate).toLocaleDateString("en-UK", {
day: "numeric",
month: "long",
year: "numeric",
})
}
</p>
<p class="text-lg text-gray-200">by {entry.data.author}</p>
<p class="text-lg text-white">{entry.data.description}</p>
<BackToBlogs />
<div id="blog-content-component" class="mx-auto mt-10 pt-10">
<h1 class="text-left text-4xl">{entry.data.title}</h1>
<p class="mt-3 text-lg text-gray-200">
Published
{
new Date(entry.data.pubDate).toLocaleDateString("en-UK", {
day: "numeric",
month: "long",
year: "numeric",
})
}
</p>
<p class="text-lg text-gray-200">by {entry.data.author}</p>
<p class="text-lg text-white">{entry.data.description}</p>
<div class="flex flex-row flex-wrap items-start justify-start">
{
entry.data.tags?.map((tag) => (
<div class="mr-2 rounded-xl border-2 border-solid border-gray-500 bg-[#282828] px-3 py-1 transition-colors duration-150 hover:border-white hover:bg-gray-300 hover:text-black">
{tag}
</div>
))
}
</div>
<div class="flex flex-row flex-wrap items-start justify-start">
{
entry.data.tags?.map((tag) => (
<div class="mr-2 rounded-xl border-2 border-solid border-gray-500 bg-[#282828] px-3 py-1 transition-colors duration-150 hover:border-white hover:bg-gray-300 hover:text-black">
{tag}
</div>
))
}
</div>
<hr class="my-5" />
<hr class="my-5" />
<Content />
</div>
<div class="mt-10">
<Footer />
</div>
<Content />
</div>
<div class="mt-10">
<Footer />
</div>
</Layout>
<style is:inline>
#blog-content-component {
width: clamp(310px, 60vw, 800px);
}
#blog-content-component {
width: clamp(310px, 60vw, 800px);
}
a:not(#navbar-div a) {
color: lightskyblue;
text-decoration: underline;
cursor: pointer;
}
a:not(#navbar-div a) {
color: lightskyblue;
text-decoration: underline;
cursor: pointer;
}
p {
display: block;
font-size: 1.1rem;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
}
p {
display: block;
font-size: 1.1rem;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
}
h1 {
display: block;
font-size: 2em;
margin-top: 0.67em;
margin-bottom: 0.67em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
}
h1 {
display: block;
font-size: 2em;
margin-top: 0.67em;
margin-bottom: 0.67em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
}
h2 {
display: block;
font-size: 1.5em;
margin-top: 0.83em;
margin-bottom: 0.83em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
}
h2 {
display: block;
font-size: 1.5em;
margin-top: 0.83em;
margin-bottom: 0.83em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
}
h3 {
display: block;
font-size: 1.17em;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
}
h3 {
display: block;
font-size: 1.17em;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
}
ul {
display: block;
list-style-type: disc;
margin-left: 0;
margin-right: 0;
margin-bottom: 0.5em;
padding-left: 40px;
}
ul {
display: block;
list-style-type: disc;
margin-left: 0;
margin-right: 0;
margin-bottom: 0.5em;
padding-left: 40px;
}
ul:not(ul ul) {
margin-top: 0.5em;
}
ul:not(ul ul) {
margin-top: 0.5em;
}
li {
display: list-item;
}
li {
display: list-item;
}
ol {
display: block;
list-style-type: decimal;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
padding-left: 40px;
}
ol {
display: block;
list-style-type: decimal;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
padding-left: 40px;
}
</style>

View file

@ -1,82 +1,81 @@
---
import NavBar from "../../components/sections/NavBar.astro";
import Layout from "../../layouts/Layout.astro";
import Card from "../../components/elements/Card.astro";
import Footer from "../../components/sections/FooterComponent.astro";
import Card from "../../components/global/Card.astro";
import Footer from "../../components/global/FooterComponent.astro";
import { getCollection } from "astro:content";
const blogPosts = await getCollection("blog");
---
<Layout
title="Blog"
description="Find out how to contact RythonDev, for sponsorship offers or collaboration opportunities!"
title="Blog"
description="Find out how to contact RythonDev, for sponsorship offers or collaboration opportunities!"
>
<div id="blog-component" class="mt-10 pt-20">
<h1 class="text-center text-5xl">Blog</h1>
<div class="mt-10 flex flex-col items-center justify-center">
<div style="width: clamp(310px, 50vw, 800px);" class="mb-10">
<p class="text-center text-lg">
This is where I upload my blogs. No paywalls, no ads, no
bullshit.
</p>
</div>
<div id="blog-component" class="mt-10 pt-20">
<h1 class="text-center text-5xl">Blog</h1>
<div class="mt-10 flex flex-col items-center justify-center">
<div style="width: clamp(310px, 50vw, 800px);" class="mb-10">
<p class="text-center text-lg">
This is where I upload my blogs. No paywalls, no ads, no
bullshit.
</p>
</div>
<!-- Series of blog posts -->
<div style="width: clamp(310px, 50vw, 800px);">
{
blogPosts.map((blog) => (
<a class="group mb-5" href={`/blog/${blog.slug}`}>
<Card
primaryColor={
blog.data.color ?? "rgba(0,0,0,0)"
}
pixelHeight="50px"
>
<div class="card-content relative px-8 py-3 text-left">
<h2 class="mb-1 text-xl font-bold">
{blog.data.title}
</h2>
<p class="line-clamp-2">
{blog.data.description}
</p>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
class="absolute right-3 top-3 size-6 stroke-white transition-all duration-150 group-hover:right-2 group-hover:top-2 group-hover:stroke-green-400"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25"
/>
</svg>
</div>
</Card>
</a>
))
}
</div>
</div>
</div>
<div class="mt-10">
<Footer />
</div>
<!-- Series of blog posts -->
<div style="width: clamp(310px, 50vw, 800px);">
{
blogPosts.map((blog) => (
<a class="group mb-5" href={`/blog/${blog.slug}`}>
<Card
primaryColor={
blog.data.color ?? "rgba(0,0,0,0)"
}
pixelHeight="50px"
>
<div class="card-content relative px-8 py-3 text-left">
<h2 class="mb-1 text-xl font-bold">
{blog.data.title}
</h2>
<p class="line-clamp-2">
{blog.data.description}
</p>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
class="absolute top-3 right-3 size-6 stroke-white transition-all duration-150 group-hover:top-2 group-hover:right-2 group-hover:stroke-green-400"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25"
/>
</svg>
</div>
</Card>
</a>
))
}
</div>
</div>
</div>
<div class="mt-10">
<Footer />
</div>
</Layout>
<style>
.card-content {
display: flex;
flex-direction: column;
background-image: radial-gradient(
rgba(255, 255, 255, 0.1) 1px,
transparent 1px
);
background-position: 50% 50%;
background-size: 1.1rem 1.1rem;
border-radius: 1.25rem;
overflow: hidden;
}
.card-content {
display: flex;
flex-direction: column;
background-image: radial-gradient(
rgba(255, 255, 255, 0.1) 1px,
transparent 1px
);
background-position: 50% 50%;
background-size: 1.1rem 1.1rem;
border-radius: 1.25rem;
overflow: hidden;
}
</style>

View file

@ -1,9 +1,9 @@
---
import NavBar from "../components/sections/NavBar.astro";
import NavBar from "../components/global/NavBar.astro";
import Layout from "../layouts/Layout.astro";
import ContactComponent from "../components/sections/ContactComponent.svelte";
import Card from "../components/elements/Card.astro";
import Footer from "../components/sections/FooterComponent.astro";
import ContactComponent from "../components/contact/ContactComponent.svelte";
import Card from "../components/global/Card.astro";
import Footer from "../components/global/FooterComponent.astro";
---
<Layout

View file

@ -1,19 +1,19 @@
---
import NavBar from "../components/sections/NavBar.astro";
import NavBar from "../components/global/NavBar.astro";
import Layout from "../layouts/Layout.astro";
import EducationComponent from "../components/sections/ExperienceComponent.astro";
import MoreExperience from "../components/sections/MoreExperience.astro";
import Footer from "../components/sections/FooterComponent.astro";
import EducationComponent from "../components/experience/ExperienceComponent.astro";
import MoreExperience from "../components/experience/MoreExperience.astro";
import Footer from "../components/global/FooterComponent.astro";
---
<Layout
title="Experience"
description="Find out RythonDev's previous education"
title="Experience"
description="Find out RythonDev's previous education"
>
<NavBar />
<div id="Experience" class="py-20">
<EducationComponent />
<MoreExperience />
</div>
<Footer />
<NavBar />
<div id="Experience" class="py-20">
<EducationComponent />
<MoreExperience />
</div>
<Footer />
</Layout>

View file

@ -1,92 +1,92 @@
---
import Layout from "../layouts/Layout.astro";
import Card from "../components/elements/Card.astro";
import Footer from "../components/sections/FooterComponent.astro";
import Card from "../components/global/Card.astro";
import Footer from "../components/global/FooterComponent.astro";
---
<Layout title="Socials" description="Check out Ryan's socials">
<div class="mx-auto my-10 w-[90%] max-w-full md:w-1/2">
<Card primaryColor="aquamarine">
<div class="card-content px-4 py-4 md:px-8 md:py-8">
<h1 class="text-center text-3xl font-bold">
Frequently Asked Questions
</h1>
<hr class="my-2" />
<!-- Who are you? -->
<h2 class="text-xl font-bold">Who are you?</h2>
<p>
I'm Ryan, I am a software developer and a coworking & study
streamer.
<br />
<br />
See my website <a
target="_blank"
href="https://rython.dev/"
class="text-blue-400 underline">here</a
> to learn more about me, including my software development portfolio
and my content creation projects.
</p>
<hr class="my-2" />
<h2 class="text-xl font-bold">
Where are you from? What languages do you speak?
</h2>
<p>
I'm born and raised in Malaysia, studying in Australia. I
speak English, Mandarin Chinese, and some Malay. I can read
both traditional and simplified Chinese characters.
</p>
<hr class="my-2" />
<!-- How to pronounce? -->
<h2 class="text-xl font-bold">
How to pronounce your username?
</h2>
<p>
Try to pronounce Python, and then replace the "Py" with
"Ry". You can also call me "Ry" or "Ryan" if you prefer.
</p>
<hr class="my-2" />
<!-- What is a coworking stream? -->
<h2 class="text-xl font-bold">What is a coworking stream?</h2>
<p>
That question is answered <a
target="_blank"
class="text-blue-400 underline"
href="https://coworking-guide.vercel.app/get-started/introduction#what-are-coworking-streams"
>here</a
>.
</p>
<hr class="my-2" />
<!-- What is a coworking stream? -->
<h2 class="text-xl font-bold">
Why are you muted? Why aren't you reading chat?
</h2>
<p>
During work time, I am muted and not reading chat to focus
on my work. I will try to catch up on chat during break
time.
</p>
<hr class="my-2" />
<!-- What is a coworking stream? -->
<h2 class="text-xl font-bold">Is that a keychron?</h2>
<p>No. It's an Epomaker GK64x modded with black switches.</p>
<hr class="my-2" />
</div>
</Card>
<Footer />
</div>
<style>
.card-content {
display: flex;
flex-direction: column;
gap: 1rem;
background-image: radial-gradient(
rgba(255, 255, 255, 0.1) 1px,
transparent 1px
);
background-position: 50% 50%;
background-size: 1.1rem 1.1rem;
border-radius: 1.25rem;
overflow: hidden;
}
</style>
<div class="mx-auto my-10 w-[90%] max-w-full md:w-1/2">
<Card primaryColor="aquamarine">
<div class="card-content px-4 py-4 md:px-8 md:py-8">
<h1 class="text-center text-3xl font-bold">
Frequently Asked Questions
</h1>
<hr class="my-2" />
<!-- Who are you? -->
<h2 class="text-xl font-bold">Who are you?</h2>
<p>
I'm Ryan, I am a software developer and a coworking & study
streamer.
<br />
<br />
See my website <a
target="_blank"
href="https://rython.dev/"
class="text-blue-400 underline">here</a
> to learn more about me, including my software development portfolio
and my content creation projects.
</p>
<hr class="my-2" />
<h2 class="text-xl font-bold">
Where are you from? What languages do you speak?
</h2>
<p>
I'm born and raised in Malaysia, studying in Australia. I
speak English, Mandarin Chinese, and some Malay. I can read
both traditional and simplified Chinese characters.
</p>
<hr class="my-2" />
<!-- How to pronounce? -->
<h2 class="text-xl font-bold">
How to pronounce your username?
</h2>
<p>
Try to pronounce Python, and then replace the "Py" with
"Ry". You can also call me "Ry" or "Ryan" if you prefer.
</p>
<hr class="my-2" />
<!-- What is a coworking stream? -->
<h2 class="text-xl font-bold">What is a coworking stream?</h2>
<p>
That question is answered <a
target="_blank"
class="text-blue-400 underline"
href="https://coworking-guide.vercel.app/get-started/introduction#what-are-coworking-streams"
>here</a
>.
</p>
<hr class="my-2" />
<!-- What is a coworking stream? -->
<h2 class="text-xl font-bold">
Why are you muted? Why aren't you reading chat?
</h2>
<p>
During work time, I am muted and not reading chat to focus
on my work. I will try to catch up on chat during break
time.
</p>
<hr class="my-2" />
<!-- What is a coworking stream? -->
<h2 class="text-xl font-bold">Is that a keychron?</h2>
<p>No. It's an Epomaker GK64x modded with black switches.</p>
<hr class="my-2" />
</div>
</Card>
<Footer />
</div>
<style>
.card-content {
display: flex;
flex-direction: column;
gap: 1rem;
background-image: radial-gradient(
rgba(255, 255, 255, 0.1) 1px,
transparent 1px
);
background-position: 50% 50%;
background-size: 1.1rem 1.1rem;
border-radius: 1.25rem;
overflow: hidden;
}
</style>
</Layout>

View file

@ -1,61 +1,61 @@
---
import NavBar from "../components/sections/NavBar.astro";
import NavBar from "../components/global/NavBar.astro";
import Layout from "../layouts/Layout.astro";
import NetworkLine from "../components/elements/NetworkLine.astro";
import WhatIDo from "../components/sections/WhatIDoComponent.astro";
import Intro from "../components/sections/IntroComponent.svelte";
import Projects from "../components/sections/ProjectsComponent.astro";
import Experience from "../components/sections/ExperienceComponent.astro";
import Skills from "../components/sections/SkillsComponent.astro";
import Contact from "../components/sections/ContactComponent.svelte";
import Card from "../components/elements/Card.astro";
import Footer from "../components/sections/FooterComponent.astro";
import NetworkLine from "../components/global/NetworkLine.astro";
import WhatIDo from "../components/what-i-do/WhatIDoComponent.astro";
import Intro from "../components/home/IntroComponent.svelte";
import Projects from "../components/projects/ProjectsComponent.astro";
import Experience from "../components/experience/ExperienceComponent.astro";
import Skills from "../components/skills/SkillsComponent.astro";
import Contact from "../components/contact/ContactComponent.svelte";
import Card from "../components/global/Card.astro";
import Footer from "../components/global/FooterComponent.astro";
---
<Layout
title="Ryan's Portfolio"
description="Ryan is a software developer, streamer and Computer Science undergraduate. Learn more about him and his skills here!"
title="Ryan's Portfolio"
description="Ryan is a software developer, streamer and Computer Science undergraduate. Learn more about him and his skills here!"
>
<NavBar />
<div id="home" class="flex items-center justify-center pt-20">
<div class="w-[90%] max-w-[1080px] lg:w-1/2 xl:w-1/2">
<Card
bgColor="#252525"
primaryColor="#BEADFA"
className="animate-fadeIn"
>
<Intro client:load />
</Card>
</div>
</div>
<NetworkLine height="70px" />
<div id="what-i-do">
<div class="mx-auto mb-10 h-[1px] w-1/3 bg-[#404040]"></div>
<WhatIDo />
</div>
<div id="projects">
<div class="pt-20">
<h1 class="mb-10 text-center text-5xl">Projects</h1>
<Projects />
</div>
</div>
<div id="skills">
<Skills />
</div>
<div id="education" class="py-20">
<Experience />
</div>
<div id="contact">
<Contact />
</div>
<Footer />
<NavBar />
<div id="home" class="flex items-center justify-center pt-20">
<div class="w-[90%] max-w-[1080px] lg:w-1/2 xl:w-1/2">
<Card
bgColor="#252525"
primaryColor="#BEADFA"
className="animate-fadeIn"
>
<Intro client:load />
</Card>
</div>
</div>
<NetworkLine height="70px" />
<div id="what-i-do">
<div class="mx-auto mb-10 h-[1px] w-1/3 bg-[#404040]"></div>
<WhatIDo />
</div>
<div id="projects">
<div class="pt-20">
<h1 class="mb-10 text-center text-5xl">Projects</h1>
<Projects />
</div>
</div>
<div id="skills">
<Skills />
</div>
<div id="education" class="py-20">
<Experience />
</div>
<div id="contact">
<Contact />
</div>
<Footer />
</Layout>
<script is:inline>
location.search.includes("?uwu") &&
document.documentElement.classList.add("uwu");
location.search.includes("?uwu") &&
document.documentElement.classList.add("uwu");
</script>
<style is:global>
.uwu #uwu {
display: flex;
}
.uwu #uwu {
display: flex;
}
</style>

View file

@ -1,108 +1,108 @@
---
import NavBar from "../components/sections/NavBar.astro";
import NavBar from "../components/global/NavBar.astro";
import Layout from "../layouts/Layout.astro";
import ProjectsComponent from "../components/sections/ProjectsComponent.astro";
import MoreProjects from "../components/sections/MoreProjects.svelte";
import Footer from "../components/sections/FooterComponent.astro";
import ProjectsComponent from "../components/projects/ProjectsComponent.astro";
import MoreProjects from "../components/projects/MoreProjects.svelte";
import Footer from "../components/global/FooterComponent.astro";
---
<Layout title="Projects" description="View what projects RythonDev has made">
<NavBar />
<div id="projects" class="pt-20">
<h1 class="mt-10 text-center text-5xl">Projects</h1>
<!-- other projects -->
<MoreProjects client:load />
</div>
<div class="pb-20">
<ProjectsComponent />
</div>
<Footer />
<NavBar />
<div id="projects" class="pt-20">
<h1 class="mt-10 text-center text-5xl">Projects</h1>
<!-- other projects -->
<MoreProjects client:load />
</div>
<div class="pb-20">
<ProjectsComponent />
</div>
<Footer />
</Layout>
<style>
.image-container img,
.image-container video,
.image-container .task-widget {
transition: transform 0.5s ease-in-out;
}
@media (min-width: 1025px) {
.image-container:hover > img,
.image-container:hover > video,
.image-container:hover > .task-widget {
transform: rotateY(0deg) rotateX(0deg) translateZ(0px)
translateX(-50%) translateY(-50%);
}
.image-container img,
.image-container video,
.image-container .task-widget {
transition: transform 0.5s ease-in-out;
}
@media (min-width: 1025px) {
.image-container:hover > img,
.image-container:hover > video,
.image-container:hover > .task-widget {
transform: rotateY(0deg) rotateX(0deg) translateZ(0px)
translateX(-50%) translateY(-50%);
}
.image-container:hover > .visit-div {
opacity: 100%;
transition: opacity 0.3s ease-in-out;
transition-delay: 0.3s;
}
}
.image-container:hover > .visit-div {
opacity: 100%;
transition: opacity 0.3s ease-in-out;
transition-delay: 0.3s;
}
}
.primary {
animation: primary 30s linear infinite;
}
.primary {
animation: primary 30s linear infinite;
}
.secondary {
animation: secondary 30s linear infinite;
}
.secondary {
animation: secondary 30s linear infinite;
}
@keyframes primary {
from {
transform: translateY(0);
}
to {
transform: translateY(-2175px);
}
}
@keyframes primary {
from {
transform: translateY(0);
}
to {
transform: translateY(-2175px);
}
}
@keyframes secondary {
from {
transform: translateY(2175px);
}
to {
transform: translateY(0);
}
}
@keyframes secondary {
from {
transform: translateY(2175px);
}
to {
transform: translateY(0);
}
}
</style>
<script is:inline>
document.addEventListener("DOMContentLoaded", () => {
const videos = document.querySelectorAll(".playable");
document.addEventListener("DOMContentLoaded", () => {
const videos = document.querySelectorAll(".playable");
videos.forEach((video) => {
// Ensure the video element supports play and pause methods
if (
typeof video.play === "function" &&
typeof video.pause === "function"
) {
video.addEventListener("mouseenter", () => {
video.play();
});
videos.forEach((video) => {
// Ensure the video element supports play and pause methods
if (
typeof video.play === "function" &&
typeof video.pause === "function"
) {
video.addEventListener("mouseenter", () => {
video.play();
});
video.addEventListener("mouseleave", () => {
video.pause();
video.currentTime = 0;
});
}
video.addEventListener("mouseleave", () => {
video.pause();
video.currentTime = 0;
});
}
videos.forEach((video) => {
if (window.innerWidth < 1025) {
video.muted = true;
video.play();
}
});
});
videos.forEach((video) => {
if (window.innerWidth < 1025) {
video.muted = true;
video.play();
}
});
});
// on screensize change
window.addEventListener("resize", () => {
videos.forEach((video) => {
if (window.innerWidth < 1025) {
video.muted = true;
// video.play();
}
});
});
});
// on screensize change
window.addEventListener("resize", () => {
videos.forEach((video) => {
if (window.innerWidth < 1025) {
video.muted = true;
// video.play();
}
});
});
});
</script>

View file

@ -1,9 +1,9 @@
---
import NavBar from "../components/sections/NavBar.astro";
import NavBar from "../components/global/NavBar.astro";
import Layout from "../layouts/Layout.astro";
import SkillsComponent from "../components/sections/SkillsComponent.astro";
import MoreSkills from "../components/sections/MoreSkills.astro";
import Footer from "../components/sections/FooterComponent.astro";
import SkillsComponent from "../components/skills/SkillsComponent.astro";
import MoreSkills from "../components/skills/MoreSkills.astro";
import Footer from "../components/global/FooterComponent.astro";
---
<Layout

View file

@ -1,7 +1,7 @@
---
import Layout from "../layouts/Layout.astro";
import StreamScheduleComponent from "../components/sections/StreamSchedule.svelte";
import Footer from "../components/sections/FooterComponent.astro";
import StreamScheduleComponent from "../components/socials/StreamSchedule.svelte";
import Footer from "../components/global/FooterComponent.astro";
import { Image } from "astro:assets";
import profile from "./_images/profile.webp";
import WebsiteIcon from "./_images/website-icon.svg";

View file

@ -1,10 +1,10 @@
---
import NavBar from "../components/sections/NavBar.astro";
import NavBar from "../components/global/NavBar.astro";
import Layout from "../layouts/Layout.astro";
import WhatIDoComponent from "../components/sections/WhatIDoComponent.astro";
import Card from "../components/elements/Card.astro";
import Line from "../components/elements/NetworkLine.astro";
import Footer from "../components/sections/FooterComponent.astro";
import WhatIDoComponent from "../components/what-i-do/WhatIDoComponent.astro";
import Card from "../components/global/Card.astro";
import Line from "../components/global/NetworkLine.astro";
import Footer from "../components/global/FooterComponent.astro";
---
<Layout

View file

@ -1,30 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
theme: {
extend: {
keyframes: {
gradient: {
"0%": {
"background-position": "0% 50%",
},
"50%": {
"background-position": "100% 50%",
},
"100%": {
"background-position": "0% 50%",
},
},
fadeIn: {
"0%": { opacity: 0 },
"100%": { opacity: 1 },
},
},
animation: {
gradient: "gradient 15s ease infinite",
fadeIn: "fadeIn 1s ease",
},
},
},
plugins: [],
};