From 8f2c5ac074aa71568dba01883880ae8f6a23de34 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Fri, 13 Feb 2026 06:19:49 -0700 Subject: [PATCH] Add dark mode toggle, PWA support, remove unused PdfViewer --- site/Caddyfile | 4 + site/package.json | 1 - site/public/icons/apple-touch-icon.png | Bin 0 -> 1784 bytes site/public/icons/icon-192.png | Bin 0 -> 1818 bytes site/public/icons/icon-512-maskable.png | Bin 0 -> 4540 bytes site/public/icons/icon-512.png | Bin 0 -> 5178 bytes site/public/manifest.json | 32 +++++++ site/public/offline.html | 66 +++++++++++++++ site/public/sw.js | 75 +++++++++++++++++ site/src/components/PdfViewer.tsx | 106 ------------------------ site/src/components/ThemeToggle.tsx | 85 +++++++++++++++++++ site/src/layouts/Layout.astro | 21 +++++ site/src/styles/global.css | 32 +++++++ 13 files changed, 315 insertions(+), 107 deletions(-) create mode 100644 site/public/icons/apple-touch-icon.png create mode 100644 site/public/icons/icon-192.png create mode 100644 site/public/icons/icon-512-maskable.png create mode 100644 site/public/icons/icon-512.png create mode 100644 site/public/manifest.json create mode 100644 site/public/offline.html create mode 100644 site/public/sw.js delete mode 100644 site/src/components/PdfViewer.tsx create mode 100644 site/src/components/ThemeToggle.tsx diff --git a/site/Caddyfile b/site/Caddyfile index a36626b..5d09ecb 100644 --- a/site/Caddyfile +++ b/site/Caddyfile @@ -8,6 +8,10 @@ # Compression encode gzip + # Service worker must not be cached + @sw path /sw.js + header @sw Cache-Control "no-cache, no-store, must-revalidate" + # Cache static assets @static { path *.jpg *.jpeg *.png *.gif *.ico *.css *.js *.pdf *.svg *.woff *.woff2 diff --git a/site/package.json b/site/package.json index d9bd10f..c77f213 100644 --- a/site/package.json +++ b/site/package.json @@ -22,7 +22,6 @@ "lucide-react": "^0.562.0", "react": "^19.2.3", "react-dom": "^19.2.3", - "react-pdf": "^10.3.0", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.18" }, diff --git a/site/public/icons/apple-touch-icon.png b/site/public/icons/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6d3d115420f132640516d14c44d06627401a570d GIT binary patch literal 1784 zcmc&#`B%~j5Z8R>c1Q=cUZ`DIVNWEFFhx7?N>_cUyCPm`YF^kkGBpD&le|({+cnFu z^~elCJG@FQv(VIF(~uGr6H&teSprQ(mVVqnV0YiVna{k>n>WAAd}i|eeBAZd8?V>W z($e?zK%dm$lkfh+8clrENRHOP+DI>Vw3hn2-R-O^)etmK^wEH{3h`KIqJK1`S5_w; z#XU(7$JEkwP8nJlx5k}56}34GebkoW@xB0>7X5w@{Q_OZ*x+GnVT_2kwXle{hJAX; zxqIfI?v(2`23ptsNSM6^Jj0a{k<_^Z;l@g4(i~BOOD<(I6_nN9E=SaPFLU4U~77#YVuqBg28!7Lv`^N-v8_9ly;=ThraC|InwvE(G;Q15Ol zY{Jbf@6-0x(_pj%#mjQilB&(R1UH%)iS?fwnQrmFL%>wRjNq4)?=Vo=*%6l0F*7|n z=;QpCUzS1FB>}Q3V1b`LcEzZ)BRkA<=<^^${Jc{o^WE#nED||!ykQrGdAHpa`$^pZ z@PslOy7Yc+28DXSh%h_;z=Up;+@8vT?+wGYF8d|4qIx=-ms*Bo%%^EcNv-5O$AL?k zi%3`yB-qoqZEF5A=fy~Vza9U>&m_e3dCqKDg{JEQq}-dqtn;d~Np9c|pKFsptR2qQ zu0%|~%z0lRU2Ov9k}njUDtxFIFf;BAbvRcA%#dTpd1U74gGO>5mj5xFWaA*|CtLC* z&MnH}N*g1&f?3^8dA*aJ> z*$(pACi;V#d$4rH)u01g2j%)RPq`~|Z-lHvAi-s&i4Cw3OJSK5Z+{h~YquS`iC-41 z7OtjLN*%c_5$R1&KdlokOWT`QB)YE}!_d9}V27w5ltCt2ny(=pW@6rp@D*V*dJ#6vpSiRTk#QN-aKik=JT&T5Q|?`S#b z@EC^K_SSr=Z#a~IU3ij|6rY51D5nLIdP@*s_a7CNzG5D?3!l79l}ft^${PWrlleDJ z)P@t2IkC4vpu+i!cE7hHik@$*88WwT36hBB%op#=vfj#(*9ABaLQgPKymdl;SW@b1 zx^TyX(PI@teK9B7)3|R?u}wYIhKzi-(#{6sQ8{DN0ltPSBgnlKX{?70s}@n-f>ie* zCEe!^IIK9HA9vKbw67A%;xM(yxAWY zVtfs8uX>r6KVwq7I_}tq0E2ThYB0fze3fVLJpKBl{HkwMlNh0%aQ(1mZ$<8+5G)D6 zYxZkM_UYO5Pk|ZIu68G*R9+@rJS9RFA_`*5>O%`+-sJ2KeJKX^z$QA^WQ>ILR+$dN1_YV>lNhtc=TX7* zX#lj)wNAN-dy8wI=zOLSV@qwgSG9*DK&}CfOh)VeKd1Shk0EnSlQ2oAa@0nmd1YFj Mu0Ck`v4|^w1KK`I5&!@I literal 0 HcmV?d00001 diff --git a/site/public/icons/icon-192.png b/site/public/icons/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..ecffad7c668fa8a3993ed9d3a0ecac0126bb7646 GIT binary patch literal 1818 zcmd5-`!^E|7~WJ1#YkW7mt0au(I?BTZIuzZ?W3&aT4B*xHFJqo2#uuhNwK+=`^a)F zCYDNKmSVOn8K#SB_St4KpZ${NRcTjM-r9lbhB$OAzIcAZAL~m1yb$6a$97?{H-O~5 zA)?;nFDxBmQj8`yq=L48+W^Vii~G~Xu(MBd@lduE>_-Ry;zC4jUQc>neLeHKS8~7N zMWysCXH*aHNedzHODYIG;@i5?Dt>(#p0iRiBJ!3D+OJafIEGhO3<5v{w?8R`gqj$+ zDk^SKNV#^^X#4+W#Z;P~S5FQRd?`99{`sDxPg3pIb-?QxwBf&=^{(j-iA4Xk7_<78 zW}FeBIz>G#l$M=|8r-;Qm-N-ch<#axwbLWHB%X1y_AcR~A&>4~NN}!!UvcG~FDxv( z+3LaU@iAgAy>$0?e6p%DT5-c-!LpuA!+!jOpV_(ce&(3JWY#JtNyre6U=A}J+LD65 z-NS72T*z7b-HFv7#y8HtXX&{zn*zLE>>9VR{7H1G!VH%;CROUhLW@6mr1KWF37fd+1 z6_l-Z>(CsQUc7|AQpLPhZJwsCJv>TSOy${fbRD?{_VUC;QO_g_F6YQFsLbpSJlbmc zKu+#dXIe`h##=Xde_84IeD2+S(ma_b82eCk(Y!`o`&RE=zLx*AzW+4!?x$da;5avK z!zeCN>11fWtP1T@Jl0-*I>__WHsRYTVf-=4em8e^(+ z8>sR(()3b!3mxfBc}`h!A5V!5Pj}#0 zLpQoR5h}ISyraFOjl5)4l{)6wC|A7wP<`^22d<_ji|k_Rx>urhYiQbQQ3tsdx}voo zTpbBw3ao3x3qmg`*RUN*-wjwS5DUP;uRsYwW1nYGVVAbmurH}cX}K7&JEHl#HPc|1 zYrhg4>%yhFsAC=rT-mO;Sn$~sX~wL{l8Hps=F2qx94k)%YR0V*V1^&4!{ke|h(U2; zo=X4ct3z3RQ~q=qO`O^VWwD)YW9{|9yyFSWKL_+wb*-XD(yq!M2@d`khkUpn{c9~5t3-O7;ycnto@99CQL)Q-etgin`PHWTFlT3xneaq zgV7oF?SWr~`)tsw$L2twS#2x*0%~7g7Rp%Rs12Qsf!IXfm_d#jmm*+oBR07KRUV9g z!h|aZ7VGn$6(0762d@X32@y`zaf$6@Wdw|cEUH;zYuj$g%1ulzlu=1(#9KHnNo t!4~2dcl!;ysi~O;^!_$!{g-ga?FOaifSa=yqTz5z%D??BDgpoi literal 0 HcmV?d00001 diff --git a/site/public/icons/icon-512-maskable.png b/site/public/icons/icon-512-maskable.png new file mode 100644 index 0000000000000000000000000000000000000000..c1533f396f9003aff524d1440a33e5e7e1467576 GIT binary patch literal 4540 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 Mj_!xb5BgvG54c+m;s5{u literal 0 HcmV?d00001 diff --git a/site/public/icons/icon-512.png b/site/public/icons/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..f47edb8eb84a2fdb6b8e152c678775418f5fbcec GIT binary patch literal 5178 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 literal 0 HcmV?d00001 diff --git a/site/public/manifest.json b/site/public/manifest.json new file mode 100644 index 0000000..5f064e4 --- /dev/null +++ b/site/public/manifest.json @@ -0,0 +1,32 @@ +{ + "name": "Electronics Reference Library", + "short_name": "Mims Library", + "description": "Classic electronics reference notebooks from Forrest M. Mims III", + "start_url": "/", + "display": "standalone", + "background_color": "#f7f3ee", + "theme_color": "#3b5998", + "icons": [ + { + "src": "/icons/icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/icons/icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "/icons/icon-512-maskable.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/favicon.svg", + "sizes": "any", + "type": "image/svg+xml" + } + ] +} diff --git a/site/public/offline.html b/site/public/offline.html new file mode 100644 index 0000000..b63cf50 --- /dev/null +++ b/site/public/offline.html @@ -0,0 +1,66 @@ + + + + + + Offline | Electronics Reference Library + + + +
+ + + + +
+

You're offline

+

Previously viewed pages and downloaded PDFs may still be available. Check your connection and try again.

+ + + diff --git a/site/public/sw.js b/site/public/sw.js new file mode 100644 index 0000000..84f4f24 --- /dev/null +++ b/site/public/sw.js @@ -0,0 +1,75 @@ +const CACHE_NAME = 'mims-library-v1'; +const PRECACHE_URLS = [ + '/', + '/offline.html', + '/favicon.svg', + '/manifest.json' +]; + +// Install: precache essential resources +self.addEventListener('install', (event) => { + event.waitUntil( + caches.open(CACHE_NAME).then((cache) => cache.addAll(PRECACHE_URLS)) + ); + self.skipWaiting(); +}); + +// Activate: clean old caches +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys().then((keys) => + Promise.all(keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k))) + ) + ); + self.clients.claim(); +}); + +// Fetch: tiered caching strategy +self.addEventListener('fetch', (event) => { + const { request } = event; + const url = new URL(request.url); + + // Only handle same-origin + if (url.origin !== location.origin) return; + + // Static assets: cache-first + if (/\.(css|js|jpg|jpeg|png|gif|svg|woff|woff2|ico)$/.test(url.pathname)) { + event.respondWith( + caches.match(request).then((cached) => + cached || fetch(request).then((response) => { + const clone = response.clone(); + caches.open(CACHE_NAME).then((cache) => cache.put(request, clone)); + return response; + }) + ) + ); + return; + } + + // PDFs: network-first, cache on success + if (/\.pdf$/.test(url.pathname)) { + event.respondWith( + fetch(request) + .then((response) => { + const clone = response.clone(); + caches.open(CACHE_NAME).then((cache) => cache.put(request, clone)); + return response; + }) + .catch(() => caches.match(request)) + ); + return; + } + + // HTML pages: network-first with offline fallback + event.respondWith( + fetch(request) + .then((response) => { + const clone = response.clone(); + caches.open(CACHE_NAME).then((cache) => cache.put(request, clone)); + return response; + }) + .catch(() => + caches.match(request).then((cached) => cached || caches.match('/offline.html')) + ) + ); +}); diff --git a/site/src/components/PdfViewer.tsx b/site/src/components/PdfViewer.tsx deleted file mode 100644 index edcc3c7..0000000 --- a/site/src/components/PdfViewer.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { useState } from 'react'; -import { Button } from '@/components/ui/button'; - -interface PdfViewerProps { - pdfUrl: string; -} - -export default function PdfViewer({ pdfUrl }: PdfViewerProps) { - const [isFullscreen, setIsFullscreen] = useState(false); - - return ( -
- {/* Controls */} -
-
- - - - - PDF Document -
- -
- - - - - - - - - Open in new tab - - - - - - - - - Download - -
-
- - {/* PDF Embed */} -
-