Skip to content

Commit 80569a8

Browse files
committed
Update CV and transition to GHActions
1 parent bb43d84 commit 80569a8

10 files changed

Lines changed: 415 additions & 49 deletions

File tree

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "github-actions"
4+
directory: "/"
5+
schedule:
6+
interval: "monthly"
7+
8+
- package-ecosystem: "pip"
9+
directory: "/"
10+
schedule:
11+
interval: "monthly"

.github/workflows/static.yml

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,55 @@
1-
# Simple workflow for deploying static content to GitHub Pages
2-
name: Deploy static content to Pages
1+
name: Build and deploy CV to Pages
32

43
on:
5-
# Runs on pushes targeting the default branch
64
push:
75
branches: ["master"]
8-
9-
# Allows you to run this workflow manually from the Actions tab
106
workflow_dispatch:
117

12-
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
138
permissions:
149
contents: read
1510
pages: write
1611
id-token: write
1712

18-
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
19-
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
13+
# Only one concurrent deployment; do not cancel in-progress runs.
2014
concurrency:
2115
group: "pages"
2216
cancel-in-progress: false
2317

2418
jobs:
25-
# Single deploy job since we're just deploying
26-
deploy:
27-
environment:
28-
name: github-pages
29-
url: ${{ steps.deployment.outputs.page_url }}
19+
build:
3020
runs-on: ubuntu-latest
3121
steps:
3222
- name: Checkout
3323
uses: actions/checkout@v4
24+
25+
- name: Set up Python
26+
uses: actions/setup-python@v5
27+
with:
28+
python-version: "3.x"
29+
cache: "pip"
30+
31+
- name: Install dependencies
32+
run: pip install -r requirements.txt
33+
34+
- name: Render CV
35+
run: rendercv render Resume.yaml
36+
3437
- name: Setup Pages
3538
uses: actions/configure-pages@v5
39+
3640
- name: Upload artifact
3741
uses: actions/upload-pages-artifact@v3
3842
with:
39-
# Upload entire repository
40-
path: '.'
43+
# Deploy only the pages/ directory — not the whole repo
44+
path: './pages'
45+
46+
deploy:
47+
environment:
48+
name: github-pages
49+
url: ${{ steps.deployment.outputs.page_url }}
50+
runs-on: ubuntu-latest
51+
needs: build
52+
steps:
4153
- name: Deploy to GitHub Pages
4254
id: deployment
4355
uses: actions/deploy-pages@v4

.gitignore

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11

