Resume page

This commit is contained in:
2025-05-04 00:38:56 -06:00
parent 68a817c0f4
commit 224fd31839
5 changed files with 737 additions and 1 deletions

View File

@ -2,7 +2,7 @@ export default function HomeButtonLinks() {
return (
<div class="flex flex-row gap-4 text-3xl">
<a
href="/files/Atridad_Lahiji_Resume_Public.pdf"
href="/resume"
target="_blank"
rel="noopener noreferrer"
aria-label="React"

View File

@ -12,6 +12,7 @@ import * as $index from "./routes/index.tsx";
import * as $post_slug_ from "./routes/post/[slug].tsx";
import * as $posts from "./routes/posts.tsx";
import * as $projects from "./routes/projects.tsx";
import * as $resume from "./routes/resume.tsx";
import * as $Chat from "./islands/Chat.tsx";
import * as $NavigationBar from "./islands/NavigationBar.tsx";
import * as $ScrollUpButton from "./islands/ScrollUpButton.tsx";
@ -29,6 +30,7 @@ const manifest = {
"./routes/post/[slug].tsx": $post_slug_,
"./routes/posts.tsx": $posts,
"./routes/projects.tsx": $projects,
"./routes/resume.tsx": $resume,
},
islands: {
"./islands/Chat.tsx": $Chat,

View File

@ -5,6 +5,7 @@ import {
LuHouse,
LuMessageCircle,
LuNotebookPen,
LuFileText,
} from "@preact-icons/lu";
interface NavigationBarProps {
@ -74,6 +75,17 @@ export default function NavigationBar({ currentPath }: NavigationBarProps) {
</a>
</li>
<li class="mx-1">
<a
href="/resume"
class={currentPath === "/resume" ? "menu-active" : ""}
>
<div class="tooltip" data-tip="Resume">
<LuFileText class="text-xl" />
</div>
</a>
</li>
<li class="mx-1">
<a
href="/projects"

239
routes/resume.tsx Normal file
View File

@ -0,0 +1,239 @@
import { Head } from "$fresh/runtime.ts";
import { Handlers, PageProps } from "$fresh/server.ts";
import {
LuMail,
LuGithub,
LuLinkedin,
LuGlobe,
LuGitBranch,
LuDownload,
} from "@preact-icons/lu";
interface ResumeData {
basics: {
name: string;
email: string;
url?: { href: string };
};
sections: {
summary: { name: string; content: string };
profiles: { name: string; items: { network: string; username: string; url: { href: string } }[] };
skills: { name: string; items: { id: string; name: string; level: number }[] };
experience: { name: string; items: { id: string; company: string; position: string; date: string; location: string; summary: string; url?: { href: string } }[] };
education: { name: string; items: { id: string; institution: string; studyType: string; area: string; date: string; summary: string }[] };
volunteer: { name: string; items: { id: string; organization: string; position: string; date: string /* No summary here */ }[] };
};
}
export const handler: Handlers<ResumeData> = {
async GET(_req, ctx) {
try {
const resp = await fetch(new URL("/files/resume.json", ctx.url).href);
if (!resp.ok) {
console.error(`Error fetching resume.json: ${resp.status} ${resp.statusText}`);
return ctx.render(undefined);
}
const resumeData: ResumeData = await resp.json();
const skillsSection = resumeData.sections.skills;
if (skillsSection && skillsSection.items) {
const tsSkill = skillsSection.items.find(s => s.name === "Typescrpt");
if (tsSkill) {
tsSkill.name = "Typescript";
}
}
return ctx.render(resumeData);
} catch (error) {
console.error("Error processing resume data:", error);
return ctx.render(undefined);
}
},
};
export default function ResumePage({ data }: PageProps<ResumeData | undefined>) {
if (!data) {
return (
<>
<Head><title>Error Loading Resume</title></Head>
<div class="container mx-auto p-4 max-w-4xl text-center">
<h1 class="text-2xl font-bold text-error">Error loading resume data.</h1>
<p>Please try refreshing the page.</p>
</div>
</>
);
}
const { basics, sections } = data;
const { summary, profiles, skills, experience, education, volunteer } = sections;
return (
<>
<Head>
<title>{basics.name} - Resume</title>
<meta name="description" content={`${basics.name}'s professional resume.`} />
</Head>
<div class="container mx-auto p-4 max-w-4xl">
<h1 class="text-4xl font-bold mb-6 text-center">{basics.name}</h1>
{/* Contact Info */}
<div class="flex justify-center items-center flex-wrap gap-x-4 gap-y-2 mb-6">
{basics.email && (
<a href={`mailto:${basics.email}`} class="link link-hover inline-flex items-center gap-1">
<LuMail /> {basics.email}
</a>
)}
{profiles.items.find(p => p.network === "GitHub") && (
<a href={profiles.items.find(p => p.network === "GitHub")!.url.href} target="_blank" rel="noopener noreferrer" class="link link-hover inline-flex items-center gap-1">
<LuGithub /> GitHub
</a>
)}
{profiles.items.find(p => p.network === "linkedin") && (
<a href={profiles.items.find(p => p.network === "linkedin")!.url.href} target="_blank" rel="noopener noreferrer" class="link link-hover inline-flex items-center gap-1">
<LuLinkedin /> LinkedIn
</a>
)}
</div>
{/* Download Resume Button */}
<div class="text-center mb-8">
<a
href="/files/Atridad_Lahiji_Resume_Public.pdf"
download="Atridad_Lahiji_Resume.pdf"
class="btn btn-primary inline-flex items-center gap-2"
>
<LuDownload /> Download Resume (PDF)
</a>
</div>
{/* Summary Card */}
{summary && (
<div class="card bg-base-200 shadow-xl mb-6">
<div class="card-body">
<h2 class="card-title text-2xl">{summary.name || "Summary"}</h2>
<div dangerouslySetInnerHTML={{ __html: summary.content }}></div>
</div>
</div>
)}
{/* Profiles Card */}
{profiles && profiles.items && profiles.items.length > 0 && (
<div class="card bg-base-200 shadow-xl mb-6">
<div class="card-body">
<h2 class="card-title text-2xl">{profiles.name || "Profiles"}</h2>
<div class="flex flex-wrap gap-4">
{profiles.items.map((profile) => {
let IconComponent = LuGlobe;
const networkLower = profile.network.toLowerCase();
if (networkLower === "github") IconComponent = LuGithub;
else if (networkLower === "linkedin") IconComponent = LuLinkedin;
else if (networkLower === "forgejo") IconComponent = LuGitBranch;
return (
<a
key={profile.network}
href={profile.url.href}
target="_blank"
rel="noopener noreferrer"
class="link link-hover inline-flex items-center gap-1"
>
<IconComponent /> {profile.network} ({profile.username})
</a>
);
})}
</div>
</div>
</div>
)}
{/* Skills Card */}
{skills && skills.items && skills.items.length > 0 && (
<div class="card bg-base-200 shadow-xl mb-6">
<div class="card-body">
<h2 class="card-title text-2xl">{skills.name || "Skills"}</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
{skills.items.map((skill) => (
<div key={skill.id || skill.name}>
<label class="label">
<span class="label-text">{skill.name}</span>
</label>
<progress
class="progress progress-primary w-full"
value={skill.level * 20}
max="100"
>
</progress>
</div>
))}
</div>
</div>
</div>
)}
{/* Experience Card */}
{experience && experience.items && experience.items.length > 0 && (
<div class="card bg-base-200 shadow-xl mb-6">
<div class="card-body">
<h2 class="card-title text-2xl">{experience.name || "Experience"}</h2>
<div class="space-y-4">
{experience.items.map((exp, index) => (
<div key={exp.id || index} class="collapse collapse-arrow bg-base-100">
<input type="radio" name="resume-accordion-experience" checked={index === 0} readOnly />
<div class="collapse-title text-xl font-medium">
{exp.position} at {exp.company} ({exp.date})
{exp.location && (
<span class="text-sm font-normal float-right pt-1">{exp.location}</span>
)}
</div>
<div class="collapse-content">
{exp.url && exp.url.href && (
<a href={exp.url.href} target="_blank" rel="noopener noreferrer" class="link link-primary block mb-2">{exp.url.href}</a>
)}
<div dangerouslySetInnerHTML={{ __html: exp.summary }}></div>
</div>
</div>
))}
</div>
</div>
</div>
)}
{/* Education Card */}
{education && education.items && education.items.length > 0 && (
<div class="card bg-base-200 shadow-xl mb-6">
<div class="card-body">
<h2 class="card-title text-2xl">{education.name || "Education"}</h2>
<div class="space-y-4">
{education.items.map((edu, index) => (
<div key={edu.id || index}>
<h3 class="text-lg font-semibold">{edu.institution}</h3>
<p>{edu.studyType} - {edu.area} ({edu.date})</p>
{edu.summary && (
<div class="ml-4 text-sm mt-1" dangerouslySetInnerHTML={{ __html: edu.summary }}></div>
)}
</div>
))}
</div>
</div>
</div>
)}
{/* Volunteering Card */}
{volunteer && volunteer.items && volunteer.items.length > 0 && (
<div class="card bg-base-200 shadow-xl mb-6">
<div class="card-body">
<h2 class="card-title text-2xl">{volunteer.name || "Volunteering"}</h2>
<div class="space-y-4">
{volunteer.items.map((vol, index) => (
<div key={vol.id || index}>
<h3 class="text-lg font-semibold">{vol.organization}</h3>
<p>{vol.position} ({vol.date})</p>
</div>
))}
</div>
</div>
</div>
)}
</div>
</>
);
}

483
static/files/resume.json Normal file
View File

@ -0,0 +1,483 @@
{
"basics": {
"url": {
"href": "https://atri.dad",
"label": ""
},
"name": "Atridad Lahijjjjj",
"email": "me@atri.dad",
"phone": "",
"picture": {
"url": "",
"size": 64,
"effects": {
"border": false,
"hidden": false,
"grayscale": false
},
"aspectRatio": 1,
"borderRadius": 0
},
"headline": "",
"location": "",
"customFields": []
},
"metadata": {
"css": {
"value": ".text-2xl {\n\tfont-size: 30px;\n}",
"visible": true
},
"page": {
"format": "letter",
"margin": 16,
"options": {
"breakLine": true,
"pageNumbers": true
}
},
"notes": "",
"theme": {
"text": "#000000",
"primary": "#0284c7",
"background": "#ffffff"
},
"layout": [
[
[
"summary",
"education",
"experience",
"projects",
"references",
"custom.b5li7wh27iylvqlsmeavvkzh"
],
[
"profiles",
"skills",
"volunteer",
"interests",
"certifications",
"awards",
"publications",
"languages"
]
]
],
"template": "glalie",
"typography": {
"font": {
"size": 14,
"family": "Lato",
"subset": "latin",
"variants": [
"regular"
]
},
"hideIcons": false,
"lineHeight": 0.95,
"underlineLinks": true
}
},
"sections": {
"awards": {
"id": "awards",
"name": "Awards",
"items": [],
"columns": 1,
"visible": true,
"separateLinks": true
},
"custom": {
"b5li7wh27iylvqlsmeavvkzh": {
"id": "b5li7wh27iylvqlsmeavvkzh",
"name": "Custom Section",
"items": [],
"columns": 1,
"visible": true,
"separateLinks": true
}
},
"skills": {
"id": "skills",
"name": "Skills",
"items": [
{
"id": "lpwyb43emmmukje3c49yupu7",
"name": "HTML + CSS + JavaScript",
"level": 5,
"visible": true,
"keywords": [],
"description": ""
},
{
"id": "c5qu0q3wct06oj1wa3u3tkar",
"visible": true,
"name": "Typescrpt",
"description": "",
"level": 5,
"keywords": []
},
{
"id": "qtq2qfeoa0bskykwhfzmlpng",
"visible": true,
"name": "Vitest, Jest, and Playwright",
"description": "",
"level": 4,
"keywords": []
},
{
"id": "b6k6q4r592uesacsz03dtvyk",
"visible": true,
"name": "Docker + Docker Compose",
"description": "",
"level": 5,
"keywords": []
},
{
"id": "lc3eu9r8vvqhsst1mkeqxgse",
"visible": true,
"name": "Go (Golang)",
"description": "",
"level": 4,
"keywords": []
},
{
"id": "lme3ob0kfpe5hgsuar42nmi6",
"visible": true,
"name": "SQL (PostgreSQL, MySQL, SQLite)",
"description": "",
"level": 4,
"keywords": []
},
{
"id": "f58rq48rtsgdftfcbpt785is",
"visible": true,
"name": "Python",
"description": "",
"level": 4,
"keywords": []
},
{
"id": "ht9fn1i89gm0e3gf5mfde0os",
"visible": true,
"name": "SCRUM",
"description": "",
"level": 5,
"keywords": []
},
{
"id": "vtpxeg6r0os9ygjmg384wo7f",
"visible": true,
"name": "Amazon Web Services (AWS)",
"description": "",
"level": 4,
"keywords": []
},
{
"id": "tk3i1xdw92vny0fk7001rrj7",
"visible": true,
"name": "Ruby",
"description": "",
"level": 2,
"keywords": []
},
{
"id": "jqy6vkxl8hed4vgow0z12vwy",
"visible": true,
"name": "Test Driven Development",
"description": "",
"level": 3,
"keywords": []
},
{
"id": "oalwcevey6plalwasugwf4q7",
"visible": true,
"name": "C#",
"description": "",
"level": 3,
"keywords": []
},
{
"id": "skhsek829sf8012wbwd38fl8",
"visible": true,
"name": "PHP",
"description": "",
"level": 2,
"keywords": []
},
{
"id": "feotadkdeli1ukx3u3ix86ig",
"name": "Time Management",
"level": 4,
"visible": true,
"keywords": [],
"description": ""
},
{
"id": "a993l06kuyinj9l88uz3ztux",
"name": "Problem Solving",
"level": 5,
"visible": true,
"keywords": [],
"description": ""
},
{
"id": "rhyu2toaznnidknrz244klqq",
"name": "Attention to Detail",
"level": 5,
"visible": true,
"keywords": [],
"description": ""
}
],
"columns": 1,
"visible": true,
"separateLinks": true
},
"summary": {
"id": "summary",
"name": "Summary",
"columns": 1,
"content": "<p>I am a full-stack web developer and researcher with a background maintaining and developing for large-scale enterprise software systems. I am in the process of completing my Master of Science in Computer Science under the supervision of Dr. Nathaniel Osgood at the University of Saskatchewan. I have completed my course work and am now moving into writing my thesis which can be done asynchronously.</p><p></p>",
"visible": true,
"separateLinks": true
},
"profiles": {
"id": "profiles",
"name": "Profiles",
"items": [
{
"id": "zuto1s9atwo6tdx9qfa9ggug",
"url": {
"href": "https://github.com/atridadl",
"label": ""
},
"icon": "github",
"network": "GitHub",
"visible": true,
"username": "atridadl"
},
{
"id": "satbehrw5da07dmi8y8j70kl",
"url": {
"href": "https://www.linkedin.com/in/atridadl/",
"label": ""
},
"icon": "linkedin",
"network": "linkedin",
"visible": true,
"username": "atridadl"
},
{
"id": "yorfn8ku98u5o0jzvumo9q2v",
"url": {
"href": "https://git.atri.dad/atridad",
"label": ""
},
"icon": "forgejo",
"network": "Forgejo",
"visible": true,
"username": "atridad"
}
],
"columns": 1,
"visible": true,
"separateLinks": true
},
"projects": {
"id": "projects",
"name": "Projects",
"items": [],
"columns": 1,
"visible": true,
"separateLinks": true
},
"education": {
"id": "education",
"name": "Education",
"items": [
{
"id": "xtkfnu2zq3myh09pumehphx9",
"url": {
"href": "",
"label": ""
},
"area": "Computer Science",
"date": "2024 Present",
"score": "",
"summary": "<p style=\"text-align: left\">Supervisor: Dr. Nathaniel Osgood</p><ul><li><p style=\"text-align: left\">CMPT 838: Computer Security</p></li><li><p style=\"text-align: left\">CMPT 815: Computer Systems and Performance Evaluation</p></li></ul>",
"visible": true,
"studyType": "Masters",
"institution": "University of Saskatchewan"
},
{
"id": "o4my8au0d7c6bf09vlqwxvyw",
"url": {
"href": "",
"label": ""
},
"area": "Computer Science",
"date": "2017 2019",
"score": "",
"summary": "",
"visible": true,
"studyType": "Bachelors (3 Year)",
"institution": "University of Saskatchewan"
},
{
"id": "pnwpsei7ag1yldmtv9f4kt4e",
"url": {
"href": "",
"label": ""
},
"area": "Computer Engineering",
"date": "2012 2017",
"score": "",
"summary": "",
"visible": true,
"studyType": "Bachelors",
"institution": "University of Saskatchewan"
}
],
"columns": 1,
"visible": true,
"separateLinks": true
},
"interests": {
"id": "interests",
"name": "Interests",
"items": [],
"columns": 1,
"visible": true,
"separateLinks": true
},
"languages": {
"id": "languages",
"name": "Languages",
"items": [],
"columns": 1,
"visible": true,
"separateLinks": true
},
"volunteer": {
"id": "volunteer",
"name": "Volunteering",
"items": [
{
"id": "xhg1p7exqggrjkldszplj1wk",
"url": {
"href": "",
"label": ""
},
"date": "2021 2022",
"summary": "",
"visible": true,
"location": "",
"position": "Mentor",
"organization": "Big Brother Big Sisters"
}
],
"columns": 1,
"visible": true,
"separateLinks": true
},
"experience": {
"id": "experience",
"name": "Experience",
"items": [
{
"id": "gn67fi9oygi5tz1x3p3r7mbf",
"url": {
"href": "https://atash.dev",
"label": ""
},
"date": "June 2019 Present",
"company": "Atash Consulting",
"summary": "<ul><li><p>Builds mobile and web applications for small-medium sized businesses</p></li><li><p>Provides consulting on as application development, system architecture, DevOps, etc</p></li><li><p>Hosting websites for small-medium sized businesses</p></li></ul>",
"visible": true,
"location": "Edmonton, Alberta",
"position": "Owner/Developer"
},
{
"id": "x8ok2hutceh7lroyhwa7kj0h",
"url": {
"href": "",
"label": ""
},
"date": "November 2023 Present",
"company": "University of Saskatchewan CEPHIL Lab",
"summary": "<ul><li><p>Developing mobile and web applications</p></li><li><p>Coordinating with other grant researchers to deliver a minimum viable product</p></li><li><p>Gathering requirements from stakeholders to craft a product timeline</p></li><li><p>Acting as a technical lead and supervisor to a developer intern</p></li></ul>",
"visible": true,
"location": "Saskatoon, Saskatchewan",
"position": "Research Technician"
},
{
"id": "f0kyaxcy3syb8wazs3ye662i",
"url": {
"href": "",
"label": ""
},
"date": "August 2021 November 2023",
"company": "Alberta Motor Association",
"summary": "<ul><li><p>Developed and maintained internal enterprise-level business applications leveraging Amazon Web Services (AWS)</p></li><li><p>Used React and Create React App (CRA) for standalone applications and micro-front-ends</p></li><li><p>Developed an in-house payment gateway for all AMA services that integrates with Stripe</p></li><li><p>Provided tier 3 support support for internal service</p></li><li><p>Participated in a bi-monthly 24/7 on-call rotation</p></li><li><p>Mentored students in the organizations Developer in Training program</p></li></ul>",
"visible": true,
"location": "Edmonton, Alberta",
"position": "Software Developer II"
},
{
"id": "yikqef72i068lfiy8iiwjm45",
"url": {
"href": "",
"label": ""
},
"date": "October 2019 August 2021",
"company": "University of Alberta IST",
"summary": "<ul><li><p>Front-end development of web applications using Vue.js</p></li><li><p>Leveraged Amazon Web Services to adopt a serverless architecture</p></li><li><p>Maintained a secure exam application developed in-house</p></li><li><p>Monitored and maintained an exam scheduling system hosted on-premises</p></li></ul>",
"visible": true,
"location": "Edmonton, Alberta",
"position": "Software Developer"
},
{
"id": "wzqfv3h8rxs6574z5hlvrhm7",
"url": {
"href": "",
"label": ""
},
"date": "July 2017 October 2019",
"company": "University of Alberta IST",
"summary": "<ul><li><p>Provided support for our Moodle installation to students, faculty, and staff</p></li><li><p>Front-end development of web applications using Vue.js</p></li></ul>",
"visible": true,
"location": "Edmonton, Alberta",
"position": "Support Analyst"
}
],
"columns": 1,
"visible": true,
"separateLinks": true
},
"references": {
"id": "references",
"name": "References",
"items": [],
"columns": 1,
"visible": true,
"separateLinks": true
},
"publications": {
"id": "publications",
"name": "Publications",
"items": [],
"columns": 1,
"visible": true,
"separateLinks": true
},
"certifications": {
"id": "certifications",
"name": "Certifications",
"items": [],
"columns": 1,
"visible": true,
"separateLinks": true
}
}
}