Update portfolio, roles and photo

This commit is contained in:
SirBlob committed 2026-10-31 21:17:42 -04:00
1 parent 7845cb5e6f
commit 4b271a08ab
7 files changed
+104 -11

No files matched your search

+2 -2
View File
@@ -26,8 +26,8 @@
"links": [{ "label": "Program", "url": "https://accessacademy.cehd.gmu.edu/ai-summer-camp" }]
},
{
"role": "Lead Software Engineer",
"organization": "Raytheon Autonomous Vehicle Competition",
"role": "Team Lead, RAVC Team",
"organization": "Raytheon Autonomous Vehicle Competition (RAVC)",
"period": "Dec 2025 – May 2026",
"highlights": [
"Beat four competing universities including Virginia Tech.",
+3 -2
View File
@@ -1,6 +1,7 @@
[
{ "role": "Team Lead", "organization": "GMU RAVC/ARC Team", "url": "https://gmu.autonomousrobotics.club/" },
{ "role": "President", "organization": "GMU Minecraft Club", "url": "https://gmmc.sirblob.co/" },
{ "role": "Team Lead", "organization": "GMU RAVC Team", "url": "https://gmu.autonomousrobotics.club/" },
{ "role": "Secretary", "organization": "GMU Autonomous Robotics Club (ARC)", "url": "https://gmu.autonomousrobotics.club/" },
{ "role": "President", "organization": "GMU Minecraft Club", "url": "https://gmmc.club/" },
{ "role": "Eagle Scout", "organization": "BSA" },
{ "role": "Volunteer", "organization": "Fairfax County CERT" }
]
+1
View File
@@ -6,6 +6,7 @@
"title": "Computer Science Student",
"email": "sirblob0@gmail.com",
"avatar": "/blob_nerd.png",
"photo": "/portfolio-photo.jpg",
"bio": "An engineer who loves making things. I build fun coding projects, compete in hackathons and robotics competitions, and enjoy games like Minecraft and Pokémon TCG Live. I'm interested in Open Source, Robotics, Embedded Systems, and AI/ML.",
"tagline": "My passion is using Computer Science with practical Engineering to enhance technology for the future.",
"education": {
+15 -3
View File
@@ -1,11 +1,18 @@
<script lang="ts">
import { profile } from '#lib/content';
let { heading, subheading, text }: { heading: string; subheading: string; text: string } = $props();
let {
heading,
subheading,
text,
image = profile.avatar
}: { heading: string; subheading: string; text: string; image?: string } = $props();
const isPixelAvatar = $derived(image === profile.avatar);
</script>
<div class="profile-intro">
<img src={profile.avatar} alt={profile.displayName} />
<img src={image} alt={profile.displayName} class:pixelated={isPixelAvatar} />
<div class="details">
<h1>{heading}</h1>
<div class="subheading">{subheading}</div>
@@ -24,10 +31,15 @@
img {
width: 160px;
image-rendering: pixelated;
aspect-ratio: 1;
object-fit: cover;
border: 1px solid color-mix(in srgb, var(--foreground) 25%, transparent);
}
img.pixelated {
image-rendering: pixelated;
}
.details {
flex: 1;
min-width: 240px;
+10
View File
@@ -0,0 +1,10 @@
import { findProjectCategory } from '#lib/content';
import { getRepoStats } from '#lib/server/github';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async () => {
const openSourceProjects = findProjectCategory('opensource')?.projects ?? [];
const codeUrls = openSourceProjects.flatMap((project) => (project.links.code ? [project.links.code] : []));
return { repoStats: await getRepoStats(codeUrls) };
};
+73 -4
View File
@@ -1,14 +1,27 @@
<script lang="ts">
import Icon from '@iconify/svelte';
import { experience, findProjectCategory, leadership, profile } from '#lib/content';
import { experience, findProjectCategory, leadership, profile, type Project } from '#lib/content';
import PageHeader from '#lib/components/ui/PageHeader.svelte';
import ProfileIntro from '#lib/components/ui/ProfileIntro.svelte';
import SectionNav from '#lib/components/ui/SectionNav.svelte';
import Section from '#lib/components/ui/Section.svelte';
import LinkButton from '#lib/components/ui/LinkButton.svelte';
import Tag from '#lib/components/ui/Tag.svelte';
import type { PageProps } from './$types';
let { data }: PageProps = $props();
const openSourceProjects = findProjectCategory('opensource')?.projects ?? [];
const openSourcePagePath = '/projects/opensource';
function projectLinks(links: Project['links']) {
return [
{ label: 'Code', url: links.code },
{ label: 'Docs', url: links.docs },
{ label: 'Demo', url: links.demo },
{ label: 'Package', url: links.package }
].filter((link): link is { label: string; url: string } => !!link.url);
}
const skillColors = ['cyan', 'magenta', 'green', 'yellow', 'orange', 'blue'];
const sections = [
@@ -22,9 +35,9 @@
</script>
<div class="page">
<PageHeader command="cat ~/portfolio.md" title="Portfolio" subtitle="Education, experience, skills, projects and leadership of {profile.name}." />
<PageHeader command="cat ~/portfolio.md" title="Portfolio" />
<ProfileIntro heading={profile.name} subheading={profile.title} text={profile.tagline} />
<ProfileIntro heading={profile.name} subheading={profile.title} text={profile.tagline} image={profile.photo} />
<SectionNav {sections} />
<Section title="Contact" id="contact">
@@ -89,17 +102,38 @@
<Section title="Projects" id="projects">
{#each openSourceProjects as project (project.name)}
<article class="project">
<div class="project-heading">
<a class="project-name" href={project.links.code ?? project.links.demo} target="_blank" rel="noopener noreferrer">&gt; {project.name}</a>
{#if project.version}<span class="version">v{project.version}</span>{/if}
<span class="muted"> - {project.description}</span>
{#if project.period}<span class="muted project-period">{project.period}</span>{/if}
{#if project.links.code && data.repoStats[project.links.code]}
{@const stats = data.repoStats[project.links.code]}
<a class="repo-stat stars" href="{project.links.code}/stargazers" target="_blank" rel="noopener noreferrer" title="GitHub stars">
<Icon icon="mdi:star-outline" width="15" />{stats.stars}
</a>
<a class="repo-stat forks" href="{project.links.code}/forks" target="_blank" rel="noopener noreferrer" title="GitHub forks">
<Icon icon="mdi:source-fork" width="15" />{stats.forks}
</a>
{/if}
</div>
<p class="project-description">{project.description}</p>
<div class="tags">
{#each project.tags as tag, index (tag)}
<Tag label={tag} colorIndex={index} />
{/each}
</div>
<div class="entry-links">
{#each projectLinks(project.links) as projectLink (projectLink.url)}
<a href={projectLink.url} target="_blank" rel="noopener noreferrer">{projectLink.label}</a>
{/each}
<a href={openSourcePagePath}>More info</a>
</div>
</article>
{/each}
<div class="button-row">
<LinkButton href={openSourcePagePath} icon="ph:git-branch-duotone">Open source projects</LinkButton>
<LinkButton href="/projects" icon="mdi:folder">All projects</LinkButton>
</div>
</Section>
<Section title="Leadership" id="leadership">
@@ -206,6 +240,41 @@
margin-top: 0.35rem;
}
.project-heading {
display: flex;
flex-wrap: wrap;
align-items: baseline;
}
.project-period {
margin-left: 0.75rem;
font-size: 0.85rem;
}
.repo-stat {
display: inline-flex;
align-items: center;
gap: 0.2rem;
margin-left: 0.75rem;
font-size: 0.85rem;
}
.repo-stat.stars {
color: var(--yellow);
}
.repo-stat.forks {
color: var(--cyan);
}
.repo-stat:hover {
text-decoration: underline;
}
.project-description {
margin: 0.25rem 0 0;
}
.leadership {
margin: 0;
padding-left: 1.25rem;
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB