Web version of the Gaudio Books audiobook library: 20 authors, 58 books, 500+ hours in the browser. Catalogue with search, a persistent player across pages (Jotai), dark theme for long listening. Next.js 16, React 19, Tailwind v4, shadcn/ui.
Gaudio Books already had mobile apps on the App Store and Google Play and a large library of recordings: 20 authors, 58 books, 1,126 tracks — over 500 hours of audio. It needed a web version: listening without installing an app, books findable through search, and a "storefront" with links to the apps and ways to support the project.

The library arrives as a single JSON file structured "author → book → part → track" and is served from a CDN. A data-transformation layer turns it into flat lists of authors and books: Cyrillic transliterated into slugs, deduplication (identical titles by different authors get -2, -3 suffixes), continuous chapter numbering, "popular" books being those with more tracks than the library average. Adding a new book needs no code changes.
// lib/data.ts — deduplicated slugs; books and chapters built in one pass
const _slugCounts: Record<string, number> = {}
export const books: Book[] = rawData.authors.flatMap(author =>
author.books.map(book => {
const base = slugify(book.title) // Cyrillic → Latin
_slugCounts[base] = (_slugCounts[base] ?? 0) + 1
const slug = _slugCounts[base] > 1 ? `${base}-${_slugCounts[base]}` : base
const tracks = book.parts.flatMap(part => part.tracks.map(t => ({ ...t, partTitle: part.title })))
return { slug, title: book.title, author: author.author, chapters: tracks.length,
isPopular: tracks.length > avgTracks, isNew: book.lastModified > ONE_YEAR_AGO }
})
)



A fixed bottom bar that lives above every page. The current book sits in a Jotai atom in the root layout, so navigating between pages never interrupts playback. The player has seekable progress, volume, speed 0.75× / 1× / 1.25× / 1.5× / 2×, a 15 / 30 / 60-minute sleep timer, a bookmark and chapter skipping.

// lib/playerStore.ts — the whole player state: one book in an atom
export const currentBookAtom = atom<Book | null>(null)
// app/layout.tsx — the player renders at the root, outside pages
<AudioPlayerWrapper />
// book/[slug] — "Listen now" just puts the book into the atom
<Button onClick={() => setCurrentBook(book)}>Listen now</Button>
A dark theme for long listening: Deep Night #0E0E12 background, Sandalwood #C9A66B accent, cream text, a soft gold glow on CTAs. There's also a light parchment theme — toggled in the header and remembered. Headings in Playfair Display, text in Geist. The look nods to the tradition (Sanskrit ornament in the hero) while staying contemporary rather than "souvenir". The interface is entirely in Russian.



The mobile app the project started with is a separate case: Gaudio Books — iOS & Android App.
A working web platform with the full 500+ hour library available straight in the browser, one player across the whole site, and an entry point for the mobile apps and donations.