Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 6 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name: Deploy to GitHub Pages
on:
push:
branches: [main]
pull_request:
workflow_dispatch:

permissions:
Expand Down Expand Up @@ -33,6 +34,9 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Lint
run: pnpm lint

- name: Build
run: pnpm build

Expand All @@ -45,6 +49,8 @@ jobs:
path: dist

deploy:
# PRs only build; pushes to main and manual dispatches (any branch) deploy
if: github.event_name != 'pull_request'
needs: build
runs-on: ubuntu-latest
environment:
Expand Down
29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ Personal portfolio and resume site for Nick Blain, a frontend developer with 12+

## About the Project

This site serves as a living resume: work history, projects, and recommendations all in one place. It's intentionally simple: no backend, no SSR, just a client-side Vue app.
This site serves as a living resume: work history, projects, recommendations, and the latest post from [The Commit with Nick](https://the-commit.netlify.app/), all in one parallax-scrolling page. It's intentionally simple: no backend, no SSR, just a client-side Vue app.

**A note on Tailwind CSS:** Tailwind was used here purely out of curiosity to see how it felt in a real project. The verdict: it's not something I'd recommend or reach for again. The utility-class approach trades readability and maintainability for speed of prototyping in a way that doesn't hold up well at scale or in team environments.
**A note on Tailwind CSS:** an earlier version of this site was built with Tailwind as an experiment. The verdict: it's not something I'd recommend or reach for again. The utility-class approach trades readability and maintainability for speed of prototyping in a way that doesn't hold up well at scale or in team environments. This version replaces it with plain SCSS on a CSS custom-property design-token system.

All site content (jobs, skills, projects, recommendations, latest blog post) lives in `src/data/resume.js`. To update the resume, edit that file and replace `public/NicholasBlainResume.pdf`.

Scroll animation is dependency-free: an IntersectionObserver `v-reveal` directive for reveals, a requestAnimationFrame transform parallax for the hero, and CSS scroll-driven animations (behind `@supports`) for decorative motion. Everything respects `prefers-reduced-motion`.

## Stack

- **Vue 3** with the Composition API
- **Vue 3** with the Composition API and `<script setup>`
- **Vue Router** for client-side routing
- **Tailwind CSS**, used as an experiment (see note above)
- **SCSS** for anything Tailwind made awkward
- **SCSS** with design tokens, `light-dark()` theming, and breakpoint mixins
- **Vite** build tooling
- **pnpm** package manager
- **GitHub Actions** CI/CD to GitHub Pages
Expand Down Expand Up @@ -53,13 +56,21 @@ Every push to `main` triggers the [deploy workflow](.github/workflows/deploy.yml
## Directory Structure

```
index.html Vite entry (theme pre-paint script lives here)
src/
assets/ Static assets (images, fonts, icons)
components/ Feature components (navbar, experience, projects, etc.)
assets/
images/ Photos, screenshots, logos
scss/ abstracts (mixins), base (tokens, reset), layout, components
components/
layout/ AppNavbar, AppFooter, ThemeToggle
sections/ Hero, BlogSpotlight, About, Projects, Experience, Recommendations
ui/ AppIcon (inline SVG registry), cards, chips, headings
composables/ useParallax, useScrollSpy, useReducedMotion
data/ resume.js (single source of truth for content)
directives/ v-reveal scroll animation
pages/ Top-level page views
router/ Vue Router configuration
App.vue Root component
public/ Public static files (index.html template, favicon)
public/ Static files (favicon, resume PDF)
```

## License
Expand Down
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import pluginVue from 'eslint-plugin-vue'

export default [
js.configs.recommended,
...pluginVue.configs['flat/base'],
...pluginVue.configs['flat/essential'],
{
languageOptions: {
Expand Down
6 changes: 3 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<!DOCTYPE html>
<html lang="en" class="light scroll-smooth" dir="ltr">
<html lang="en" class="light" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta name="description" content="Nick Blain, Senior Front-End Vue Developer. Portfolio, resume, and latest writing.">
<link rel="icon" href="/favicon.ico">
<script>
// Apply saved or system theme before first paint to prevent flash
Expand All @@ -15,9 +16,8 @@
})();
</script>
<title>Nick.</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tiny-slider/2.9.4/tiny-slider.css">
</head>
<body class="font-poppins text-base text-black dark:text-white dark:bg-slate-900">
<body>
<noscript>
<strong>We're sorry but this site doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
Expand Down
19 changes: 7 additions & 12 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
{
"compilerOptions": {
"target": "es5",
"target": "esnext",
"module": "esnext",
"moduleResolution": "bundler",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
"@/*": ["src/*"]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
"lib": ["esnext", "dom", "dom.iterable"]
},
"include": ["src/**/*", "vite.config.js", "eslint.config.js"],
"exclude": ["node_modules", "dist"]
}
22 changes: 6 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nick-resume",
"version": "1.0.0",
"version": "2.0.0",
"description": "Nick - Online Resume",
"private": true,
"type": "module",
Expand All @@ -13,27 +13,17 @@
"lint": "eslint ."
},
"dependencies": {
"feather-icons": "^4.29.1",
"tiny-slider": "^2.9.4",
"vue": "^3.5.41",
"vue-countup-v3": "^1.4.1",
"vue-router": "^4.6.0"
},
"devDependencies": {
"@eslint/js": "^9.39.0",
"@eslint/js": "^10.0.1",
"@vitejs/plugin-vue": "^6.0.8",
"autoprefixer": "^10.4.17",
"eslint": "^9.39.0",
"eslint": "^10.8.1",
"eslint-plugin-vue": "^10.10.0",
"postcss": "^8.4.35",
"sass": "^1.72.0",
"tailwindcss": "^3.4.1",
"vite": "^8.2.2"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
"vite": "^8.2.2",
"vue-eslint-parser": "^10.4.1"
}
}
Loading