feat: enhance UI components with backdrop blur effects and improved background styles for better visual aesthetics
This commit is contained in:
@@ -27,13 +27,13 @@ export default function LanguageSelector() {
|
|||||||
<DropdownMenuContent align="end">
|
<DropdownMenuContent align="end">
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={() => handleLanguageChange("fr")}
|
onClick={() => handleLanguageChange("fr")}
|
||||||
className={i18n.language === "fr" ? "bg-accent" : ""}
|
className={i18n.language === "fr" ? "bg-accent/80 backdrop-blur-md" : ""}
|
||||||
>
|
>
|
||||||
{t("language.fr")}
|
{t("language.fr")}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={() => handleLanguageChange("en")}
|
onClick={() => handleLanguageChange("en")}
|
||||||
className={i18n.language === "en" ? "bg-accent" : ""}
|
className={i18n.language === "en" ? "bg-accent/80 backdrop-blur-md" : ""}
|
||||||
>
|
>
|
||||||
{t("language.en")}
|
{t("language.en")}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export function DeleteUserDialog({
|
|||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={handleDelete}
|
onClick={handleDelete}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
className="bg-destructive/90 backdrop-blur-md text-destructive-foreground hover:bg-destructive/80"
|
||||||
>
|
>
|
||||||
{isLoading ? "Suppression..." : "Supprimer"}
|
{isLoading ? "Suppression..." : "Supprimer"}
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export function LoginForm({ from }: LoginFormProps) {
|
|||||||
autoComplete="email"
|
autoComplete="email"
|
||||||
required
|
required
|
||||||
defaultValue="demo@stripstream.local"
|
defaultValue="demo@stripstream.local"
|
||||||
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-10 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -79,7 +79,7 @@ export function LoginForm({ from }: LoginFormProps) {
|
|||||||
autoComplete="current-password"
|
autoComplete="current-password"
|
||||||
required
|
required
|
||||||
defaultValue="fft$VSD96dis"
|
defaultValue="fft$VSD96dis"
|
||||||
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-10 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
@@ -105,7 +105,7 @@ export function LoginForm({ from }: LoginFormProps) {
|
|||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
className="bg-[#4F46E5] inline-flex w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
className="bg-[#4F46E5] inline-flex w-full items-center justify-center rounded-md bg-primary/90 backdrop-blur-md px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isLoading ? t("login.form.submit.loading.login") : t("login.form.submit.login")}
|
{isLoading ? t("login.form.submit.loading.login") : t("login.form.submit.login")}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export function RegisterForm({ from: _from }: RegisterFormProps) {
|
|||||||
type="email"
|
type="email"
|
||||||
autoComplete="email"
|
autoComplete="email"
|
||||||
required
|
required
|
||||||
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-10 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -116,7 +116,7 @@ export function RegisterForm({ from: _from }: RegisterFormProps) {
|
|||||||
type="password"
|
type="password"
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
required
|
required
|
||||||
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-10 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -132,14 +132,14 @@ export function RegisterForm({ from: _from }: RegisterFormProps) {
|
|||||||
type="password"
|
type="password"
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
required
|
required
|
||||||
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-10 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{error && <ErrorMessage errorCode={error.code} variant="form" />}
|
{error && <ErrorMessage errorCode={error.code} variant="form" />}
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
className="bg-[#4F46E5] inline-flex w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
className="bg-[#4F46E5] inline-flex w-full items-center justify-center rounded-md bg-primary/90 backdrop-blur-md px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isLoading ? t("login.form.submit.loading.register") : t("login.form.submit.register")}
|
{isLoading ? t("login.form.submit.loading.register") : t("login.form.submit.register")}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export function CompactModeButton({ onToggle }: CompactModeButtonProps) {
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
className="inline-flex items-center gap-2 px-2 py-1.5 text-sm font-medium rounded-lg hover:bg-accent hover:text-accent-foreground whitespace-nowrap"
|
className="inline-flex items-center gap-2 px-2 py-1.5 text-sm font-medium rounded-lg hover:bg-accent/80 hover:backdrop-blur-md hover:text-accent-foreground whitespace-nowrap"
|
||||||
title={isCompact ? t("series.filters.normal") : t("series.filters.compact")}
|
title={isCompact ? t("series.filters.normal") : t("series.filters.compact")}
|
||||||
>
|
>
|
||||||
{isCompact ? <LayoutTemplate className="h-4 w-4" /> : <LayoutGrid className="h-4 w-4" />}
|
{isCompact ? <LayoutTemplate className="h-4 w-4" /> : <LayoutGrid className="h-4 w-4" />}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function UnreadFilterButton({ showOnlyUnread, onToggle }: UnreadFilterBut
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
onClick={onToggle}
|
onClick={onToggle}
|
||||||
className="inline-flex items-center gap-2 px-2 py-1.5 text-sm font-medium rounded-lg hover:bg-accent hover:text-accent-foreground whitespace-nowrap"
|
className="inline-flex items-center gap-2 px-2 py-1.5 text-sm font-medium rounded-lg hover:bg-accent/80 hover:backdrop-blur-md hover:text-accent-foreground whitespace-nowrap"
|
||||||
title={showOnlyUnread ? t("series.filters.showAll") : t("series.filters.unread")}
|
title={showOnlyUnread ? t("series.filters.showAll") : t("series.filters.unread")}
|
||||||
>
|
>
|
||||||
<Filter className="h-4 w-4" />
|
<Filter className="h-4 w-4" />
|
||||||
|
|||||||
@@ -90,11 +90,11 @@ export function DebugInfo() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`fixed bottom-4 right-4 bg-zinc-900 border border-zinc-700 rounded-lg shadow-lg p-4 text-zinc-100 z-50 ${
|
className={`fixed bottom-4 right-4 bg-zinc-900/90 backdrop-blur-md border border-zinc-700 rounded-lg shadow-lg p-4 text-zinc-100 z-50 ${
|
||||||
isMinimized ? "w-auto" : "w-[800px] max-h-[50vh] overflow-auto"
|
isMinimized ? "w-auto" : "w-[800px] max-h-[50vh] overflow-auto"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between mb-4 sticky top-0 bg-zinc-900 pb-2">
|
<div className="flex items-center justify-between mb-4 sticky top-0 bg-zinc-900/90 backdrop-blur-md pb-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<h2 className="font-bold text-lg">{t("debug.title")}</h2>
|
<h2 className="font-bold text-lg">{t("debug.title")}</h2>
|
||||||
{!isMinimized && (
|
{!isMinimized && (
|
||||||
@@ -107,7 +107,7 @@ export function DebugInfo() {
|
|||||||
{!isMinimized && (
|
{!isMinimized && (
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowFilters(!showFilters)}
|
onClick={() => setShowFilters(!showFilters)}
|
||||||
className={`hover:bg-zinc-700 rounded-full p-1.5 ${showFilters ? "bg-zinc-700" : ""}`}
|
className={`hover:bg-zinc-700/80 hover:backdrop-blur-md rounded-full p-1.5 ${showFilters ? "bg-zinc-700/80 backdrop-blur-md" : ""}`}
|
||||||
aria-label="Filtres"
|
aria-label="Filtres"
|
||||||
>
|
>
|
||||||
<Filter className="h-5 w-5" />
|
<Filter className="h-5 w-5" />
|
||||||
@@ -115,7 +115,7 @@ export function DebugInfo() {
|
|||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={fetchLogs}
|
onClick={fetchLogs}
|
||||||
className="hover:bg-zinc-700 rounded-full p-1.5"
|
className="hover:bg-zinc-700/80 hover:backdrop-blur-md rounded-full p-1.5"
|
||||||
aria-label={t("debug.actions.refresh")}
|
aria-label={t("debug.actions.refresh")}
|
||||||
disabled={isRefreshing}
|
disabled={isRefreshing}
|
||||||
>
|
>
|
||||||
@@ -123,14 +123,14 @@ export function DebugInfo() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsMinimized(!isMinimized)}
|
onClick={() => setIsMinimized(!isMinimized)}
|
||||||
className="hover:bg-zinc-700 rounded-full p-1.5"
|
className="hover:bg-zinc-700/80 hover:backdrop-blur-md rounded-full p-1.5"
|
||||||
aria-label={t(isMinimized ? "debug.actions.maximize" : "debug.actions.minimize")}
|
aria-label={t(isMinimized ? "debug.actions.maximize" : "debug.actions.minimize")}
|
||||||
>
|
>
|
||||||
{isMinimized ? <Maximize2 className="h-5 w-5" /> : <Minimize2 className="h-5 w-5" />}
|
{isMinimized ? <Maximize2 className="h-5 w-5" /> : <Minimize2 className="h-5 w-5" />}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={clearLogs}
|
onClick={clearLogs}
|
||||||
className="hover:bg-zinc-700 rounded-full p-1.5"
|
className="hover:bg-zinc-700/80 hover:backdrop-blur-md rounded-full p-1.5"
|
||||||
aria-label={t("debug.actions.clear")}
|
aria-label={t("debug.actions.clear")}
|
||||||
>
|
>
|
||||||
<X className="h-5 w-5" />
|
<X className="h-5 w-5" />
|
||||||
@@ -139,7 +139,7 @@ export function DebugInfo() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isMinimized && showFilters && (
|
{!isMinimized && showFilters && (
|
||||||
<div className="mb-4 p-3 bg-zinc-800 rounded-lg">
|
<div className="mb-4 p-3 bg-zinc-800/80 backdrop-blur-md rounded-lg">
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{[
|
{[
|
||||||
{ key: "all", label: "Toutes", icon: Calendar },
|
{ key: "all", label: "Toutes", icon: Calendar },
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ function BookDownloadCard({ book, status, onDelete, onRetry }: BookDownloadCardP
|
|||||||
return (
|
return (
|
||||||
<Card className="p-4">
|
<Card className="p-4">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<div className="relative w-12 aspect-[2/3] bg-muted rounded overflow-hidden">
|
<div className="relative w-12 aspect-[2/3] bg-muted/80 backdrop-blur-md rounded overflow-hidden">
|
||||||
<Image
|
<Image
|
||||||
src={`/api/komga/images/books/${book.id}/thumbnail`}
|
src={`/api/komga/images/books/${book.id}/thumbnail`}
|
||||||
alt={t("books.coverAlt", { title: book.metadata?.title })}
|
alt={t("books.coverAlt", { title: book.metadata?.title })}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export function HeroSection({ series }: HeroSectionProps) {
|
|||||||
{series?.map((series) => (
|
{series?.map((series) => (
|
||||||
<div
|
<div
|
||||||
key={series.id}
|
key={series.id}
|
||||||
className="relative aspect-[2/3] bg-muted rounded-lg overflow-hidden"
|
className="relative aspect-[2/3] bg-muted/80 backdrop-blur-md rounded-lg overflow-hidden"
|
||||||
>
|
>
|
||||||
<SeriesCover
|
<SeriesCover
|
||||||
series={series as KomgaSeries}
|
series={series as KomgaSeries}
|
||||||
@@ -42,7 +42,7 @@ export function HeroSection({ series }: HeroSectionProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Overlay gradient */}
|
{/* Overlay gradient */}
|
||||||
<div className="absolute inset-0 bg-gradient-to-b from-background/50 to-background" />
|
<div className="absolute inset-0 bg-gradient-to-b from-background/70 to-background backdrop-blur-sm" />
|
||||||
|
|
||||||
{/* Contenu */}
|
{/* Contenu */}
|
||||||
<div className="relative h-full container flex flex-col items-center justify-center text-center space-y-2 sm:space-y-4">
|
<div className="relative h-full container flex flex-col items-center justify-center text-center space-y-2 sm:space-y-4">
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ function MediaCard({ item, onClick }: MediaCardProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className="flex-shrink-0 w-[200px] relative flex flex-col rounded-lg border bg-card text-card-foreground shadow-sm hover:bg-accent hover:text-accent-foreground transition-colors overflow-hidden cursor-pointer"
|
className="flex-shrink-0 w-[200px] relative flex flex-col rounded-lg border bg-card/70 backdrop-blur-md text-card-foreground shadow-sm hover:bg-accent/80 hover:backdrop-blur-md hover:text-accent-foreground transition-colors overflow-hidden cursor-pointer"
|
||||||
>
|
>
|
||||||
<div className="relative aspect-[2/3] bg-muted">
|
<div className="relative aspect-[2/3] bg-muted">
|
||||||
{isSeries ? (
|
{isSeries ? (
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export default function ClientLayout({ children, initialLibraries = [], initialF
|
|||||||
return (
|
return (
|
||||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||||
<DebugProvider>
|
<DebugProvider>
|
||||||
<div className="relative min-h-screen h-full" style={backgroundStyle}>
|
<div className="relative min-h-screen bg-background" style={backgroundStyle}>
|
||||||
{!isPublicRoute && <Header onToggleSidebar={handleToggleSidebar} />}
|
{!isPublicRoute && <Header onToggleSidebar={handleToggleSidebar} />}
|
||||||
{!isPublicRoute && (
|
{!isPublicRoute && (
|
||||||
<Sidebar
|
<Sidebar
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function Header({ onToggleSidebar }: HeaderProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="sticky top-0 z-50 w-full border-b border-border/40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 pt-safe">
|
<header className="sticky top-0 z-50 w-full border-b border-border/40 bg-background/70 backdrop-blur-md supports-[backdrop-filter]:bg-background/50 pt-safe">
|
||||||
<div className="container flex h-14 max-w-screen-2xl items-center">
|
<div className="container flex h-14 max-w-screen-2xl items-center">
|
||||||
<button
|
<button
|
||||||
onClick={onToggleSidebar}
|
onClick={onToggleSidebar}
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ export function Sidebar({ isOpen, onClose, initialLibraries, initialFavorites, u
|
|||||||
suppressHydrationWarning
|
suppressHydrationWarning
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed left-0 top-14 z-30 h-[calc(100vh-3.5rem)] w-64 border-r border-border/40",
|
"fixed left-0 top-14 z-30 h-[calc(100vh-3.5rem)] w-64 border-r border-border/40",
|
||||||
"bg-background/80 backdrop-blur-sm supports-[backdrop-filter]:bg-background/60",
|
"bg-background/70 backdrop-blur-md supports-[backdrop-filter]:bg-background/50",
|
||||||
"transition-transform duration-300 ease-in-out flex flex-col",
|
"transition-transform duration-300 ease-in-out flex flex-col",
|
||||||
isOpen ? "translate-x-0" : "-translate-x-full"
|
isOpen ? "translate-x-0" : "-translate-x-full"
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ export function PaginatedSeriesGrid({
|
|||||||
{/* Loading indicator */}
|
{/* Loading indicator */}
|
||||||
{isChangingPage && (
|
{isChangingPage && (
|
||||||
<div className="absolute inset-0 flex items-center justify-center bg-background/50 backdrop-blur-sm z-10">
|
<div className="absolute inset-0 flex items-center justify-center bg-background/50 backdrop-blur-sm z-10">
|
||||||
<div className="flex items-center gap-2 px-4 py-2 rounded-full bg-background border shadow-sm">
|
<div className="flex items-center gap-2 px-4 py-2 rounded-full bg-background/70 backdrop-blur-md border shadow-sm">
|
||||||
<Loader2 className="h-4 w-4 animate-spin" />
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
<span className="text-sm">{t("sidebar.libraries.loading")}</span>
|
<span className="text-sm">{t("sidebar.libraries.loading")}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -98,12 +98,12 @@ export function BookReader({ book, pages, onClose, nextBook }: BookReaderProps)
|
|||||||
<div className="relative h-full w-full flex items-center justify-center">
|
<div className="relative h-full w-full flex items-center justify-center">
|
||||||
{showEndMessage && (
|
{showEndMessage && (
|
||||||
<div className="absolute inset-0 flex items-center justify-center bg-background/80 backdrop-blur-sm z-50">
|
<div className="absolute inset-0 flex items-center justify-center bg-background/80 backdrop-blur-sm z-50">
|
||||||
<div className="bg-background border rounded-lg shadow-lg p-6 max-w-md text-center">
|
<div className="bg-background/80 backdrop-blur-md border rounded-lg shadow-lg p-6 max-w-md text-center">
|
||||||
<h3 className="text-lg font-semibold mb-2">{t("reader.endOfSeries")}</h3>
|
<h3 className="text-lg font-semibold mb-2">{t("reader.endOfSeries")}</h3>
|
||||||
<p className="text-muted-foreground mb-4">{t("reader.endOfSeriesMessage")}</p>
|
<p className="text-muted-foreground mb-4">{t("reader.endOfSeriesMessage")}</p>
|
||||||
<button
|
<button
|
||||||
onClick={() => onClose?.(currentPage)}
|
onClick={() => onClose?.(currentPage)}
|
||||||
className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors"
|
className="px-4 py-2 bg-primary/90 backdrop-blur-md text-primary-foreground rounded-md hover:bg-primary/80 transition-colors"
|
||||||
>
|
>
|
||||||
{t("reader.backToSeries")}
|
{t("reader.backToSeries")}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const ControlButtons = ({
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onToggleDoublePage();
|
onToggleDoublePage();
|
||||||
}}
|
}}
|
||||||
className="p-2 rounded-full bg-background/50 hover:bg-background/80 transition-colors"
|
className="p-2 rounded-full bg-background/70 backdrop-blur-md hover:bg-background/80 transition-colors"
|
||||||
aria-label={t(
|
aria-label={t(
|
||||||
isDoublePage
|
isDoublePage
|
||||||
? "reader.controls.doublePage.disable"
|
? "reader.controls.doublePage.disable"
|
||||||
@@ -71,7 +71,7 @@ export const ControlButtons = ({
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onToggleDirection();
|
onToggleDirection();
|
||||||
}}
|
}}
|
||||||
className="p-2 rounded-full bg-background/50 hover:bg-background/80 transition-colors"
|
className="p-2 rounded-full bg-background/70 backdrop-blur-md hover:bg-background/80 transition-colors"
|
||||||
aria-label={t("reader.controls.direction.current", {
|
aria-label={t("reader.controls.direction.current", {
|
||||||
direction: t(
|
direction: t(
|
||||||
direction === "ltr"
|
direction === "ltr"
|
||||||
@@ -91,7 +91,7 @@ export const ControlButtons = ({
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onToggleFullscreen();
|
onToggleFullscreen();
|
||||||
}}
|
}}
|
||||||
className="p-2 rounded-full bg-background/50 hover:bg-background/80 transition-colors"
|
className="p-2 rounded-full bg-background/70 backdrop-blur-md hover:bg-background/80 transition-colors"
|
||||||
aria-label={t(
|
aria-label={t(
|
||||||
isFullscreen ? "reader.controls.fullscreen.exit" : "reader.controls.fullscreen.enter"
|
isFullscreen ? "reader.controls.fullscreen.exit" : "reader.controls.fullscreen.enter"
|
||||||
)}
|
)}
|
||||||
@@ -104,7 +104,7 @@ export const ControlButtons = ({
|
|||||||
onToggleThumbnails();
|
onToggleThumbnails();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"p-2 rounded-full bg-background/50 hover:bg-background/80 transition-colors",
|
"p-2 rounded-full bg-background/70 backdrop-blur-md hover:bg-background/80 transition-colors",
|
||||||
showThumbnails && "ring-2 ring-primary"
|
showThumbnails && "ring-2 ring-primary"
|
||||||
)}
|
)}
|
||||||
aria-label={t(
|
aria-label={t(
|
||||||
@@ -113,7 +113,7 @@ export const ControlButtons = ({
|
|||||||
>
|
>
|
||||||
<Images className="h-6 w-6" />
|
<Images className="h-6 w-6" />
|
||||||
</button>
|
</button>
|
||||||
<div className="p-2 rounded-full bg-background/50" onClick={(e) => e.stopPropagation()}>
|
<div className="p-2 rounded-full bg-background/70 backdrop-blur-md" onClick={(e) => e.stopPropagation()}>
|
||||||
<PageInput
|
<PageInput
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
totalPages={totalPages}
|
totalPages={totalPages}
|
||||||
@@ -133,7 +133,7 @@ export const ControlButtons = ({
|
|||||||
onClose(currentPage);
|
onClose(currentPage);
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"absolute top-4 right-4 p-2 rounded-full bg-background/50 hover:bg-background/80 transition-all duration-300 z-30",
|
"absolute top-4 right-4 p-2 rounded-full bg-background/70 backdrop-blur-md hover:bg-background/80 transition-all duration-300 z-30",
|
||||||
showControls ? "opacity-100" : "opacity-0 pointer-events-none"
|
showControls ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||||
)}
|
)}
|
||||||
aria-label={t("reader.controls.close")}
|
aria-label={t("reader.controls.close")}
|
||||||
@@ -150,7 +150,7 @@ export const ControlButtons = ({
|
|||||||
onPreviousPage();
|
onPreviousPage();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"absolute top-1/2 -translate-y-1/2 p-2 rounded-full bg-background/50 hover:bg-background/80 transition-all duration-300 z-20",
|
"absolute top-1/2 -translate-y-1/2 p-2 rounded-full bg-background/70 backdrop-blur-md hover:bg-background/80 transition-all duration-300 z-20",
|
||||||
direction === "rtl" ? "right-4" : "left-4",
|
direction === "rtl" ? "right-4" : "left-4",
|
||||||
showControls ? "opacity-100" : "opacity-0 pointer-events-none"
|
showControls ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||||
)}
|
)}
|
||||||
@@ -168,7 +168,7 @@ export const ControlButtons = ({
|
|||||||
onNextPage();
|
onNextPage();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"absolute top-1/2 -translate-y-1/2 p-2 rounded-full bg-background/50 hover:bg-background/80 transition-all duration-300 z-20",
|
"absolute top-1/2 -translate-y-1/2 p-2 rounded-full bg-background/70 backdrop-blur-md hover:bg-background/80 transition-all duration-300 z-20",
|
||||||
direction === "rtl" ? "left-4" : "right-4",
|
direction === "rtl" ? "left-4" : "right-4",
|
||||||
showControls ? "opacity-100" : "opacity-0 pointer-events-none"
|
showControls ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export const NavigationBar = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"absolute bottom-0 left-0 right-0 bg-background/50 backdrop-blur-sm border-t border-border/40 transition-all duration-300 ease-in-out z-30",
|
"absolute bottom-0 left-0 right-0 bg-background/70 backdrop-blur-md border-t border-border/40 transition-all duration-300 ease-in-out z-30",
|
||||||
showThumbnails ? "h-52 opacity-100" : "h-0 opacity-0"
|
showThumbnails ? "h-52 opacity-100" : "h-0 opacity-0"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -90,7 +90,7 @@ export const NavigationBar = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{showControls && (
|
{showControls && (
|
||||||
<div className="absolute top-0 left-1/2 -translate-x-1/2 -translate-y-full px-4 py-2 rounded-full bg-background/50 text-sm">
|
<div className="absolute top-0 left-1/2 -translate-x-1/2 -translate-y-full px-4 py-2 rounded-full bg-background/70 backdrop-blur-md text-sm">
|
||||||
Page {currentPage} / {pages.length}
|
Page {currentPage} / {pages.length}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export const PageInput = ({ currentPage, totalPages, onPageChange }: PageInputPr
|
|||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-12 bg-background/50 text-center rounded-md py-1 px-2",
|
"w-12 bg-background/70 backdrop-blur-md text-center rounded-md py-1 px-2",
|
||||||
"focus:outline-none focus:ring-2 focus:ring-primary",
|
"focus:outline-none focus:ring-2 focus:ring-primary",
|
||||||
"text-sm text-foreground"
|
"text-sm text-foreground"
|
||||||
)}
|
)}
|
||||||
@@ -80,7 +80,7 @@ export const PageInput = ({ currentPage, totalPages, onPageChange }: PageInputPr
|
|||||||
<button
|
<button
|
||||||
onClick={handleGoToPage}
|
onClick={handleGoToPage}
|
||||||
data-action="goto"
|
data-action="goto"
|
||||||
className="p-1 rounded-md bg-background/50 hover:bg-background/80 transition-colors"
|
className="p-1 rounded-md bg-background/70 backdrop-blur-md hover:bg-background/80 transition-colors"
|
||||||
aria-label="Aller à cette page"
|
aria-label="Aller à cette page"
|
||||||
>
|
>
|
||||||
<ArrowRight className="h-4 w-4" />
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ export function PaginatedBookGrid({
|
|||||||
{/* Loading indicator */}
|
{/* Loading indicator */}
|
||||||
{isChangingPage && (
|
{isChangingPage && (
|
||||||
<div className="absolute inset-0 flex items-center justify-center bg-background/50 backdrop-blur-sm z-10">
|
<div className="absolute inset-0 flex items-center justify-center bg-background/50 backdrop-blur-sm z-10">
|
||||||
<div className="flex items-center gap-2 px-4 py-2 rounded-full bg-background border shadow-sm">
|
<div className="flex items-center gap-2 px-4 py-2 rounded-full bg-background/70 backdrop-blur-md border shadow-sm">
|
||||||
<Loader2 className="h-4 w-4 animate-spin" />
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
<span className="text-sm">{t("books.loading")}</span>
|
<span className="text-sm">{t("books.loading")}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ export const SeriesHeader = ({ series, refreshSeries }: SeriesHeaderProps) => {
|
|||||||
<div className="relative container mx-auto px-4 py-8">
|
<div className="relative container mx-auto px-4 py-8">
|
||||||
<div className="flex flex-col md:flex-row gap-6 items-center md:items-start w-full">
|
<div className="flex flex-col md:flex-row gap-6 items-center md:items-start w-full">
|
||||||
{/* Image principale */}
|
{/* Image principale */}
|
||||||
<div className="relative w-[180px] aspect-[2/3] rounded-lg overflow-hidden shadow-lg bg-muted flex-shrink-0">
|
<div className="relative w-[180px] aspect-[2/3] rounded-lg overflow-hidden shadow-lg bg-muted/80 backdrop-blur-md flex-shrink-0">
|
||||||
<SeriesCover
|
<SeriesCover
|
||||||
series={series as KomgaSeries}
|
series={series as KomgaSeries}
|
||||||
alt={t("series.header.coverAlt", { title: series.metadata.title })}
|
alt={t("series.header.coverAlt", { title: series.metadata.title })}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export function BackgroundSettings() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border bg-card text-card-foreground shadow-sm">
|
<div className="rounded-lg border bg-card/70 backdrop-blur-md text-card-foreground shadow-sm">
|
||||||
<div className="p-5 space-y-6">
|
<div className="p-5 space-y-6">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-xl font-semibold flex items-center gap-2">
|
<h2 className="text-xl font-semibold flex items-center gap-2">
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export function CacheSettings({ initialTTLConfig }: CacheSettingsProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border bg-card text-card-foreground shadow-sm">
|
<div className="rounded-lg border bg-card/70 backdrop-blur-md text-card-foreground shadow-sm">
|
||||||
<div className="p-5 space-y-4">
|
<div className="p-5 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-xl font-semibold flex items-center gap-2">
|
<h2 className="text-xl font-semibold flex items-center gap-2">
|
||||||
@@ -205,7 +205,7 @@ export function CacheSettings({ initialTTLConfig }: CacheSettingsProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Informations sur la taille du cache */}
|
{/* Informations sur la taille du cache */}
|
||||||
<div className="rounded-md border bg-muted/50 p-4 space-y-3">
|
<div className="rounded-md border bg-muted/50 backdrop-blur-md p-4 space-y-3">
|
||||||
<div className="flex items-center gap-2 font-medium">
|
<div className="flex items-center gap-2 font-medium">
|
||||||
<HardDrive className="h-4 w-4" />
|
<HardDrive className="h-4 w-4" />
|
||||||
{t("settings.cache.size.title")}
|
{t("settings.cache.size.title")}
|
||||||
@@ -255,7 +255,7 @@ export function CacheSettings({ initialTTLConfig }: CacheSettingsProps) {
|
|||||||
min="1"
|
min="1"
|
||||||
value={ttlConfig.defaultTTL}
|
value={ttlConfig.defaultTTL}
|
||||||
onChange={handleTTLChange}
|
onChange={handleTTLChange}
|
||||||
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-9 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -269,7 +269,7 @@ export function CacheSettings({ initialTTLConfig }: CacheSettingsProps) {
|
|||||||
min="1"
|
min="1"
|
||||||
value={ttlConfig.homeTTL}
|
value={ttlConfig.homeTTL}
|
||||||
onChange={handleTTLChange}
|
onChange={handleTTLChange}
|
||||||
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-9 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -283,7 +283,7 @@ export function CacheSettings({ initialTTLConfig }: CacheSettingsProps) {
|
|||||||
min="1"
|
min="1"
|
||||||
value={ttlConfig.librariesTTL}
|
value={ttlConfig.librariesTTL}
|
||||||
onChange={handleTTLChange}
|
onChange={handleTTLChange}
|
||||||
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-9 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -297,7 +297,7 @@ export function CacheSettings({ initialTTLConfig }: CacheSettingsProps) {
|
|||||||
min="1"
|
min="1"
|
||||||
value={ttlConfig.seriesTTL}
|
value={ttlConfig.seriesTTL}
|
||||||
onChange={handleTTLChange}
|
onChange={handleTTLChange}
|
||||||
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-9 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -311,7 +311,7 @@ export function CacheSettings({ initialTTLConfig }: CacheSettingsProps) {
|
|||||||
min="1"
|
min="1"
|
||||||
value={ttlConfig.booksTTL}
|
value={ttlConfig.booksTTL}
|
||||||
onChange={handleTTLChange}
|
onChange={handleTTLChange}
|
||||||
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-9 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -325,14 +325,14 @@ export function CacheSettings({ initialTTLConfig }: CacheSettingsProps) {
|
|||||||
min="1"
|
min="1"
|
||||||
value={ttlConfig.imagesTTL}
|
value={ttlConfig.imagesTTL}
|
||||||
onChange={handleTTLChange}
|
onChange={handleTTLChange}
|
||||||
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-9 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="flex-1 inline-flex items-center justify-center rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
className="flex-1 inline-flex items-center justify-center rounded-md bg-primary/90 backdrop-blur-md px-3 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{t("settings.cache.buttons.saveTTL")}
|
{t("settings.cache.buttons.saveTTL")}
|
||||||
</button>
|
</button>
|
||||||
@@ -340,7 +340,7 @@ export function CacheSettings({ initialTTLConfig }: CacheSettingsProps) {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={handleClearCache}
|
onClick={handleClearCache}
|
||||||
disabled={isCacheClearing}
|
disabled={isCacheClearing}
|
||||||
className="flex-1 inline-flex items-center justify-center rounded-md bg-destructive px-3 py-2 text-sm font-medium text-destructive-foreground ring-offset-background transition-colors hover:bg-destructive/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
className="flex-1 inline-flex items-center justify-center rounded-md bg-destructive/90 backdrop-blur-md px-3 py-2 text-sm font-medium text-destructive-foreground ring-offset-background transition-colors hover:bg-destructive/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isCacheClearing ? (
|
{isCacheClearing ? (
|
||||||
<>
|
<>
|
||||||
@@ -357,7 +357,7 @@ export function CacheSettings({ initialTTLConfig }: CacheSettingsProps) {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={handleClearServiceWorkerCache}
|
onClick={handleClearServiceWorkerCache}
|
||||||
disabled={isServiceWorkerClearing}
|
disabled={isServiceWorkerClearing}
|
||||||
className="flex-1 inline-flex items-center justify-center rounded-md bg-destructive px-3 py-2 text-sm font-medium text-destructive-foreground ring-offset-background transition-colors hover:bg-destructive/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
className="flex-1 inline-flex items-center justify-center rounded-md bg-destructive/90 backdrop-blur-md px-3 py-2 text-sm font-medium text-destructive-foreground ring-offset-background transition-colors hover:bg-destructive/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isServiceWorkerClearing ? (
|
{isServiceWorkerClearing ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export function DisplaySettings() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border bg-card text-card-foreground shadow-sm">
|
<div className="rounded-lg border bg-card/70 backdrop-blur-md text-card-foreground shadow-sm">
|
||||||
<div className="p-5 space-y-4">
|
<div className="p-5 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-xl font-semibold flex items-center gap-2">
|
<h2 className="text-xl font-semibold flex items-center gap-2">
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ export function KomgaSettings({ initialConfig }: KomgaSettingsProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-lg border bg-card text-card-foreground shadow-sm">
|
<div className="rounded-lg border bg-card/70 backdrop-blur-md text-card-foreground shadow-sm">
|
||||||
<div className="p-5 space-y-4">
|
<div className="p-5 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-xl font-semibold flex items-center gap-2">
|
<h2 className="text-xl font-semibold flex items-center gap-2">
|
||||||
@@ -173,7 +173,7 @@ export function KomgaSettings({ initialConfig }: KomgaSettingsProps) {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setIsEditingConfig(true)}
|
onClick={() => setIsEditingConfig(true)}
|
||||||
className="inline-flex items-center justify-center rounded-md bg-secondary px-3 py-2 text-sm font-medium text-secondary-foreground ring-offset-background transition-colors hover:bg-secondary/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
className="inline-flex items-center justify-center rounded-md bg-secondary/80 backdrop-blur-md px-3 py-2 text-sm font-medium text-secondary-foreground ring-offset-background transition-colors hover:bg-secondary/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
||||||
>
|
>
|
||||||
{t("settings.komga.buttons.edit")}
|
{t("settings.komga.buttons.edit")}
|
||||||
</button>
|
</button>
|
||||||
@@ -192,7 +192,7 @@ export function KomgaSettings({ initialConfig }: KomgaSettingsProps) {
|
|||||||
required
|
required
|
||||||
value={config.serverUrl}
|
value={config.serverUrl}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-9 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -206,7 +206,7 @@ export function KomgaSettings({ initialConfig }: KomgaSettingsProps) {
|
|||||||
required
|
required
|
||||||
value={config.username}
|
value={config.username}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-9 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -220,7 +220,7 @@ export function KomgaSettings({ initialConfig }: KomgaSettingsProps) {
|
|||||||
required
|
required
|
||||||
value={config.password}
|
value={config.password}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-9 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -228,7 +228,7 @@ export function KomgaSettings({ initialConfig }: KomgaSettingsProps) {
|
|||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className="flex-1 inline-flex items-center justify-center rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
className="flex-1 inline-flex items-center justify-center rounded-md bg-primary/90 backdrop-blur-md px-3 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isSaving ? (
|
{isSaving ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
export function BookSkeleton() {
|
export function BookSkeleton() {
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-background flex items-center justify-center">
|
<div className="fixed inset-0 bg-background/80 backdrop-blur-md flex items-center justify-center">
|
||||||
<div className="w-full h-full max-w-6xl mx-auto flex flex-col items-center justify-center space-y-4">
|
<div className="w-full h-full max-w-6xl mx-auto flex flex-col items-center justify-center space-y-4">
|
||||||
{/* Barre de navigation */}
|
{/* Barre de navigation */}
|
||||||
<div className="w-full h-12 bg-muted rounded animate-pulse" />
|
<div className="w-full h-12 bg-muted/80 backdrop-blur-md rounded animate-pulse" />
|
||||||
|
|
||||||
{/* Page du livre */}
|
{/* Page du livre */}
|
||||||
<div className="w-full flex-1 bg-muted rounded animate-pulse" />
|
<div className="w-full flex-1 bg-muted/80 backdrop-blur-md rounded animate-pulse" />
|
||||||
|
|
||||||
{/* Barre de contrôles */}
|
{/* Barre de contrôles */}
|
||||||
<div className="w-full h-16 bg-muted rounded animate-pulse" />
|
<div className="w-full h-16 bg-muted/80 backdrop-blur-md rounded animate-pulse" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const ErrorMessage = ({
|
|||||||
<div
|
<div
|
||||||
role="alert"
|
role="alert"
|
||||||
aria-live="assertive"
|
aria-live="assertive"
|
||||||
className="relative overflow-hidden rounded-lg border border-destructive/50 bg-background p-6 shadow-lg dark:border-destructive/30 dark:bg-destructive/5"
|
className="relative overflow-hidden rounded-lg border border-destructive/50 bg-background/80 backdrop-blur-md p-6 shadow-lg dark:border-destructive/30 dark:bg-destructive/5"
|
||||||
>
|
>
|
||||||
<div className="absolute inset-0 bg-destructive/5 dark:bg-gradient-to-b dark:from-destructive/10 dark:to-destructive/5" />
|
<div className="absolute inset-0 bg-destructive/5 dark:bg-gradient-to-b dark:from-destructive/10 dark:to-destructive/5" />
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export function InstallPWA() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed bottom-4 left-4 right-4 sm:left-auto sm:right-4 z-50">
|
<div className="fixed bottom-4 left-4 right-4 sm:left-auto sm:right-4 z-50">
|
||||||
<div className="bg-card border shadow-lg rounded-lg p-4 max-w-sm mx-auto sm:mx-0">
|
<div className="bg-card/80 backdrop-blur-md border shadow-lg rounded-lg p-4 max-w-sm mx-auto sm:mx-0">
|
||||||
<div className="flex items-start gap-4">
|
<div className="flex items-start gap-4">
|
||||||
<Download className="h-6 w-6 flex-shrink-0 text-primary" />
|
<Download className="h-6 w-6 flex-shrink-0 text-primary" />
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
@@ -120,7 +120,7 @@ export function InstallPWA() {
|
|||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
onClick={handleInstallClick}
|
onClick={handleInstallClick}
|
||||||
className="w-full bg-primary text-primary-foreground px-4 py-2 rounded-md hover:bg-primary/90 transition-colors"
|
className="w-full bg-primary/90 backdrop-blur-md text-primary-foreground px-4 py-2 rounded-md hover:bg-primary/80 transition-colors"
|
||||||
>
|
>
|
||||||
Installer l'application
|
Installer l'application
|
||||||
</button>
|
</button>
|
||||||
@@ -128,7 +128,7 @@ export function InstallPWA() {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={handleDismiss}
|
onClick={handleDismiss}
|
||||||
className="p-1 hover:bg-accent hover:text-accent-foreground rounded-md transition-colors"
|
className="p-1 hover:bg-accent/80 hover:backdrop-blur-md hover:text-accent-foreground rounded-md transition-colors"
|
||||||
aria-label="Fermer"
|
aria-label="Fermer"
|
||||||
>
|
>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export function NetworkStatus() {
|
|||||||
if (isOnline) return null;
|
if (isOnline) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed bottom-4 left-4 z-[100] flex items-center gap-2 rounded-lg bg-destructive px-4 py-2 text-sm text-destructive-foreground shadow-lg">
|
<div className="fixed bottom-4 left-4 z-[100] flex items-center gap-2 rounded-lg bg-destructive/90 backdrop-blur-md px-4 py-2 text-sm text-destructive-foreground shadow-lg">
|
||||||
<WifiOff className="h-4 w-4" />
|
<WifiOff className="h-4 w-4" />
|
||||||
<span>Hors ligne</span>
|
<span>Hors ligne</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export function Pagination({ currentPage, totalPages, onPageChange, className }:
|
|||||||
<button
|
<button
|
||||||
onClick={() => onPageChange(currentPage - 1)}
|
onClick={() => onPageChange(currentPage - 1)}
|
||||||
disabled={currentPage === 1}
|
disabled={currentPage === 1}
|
||||||
className="inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 gap-1 hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50"
|
className="inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 gap-1 hover:bg-accent/80 hover:backdrop-blur-md hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50"
|
||||||
aria-label="Page précédente"
|
aria-label="Page précédente"
|
||||||
>
|
>
|
||||||
<ChevronLeft className="h-4 w-4" />
|
<ChevronLeft className="h-4 w-4" />
|
||||||
@@ -87,8 +87,8 @@ export function Pagination({ currentPage, totalPages, onPageChange, className }:
|
|||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex items-center justify-center rounded-md text-sm font-medium h-10 w-10",
|
"inline-flex items-center justify-center rounded-md text-sm font-medium h-10 w-10",
|
||||||
page === currentPage
|
page === currentPage
|
||||||
? "bg-primary text-primary-foreground"
|
? "bg-primary/90 backdrop-blur-md text-primary-foreground"
|
||||||
: "hover:bg-accent hover:text-accent-foreground"
|
: "hover:bg-accent/80 hover:backdrop-blur-md hover:text-accent-foreground"
|
||||||
)}
|
)}
|
||||||
aria-label={`Page ${page}`}
|
aria-label={`Page ${page}`}
|
||||||
aria-current={page === currentPage ? "page" : undefined}
|
aria-current={page === currentPage ? "page" : undefined}
|
||||||
@@ -103,7 +103,7 @@ export function Pagination({ currentPage, totalPages, onPageChange, className }:
|
|||||||
<button
|
<button
|
||||||
onClick={() => onPageChange(currentPage + 1)}
|
onClick={() => onPageChange(currentPage + 1)}
|
||||||
disabled={currentPage === totalPages}
|
disabled={currentPage === totalPages}
|
||||||
className="inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 gap-1 hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50"
|
className="inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 gap-1 hover:bg-accent/80 hover:backdrop-blur-md hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50"
|
||||||
aria-label="Page suivante"
|
aria-label="Page suivante"
|
||||||
>
|
>
|
||||||
<span className="sr-only md:not-sr-only">Suivant</span>
|
<span className="sr-only md:not-sr-only">Suivant</span>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const AlertDialogContent = React.forwardRef<
|
|||||||
<AlertDialogPrimitive.Content
|
<AlertDialogPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background/80 backdrop-blur-md p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ const badgeVariants = cva(
|
|||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default:
|
default:
|
||||||
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
"border-transparent bg-primary/90 backdrop-blur-md text-primary-foreground hover:bg-primary/70",
|
||||||
secondary:
|
secondary:
|
||||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
"border-transparent bg-secondary/80 backdrop-blur-md text-secondary-foreground hover:bg-secondary/70",
|
||||||
destructive:
|
destructive:
|
||||||
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
"border-transparent bg-destructive/90 backdrop-blur-md text-destructive-foreground hover:bg-destructive/70",
|
||||||
outline: "text-foreground",
|
outline: "text-foreground",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ const buttonVariants = cva(
|
|||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
default: "bg-primary/90 backdrop-blur-md text-primary-foreground hover:bg-primary/80",
|
||||||
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
destructive: "bg-destructive/90 backdrop-blur-md text-destructive-foreground hover:bg-destructive/80",
|
||||||
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
outline: "border border-input bg-background/70 backdrop-blur-md hover:bg-accent/80 hover:text-accent-foreground",
|
||||||
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
secondary: "bg-secondary/80 backdrop-blur-md text-secondary-foreground hover:bg-secondary/70",
|
||||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
ghost: "hover:bg-accent/80 hover:backdrop-blur-md hover:text-accent-foreground",
|
||||||
link: "text-primary underline-offset-4 hover:underline",
|
link: "text-primary underline-offset-4 hover:underline",
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElemen
|
|||||||
({ className, ...props }, ref) => (
|
({ className, ...props }, ref) => (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)}
|
className={cn("rounded-lg border bg-card/70 backdrop-blur-md text-card-foreground shadow-sm", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export const CoverClient = ({
|
|||||||
|
|
||||||
if (imageError) {
|
if (imageError) {
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full flex items-center justify-center bg-muted rounded-lg">
|
<div className="w-full h-full flex items-center justify-center bg-muted/80 backdrop-blur-md rounded-lg">
|
||||||
<ImageOff className="w-12 h-12 text-muted-foreground" />
|
<ImageOff className="w-12 h-12 text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const DialogContent = React.forwardRef<
|
|||||||
<DialogPrimitive.Content
|
<DialogPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background/80 backdrop-blur-md p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const DropdownMenuSubContent = React.forwardRef<
|
|||||||
<DropdownMenuPrimitive.SubContent
|
<DropdownMenuPrimitive.SubContent
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover/80 backdrop-blur-md p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -63,7 +63,7 @@ const DropdownMenuContent = React.forwardRef<
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover/80 backdrop-blur-md p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
"flex h-10 w-full rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export function ProgressBar({ progress, total, type }: ProgressBarProps) {
|
|||||||
? "bg-gradient-to-r from-purple-500 to-pink-500"
|
? "bg-gradient-to-r from-purple-500 to-pink-500"
|
||||||
: "bg-gradient-to-r from-blue-500 to-cyan-500";
|
: "bg-gradient-to-r from-blue-500 to-cyan-500";
|
||||||
return (
|
return (
|
||||||
<div className="absolute bottom-0 left-0 right-0 px-3 py-2 bg-black/50 backdrop-blur-sm border-t border-white/10">
|
<div className="absolute bottom-0 left-0 right-0 px-3 py-2 bg-black/70 backdrop-blur-md border-t border-white/10">
|
||||||
<div className="h-2 bg-white/30 rounded-full overflow-hidden">
|
<div className="h-2 bg-white/30 rounded-full overflow-hidden">
|
||||||
<div
|
<div
|
||||||
className={`h-full transition-all duration-300 ${barColor}`}
|
className={`h-full transition-all duration-300 ${barColor}`}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const Progress = React.forwardRef<
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ProgressPrimitive.Indicator
|
<ProgressPrimitive.Indicator
|
||||||
className="h-full w-full flex-1 bg-primary transition-all"
|
className="h-full w-full flex-1 bg-primary/90 backdrop-blur-md transition-all"
|
||||||
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
||||||
/>
|
/>
|
||||||
</ProgressPrimitive.Root>
|
</ProgressPrimitive.Root>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
|
|||||||
<SelectPrimitive.Trigger
|
<SelectPrimitive.Trigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background/70 backdrop-blur-md px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -40,7 +40,7 @@ const SelectContent = React.forwardRef<
|
|||||||
<SelectPrimitive.Content
|
<SelectPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover/80 backdrop-blur-md text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
position === "popper" &&
|
position === "popper" &&
|
||||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||||
className
|
className
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const TableFooter = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<tfoot
|
<tfoot
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className)}
|
className={cn("border-t bg-muted/50 backdrop-blur-md font-medium [&>tr]:last:border-b-0", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
@@ -48,7 +48,7 @@ const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTML
|
|||||||
<tr
|
<tr
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
"border-b transition-colors hover:bg-muted/50 hover:backdrop-blur-md data-[state=selected]:bg-muted/80 data-[state=selected]:backdrop-blur-md",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ const TabsList = React.forwardRef<HTMLDivElement, TabsListProps>(({ className, .
|
|||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
|
"inline-flex h-10 items-center justify-center rounded-md bg-muted/80 backdrop-blur-md p-1 text-muted-foreground",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -87,7 +87,7 @@ const TabsTrigger = React.forwardRef<HTMLButtonElement, TabsTriggerProps>(
|
|||||||
aria-selected={isSelected}
|
aria-selected={isSelected}
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
isSelected && "bg-background text-foreground shadow-sm",
|
isSelected && "bg-background/90 backdrop-blur-md text-foreground shadow-sm",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
onClick={() => onValueChange(value)}
|
onClick={() => onValueChange(value)}
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ const toastVariants = cva(
|
|||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: "border border-border/40 bg-background/60 text-foreground shadow-lg",
|
default: "border border-border/40 bg-background/70 backdrop-blur-md text-foreground shadow-lg",
|
||||||
destructive:
|
destructive:
|
||||||
"destructive group border-destructive/20 bg-destructive/60 text-destructive-foreground font-medium",
|
"destructive group border-destructive/20 bg-destructive/70 backdrop-blur-md text-destructive-foreground font-medium",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ body {
|
|||||||
@apply border-border;
|
@apply border-border;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground;
|
@apply text-foreground;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,4 +105,15 @@ body {
|
|||||||
.pt-safe {
|
.pt-safe {
|
||||||
padding-top: env(safe-area-inset-top, 0);
|
padding-top: env(safe-area-inset-top, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Glassmorphism utilities */
|
||||||
|
.glass {
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.glass-strong {
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
-webkit-backdrop-filter: blur(16px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user