A personal portfolio website for downloading CVs in English and French, with a responsive design, dark mode, and language filtering.
Live Site: https://odysseu.github.io/
- Dual Language Support: English and French CVs with language toggle
- Multiple Versions: Simple (1-page) and Full (detailed) versions for each language
- Dark Mode: Toggle between light and dark themes (persisted via localStorage)
- Responsive Design: Works on mobile, tablet, and desktop
- Preview Images: Visual previews of each CV version
- Direct Download: Click preview images to download PDFs
- GitHub Profile Link: Clickable profile picture linking to GitHub
.
├── index.html # Main webpage
├── favicon.ico # Site favicon
├── circle_profile.png # Profile picture
├── github_profile.jpg # GitHub profile image (unused)
├── css/
│ └── styles.css # All styles with CSS variables for theming
├── js/
│ └── script.js # Interactive functionality
├── build_cv_website.sh # Full build script (LaTeX + previews)
├── generate_cv_previews.py # Generate preview images from PDFs
├── cv_english_simple.tex # English CV (1-page version)
├── cv_english_full.tex # English CV (detailed version)
├── cv_french_simple.tex # French CV (1-page version)
├── cv_french_full.tex # French CV (detailed version)
├── *.pdf # Generated CV PDFs
└── *preview.png # Generated preview images
index.html
├── css/styles.css
│ ├── :root variables (light theme colors)
│ ├── body.dark-mode variables (dark theme colors)
│ ├── .container, .profile-picture, .cv-grid, etc.
│ └── Responsive breakpoints
└── js/script.js
├── filterByLanguage() - Shows/hides CVs by language
├── toggleDarkMode() - Toggles dark mode + saves preference
├── updateDarkModeButton() - Updates button icon
└── downloadCV(version) - Triggers PDF download
- Profile Section: Profile picture (links to GitHub), title, subtitle
- Theme Toggle: Button in top-right corner
- Language Tabs: Radio buttons for English/French filtering
- CV Grid: Preview images organized by language, clickable to download
- Note Section: Instructions for users
- CSS Custom Properties (variables) for easy theming
- Dark mode via
body.dark-modeclass - Flexbox/Grid for responsive layouts
- Hover effects on CV preview cards
- Proper contrast for accessibility
- Language Filtering: Uses
data-languageattributes and CSS.hiddenclass - Dark Mode Persistence: Saves preference to
localStorage - Dynamic Downloads: Creates temporary
<a>elements withdownloadattribute - DOMContentLoaded: Initializes language filter and dark mode on page load
The site uses a automated build system to generate PDFs from LaTeX source files and create preview images.
1. LaTeX Compilation
├── cv_english_simple.tex → cv_english_simple.pdf
├── cv_english_full.tex → cv_english.pdf
├── cv_french_simple.tex → cv_french_simple.pdf
└── cv_french_full.tex → cv_french.pdf
2. Preview Generation
├── cv_english.pdf → english_simple_cv_preview.png (200px wide)
├── cv_english.pdf → english_full_cv_preview.png (200px wide)
├── cv_french.pdf → french_simple_cv_preview.png (200px wide)
└── cv_french.pdf → french_full_cv_preview.png (200px wide)
3. Static Site
└── index.html references all generated files
# Make executable (first time only)
chmod +x build_cv_website.sh
# Run full build
./build_cv_website.shpython3 generate_cv_previews.pyrm -f cv_*.pdf
./build_cv_website.shpdflatex- LaTeX compiler (part of TeX Live)- Required LaTeX packages:
fontawesome,latexsym, French language support
ghostscript- PDF to image conversion- Python 3 with
Pillowlibrary - Image resizing
# LaTeX and required packages
sudo apt install texlive texlive-latex-extra texlive-fonts-extra texlive-lang-french
# Ghostscript for PDF to PNG conversion
sudo apt install ghostscript
# Python Pillow for image processing
pip install PillowThis is a static site. Simply push to the main branch of this repository:
# After building
git add .
git commit -m "Update CVs and rebuild"
git push origin mainGitHub Pages will automatically serve the site from the root directory.
- Edit the
.texfiles (cv_english_simple.tex, etc.) - Run the build script:
./build_cv_website.sh - Commit and push changes
- Create new
.texfile - Add PDF generation to
build_cv_website.sh - Add preview generation to
generate_cv_previews.py - Add HTML element in
index.htmlwith properonclickhandler - Add mapping in
js/script.jsdownloadCV()function
Edit css/styles.css:
- Light theme: Modify
:rootvariables - Dark theme: Modify
body.dark-modevariables - Layout: Adjust
.container,.cv-grid, etc.
- Add new language
.texfiles - Update
build_cv_website.shandgenerate_cv_previews.py - Add radio button in
index.html - Add corresponding
.language-groupdiv withdata-languageattribute - Add language mappings in
js/script.js
! LaTeX Error: File `fontawesome.sty' not found.
Solution: Install required packages:
sudo apt install texlive-latex-extra texlive-fonts-extra texlive-lang-frenchgs: command not found
Solution: Install ghostscript:
sudo apt install ghostscriptModuleNotFoundError: No module named 'PIL'
Solution: Install Pillow:
pip install PillowThe build script will use existing PDFs if compilation fails. Check:
- LaTeX file paths are correct
- No syntax errors in
.texfiles - All required LaTeX packages are installed
- Uses ghostscript at 150 DPI for initial conversion
- Resizes to 200px width with aspect ratio preserved
- Uses LANCZOS resampling for quality
- Temporary files are automatically cleaned up
- Runs
pdflatextwice to resolve all references - Uses
-interaction=nonstopmodeto prevent hanging on errors - Falls back to existing PDFs if compilation fails
- CSS variables switch between light/dark color schemes
- Preference stored in
localStoragewith keydarkMode - Button icon changes between 🌓 (moon) and ☀️ (sun)
- Uses CSS
.hiddenclass for hiding non-selected languages data-languageattribute matches language selection- Default: French selected on page load
- Creates temporary
<a>element withdownloadattribute - Uses predefined filename mappings for each version
- Element is removed after triggering click event
Personal portfolio project. Feel free to use as inspiration for your own CV website.