Update resume content, styling, and export configuration

Refine experience descriptions for clarity and brevity, adjust green
theme colors and spacing, add part-time employment type, add
company-section-label style, set print media type in export script,
and switch background to white.

Made-with: Cursor
This commit is contained in:
ilia 2026-03-25 16:00:36 -04:00
parent c8a49018b1
commit fa336caf31
8 changed files with 89 additions and 47 deletions

Binary file not shown.

View File

@ -39,7 +39,7 @@ experience:
description: | description: |
• Integrated end-to-end Cypress automation from the ground up for GUI and API testing across critical product flows; led training for engineering. • Integrated end-to-end Cypress automation from the ground up for GUI and API testing across critical product flows; led training for engineering.
• Conducted AODA accessibility work: alt text, keyboard navigation, color contrast; scaled regression across web and mobile via Bitbucket CI/CD. • Conducted AODA accessibility work: alt text, keyboard navigation, color contrast; scaled regression across web and mobile via Bitbucket CI/CD.
• Used Ansible to automate provisioning for repeatable test environments; partnered with engineers and product on triage and quality gates. • Used Ansible to automate provisioning for repeatable test environments.
• Partnered with software engineers and product on defect triage, test reporting, and pragmatic quality gates. • Partnered with software engineers and product on defect triage, test reporting, and pragmatic quality gates.
- company: Attabotics - company: Attabotics
@ -50,7 +50,7 @@ experience:
location: Calgary, Alberta, Canada location: Calgary, Alberta, Canada
description: | description: |
• Wrote Gherkin/SpecFlow scenarios with C# step definitions; sustained 3,500+ automated scenarios in a .NET / Azure environment. • Wrote Gherkin/SpecFlow scenarios with C# step definitions; sustained 3,500+ automated scenarios in a .NET / Azure environment.
• Practiced left-shift QA within a large Agile team: testers engaged early in design and development. • Practiced left-shift QA within a large Agile team.
• Used Docker for local test environments and SQL Server for test data validation and traceability. • Used Docker for local test environments and SQL Server for test data validation and traceability.
- company: Levkin Inc. - company: Levkin Inc.
@ -63,7 +63,6 @@ experience:
• Built reusable Playwright testing building blocks with deterministic patterns, reducing flakiness and eliminating reliance on arbitrary sleeps or built-in waits. • Built reusable Playwright testing building blocks with deterministic patterns, reducing flakiness and eliminating reliance on arbitrary sleeps or built-in waits.
• Audited and refactored legacy test and UI code toward current standards; documented testing strategy and shared knowledge across the team. • Audited and refactored legacy test and UI code toward current standards; documented testing strategy and shared knowledge across the team.
• Optimized GitLab CI/CD pipelines for speed and reliability; piped test and pipeline metrics into Grafana dashboards for release visibility. • Optimized GitLab CI/CD pipelines for speed and reliability; piped test and pipeline metrics into Grafana dashboards for release visibility.
• Used GitLab for repositories, merge requests, and code review as part of day-to-day development and collaboration.
• Provisioned AWS environments with Terraform, validated them end-to-end, and promoted changes to dev following the team's standard release procedure. • Provisioned AWS environments with Terraform, validated them end-to-end, and promoted changes to dev following the team's standard release procedure.
- company: Accountants Templates Inc. - company: Accountants Templates Inc.
@ -73,8 +72,8 @@ experience:
employment: contract employment: contract
location: Calgary, Alberta, Canada location: Calgary, Alberta, Canada
description: | description: |
• Owned CaseWare/CaseView template delivery: compliance updates, standards-driven releases, and documentation for internal and client use. • Owned CaseWare/CaseView template delivery including compliance updates, standards-driven releases, and documentation for internal and client use.
• Reviewed software for improvements and implemented recommendations; collaborated with support on reported issues. • Reviewed software for improvements and implemented recommendations and collaborated with support on reported issues.
• Streamlined build and packaging workflows, removing approximately eight hours of manual effort per release cycle. • Streamlined build and packaging workflows, removing approximately eight hours of manual effort per release cycle.
- company: MNP LLP - company: MNP LLP
@ -96,19 +95,21 @@ experience:
employment: full-time employment: full-time
location: Toronto, Ontario, Canada location: Toronto, Ontario, Canada
description: | description: |
• Implemented features, resolved defects, and maintained financial and audit systems; supported distributors and clients. • Implemented features, resolved defects, and maintained financial and audit systems whille supporting distributors and clients.
• Delivered client templates with JavaScript, HTML, YUI, jQuery, JSON, and CSS at global scale. • Delivered client templates with JavaScript, HTML, YUI, jQuery, JSON, and CSS at global scale.
• Designed and executed automated validation with SilkTest; mentored junior developers, built reusable JS libraries, and used Agile Scrum, Jira, and Git. • Designed and executed automated validation with SilkTest
• Mentored junior developers, built reusable JS libraries, and used Agile Scrum, Jira, and Git.
- company: ROLI Consulting - company: ROLI Consulting
position: Web/Application Developer position: Web/Application Developer
timeperiod: January 2001 - July 2012 timeperiod: January 2001 - July 2012
remote: true remote: true
employment: full-time employment: part-time
location: Vaughan, Ontario, Canada location: Vaughan, Ontario, Canada
description: | description: |
• Developed and maintained a voice broadcasting system and text-messaging service using Python and the Twilio API for commercial clients. • Developed and maintained a voice broadcasting system and text-messaging service using Python and the Twilio API for commercial clients.
• Designed and maintained websites across multiple stacks, including WordPress; provided general technical consulting for nonprofits and SMBs. • Designed and maintained websites across multiple stacks, including WordPress
• Provided general technical consulting for nonprofits and SMBs.
- company: Earlier Career - company: Earlier Career
timeperiod: May 2005 - August 2006 timeperiod: May 2005 - August 2006

