Initial commit: Shelfless – alternative Audiobookshelf frontend

React + Vite + TypeScript SPA covering the full ABS feature set (library
browsing, item detail, metadata/cover editing, podcasts, player with session
sync, admin: users/libraries/scanner/server settings). Dev uses a dynamic
CORS proxy; production is served by server/index.mjs (static + reverse proxy
to ABS_URL). Includes systemd unit and installer under deploy/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-06-02 20:23:04 +02:00
commit 83d8b7b99d
93 changed files with 9790 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
import { cn } from '@/lib/cn'
export interface TabDef {
key: string
label: string
}
interface Props {
tabs: TabDef[]
active: string
onChange: (key: string) => void
}
export function Tabs({ tabs, active, onChange }: Props) {
return (
<div role="tablist" className="flex gap-1 border-b border-border">
{tabs.map((t) => (
<button
key={t.key}
role="tab"
aria-selected={active === t.key}
onClick={() => onChange(t.key)}
className={cn(
'relative -mb-px px-4 py-2.5 text-sm font-medium transition-colors',
active === t.key
? 'text-text'
: 'text-text-muted hover:text-text',
)}
>
{t.label}
{active === t.key && (
<span className="absolute inset-x-2 -bottom-px h-0.5 rounded-full bg-accent" />
)}
</button>
))}
</div>
)
}