108 lines
2.3 KiB
Vue
108 lines
2.3 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from "vue";
|
|
|
|
interface TimelineItemData {
|
|
section: "education" | "work-experience" | "projects";
|
|
institution?: string;
|
|
degree?: string;
|
|
company?: string;
|
|
position?: string;
|
|
start: string;
|
|
end?: string;
|
|
excerpt?: string;
|
|
}
|
|
|
|
const props = defineProps<{ item: TimelineItemData }>();
|
|
|
|
const roleTitle = computed(() => {
|
|
if (props.item.section === "education") {
|
|
return props.item.degree || "No Title";
|
|
} else if (props.item.section === "work-experience") {
|
|
return props.item.position || "No Position";
|
|
}
|
|
return "";
|
|
});
|
|
|
|
const placeTitle = computed(() => {
|
|
if (props.item.section === "education") {
|
|
return props.item.institution || "";
|
|
} else if (props.item.section === "work-experience") {
|
|
return props.item.company || "";
|
|
}
|
|
return "";
|
|
});
|
|
|
|
const dateRange = computed(() => {
|
|
const { start, end } = props.item;
|
|
if (!end || end.toLowerCase() === "present") {
|
|
return `${start} - Present`;
|
|
}
|
|
return `${start} - ${end}`;
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="timeline-item">
|
|
<div class="timeline-dot"></div>
|
|
|
|
<div class="card card-lift card-gradient-border">
|
|
<div class="card-content">
|
|
<div class="card-header timeline-header">
|
|
<h3 class="card-title timeline-role">{{ roleTitle }}</h3>
|
|
<span class="card-meta">{{ dateRange }}</span>
|
|
</div>
|
|
|
|
<div class="timeline-place" v-if="placeTitle">
|
|
{{ placeTitle }}
|
|
</div>
|
|
|
|
<p
|
|
v-if="item.excerpt"
|
|
class="card-excerpt timeline-excerpt"
|
|
v-html="item.excerpt"
|
|
></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.timeline-item {
|
|
position: relative;
|
|
margin-bottom: 3em;
|
|
margin-left: 2.5rem;
|
|
}
|
|
|
|
.timeline-dot {
|
|
position: absolute;
|
|
left: -2rem;
|
|
top: 1.25rem;
|
|
width: 14px;
|
|
height: 14px;
|
|
border-radius: 50%;
|
|
background-color: var(--background-color);
|
|
border: 2px solid var(--outline-color);
|
|
transition:
|
|
background-color 0.3s,
|
|
border-color 0.3s;
|
|
}
|
|
|
|
.timeline-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-bottom: 0.5em;
|
|
}
|
|
|
|
.timeline-role {
|
|
margin: 0.2em 0 0.25em;
|
|
font-size: 1.2em;
|
|
color: var(--secondary-text-color);
|
|
font-weight: bold;
|
|
}
|
|
|
|
.timeline-place {
|
|
font-size: 1em;
|
|
color: var(--text-color);
|
|
margin-bottom: 0.75em;
|
|
}
|
|
</style>
|