Skip to content

Commit 260574c

Browse files
committed
add pdf portfolio preview
1 parent 229594b commit 260574c

3 files changed

Lines changed: 99 additions & 10 deletions

File tree

195 KB
Binary file not shown.

src/scripts/resume-preview.js

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,46 @@
11
/**
2-
* Resume preview: open PDF in a modal overlay instead of downloading.
2+
* Resume / Portfolio preview: open PDF in a modal overlay.
33
* Binds to all links whose href points to Ilian-Khankhalaev-Resume.pdf.
4+
* Modal includes a toggle to flip between Resume and Portfolio PDFs.
45
*/
56
(function () {
67
var modal = null;
78
var iframe = null;
89
var closeBtn = null;
910
var downloadLink = null;
1011
var escapeHandler = null;
12+
var resumeUrl = null;
13+
var portfolioUrl = null;
14+
var btnResume = null;
15+
var btnPortfolio = null;
16+
17+
function setPdfView(url, label) {
18+
var separator = url.indexOf('#') === -1 ? '#' : '&';
19+
var pdfUrlWithView = url + separator + 'view=FitH';
20+
iframe.setAttribute('src', pdfUrlWithView);
21+
iframe.setAttribute('title', label);
22+
downloadLink.setAttribute('href', url);
23+
}
1124

1225
function createModal() {
1326
if (modal) return modal;
1427
modal = document.createElement('div');
1528
modal.className = 'resume-preview-modal';
1629
modal.setAttribute('role', 'dialog');
1730
modal.setAttribute('aria-modal', 'true');
18-
modal.setAttribute('aria-label', 'Resume preview');
31+
modal.setAttribute('aria-label', 'Resume and portfolio preview');
1932
modal.innerHTML =
2033
'<div class="resume-preview-backdrop" aria-hidden="true"></div>' +
2134
'<div class="resume-preview-box">' +
2235
'<div class="resume-preview-header">' +
23-
'<a href="#" class="resume-preview-download" target="_blank" rel="noopener noreferrer">Download PDF</a>' +
24-
'<button type="button" class="resume-preview-close" aria-label="Close preview">&times;</button>' +
36+
'<div class="resume-preview-toggle" role="tablist" aria-label="Choose document">' +
37+
'<button type="button" class="resume-preview-tab is-active" role="tab" aria-selected="true" data-doc="resume">Resume</button>' +
38+
'<button type="button" class="resume-preview-tab" role="tab" aria-selected="false" data-doc="portfolio">Portfolio</button>' +
39+
'</div>' +
40+
'<div class="resume-preview-header-right">' +
41+
'<a href="#" class="resume-preview-download" target="_blank" rel="noopener noreferrer">Download PDF</a>' +
42+
'<button type="button" class="resume-preview-close" aria-label="Close preview">&times;</button>' +
43+
'</div>' +
2544
'</div>' +
2645
'<div class="resume-preview-iframe-wrap">' +
2746
'<iframe class="resume-preview-iframe" title="Resume (PDF)"></iframe>' +
@@ -31,6 +50,8 @@
3150
iframe = modal.querySelector('.resume-preview-iframe');
3251
closeBtn = modal.querySelector('.resume-preview-close');
3352
downloadLink = modal.querySelector('.resume-preview-download');
53+
btnResume = modal.querySelector('.resume-preview-tab[data-doc="resume"]');
54+
btnPortfolio = modal.querySelector('.resume-preview-tab[data-doc="portfolio"]');
3455
var backdrop = modal.querySelector('.resume-preview-backdrop');
3556

3657
function close() {
@@ -55,16 +76,38 @@
5576
e.stopPropagation();
5677
downloadLink.setAttribute('href', iframe.getAttribute('src') || '#');
5778
});
79+
80+
btnResume.addEventListener('click', function () {
81+
if (!resumeUrl) return;
82+
btnResume.classList.add('is-active');
83+
btnResume.setAttribute('aria-selected', 'true');
84+
btnPortfolio.classList.remove('is-active');
85+
btnPortfolio.setAttribute('aria-selected', 'false');
86+
setPdfView(resumeUrl, 'Resume (PDF)');
87+
});
88+
btnPortfolio.addEventListener('click', function () {
89+
if (!portfolioUrl) return;
90+
btnPortfolio.classList.add('is-active');
91+
btnPortfolio.setAttribute('aria-selected', 'true');
92+
btnResume.classList.remove('is-active');
93+
btnResume.setAttribute('aria-selected', 'false');
94+
setPdfView(portfolioUrl, 'Portfolio (PDF)');
95+
});
96+
5897
return modal;
5998
}
6099

61-
function openPreview(url) {
100+
function openPreview(resumeHref) {
62101
createModal();
63-
var absoluteUrl = new URL(url, window.location.href).href;
64-
var separator = absoluteUrl.indexOf('#') === -1 ? '#' : '&';
65-
var pdfUrlWithView = absoluteUrl + separator + 'view=FitH';
66-
iframe.setAttribute('src', pdfUrlWithView);
67-
downloadLink.setAttribute('href', absoluteUrl);
102+
resumeUrl = new URL(resumeHref, window.location.href).href;
103+
portfolioUrl = resumeUrl.replace('Ilian-Khankhalaev-Resume.pdf', 'Ilian-Khankhalaev-Portfolio.pdf');
104+
105+
btnResume.classList.add('is-active');
106+
btnResume.setAttribute('aria-selected', 'true');
107+
btnPortfolio.classList.remove('is-active');
108+
btnPortfolio.setAttribute('aria-selected', 'false');
109+
setPdfView(resumeUrl, 'Resume (PDF)');
110+
68111
modal.classList.add('resume-preview-open');
69112
document.body.style.overflow = 'hidden';
70113
document.addEventListener('keydown', escapeHandler, true);

src/styles/main.css

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4042,6 +4042,52 @@ body.page-projects .project-detail .project-meta-links a:focus-visible {
40424042
-webkit-backdrop-filter: blur(12px);
40434043
}
40444044

4045+
.resume-preview-toggle {
4046+
display: flex;
4047+
align-items: center;
4048+
gap: 0;
4049+
background: rgba(0, 0, 0, 0.2);
4050+
border-radius: 10px;
4051+
padding: 3px;
4052+
border: 1px solid rgba(255, 255, 255, 0.08);
4053+
}
4054+
4055+
.resume-preview-tab {
4056+
padding: 0.45rem 1rem;
4057+
font-size: 0.8125rem;
4058+
font-weight: 500;
4059+
color: rgba(255, 255, 255, 0.65);
4060+
background: none;
4061+
border: none;
4062+
border-radius: 8px;
4063+
cursor: pointer;
4064+
transition: color 0.2s ease, background 0.2s ease;
4065+
}
4066+
4067+
.resume-preview-tab:hover {
4068+
color: rgba(255, 255, 255, 0.9);
4069+
}
4070+
4071+
.resume-preview-tab.is-active {
4072+
color: rgba(255, 255, 255, 0.98);
4073+
background: rgba(255, 255, 255, 0.1);
4074+
}
4075+
4076+
.resume-preview-tab:focus {
4077+
outline: none;
4078+
}
4079+
4080+
.resume-preview-tab:focus-visible {
4081+
outline: none;
4082+
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.35);
4083+
}
4084+
4085+
.resume-preview-header-right {
4086+
display: flex;
4087+
align-items: center;
4088+
gap: 0.75rem;
4089+
}
4090+
40454091
.resume-preview-download {
40464092
display: inline-flex;
40474093
align-items: center;

0 commit comments

Comments
 (0)