Personal Website for @jaspermayone.com jaspermayone.com

Add project ordering and new projects

- Add order field to ProjectItem type for custom ordering
- Add ZipMerge, Strings, Calendar Backend, and Boxcar projects
- Reorder projects to prioritize polished/published projects
- Sort portfolio display by order field

+75 -23
+9 -1
src/app/portfolio/page.tsx
··· 95 95 }; 96 96 97 97 export default function Portfolio() { 98 + // Sort projects by order field, with projects without order at the end 99 + const sortedProjects = [...projects].sort((a, b) => { 100 + if (a.order === undefined && b.order === undefined) return 0; 101 + if (a.order === undefined) return 1; 102 + if (b.order === undefined) return -1; 103 + return a.order - b.order; 104 + }); 105 + 98 106 return ( 99 107 <> 100 108 <Script ··· 115 123 </div> 116 124 117 125 <div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3"> 118 - {projects.map((project, index) => ( 126 + {sortedProjects.map((project, index) => ( 119 127 <div 120 128 key={index} 121 129 className="overflow-hidden rounded-lg border border-gray-200 transition-shadow duration-200 hover:shadow-lg dark:border-gray-700"
+65 -22
src/lib/defs.ts
··· 416 416 */ 417 417 export const projects: ProjectItem[] = [ 418 418 { 419 - title: "Receipt Printer Business Card", 420 - description: 421 - "A creative business card that prints on thermal receipt paper.", 422 - github: "jaspermayone/receipt-printer-biz-card", 423 - tags: ["HTML"], 424 - date: "2025", 425 - }, 426 - { 427 419 title: "Personal Website", 428 420 description: "My personal website showcasing my projects and skills.", 429 421 link: "https://jaspermayone.com", ··· 431 423 tags: ["Next.js", "TypeScript", "Tailwind"], 432 424 date: "2025", 433 425 image: "/images/projects/website.webp", 434 - }, 435 - { 436 - title: "LaTex Generated CV/Resume", 437 - description: "My personal cv/resume built with LaTex.", 438 - link: "https://jasper.cv", 439 - github: "jaspermayone/cv", 440 - tags: ["LaTex", "Github Actions"], 441 - date: "2025", 442 - image: "https://jasper.cv/jaspermayone-cv.jpeg", 426 + order: 1, 443 427 }, 444 428 { 445 429 title: "Slack Profile CLI", ··· 449 433 github: "jaspermayone/slack-profile-cli", 450 434 tags: ["Node.js", "Ruby", "CLI", "Slack API"], 451 435 date: "2025", 436 + order: 2, 452 437 }, 453 438 { 454 - title: "MLH Discord Integration", 455 - description: 456 - "Discord bot that integrates with MyMLH identity platform for tighter linking of roles and user experience enhancement.", 457 - tags: ["Discord", "Ruby", "Ruby on Rails"], 439 + title: "LaTex Generated CV/Resume", 440 + description: "My personal cv/resume built with LaTex.", 441 + link: "https://jasper.cv", 442 + github: "jaspermayone/cv", 443 + tags: ["LaTex", "Github Actions"], 458 444 date: "2025", 459 - image: "/images/projects/mlh-discord.webp", 445 + image: "https://jasper.cv/jaspermayone-cv.jpeg", 446 + order: 3, 460 447 }, 461 448 { 462 449 title: "WIP - Metro", ··· 467 454 tags: ["Next.js", "TypeScript", "Tailwind"], 468 455 date: "2024", 469 456 image: "/images/projects/metro.webp", 457 + order: 4, 458 + }, 459 + { 460 + title: "Receipt Printer Business Card", 461 + description: 462 + "A creative business card that prints on thermal receipt paper.", 463 + github: "jaspermayone/receipt-printer-biz-card", 464 + tags: ["HTML"], 465 + date: "2025", 466 + order: 5, 470 467 }, 471 468 { 472 469 title: "Obsidian AI Tagger", ··· 475 472 github: "jaspermayone/obsidian-ai-tagger", 476 473 tags: ["TypeScript", "Obsidian", "AI"], 477 474 date: "2025", 475 + order: 6, 476 + }, 477 + { 478 + title: "Calendar Backend", 479 + description: 480 + "Backend service that fetches Wentworth University courses and helps students add them to Google Calendar.", 481 + github: "WITCodingClub/calendar-backend", 482 + tags: ["Ruby", "Ruby on Rails"], 483 + date: "2025", 484 + order: 7, 485 + }, 486 + { 487 + title: "MLH Discord Integration", 488 + description: 489 + "Discord bot that integrates with MyMLH identity platform for tighter linking of roles and user experience enhancement.", 490 + tags: ["Discord", "Ruby", "Ruby on Rails"], 491 + date: "2025", 492 + image: "/images/projects/mlh-discord.webp", 493 + order: 8, 478 494 }, 479 495 { 480 496 title: "Hack Club - Arcadius", 481 497 description: 482 498 "A freindly dino (slack bot) that managed the onboarding flow for Hack Club's 2024 summer event Arcade. (https://arcade.hackclub.com)", 483 499 github: "hackclub/arcadius", 500 + order: 9, 501 + }, 502 + { 503 + title: "Strings", 504 + description: 505 + "Simple strings server for the Wentworth Coding Club and personal use.", 506 + github: "jaspermayone/strings", 507 + tags: ["TypeScript"], 508 + date: "2026", 509 + order: 10, 510 + }, 511 + { 512 + title: "ZipMerge", 513 + description: 514 + "Simple app to help make it through COMP1050 with a professor who won't use version control.", 515 + github: "jaspermayone/ZipMerge", 516 + tags: ["Swift"], 517 + date: "2026", 518 + order: 11, 519 + }, 520 + { 521 + title: "Boxcar", 522 + description: "My opinionated Ruby on Rails template.", 523 + github: "jaspermayone/boxcar", 524 + tags: ["Ruby", "Ruby on Rails"], 525 + date: "2025", 526 + order: 12, 484 527 }, 485 528 ]; 486 529
+1
src/lib/types.ts
··· 47 47 tags?: string[]; 48 48 date?: string; 49 49 image?: string; 50 + order?: number; 50 51 } 51 52 52 53 export interface Concert {