mirror of
https://github.com/temetro/temetro.git
synced 2026-07-26 11:58:14 +00:00
d237504af9
Add three UI locales (so/ar/de) with full ~1,660-key translations alongside en/fr, selectable in Settings → Profile. Arabic gets full right-to-left support: - config.ts registers the locales and exports a `dirFor` helper; an inline <head> script in layout.tsx sets <html dir/lang> before first paint (no RTL flash), and i18n-provider keeps them in sync on language change. - ~160 physical direction utilities converted to logical (ms/me/ps/pe/ start/end/text-start/text-end); directional chevrons/arrows get rtl:rotate-180; chat-bubble align variants fixed to logical. - IBM Plex Sans Arabic appended to the sans/heading font stacks for per-character Arabic fallback. - Language persists to the backend user_settings and re-applies on sign-in so it roams across devices (localStorage stays the offline source of truth). - New scripts/check-locales.mjs (npm run check-locales) enforces key/placeholder parity and Arabic CLDR plural completeness. Bump to 0.3.0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
131 lines
3.1 KiB
TypeScript
131 lines
3.1 KiB
TypeScript
"use client";
|
|
|
|
import { mergeProps } from "@base-ui/react/merge-props";
|
|
import { useRender } from "@base-ui/react/use-render";
|
|
import {
|
|
ChevronLeftIcon,
|
|
ChevronRightIcon,
|
|
MoreHorizontalIcon,
|
|
} from "lucide-react";
|
|
import type * as React from "react";
|
|
import { cn } from "@/lib/utils";
|
|
import { type Button, buttonVariants } from "@/components/ui/button";
|
|
|
|
export function Pagination({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<"nav">): React.ReactElement {
|
|
return (
|
|
<nav
|
|
aria-label="pagination"
|
|
className={cn("mx-auto flex w-full justify-center", className)}
|
|
data-slot="pagination"
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function PaginationContent({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<"ul">): React.ReactElement {
|
|
return (
|
|
<ul
|
|
className={cn("flex flex-row items-center gap-1", className)}
|
|
data-slot="pagination-content"
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function PaginationItem({
|
|
...props
|
|
}: React.ComponentProps<"li">): React.ReactElement {
|
|
return <li data-slot="pagination-item" {...props} />;
|
|
}
|
|
|
|
export type PaginationLinkProps = {
|
|
isActive?: boolean;
|
|
size?: React.ComponentProps<typeof Button>["size"];
|
|
} & useRender.ComponentProps<"a">;
|
|
|
|
export function PaginationLink({
|
|
className,
|
|
isActive,
|
|
size = "icon",
|
|
render,
|
|
...props
|
|
}: PaginationLinkProps): React.ReactElement {
|
|
const defaultProps = {
|
|
"aria-current": isActive ? ("page" as const) : undefined,
|
|
className: render
|
|
? className
|
|
: cn(
|
|
buttonVariants({
|
|
size,
|
|
variant: isActive ? "outline" : "ghost",
|
|
}),
|
|
className,
|
|
),
|
|
"data-active": isActive,
|
|
"data-slot": "pagination-link",
|
|
};
|
|
|
|
return useRender({
|
|
defaultTagName: "a",
|
|
props: mergeProps<"a">(defaultProps, props),
|
|
render,
|
|
});
|
|
}
|
|
|
|
export function PaginationPrevious({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<typeof PaginationLink>): React.ReactElement {
|
|
return (
|
|
<PaginationLink
|
|
aria-label="Go to previous page"
|
|
className={cn("max-sm:aspect-square max-sm:p-0", className)}
|
|
size="default"
|
|
{...props}
|
|
>
|
|
<ChevronLeftIcon className="sm:-ms-1 rtl:rotate-180" />
|
|
<span className="max-sm:hidden">Previous</span>
|
|
</PaginationLink>
|
|
);
|
|
}
|
|
|
|
export function PaginationNext({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<typeof PaginationLink>): React.ReactElement {
|
|
return (
|
|
<PaginationLink
|
|
aria-label="Go to next page"
|
|
className={cn("max-sm:aspect-square max-sm:p-0", className)}
|
|
size="default"
|
|
{...props}
|
|
>
|
|
<span className="max-sm:hidden">Next</span>
|
|
<ChevronRightIcon className="sm:-me-1 rtl:rotate-180" />
|
|
</PaginationLink>
|
|
);
|
|
}
|
|
|
|
export function PaginationEllipsis({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<"span">): React.ReactElement {
|
|
return (
|
|
<span
|
|
aria-hidden
|
|
className={cn("flex min-w-7 justify-center", className)}
|
|
data-slot="pagination-ellipsis"
|
|
{...props}
|
|
>
|
|
<MoreHorizontalIcon className="size-5 sm:size-4" />
|
|
<span className="sr-only">More pages</span>
|
|
</span>
|
|
);
|
|
}
|