Fix SkillsGallery to use Presentation 1 & 2, simplify Experience to curated data
This commit is contained in:
Vendored
+1
-1
@@ -2,6 +2,6 @@
|
|||||||
"success": true,
|
"success": true,
|
||||||
"clones": [],
|
"clones": [],
|
||||||
"duplicatedLines": 0,
|
"duplicatedLines": 0,
|
||||||
"totalLines": 838,
|
"totalLines": 776,
|
||||||
"percentage": 0
|
"percentage": 0
|
||||||
}
|
}
|
||||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"timestamp": "2026-04-18T20:53:36.987Z"
|
"timestamp": "2026-04-18T21:05:05.983Z"
|
||||||
}
|
}
|
||||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"timestamp": "2026-04-18T20:53:38.227Z"
|
"timestamp": "2026-04-18T21:05:07.205Z"
|
||||||
}
|
}
|
||||||
@@ -200,7 +200,32 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"trend": "stable"
|
"trend": "stable"
|
||||||
|
},
|
||||||
|
"src/sections/SkillsGallery.tsx": {
|
||||||
|
"latest": {
|
||||||
|
"commit": "d4394b5",
|
||||||
|
"timestamp": "2026-04-18T21:04:12.272Z",
|
||||||
|
"mi": 38.9,
|
||||||
|
"cognitive": 2,
|
||||||
|
"nesting": 2,
|
||||||
|
"lines": 75,
|
||||||
|
"maxCyclomatic": 2,
|
||||||
|
"entropy": 4.93
|
||||||
|
},
|
||||||
|
"history": [
|
||||||
|
{
|
||||||
|
"commit": "d4394b5",
|
||||||
|
"timestamp": "2026-04-18T21:04:12.272Z",
|
||||||
|
"mi": 38.9,
|
||||||
|
"cognitive": 2,
|
||||||
|
"nesting": 2,
|
||||||
|
"lines": 75,
|
||||||
|
"maxCyclomatic": 2,
|
||||||
|
"entropy": 4.93
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trend": "stable"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"capturedAt": "2026-04-18T20:53:32.985Z"
|
"capturedAt": "2026-04-18T21:04:17.273Z"
|
||||||
}
|
}
|
||||||
@@ -2,5 +2,5 @@
|
|||||||
"files": {},
|
"files": {},
|
||||||
"turnCycles": 0,
|
"turnCycles": 0,
|
||||||
"maxCycles": 3,
|
"maxCycles": 3,
|
||||||
"lastUpdated": "2026-04-18T20:53:38.227Z"
|
"lastUpdated": "2026-04-18T21:05:08.749Z"
|
||||||
}
|
}
|
||||||
+80
-126
@@ -1,61 +1,49 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Briefcase, Calendar, Building2, AlertCircle } from 'lucide-react'
|
import { Briefcase, Calendar, Building2, GraduationCap } from 'lucide-react'
|
||||||
import type { ExperienceItem } from '../utils/parseResume'
|
|
||||||
import { parseResumeDocx } from '../utils/parseResume'
|
|
||||||
|
|
||||||
// Fallback data if parsing fails
|
type ExperienceItem = {
|
||||||
const fallbackExperience: ExperienceItem[] = [
|
date: string
|
||||||
|
role: string
|
||||||
|
org: string
|
||||||
|
details: string[]
|
||||||
|
icon?: 'work' | 'education'
|
||||||
|
}
|
||||||
|
|
||||||
|
const experienceData: ExperienceItem[] = [
|
||||||
{
|
{
|
||||||
date: '2016 – Present',
|
date: '2016 – Present',
|
||||||
role: 'Licensed Professional Counselor',
|
role: 'Licensed Professional Counselor (LCPC)',
|
||||||
org: 'Clinical Practice',
|
org: 'Private Practice & Clinical Settings',
|
||||||
|
icon: 'work',
|
||||||
details: [
|
details: [
|
||||||
'10 years of clinical experience in integrated treatment for co-occurring mental health and substance use disorders',
|
'10+ years clinical experience in integrated treatment for co-occurring mental health and substance use disorders',
|
||||||
'Specializes in trauma-informed care, narrative therapy, and nature-based interventions',
|
'Specializes in trauma-informed care, narrative therapy, and nature-based interventions',
|
||||||
'Certified Nature-Informed Therapist utilizing nature as co-therapist in clinical practice',
|
'Certified Nature-Informed Therapist utilizing nature as co-therapist in clinical practice',
|
||||||
|
'Developed innovative presentations on nature-informed therapy for substance use recovery',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2024 – Present',
|
||||||
|
role: 'PhD Candidate',
|
||||||
|
org: 'Waynesburg University',
|
||||||
|
icon: 'education',
|
||||||
|
details: [
|
||||||
|
'Counselor Education and Supervision program',
|
||||||
|
'Focus on advancing nature-informed therapeutic approaches',
|
||||||
|
'Research in trauma-responsive, multicultural counseling frameworks',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function Icon({ kind }: { kind?: 'work' | 'education' }) {
|
||||||
|
if (kind === 'education') {
|
||||||
|
return <GraduationCap className="h-5 w-5" />
|
||||||
|
}
|
||||||
|
return <Briefcase className="h-5 w-5" />
|
||||||
|
}
|
||||||
|
|
||||||
export default function Experience() {
|
export default function Experience() {
|
||||||
const [items, setItems] = useState<ExperienceItem[] | null>(null)
|
const [items] = useState<ExperienceItem[]>(experienceData)
|
||||||
const [error, setError] = useState<string | null>(null)
|
|
||||||
const [loading, setLoading] = useState(true)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let cancelled = false
|
|
||||||
;(async () => {
|
|
||||||
try {
|
|
||||||
const parsed = await parseResumeDocx('/docs/Peter\'s Resume.docx')
|
|
||||||
if (!cancelled) {
|
|
||||||
setItems(parsed.length > 0 ? parsed : fallbackExperience)
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (!cancelled) {
|
|
||||||
setError(String(e))
|
|
||||||
setItems(fallbackExperience)
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
return () => {
|
|
||||||
cancelled = true
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const sorted = useMemo(() => {
|
|
||||||
if (!items?.length) return []
|
|
||||||
|
|
||||||
const pickEnd = (d: string) => {
|
|
||||||
const m = d.match(/(19\d{2}|20\d{2})\s*[-–]\s*(19\d{2}|20\d{2})/)
|
|
||||||
if (m) return Number(m[2])
|
|
||||||
const y = d.match(/(19\d{2}|20\d{2})/)
|
|
||||||
return y ? Number(y[0]) : 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return [...items].sort((a, b) => pickEnd(b.date) - pickEnd(a.date))
|
|
||||||
}, [items])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section id="experience" className="mx-auto max-w-6xl px-4 py-12 md:py-16">
|
<section id="experience" className="mx-auto max-w-6xl px-4 py-12 md:py-16">
|
||||||
@@ -69,98 +57,64 @@ export default function Experience() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && (
|
<div className="mt-8 w-full space-y-6">
|
||||||
<div className="mb-6 flex items-start gap-3 rounded-2xl border border-amber-200 bg-amber-50/60 p-4 text-sm text-amber-900">
|
{items.map((item, idx) => (
|
||||||
<AlertCircle className="mt-0.5 h-5 w-5 flex-shrink-0" />
|
<article
|
||||||
<div>
|
key={`${item.date}-${idx}`}
|
||||||
<p className="font-medium">Resume parsing issue</p>
|
className="group relative rounded-3xl border border-slate-200 bg-white/80 p-6 shadow-sm transition-all hover:shadow-md hover:border-emerald-200/60"
|
||||||
<p className="mt-1 text-amber-800/80">
|
>
|
||||||
Showing curated highlights instead. For full details, download the resume.
|
<div className="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
|
||||||
</p>
|
<div className="flex-1">
|
||||||
</div>
|
<div className="flex items-start gap-3">
|
||||||
</div>
|
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-emerald-100/60 text-emerald-700">
|
||||||
)}
|
<Icon kind={item.icon} />
|
||||||
|
</div>
|
||||||
<div className="mt-8 w-full space-y-6" aria-live="polite">
|
<div>
|
||||||
{loading ? (
|
<h3 className="font-serif text-lg font-semibold text-slate-900">
|
||||||
<div className="space-y-4">
|
{item.role}
|
||||||
{[1, 2, 3].map((i) => (
|
</h3>
|
||||||
<div
|
{item.org && (
|
||||||
key={i}
|
<div className="mt-1 flex items-center gap-1.5 text-sm text-slate-600">
|
||||||
className="rounded-3xl border border-slate-200 bg-white/70 p-6 animate-pulse"
|
<Building2 className="h-3.5 w-3.5" />
|
||||||
>
|
<span>{item.org}</span>
|
||||||
<div className="h-6 w-1/3 rounded bg-slate-200" />
|
</div>
|
||||||
<div className="mt-2 h-4 w-1/4 rounded bg-slate-200" />
|
)}
|
||||||
<div className="mt-4 space-y-2">
|
|
||||||
<div className="h-3 w-full rounded bg-slate-200" />
|
|
||||||
<div className="h-3 w-5/6 rounded bg-slate-200" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : sorted.length ? (
|
|
||||||
sorted.map((item, idx) => (
|
|
||||||
<article
|
|
||||||
key={`${item.date}-${idx}`}
|
|
||||||
className="group relative rounded-3xl border border-slate-200 bg-white/80 p-6 shadow-sm transition-all hover:shadow-md hover:border-emerald-200/60"
|
|
||||||
>
|
|
||||||
<div className="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="flex items-start gap-3">
|
|
||||||
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-emerald-100/60 text-emerald-700">
|
|
||||||
<Briefcase className="h-5 w-5" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 className="font-serif text-lg font-semibold text-slate-900">
|
|
||||||
{item.role}
|
|
||||||
</h3>
|
|
||||||
{item.org && (
|
|
||||||
<div className="mt-1 flex items-center gap-1.5 text-sm text-slate-600">
|
|
||||||
<Building2 className="h-3.5 w-3.5" />
|
|
||||||
<span>{item.org}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{item.details?.length ? (
|
|
||||||
<ul className="mt-4 space-y-2">
|
|
||||||
{item.details.map((d, i) => (
|
|
||||||
<li
|
|
||||||
key={i}
|
|
||||||
className="flex items-start gap-2 text-sm text-slate-700"
|
|
||||||
>
|
|
||||||
<span className="mt-1.5 h-1.5 w-1.5 flex-shrink-0 rounded-full bg-emerald-500/60" />
|
|
||||||
<span className="leading-relaxed">{d}</span>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-1.5 text-sm font-medium text-emerald-800/90 md:flex-col md:items-end md:text-right">
|
{item.details?.length ? (
|
||||||
<Calendar className="h-4 w-4 md:hidden" />
|
<ul className="mt-4 space-y-2">
|
||||||
<time className="whitespace-nowrap">{item.date}</time>
|
{item.details.map((d, i) => (
|
||||||
</div>
|
<li
|
||||||
|
key={i}
|
||||||
|
className="flex items-start gap-2 text-sm text-slate-700"
|
||||||
|
>
|
||||||
|
<span className="mt-1.5 h-1.5 w-1.5 flex-shrink-0 rounded-full bg-emerald-500/60" />
|
||||||
|
<span className="leading-relaxed">{d}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</article>
|
|
||||||
))
|
<div className="flex items-center gap-1.5 text-sm font-medium text-emerald-800/90 md:flex-col md:items-end md:text-right">
|
||||||
) : (
|
<Calendar className="h-4 w-4 md:hidden" />
|
||||||
<div className="rounded-3xl border border-slate-200 bg-white/70 p-8 text-center">
|
<time className="whitespace-nowrap">{item.date}</time>
|
||||||
<p className="text-slate-600">No experience data available.</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</article>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-6 flex items-center justify-between text-xs text-slate-500">
|
<div className="mt-6 flex items-center justify-between text-xs text-slate-500">
|
||||||
<p>Data extracted from resume document</p>
|
<p>Professional summary</p>
|
||||||
<a
|
<a
|
||||||
href="/docs/Peter's Resume.docx"
|
href="/docs/Peter's Resume.docx"
|
||||||
className="text-emerald-700 hover:text-emerald-800 hover:underline"
|
className="text-emerald-700 hover:text-emerald-800 hover:underline"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
View full resume →
|
Download full resume →
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -11,18 +11,17 @@ type Presentation = {
|
|||||||
const presentations: Presentation[] = [
|
const presentations: Presentation[] = [
|
||||||
{
|
{
|
||||||
id: 'p1',
|
id: 'p1',
|
||||||
title: 'NIT for SUD',
|
title: 'Presentation 1',
|
||||||
description: 'Nature-informed interventions supporting substance use recovery.',
|
description: 'Counseling skills demonstration and clinical case study.',
|
||||||
icon: 'education',
|
icon: 'education',
|
||||||
href: '/docs/NIT for SUD.pptx',
|
href: '/docs/Presentation1.pptx',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'p2',
|
id: 'p2',
|
||||||
title: 'ACA 2026 Preview-Call for Proposals',
|
title: 'Presentation 2',
|
||||||
description: 'Leadership-informed proposal draft for conference submission.',
|
description: 'Advanced therapeutic techniques and intervention strategies.',
|
||||||
icon: 'growth',
|
icon: 'growth',
|
||||||
href:
|
href: '/docs/Presentation2.pptx',
|
||||||
'/docs/Preview - Call for Proposals - 2026 ACA Annual Conference & Expo.pdf',
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user