Personal portfolio built with Astro, Tailwind CSS, and MDX.
# Install dependencies
npm install
# Start dev server (http://localhost:4321)
npm run dev
# Build for production
npm run build
# Preview production build
npm run previewsrc/
├── components/
│ ├── HomePage.astro # The whole homepage: summary panel, sections, own nav and footer
│ ├── SiteNav.astro # Nav for the other pages (404, 500)
│ └── SiteFooter.astro # Footer for the other pages (404, 500)
├── lib/
│ ├── site-content.ts # Homepage copy: hero, stats, services, section text, contact links
│ ├── codyssey.ts # Codyssey writing, fetched at build time
│ └── career.ts # Date formatting, years of experience, skill group order
├── content/
│ ├── experience.json # Work history (Experience section)
│ ├── projects.json # Case studies (Selected Work section)
│ ├── skills.json # Skills section
│ └── talks.json # Talks in the Talks & Writing section
├── layouts/
│ └── BaseLayout.astro # Site shell (meta; nav and footer except on the homepage)
├── pages/
│ ├── index.astro # Homepage
│ ├── cv.astro # Print-first CV, rendered to the downloadable PDF
│ ├── 404.astro
│ └── 500.astro
└── styles/
└── global.css # Tailwind import, theme and custom utilities
Articles live on Codyssey.dev and are pulled into the Talks & Writing section at build time. There is no local blog.
/cv is a print-first page built from the same JSON content as the homepage (experience, skills, talks). pnpm build runs astro build and then scripts/generate-cv-pdf.mjs, which opens the built page in headless Chromium and writes dist/davor-minchorov-cv.pdf. The "Download CV" links in the hero and contact sections point to that file, and every deploy (including the daily rebuild) regenerates it, so the PDF is always in step with the site.
The script needs the Playwright Chromium build:
pnpm exec playwright install chromium
# or point it at an existing Chrome/Chromium binary
CV_PDF_CHROMIUM_PATH=/path/to/chrome pnpm buildThe PDF only exists after a build, so /davor-minchorov-cv.pdf returns 404 under pnpm dev. Use pnpm build && pnpm preview to check it.
public/og-image.jpg is generated from src/assets/davor-minchorov.webp and the site fonts. Regenerate it whenever the positioning line changes:
node scripts/generate-og-image.mjsThe site uses a professional light-mode palette defined in the @theme block of src/styles/global.css:
- Background: Warm off-white (#FAFAF9)
- Accent: Deep forest green (#1A5C3A)
- Typography: Source Serif 4 (display), Instrument Sans (body), IBM Plex Mono (code/labels)
The site deploys with Cloudflare Workers Builds, which is connected to this repository. Every push to main runs pnpm build and then npx wrangler deploy. Both commands are set in the Worker's build settings in the Cloudflare dashboard (Worker davorminchorov-com, then Settings → Build), not in this repository.
The Workers Builds image has no root access, so Playwright can't install Chromium's system libraries there. When WORKERS_CI=1 is set (Workers Builds sets it), scripts/generate-cv-pdf.mjs uses @sparticuz/chromium instead, a Chromium build that ships its own libraries.
The site also rebuilds once a day, so newly published Codyssey content shows up without a push. wrangler.toml sets a cron trigger (06:00 UTC), and the scheduled handler in worker/index.js calls a Workers Builds deploy hook. The hook URL is stored as the DEPLOY_HOOK_URL Worker secret. To start a rebuild by hand, re-run the latest build from the Worker's build history in the Cloudflare dashboard.
.github/workflows/build-check.yml runs the same build (including the CV PDF step) on pull requests, so a broken build shows up before it reaches main. It doesn't deploy.
Routes and the custom domain are set in wrangler.toml.
- Colors/fonts: Edit the
@themeblock insrc/styles/global.css - Homepage copy: Edit
src/lib/site-content.ts - Homepage layout: Edit
src/components/HomePage.astro - Meta/SEO: Edit defaults in
src/layouts/BaseLayout.astro - Case studies, experience, skills, talks: Edit the JSON files in
src/content/ - CV: Same JSON files, plus the summary and contact lines in
src/pages/cv.astro





