Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"webtorrent": "^2.8.5"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.2.4",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
Expand All @@ -85,13 +86,12 @@
"@types/webtorrent": "^0.110.1",
"@vitejs/plugin-react": "^5.1.4",
"@vitest/coverage-v8": "^3.2.4",
"autoprefixer": "^10.5.0",
"dotenv": "^17.4.2",
"eslint": "^9.39.2",
"eslint-config-next": "16.2.4",
"jsdom": "^29.0.1",
"postcss": "^8.5.14",
"tailwindcss": "^3.4.17",
"tailwindcss": "^4.2.4",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"vitest": "^3.2.4"
Expand Down
763 changes: 373 additions & 390 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
'@tailwindcss/postcss': {},
},
};

Expand Down
4 changes: 2 additions & 2 deletions src/app/account/account-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ function AccountPageContent(): React.ReactElement {
{subscriptionLabel}
</span>
{subscriptionStatus?.status ? <span className={cn(
'text-xs px-2 py-0.5 rounded',
'text-xs px-2 py-0.5 rounded-sm',
subscriptionStatus.status === 'active'
? 'bg-status-success/10 text-status-success'
: subscriptionStatus.status === 'cancelled'
Expand Down Expand Up @@ -733,7 +733,7 @@ function AccountPageContent(): React.ReactElement {
{formatCurrency(payment.amountUsd)}
</p>
<span className={cn(
'text-xs px-2 py-0.5 rounded',
'text-xs px-2 py-0.5 rounded-sm',
payment.status === 'confirmed' || payment.status === 'forwarded'
? 'bg-status-success/10 text-status-success'
: payment.status === 'pending' || payment.status === 'detected'
Expand Down
2 changes: 1 addition & 1 deletion src/app/archive/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default function ArchivePage() {
<Link
key={`${m.year}-${m.month}`}
href={`/torrents/archive/${m.year}/${String(m.month).padStart(2, '0')}`}
className="rounded border border-border-subtle px-4 py-3 text-sm text-text-primary hover:border-accent-primary/30 hover:bg-bg-hover transition-colors"
className="rounded-sm border border-border-subtle px-4 py-3 text-sm text-text-primary hover:border-accent-primary/30 hover:bg-bg-hover transition-colors"
>
{m.label}
</Link>
Expand Down
84 changes: 29 additions & 55 deletions src/app/dht/[infohash]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,16 @@ export default async function DhtTorrentPage({ params }: PageProps) {
</nav>

{/* Hero with backdrop */}
{torrent.backdrop_url && (
<div className="relative -mx-4 -mt-2 h-48 sm:h-64 overflow-hidden rounded-lg sm:mx-0">
{torrent.backdrop_url ? <div className="relative -mx-4 -mt-2 h-48 sm:h-64 overflow-hidden rounded-lg sm:mx-0">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={torrent.backdrop_url}
alt=""
className="h-full w-full object-cover"
loading="eager"
/>
<div className="absolute inset-0 bg-gradient-to-t from-bg-primary via-bg-primary/60 to-transparent" />
</div>
)}
<div className="absolute inset-0 bg-linear-to-t from-bg-primary via-bg-primary/60 to-transparent" />
</div> : null}

{/* Header card */}
<div className={`card p-6 ${torrent.backdrop_url ? '-mt-24 relative z-10' : ''}`}>
Expand All @@ -132,7 +130,7 @@ export default async function DhtTorrentPage({ params }: PageProps) {
/>
</div>
) : (
<div className="flex h-20 w-16 shrink-0 items-center justify-center rounded bg-bg-tertiary text-3xl">
<div className="flex h-20 w-16 shrink-0 items-center justify-center rounded-sm bg-bg-tertiary text-3xl">
{getMediaIcon(torrent.extension)}
</div>
)}
Expand All @@ -144,37 +142,26 @@ export default async function DhtTorrentPage({ params }: PageProps) {
)}

{/* Tagline */}
{torrent.tagline && (
<p className="mt-1 text-sm italic text-text-muted">&ldquo;{torrent.tagline}&rdquo;</p>
)}
{torrent.tagline ? <p className="mt-1 text-sm italic text-text-muted">&ldquo;{torrent.tagline}&rdquo;</p> : null}

{/* Meta badges row */}
<div className="mt-3 flex flex-wrap items-center gap-2">
{torrent.year && (
<span className="rounded bg-bg-tertiary px-2 py-0.5 text-xs font-medium text-text-secondary">
{torrent.year ? <span className="rounded-sm bg-bg-tertiary px-2 py-0.5 text-xs font-medium text-text-secondary">
{torrent.year}
</span>
)}
{torrent.content_rating && (
<span className="rounded border border-text-muted/30 px-2 py-0.5 text-xs font-medium text-text-secondary">
</span> : null}
{torrent.content_rating ? <span className="rounded-sm border border-text-muted/30 px-2 py-0.5 text-xs font-medium text-text-secondary">
{torrent.content_rating}
</span>
)}
{torrent.runtime_minutes && (
<span className="text-xs text-text-muted">
</span> : null}
{torrent.runtime_minutes ? <span className="text-xs text-text-muted">
{Math.floor(torrent.runtime_minutes / 60)}h {torrent.runtime_minutes % 60}m
</span>
)}
{torrent.content_type && (
<span className="rounded-full bg-bg-tertiary px-2 py-0.5 text-xs capitalize text-text-secondary">
</span> : null}
{torrent.content_type ? <span className="rounded-full bg-bg-tertiary px-2 py-0.5 text-xs capitalize text-text-secondary">
{torrent.content_type}
</span>
)}
</span> : null}
</div>

{/* IMDB rating */}
{hasImdb && (
<div className="mt-3 flex items-center gap-3">
{hasImdb ? <div className="mt-3 flex items-center gap-3">
<a
href={`https://www.imdb.com/title/${torrent.imdb_id}/`}
target="_blank"
Expand All @@ -187,12 +174,10 @@ export default async function DhtTorrentPage({ params }: PageProps) {
<span className="text-xs text-text-muted">
{(torrent.imdb_votes ?? 0).toLocaleString()} votes
</span>
</div>
)}
</div> : null}

{/* Genres */}
{torrent.genres && (
<div className="mt-3 flex flex-wrap gap-1.5">
{torrent.genres ? <div className="mt-3 flex flex-wrap gap-1.5">
{torrent.genres.split(', ').map((genre) => (
<span
key={genre}
Expand All @@ -201,45 +186,34 @@ export default async function DhtTorrentPage({ params }: PageProps) {
{genre}
</span>
))}
</div>
)}
</div> : null}

{/* Infohash */}
<p className="mt-3 font-mono text-[10px] text-text-muted/60 hidden sm:block">{infohash}</p>
</div>
</div>

{/* Synopsis */}
{torrent.overview && (
<div className="mt-6">
{torrent.overview ? <div className="mt-6">
<h2 className="text-sm font-semibold text-text-secondary uppercase tracking-wider mb-2">Synopsis</h2>
<p className="text-sm leading-relaxed text-text-primary">{torrent.overview}</p>
</div>
)}
</div> : null}

{/* Credits row */}
{(torrent.director || torrent.cast || torrent.writers) && (
<div className="mt-6 grid gap-4 sm:grid-cols-3">
{torrent.director && (
<div>
{(torrent.director || torrent.cast || torrent.writers) ? <div className="mt-6 grid gap-4 sm:grid-cols-3">
{torrent.director ? <div>
<h3 className="text-xs font-semibold text-text-muted uppercase tracking-wider">Director</h3>
<p className="mt-1 text-sm text-text-primary">{torrent.director}</p>
</div>
)}
{torrent.writers && (
<div>
</div> : null}
{torrent.writers ? <div>
<h3 className="text-xs font-semibold text-text-muted uppercase tracking-wider">Writers</h3>
<p className="mt-1 text-sm text-text-primary">{torrent.writers}</p>
</div>
)}
{torrent.cast && (
<div className="sm:col-span-2">
</div> : null}
{torrent.cast ? <div className="sm:col-span-2">
<h3 className="text-xs font-semibold text-text-muted uppercase tracking-wider">Cast</h3>
<p className="mt-1 text-sm text-text-primary">{torrent.cast}</p>
</div>
)}
</div>
)}
</div> : null}
</div> : null}

{/* Stats grid */}
<div className="mt-6 grid grid-cols-2 gap-4 sm:grid-cols-4">
Expand Down Expand Up @@ -279,7 +253,7 @@ export default async function DhtTorrentPage({ params }: PageProps) {
return (
<div
key={f.index}
className="flex items-center gap-3 rounded px-3 py-1.5 text-sm hover:bg-bg-hover"
className="flex items-center gap-3 rounded-sm px-3 py-1.5 text-sm hover:bg-bg-hover"
>
<span className="shrink-0">{getMediaIcon(f.extension)}</span>
<span className="min-w-0 flex-1 truncate text-text-primary" title={f.path}>
Expand All @@ -300,7 +274,7 @@ export default async function DhtTorrentPage({ params }: PageProps) {
<strong>{displayName}</strong> is a {torrent.content_type || 'torrent'} available via the BitTorrent DHT network.
Total size: {formatBytes(torrent.size)} across {torrent.files_count ?? 'unknown'} files.
{torrent.seeders != null && torrent.seeders > 0 && ` Currently ${torrent.seeders} seeders are sharing this torrent.`}
{hasTmdb && torrent.overview && ` ${torrent.overview}`}
{hasTmdb && torrent.overview ? ` ${torrent.overview}` : null}
</p>
<DhtIndexCta infohash={infohash} magnetUri={magnetUri} />
</div>
Expand Down
8 changes: 4 additions & 4 deletions src/app/dht/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ const DhtResultsList = memo(function DhtResultsList({
key={result.infohash}
href={`/dht/${result.infohash}`}
className={cn(
'block rounded border border-transparent px-3 py-2',
'block rounded-sm border border-transparent px-3 py-2',
'hover:border-accent-primary/30 hover:bg-bg-hover',
'transition-colors'
)}
Expand All @@ -147,7 +147,7 @@ const DhtResultsList = memo(function DhtResultsList({
onAddToLibrary(result);
}}
className={cn(
'flex items-center gap-1 rounded px-2 py-1 text-xs',
'flex items-center gap-1 rounded-sm px-2 py-1 text-xs',
'bg-accent-primary/20 text-accent-primary hover:bg-accent-primary/30',
'transition-colors shrink-0'
)}
Expand All @@ -164,7 +164,7 @@ const DhtResultsList = memo(function DhtResultsList({
</span>
{result.content_type ? (
<span className={cn(
'shrink-0 rounded px-1.5 py-0.5 text-[10px] font-medium uppercase',
'shrink-0 rounded-sm px-1.5 py-0.5 text-[10px] font-medium uppercase',
getCategoryColor(result.content_type)
)}>
{formatContentType(result.content_type)}
Expand Down Expand Up @@ -424,7 +424,7 @@ function DhtPageInner(): React.ReactElement {
onClick={() => handleSort(option.key)}
title={sortBy === option.key ? 'Click to reverse order' : `Sort by ${option.label}`}
className={cn(
'flex items-center gap-1 rounded px-2 py-1 text-xs transition-colors',
'flex items-center gap-1 rounded-sm px-2 py-1 text-xs transition-colors',
sortBy === option.key
? 'bg-accent-primary/20 text-accent-primary'
: 'text-text-secondary hover:bg-bg-hover hover:text-text-primary'
Expand Down
6 changes: 3 additions & 3 deletions src/app/find-torrents/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ function FindTorrentsPageInner(): React.ReactElement {
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search for torrents..."
className="w-full rounded-lg border border-bg-tertiary bg-bg-secondary py-3 pl-11 pr-4 text-text-primary placeholder-text-muted focus:border-accent-primary focus:outline-none focus:ring-1 focus:ring-accent-primary"
className="w-full rounded-lg border border-bg-tertiary bg-bg-secondary py-3 pl-11 pr-4 text-text-primary placeholder-text-muted focus:border-accent-primary focus:outline-hidden focus:ring-1 focus:ring-accent-primary"
/>
</div>
</div>
Expand All @@ -427,7 +427,7 @@ function FindTorrentsPageInner(): React.ReactElement {
aria-label="Sort by"
value={sort}
onChange={(e) => setSort(e.target.value)}
className="w-full rounded-lg border border-bg-tertiary bg-bg-secondary px-4 py-3 text-text-primary focus:border-accent-primary focus:outline-none focus:ring-1 focus:ring-accent-primary"
className="w-full rounded-lg border border-bg-tertiary bg-bg-secondary px-4 py-3 text-text-primary focus:border-accent-primary focus:outline-hidden focus:ring-1 focus:ring-accent-primary"
>
{SORT_OPTIONS.map((option) => (
<option key={option.value} value={option.value}>
Expand All @@ -445,7 +445,7 @@ function FindTorrentsPageInner(): React.ReactElement {
aria-label="Provider"
value={provider}
onChange={(e) => setProvider(e.target.value)}
className="w-full rounded-lg border border-bg-tertiary bg-bg-secondary px-4 py-3 text-text-primary focus:border-accent-primary focus:outline-none focus:ring-1 focus:ring-accent-primary"
className="w-full rounded-lg border border-bg-tertiary bg-bg-secondary px-4 py-3 text-text-primary focus:border-accent-primary focus:outline-hidden focus:ring-1 focus:ring-accent-primary"
>
{PROVIDERS.map((p) => (
<option key={p.value} value={p.value}>
Expand Down
2 changes: 1 addition & 1 deletion src/app/forgot-password/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export default function ForgotPasswordPage(): React.ReactElement {
className={cn(
'w-full rounded-lg border border-border-default bg-bg-secondary px-4 py-3',
'text-text-primary placeholder:text-text-muted',
'focus:border-accent-primary focus:outline-none focus:ring-1 focus:ring-accent-primary'
'focus:border-accent-primary focus:outline-hidden focus:ring-1 focus:ring-accent-primary'
)}
placeholder="you@example.com"
/>
Expand Down
Loading
Loading