From 7d69262d0efba50499ba48627af0131d097b97f1 Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Tue, 3 Mar 2026 20:23:52 -0500 Subject: [PATCH] Polish settings UI, add tooltips, replace timeAgo with date-fns Clean up settings section design: consolidate backup cards, add hover-reveal actions with tooltips, improve icon sizing across components, and replace custom timeAgo helper with date-fns formatDistanceToNow in webhook card. Co-Authored-By: Claude Opus 4.6 --- app/(auth)/register/page.tsx | 2 +- .../_components/continue-watching-card.tsx | 4 +- .../_components/continue-watching-section.tsx | 2 +- .../dashboard/_components/library-section.tsx | 2 +- .../_components/recommendations-section.tsx | 2 +- .../dashboard/_components/stats-display.tsx | 2 +- .../dashboard/_components/stats-section.tsx | 2 +- app/(pages)/explore/hero-banner.tsx | 4 +- app/(pages)/explore/page.tsx | 6 +- .../settings/_components/account-section.tsx | 4 +- .../settings/_components/backup-section.tsx | 69 ++++++++++++------- .../_components/integrations-section.tsx | 2 +- .../settings/_components/server-section.tsx | 2 +- .../settings/_components/settings-shell.tsx | 2 +- .../settings/_components/webhook-card.tsx | 33 +++------ app/(pages)/settings/page.tsx | 2 +- app/(pages)/setup/page.tsx | 12 ++-- .../titles/[id]/_components/star-rating.tsx | 4 +- .../titles/[id]/_components/status-button.tsx | 12 +--- .../titles/[id]/_components/title-actions.tsx | 2 +- .../titles/[id]/_components/title-seasons.tsx | 14 ++-- components/auth-form.tsx | 4 +- components/command-palette.tsx | 17 ++--- components/landing-page.tsx | 2 +- components/mobile-tab-bar.tsx | 3 +- components/nav-bar.tsx | 45 +++++++----- components/sofa-logo.tsx | 12 +--- components/title-card.tsx | 4 +- 28 files changed, 128 insertions(+), 143 deletions(-) diff --git a/app/(auth)/register/page.tsx b/app/(auth)/register/page.tsx index 7ce889d..f9b1621 100644 --- a/app/(auth)/register/page.tsx +++ b/app/(auth)/register/page.tsx @@ -51,7 +51,7 @@ export default function RegisterPage() { }} >
- +

