Skip to content

feat(xp): add terminal-style ui for experience timeline#32

Open
caiokf wants to merge 1 commit intomainfrom
terminal-ui-experience-timeline
Open

feat(xp): add terminal-style ui for experience timeline#32
caiokf wants to merge 1 commit intomainfrom
terminal-ui-experience-timeline

Conversation

@caiokf
Copy link
Owner

@caiokf caiokf commented Dec 14, 2025

terminal-ui

Replace the traditional card-based timeline with a terminal-themed presentation to show career entries in a command-output style. This introduces a .terminal container, header (window controls and title), prompt/output lines, ASCII timeline connectors, compact formatted fields (role, period, tags, highlights, tech stack, URL), and a show-more interaction that reveals remaining entries. Also update computed properties (totalCompanies, remainingCount), utilities (formatting, duration, tag classes), and various CSS styles to support the terminal UI and responsive behavior.

The change was needed to provide an alternative terminal UI option requested in the prompt, offering a compact, readable, and themed way to browse experiences while keeping existing data (highlights, technologies, websites) available in a CLI-like layout.

Summary by CodeRabbit

  • New Features
    • Redesigned Experience section with a new terminal-style interface for improved visual presentation.
    • Enhanced date and duration formatting with clearer start-to-end date displays (e.g., "3y 4m", "<1m").
    • Experience entries now prominently display tags, highlights, and technology stacks in a more organized layout.

✏️ Tip: You can customize this high-level summary in your review settings.

Replace the traditional card-based timeline with a terminal-themed presentation to show career entries in a command-output style. This introduces a .terminal container, header (window controls and title), prompt/output lines, ASCII timeline connectors, compact formatted fields (role, period, tags, highlights, tech stack, URL), and a show-more interaction that reveals remaining entries. Also update computed properties (totalCompanies, remainingCount), utilities (formatting, duration, tag classes), and various CSS styles to support the terminal UI and responsive behavior.

The change was needed to provide an alternative terminal UI option requested in the prompt, offering a compact, readable, and themed way to browse experiences while keeping existing data (highlights, technologies, websites) available in a CLI-like layout.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 14, 2025

Walkthrough

The ExperiencePage.vue component undergoes a comprehensive visual redesign, transitioning from a timeline-based layout to a terminal-style UI. The changes include new computed properties for company statistics, helper functions for date/tag/technology formatting, restructured template rendering, and extensive CSS styling to achieve the terminal aesthetic.

Changes

Cohort / File(s) Summary
Terminal UI Experience Redesign
src/pages/ExperiencePage.vue
Replaces timeline experience rendering with terminal-style UI block structure; adds computed properties (totalCompanies, remainingCount) and helper functions (getViaName, formatDateRange, formatMonth, parseTechnologies, getTagClass); reformats date displays with arrow indicators (start → end); restructures experience data presentation with explicit Period, Tags, Highlights, and Stack fields; removes logo imports and via mappings; reorganizes CSS for terminal header/body, prompt lines, output formatting, tag styling, and theme handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

Areas requiring attention:

  • Verify all date formatting helpers (formatDateRange, formatMonth) produce expected output formats across edge cases (single months, year-only spans, "present" scenarios)
  • Test the computed properties (totalCompanies, remainingCount) logic for accuracy with various experience datasets
  • Validate the parseTechnologies helper correctly splits and formats technology stacks
  • Review CSS terminal styling for accessibility, responsiveness, and cross-browser compatibility
  • Confirm the getTagClass mapping aligns with intended tag color schemes
  • Test the showAll toggle behavior and "END OF CAREER LOG" conditional rendering

Poem

🐰 A terminal awakens, all pixels align, \
Experience logs blink in glowing design, \
From timelines past to command-line bright, \
The career story shines in monospace light!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(xp): add terminal-style ui for experience timeline' accurately and clearly describes the main change - introducing a terminal-style UI for the experience timeline component.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch terminal-ui-experience-timeline

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/pages/ExperiencePage.vue (1)

387-440: Consider whether hard-coded terminal colors align with maintainability goals.

