From 5ae7040496b40cbaa8f55a0c0faac736b7ecee35 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Sun, 11 Jan 2026 14:24:39 -0700 Subject: [PATCH] Add flair badge gamification system with custom SVG badges - Create 12 Office Space themed SVG badges (extraction, basement, printer, coffee, tps, bobs, memo, oface, stapler, conclusions, spreadsheet, flair-badge) - Implement FlairBadge.astro component with localStorage persistence - Add 15-second timer per page to earn flair - Create floating counter, modal flair board, toast notifications - Override Starlight Footer to inject flair system globally - Add name capture dialog on first flair earned Features: - Badges glow golden when earned, grayscale when locked - Progress persists across browser sessions - Stan quote: "We need to talk about your document processing..." --- astro.config.mjs | 3 + public/flair/basement.svg | 12 + public/flair/bobs.svg | 17 + public/flair/coffee.svg | 14 + public/flair/conclusions.svg | 17 + public/flair/extraction.svg | 11 + public/flair/flair-badge.svg | 16 + public/flair/memo.svg | 18 + public/flair/oface.svg | 20 + public/flair/printer.svg | 15 + public/flair/spreadsheet.svg | 23 + public/flair/stapler.svg | 17 + public/flair/tps.svg | 15 + src/assets/flair/basement.svg | 12 + src/assets/flair/bobs.svg | 17 + src/assets/flair/coffee.svg | 14 + src/assets/flair/conclusions.svg | 17 + src/assets/flair/extraction.svg | 11 + src/assets/flair/flair-badge.svg | 16 + src/assets/flair/memo.svg | 18 + src/assets/flair/oface.svg | 20 + src/assets/flair/printer.svg | 15 + src/assets/flair/spreadsheet.svg | 23 + src/assets/flair/stapler.svg | 17 + src/assets/flair/tps.svg | 15 + src/components/FlairBadge.astro | 979 +++++++++++++++++++++++++++++++ src/components/Footer.astro | 15 + src/data/flair-config.json | 34 +- 28 files changed, 1410 insertions(+), 11 deletions(-) create mode 100644 public/flair/basement.svg create mode 100644 public/flair/bobs.svg create mode 100644 public/flair/coffee.svg create mode 100644 public/flair/conclusions.svg create mode 100644 public/flair/extraction.svg create mode 100644 public/flair/flair-badge.svg create mode 100644 public/flair/memo.svg create mode 100644 public/flair/oface.svg create mode 100644 public/flair/printer.svg create mode 100644 public/flair/spreadsheet.svg create mode 100644 public/flair/stapler.svg create mode 100644 public/flair/tps.svg create mode 100644 src/assets/flair/basement.svg create mode 100644 src/assets/flair/bobs.svg create mode 100644 src/assets/flair/coffee.svg create mode 100644 src/assets/flair/conclusions.svg create mode 100644 src/assets/flair/extraction.svg create mode 100644 src/assets/flair/flair-badge.svg create mode 100644 src/assets/flair/memo.svg create mode 100644 src/assets/flair/oface.svg create mode 100644 src/assets/flair/printer.svg create mode 100644 src/assets/flair/spreadsheet.svg create mode 100644 src/assets/flair/stapler.svg create mode 100644 src/assets/flair/tps.svg create mode 100644 src/components/FlairBadge.astro create mode 100644 src/components/Footer.astro diff --git a/astro.config.mjs b/astro.config.mjs index 82be796..6a47186 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -11,6 +11,9 @@ export default defineConfig({ integrations: [ starlight({ title: 'mcwaddams', + components: { + Footer: './src/components/Footer.astro', + }, tagline: 'I was told there would be document extraction.', logo: { src: './src/assets/stapler.svg', diff --git a/public/flair/basement.svg b/public/flair/basement.svg new file mode 100644 index 0000000..60f32ab --- /dev/null +++ b/public/flair/basement.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/flair/bobs.svg b/public/flair/bobs.svg new file mode 100644 index 0000000..2cb6940 --- /dev/null +++ b/public/flair/bobs.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/public/flair/coffee.svg b/public/flair/coffee.svg new file mode 100644 index 0000000..187cfc3 --- /dev/null +++ b/public/flair/coffee.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/public/flair/conclusions.svg b/public/flair/conclusions.svg new file mode 100644 index 0000000..cc4d5bc --- /dev/null +++ b/public/flair/conclusions.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/public/flair/extraction.svg b/public/flair/extraction.svg new file mode 100644 index 0000000..d4aed1e --- /dev/null +++ b/public/flair/extraction.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/flair/flair-badge.svg b/public/flair/flair-badge.svg new file mode 100644 index 0000000..3e199e0 --- /dev/null +++ b/public/flair/flair-badge.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + 37 + + + diff --git a/public/flair/memo.svg b/public/flair/memo.svg new file mode 100644 index 0000000..6365b55 --- /dev/null +++ b/public/flair/memo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + MEMO + + + + diff --git a/public/flair/oface.svg b/public/flair/oface.svg new file mode 100644 index 0000000..594a411 --- /dev/null +++ b/public/flair/oface.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/flair/printer.svg b/public/flair/printer.svg new file mode 100644 index 0000000..ccc9103 --- /dev/null +++ b/public/flair/printer.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + PC LOAD + diff --git a/public/flair/spreadsheet.svg b/public/flair/spreadsheet.svg new file mode 100644 index 0000000..27839ea --- /dev/null +++ b/public/flair/spreadsheet.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + A + B + C + + + + diff --git a/public/flair/stapler.svg b/public/flair/stapler.svg new file mode 100644 index 0000000..34be001 --- /dev/null +++ b/public/flair/stapler.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/public/flair/tps.svg b/public/flair/tps.svg new file mode 100644 index 0000000..4234e71 --- /dev/null +++ b/public/flair/tps.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + TPS + + + + diff --git a/src/assets/flair/basement.svg b/src/assets/flair/basement.svg new file mode 100644 index 0000000..60f32ab --- /dev/null +++ b/src/assets/flair/basement.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/flair/bobs.svg b/src/assets/flair/bobs.svg new file mode 100644 index 0000000..2cb6940 --- /dev/null +++ b/src/assets/flair/bobs.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/flair/coffee.svg b/src/assets/flair/coffee.svg new file mode 100644 index 0000000..187cfc3 --- /dev/null +++ b/src/assets/flair/coffee.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/flair/conclusions.svg b/src/assets/flair/conclusions.svg new file mode 100644 index 0000000..cc4d5bc --- /dev/null +++ b/src/assets/flair/conclusions.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/flair/extraction.svg b/src/assets/flair/extraction.svg new file mode 100644 index 0000000..d4aed1e --- /dev/null +++ b/src/assets/flair/extraction.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/flair/flair-badge.svg b/src/assets/flair/flair-badge.svg new file mode 100644 index 0000000..3e199e0 --- /dev/null +++ b/src/assets/flair/flair-badge.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + 37 + + + diff --git a/src/assets/flair/memo.svg b/src/assets/flair/memo.svg new file mode 100644 index 0000000..6365b55 --- /dev/null +++ b/src/assets/flair/memo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + MEMO + + + + diff --git a/src/assets/flair/oface.svg b/src/assets/flair/oface.svg new file mode 100644 index 0000000..594a411 --- /dev/null +++ b/src/assets/flair/oface.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/flair/printer.svg b/src/assets/flair/printer.svg new file mode 100644 index 0000000..ccc9103 --- /dev/null +++ b/src/assets/flair/printer.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + PC LOAD + diff --git a/src/assets/flair/spreadsheet.svg b/src/assets/flair/spreadsheet.svg new file mode 100644 index 0000000..27839ea --- /dev/null +++ b/src/assets/flair/spreadsheet.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + A + B + C + + + + diff --git a/src/assets/flair/stapler.svg b/src/assets/flair/stapler.svg new file mode 100644 index 0000000..34be001 --- /dev/null +++ b/src/assets/flair/stapler.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/flair/tps.svg b/src/assets/flair/tps.svg new file mode 100644 index 0000000..4234e71 --- /dev/null +++ b/src/assets/flair/tps.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + TPS + + + + diff --git a/src/components/FlairBadge.astro b/src/components/FlairBadge.astro new file mode 100644 index 0000000..2e47128 --- /dev/null +++ b/src/components/FlairBadge.astro @@ -0,0 +1,979 @@ +--- +/** + * FlairBadge - Collect pieces of flair by spending time on key pages + * Adapted for Starlight documentation site + * + * "We need to talk about your flair..." - Stan, Manager + * + * Features: + * - Floating counter in bottom-right corner + * - Opens modal "flair board" showing collection + * - 15-second timer per page to earn flair + * - localStorage persistence across sessions + * - Astro view transition support + */ + +import flairConfig from '../data/flair-config.json'; + +interface Props { + currentPath: string; +} + +const { currentPath } = Astro.props; + +// Normalize path for matching (handle trailing slashes) +const normalizedPath = currentPath === '/' ? '/' : currentPath.replace(/\/$/, '') + '/'; +const altPath = currentPath === '/' ? '/' : currentPath.replace(/\/$/, ''); + +// Check if current page has flair (try both with and without trailing slash) +const currentFlair = flairConfig.flairs.find(f => + f.path === normalizedPath || f.path === altPath || f.path === currentPath +); +--- + + + + + +
+
+ + 🎉 +
+
+

Flair Earned!

+

Badge Name

+
+
+ + + +
+
+ 🎖️ +

You earned your first flair!

+

What should we call you?

+
+ +
+ +
+ + +
+
+
+
+ + + + + + + + + diff --git a/src/components/Footer.astro b/src/components/Footer.astro new file mode 100644 index 0000000..27f1cff --- /dev/null +++ b/src/components/Footer.astro @@ -0,0 +1,15 @@ +--- +/** + * Custom Footer component that includes the FlairBadge system + * Wraps Starlight's default Footer + */ +import type { Props } from '@astrojs/starlight/props'; +import Default from '@astrojs/starlight/components/Footer.astro'; +import FlairBadge from './FlairBadge.astro'; + +// Get current path for flair matching +const currentPath = Astro.url.pathname; +--- + + + diff --git a/src/data/flair-config.json b/src/data/flair-config.json index ae64fb0..13b25eb 100644 --- a/src/data/flair-config.json +++ b/src/data/flair-config.json @@ -7,83 +7,95 @@ "path": "/", "name": "I Was Told There Would Be Extraction", "placeholder": "📄", + "image": "/flair/extraction.svg", "description": "Started your mcwaddams journey" }, { "id": "backstory", - "path": "/backstory", + "path": "/backstory/", "name": "Basement Dweller", "placeholder": "🔴", + "image": "/flair/basement.svg", "description": "Learned about Milton and the legacy documents" }, { "id": "installation", - "path": "/installation", + "path": "/installation/", "name": "PC Load Letter", "placeholder": "🖨️", + "image": "/flair/printer.svg", "description": "Successfully installed mcwaddams" }, { "id": "quickstart", - "path": "/quickstart", + "path": "/quickstart/", "name": "Case of the Mondays", "placeholder": "☕", + "image": "/flair/coffee.svg", "description": "Completed the quick start guide" }, { "id": "reference", - "path": "/reference/tools", + "path": "/reference/tools/", "name": "TPS Report Expert", "placeholder": "📋", + "image": "/flair/tps.svg", "description": "Read the complete tools reference" }, { "id": "architecture", - "path": "/explanation/architecture", + "path": "/explanation/architecture/", "name": "The Bobs Approved", "placeholder": "👔", + "image": "/flair/bobs.svg", "description": "Understood the architecture" }, { "id": "dashboard", - "path": "/tps/dashboard", + "path": "/tps/dashboard/", "name": "Did You Get The Memo?", "placeholder": "📝", + "image": "/flair/memo.svg", "description": "Checked the test dashboard" }, { "id": "torture", - "path": "/tps/torture", + "path": "/tps/torture/", "name": "O Face", "placeholder": "😮", + "image": "/flair/oface.svg", "description": "Witnessed the torture test results" }, { "id": "credits", - "path": "/community/credits", + "path": "/community/credits/", "name": "I Have Your Stapler", "placeholder": "🔴", + "image": "/flair/stapler.svg", "description": "Found the credits and attributions" }, { "id": "tutorial", - "path": "/tutorials/first-extraction", + "path": "/tutorials/first-extraction/", "name": "Jump to Conclusions", "placeholder": "🎲", + "image": "/flair/conclusions.svg", "description": "Completed your first extraction tutorial" }, { "id": "tables", - "path": "/how-to/extract-tables", + "path": "/how-to/extract-tables/", "name": "Spreadsheet Survivor", "placeholder": "📊", + "image": "/flair/spreadsheet.svg", "description": "Mastered table extraction" }, { "id": "collector", - "path": "/community/leaderboard", + "path": "/community/leaderboard/", "name": "37 Pieces of Flair", "placeholder": "🎖️", + "image": "/flair/flair-badge.svg", "description": "Discovered the flair leaderboard" } ],