shadcn primitives and logos keyed: dialog, sheet, pagination, carousel, breadcrumb, theme toggles
These are the strings a user meets everywhere, mostly sr-only: the dialog and
sheet close buttons, pagination labels, carousel arrows, the breadcrumb ellipsis
and both colour-mode toggles. nav aria-label='pagination' became a real key too —
a screen reader announces it, so it is user-facing.
Logo alt text keeps the product name and translates only around it
('Logótipo Officer'). Arrow-button insets became logical (-start-12/-end-12).
The three 'useX must be used within <Y>' Errors are deliberately untouched:
never-translate, per the doc's list.
This commit is contained in:
@@ -1,17 +1,14 @@
|
|||||||
|
import { useTranslation } from '@/components/locales';
|
||||||
|
|
||||||
type SvgLogoProps = {
|
type SvgLogoProps = {
|
||||||
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
||||||
};
|
};
|
||||||
|
|
||||||
export function OfficerIconLogo({ size = 'xl' }: SvgLogoProps) {
|
export function OfficerIconLogo({ size = 'xl' }: SvgLogoProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const config = sizeConfig[size];
|
const config = sizeConfig[size];
|
||||||
|
|
||||||
return (
|
return <img src="/officer-logo.svg" alt={t('logo.icon')} style={{ width: config.width, height: 'auto' }} />;
|
||||||
<img
|
|
||||||
src="/officer-logo.svg"
|
|
||||||
alt="Officer Icon"
|
|
||||||
style={{ width: config.width, height: 'auto' }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const sizeConfig = {
|
const sizeConfig = {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { useTranslation } from '@/components/locales';
|
||||||
|
|
||||||
type SvgLogoProps = {
|
type SvgLogoProps = {
|
||||||
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
||||||
square?: boolean;
|
square?: boolean;
|
||||||
@@ -12,27 +14,17 @@ export function OfficerSvgLogo({ size = 'xl', square = false }: SvgLogoProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function OfficerSvgLogoRegular({ size = 'xl' }: SvgLogoProps) {
|
export function OfficerSvgLogoRegular({ size = 'xl' }: SvgLogoProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const config = sizeConfig.regular[size];
|
const config = sizeConfig.regular[size];
|
||||||
|
|
||||||
return (
|
return <img src="/officer-logo.svg" alt={t('logo.logo')} style={{ width: config.width, height: 'auto' }} />;
|
||||||
<img
|
|
||||||
src="/officer-logo.svg"
|
|
||||||
alt="Officer Logo"
|
|
||||||
style={{ width: config.width, height: 'auto' }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OfficerSvgLogoSquare({ size = 'xl' }: SvgLogoProps) {
|
export function OfficerSvgLogoSquare({ size = 'xl' }: SvgLogoProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const config = sizeConfig.square[size];
|
const config = sizeConfig.square[size];
|
||||||
|
|
||||||
return (
|
return <img src="/officer-logo.svg" alt={t('logo.logo')} style={{ width: config.width, height: 'auto' }} />;
|
||||||
<img
|
|
||||||
src="/officer-logo.svg"
|
|
||||||
alt="Officer Logo"
|
|
||||||
style={{ width: config.width, height: 'auto' }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const sizeConfig = {
|
const sizeConfig = {
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { Moon, Sun } from 'lucide-react';
|
import { Moon, Sun } from 'lucide-react';
|
||||||
import { cn } from 'helpers/cn';
|
import { cn } from 'helpers/cn';
|
||||||
import { useColorMode } from './ThemeProvider';
|
import { useColorMode } from './ThemeProvider';
|
||||||
|
import { useTranslation } from '@/components/locales';
|
||||||
|
|
||||||
type ThemeToggleProps = { colorDark?: boolean; colorLight?: boolean };
|
type ThemeToggleProps = { colorDark?: boolean; colorLight?: boolean };
|
||||||
|
|
||||||
export const ThemeToggle = (props: ThemeToggleProps) => {
|
export const ThemeToggle = (props: ThemeToggleProps) => {
|
||||||
const { colorDark, colorLight } = props;
|
const { colorDark, colorLight } = props;
|
||||||
const { colorMode, setColorMode } = useColorMode();
|
const { colorMode, setColorMode } = useColorMode();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const toggle = () => {
|
const toggle = () => {
|
||||||
setColorMode(colorMode === 'dark' ? 'light' : 'dark');
|
setColorMode(colorMode === 'dark' ? 'light' : 'dark');
|
||||||
@@ -26,7 +28,7 @@ export const ThemeToggle = (props: ThemeToggleProps) => {
|
|||||||
colorDark && 'text-black',
|
colorDark && 'text-black',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<span className="sr-only">Toggle color mode</span>
|
<span className="sr-only">{t('theme.toggle')}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Slot } from '@radix-ui/react-slot';
|
|||||||
import { ChevronRight, MoreHorizontal } from 'lucide-react';
|
import { ChevronRight, MoreHorizontal } from 'lucide-react';
|
||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { useTranslation } from '@/components/locales';
|
||||||
|
|
||||||
const Breadcrumb = React.forwardRef<
|
const Breadcrumb = React.forwardRef<
|
||||||
HTMLElement,
|
HTMLElement,
|
||||||
@@ -66,17 +67,20 @@ const BreadcrumbSeparator = ({ children, className, ...props }: React.ComponentP
|
|||||||
);
|
);
|
||||||
BreadcrumbSeparator.displayName = 'BreadcrumbSeparator';
|
BreadcrumbSeparator.displayName = 'BreadcrumbSeparator';
|
||||||
|
|
||||||
const BreadcrumbEllipsis = ({ className, ...props }: React.ComponentProps<'span'>) => (
|
const BreadcrumbEllipsis = ({ className, ...props }: React.ComponentProps<'span'>) => {
|
||||||
<span
|
const { t } = useTranslation();
|
||||||
role="presentation"
|
return (
|
||||||
aria-hidden="true"
|
<span
|
||||||
className={cn('flex h-9 w-9 items-center justify-center', className)}
|
role="presentation"
|
||||||
{...props}
|
aria-hidden="true"
|
||||||
>
|
className={cn('flex h-9 w-9 items-center justify-center', className)}
|
||||||
<MoreHorizontal className="h-4 w-4" />
|
{...props}
|
||||||
<span className="sr-only">More</span>
|
>
|
||||||
</span>
|
<MoreHorizontal className="h-4 w-4" />
|
||||||
);
|
<span className="sr-only">{t('breadcrumb.more')}</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
BreadcrumbEllipsis.displayName = 'BreadcrumbElipssis';
|
BreadcrumbEllipsis.displayName = 'BreadcrumbElipssis';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ArrowLeft, ArrowRight } from 'lucide-react';
|
|||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { useTranslation } from '@/components/locales';
|
||||||
|
|
||||||
type CarouselApi = UseEmblaCarouselType[1];
|
type CarouselApi = UseEmblaCarouselType[1];
|
||||||
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
|
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
|
||||||
@@ -168,6 +169,7 @@ CarouselItem.displayName = 'CarouselItem';
|
|||||||
const CarouselPrevious = React.forwardRef<HTMLButtonElement, React.ComponentProps<typeof Button>>(
|
const CarouselPrevious = React.forwardRef<HTMLButtonElement, React.ComponentProps<typeof Button>>(
|
||||||
({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
|
({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
|
||||||
const { orientation, scrollPrev, canScrollPrev } = useCarousel();
|
const { orientation, scrollPrev, canScrollPrev } = useCarousel();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
@@ -177,7 +179,7 @@ const CarouselPrevious = React.forwardRef<HTMLButtonElement, React.ComponentProp
|
|||||||
className={cn(
|
className={cn(
|
||||||
'absolute h-8 w-8 rounded-full',
|
'absolute h-8 w-8 rounded-full',
|
||||||
orientation === 'horizontal'
|
orientation === 'horizontal'
|
||||||
? '-left-12 top-1/2 -translate-y-1/2'
|
? '-start-12 top-1/2 -translate-y-1/2'
|
||||||
: '-top-12 left-1/2 -translate-x-1/2 rotate-90',
|
: '-top-12 left-1/2 -translate-x-1/2 rotate-90',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
@@ -186,7 +188,7 @@ const CarouselPrevious = React.forwardRef<HTMLButtonElement, React.ComponentProp
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ArrowLeft className="h-4 w-4" />
|
<ArrowLeft className="h-4 w-4" />
|
||||||
<span className="sr-only">Previous slide</span>
|
<span className="sr-only">{t('carousel.previous')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -196,6 +198,7 @@ CarouselPrevious.displayName = 'CarouselPrevious';
|
|||||||
const CarouselNext = React.forwardRef<HTMLButtonElement, React.ComponentProps<typeof Button>>(
|
const CarouselNext = React.forwardRef<HTMLButtonElement, React.ComponentProps<typeof Button>>(
|
||||||
({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
|
({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
|
||||||
const { orientation, scrollNext, canScrollNext } = useCarousel();
|
const { orientation, scrollNext, canScrollNext } = useCarousel();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
@@ -205,7 +208,7 @@ const CarouselNext = React.forwardRef<HTMLButtonElement, React.ComponentProps<ty
|
|||||||
className={cn(
|
className={cn(
|
||||||
'absolute h-8 w-8 rounded-full',
|
'absolute h-8 w-8 rounded-full',
|
||||||
orientation === 'horizontal'
|
orientation === 'horizontal'
|
||||||
? '-right-12 top-1/2 -translate-y-1/2'
|
? '-end-12 top-1/2 -translate-y-1/2'
|
||||||
: '-bottom-12 left-1/2 -translate-x-1/2 rotate-90',
|
: '-bottom-12 left-1/2 -translate-x-1/2 rotate-90',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
@@ -214,7 +217,7 @@ const CarouselNext = React.forwardRef<HTMLButtonElement, React.ComponentProps<ty
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<ArrowRight className="h-4 w-4" />
|
<ArrowRight className="h-4 w-4" />
|
||||||
<span className="sr-only">Next slide</span>
|
<span className="sr-only">{t('carousel.next')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|||||||
import { X } from 'lucide-react';
|
import { X } from 'lucide-react';
|
||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { useTranslation } from '@/components/locales';
|
||||||
|
|
||||||
const Dialog = DialogPrimitive.Root;
|
const Dialog = DialogPrimitive.Root;
|
||||||
|
|
||||||
@@ -30,25 +31,28 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|||||||
const DialogContent = React.forwardRef<
|
const DialogContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||||
>(({ className, children, ...props }, ref) => (
|
>(({ className, children, ...props }, ref) => {
|
||||||
<DialogPortal>
|
const { t } = useTranslation();
|
||||||
<DialogOverlay />
|
return (
|
||||||
<DialogPrimitive.Content
|
<DialogPortal>
|
||||||
ref={ref}
|
<DialogOverlay />
|
||||||
className={cn(
|
<DialogPrimitive.Content
|
||||||
'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',
|
ref={ref}
|
||||||
className,
|
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',
|
||||||
{...props}
|
className,
|
||||||
>
|
)}
|
||||||
{children}
|
{...props}
|
||||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
>
|
||||||
<X className="h-4 w-4" />
|
{children}
|
||||||
<span className="sr-only">Close</span>
|
<DialogPrimitive.Close className="absolute end-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||||
</DialogPrimitive.Close>
|
<X className="h-4 w-4" />
|
||||||
</DialogPrimitive.Content>
|
<span className="sr-only">{t('button.close')}</span>
|
||||||
</DialogPortal>
|
</DialogPrimitive.Close>
|
||||||
));
|
</DialogPrimitive.Content>
|
||||||
|
</DialogPortal>
|
||||||
|
);
|
||||||
|
});
|
||||||
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||||
|
|
||||||
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ import { Moon, Sun } from 'lucide-react';
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useColorMode } from '@/components/ui/ThemeProvider';
|
import { useColorMode } from '@/components/ui/ThemeProvider';
|
||||||
import { cn } from 'helpers/cn';
|
import { cn } from 'helpers/cn';
|
||||||
|
import { useTranslation } from '@/components/locales';
|
||||||
|
|
||||||
export const ModeToggle = React.forwardRef<React.ElementRef<typeof Button>, React.ComponentProps<typeof Button>>(
|
export const ModeToggle = React.forwardRef<React.ElementRef<typeof Button>, React.ComponentProps<typeof Button>>(
|
||||||
({ className, ...props }, ref) => {
|
({ className, ...props }, ref) => {
|
||||||
const { colorMode, setColorMode } = useColorMode();
|
const { colorMode, setColorMode } = useColorMode();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
@@ -19,7 +21,7 @@ export const ModeToggle = React.forwardRef<React.ElementRef<typeof Button>, Reac
|
|||||||
>
|
>
|
||||||
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
||||||
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
||||||
<span className="sr-only">Toggle color mode</span>
|
<span className="sr-only">{t('theme.toggle')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,15 +4,19 @@ import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
|
|||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import type { ButtonProps } from '@/components/ui/button';
|
import type { ButtonProps } from '@/components/ui/button';
|
||||||
import { buttonVariants } from '@/components/ui/button';
|
import { buttonVariants } from '@/components/ui/button';
|
||||||
|
import { useTranslation } from '@/components/locales';
|
||||||
|
|
||||||
const Pagination = ({ className, ...props }: React.ComponentProps<'nav'>) => (
|
const Pagination = ({ className, ...props }: React.ComponentProps<'nav'>) => {
|
||||||
<nav
|
const { t } = useTranslation();
|
||||||
role="navigation"
|
return (
|
||||||
aria-label="pagination"
|
<nav
|
||||||
className={cn('mx-auto flex w-full justify-center', className)}
|
role="navigation"
|
||||||
{...props}
|
aria-label={t('pagination.label')}
|
||||||
/>
|
className={cn('mx-auto flex w-full justify-center', className)}
|
||||||
);
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
Pagination.displayName = 'Pagination';
|
Pagination.displayName = 'Pagination';
|
||||||
|
|
||||||
const PaginationContent = React.forwardRef<HTMLUListElement, React.ComponentProps<'ul'>>(
|
const PaginationContent = React.forwardRef<HTMLUListElement, React.ComponentProps<'ul'>>(
|
||||||
@@ -47,28 +51,47 @@ const PaginationLink = ({ className, isActive, size = 'icon', ...props }: Pagina
|
|||||||
);
|
);
|
||||||
PaginationLink.displayName = 'PaginationLink';
|
PaginationLink.displayName = 'PaginationLink';
|
||||||
|
|
||||||
const PaginationPrevious = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => (
|
const PaginationPrevious = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => {
|
||||||
<PaginationLink aria-label="Go to previous page" size="default" className={cn('gap-1 pl-2.5', className)} {...props}>
|
const { t } = useTranslation();
|
||||||
<ChevronLeft className="h-4 w-4" />
|
return (
|
||||||
<span>Previous</span>
|
<PaginationLink
|
||||||
</PaginationLink>
|
aria-label={t('pagination.goToPrevious')}
|
||||||
);
|
size="default"
|
||||||
|
className={cn('gap-1 ps-2.5', className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChevronLeft className="h-4 w-4" />
|
||||||
|
<span>{t('pagination.previous')}</span>
|
||||||
|
</PaginationLink>
|
||||||
|
);
|
||||||
|
};
|
||||||
PaginationPrevious.displayName = 'PaginationPrevious';
|
PaginationPrevious.displayName = 'PaginationPrevious';
|
||||||
|
|
||||||
const PaginationNext = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => (
|
const PaginationNext = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => {
|
||||||
<PaginationLink aria-label="Go to next page" size="default" className={cn('gap-1 pr-2.5', className)} {...props}>
|
const { t } = useTranslation();
|
||||||
<span>Next</span>
|
return (
|
||||||
<ChevronRight className="h-4 w-4" />
|
<PaginationLink
|
||||||
</PaginationLink>
|
aria-label={t('pagination.goToNext')}
|
||||||
);
|
size="default"
|
||||||
|
className={cn('gap-1 pe-2.5', className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<span>{t('pagination.next')}</span>
|
||||||
|
<ChevronRight className="h-4 w-4" />
|
||||||
|
</PaginationLink>
|
||||||
|
);
|
||||||
|
};
|
||||||
PaginationNext.displayName = 'PaginationNext';
|
PaginationNext.displayName = 'PaginationNext';
|
||||||
|
|
||||||
const PaginationEllipsis = ({ className, ...props }: React.ComponentProps<'span'>) => (
|
const PaginationEllipsis = ({ className, ...props }: React.ComponentProps<'span'>) => {
|
||||||
<span aria-hidden className={cn('flex h-9 w-9 items-center justify-center', className)} {...props}>
|
const { t } = useTranslation();
|
||||||
<MoreHorizontal className="h-4 w-4" />
|
return (
|
||||||
<span className="sr-only">More pages</span>
|
<span aria-hidden className={cn('flex h-9 w-9 items-center justify-center', className)} {...props}>
|
||||||
</span>
|
<MoreHorizontal className="h-4 w-4" />
|
||||||
);
|
<span className="sr-only">{t('pagination.morePages')}</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
PaginationEllipsis.displayName = 'PaginationEllipsis';
|
PaginationEllipsis.displayName = 'PaginationEllipsis';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { X } from 'lucide-react';
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { useTranslation } from '@/components/locales';
|
||||||
|
|
||||||
const Sheet = SheetPrimitive.Root;
|
const Sheet = SheetPrimitive.Root;
|
||||||
|
|
||||||
@@ -51,18 +52,21 @@ interface SheetContentProps
|
|||||||
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, VariantProps<typeof sheetVariants> {}
|
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, VariantProps<typeof sheetVariants> {}
|
||||||
|
|
||||||
const SheetContent = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Content>, SheetContentProps>(
|
const SheetContent = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Content>, SheetContentProps>(
|
||||||
({ side = 'right', className, children, ...props }, ref) => (
|
({ side = 'right', className, children, ...props }, ref) => {
|
||||||
<SheetPortal>
|
const { t } = useTranslation();
|
||||||
<SheetOverlay />
|
return (
|
||||||
<SheetPrimitive.Content ref={ref} className={cn(sheetVariants({ side }), className)} {...props}>
|
<SheetPortal>
|
||||||
{children}
|
<SheetOverlay />
|
||||||
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
<SheetPrimitive.Content ref={ref} className={cn(sheetVariants({ side }), className)} {...props}>
|
||||||
<X className="h-4 w-4" />
|
{children}
|
||||||
<span className="sr-only">Close</span>
|
<SheetPrimitive.Close className="absolute end-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
||||||
</SheetPrimitive.Close>
|
<X className="h-4 w-4" />
|
||||||
</SheetPrimitive.Content>
|
<span className="sr-only">{t('button.close')}</span>
|
||||||
</SheetPortal>
|
</SheetPrimitive.Close>
|
||||||
),
|
</SheetPrimitive.Content>
|
||||||
|
</SheetPortal>
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user