feat: ResumeProfileView — career_summary, education, achievements sections and sync status label
This commit is contained in:
parent
9f984c22cb
commit
22bc57242e
1 changed files with 102 additions and 0 deletions
|
|
@ -56,6 +56,23 @@
|
||||||
<p v-if="uploadError" class="error">{{ uploadError }}</p>
|
<p v-if="uploadError" class="error">{{ uploadError }}</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Sync status label -->
|
||||||
|
<div v-if="store.lastSynced" class="sync-status-label">
|
||||||
|
Content synced from Resume Library — {{ fmtDate(store.lastSynced) }}.
|
||||||
|
Changes here update the default library entry when you save.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Career Summary -->
|
||||||
|
<section class="form-section">
|
||||||
|
<h3>Career Summary</h3>
|
||||||
|
<p class="section-note">Used in cover letter generation and as your professional introduction.</p>
|
||||||
|
<div class="field-row">
|
||||||
|
<label for="career-summary">Career summary</label>
|
||||||
|
<textarea id="career-summary" v-model="store.career_summary"
|
||||||
|
rows="4" placeholder="2-3 sentences summarising your background and what you bring."></textarea>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Personal Information -->
|
<!-- Personal Information -->
|
||||||
<section class="form-section">
|
<section class="form-section">
|
||||||
<h3>Personal Information</h3>
|
<h3>Personal Information</h3>
|
||||||
|
|
@ -130,6 +147,57 @@
|
||||||
<button @click="store.addExperience()">+ Add Position</button>
|
<button @click="store.addExperience()">+ Add Position</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Education -->
|
||||||
|
<section class="form-section">
|
||||||
|
<h3>Education</h3>
|
||||||
|
<div v-for="(edu, idx) in store.education" :key="edu.id" class="experience-card">
|
||||||
|
<div class="experience-card__header">
|
||||||
|
<span class="experience-card__label">Education {{ idx + 1 }}</span>
|
||||||
|
<button class="btn-remove" @click="store.removeEducation(idx)"
|
||||||
|
:aria-label="`Remove education entry ${idx + 1}`">Remove</button>
|
||||||
|
</div>
|
||||||
|
<div class="field-row">
|
||||||
|
<label>Institution</label>
|
||||||
|
<input v-model="edu.institution" placeholder="University or school name" />
|
||||||
|
</div>
|
||||||
|
<div class="field-row-grid">
|
||||||
|
<div class="field-row">
|
||||||
|
<label>Degree</label>
|
||||||
|
<input v-model="edu.degree" placeholder="e.g. B.S., M.A., Ph.D." />
|
||||||
|
</div>
|
||||||
|
<div class="field-row">
|
||||||
|
<label>Field of study</label>
|
||||||
|
<input v-model="edu.field" placeholder="e.g. Computer Science" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field-row-grid">
|
||||||
|
<div class="field-row">
|
||||||
|
<label>Start year</label>
|
||||||
|
<input v-model="edu.start_date" placeholder="2015" />
|
||||||
|
</div>
|
||||||
|
<div class="field-row">
|
||||||
|
<label>End year</label>
|
||||||
|
<input v-model="edu.end_date" placeholder="2019" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn-secondary" @click="store.addEducation">+ Add education</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Achievements -->
|
||||||
|
<section class="form-section">
|
||||||
|
<h3>Achievements</h3>
|
||||||
|
<p class="section-note">Awards, certifications, open-source projects, publications.</p>
|
||||||
|
<div v-for="(ach, idx) in store.achievements" :key="idx" class="achievement-row">
|
||||||
|
<input :value="ach"
|
||||||
|
@input="store.achievements[idx] = ($event.target as HTMLInputElement).value"
|
||||||
|
placeholder="Describe the achievement" />
|
||||||
|
<button class="btn-remove" @click="store.achievements.splice(idx, 1)"
|
||||||
|
:aria-label="`Remove achievement ${idx + 1}`">✕</button>
|
||||||
|
</div>
|
||||||
|
<button class="btn-secondary" @click="store.achievements.push('')">+ Add achievement</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<section class="form-section">
|
<section class="form-section">
|
||||||
<h3>Preferences & Availability</h3>
|
<h3>Preferences & Availability</h3>
|
||||||
|
|
@ -302,6 +370,10 @@ function handleFileSelect(event: Event) {
|
||||||
uploadError.value = null
|
uploadError.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fmtDate(iso: string) {
|
||||||
|
return new Date(iso).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
|
||||||
|
}
|
||||||
|
|
||||||
async function handleUpload() {
|
async function handleUpload() {
|
||||||
const file = pendingFile.value
|
const file = pendingFile.value
|
||||||
if (!file) return
|
if (!file) return
|
||||||
|
|
@ -407,4 +479,34 @@ h3 { font-size: 1rem; font-weight: 600; margin-bottom: var(--space-3); }
|
||||||
.toggle-btn { margin-left: 10px; padding: 2px 10px; background: transparent; border: 1px solid var(--color-border); border-radius: 4px; color: var(--color-text-muted); cursor: pointer; font-size: 0.78rem; }
|
.toggle-btn { margin-left: 10px; padding: 2px 10px; background: transparent; border: 1px solid var(--color-border); border-radius: 4px; color: var(--color-text-muted); cursor: pointer; font-size: 0.78rem; }
|
||||||
.loading { text-align: center; padding: var(--space-8); color: var(--color-text-muted); }
|
.loading { text-align: center; padding: var(--space-8); color: var(--color-text-muted); }
|
||||||
.replace-section { background: var(--color-surface-alt); border-radius: 8px; padding: var(--space-4); }
|
.replace-section { background: var(--color-surface-alt); border-radius: 8px; padding: var(--space-4); }
|
||||||
|
.sync-status-label {
|
||||||
|
font-size: 0.82rem; color: var(--color-text-muted);
|
||||||
|
border-left: 3px solid var(--color-primary);
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
margin-bottom: var(--space-6);
|
||||||
|
background: color-mix(in srgb, var(--color-primary) 6%, var(--color-surface-alt));
|
||||||
|
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
|
||||||
|
}
|
||||||
|
.achievement-row {
|
||||||
|
display: flex; gap: var(--space-2); align-items: center; margin-bottom: var(--space-2);
|
||||||
|
}
|
||||||
|
.achievement-row input { flex: 1; }
|
||||||
|
.btn-remove {
|
||||||
|
background: none; border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--radius-sm); padding: 2px var(--space-2);
|
||||||
|
cursor: pointer; color: var(--color-text-muted); font-size: 0.8rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.btn-remove:hover { color: var(--color-error, #dc2626); border-color: var(--color-error, #dc2626); }
|
||||||
|
.field-row-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
|
||||||
|
.btn-secondary {
|
||||||
|
padding: 7px 16px; background: transparent;
|
||||||
|
border: 1px solid var(--color-border); border-radius: 6px;
|
||||||
|
color: var(--color-text-muted); cursor: pointer; font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
.btn-secondary:hover { border-color: var(--color-accent); color: var(--color-accent); }
|
||||||
|
.experience-card__header {
|
||||||
|
display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-3);
|
||||||
|
}
|
||||||
|
.experience-card__label { font-size: 0.82rem; color: var(--color-text-muted); font-weight: 500; }
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue