Ryan Malloy f7b160a9c1 Initial commit: Forrest Mims Electronics Reference Library
Astro site with e-book reader for classic electronics notebooks.
15 Mims notebooks + 1 Ugly's Electrical Reference, served via
Docker/Caddy at mims.l.supported.systems. PDFs tracked with git-lfs.
2026-02-13 05:09:09 -07:00

182 lines
7.7 KiB
Plaintext

---
import Layout from '@/layouts/Layout.astro';
import { Badge } from '@/components/ui/badge';
import EBookReader from '@/components/EBookReader';
import { getCollection, type CollectionEntry } from 'astro:content';
export async function getStaticPaths() {
const books = await getCollection('books');
return books
.filter(book => book.data.collection === 'uglys')
.map(book => ({
params: { slug: book.slug.split('/').pop() },
props: { book }
}));
}
interface Props {
book: CollectionEntry<'books'>;
}
const { book } = Astro.props;
const { title, shortTitle, description, topics, localPdf, coverImage, year, archiveOrgUrl, formats } = book.data;
// Get all uglys books for navigation
const allBooks = await getCollection('books');
const uglysBooks = allBooks
.filter(b => b.data.collection === 'uglys')
.sort((a, b) => a.data.sortOrder - b.data.sortOrder);
const currentIndex = uglysBooks.findIndex(b => b.slug === book.slug);
const prevBook = currentIndex > 0 ? uglysBooks[currentIndex - 1] : null;
const nextBook = currentIndex < uglysBooks.length - 1 ? uglysBooks[currentIndex + 1] : null;
---
<Layout title={shortTitle} description={description}>
<div class="space-y-8">
<!-- Breadcrumb -->
<div class="flex items-center gap-2 text-sm text-muted-foreground">
<a href="/" class="hover:text-foreground transition-colors">Home</a>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="9 18 15 12 9 6"/>
</svg>
<a href="/uglys" class="hover:text-foreground transition-colors">Ugly's Collection</a>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="9 18 15 12 9 6"/>
</svg>
<span class="text-foreground">{shortTitle}</span>
</div>
<!-- Compact Header -->
<div class="flex flex-col md:flex-row md:items-start gap-6">
<!-- Book Info -->
<div class="flex-1 space-y-4">
<div>
{year && (
<div class="inline-flex items-center gap-2 text-sm text-muted-foreground mb-2">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="18" height="18" x="3" y="4" rx="2" ry="2"/>
<line x1="16" x2="16" y1="2" y2="6"/>
<line x1="8" x2="8" y1="2" y2="6"/>
<line x1="3" x2="21" y1="10" y2="10"/>
</svg>
{year} Edition
</div>
)}
<h1 class="text-2xl md:text-3xl font-bold title-accent">{title}</h1>
<p class="text-muted-foreground mt-2">{description}</p>
</div>
<div class="flex flex-wrap gap-2">
{topics.slice(0, 5).map((topic) => (
<Badge variant="secondary" className="text-xs">
{topic.replace(/-/g, ' ')}
</Badge>
))}
{topics.length > 5 && (
<Badge variant="outline" className="text-xs">
+{topics.length - 5} more
</Badge>
)}
</div>
</div>
<!-- Quick Actions -->
<div class="flex flex-row md:flex-col gap-2">
<a
href={localPdf}
download
class="inline-flex items-center justify-center gap-2 px-4 py-2.5 bg-primary text-primary-foreground rounded-lg font-medium hover:bg-primary/90 transition-colors text-sm"
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" x2="12" y1="15" y2="3"/>
</svg>
<span>Download</span>
</a>
{archiveOrgUrl && (
<a
href={archiveOrgUrl}
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center justify-center gap-2 px-4 py-2.5 border border-border rounded-lg font-medium hover:bg-muted transition-colors text-sm"
>
<span>Archive.org</span>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
<polyline points="15 3 21 3 21 9"/>
<line x1="10" x2="21" y1="14" y2="3"/>
</svg>
</a>
)}
</div>
</div>
<!-- E-Book Reader -->
<div class="mt-6">
<EBookReader
pdfUrl={localPdf}
title={shortTitle}
coverImage={coverImage}
client:load
/>
</div>
<!-- Navigation -->
<div class="flex items-center justify-between pt-8 border-t border-border">
{prevBook ? (
<a
href={`/uglys/${prevBook.slug.split('/').pop()}`}
class="group flex items-center gap-3 p-3 -m-3 rounded-lg hover:bg-muted/50 transition-colors"
>
<div class="w-8 h-8 rounded-full bg-muted flex items-center justify-center group-hover:bg-primary/10 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-muted-foreground group-hover:text-primary transition-colors">
<polyline points="15 18 9 12 15 6"/>
</svg>
</div>
<div class="text-left">
<div class="text-xs text-muted-foreground">Previous</div>
<div class="text-sm font-medium text-foreground hidden sm:block">{prevBook.data.shortTitle}</div>
</div>
</a>
) : (
<div></div>
)}
<a
href="/uglys"
class="flex items-center gap-2 px-4 py-2 rounded-lg border border-border hover:bg-muted transition-colors text-sm"
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="7" height="7" x="3" y="3" rx="1"/>
<rect width="7" height="7" x="14" y="3" rx="1"/>
<rect width="7" height="7" x="14" y="14" rx="1"/>
<rect width="7" height="7" x="3" y="14" rx="1"/>
</svg>
<span class="hidden sm:inline">All References</span>
</a>
{nextBook ? (
<a
href={`/uglys/${nextBook.slug.split('/').pop()}`}
class="group flex items-center gap-3 p-3 -m-3 rounded-lg hover:bg-muted/50 transition-colors"
>
<div class="text-right">
<div class="text-xs text-muted-foreground">Next</div>
<div class="text-sm font-medium text-foreground hidden sm:block">{nextBook.data.shortTitle}</div>
</div>
<div class="w-8 h-8 rounded-full bg-muted flex items-center justify-center group-hover:bg-primary/10 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-muted-foreground group-hover:text-primary transition-colors">
<polyline points="9 18 15 12 9 6"/>
</svg>
</div>
</a>
) : (
<div></div>
)}
</div>
</div>
</Layout>