From 9674f215f868d7673adf293fce8b85381c3582f6 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Fri, 13 Feb 2026 07:31:25 -0700 Subject: [PATCH] Add HandDrawn component with dark mode support, apply to homepage and collection pages Port hand-drawn visual effects (highlight, underline, circle variants) with dark mode fixes: CSS variable-based text color, reduced highlighter opacity in dark mode, and proper static text fallback for non-animated instances. Applied orange underline to hero text, teal/green circles to stats, yellow highlight to "Heritage", and underlines on collection headers. --- site/src/components/HandDrawn.astro | 381 ++++++++++++++++++++++++++++ site/src/pages/index.astro | 9 +- site/src/pages/mims/index.astro | 3 +- site/src/pages/uglys/index.astro | 3 +- site/src/styles/global.css | 2 + 5 files changed, 392 insertions(+), 6 deletions(-) create mode 100644 site/src/components/HandDrawn.astro diff --git a/site/src/components/HandDrawn.astro b/site/src/components/HandDrawn.astro new file mode 100644 index 0000000..014bcbd --- /dev/null +++ b/site/src/components/HandDrawn.astro @@ -0,0 +1,381 @@ +--- +/** + * HandDrawn - Reusable hand-drawn effects for emphasis with animations + * + * Variants: + * - highlight: Highlighter blob behind text (dark text, colored background) + * - underline: Squiggly underline beneath text + * - circle: Hand-drawn circle/oval around text + * + * Colors: + * - yellow (default): Classic yellow highlighter + * - pink: Pink/magenta emphasis + * - green: Green emphasis + * - blue: Blue emphasis + * - orange: Warm orange emphasis + * - teal: Teal/cyan emphasis + * + * Animation: + * - animate: Enable draw-on/fade-in animations (default: true) + * - trigger: 'load' (immediate) or 'visible' (when scrolled into view) + * - delay: Animation delay in ms (default: 0) + * - duration: Animation duration in ms (default: 600 for draw, 400 for highlight) + */ + +interface Props { + variant?: 'highlight' | 'underline' | 'circle'; + color?: 'yellow' | 'pink' | 'green' | 'blue' | 'orange' | 'teal'; + animate?: boolean; + trigger?: 'load' | 'visible'; + delay?: number; + duration?: number; + class?: string; +} + +const { + variant = 'highlight', + color = 'yellow', + animate = true, + trigger = 'visible', + delay = 0, + duration = variant === 'highlight' ? 400 : 600, + class: className = '', +} = Astro.props; + +// Color mappings for realistic highlighter colors (Staedtler Textsurfer Classic inspired) +// Uses custom CSS classes for authentic fluorescent marker look +const colorMap = { + yellow: { + highlight: { primary: 'hd-fill-yellow', secondary: 'hd-fill-yellow-light' }, + underline: 'hd-stroke-yellow', + circle: 'hd-stroke-yellow', + }, + pink: { + highlight: { primary: 'hd-fill-pink', secondary: 'hd-fill-pink-light' }, + underline: 'hd-stroke-pink', + circle: 'hd-stroke-pink', + }, + green: { + highlight: { primary: 'hd-fill-green', secondary: 'hd-fill-green-light' }, + underline: 'hd-stroke-green', + circle: 'hd-stroke-green', + }, + blue: { + highlight: { primary: 'hd-fill-blue', secondary: 'hd-fill-blue-light' }, + underline: 'hd-stroke-blue', + circle: 'hd-stroke-blue', + }, + orange: { + highlight: { primary: 'hd-fill-orange', secondary: 'hd-fill-orange-light' }, + underline: 'hd-stroke-orange', + circle: 'hd-stroke-orange', + }, + teal: { + highlight: { primary: 'hd-fill-teal', secondary: 'hd-fill-teal-light' }, + underline: 'hd-stroke-teal', + circle: 'hd-stroke-teal', + }, +}; + +const colors = colorMap[color]; + +// Generate unique ID for this instance +const id = `hd-${Math.random().toString(36).slice(2, 9)}`; + +// Animation classes +const animateClass = animate ? 'hand-drawn-animate' : ''; +const triggerClass = trigger === 'visible' ? 'hand-drawn-observe' : 'hand-drawn-immediate'; + +// Circle-specific randomization for organic feel +const circleJitterScale = 0.8 + Math.random() * 0.4; +const circleSpeedMultiplier = 0.9 + Math.random() * 0.4; +const circleStrokeLength = 85 + Math.floor(Math.random() * 8); +--- + +{variant === 'highlight' && ( + + + + + + +)} + +{variant === 'underline' && ( + + + + +)} + +{variant === 'circle' && ( + + + + +)} + + + + diff --git a/site/src/pages/index.astro b/site/src/pages/index.astro index 7e7e371..44ed47f 100644 --- a/site/src/pages/index.astro +++ b/site/src/pages/index.astro @@ -1,6 +1,7 @@ --- import Layout from '@/layouts/Layout.astro'; import BookGrid from '@/components/BookGrid.astro'; +import HandDrawn from '@/components/HandDrawn.astro'; import { getCollection } from 'astro:content'; const allBooks = await getCollection('books'); @@ -29,7 +30,7 @@ const totalBooks = allBooks.length;

