From ff1e078be91082040b62445826489b9638084f5d Mon Sep 17 00:00:00 2001 From: Robin Dittmar Date: Sat, 5 Sep 2026 20:30:52 +0200 Subject: [PATCH] fix cv page improvements --- src/components/CvIcon.vue | 7 +- src/views/CvView.vue | 236 +++++++++++++++++++++++++++++--------- 2 files changed, 184 insertions(+), 59 deletions(-) diff --git a/src/components/CvIcon.vue b/src/components/CvIcon.vue index 3b3056c..3cbe46d 100644 --- a/src/components/CvIcon.vue +++ b/src/components/CvIcon.vue @@ -8,6 +8,7 @@ type IconName = | 'linkedin' | 'github' | 'code' + | 'verified' | 'summary' | 'experience' | 'education' @@ -20,8 +21,8 @@ type IconName = const props = defineProps<{ name: IconName }>() // Sourced from lucide-static (ISC license): phone, mail, map-pin, linkedin, -// github, file-text, briefcase, graduation-cap, award, languages, -// chart-column, layers, heart. +// github, code, badge-check, file-text, briefcase, graduation-cap, award, +// languages, chart-column, layers, heart. const MARKUP: Record = { phone: '', @@ -34,6 +35,8 @@ const MARKUP: Record = { github: '', code: '', + verified: + '', summary: '', experience: diff --git a/src/views/CvView.vue b/src/views/CvView.vue index d25e4af..d6c15eb 100644 --- a/src/views/CvView.vue +++ b/src/views/CvView.vue @@ -20,6 +20,13 @@ onBeforeUnmount(() => { robotsMeta?.remove() }) +interface Project { + title: string + repo: string + desc: string + url: string +} + interface ExperienceEntry { company: string location: string @@ -56,16 +63,24 @@ interface AdditionalExperience { desc: string } -interface Project { - title: string - repo: string - desc: string - url: string -} - const SKILL_MAX = 8 const LANGUAGE_MAX = 5 +const projects: Project[] = [ + { + title: 'Frontend', + repo: 'dttmr-fe', + desc: 'Offline-first PWA for shared, syncable to-do lists and tracking workouts. Vue 3 + TypeScript.', + url: 'https://git.dittmar.dev/robin/dttmr-fe', + }, + { + title: 'API', + repo: 'dttmr-api', + desc: 'Go backend powering auth and sync for the to-do list/workout tracking app.', + url: 'https://git.dittmar.dev/robin/dttmr-api', + }, +] + const experience: ExperienceEntry[] = [ { company: 'Greenbone AG', @@ -211,21 +226,6 @@ const skills: Skill[] = [ { name: 'Claude Code', rating: 4 }, ] -const projects: Project[] = [ - { - title: 'Frontend', - repo: 'dttmr-fe', - desc: 'Offline-first PWA for shared, syncable to-do lists. Vue 3 + TypeScript.', - url: 'https://git.dittmar.dev/robin/dttmr-fe', - }, - { - title: 'API', - repo: 'dttmr-api', - desc: 'Go backend powering auth and sync for the to-do list app.', - url: 'https://git.dittmar.dev/robin/dttmr-api', - }, -] - const additionalExperiences: AdditionalExperience[] = [ { title: 'Minecraft Mod', @@ -252,19 +252,20 @@ const additionalExperiences: AdditionalExperience[] = [ Portrait of Robin Dittmar

Robin Dittmar

- Software Developer + Software Developer
+ -
+

Contacts

Phone - +49159/01668799 + +49 1590 1668799

Email - robindittmar@gmail.com + robindittmar@gmail.com

Location @@ -310,7 +311,7 @@ const additionalExperiences: AdditionalExperience[] = [

Experience

-
    +
    • @@ -327,7 +328,7 @@ const additionalExperiences: AdditionalExperience[] = [

    Education

    -
      +
      • @@ -342,8 +343,11 @@ const additionalExperiences: AdditionalExperience[] = [

        Key Achievements

        -

        {{ item.title }}

        -

        {{ item.desc }}

        + +
        +

        {{ item.title }}

        +

        {{ item.desc }}

        +
        @@ -354,8 +358,13 @@ const additionalExperiences: AdditionalExperience[] = [ {{ lang.name }} {{ lang.level }}

        -
        -
        +
        +
@@ -365,8 +374,13 @@ const additionalExperiences: AdditionalExperience[] = [
{{ skill.name }} -
-
+
+
@@ -409,16 +423,18 @@ const additionalExperiences: AdditionalExperience[] = [ .profile-top { display: flex; align-items: center; - gap: 1rem; - margin-bottom: 1.25rem; + gap: 1.1rem; + margin-bottom: 1rem; } .profile-top h1 { font-size: 1.4rem; - margin-bottom: 0.4rem; + margin-bottom: 0.45rem; + letter-spacing: 0.01em; } .avatar { + display: block; width: 76px; height: 76px; border-radius: 50%; @@ -428,18 +444,48 @@ const additionalExperiences: AdditionalExperience[] = [ flex-shrink: 0; } +.role-badge { + display: inline-flex; + padding: 0.22rem 0.65rem; + border-radius: 3px; + background: var(--c-accent-bg); + color: var(--c-accent-strong); + font-size: 0.78rem; + font-weight: 500; +} + +.ledger-rule { + height: 4px; + margin-bottom: 1.5rem; + border-top: 1.5px solid var(--c-border-hover); + border-bottom: 1px dashed var(--c-border); +} + .section-heading { display: flex; align-items: center; - gap: 0.45rem; - font-size: 1.1rem; - margin: 1.75rem 0 0.75rem; + gap: 0.55rem; + font-size: 1.08rem; + font-weight: 600; + margin: 2rem 0 0.85rem; +} + +.section-heading::after { + content: ''; + flex: 1; + height: 1px; + background: var(--c-border); + margin-left: 0.35rem; } .section-heading .cv-icon { font-size: 0.85rem; color: var(--c-accent-strong); - opacity: 0.85; +} + +.card { + border-radius: 4px; + box-shadow: none; } .info-card { @@ -451,6 +497,11 @@ const additionalExperiences: AdditionalExperience[] = [ margin-bottom: 0.75rem; } +.contact-card { + border-color: var(--c-accent-soft); + box-shadow: 0 10px 28px rgba(61, 114, 180, 0.22); +} + .row { display: flex; justify-content: space-between; @@ -465,6 +516,18 @@ const additionalExperiences: AdditionalExperience[] = [ margin-bottom: 0; } +.info-card > .row { + padding-bottom: 0.5rem; + margin-bottom: 0.5rem; + border-bottom: 1px dashed var(--c-border); +} + +.info-card > .row:last-child { + padding-bottom: 0; + margin-bottom: 0; + border-bottom: none; +} + .row strong { color: var(--c-heading); } @@ -488,8 +551,30 @@ const additionalExperiences: AdditionalExperience[] = [ color: var(--c-text); } +.achievement-row { + display: flex; + gap: 0.7rem; + align-items: flex-start; +} + .achievement-row + .achievement-row { margin-top: 0.85rem; + padding-top: 0.85rem; + border-top: 1px dashed var(--c-border); +} + +.achv-icon { + display: flex; + align-items: center; + justify-content: center; + width: 1.6rem; + height: 1.6rem; + flex-shrink: 0; + margin-top: 0.05rem; + border-radius: 50%; + background: var(--c-accent-bg); + color: var(--c-accent-strong); + font-size: 0.9rem; } .achievement-row h4 { @@ -507,22 +592,24 @@ const additionalExperiences: AdditionalExperience[] = [ margin-top: 0.85rem; } -/* rating meters */ -.meter { - width: 100%; - height: 6px; - border-radius: 999px; - background: var(--c-bg-mute); - overflow: hidden; +/* rating tallies */ +.tally { + display: flex; + gap: 3px; } -.meter-fill { - height: 100%; - border-radius: 999px; +.tally-tick { + flex: 1; + height: 6px; + border-radius: 1px; + background: var(--c-bg-mute); +} + +.tally-tick.filled { background: var(--c-accent); } -.meter-lg { +.tally-lg .tally-tick { height: 7px; } @@ -536,6 +623,46 @@ const additionalExperiences: AdditionalExperience[] = [ margin: 0; } +/* timeline (experience / education): a real chronological record, so the + rail + nodes carry meaning rather than decorate */ +.timeline { + position: relative; + gap: 0.9rem; + padding-left: 1.1rem; +} + +.timeline::before { + content: ''; + position: absolute; + left: 3px; + top: 0.6rem; + bottom: 0.6rem; + width: 1px; + background: var(--c-border-hover); +} + +.timeline > li { + position: relative; +} + +.timeline > li::before { + content: ''; + position: absolute; + left: -1.1rem; + top: 1.1rem; + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--c-bg); + border: 1.5px solid var(--c-text-soft); +} + +.timeline-current > li:first-child::before { + border-color: var(--c-accent-strong); + background: var(--c-accent-strong); + box-shadow: 0 0 0 3px var(--c-accent-bg); +} + .job-card { padding: 0.9rem 1.1rem; } @@ -697,9 +824,4 @@ const additionalExperiences: AdditionalExperience[] = [ background-color: var(--c-bg-mute); color: var(--c-text-soft); } - -.tag-accent { - background-color: var(--c-accent-bg); - color: var(--c-accent-strong); -}