diff --git a/app/(pages)/dashboard/_components/continue-watching-card.tsx b/app/(pages)/dashboard/_components/continue-watching-card.tsx index 904e3e4..1f71dcd 100644 --- a/app/(pages)/dashboard/_components/continue-watching-card.tsx +++ b/app/(pages)/dashboard/_components/continue-watching-card.tsx @@ -48,7 +48,7 @@ export function ContinueWatchingCard({ /> ) : (
- +
)}
@@ -76,7 +76,7 @@ export function ContinueWatchingCard({

- +

{progress > 0 && ( diff --git a/app/(pages)/dashboard/_components/continue-watching-section.tsx b/app/(pages)/dashboard/_components/continue-watching-section.tsx index 197e700..07d4775 100644 --- a/app/(pages)/dashboard/_components/continue-watching-section.tsx +++ b/app/(pages)/dashboard/_components/continue-watching-section.tsx @@ -34,7 +34,7 @@ export async function ContinueWatchingSection({ userId }: { userId: string }) { return ( } + icon={} > diff --git a/app/(pages)/dashboard/_components/library-section.tsx b/app/(pages)/dashboard/_components/library-section.tsx index 51f6c9f..b2f5adc 100644 --- a/app/(pages)/dashboard/_components/library-section.tsx +++ b/app/(pages)/dashboard/_components/library-section.tsx @@ -21,7 +21,7 @@ export async function LibrarySection({ userId }: { userId: string }) { return ( } + icon={} > diff --git a/app/(pages)/dashboard/_components/recommendations-section.tsx b/app/(pages)/dashboard/_components/recommendations-section.tsx index 5585bfc..13ac76e 100644 --- a/app/(pages)/dashboard/_components/recommendations-section.tsx +++ b/app/(pages)/dashboard/_components/recommendations-section.tsx @@ -24,7 +24,7 @@ export async function RecommendationsSection({ userId }: { userId: string }) { return ( } + icon={} > diff --git a/app/(pages)/dashboard/_components/stats-display.tsx b/app/(pages)/dashboard/_components/stats-display.tsx index 3a3eb3d..29cec28 100644 --- a/app/(pages)/dashboard/_components/stats-display.tsx +++ b/app/(pages)/dashboard/_components/stats-display.tsx @@ -63,7 +63,7 @@ export function StatsDisplay({ stats }: { stats: DashboardStats }) {
- +
{def.label} diff --git a/app/(pages)/dashboard/_components/stats-section.tsx b/app/(pages)/dashboard/_components/stats-section.tsx index 3666aa1..cce6988 100644 --- a/app/(pages)/dashboard/_components/stats-section.tsx +++ b/app/(pages)/dashboard/_components/stats-section.tsx @@ -18,7 +18,7 @@ export async function StatsSection({ userId }: { userId: string }) { {isEmpty && (
- +

Your library is empty

diff --git a/app/(pages)/explore/hero-banner.tsx b/app/(pages)/explore/hero-banner.tsx index 92ae30d..c619b82 100644 --- a/app/(pages)/explore/hero-banner.tsx +++ b/app/(pages)/explore/hero-banner.tsx @@ -68,7 +68,7 @@ export function HeroBanner({ {voteAverage > 0 && ( - + {voteAverage.toFixed(1)} )} @@ -88,7 +88,7 @@ export function HeroBanner({ href={href} className="mt-4 inline-flex h-9 items-center gap-2 rounded-lg bg-primary px-4 text-sm font-medium text-primary-foreground transition-all hover:shadow-md hover:shadow-primary/20" > - + Add to Library diff --git a/app/(pages)/explore/page.tsx b/app/(pages)/explore/page.tsx index 4996a13..7e5b341 100644 --- a/app/(pages)/explore/page.tsx +++ b/app/(pages)/explore/page.tsx @@ -66,19 +66,19 @@ export default async function ExplorePage() { } + icon={} items={trendingItems.slice(0, 20)} /> } + icon={} items={popularMovieItems.slice(0, 20)} /> } + icon={} items={popularTvItems.slice(0, 20)} /> diff --git a/app/(pages)/settings/_components/account-section.tsx b/app/(pages)/settings/_components/account-section.tsx index e4c0b07..f9dce0a 100644 --- a/app/(pages)/settings/_components/account-section.tsx +++ b/app/(pages)/settings/_components/account-section.tsx @@ -27,7 +27,7 @@ export function AccountSection({ return (
- +

Account

@@ -59,7 +59,7 @@ export function AccountSection({ router.refresh(); }} > - + Sign out diff --git a/app/(pages)/settings/_components/backup-section.tsx b/app/(pages)/settings/_components/backup-section.tsx index 43ba684..56ef56a 100644 --- a/app/(pages)/settings/_components/backup-section.tsx +++ b/app/(pages)/settings/_components/backup-section.tsx @@ -27,6 +27,11 @@ import { Button } from "@/components/ui/button"; import { CardContent, CardDescription, CardTitle } from "@/components/ui/card"; import { Spinner } from "@/components/ui/spinner"; import { Switch } from "@/components/ui/switch"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/components/ui/tooltip"; import type { BackupInfo } from "@/lib/services/backup"; import { createBackupAction, @@ -208,38 +213,50 @@ export function BackupSection({ )}
-
@@ -275,8 +261,7 @@ export function WebhookCard({ Setup instructions diff --git a/app/(pages)/settings/page.tsx b/app/(pages)/settings/page.tsx index af93689..1a11bbe 100644 --- a/app/(pages)/settings/page.tsx +++ b/app/(pages)/settings/page.tsx @@ -112,7 +112,7 @@ export default async function SettingsPage() { {isAdmin && (
- +

Server

diff --git a/app/(pages)/setup/page.tsx b/app/(pages)/setup/page.tsx index c7dee70..38bf302 100644 --- a/app/(pages)/setup/page.tsx +++ b/app/(pages)/setup/page.tsx @@ -24,7 +24,7 @@ const steps = [ className="inline-flex items-center gap-1 font-medium text-primary underline decoration-primary/30 underline-offset-2 transition-colors hover:decoration-primary" > themoviedb.org - +
{" "} and sign up for a free account. @@ -43,7 +43,7 @@ const steps = [ className="inline-flex items-center gap-1 font-medium text-primary underline decoration-primary/30 underline-offset-2 transition-colors hover:decoration-primary" > Settings → API - + {" "} and request an API key. Choose “Developer” when asked. You need the{" "} @@ -133,7 +133,7 @@ export default function SetupPage() { {/* Header */}
- + Setup required

@@ -188,12 +188,12 @@ export default function SetupPage() { > {copiedIdx === idx ? ( <> - + Copied ) : ( <> - + Copy )} @@ -217,7 +217,7 @@ export default function SetupPage() { {configured === true ? (
- +

diff --git a/app/(pages)/titles/[id]/_components/star-rating.tsx b/app/(pages)/titles/[id]/_components/star-rating.tsx index 1d36952..49a702c 100644 --- a/app/(pages)/titles/[id]/_components/star-rating.tsx +++ b/app/(pages)/titles/[id]/_components/star-rating.tsx @@ -40,9 +40,9 @@ export function StarRating({ value, onChange }: StarRatingProps) { }} > {filled ? ( - + ) : ( - + )} ); diff --git a/app/(pages)/titles/[id]/_components/status-button.tsx b/app/(pages)/titles/[id]/_components/status-button.tsx index a1814be..fced4c2 100644 --- a/app/(pages)/titles/[id]/_components/status-button.tsx +++ b/app/(pages)/titles/[id]/_components/status-button.tsx @@ -50,7 +50,7 @@ export function StatusButton({ currentStatus, onChange }: StatusButtonProps) { transition={{ duration: 0.15 }} className="inline-flex h-9 items-center gap-2 rounded-lg bg-primary/10 px-4 text-sm font-medium text-primary ring-1 ring-primary/20 transition-all hover:bg-primary/15 hover:ring-primary/30 active:scale-[0.97]" > - + Watchlist ) : ( @@ -66,14 +66,8 @@ export function StatusButton({ currentStatus, onChange }: StatusButtonProps) { className={`group inline-flex h-9 items-center gap-2 rounded-lg px-4 text-sm font-medium ring-1 transition-all active:scale-[0.97] ${config.class} ${config.bgClass} ${config.borderClass} hover:ring-destructive/30 hover:bg-destructive/10 hover:text-destructive`} > - - + + diff --git a/app/(pages)/titles/[id]/_components/title-actions.tsx b/app/(pages)/titles/[id]/_components/title-actions.tsx index 4497218..4f5d745 100644 --- a/app/(pages)/titles/[id]/_components/title-actions.tsx +++ b/app/(pages)/titles/[id]/_components/title-actions.tsx @@ -30,7 +30,7 @@ export function TitleActions() { onClick={handleWatchMovie} className="inline-flex h-9 items-center gap-2 rounded-lg bg-primary px-4 text-sm font-medium text-primary-foreground transition-all active:scale-[0.97] hover:shadow-md hover:shadow-primary/20" > - + Mark Watched )} diff --git a/app/(pages)/titles/[id]/_components/title-seasons.tsx b/app/(pages)/titles/[id]/_components/title-seasons.tsx index 1984525..1d881b6 100644 --- a/app/(pages)/titles/[id]/_components/title-seasons.tsx +++ b/app/(pages)/titles/[id]/_components/title-seasons.tsx @@ -56,7 +56,7 @@ export function TitleSeasons() { type="button" className="inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground transition-colors hover:bg-accent hover:text-foreground" > - + Mark All Watched } @@ -160,15 +160,9 @@ export function TitleSeasons() { )} {isOpen ? ( - + ) : ( - + )}

@@ -221,7 +215,7 @@ export function TitleSeasons() { damping: 15, }} > - + )} diff --git a/components/auth-form.tsx b/components/auth-form.tsx index c77ea04..240a2a6 100644 --- a/components/auth-form.tsx +++ b/components/auth-form.tsx @@ -97,7 +97,7 @@ export function AuthForm({ >
- +

{isRegister ? "Create your account" : "Welcome back"} @@ -124,7 +124,7 @@ export function AuthForm({ whileTap={{ scale: 0.98 }} className="inline-flex h-11 w-full items-center justify-center gap-2 rounded-lg border border-border/50 bg-background/50 text-sm font-medium transition-all hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-50" > - + {oidcLoading ? "Redirecting..." : `Sign in with ${authConfig?.oidcProviderName || "SSO"}`} diff --git a/components/command-palette.tsx b/components/command-palette.tsx index 7249611..30f602d 100644 --- a/components/command-palette.tsx +++ b/components/command-palette.tsx @@ -235,9 +235,9 @@ export function CommandPalette() {

{r.type === "movie" ? ( - + ) : ( - + )} {r.type} {r.releaseDate && ( @@ -273,10 +273,7 @@ export function CommandPalette() { onSelect={() => handleRecentSearch(q)} className="group" > - + {q} - + @@ -305,7 +302,7 @@ export function CommandPalette() { router.push("/dashboard"); }} > - + Go to Dashboard G H @@ -315,7 +312,7 @@ export function CommandPalette() { router.push("/explore"); }} > - + Go to Explore G E @@ -325,7 +322,7 @@ export function CommandPalette() { setHelpOpen(true); }} > - + Keyboard Shortcuts ? diff --git a/components/landing-page.tsx b/components/landing-page.tsx index 3ee3e6c..b5917d9 100644 --- a/components/landing-page.tsx +++ b/components/landing-page.tsx @@ -139,7 +139,7 @@ export function LandingPage({ posterUrls }: { posterUrls: string[] }) { delay: 0.1, }} > - + - +
{navLinks.map((link) => { @@ -61,14 +66,14 @@ export function NavBar() {
-
+
{/* Mobile search trigger */} {/* Desktop search trigger pill */} @@ -77,32 +82,34 @@ export function NavBar() { onClick={() => setCommandPaletteOpen(true)} className="hidden items-center gap-2 rounded-lg border border-border/50 bg-card/50 px-3 py-1.5 text-sm text-muted-foreground transition-all hover:border-primary/20 hover:bg-card sm:inline-flex" > - + Search... ⌘K -
- - {session?.user?.name} - - + + } + className="hidden items-center gap-1.5 rounded-md px-2 py-1.5 text-sm leading-none text-muted-foreground transition-colors hover:text-foreground sm:inline-flex" > - - - -
+ + + Log out +
diff --git a/components/sofa-logo.tsx b/components/sofa-logo.tsx index 7323349..0e0dde4 100644 --- a/components/sofa-logo.tsx +++ b/components/sofa-logo.tsx @@ -1,17 +1,9 @@ -export function SofaLogo({ - size = 24, - className, -}: { - size?: number; - className?: string; -}) { +export function SofaLogo({ className }: { className?: string }) { return ( diff --git a/components/title-card.tsx b/components/title-card.tsx index 2f3baa9..bd88dd1 100644 --- a/components/title-card.tsx +++ b/components/title-card.tsx @@ -69,11 +69,11 @@ export function TitleCard({

{title}

- + {year && {year}} {voteAverage != null && voteAverage > 0 && ( - + {voteAverage.toFixed(1)} )}