The Hand-Drawn References That - Taught Generations + Taught Generations

@@ -75,11 +76,11 @@ const totalBooks = allBooks.length;

Collections
-
100+
+
100+
Circuit Projects
-
Free
+
Free
PDF Downloads
@@ -183,7 +184,7 @@ const totalBooks = allBooks.length;
-

Preserving Electronics Heritage

+

Preserving Electronics Heritage

These references represent the golden age of hands-on electronics education. Forrest M. Mims III, a Texas A&M graduate and one of the most widely read electronics authors in history, taught millions diff --git a/site/src/pages/mims/index.astro b/site/src/pages/mims/index.astro index a014396..69771f1 100644 --- a/site/src/pages/mims/index.astro +++ b/site/src/pages/mims/index.astro @@ -1,6 +1,7 @@ --- import Layout from '@/layouts/Layout.astro'; import FilterableBookGrid from '@/components/FilterableBookGrid'; +import HandDrawn from '@/components/HandDrawn.astro'; import { getCollection } from 'astro:content'; import { serializeBook } from '@/lib/types'; @@ -32,7 +33,7 @@ const serializedBooks = mimsBooks.map(serializeBook);

- Forrest Mims Mini-Notebooks + Forrest Mims Mini-Notebooks

The complete Radio Shack Engineer's Mini-Notebook series. Hand-illustrated electronics diff --git a/site/src/pages/uglys/index.astro b/site/src/pages/uglys/index.astro index 83b6280..f580b22 100644 --- a/site/src/pages/uglys/index.astro +++ b/site/src/pages/uglys/index.astro @@ -1,6 +1,7 @@ --- import Layout from '@/layouts/Layout.astro'; import FilterableBookGrid from '@/components/FilterableBookGrid'; +import HandDrawn from '@/components/HandDrawn.astro'; import { getCollection } from 'astro:content'; import { serializeBook } from '@/lib/types'; @@ -32,7 +33,7 @@ const serializedBooks = uglysBooks.map(serializeBook);

- Ugly's Electrical References + Ugly's Electrical References

The pocket-sized bible for electricians. Packed with tables, formulas, wiring diagrams, diff --git a/site/src/styles/global.css b/site/src/styles/global.css index 05843e4..0f64b61 100644 --- a/site/src/styles/global.css +++ b/site/src/styles/global.css @@ -84,6 +84,7 @@ --sidebar-accent-foreground: oklch(0.30 0.03 250); --sidebar-border: oklch(0.85 0.04 230); --sidebar-ring: oklch(0.55 0.12 250); + --hd-text-color: rgb(15 23 42); } .dark { @@ -118,6 +119,7 @@ --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(1 0 0 / 10%); --sidebar-ring: oklch(0.556 0 0); + --hd-text-color: rgb(248 250 252); } @layer base {