The terminal UI uses hard-coded hex colors (#1a1a1a, #2d2d2d, #50fa7b, etc.) rather than CSS custom properties like var(--color-*). This ensures a consistent terminal theme across light and dark modes (confirmed by lines 748-754), but reduces maintainability if colors need to change. If the terminal should always use a fixed Dracula-style palette regardless of site theme, this is acceptable; otherwise, consider abstracting key colors to custom properties.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9570d4e and 1eaed83.

📒 Files selected for processing (1)
  • src/pages/ExperiencePage.vue (8 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 via vueIndentScriptAndStyle: true in .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 (1)
📚 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 (8)
src/pages/ExperiencePage.vue (8)

13-22: LGTM!

The terminal header effectively establishes the terminal aesthetic with window controls and a command-style title.


199-206: LGTM!

The via name mapping handles unknown values gracefully with a fallback to the original value.


211-218: LGTM!

The years of experience calculation correctly finds the oldest start date and computes the difference from the current year.


229-254: LGTM!

The computed properties correctly handle visible experiences and recent technologies filtering. The case-insensitive sorting ensures consistent technology display.


287-327: LGTM!

The duration calculation, technology parsing, and tag classification functions are implemented correctly. The compact duration format (e.g., "3y 4m", "<1m") fits the terminal aesthetic well.


490-663: LGTM!

The experience block and detail line styles comprehensively support the terminal UI layout with appropriate visual hierarchy and color coding.


701-755: LGTM!

The responsive styles appropriately scale the terminal UI for different screen sizes. The custom media queries (--md, --lg) assume proper configuration elsewhere in the build setup.


256-285: No error handling needed for date formatting.

All dates in experiencesConfig use valid ISO 8601 format (YYYY-MM-DD). The data is hardcoded and consistently formatted, so new Date() will always produce valid date objects. Error handling for invalid dates is unnecessary in this context.

Likely an incorrect or invalid review comment.

Comment on lines +61 to +69
<div class="timeline-connector">
<span v-if="index === 0" class="connector-char">┌</span>
<span v-else class="connector-char">├</span>
<span class="connector-line">────</span>
<span class="connector-node" :class="{ current: !experience.endDate }">{{
!experience.endDate ? "◉" : "○"
}}</span>
<span class="connector-line">──</span>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Consider adding aria-hidden to decorative ASCII timeline characters.

The ASCII timeline connectors (┌, ├, ○, ◉, etc.) are purely decorative but may be announced by screen readers in confusing ways. Consider wrapping the timeline-connector divs or the individual spans with aria-hidden="true" to improve accessibility.

Example:

-<div class="timeline-connector">
+<div class="timeline-connector" aria-hidden="true">
🤖 Prompt for AI Agents
In src/pages/ExperiencePage.vue around lines 61-69, the ASCII timeline
characters are decorative and should be hidden from assistive tech; add
aria-hidden="true" to the timeline-connector container or to each decorative
span (connector-char, connector-line, connector-node) so screen readers skip
them, and ensure any semantic status (e.g., current vs ended) is exposed
separately to AT via an accessible label or a visually-hidden element on the
experience item.

Comment on lines +156 to +171
<div v-if="!showAll" class="show-more-block">
<div class="timeline-connector">
<span class="connector-char">│</span>
</div>
<div class="output-line">
<span class="output-dim">... {{ remainingCount }} more entries hidden ...</span>
</div>
<div class="output-line blank"></div>
<div class="prompt-line">
<span class="prompt">$</span>
<button @click="showAll = true" class="show-more-cmd">
career --list --all
<span class="cursor">▋</span>
</button>
</div>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard against showing the block when remainingCount ≤ 0.

If the total number of experiences is less than or equal to INITIAL_VISIBLE_COUNT, remainingCount (line 225) will be zero or negative, yet the show-more block will still display with a confusing message like "... 0 more entries hidden ...".

Apply this diff to fix the condition:

-<div v-if="!showAll" class="show-more-block">
+<div v-if="!showAll && remainingCount > 0" class="show-more-block">
🤖 Prompt for AI Agents
In src/pages/ExperiencePage.vue around lines 156 to 171, the "show-more" block
is rendered even when remainingCount is 0 or negative; change the v-if to guard
both conditions (only render when not showing all AND remainingCount > 0).
Update the template condition from v-if="!showAll" to v-if="!showAll &&
remainingCount > 0" so the block is hidden when there are no additional entries
to reveal.

Comment on lines +686 to 699
.cursor {
color: #50fa7b;
animation: blink 1s step-end infinite;
}

.show-more-line {
display: block;
@keyframes blink {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Respect prefers-reduced-motion for the blinking cursor.

The blinking cursor animation should pause for users who have requested reduced motion to improve accessibility.

Apply this diff:

 @keyframes blink {
   0%,
   100% {
     opacity: 1;
   }
   50% {
     opacity: 0;
   }
 }
+
+@media (prefers-reduced-motion: reduce) {
+  .cursor {
+    animation: none;
+  }
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.cursor {
color: #50fa7b;
animation: blink 1s step-end infinite;
}
.show-more-line {
display: block;
@keyframes blink {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
.cursor {
color: #50fa7b;
animation: blink 1s step-end infinite;
}
@keyframes blink {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.cursor {
animation: none;
}
}
🤖 Prompt for AI Agents
In src/pages/ExperiencePage.vue around lines 686 to 699, the .cursor blinking
animation does not respect users' prefers-reduced-motion setting; add a CSS
media query to disable the animation for users who prefer reduced motion (e.g.
@media (prefers-reduced-motion: reduce) { .cursor { animation: none; } }) so the
cursor does not blink when reduced motion is requested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant