Compare commits

..

No commits in common. "main" and "v1.0.0" have entirely different histories.
main ... v1.0.0

8 changed files with 62 additions and 104 deletions

View file

@ -14,7 +14,7 @@
{ "type": "ci", "section": "CI/CD" }, { "type": "ci", "section": "CI/CD" },
{ "type": "docs", "section": "Documentation" }, { "type": "docs", "section": "Documentation" },
{ "type": "refactor", "section": "Refactor" }, { "type": "refactor", "section": "Refactor" },
{ "type": "chore", "section": "Chores" } { "type": "chore", "hidden": true }
] ]
}, },
"plugins": [ "plugins": [
@ -31,11 +31,11 @@
{ "type": "deps", "release": "minor" }, { "type": "deps", "release": "minor" },
{ "type": "new", "release": "minor" }, { "type": "new", "release": "minor" },
{ "type": "fix", "release": "patch" }, { "type": "fix", "release": "patch" },
{ "type": "build", "release": "patch" }, { "type": "build", "release": false },
{ "type": "ci", "release": "patch" }, { "type": "ci", "release": false },
{ "type": "chore", "release": "patch" }, { "type": "chore", "release": false },
{ "type": "docs", "release": "patch" }, { "type": "docs", "release": false },
{ "type": "refactor", "release": "patch" } { "type": "refactor", "release": false }
] ]
} }
], ],

View file

@ -1,31 +1,3 @@
## [1.1.0](https://ssh.git.badblocks.dev/badbl0cks/portfolio/compare/v1.0.1...v1.1.0) (2025-08-15)
### New Features
* allow project card to show on-the-way button for projects not yet uploaded ([d2e0fbd](https://ssh.git.badblocks.dev/badbl0cks/portfolio/commit/d2e0fbdd737b42182af9b54adc77310749ccf794))
### Bug Fixes
* add <a href="[#projects](https://ssh.git.badblocks.dev/badbl0cks/portfolio/issues/projects)"> around the View My Work button. update wording on ([6fd9f47](https://ssh.git.badblocks.dev/badbl0cks/portfolio/commit/6fd9f4732566bf9366cd05a7abf4310dea3fbe16))
### Refactor
* change button text to be more clear ([ed6188b](https://ssh.git.badblocks.dev/badbl0cks/portfolio/commit/ed6188bc759cbf0ab4c1f2ad5a548d8ea31dd7a5))
### Chores
* merge staging changes for next release ([48f5e7b](https://ssh.git.badblocks.dev/badbl0cks/portfolio/commit/48f5e7b46c1e1a318d1eca26ab1d9365d1acdbcc))
## [1.0.1](https://ssh.git.badblocks.dev/badbl0cks/portfolio/compare/v1.0.0...v1.0.1) (2025-08-15)
### CI/CD
* don't hide or ignore any commit types, at least bump the patch version if ([185dc5f](https://ssh.git.badblocks.dev/badbl0cks/portfolio/commit/185dc5f66267d5ab8446ab51e03f051a4210e0b3))
### Chores
* merge staging changes for next release ([cea509a](https://ssh.git.badblocks.dev/badbl0cks/portfolio/commit/cea509a0cee89047e9b261c87906cd05349ca1fd))
## 1.0.0 (2025-08-15) ## 1.0.0 (2025-08-15)
### New Features ### New Features

View file

@ -5,12 +5,12 @@ A sweet little portfolio site with some absolutely ridiculous SMS shenanigans bu
## ✨ The Good Stuff ## ✨ The Good Stuff
- 🌙 **Night mode everything** - DaisyUI components that won't burn your eyeballs - 🌙 **Night mode everything** - DaisyUI components that won't burn your eyeballs
- 📱 **SMS contact form** - Because I get wayyyyy too many emails already - 📱 **SMS contact form** - Because I get wayyy too many emails already
- 🎭 **Snazzy animations** - ScrollReveal, Typed.js, and more doing their thang - 🎭 **Snazzy animations** - ScrollReveal + Typed.js doing their thang
- 🐳 **Zero-downtime deploys** - Blue-green magic with Docker & HAProxy - 🐳 **Zero-downtime deploys** - Blue-green magic with Docker & HAProxy
- 🔧 **Overengineered infrastructure** - If you didn't spend a week working on a fun but useless feature that will never be used, did you really do any development? - 🔧 **Overengineered infrastructure** - We like to do things the hard way over here
## 🏃‍♂️ Wanna Try It Out? ## 🏃‍♂️ Getting Started
```bash ```bash
# Grab the dependencies # Grab the dependencies
@ -38,9 +38,9 @@ bun run generate
## 📞 Contact Form Wizardry ## 📞 Contact Form Wizardry
Two-step verification anti-abuse dance: drop your message → prove you're human with SMS → message gets yeeted to my phone via some very questionable infrastructure choices! Two-step verification dance: drop your message → prove you're human with SMS → message gets yeeted to my phone via some questionable infrastructure choices.
Rate-limited because spam just sucks! Rate-limited because spam just sucksssss! 🛡️
## 🏗️ Infrastructure Tomfoolery ## 🏗️ Infrastructure Tomfoolery
@ -57,8 +57,8 @@ Here's where things get ~completely~ unhinged:
I'm running the `android-sms-gateway` app on a completely deranged setup: I'm running the `android-sms-gateway` app on a completely deranged setup:
- **Hardware:** Pixel 1 with the battery surgically removed (no spicy pillows please) - **Hardware:** Pixel 1 with the battery surgically removed (no spicy pillows please)
- **Power:** Permanently plugged into the wall like some kind of cursed landline - **Power:** Permanently plugged into the wall like some kind of cursed landline
- **Network:** Hardwired ethernet via attached USB hub (WhyFight with WiFi?) - **Network:** Hardwired ethernet via USB-C adapter ("WhyFight" with WiFi?)
- **Purpose:** Sits there patiently 24/7 just waiting to send OTPs and forward your messages to my actual phone - **Purpose:** Sits there 24/7 just waiting to send OTPs and forward your messages to my actual phone
The whole contraption lives on my home network and the VPS reaches it through a WireGuard tunnel because apparently I enjoy making simple things complicated just to save $2 a month! The whole contraption lives on my home network and the VPS reaches it through a WireGuard tunnel because apparently I enjoy making simple things complicated just to save $2 a month!
@ -67,83 +67,84 @@ The whole contraption lives on my home network and the VPS reaches it through a
This repo follows a three-branch strategy with some absolutely bonkers automated promotions because manually managing branches is for chumps: This repo follows a three-branch strategy with some absolutely bonkers automated promotions because manually managing branches is for chumps:
- **`dev`** - Where the magic happens! All new features and fixes go here - **`dev`** - Where the magic happens! All new features and fixes go here
- **`staging`** - Integration testing playground, auto-promoted from dev daily at 04:00 PST via scheduler - **`staging`** - Integration testing playground, auto-promoted from dev daily at 13:00 UTC via scheduler
- **`main`** - Production branch, gets promoted from staging weekly on Sundays at 05:00 PST via scheduler - **`main`** - Production branch, gets promoted from staging weekly on Sundays at 14:00 UTC via scheduler
### The Repository Setup ### The Repository Setup
It's a bit of a funky setup here: We're running a bit of a funky setup here:
- **Primary repo:** My Forgejo server (I obviously like self-hosting things) - **Primary repo:** Git origin (configurable - can be self-hosted, GitHub, etc.)
- **GitHub Mirror:** Forgejo repo configured to push-only mirror to Github for CI/CD and visibility - **GitHub Mirror:** Optional push-only mirror for CI/CD and visibility
- **CI/CD:** GitHub Actions (triggered by pushes or scheduled workflows) - **CI/CD:** GitHub Actions (triggered by pushes or scheduled workflows)
So the workflow is: do some coding, commit and push to my Forgejo instance → mirror to GitHub → GitHub Actions does the heavy lifting so my little VPS doesn't have to suffer so much. So the workflow is: push to Git origin → (optional mirror to GitHub) → GitHub Actions does the heavy lifting.
### Branch Promotion Dance 💃 ### Branch Promotion Dance 💃
**Daily (dev → staging):** **Daily (dev → staging):**
- Wannabe robot overlord wakes up at 04:00 PST every day - Robot overlord wakes up at 13:00 UTC every day
- Checks if dev has new commits (because we're not doing all this work for nothing!) - Checks if dev has new commits (because we're not animals)
- Actually validates the build passed via GitHub API (fancy!) - Actually validates the build passed via GitHub API (fancy!)
- Fast-forward merge to staging (keeps git history from becoming spaghetti) - Fast-forward merge to staging (keeps git history from becoming spaghetti)
- Supports `[skip ci]` in commit messages for when you inevitably break something
- Manual "YOLO deploy anyway" button available - Manual "YOLO deploy anyway" button available
**Weekly (staging → main):** **Weekly (staging → main):**
- Sunday funday at 05:00 PST for production releases - Sunday funday at 14:00 UTC for production releases
- Runs semantic-release for proper versioning (we're not completely chaotic) - Runs semantic-release for proper versioning (we're not completely chaotic)
- Seduce the GitHub API with a token for build status - Some gnarly branch gymnastics to keep everything synchronized
- SSH-signed commits because I <3 cryptography - SSH-signed commits because we pretend to care about security
- Manual panic button also available - Manual panic button also available
### 🤖 The 5-Workflow CI/CD Circus ### 🤖 The 5-Workflow CI/CD Circus
Because apparently one workflow is never enough, I've got a whole collection of automations: Because apparently one workflow wasn't enough, we've got a whole circus of automation:
1. **`build.yml`** - The overachiever that builds everything and gets good grades 1. **`build.yml`** - The overachiever that builds everything
- Gets triggered by basically anything that moves - Gets triggered by basically anything that moves
- Smart enough to skip builds when we already did the work (lazy!) - Smart enough to skip builds when we already did the work (lazy efficiency!)
- Hoards artifacts for 30 days like a digital packrat - Hoards artifacts for 2 days like a digital packrat
- Has more caching layers than an onion-flavored wedding cake - Has more caching layers than a wedding cake
2. **`deploy.yml`** - The deployment minion (does what it's told) 2. **`deploy.yml`** - The deployment minion (does what it's told)
- Gets bossed around by the other workflows - Gets bossed around by the other workflows
- Juggles blue-green deployments without dropping anything - Juggles blue-green deployments without dropping anything
- Speaks fluent SSH and WireGuard - Speaks fluent SSH and WireGuard
- Downloads artifacts faster than you can say "docker load" - Downloads artifacts faster than you can say "containerization"
3. **`stage.yml`** - The daily grind automation 3. **`stage.yml`** - The daily grind automation
- Wakes up every day to promote dev → staging - Wakes up every day to promote dev → staging
- Actually checks if builds passed (responsible adult behavior) - Actually checks if builds passed (responsible adult behavior)
- Signs commits with SSH keys because I'm fancy like that - Signs commits with SSH keys because we're fancy like that
- Has a "force" option for when things go sideways - Has a "force" option for when things go sideways
4. **`release.yml`** - The weekly release partayyyy 4. **`release.yml`** - The weekly release party host
- Shows up every Sunday with semantic versioning - Shows up every Sunday with semantic versioning
- Does some serious git branch yoga to keep everything aligned - Does some serious git branch yoga to keep everything aligned
- Maintains that linear history we all pretend to care about but never look at - Maintains that linear history we all pretend to care about
5. **`scheduler-*.yml`** - The workflow orchestrators 5. **`scheduler-*.yml`** - The workflow orchestrators
- Exists because GitHub has weird scheduling quirks - Exists because GitHub has weird scheduling quirks
- Makes sure the workflow runs from the right branch - Makes sure the right code runs from the right branch
- Basically the puppet masters of this whole operation - Basically the puppet masters of this whole operation
## 🚢 Deployment Shenanigans ## 🚢 Deployment Shenanigans
Pushes to `staging` or `main` branches trigger some absolutely wild blue-green deployment wizardry with more caching than your browser! Pushes to `staging` or `main` branches trigger some absolutely wild blue-green deployment wizardry with more caching than your browser history!
### Blue-Green Magic ✨ ### Blue-Green Magic ✨
1. **Build Phase:** Smart enough to skip rebuilding stuff we already built (because efficiency is sexy) 1. **Build Phase:** Smart enough to skip rebuilding stuff we already built (because efficiency is sexy)
3. **Configure Phase:** Update HAProxy's config, then call it's cell phone and SIG_HUP! 2. **Deploy Phase:** Download cached goodies and poke the new containers to make sure they're alive
3. **Deploy Phase:** Download cached goodies and poke the new containers to make sure they're alive 3. **Switch Phase:** HAProxy does the old switcheroo faster than a shell game
4. **Cleanup Phase:** Yeet the old containers into the great /dev/null 4. **Cleanup Phase:** Yeet the old containers into the digital void
5. **Artifact Hoarding:** Keeps old build artifacts much longer than you'd ever need (30 days) 5. **Artifact Hoarding:** Keeps build artifacts for 30 days like a digital packrat with commitment issues
6. **Moon Phases:** 🌑 🌒 🌓 🌔 🌝 🌖 🌗 🌘 🌚 6. **Moon Phases:** 🌑 🌒 🌓 🌔 🌝 🌖 🌗 🌘 🌚 (for spiritual alignment)
### GitHub Secrets/.env Setup ### GitHub Secrets Setup
Deployments generate the needed .env from GitHub secrets, so make sure to slap some secrets up first or copy the .env.example file and edit! Deployments generate the needed .env from GitHub secrets, so make sure to slap some secrets up first!
### WireGuard Setup ### WireGuard Setup
The stack is rocking the popular [gluetun](https://github.com/qdm12/gluetun) container, so just set up your WIREGUARD_ environment variables with your Github secrets! The stack is rocking gluetun, so just set up your WIREGUARD_ environment variables in Github secrets:
## 🔒 Security Fortress ## 🔒 Security Fortress
@ -152,7 +153,7 @@ The stack is rocking the popular [gluetun](https://github.com/qdm12/gluetun) con
- 🔢 TOTP phone verification + rate limiting - 🔢 TOTP phone verification + rate limiting
- 🔤 ASCII-only validation (No spammy weird characters please!) - 🔤 ASCII-only validation (No spammy weird characters please!)
## 🆘 Note to Self: When Things Go Wrong ## 🆘 When Things Go Wrong
```bash ```bash
# Check if containers are actually alive # Check if containers are actually alive
@ -186,4 +187,4 @@ This project is licensed under **AGPL 3.0 only** - see the [LICENSE](LICENSE) fi
--- ---
*Built with ❤️ and lots of ☕! (Wow, if you've read this far, and you're hiring, just hire me!)* *Built with ❤️ and lots of ☕! (Sheesh, if you've read this far, just hire me, please!)*

View file

@ -145,7 +145,7 @@
:disabled="!isVerified || isSendingMessage || isMessageSent" :disabled="!isVerified || isSendingMessage || isMessageSent"
> >
<span v-if="isSendingMessage" class="loading loading-spinner" /> <span v-if="isSendingMessage" class="loading loading-spinner" />
Send Me a Text! Text Me! (Rob )
</button> </button>
</div> </div>
</form> </form>

View file

@ -18,9 +18,6 @@
> >
Source Code Source Code
</button> </button>
<button v-else class="btn btn-secondary btn-disabled">
Source Code (on the way!)
</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -8,9 +8,7 @@
Hi, I'm <span class="text-primary">Rob</span>! Hi, I'm <span class="text-primary">Rob</span>!
</h1> </h1>
<p class="py-6 text-2xl">I'm <span id="typed-text" /></p> <p class="py-6 text-2xl">I'm <span id="typed-text" /></p>
<a href="#projects" <button class="btn btn-primary">View My Work</button>
><button class="btn btn-primary">View My Work</button></a
>
</div> </div>
</div> </div>
</section> </section>
@ -32,7 +30,7 @@
</div> </div>
<div class="md:w-2/3"> <div class="md:w-2/3">
<p class="text-lg mb-4"> <p class="text-lg mb-4">
Hi! I'm a passionate and creative web developer with a knack for Hiya! I'm a passionate and creative web developer with a knack for
building beautiful and functional websites. I love learning new building beautiful and functional websites. I love learning new
technologies and I'm always looking for exciting projects to work technologies and I'm always looking for exciting projects to work
on. on.
@ -54,44 +52,34 @@
</section> </section>
<section id="projects" class="py-20 bg-base-200"> <section id="projects" class="py-20 bg-base-200">
<div class="container mx-auto px-4"> <div class="container mx-auto px-4">
<h2 class="text-4xl font-bold text-center mb-12">Works in Progress</h2> <h2 class="text-4xl font-bold text-center mb-12">Current Projects</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<ProjectCard <ProjectCard
title="PKMNTradeClub" title="PKMNTradeClub"
description="A project started to learn and practice Django while facilitating trading between players of Pokémon TCG Pocket, which frustratingly lacks trade matching features." description="A web app to facilitate trading between players of Pokémon TCG Pocket, which frustratingly lacks trade matching features. Currently in development!"
source-code-link="https://git.badblocks.dev/badbl0cks/pkmntrade.club"
/>
<ProjectCard
title="This Portfolio Site!"
description="A portfolio site built to explore and learn Nuxt.js while showcasing my projects and skills."
source-code-link="https://git.badblocks.dev/badbl0cks/portfolio"
/> />
<ProjectCard <ProjectCard
title="Home Lab & Self-Hosted Solutions" title="Home Lab & Self-Hosted Solutions"
description="A collection of hardware, software projects, and experiments to learn and explore new technologies and concepts, as well as augment and enhance my personal tech space." description="A collection of hardware, projects, and experiments to learn and explore new technologies and concepts, as well as augment and enhance my personal tech space."
/> />
</div> </div>
</div> </div>
</section> </section>
<section id="projects" class="py-20 bg-base-200"> <section id="projects" class="py-20 bg-base-200">
<div class="container mx-auto px-4"> <div class="container mx-auto px-4">
<h2 class="text-4xl font-bold text-center mb-12"> <h2 class="text-4xl font-bold text-center mb-12">Past Projects</h2>
Neat Things I've Done
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<ProjectCard <ProjectCard
title="PokeEmerald Mods" title="PokeEmerald Mods"
description="Various mods for one of my favorite games, Pokémon Emerald, to streamline my replays with custom QoL features." description="Various mods for one of my favorite games, Pokémon Emerald, to streamline my replays with custom QoL features."
source-code-link="https://git.badblocks.dev/badbl0cks/pokeemerald" />
<ProjectCard
title="EditMii"
description="A Python script that allows users to view their WiiU Mii character's data and optionally change the Mii's name. Created in order to easily set flashy, custom names for online play."
/> />
<ProjectCard <ProjectCard
title="BOTW Completer" title="BOTW Completer"
description="A Nintendo Switch application that helps users find missing items and locations in Breath of the Wild by modifying the save file to add stamps to the in-game map." description="A Nintendo Switch application that helps users find missing items and locations in Breath of the Wild by modifying the save file to add stamps to the in-game map."
source-code-link="https://git.badblocks.dev/badbl0cks/botw-completer"
/>
<ProjectCard
title="EditMii"
description="An app that allows users to view their WiiU Mii character's data and optionally change the Mii's name. Created in order to easily set flashy, custom names for online play."
/> />
</div> </div>
</div> </div>
@ -114,8 +102,8 @@ onMounted(() => {
const { $sr } = useNuxtApp(); const { $sr } = useNuxtApp();
const typedOptions = { const typedOptions = {
strings: [ strings: [
"an aspiring Software Engineer.",
"a self-taught Web Developer with experience.", "a self-taught Web Developer with experience.",
"a Bachelor's degree holder in Software Engineering.",
"a Full-Stack Magician.", "a Full-Stack Magician.",
"a UI/UX Problem Solver.", "a UI/UX Problem Solver.",
"a Web Accessibility Advocate.", "a Web Accessibility Advocate.",

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "portfolio", "name": "portfolio",
"version": "1.1.0", "version": "1.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "portfolio", "name": "portfolio",
"version": "1.1.0", "version": "1.0.0",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@nuxt/fonts": "0.11.4", "@nuxt/fonts": "0.11.4",

View file

@ -1,6 +1,6 @@
{ {
"name": "portfolio", "name": "portfolio",
"version": "1.1.0", "version": "1.0.0",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {