A personal comic book collection tracker with financial analytics, multi-view browsing, and comprehensive organization. Currently tracking 787 comics across 176 series. Built with React 18, TypeScript, and Tailwind CSS.
Live Site: comics.banast.as
- Track comics with full metadata: title, series, issue, grade, value, cover artist, storage location, tags, signatures, and more
- Monitor financial performance with purchase vs. current value, gain/loss calculations, and top gainers/losers
- Browse the collection multiple ways: grid view, list view, by series, by artist, by tag, by storage location, or by condition (raw/slabbed/variant)
- Search across titles, series, artists, notes, and signatures with sorting by any field
- View analytics on a dashboard with collection stats, value breakdowns, and highlighted comics
- React 18 + TypeScript 5.5 + Vite 7
- Tailwind CSS 3.4 for styling
- Zustand 5 for state management
- Zod 4 for data validation
- Lucide React for icons
- react-helmet-async for dynamic SEO meta tags
git clone https://github.com/banastas/comics.banast.as.git
cd comics.banast.as
npm install
npm run devOpen http://localhost:5173 in your browser.
src/
├── components/ # React components (31 files)
│ ├── Dashboard.tsx # Analytics dashboard with stats cards
│ ├── ComicCard.tsx # Grid view card (keyboard accessible)
│ ├── ComicListView.tsx # List view layout (keyboard accessible)
│ ├── ComicDetail.tsx # Individual comic page
│ ├── ComicForm.tsx # Add/edit comic form
│ ├── DetailPageLayout.tsx # Shared layout for all detail views
│ ├── DetailPageHeader.tsx # Header component for detail pages
│ ├── Breadcrumb.tsx # Navigation breadcrumbs
│ ├── SeriesDetail.tsx # Series drill-down view
│ ├── CoverArtistDetail.tsx
│ ├── TagDetail.tsx
│ ├── StorageLocationDetail.tsx
│ ├── StorageLocationsListing.tsx
│ ├── RawComicsDetail.tsx
│ ├── SlabbedComicsDetail.tsx
│ ├── VariantsDetail.tsx
│ ├── FilterControls.tsx
│ ├── SEO.tsx # Dynamic meta tags + structured data
│ ├── ResponsiveImage.tsx
│ ├── ErrorBoundary.tsx
│ ├── LoadingSkeleton.tsx # Loading states with ARIA
│ ├── Toast.tsx # Toast notifications
│ └── ... # Dashboard sub-components, mobile controls
├── stores/
│ └── comicStore.ts # Zustand state store
├── hooks/ # useRouting, useScrollToTop, useResponsiveBreakpoint
├── types/
│ └── Comic.ts # TypeScript interfaces
├── utils/ # formatting, stats, sorting, analytics, routing
├── data/
│ └── comics.json # Collection data (787 comics)
└── styles/
└── responsive.css
Total comics, collection value, average grade, raw vs. slabbed breakdown, variant count, signed comics count, biggest gainer/loser, most valuable slabbed and raw comics. All cards are clickable and navigate to their respective detail views.
- Grid view with cover art, grade badges, and value info
- List view for compact browsing
- Detail pages for individual comics with related issues from the same series
- By series (176 series) with per-series stats
- By cover artist with artist-specific collection views
- By tag for custom grouping
- By storage location (7 archive boxes + CGC + Loose)
- By condition: raw comics, slabbed/graded comics, variant covers
Full-text search across multiple fields. Sort by title, series, issue number, release date, grade, purchase date, purchase price, or current value. Ascending/descending toggle.
- JSON-based storage (
src/data/comics.json) - Built-in CSV to JSON converter for bulk imports
- Automatic timestamps on creation and updates
- Dynamic meta tags with react-helmet-async
- Schema.org structured data (ComicIssue, ComicSeries, Collection, Breadcrumb)
- Auto-generated sitemap (~1,134 URLs)
- Open Graph and Twitter Card support
- Hash-based SEO-friendly slugs (e.g.,
#/comic/batman-issue-1-variant)
- Lazy-loaded detail views with code splitting
- Manual Vite chunks (react-vendor, icons, data, utils, components)
- Terser minification with console/debugger stripping
- Native lazy loading and async decoding for images
- Skeleton loading states
- Granular Zustand selectors to minimize re-renders
- Stable debounce refs to prevent unnecessary recreations
- Keyboard-navigable comic cards (Enter/Space to activate)
- ARIA labels on all interactive elements and form controls
aria-current="page"on breadcrumbs- Loading skeletons with
role="status"andaria-busy focus-visiblering indicators for keyboard users- Error boundaries on all lazy-loaded routes
Mobile-first layout from 320px to 4K. 44px minimum touch targets. Fluid typography. Works on desktop, tablet, and phone.
npm run dev # Start dev server
npm run build # Generate sitemap + production build
npm run preview # Preview production build
npm run lint # ESLint
npm run generate:sitemap # Regenerate sitemap only- Click the file upload icon in the header
- Upload a CSV with columns: title, seriesName, issueNumber, releaseDate, coverImageUrl, coverArtist, grade, purchasePrice, purchaseDate, currentValue, notes, signedBy, storageLocation, tags, isSlabbed, isVariant, isGraphicNovel
- Download the converted JSON
- Replace
src/data/comics.jsonand restart the dev server
Add entries directly to src/data/comics.json following the Comic interface in src/types/Comic.ts.
npm run buildDeploy the dist/ folder to any static host (Netlify, Vercel, GitHub Pages, Cloudflare Pages, etc.). No server or environment variables required.
- JSON file storage (no database)
- Single-user (no authentication)
- Cover images hosted externally (covers.banast.as)
- Hash-based routing (SPA limitations for crawlers)
- No automated backup or sync
MIT