View File

@ -83,6 +83,7 @@ const convert = async () => {
} catch (_err) { } catch (_err) {
/* ignore if fonts API missing */ /* ignore if fonts API missing */
} }
await page.emulateMediaType('print');
await new Promise((r) => setTimeout(r, 300)); await new Promise((r) => setTimeout(r, 300));
if ( if (
@ -93,7 +94,8 @@ const convert = async () => {
await page.pdf({ await page.pdf({
path: fullDirectoryPath + dir.name + '.pdf', path: fullDirectoryPath + dir.name + '.pdf',
format: 'A4', format: 'A4',
printBackground: true printBackground: true,
margin: { top: '0', bottom: '0', left: '0', right: '0' }
}); });
await browser.close(); await browser.close();
} }

View File

@ -24,6 +24,6 @@ body {
padding: 0; padding: 0;
margin: 0; margin: 0;
overflow-x: hidden; overflow-x: hidden;
background: #CCCCCC; background: white;
} }
</style> </style>

View File

@ -23,7 +23,7 @@ export default Vue.component('resume', {
} }
.page-wrapper { .page-wrapper {
overflow-x: hidden; overflow-x: hidden;
background: #CCCCCC; background: white;
margin: 0; margin: 0;
padding: 0; padding: 0;
-webkit-print-color-adjust: exact; -webkit-print-color-adjust: exact;

View File

@ -44,7 +44,7 @@
<div class="experience" v-for="experience in person.experience" :key="experience.company"> <div class="experience" v-for="experience in person.experience" :key="experience.company">
<h2 class="company-row"> <h2 class="company-row">
<span class="company-primary"> <span class="company-primary">
<span class="company">{{experience.company}}</span><!-- <span :class="['company', experience.sub_companies && 'company-section-label']">{{experience.company}}</span><!--
--><span --><span
v-if="experienceWorkBadges(experience).length" v-if="experienceWorkBadges(experience).length"
class="exp-name-icon-gutter" class="exp-name-icon-gutter"
@ -190,7 +190,7 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
<!-- Add "scoped" attribute to limit CSS to this component only --> <!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="less" scoped> <style lang="less" scoped>
@text-green: #008000; @text-green: #1a6847;
@pad-x: 26px; @pad-x: 26px;
#template { #template {
box-sizing:border-box; box-sizing:border-box;
@ -201,6 +201,7 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
overflow-x: hidden; overflow-x: hidden;
background: white;
h1, h2 { h1, h2 {
/*font-family:'Open Sans Condensed', sans-serif;*/ /*font-family:'Open Sans Condensed', sans-serif;*/
margin:0; margin:0;
@ -228,9 +229,9 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
#resume-header { #resume-header {
color: white; color: white;
background-color: green; background-color: @text-green;
box-shadow: inset 0px 0px 200px #301030; box-shadow: inset 0px 0px 200px rgba(0,0,0,0.12);
padding: 26px @pad-x 16px; padding: 22px @pad-x 14px;
#header-left { #header-left {
width:100%; width:100%;
@ -281,9 +282,9 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
#resume-about { #resume-about {
flex-shrink: 0; flex-shrink: 0;
padding: 8px @pad-x 10px; padding: 6px @pad-x 8px;
background-color: green; background-color: @text-green;
box-shadow: inset 0px 0px 100px #301030; box-shadow: inset 0px 0px 100px rgba(0,0,0,0.08);
box-sizing: border-box; box-sizing: border-box;
h2 { h2 {
font-size: 16px; font-size: 16px;
@ -294,14 +295,14 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
color: white; color: white;
} }
p { p {
font-size: 10.5px; font-size: 11px;
line-height: 1.38; line-height: 1.38;
margin: 0; margin: 0;
white-space: pre-line; white-space: pre-line;
} }
.core-strengths { .core-strengths {
margin-top: 5px; margin-top: 5px;
font-size: 10.5px; font-size: 11px;
line-height: 1.4; line-height: 1.4;
white-space: normal; white-space: normal;
opacity: 0.92; opacity: 0.92;
@ -316,7 +317,8 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
min-width: 0; min-width: 0;
max-width: 100%; max-width: 100%;
box-sizing: border-box; box-sizing: border-box;
padding: 8px @pad-x 10px; padding: 6px @pad-x 6px;
background: white;
#experience-title, #education-title, #skills-title, #projects-title { #experience-title, #education-title, #skills-title, #projects-title {
font-size:22px; font-size:22px;
@ -335,18 +337,18 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
/* Block + inline-block: reliable in PDF print pipeline (avoids flex/padding quirks) */ /* Block + inline-block: reliable in PDF print pipeline (avoids flex/padding quirks) */
.experience-legend { .experience-legend {
display: block; display: block;
margin: 0 0 5px 0; margin: 0 0 3px 0;
padding: 0; padding: 0;
font-size: 9px; font-size: 9px;
line-height: 1.45; line-height: 1.45;
color: #5a7a5a; color: #4a7a6a;
max-width: 100%; max-width: 100%;
} }
.experience-legend-intro { .experience-legend-intro {
display: inline-block; display: inline-block;
font-weight: 700; font-weight: 700;
color: #4a6a4a; color: #2a6a52;
margin-right: 12px; margin-right: 12px;
vertical-align: baseline; vertical-align: baseline;
} }
@ -378,14 +380,14 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
} }
.experience { .experience {
margin: 0 0 8px 0; margin: 0 0 5px 0;
break-inside: avoid; break-inside: avoid;
page-break-inside: avoid; page-break-inside: avoid;
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
ul { ul {
margin: 4px 0 0 0; margin: 3px 0 0 0;
} }
} }
@ -394,8 +396,8 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
justify-content: space-between; justify-content: space-between;
align-items: baseline; align-items: baseline;
flex-wrap: wrap; flex-wrap: wrap;
gap: 4px 10px; gap: 3px 10px;
margin: 0 0 4px 0; margin: 0 0 2px 0;
line-height: 1.2; line-height: 1.2;
.company-primary { .company-primary {
display: inline; display: inline;
@ -434,9 +436,9 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
} }
} }
.company-location { .company-location {
font-size: 10.5px; font-size: 11px;
font-weight: 400; font-weight: 400;
color: #5a7a5a; color: #4a7a6a;
margin-left: auto; margin-left: auto;
text-align: right; text-align: right;
max-width: 55%; max-width: 55%;
@ -453,8 +455,8 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
justify-content: space-between; justify-content: space-between;
align-items: baseline; align-items: baseline;
flex-wrap: wrap; flex-wrap: wrap;
gap: 3px 10px; gap: 2px 10px;
margin: 0 0 4px 0; margin: 0 0 2px 0;
line-height: 1.25; line-height: 1.25;
} }
@ -464,9 +466,9 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
list-style-position: outside; list-style-position: outside;
list-style-type: disc; list-style-type: disc;
li { li {
font-size: 10.5px; font-size: 11px;
line-height: 1.32; line-height: 1.3;
margin: 0 0 2px 0; margin: 0 0 1px 0;
padding-left: 2px; padding-left: 2px;
overflow-wrap: anywhere; overflow-wrap: anywhere;
word-break: break-word; word-break: break-word;
@ -486,8 +488,8 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
.experience-timeperiod { .experience-timeperiod {
font-weight: 400; font-weight: 400;
color: #5a7a5a; color: #4a7a6a;
font-size: 10.5px; font-size: 11px;
line-height: 1.3; line-height: 1.3;
margin-left: auto; margin-left: auto;
text-align: right; text-align: right;
@ -532,7 +534,7 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
.sub-company-sep { .sub-company-sep {
display: inline-block; display: inline-block;
margin: 0 8px; margin: 0 8px;
color: #5a7a5a; color: #4a7a6a;
font-weight: 700; font-weight: 700;
font-size: 13px; font-size: 13px;
} }
@ -548,7 +550,7 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
} }
#skills-container { #skills-container {
margin-top: 8px; margin-top: 5px;
padding-left: 12px; padding-left: 12px;
padding-right: 12px; padding-right: 12px;
box-sizing: border-box; box-sizing: border-box;
@ -588,7 +590,7 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
color: #1a1a1a; color: #1a1a1a;
min-width: 0; min-width: 0;
padding: 3px 6px; padding: 3px 6px;
background: #f6faf6; background: #f2f9f6;
border-left: 3px solid @text-green; border-left: 3px solid @text-green;
overflow-wrap: anywhere; overflow-wrap: anywhere;
word-break: break-word; word-break: break-word;
@ -596,7 +598,7 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
} }
#projects-container { #projects-container {
margin-top: 8px; margin-top: 5px;
padding-left: 12px; padding-left: 12px;
padding-right: 12px; padding-right: 12px;
box-sizing: border-box; box-sizing: border-box;
@ -606,12 +608,21 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
} }
.project { .project {
margin: 0 0 6px 0; margin: 0 0 4px 0;
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
} }
.company-section-label {
font-style: italic;
font-weight: 600;
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #555;
}
.project-name { .project-name {
font-size: 15px; font-size: 15px;
font-weight: 700; font-weight: 700;
@ -620,7 +631,7 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
} }
#education-container { #education-container {
margin-top: 8px; margin-top: 5px;
padding-left: 12px; padding-left: 12px;
padding-right: 12px; padding-right: 12px;
box-sizing: border-box; box-sizing: border-box;
@ -633,10 +644,19 @@ export default Vue.component(name, Object.assign({}, baseOptions, {
} }
@page {
margin: 5mm 0 4mm 0;
}
@page :first {
margin-top: 0;
margin-bottom: 4mm;
}
.spacer { .spacer {
width:100%; width:100%;
border-bottom:1px solid @text-green; border-bottom:1px solid @text-green;
margin: 3px 0 4px; margin: 2px 0 3px;
padding-top: 0; padding-top: 0;
box-sizing: border-box; box-sizing: border-box;
} }

View File

@ -138,6 +138,11 @@ function getVueOptions (name) {
icon: 'fa fa-briefcase', icon: 'fa fa-briefcase',
label: 'Full-time' label: 'Full-time'
}, },
parttime: {
key: 'parttime',
icon: 'fa fa-clock-o',
label: 'Part-time'
},
coop: { coop: {
key: 'coop', key: 'coop',
icon: 'fa fa-graduation-cap', icon: 'fa fa-graduation-cap',
@ -185,6 +190,11 @@ function getVueOptions (name) {
icon: 'fa fa-briefcase', icon: 'fa fa-briefcase',
label: 'Full-time' label: 'Full-time'
}, },
{
key: 'parttime',
icon: 'fa fa-clock-o',
label: 'Part-time'
},
{ {
key: 'coop', key: 'coop',
icon: 'fa fa-graduation-cap', icon: 'fa fa-graduation-cap',

View File

@ -37,7 +37,7 @@
<div class="experience" v-for="experience in person.experience" :key="experience.company"> <div class="experience" v-for="experience in person.experience" :key="experience.company">
<h2 class="company-row"> <h2 class="company-row">
<span class="company-primary"> <span class="company-primary">
<span class="company">{{experience.company}}</span><!-- <span :class="['company', experience.sub_companies && 'company-section-label']">{{experience.company}}</span><!--
--><span --><span
v-if="experienceWorkBadges(experience).length" v-if="experienceWorkBadges(experience).length"
class="exp-name-icon-gutter" class="exp-name-icon-gutter"
@ -308,6 +308,15 @@ export default Vue.component(name, getVueOptions(name));
} }
} }
.company-section-label {
font-style: italic;
font-weight: 600;
font-size: 16px;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #666;
}
.education-description { .education-description {
font-size:20px; font-size:20px;
} }