feat(xp): render experience timeline as a git-style terminal log#30
feat(xp): render experience timeline as a git-style terminal log#30
Conversation
Replace the old sidebar badges and linear timeline with a rich, git-inspired terminal view to present experiences as commits. This refactor adds a terminal header, commit list navigation, a styled git log window with graph visualization, commit metadata (hashes, author, date), tags as refs, tech badges as diff stats, and interactive behaviors (hover highlighting, smooth scroll to commit, show-more). It also removes the old BadgeGroup import/usages and via-logo helper, consolidates logo handling, updates date/formatting and duration formatting, and introduces many CSS rules to style the new terminal/log UI for multiple responsive breakpoints.
WalkthroughExperiencePage.vue has been redesigned from a traditional technologies sidebar to a terminal-style git log interface. The update introduces commit-oriented navigation, synthetic commit hashing, graph visualization, color-coded branches and tags, and interactive scrolling with expanded history toggling. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/pages/ExperiencePage.vue (1)
356-384: Clarify the "ago" suffix for current positions.Lines 379-381 append "ago" to the duration when
!experience.endDate(current position). This is semantically incorrect—"2y 3m ago" implies the experience ended 2y 3m in the past, but for current positions, the duration should represent time elapsed since starting, not time since ending.Consider either:
- Removing the "ago" suffix for current positions, or
- Changing the logic to show elapsed time since start more clearly
Apply this diff to remove the misleading "ago" suffix:
function calculateDuration(experience: Experience): string { const startDate = new Date(experience.startDate); const endDate = experience.endDate ? new Date(experience.endDate) : new Date(); const months = (endDate.getFullYear() - startDate.getFullYear()) * 12 + (endDate.getMonth() - startDate.getMonth()); const years = Math.floor(months / 12); const remainingMonths = months % 12; let duration = ""; if (years > 0) { duration += `${years}y`; } if (remainingMonths > 0) { if (duration) duration += " "; duration += `${remainingMonths}m`; } if (!duration) { duration = "<1m"; } - if (!experience.endDate) { - duration += " ago"; - } return duration; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/pages/ExperiencePage.vue(7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.vue: Indent content inside<script>and<style>tags in Vue files (configured viavueIndentScriptAndStyle: truein.prettierrc)
Use Vue 3 Composition API with<script setup>syntax for Vue components
D3 integration should use imperative DOM manipulation within Vue lifecycle hooks, kept separate from Vue reactivity
Files:
src/pages/ExperiencePage.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use constants:
IDEAL_BLIP_WIDTH = 22px,NEW_GROUP_BLIP_WIDTH = 88px,EXISTING_GROUP_BLIP_WIDTH = 124px
Files:
src/pages/ExperiencePage.vue
🧠 Learnings (2)
📚 Learning: 2025-12-14T01:59:00.938Z
Learnt from: CR
Repo: caiokf/homepage PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-14T01:59:00.938Z
Learning: Applies to **/*.vue : Use Vue 3 Composition API with `<script setup>` syntax for Vue components
Applied to files:
src/pages/ExperiencePage.vue
📚 Learning: 2025-12-14T01:59:00.938Z
Learnt from: CR
Repo: caiokf/homepage PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-14T01:59:00.938Z
Learning: Applies to **/*.{ts,tsx,vue} : Use constants: `IDEAL_BLIP_WIDTH = 22px`, `NEW_GROUP_BLIP_WIDTH = 88px`, `EXISTING_GROUP_BLIP_WIDTH = 124px`
Applied to files:
src/pages/ExperiencePage.vue
🔇 Additional comments (14)
src/pages/ExperiencePage.vue (14)
7-26: LGTM!The terminal header and commit navigation are well-implemented with proper interactive states (hover, active) and semantic button elements for accessibility.
28-42: LGTM!Career stats display properly uses computed properties and presents the information clearly.
46-54: LGTM!Terminal window chrome provides good visual fidelity to the git terminal aesthetic.
70-80: LGTM!The git graph visualization correctly handles visual states and boundary conditions for the graph lines and nodes.
85-118: LGTM!Commit metadata is well-structured with proper conditional rendering for optional fields like website links.
157-166: LGTM!Technology badges are rendered correctly using the parsed technologies list.
180-195: LGTM!The show-more functionality provides good progressive disclosure with clear messaging about the hidden content.
238-254: LGTM!The ref handling and scroll navigation are properly implemented using Vue 3's Composition API with appropriate type checking.
256-281: LGTM!All computed properties are correctly implemented with proper use of Sets for uniqueness and efficient calculations.
284-295: LGTM!The hash generation is deterministic and correctly uses modulo to safely index the base string. While not cryptographically secure, it's appropriate for generating stable UI identifiers.
298-328: LGTM!Color mapping functions properly handle tag-to-CSS-class mapping with appropriate fallbacks.
330-354: LGTM!Date formatting correctly mimics git's date output format with proper day/month name lookups.
386-388: LGTM!Technology parsing correctly splits and trims the comma-separated technology list.
391-1007: LGTM!The styling comprehensively implements the terminal/git log aesthetic with proper use of CSS custom properties, flexible layouts, and responsive design patterns. The code follows Vue file indentation guidelines.
Based on learnings, the style content inside the
<style>tag is properly indented as per thevueIndentScriptAndStyle: trueconfiguration.
| <div class="commit-diff"> | ||
| <div class="diff-header"> | ||
| <span class="diff-files" | ||
| >{{ parseTechnologies(experience.technologies).length }} technologies</span | ||
| > | ||
| <span class="diff-separator">|</span> | ||
| <span class="diff-insertions" | ||
| >+{{ Math.floor(Math.random() * 50000) + 10000 }}</span | ||
| > | ||
| <span class="diff-deletions" | ||
| >-{{ Math.floor(Math.random() * 20000) + 5000 }}</span | ||
| > | ||
| </div> |
There was a problem hiding this comment.
Make diff stats deterministic.
The diff insertions and deletions use Math.random() on lines 150-154, causing the values to change on every render. This breaks the git metaphor where diff stats are stable and consistent.
Apply this diff to generate deterministic values based on the experience data:
<div class="diff-header">
<span class="diff-files"
>{{ parseTechnologies(experience.technologies).length }} technologies</span
>
<span class="diff-separator">|</span>
<span class="diff-insertions"
- >+{{ Math.floor(Math.random() * 50000) + 10000 }}</span
+ >+{{ Math.floor((experience.slug.length * 3000 + index * 2000) % 50000) + 10000 }}</span
>
<span class="diff-deletions"
- >-{{ Math.floor(Math.random() * 20000) + 5000 }}</span
+ >-{{ Math.floor((experience.slug.length * 1000 + index * 500) % 20000) + 5000 }}</span
>
</div>Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/pages/ExperiencePage.vue around lines 144-156, the diff
insertions/deletions use Math.random() which changes on every render; replace
them with deterministic values derived from the experience data: compute a small
deterministic numeric hash (e.g., sum/rolling hash of experience.id or
JSON.stringify(experience) or experience.title) and map it into the original
ranges (insertions = (hash % 50000) + 10000, deletions = (hash2 % 20000) +
5000). Move this logic into a computed property or a helper function that
returns insertions/deletions for the given experience so the values remain
stable across renders.
Replace the old sidebar badges and linear timeline with a rich, git-inspired terminal view to present experiences as commits. This refactor adds a terminal header, commit list navigation, a styled git log window with graph visualization, commit metadata (hashes, author, date), tags as refs, tech badges as diff stats, and interactive behaviors (hover highlighting, smooth scroll to commit, show-more). It also removes the old BadgeGroup import/usages and via-logo helper, consolidates logo handling, updates date/formatting and duration formatting, and introduces many CSS rules to style the new terminal/log UI for multiple responsive breakpoints.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.