chore: update various components and services for improved functionality and consistency, including formatting adjustments and minor refactors

This commit is contained in:
Julien Froidefond
2025-12-07 09:54:05 +01:00
parent 4f5724c0ff
commit 39e3328123
141 changed files with 5292 additions and 3243 deletions

View File

@@ -13,9 +13,9 @@ interface ErrorMessageProps {
retryLabel?: string;
}
export const ErrorMessage = ({
errorCode,
error,
export const ErrorMessage = ({
errorCode,
error,
variant = "default",
onRetry,
retryLabel,
@@ -37,12 +37,7 @@ export const ErrorMessage = ({
<AlertCircle className="h-4 w-4" />
<p>{message}</p>
{onRetry && (
<Button
onClick={onRetry}
variant="ghost"
size="sm"
className="ml-auto"
>
<Button onClick={onRetry} variant="ghost" size="sm" className="ml-auto">
<RefreshCw className="h-3 w-3" />
</Button>
)}
@@ -68,11 +63,11 @@ export const ErrorMessage = ({
{t("errors.GENERIC_ERROR")}
</h3>
<p className="text-sm text-destructive/90 dark:text-red-300/90">{message}</p>
{onRetry && (
<Button
<Button
onClick={onRetry}
variant="outline"
variant="outline"
size="sm"
className="mt-4 border-destructive/30 hover:bg-destructive/10"
>

View File

@@ -24,13 +24,10 @@ const badgeVariants = cva(
);
export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}
function Badge({ className, variant, ...props }: BadgeProps) {
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
);
return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
}
export { Badge, badgeVariants };

View File

@@ -138,8 +138,8 @@ export function BookCover({
{showOverlay && overlayVariant === "default" && (
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/60 to-transparent p-4 space-y-2 translate-y-full group-hover:translate-y-0 transition-transform duration-200">
<p className="text-sm font-medium text-white text-left line-clamp-2">
{book.metadata.title ||
(book.metadata.number
{book.metadata.title ||
(book.metadata.number
? t("navigation.volume", { number: book.metadata.number })
: "")}
</p>
@@ -155,8 +155,8 @@ export function BookCover({
{showOverlay && overlayVariant === "home" && (
<div className="absolute inset-0 bg-black/60 opacity-0 hover:opacity-100 transition-opacity duration-200 flex flex-col justify-end p-3">
<h3 className="font-medium text-sm text-white line-clamp-2">
{book.metadata.title ||
(book.metadata.number
{book.metadata.title ||
(book.metadata.number
? t("navigation.volume", { number: book.metadata.number })
: "")}
</h3>

View File

@@ -273,8 +273,8 @@ export function BookOfflineButton({ book, className }: BookOfflineButtonProps) {
const buttonTitle = isLoading
? `Téléchargement en cours (${Math.round(downloadProgress)}%)`
: isAvailableOffline
? "Supprimer hors ligne"
: "Disponible hors ligne";
? "Supprimer hors ligne"
: "Disponible hors ligne";
return (
<Button

View File

@@ -9,9 +9,12 @@ const buttonVariants = cva(
variants: {
variant: {
default: "bg-primary/90 backdrop-blur-md text-primary-foreground hover:bg-primary/80",
destructive: "bg-destructive/90 backdrop-blur-md text-destructive-foreground hover:bg-destructive/80",
outline: "border border-input bg-background/70 backdrop-blur-md hover:bg-accent/80 hover:text-accent-foreground",
secondary: "bg-secondary/80 backdrop-blur-md text-secondary-foreground hover:bg-secondary/70",
destructive:
"bg-destructive/90 backdrop-blur-md text-destructive-foreground hover:bg-destructive/80",
outline:
"border border-input bg-background/70 backdrop-blur-md hover:bg-accent/80 hover:text-accent-foreground",
secondary:
"bg-secondary/80 backdrop-blur-md text-secondary-foreground hover:bg-secondary/70",
ghost: "hover:bg-accent/80 hover:backdrop-blur-md hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
@@ -30,8 +33,7 @@ const buttonVariants = cva(
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
asChild?: boolean;
}

View File

@@ -6,7 +6,10 @@ const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElemen
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("rounded-lg border bg-card/70 backdrop-blur-md text-card-foreground shadow-sm", className)}
className={cn(
"rounded-lg border bg-card/70 backdrop-blur-md text-card-foreground shadow-sm",
className
)}
{...props}
/>
)

View File

@@ -26,4 +26,3 @@ const Checkbox = React.forwardRef<
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
export { Checkbox };

View File

@@ -24,8 +24,7 @@ const containerVariants = cva("mx-auto px-2 sm:px-6 lg:px-8", {
});
export interface ContainerProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof containerVariants> {
extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof containerVariants> {
as?: React.ElementType;
}
@@ -44,4 +43,3 @@ const Container = React.forwardRef<HTMLDivElement, ContainerProps>(
Container.displayName = "Container";
export { Container, containerVariants };

View File

@@ -56,7 +56,7 @@ export const CoverClient = ({
const timer = setTimeout(() => {
setImageError(false);
setIsLoading(true);
setRetryCount(prev => prev + 1);
setRetryCount((prev) => prev + 1);
}, 2000);
return () => clearTimeout(timer);
@@ -80,9 +80,10 @@ export const CoverClient = ({
};
// Ajouter un timestamp pour forcer le rechargement en cas de retry
const imageUrlWithRetry = retryCount > 0
? `${imageUrl}${imageUrl.includes('?') ? '&' : '?'}retry=${retryCount}`
: imageUrl;
const imageUrlWithRetry =
retryCount > 0
? `${imageUrl}${imageUrl.includes("?") ? "&" : "?"}retry=${retryCount}`
: imageUrl;
if (imageError) {
return (

View File

@@ -30,4 +30,3 @@ const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
IconButton.displayName = "IconButton";
export { IconButton };

View File

@@ -8,18 +8,12 @@ const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
);
interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement>,
VariantProps<typeof labelVariants> {}
interface LabelProps
extends React.LabelHTMLAttributes<HTMLLabelElement>, VariantProps<typeof labelVariants> {}
const Label = React.forwardRef<HTMLLabelElement, LabelProps>(
({ className, ...props }, ref) => (
<label
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
)
);
const Label = React.forwardRef<HTMLLabelElement, LabelProps>(({ className, ...props }, ref) => (
<label ref={ref} className={cn(labelVariants(), className)} {...props} />
));
Label.displayName = "Label";
export { Label };

View File

@@ -25,9 +25,7 @@ const NavButton = React.forwardRef<HTMLButtonElement, NavButtonProps>(
<Icon className="mr-2 h-4 w-4" />
<span className="truncate">{label}</span>
</div>
{count !== undefined && (
<span className="text-xs text-muted-foreground">{count}</span>
)}
{count !== undefined && <span className="text-xs text-muted-foreground">{count}</span>}
</button>
);
}
@@ -36,4 +34,3 @@ const NavButton = React.forwardRef<HTMLButtonElement, NavButtonProps>(
NavButton.displayName = "NavButton";
export { NavButton };

View File

@@ -6,10 +6,11 @@ interface ProgressBarProps {
export function ProgressBar({ progress, total, type }: ProgressBarProps) {
const percentage = Math.round((progress / total) * 100);
const barColor = type === "series"
? "bg-gradient-to-r from-purple-500 to-pink-500"
: "bg-gradient-to-r from-blue-500 to-cyan-500";
const barColor =
type === "series"
? "bg-gradient-to-r from-purple-500 to-pink-500"
: "bg-gradient-to-r from-blue-500 to-cyan-500";
return (
<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">

View File

@@ -10,9 +10,7 @@ const RadioGroup = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
>(({ className, ...props }, ref) => {
return (
<RadioGroupPrimitive.Root className={cn("grid gap-2", className)} {...props} ref={ref} />
);
return <RadioGroupPrimitive.Root className={cn("grid gap-2", className)} {...props} ref={ref} />;
});
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
@@ -38,4 +36,3 @@ const RadioGroupItem = React.forwardRef<
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
export { RadioGroup, RadioGroupItem };

View File

@@ -76,10 +76,7 @@ const ScrollContainer = React.forwardRef<HTMLDivElement, ScrollContainerProps>(
<div
ref={scrollContainerRef}
onScroll={handleScroll}
className={cn(
"flex gap-4 overflow-x-auto scrollbar-hide scroll-smooth pb-4",
className
)}
className={cn("flex gap-4 overflow-x-auto scrollbar-hide scroll-smooth pb-4", className)}
{...props}
>
{children}
@@ -102,4 +99,3 @@ const ScrollContainer = React.forwardRef<HTMLDivElement, ScrollContainerProps>(
ScrollContainer.displayName = "ScrollContainer";
export { ScrollContainer };

View File

@@ -42,4 +42,3 @@ const Section = React.forwardRef<HTMLElement, SectionProps>(
Section.displayName = "Section";
export { Section };

View File

@@ -24,4 +24,3 @@ const Separator = React.forwardRef<HTMLDivElement, SeparatorProps>(
Separator.displayName = "Separator";
export { Separator };

View File

@@ -1,16 +1,7 @@
import { cn } from "@/lib/utils";
function Skeleton({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn("animate-pulse rounded-md bg-muted", className)}
{...props}
/>
);
function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
return <div className={cn("animate-pulse rounded-md bg-muted", className)} {...props} />;
}
export { Skeleton };

View File

@@ -69,10 +69,7 @@ export function SliderControl({
<Plus className="h-4 w-4" />
</Button>
</div>
{description && (
<p className="text-xs text-muted-foreground">{description}</p>
)}
{description && <p className="text-xs text-muted-foreground">{description}</p>}
</div>
);
}

View File

@@ -1,9 +1,9 @@
"use client"
"use client";
import * as React from "react"
import * as SliderPrimitive from "@radix-ui/react-slider"
import * as React from "react";
import * as SliderPrimitive from "@radix-ui/react-slider";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Slider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
@@ -11,11 +11,8 @@ const Slider = React.forwardRef<
>(({ className, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
"relative flex w-full touch-auto select-none items-center",
className
)}
style={{ touchAction: 'pan-x' }}
className={cn("relative flex w-full touch-auto select-none items-center", className)}
style={{ touchAction: "pan-x" }}
{...props}
>
<SliderPrimitive.Track className="relative h-3 w-full grow overflow-hidden rounded-full bg-secondary">
@@ -23,8 +20,7 @@ const Slider = React.forwardRef<
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-6 w-6 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:scale-110 active:scale-105 touch-manipulation cursor-pointer" />
</SliderPrimitive.Root>
))
Slider.displayName = SliderPrimitive.Root.displayName
export { Slider }
));
Slider.displayName = SliderPrimitive.Root.displayName;
export { Slider };

View File

@@ -21,19 +21,14 @@ const statusBadgeVariants = cva("flex items-center gap-1", {
});
export interface StatusBadgeProps
extends Omit<BadgeProps, "variant">,
VariantProps<typeof statusBadgeVariants> {
extends Omit<BadgeProps, "variant">, VariantProps<typeof statusBadgeVariants> {
icon?: LucideIcon;
children: React.ReactNode;
}
const StatusBadge = ({ status, icon: Icon, children, className, ...props }: StatusBadgeProps) => {
return (
<Badge
variant="outline"
className={cn(statusBadgeVariants({ status }), className)}
{...props}
>
<Badge variant="outline" className={cn(statusBadgeVariants({ status }), className)} {...props}>
{Icon && <Icon className="w-4 h-4" />}
{children}
</Badge>
@@ -41,4 +36,3 @@ const StatusBadge = ({ status, icon: Icon, children, className, ...props }: Stat
};
export { StatusBadge, statusBadgeVariants };

View File

@@ -3,8 +3,10 @@
import * as React from "react";
import { cn } from "@/lib/utils";
interface SwitchProps
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "role" | "aria-checked"> {
interface SwitchProps extends Omit<
React.InputHTMLAttributes<HTMLInputElement>,
"type" | "role" | "aria-checked"
> {
onCheckedChange?: (checked: boolean) => void;
}

View File

@@ -5,11 +5,7 @@ import { cn } from "@/lib/utils";
const Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(
({ className, ...props }, ref) => (
<div className="relative w-full overflow-auto">
<table
ref={ref}
className={cn("w-full caption-bottom text-sm", className)}
{...props}
/>
<table ref={ref} className={cn("w-full caption-bottom text-sm", className)} {...props} />
</div>
)
);
@@ -37,7 +33,10 @@ const TableFooter = React.forwardRef<
>(({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn("border-t bg-muted/50 backdrop-blur-md 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}
/>
));
@@ -93,4 +92,3 @@ const TableCaption = React.forwardRef<
TableCaption.displayName = "TableCaption";
export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };

View File

@@ -27,7 +27,8 @@ const toastVariants = cva(
{
variants: {
variant: {
default: "border border-border/40 bg-background/70 backdrop-blur-md text-foreground shadow-lg",
default:
"border border-border/40 bg-background/70 backdrop-blur-md text-foreground shadow-lg",
destructive:
"destructive group border-destructive/20 bg-destructive/70 backdrop-blur-md text-destructive-foreground font-medium",
},