diff --git a/gitprofile.config.ts b/gitprofile.config.ts index c9661bc..00e8980 100644 --- a/gitprofile.config.ts +++ b/gitprofile.config.ts @@ -80,10 +80,15 @@ const CONFIG = { seo: { title: 'Ilia Dobkin — SDET & Test Automation Engineer', description: - 'Software Development Engineer in Test with deep experience in Cypress, Playwright, Selenium, CI/CD, and end-to-end test automation.', + 'Software Development Engineer in Test with 20+ years across product, platform, and industrial test automation — Cypress, Playwright, Selenium, CI/CD, accessibility, and regulated domains.', imageURL: '', }, location: 'Thornhill, Ontario, Canada', + about: [ + 'Driven software engineer with 20+ years of experience spanning product, platform, and industrial test automation — from global audit and financial systems (CaseWare, MNP, JazzIt) to modern web delivery for startups and enterprises alike.', + 'Builds and maintains a self-hosted infrastructure lab (Proxmox, Ansible, Caddy, CI runners) that mirrors production-grade DevOps practices.', + 'Seeking roles where I can provide testing guidance, strengthen CI/CD operations, and collaborate with teams to optimize product delivery.', + ], social: { linkedin: 'idobkin', x: '', @@ -108,48 +113,90 @@ const CONFIG = { }, resume: { fileUrl: '/resume.pdf', + sectionTitle: 'Core strengths', previewLines: [ - 'Driven software engineer with deep experience in product, platform, and industrial test automation systems, from audit and financial software to modern web delivery.', - 'Seeking roles where I can provide testing guidance, strengthen development operations through continuous integration, and collaborate with teams to optimize product delivery.', - '', - 'Core strengths: end-to-end test automation (Cypress, Playwright, Selenium), CI/CD integration, accessibility (AODA/WCAG), and frameworks built for team adoption.', + 'E2E test automation (Cypress, Playwright, Selenium), BDD (SpecFlow, Cucumber), and accessibility (AODA / WCAG).', + 'Observability (Grafana, Prometheus), IaC (Terraform), and API and performance testing (Postman, Artillery).', + 'Reusable frameworks built for team adoption.', ], }, skills: [ 'Cypress', 'Playwright', 'Selenium', + 'SilkTest', + 'SpecFlow', + 'Cucumber', + 'Gherkin', + 'BDD', 'TypeScript', 'JavaScript', 'C#', 'Python', 'Java', '.NET', + 'ASP.NET', 'Node.js', + 'Spring Boot', + 'PyTest', + 'JUnit', + 'HTML', + 'CSS', + 'jQuery', + 'REST API', + 'Page object model', + 'Cross-browser testing', + 'Mobile testing', 'GitHub Actions', + 'GitHub', 'GitLab CI', + 'Bitbucket', 'Jenkins', 'Azure DevOps', - 'Bitbucket Pipelines', 'Ansible', + 'Terraform', + 'CI/CD', + 'Self-hosted runners', 'Docker', + 'Proxmox', 'AWS', - 'GCP', + 'AWS Lambda', 'Azure', + 'GCP', 'PostgreSQL', 'MySQL', 'SQL Server', + 'DB2', + 'Informatica', + 'ETL', 'Postman', 'Artillery', + 'JMeter', 'Grafana', 'Prometheus', - 'SpecFlow', - 'Cucumber', - 'Gherkin', + 'Sentry', + 'DataDog', 'AODA / WCAG', 'Agile / Scrum', + 'Shift-left QA', 'Jira', + 'Confluence', 'Git', + 'TestRail', + 'Twilio', + 'WordPress', + 'CaseWare', + 'CaseView', + 'Crystal Reports', + 'Linux', + 'Caddy', + 'TrueNAS', + 'Vaultwarden', + 'Gitea', + 'SonarQube', + 'n8n', + 'DNS', + 'Local LLM / GPU', ], experiences: [], certifications: [], diff --git a/global.d.ts b/global.d.ts index d4efea1..a54d74a 100644 --- a/global.d.ts +++ b/global.d.ts @@ -217,6 +217,11 @@ interface Resume { */ fileUrl?: string; + /** + * Card heading (e.g. Core strengths) + */ + sectionTitle?: string; + /** * Preview lines shown on the profile page */ @@ -345,6 +350,11 @@ interface Config { */ location?: string; + /** + * About me paragraphs (shown at top of sidebar; when set, GitHub bio is hidden on the avatar card) + */ + about?: Array; + /** * Social links */ diff --git a/public/resume.pdf b/public/resume.pdf index 01dfa5e..9735a0a 100644 Binary files a/public/resume.pdf and b/public/resume.pdf differ diff --git a/src/components/about-card/index.tsx b/src/components/about-card/index.tsx new file mode 100644 index 0000000..c43da99 --- /dev/null +++ b/src/components/about-card/index.tsx @@ -0,0 +1,42 @@ +import { skeleton } from '../../utils'; + +const AboutCard = ({ + loading, + paragraphs, +}: { + loading: boolean; + paragraphs: string[]; +}) => { + return ( +
+
+
+
+ {loading ? ( + skeleton({ widthCls: 'w-36', heightCls: 'h-8' }) + ) : ( + About me + )} +
+
+
+ {loading ? ( +
+ {skeleton({ widthCls: 'w-full', heightCls: 'h-4', shape: 'rounded' })} + {skeleton({ widthCls: 'w-11/12', heightCls: 'h-4', shape: 'rounded' })} + {skeleton({ widthCls: 'w-full', heightCls: 'h-4', shape: 'rounded' })} +
+ ) : ( +
+ {paragraphs.map((p, i) => ( +

{p}

+ ))} +
+ )} +
+
+
+ ); +}; + +export default AboutCard; diff --git a/src/components/avatar-card/index.tsx b/src/components/avatar-card/index.tsx index f08c0ee..3009cc2 100644 --- a/src/components/avatar-card/index.tsx +++ b/src/components/avatar-card/index.tsx @@ -8,6 +8,10 @@ interface AvatarCardProps { loading: boolean; avatarRing: boolean; resumeFileUrl?: string; + /** When true, omit GitHub bio (e.g. when About me is in config). */ + suppressBio?: boolean; + /** When true, omit resume button (PDF is linked from Core strengths). */ + suppressResumeDownload?: boolean; } /** @@ -23,6 +27,8 @@ const AvatarCard: React.FC = ({ loading, avatarRing, resumeFileUrl, + suppressBio = false, + suppressResumeDownload = false, }): React.JSX.Element => { return (
@@ -70,13 +76,16 @@ const AvatarCard: React.FC = ({ )} -
- {loading || !profile - ? skeleton({ widthCls: 'w-48', heightCls: 'h-5' }) - : profile.bio} -
+ {!suppressBio && ( +
+ {loading || !profile + ? skeleton({ widthCls: 'w-48', heightCls: 'h-5' }) + : profile.bio} +
+ )}
{resumeFileUrl && + !suppressResumeDownload && (loading ? (
{skeleton({ widthCls: 'w-40', heightCls: 'h-8' })} diff --git a/src/components/gitprofile.tsx b/src/components/gitprofile.tsx index 485b6bd..3154bce 100644 --- a/src/components/gitprofile.tsx +++ b/src/components/gitprofile.tsx @@ -16,6 +16,7 @@ import { DEFAULT_THEMES } from '../constants/default-themes'; import ThemeChanger from './theme-changer'; import { BG_COLOR } from '../constants'; import AvatarCard from './avatar-card'; +import AboutCard from './about-card'; import { Profile } from '../interfaces/profile'; import DetailsCard from './details-card'; import SkillCard from './skill-card'; @@ -200,11 +201,22 @@ const GitProfile = ({ config }: { config: Config }) => { themeConfig={sanitizedConfig.themeConfig} /> )} + {sanitizedConfig.about.length !== 0 && ( + + )} { github={sanitizedConfig.github} social={sanitizedConfig.social} /> + {sanitizedConfig.resume.fileUrl && + sanitizedConfig.resume.previewLines.length !== 0 && ( + + )} {sanitizedConfig.skills.length !== 0 && ( )} - {sanitizedConfig.resume.fileUrl && - sanitizedConfig.resume.previewLines.length !== 0 && ( - - )} {sanitizedConfig.certifications.length !== 0 && ( { const pdfPath = resolvePublicUrl(fileUrl); @@ -65,7 +67,7 @@ const ResumeCard = ({ {loading ? ( skeleton({ widthCls: 'w-32', heightCls: 'h-8' }) ) : ( - Resume + {sectionTitle} )}
diff --git a/src/interfaces/sanitized-config.tsx b/src/interfaces/sanitized-config.tsx index fc44279..a626761 100644 --- a/src/interfaces/sanitized-config.tsx +++ b/src/interfaces/sanitized-config.tsx @@ -68,6 +68,7 @@ export interface SanitizedSocial { export interface SanitizedResume { fileUrl?: string; + sectionTitle: string; previewLines: Array; } @@ -131,6 +132,7 @@ export interface SanitizedConfig { projects: SanitizedProjects; seo: SanitizedSEO; location?: string; + about: Array; social: SanitizedSocial; resume: SanitizedResume; skills: Array; diff --git a/src/utils/index.tsx b/src/utils/index.tsx index bc2c0e3..b33a03b 100644 --- a/src/utils/index.tsx +++ b/src/utils/index.tsx @@ -76,6 +76,7 @@ export const getSanitizedConfig = ( imageURL: config?.seo?.imageURL, }, location: config?.location, + about: config?.about?.filter((p) => p.trim()) || [], social: { linkedin: config?.social?.linkedin, x: config?.social?.x, @@ -100,6 +101,7 @@ export const getSanitizedConfig = ( }, resume: { fileUrl: config?.resume?.fileUrl || '', + sectionTitle: config?.resume?.sectionTitle || 'Core strengths', previewLines: config?.resume?.previewLines || [], }, skills: config?.skills || [],