Files for my website bwc9876.dev

Add Resume as Typst File

bwc9876.dev f74f4db4 91734c71

verified
+244 -19
+2 -19
flake.nix
··· 4 4 flakelight ./. ( 5 5 {lib, ...}: { 6 6 systems = lib.systems.flakeExposed; 7 - package = pkgs: let 8 - src = ./.; 9 - in 10 - pkgs.buildNpmPackage { 11 - name = "portfolio-site"; 12 - version = "0.0.0"; 13 - inherit src; 14 - packageJSON = ./package.json; 15 - npmDeps = pkgs.importNpmLock { 16 - npmRoot = src; 17 - }; 18 - npmConfigHook = pkgs.importNpmLock.npmConfigHook; 19 - installPhase = "cp -r dist/ $out"; 20 - ASTRO_TELEMETRY_DISABLED = 1; 21 - }; 22 - devShell.packages = pkgs: 23 - with pkgs; [ 24 - nodejs_24 25 - ]; 26 7 formatters = pkgs: let 27 8 alejandra = "${pkgs.alejandra}/bin/alejandra ."; 9 + typstyle = "${pkgs.typstyle}/bin/typstyle -i src/assets/resume.typ"; 28 10 in { 29 11 "*.nix" = alejandra; 12 + "*.typ" = typstyle; 30 13 }; 31 14 } 32 15 );
+10
nix/devShell.nix
··· 1 + { 2 + packages = pkgs: 3 + with pkgs; [ 4 + nodejs_24 5 + typst 6 + typstyle 7 + tinymist 8 + ]; 9 + env = pkgs: {TYPST_PACKAGE_PATH = "${pkgs.resumeTypstPlugins}";}; 10 + }
+19
nix/packages/_default.nix
··· 1 + {pkgs}: let 2 + src = ../..; 3 + in 4 + pkgs.buildNpmPackage { 5 + name = "portfolio-site"; 6 + version = "0.0.0"; 7 + inherit src; 8 + packageJSON = ../../package.json; 9 + npmDeps = pkgs.importNpmLock { 10 + npmRoot = src; 11 + }; 12 + npmConfigHook = pkgs.importNpmLock.npmConfigHook; 13 + installPhase = "cp -r dist/ $out"; 14 + nativeBuildInputs = [ 15 + pkgs.typst 16 + ]; 17 + TYPST_PACKAGE_PATH = "${pkgs.resumeTypstPlugins}"; 18 + ASTRO_TELEMETRY_DISABLED = 1; 19 + }
+15
nix/packages/resumeTypstPlugins.nix
··· 1 + {pkgs}: let 2 + typst-packages = pkgs.fetchgit { 3 + url = "https://github.com/typst/packages.git"; 4 + rev = "20dfd96e1e5f5284bde5eaaeacb094bee9215fb0"; 5 + sparseCheckout = map (p: "packages/preview/${p}") [ 6 + "basic-resume/0.2.9" 7 + "scienceicons/0.1.0" 8 + ]; 9 + hash = "sha256-k14km63OmRU/9pj02oIA+XXmqpQ0GpUqWxzP7gCvlKU="; 10 + }; 11 + in 12 + pkgs.runCommand "plugins-dir" {} '' 13 + mkdir -p $out 14 + ln -s ${typst-packages}/packages/preview $out/preview 15 + ''
+148
src/assets/resume.typ
··· 1 + #import "@preview/basic-resume:0.2.9": * 2 + 3 + #let name = "Benjamin Crocker" 4 + #let location = "West Chester, PA" 5 + #let email = "bc1016579@wcupa.edu" 6 + #let github = "github.com/Bwc9876" 7 + #let linkedin = "linkedin.com/in/bwc9876" 8 + #let phone = "(610)-906-9343" 9 + #let personal-site = "bwc9876.dev" 10 + 11 + #set document( 12 + title: "Benjamin Crocker Resume", 13 + ) 14 + 15 + #show: resume.with( 16 + author: name, 17 + location: location, 18 + email: email, 19 + //github: github, 20 + //linkedin: linkedin, 21 + phone: phone, 22 + personal-site: personal-site, 23 + accent-color: "#26428b", 24 + font: "New Computer Modern", 25 + paper: "us-letter", 26 + author-position: left, 27 + personal-info-position: left, 28 + ) 29 + 30 + /* 31 + * Lines that start with == are formatted into section headings 32 + * You can use the specific formatting functions if needed 33 + * The following formatting functions are listed below 34 + * #edu(dates: "", degree: "", gpa: "", institution: "", location: "", consistent: false) 35 + * #work(company: "", dates: "", location: "", title: "") 36 + * #project(dates: "", name: "", role: "", url: "") 37 + * certificates(name: "", issuer: "", url: "", date: "") 38 + * #extracurriculars(activity: "", dates: "") 39 + * There are also the following generic functions that don't apply any formatting 40 + * #generic-two-by-two(top-left: "", top-right: "", bottom-left: "", bottom-right: "") 41 + * #generic-one-by-two(left: "", right: "") 42 + */ 43 + == Education 44 + 45 + #edu( 46 + institution: "West Chester University", 47 + location: "West Chester, PA", 48 + dates: dates-helper( 49 + start-date: "Aug. 2023", 50 + end-date: "Dec. 2026 (Projected)", 51 + ), 52 + degree: "Bachelor of Computer Science, Minor in Professional and Technical Writing", 53 + consistent: true, 54 + ) 55 + - Dean's List Fall 2023 56 + - Treasurer of: Computer Science Club, Competitive Programming Club, Sexuality and Gender Alliance 57 + 58 + #edu( 59 + institution: "Berks Career and Technology Center", 60 + location: "Leesport, PA", 61 + dates: dates-helper(start-date: "Aug. 2020", end-date: "May 2023"), 62 + degree: "Information Technology Programming", 63 + consistent: true, 64 + ) 65 + - Part-time student working on software development in VB.NET Winforms and learning various aspects of the Software Development Life Cycle (SDLC) 66 + 67 + == Work Experience 68 + 69 + #work( 70 + title: "Help Desk Consultant", 71 + location: "West Chester, PA", 72 + company: "West Chester University", 73 + dates: dates-helper(start-date: "Jan. 2024", end-date: "Present"), 74 + ) 75 + - Supported users with various on-campus systems, including the RamPortal SIS 76 + - Tested and found security issues on university endpoints and systems 77 + 78 + #work( 79 + title: "Information Technology Intern", 80 + location: "Limerick, PA", 81 + company: "The Victory Bank", 82 + dates: dates-helper(start-date: "May 2023", end-date: "Aug. 2023"), 83 + ) 84 + - Troubleshooted and provided support for endpoint devices, performed device imaging and configuration 85 + - Supported VDI environments and maintenance of an ActiveDirectory domain 86 + 87 + == Projects 88 + 89 + #project( 90 + name: "West Chester University ASL Interface", 91 + // Role is optional 92 + role: "Contributor", 93 + // Dates is optional 94 + dates: dates-helper(start-date: "Feb. 2025", end-date: "Present"), 95 + url: "github.com/amiruzzaman/ASL_research", 96 + ) 97 + - Web interface for translating ASL to English and vice-versa 98 + - Frontend built in AstroJS with Tailwind and daisyUI 99 + - Live rendering of ASL animations (landmark data rendered to a Canvas to look like a person signing ASL) via JavaScript 100 + - Connects to backend running a Flask web server to handle computationally complex tasks 101 + 102 + #project( 103 + name: "West Chester Programming Competition", 104 + // Role is optional 105 + role: "Author", 106 + // Dates is optional 107 + dates: dates-helper(start-date: "May 2024", end-date: "Present"), 108 + // URL is also optional 109 + url: "bwc9876.dev/projects/wcpc", 110 + ) 111 + - Web interface for holding and participating in the West Chester Programming Competition 112 + - Built with a Rust backend and SQLite Database (can be switched) 113 + - Uses AstroJS to build most of the frontend with Tailwind. Pages are server-side rendered (SSR) with Tera 114 + - Supports SSO login with user's WCU account and OAuth account linking for easier sign-in later 115 + - Users can submit code that is run in a sand-boxed "jail". Code output is tested against expected output for scoring 116 + - Live leaderboard for tracking competitions, ability for competitors to export their code as a Git repository 117 + 118 + #project( 119 + name: "Outer Wilds Mod Manager", 120 + // Role is optional 121 + role: "Author", 122 + // Dates is optional 123 + dates: dates-helper(start-date: "Dec. 2022", end-date: "Present"), 124 + // URL is also optional 125 + url: "outerwildsmods.com/mod-manager", 126 + ) 127 + - Built and maintained free desktop application for downloading and managing mods for the game Outer Wilds 128 + - Built in Tauri with Rust for application logic and a web UI frontend built in React with MUI 129 + - Distributed on various platforms including Windows, MacOS, Linux, Steam Deck 130 + 131 + == Certificates 132 + 133 + #certificates( 134 + name: "PA State Skills Certification - Computer Technology / Systems", 135 + issuer: "NOCTI", 136 + date: "May 2023", 137 + ) 138 + 139 + #certificates( 140 + name: "OSHA 10 Hour General Industry Safety and Health", 141 + issuer: "OSHA", 142 + date: "Mar. 2023", 143 + ) 144 + 145 + == Skills 146 + - *Programming Languages*: Rust, JavaScript, TypeScript, Python, C\#, SQL, Visual Basic .NET 147 + - *Technologies*: Git VCS, React, AstroJS, Tailwind, CSS, SASS, Bootstrap, MUI, Tauri, SAML, OAuth, LDAP, ActiveDirectory, GitHub Actions, Nix 148 +
+1
src/components/Socials.astro
··· 15 15 } 16 16 17 17 const socialData: SocialData = [ 18 + { name: "Resume", icon: "file-earmark-text-fill", link: "/resume.pdf" }, 18 19 { name: "GitHub", icon: "github", link: "https://github.com/Bwc9876" }, 19 20 { name: "Twitter (X)", icon: "twitter-x", link: "https://x.com/Bwc9876" }, 20 21 { name: "LinkedIn", icon: "linkedin", link: "https://www.linkedin.com/in/bwc9876" },
+49
src/pages/resume.pdf.ts
··· 1 + import rawTypst from "@assets/resume.typ?raw"; 2 + import { spawn } from "node:child_process"; 3 + 4 + const compileTypst = (raw: string): Promise<Buffer> => { 5 + console.debug(process.env["TYPST_PACKAGE_PATH"]) 6 + const cmd = spawn("typst", ["compile", "-f", "pdf", "-", "-"], {stdio: "pipe"}); 7 + 8 + cmd.stdin.write(raw); 9 + cmd.stdin.end(); 10 + 11 + return new Promise((resolve, reject) => { 12 + cmd.on("error", reject); 13 + 14 + let stderr = ""; 15 + cmd.stderr.setEncoding("utf8"); 16 + cmd.stderr.on("data", (data) => { 17 + stderr += data; 18 + }); 19 + 20 + let stdout: Buffer | null = null; 21 + cmd.stdout.on("data", (data) => { 22 + if (stdout === null) { 23 + stdout = data; 24 + } else { 25 + stdout += data; 26 + } 27 + }); 28 + 29 + cmd.on("exit", (code) => { 30 + if (code === 0) { 31 + if (stdout !== null) { 32 + resolve(stdout as Buffer); 33 + } else { 34 + reject(new Error(`No stdout, Stderr: ${stderr}`)); 35 + } 36 + } else { 37 + reject(new Error(`Exited with code ${code} Stderr: ${stderr}`)); 38 + } 39 + }); 40 + 41 + 42 + }); 43 + }; 44 + 45 + export async function GET() { 46 + const data = await compileTypst(rawTypst); 47 + // @ts-expect-error "idk why it thinks this is wrong? Astro supports responses from a Buffer" 48 + return new Response(data); 49 + }