22
.DS_Store
3-
*venv/
4-
*vscode/
5-
*output/
6-
3+
.venv/
4+
.vscode/
75
rendercv_output/
6+
7+
# CI-generated artifact — do not commit
8+
pages/alejnp_cv.pdf

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# alejnp.github.io
2+
3+
Personal CV site, live at [alejnp.github.io](https://alejnp.github.io).
4+
Courtesy of [RenderCV](https://rendercv.com) and GitHub Pages!
5+
6+
## How it works
7+
8+
1. [`Resume.yaml`](Resume.yaml) describes the content and structure of the CV,
9+
as well as RenderCV settings.
10+
2. Pushes to `master` will trigger CI, which:
11+
- Installs [RenderCV](https://rendercv.com) from `requirements.txt`.
12+
- Runs `rendercv render Resume.yaml`, writing the PDF to `pages/alejnp_cv.pdf`.
13+
- Deploys the `pages/` directory to GitHub Pages.
14+
3. Pages are available at [alejnp.github.io](https://alejnp.github.io)!
15+
16+
## Local preview
17+
18+
```bash
19+
python3 -m venv .venv
20+
. .venv/bin/activate
21+
python3 -m pip install -r requirements.txt
22+
python3 -m rendercv render Resume.yaml
23+
python3 -m http.server -d pages # open browser
24+
```

Resume.pdf

-58.2 KB
Binary file not shown.

Resume.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ locale:
22
language: english
33
settings:
44
render_command:
5-
pdf_path: "Resume.pdf"
5+
pdf_path: "pages/alejnp_cv.pdf"
66
dont_generate_html: true
77
dont_generate_markdown: true
88
dont_generate_png: true
@@ -16,7 +16,7 @@ cv:
1616
- network: LinkedIn
1717
username: alejnp
1818
- network: GitHub
19-
username: alxe
19+
username: alejnp
2020
sections:
2121
about me:
2222
- Hello! I'm Alejandro, a Software Engineer with over five years of

index.html

Lines changed: 0 additions & 28 deletions
This file was deleted.

pages/index.html

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<meta name="description" content="CV of Alejandro Núñez Pérez — Software Engineer with over five years of experience.">
8+
<meta name="author" content="Alejandro Núñez Pérez">
9+
<meta name="robots" content="index, follow">
10+
11+
<!-- Open Graph -->
12+
<meta property="og:title" content="Alejandro Núñez Pérez — CV">
13+
<meta property="og:description" content="Software Engineer with over five years of experience across multiple roles.">
14+
<meta property="og:type" content="website">
15+
<meta property="og:url" content="https://me.alejnp.es/">
16+
17+
<link rel="canonical" href="https://me.alejnp.es/">
18+
<link rel="icon" href="https://github.com/alejnp.png">
19+
<link rel="stylesheet" href="style.css">
20+
21+
<title>Alejandro Núñez Pérez — CV</title>
22+
</head>
23+
24+
<body>
25+
26+
<!-- Loading overlay: visible until the PDF (or fallback) is ready -->
27+
<div id="loading" role="status" aria-label="Loading CV…">
28+
<div class="spinner" aria-hidden="true"></div>
29+
<p>Loading CV...</p>
30+
</div>
31+
32+
<!-- PDF viewer ─────────────────────────────────────────────
33+
The inner #inline-fallback renders only when the browser
34+
cannot display the PDF. JS uses it as a sentinel to detect
35+
failure without any custom events.
36+
──────────────────────────────────────────────────────────── -->
37+
<object id="pdf-viewer" data="alejnp_cv.pdf" type="application/pdf"
38+
aria-label="Alejandro Núñez Pérez, CV (PDF)">
39+
<div id="inline-fallback"></div>
40+
</object>
41+
42+
<!-- Nicer fallback shown by JS (mobile / PDF load failure)
43+
Also acts as a <noscript>-accessible fallback since it has
44+
display:none only via JS; see noscript block below. -->
45+
<div id="fallback" class="fallback" style="display:none">
46+
<span data-icon aria-hidden="true">📄</span>
47+
<p>PDF preview is not available in this browser.</p>
48+
<a href="alejnp_cv.pdf" download class="btn">
49+
<!-- Download icon -->
50+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
51+
fill="none" stroke="currentColor" stroke-width="2"
52+
stroke-linecap="round" stroke-linejoin="round"
53+
aria-hidden="true">
54+
<path d="M12 15V3m0 12-4-4m4 4 4-4"/>
55+
<path d="M2 17v2a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-2"/>
56+
</svg>
57+
Download CV (PDF)
58+
</a>
59+
</div>
60+
61+
<!-- No-JS fallback: if JS is disabled, reveal the fallback via CSS -->
62+
<noscript>
63+
<style>
64+
#loading { display: none !important; }
65+
#fallback { display: flex !important; }
66+
</style>
67+
</noscript>
68+
69+
<!-- Floating download button ───────────────────────────────
70+
Hidden until JS marks it .visible after load. -->
71+
<a id="fab" href="alejnp_cv.pdf" download aria-label="Download CV">
72+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
73+
fill="none" stroke="currentColor" stroke-width="2.2"
74+
stroke-linecap="round" stroke-linejoin="round"
75+
aria-hidden="true">
76+
<path d="M12 15V3m0 12-4-4m4 4 4-4"/>
77+
<path d="M2 17v2a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-2"/>
78+
</svg>
79+
</a>
80+
81+
<script src="script.js"></script>
82+
</body>
83+
84+
</html>

pages/script.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
'use strict';
2+
3+
(function () {
4+
var PDF_URL = 'alejnp_cv.pdf';
5+
6+
var loading = document.getElementById('loading');
7+
var viewer = document.getElementById('pdf-viewer');
8+
var fallback = document.getElementById('fallback');
9+
var inlineSentinel = document.getElementById('inline-fallback');
10+
var fab = document.getElementById('fab');
11+
12+
/* ── Mobile / inline-PDF detection ─────────────────────────
13+
iOS Safari and most Android browsers cannot render PDFs
14+
inline. Detect this early and skip straight to the download
15+
UI instead of showing a blank <object> for several seconds.
16+
──────────────────────────────────────────────────────────── */
17+
function isMobileBrowser() {
18+
return /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
19+
}
20+
21+
function showFallback() {
22+
if (viewer) viewer.style.display = 'none';
23+
if (fallback) fallback.style.display = 'flex';
24+
if (loading) loading.classList.add('hidden');
25+
}
26+
27+
function hideLoading() {
28+
if (loading) loading.classList.add('hidden');
29+
showFab();
30+
}
31+
32+
function showFab() {
33+
if (fab) fab.classList.add('visible');
34+
}
35+
36+
/* ── Mobile: skip inline render entirely ───────────────── */
37+
if (isMobileBrowser()) {
38+
showFallback();
39+
return;
40+
}
41+
42+
/* ── Desktop: hide loader once the page has fully loaded ── */
43+
// window 'load' is the most cross-browser-reliable signal that
44+
// the <object> has either rendered the PDF or given up.
45+
window.addEventListener('load', function () {
46+
hideLoading();
47+
});
48+
49+
// Safety fallback: if 'load' never fires or stalls, give up
50+
// after 10 s so the spinner doesn't sit there forever.
51+
var safetyTimer = setTimeout(function () {
52+
hideLoading();
53+
}, 10000);
54+
55+
window.addEventListener('load', function () {
56+
clearTimeout(safetyTimer);
57+
58+
// Heuristic: the #inline-fallback div lives inside <object>.
59+
// It is only rendered (offsetParent !== null) when the browser
60+
// cannot display the PDF — i.e. it acted as fallback content.
61+
if (inlineSentinel && inlineSentinel.offsetParent !== null) {
62+
showFallback();
63+
}
64+
});
65+
66+
/* ── Verify the PDF URL is reachable (network error guard) ─
67+
Catches 404s and other HTTP errors that the <object> element
68+
swallows silently.
69+
──────────────────────────────────────────────────────────── */
70+
fetch(PDF_URL, { method: 'HEAD' })
71+
.then(function (res) {
72+
if (!res.ok) showFallback();
73+
})
74+
.catch(function () {
75+
showFallback();
76+
});
77+
}());

0 commit comments

Comments
 (0)