diff --git a/package.json b/package.json index 6a81f91..561f53b 100644 --- a/package.json +++ b/package.json @@ -10,27 +10,27 @@ "start": "vite build && bun server/server.js" }, "devDependencies": { - "@sveltejs/adapter-node": "^5.4.0", - "@sveltejs/kit": "^2.49.2", - "@sveltejs/vite-plugin-svelte": "^6.2.1", + "@sveltejs/adapter-node": "^5.5.2", + "@sveltejs/kit": "^2.50.1", + "@sveltejs/vite-plugin-svelte": "^6.2.4", "@tailwindcss/forms": "^0.5.11", "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "^4.1.18", - "svelte": "^5.46.0", - "svelte-check": "^4.3.4", + "svelte": "^5.49.1", + "svelte-check": "^4.3.6", "tailwindcss": "^4.1.18", "typescript": "^5.9.3", - "vite": "^7.3.0" + "vite": "^7.3.1" }, "dependencies": { - "@iconify/svelte": "^5.1.0", + "@iconify/svelte": "^5.2.1", "@threlte/core": "^8.3.1", "@types/three": "^0.181.0", - "cors": "^2.8.5", + "cors": "^2.8.6", "discord.js": "^14.25.1", "dotenv": "^17.2.3", "express": "^5.2.1", - "hotkeys-js": "^4.0.0-beta.7", + "hotkeys-js": "^4.0.0", "play-dl": "^1.9.7", "three": "^0.181.2" } diff --git a/src/lib/config/content.ts b/src/lib/config/content.ts index 179a4ed..c4919f8 100644 --- a/src/lib/config/content.ts +++ b/src/lib/config/content.ts @@ -2,7 +2,47 @@ // PROJECTS // ============================================================================ -export interface Project { +export interface OpenSourceProject { + name: string; + description: string; + tech: string[]; + github?: string; + live?: string; + image?: string; +} + + +export const openSourceProjects: OpenSourceProject[] = [ + { + name: 'Pkit', + description: 'CLI toolkit and utilities (Rust project) — small developer-focused CLI.', + tech: ['Rust', 'CLI'], + live: 'https://pkit.sirblob.co/', + github: 'https://github.com/dead-projects-inc/pkit-cli', + image: 'https://icons.veryicon.com/png/o/business/vscode-program-item-icon/rust-1.png', + }, + { + name: 'OBookLLM', + description: "OBookLLM is a powerful, self-hosted, offline-capable alternative to NotebookLLM.", + tech: ['Python', 'LLM', 'AI', 'NotebookLLM'], + github: 'https://github.com/SirBlobby/OBookLLM', + image: 'https://upload.wikimedia.org/wikipedia/commons/c/c3/Python-logo-notext.svg', + }, + { + name: 'Filaprint', + description: 'Filaprint is a web application to help 3D printing enthusiasts manage their filament inventory, track print jobs, view 3D models, and calculate costs and energy usage.', + tech: ['Sveltekit', 'Management', '3D Printing'], + github: 'https://github.com/SirBlobby/Filaprint', + image: 'https://repository-images.githubusercontent.com/354583933/72c58c80-9727-11eb-98b2-f352fded32b9', + } +]; + +// ============================================================================ +// PACKAGES +// ============================================================================ + + +export interface PackageProject { name: string; description: string; tech: string[]; @@ -12,7 +52,7 @@ export interface Project { featured?: boolean; } -export const projects: Project[] = [ +export const packageProjects: PackageProject[] = [ { name: 'PokemonTCGAPI', description: 'UnOfficial NPM package wrapper for the PokemonTCG API.', @@ -36,15 +76,6 @@ export const projects: Project[] = [ live: 'https://www.npmjs.com/package/@sirblob/mcp-selenium', image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/1200px-Npm-logo.svg.png', featured: true - }, - { - name: 'Pkit', - description: 'CLI toolkit and utilities (Rust project) — small developer-focused CLI.', - tech: ['Rust', 'CLI'], - live: 'https://pkit.sirblob.co/', - github: 'https://github.com/dead-projects-inc/pkit-cli', - image: 'https://icons.veryicon.com/png/o/business/vscode-program-item-icon/rust-1.png', - featured: false } ]; @@ -91,7 +122,7 @@ export const models: Model3D[] = [ export type Card = { title: string; description: string; - image?: string; + image?: string | null; link?: string; repo?: string; devpost?: string; @@ -197,8 +228,22 @@ export const cards: Card[] = [ location: "Blacksburg, VA", year: "2025", tags: ["react", "node.js", "python", "mongodb", "geospatial", "mapbox"], - featured: true, + featured: false, liveWarning: true + }, + { + image: "/img/hoya26.png", + title: "Ethix", + description: "A sustainability platform that helps users detect and report greenwashing - misleading environmental claims made by companies and products.", + repo: "https://github.com/SirBlobby/Hoya26", + devpost: "https://devpost.com/software/ethix", + link: "https://ethix.sirblob.co/", + hackathonName: "HoyaHax 2026", + university: "Georgetown University", + location: "Washington, D.C.", + year: "2026", + tags: ["Svelte", "TypeScript", "Python", "Flask", "Tailwind", "Sustainability"], + featured: true } ]; diff --git a/src/lib/config/index.ts b/src/lib/config/index.ts index 3c21535..bdcfb6d 100644 --- a/src/lib/config/index.ts +++ b/src/lib/config/index.ts @@ -26,8 +26,8 @@ export { } from './theme'; // Content: projects, models, hackathon cards -export type { Project, Model3D, Card } from './content'; -export { projects, models, cards, sortedCards } from './content'; +export type { OpenSourceProject, PackageProject, Model3D, Card } from './content'; +export { openSourceProjects, packageProjects, models, cards, sortedCards } from './content'; // Terminal settings, TUI styling, speed presets, model viewer, particles, shortcuts export type { SpeedPreset, TerminalSettings } from './terminal'; diff --git a/src/lib/pages/about.ts b/src/lib/pages/about.ts index 1d27867..1933dd8 100644 --- a/src/lib/pages/about.ts +++ b/src/lib/pages/about.ts @@ -1,20 +1,20 @@ import type { TerminalLine } from '$lib/components/tui/types'; import { user } from '$lib/config'; -const artist = [ - { - name: 'Noah Floersch', - url: 'https://music.youtube.com/channel/UCgPjhKqPg5cPxErhqnoPlWg?si=B7GEz2QMNtrgnAbz' - }, - { - name: 'Laufey', - url: 'https://music.youtube.com/channel/UCJtROTPxo3qnEzww8JyDxuA?si=WwgYFkoccnXtJ6Im' - }, - { - name: 'Tate McRae', - url: 'https://music.youtube.com/channel/UCz86IA7ooUetFnUGa_YlsVw?si=A1t0-hLHswhbEG0U' - } -] +// const artist = [ +// { +// name: 'Noah Floersch', +// url: 'https://music.youtube.com/channel/UCgPjhKqPg5cPxErhqnoPlWg?si=B7GEz2QMNtrgnAbz' +// }, +// { +// name: 'Laufey', +// url: 'https://music.youtube.com/channel/UCJtROTPxo3qnEzww8JyDxuA?si=WwgYFkoccnXtJ6Im' +// }, +// { +// name: 'Tate McRae', +// url: 'https://music.youtube.com/channel/UCz86IA7ooUetFnUGa_YlsVw?si=A1t0-hLHswhbEG0U' +// } +// ] const hobbies = [ { @@ -152,7 +152,7 @@ export const lines: TerminalLine[] = [ { type: 'link', href: "/about#games", content: `(&bg-orange, black, bold)Games(&)`, inline: true }, { type: 'link', href: "/about#shows", content: `(&bg-yellow, black, bold)Shows(&)`, inline: true }, { type: 'link', href: "/about#movies", content: `(&bg-green, black, bold)Movies(&)`, inline: true }, - { type: 'link', href: "/about#music", content: `(&bg-accent, black, bold)Music(&)`, inline: true }, + // { type: 'link', href: "/about#music", content: `(&bg-accent, black, bold)Music(&)`, inline: true }, ] }, @@ -240,22 +240,22 @@ export const lines: TerminalLine[] = [ { type: 'blank', content: '' }, - { type: 'divider', content: 'Music Recommendations', id: 'music' }, + // { type: 'divider', content: 'Music Recommendations', id: 'music' }, - { - type: 'group', - content: '', - groupDirection: 'row', - children: [ - { type: 'output', content: '(&accent)Artists:(&) ', inline: true }, - ...artist.flatMap((a, i): TerminalLine[] => { - const item: TerminalLine = { type: 'link', content: `(&primary)${a.name}(&)`, href: a.url, inline: true }; - return i < artist.length - 1 ? [item, { type: 'output', content: ' (&muted)•(&) ', inline: true }] : [item]; - }), - ] - }, + // { + // type: 'group', + // content: '', + // groupDirection: 'row', + // children: [ + // { type: 'output', content: '(&accent)Artists:(&) ', inline: true }, + // ...artist.flatMap((a, i): TerminalLine[] => { + // const item: TerminalLine = { type: 'link', content: `(&primary)${a.name}(&)`, href: a.url, inline: true }; + // return i < artist.length - 1 ? [item, { type: 'output', content: ' (&muted)•(&) ', inline: true }] : [item]; + // }), + // ] + // }, - { type: 'blank', content: '' }, + // { type: 'blank', content: '' }, // { // type: 'card', // id: 'music-player', diff --git a/src/lib/pages/portfolio.ts b/src/lib/pages/portfolio.ts index b351a50..1de6ba3 100644 --- a/src/lib/pages/portfolio.ts +++ b/src/lib/pages/portfolio.ts @@ -1,6 +1,22 @@ import type { TerminalLine } from '$lib/components/tui/types'; -import { user, skills, projects } from '$lib/config'; +import { user, skills, openSourceProjects } from '$lib/config'; + +const openSourceElements:TerminalLine[] = []; + +openSourceProjects.forEach(project => { + openSourceElements.push( + { + type: 'output', + content: `(&orange,bold)▸ ${project.name}(&) - ${project.description}` + }, + { + type: 'output', + content: ` ${project.tech.map(tech => `(&blue)${tech}(&)`).join(' (&muted)•(&) ')}` + }, + { type: 'blank', content: '' } + ); +}); export const lines: TerminalLine[] = [ // Header command @@ -25,6 +41,7 @@ export const lines: TerminalLine[] = [ ] }, + { type: 'blank', content: '' }, { type: 'blank', content: '' }, { type: 'group', content: '', groupAlign: 'start', groupGap: '1rem', @@ -86,49 +103,7 @@ export const lines: TerminalLine[] = [ { type: 'divider', content: 'PROJECTS', id: 'projects' }, - // Featured projects with buttons - ...projects.filter(p => p.featured).flatMap(project => [ - { type: 'header' as const, content: `(&bold)${project.name}(&)` }, - { type: 'output' as const, content: `(&muted)${project.description}(&)` }, - { type: 'info' as const, content: `(&info)TechStack:(&) (&magenta)${project.tech.join(', ')}(&)` }, - ...(project.github ? [{ - type: 'button' as const, - content: 'View on GitHub', - icon: 'mdi:github', - style: 'accent' as const, - href: project.github - }] : []), - ...(project.live ? [{ - type: 'button' as const, - content: 'View Live Demo', - icon: 'mdi:open-in-new', - style: 'accent' as const, - href: project.live - }] : []), - { type: 'blank' as const, content: '' } - ]), - - // Other projects - ...projects.filter(p => !p.featured).flatMap(project => [ - { type: 'success' as const, content: `(&success)${project.name}(&)` }, - { type: 'output' as const, content: `(&muted)${project.description}(&)` }, - { type: 'info' as const, content: `(&info)TechStack:(&) (&magenta)${project.tech.join(', ')}(&)` }, - ...(project.github ? [{ - type: 'button' as const, - content: 'View on GitHub', - icon: 'mdi:github', - style: 'accent' as const, - href: project.github - }] : []), - ...(project.live ? [{ - type: 'button' as const, - content: 'View Live', - icon: 'mdi:open-in-new', - style: 'accent' as const, - href: project.live - }] : []), - { type: 'blank' as const, content: '' } - ]), + ...openSourceElements, // End { type: 'success', content: `(&success)Portfolio loaded successfully!(&)` } diff --git a/src/lib/pages/projects.ts b/src/lib/pages/projects.ts index 8fecaf9..507bcf0 100644 --- a/src/lib/pages/projects.ts +++ b/src/lib/pages/projects.ts @@ -1,16 +1,67 @@ import type { TerminalLine } from '$lib/components/tui/types'; -import { sortedCards, projects } from '$lib/config'; +import { sortedCards, packageProjects, openSourceProjects } from '$lib/config'; const totalHackathons = sortedCards.length; const totalAwards = sortedCards.filter(c => c.awards && c.awards.length > 0).length; const featuredCount = sortedCards.filter(c => c.featured).length; + +const openSourceElements:TerminalLine[] = []; + +openSourceProjects.forEach(project => { + openSourceElements.push( + { + type: 'card', + content: '', + cardTitle: project.name, + // cardFooter: '' + (project.github ? `(&muted)GitHub:(&) (&link)${project.github}(&)` : ''), + image: project.image || '/images/placeholder.png', + imageAlt: 'Placeholder image', + children: [ + ...project.tech.map(tech => ({ + type: 'output' as const, + content: `(&bg-blue, black)${tech}(&)`, + inline: true + })), + { + type: 'button', + content: 'View on GitHub', + href: project.github || 'https://github.com/', + icon: 'mdi:github', + style: 'accent', + }, + project.live ? { + type: 'button', + content: 'View Live Demo', + href: project.live, + icon: 'mdi:open-in-new', + style: 'primary' + } : { type: 'blank', content: '' } + ], + inline: true, + display: 'flex', + cardWidth: '275px' + }, + ); +}); + + // Build the terminal lines with card grid export const lines: TerminalLine[] = [ - { type: 'command', content: 'ls ~/projects' }, - { type: 'divider', content: 'PROJECTS' }, - ...projects.filter(p => p.featured).flatMap(project => [ - { type: 'header' as const, content: `(&bold)${project.name}(&)` }, + { type: 'command' as const, content: 'ls ~/projects' }, + { + type: 'group' as const, content: '', groupAlign: 'start', groupGap: '1rem', + children: [ + { type: 'link' as const, href: "/projects#opensource", content: `(&bg-blue,black)Open Scourced(&)`, inline: true }, + { type: 'link' as const, href: "/projects#packages", content: `(&bg-orange,black)Packages(&)`, inline: true }, + { type: 'link' as const, href: "/projects#hackathons", content: `(&bg-green,black)Hackathons(&)`, inline: true }, + ] + }, + { type: 'divider' as const, content: 'OPEN SOURCED', id: 'opensource' }, + ...openSourceElements, + { type: 'divider' as const, content: 'PACKAGES', id: 'packages' }, + ...packageProjects.filter(p => p.featured).flatMap(project => [ + { type: 'header' as const, content: `(&orange)${project.name}(&)` }, { type: 'output' as const, content: `(&muted)${project.description}(&)` }, { type: 'info' as const, content: `(&info)TechStack:(&) (&magenta)${project.tech.join(', ')}(&)` }, ...(project.github ? [{ @@ -29,8 +80,8 @@ export const lines: TerminalLine[] = [ }] : []), { type: 'blank' as const, content: '' } ]), - ...projects.filter(p => !p.featured).flatMap(project => [ - { type: 'success' as const, content: `(&success)${project.name}(&)` }, + ...packageProjects.filter(p => !p.featured).flatMap(project => [ + { type: 'header' as const, content: `${project.name}` }, { type: 'output' as const, content: `(&muted)${project.description}(&)` }, { type: 'info' as const, content: `(&info)TechStack:(&) (&magenta)${project.tech.join(', ')}(&)` }, ...(project.github ? [{ @@ -49,13 +100,13 @@ export const lines: TerminalLine[] = [ }] : []), { type: 'blank' as const, content: '' } ]), - { type: 'divider', content: 'HACKATHONS' }, - { type: 'command', content: 'ls ~/hackathons --grid' }, - { type: 'blank', content: '' }, - { type: 'header', content: `Hackathon Journey` }, - { type: 'output', content: `(&muted)Total:(&) (&primary)${totalHackathons}(&) (&muted)| Awards:(&) (&yellow)${totalAwards}(&) (&muted)| Featured:(&) (&accent)${featuredCount}(&)` }, - { type: 'blank', content: '' }, - { type: 'cardgrid', content: '', cards: sortedCards }, - { type: 'blank', content: '' }, - { type: 'success', content: `(&success)Ready for the next hackathon! 🚀(&)` }, + { type: 'divider' as const, content: 'HACKATHONS', id: 'hackathons' }, + // { type: 'command', content: 'ls ~/hackathons --grid' }, + { type: 'blank' as const, content: '' }, + { type: 'header' as const, content: `Hackathon Journey` }, + { type: 'output' as const, content: `(&muted)Total:(&) (&primary)${totalHackathons}(&) (&muted)| Awards:(&) (&yellow)${totalAwards}(&) (&muted)| Featured:(&) (&accent)${featuredCount}(&)` }, + { type: 'blank' as const, content: '' }, + { type: 'cardgrid' as const, content: '', cards: sortedCards }, + { type: 'blank' as const, content: '' }, + { type: 'success' as const, content: `(&success)Ready for the next hackathon! 🚀(&)` }, ]; \ No newline at end of file diff --git a/static/img/hoya26.png b/static/img/hoya26.png new file mode 100644 index 0000000..ea25a42 Binary files /dev/null and b/static/img/hoya26.png differ