i18n
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
import { UnstyledButton } from "@mantine/core"
|
||||
import { ArrowLeftIcon } from "@phosphor-icons/react"
|
||||
import { useRouter } from "@tanstack/react-router"
|
||||
import { useLingui } from "@lingui/react/macro"
|
||||
|
||||
const BackButton = ({ top=20, left=20 }: { top?: number, left?: number }) => {
|
||||
const router = useRouter()
|
||||
const { t } = useLingui()
|
||||
|
||||
return (
|
||||
<UnstyledButton
|
||||
aria-label='Go back'
|
||||
aria-label={t`Go back`}
|
||||
style={{ cursor: 'pointer', zIndex: 1000, display: 'flex' }}
|
||||
onClick={() => router.history.back()}
|
||||
pos='absolute'
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import { Title, AppShell, Flex } from "@mantine/core";
|
||||
import { useLingui } from "@lingui/react";
|
||||
import { HeaderConfig } from "../types/header-config";
|
||||
import BackButton from "./back-button";
|
||||
|
||||
const Header = ({ collapsed, title, withBackButton }: HeaderConfig) => {
|
||||
const Header = ({ collapsed, title, titleValues, withBackButton }: HeaderConfig) => {
|
||||
const { i18n } = useLingui();
|
||||
const resolvedTitle =
|
||||
typeof title === "string" || title === undefined
|
||||
? title
|
||||
: i18n._({ ...title, values: titleValues });
|
||||
|
||||
return (
|
||||
<AppShell.Header
|
||||
id='app-header'
|
||||
@@ -15,7 +22,7 @@ const Header = ({ collapsed, title, withBackButton }: HeaderConfig) => {
|
||||
{ withBackButton && <BackButton /> }
|
||||
<Flex justify='center' px='md' mt={8}>
|
||||
<Title order={1} lts='0.08em' style={{ userSelect: 'none' }}>
|
||||
{title?.toLocaleUpperCase()}
|
||||
{resolvedTitle?.toLocaleUpperCase()}
|
||||
</Title>
|
||||
</Flex>
|
||||
</AppShell.Header>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AuthProvider } from "@/contexts/auth-context"
|
||||
import { SpotifyProvider } from "@/contexts/spotify-context"
|
||||
import { LinguiProvider } from "@/lib/i18n/provider"
|
||||
import MantineProvider from "@/lib/mantine/mantine-provider"
|
||||
//import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools'
|
||||
//import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
|
||||
@@ -8,7 +9,8 @@ import { Toaster } from "sonner"
|
||||
|
||||
const Providers = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<LinguiProvider>
|
||||
<AuthProvider>
|
||||
<SpotifyProvider>
|
||||
<MantineProvider>
|
||||
{/*<TanStackDevtools
|
||||
@@ -31,7 +33,8 @@ const Providers = ({ children }: { children: React.ReactNode }) => {
|
||||
{children}
|
||||
</MantineProvider>
|
||||
</SpotifyProvider>
|
||||
</AuthProvider>
|
||||
</AuthProvider>
|
||||
</LinguiProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { UnstyledButton } from "@mantine/core"
|
||||
import { GearIcon } from "@phosphor-icons/react"
|
||||
import { useNavigate } from "@tanstack/react-router"
|
||||
import { useLingui } from "@lingui/react/macro"
|
||||
import { memo } from "react";
|
||||
|
||||
interface SettingButtonProps {
|
||||
@@ -11,10 +12,11 @@ interface SettingButtonProps {
|
||||
|
||||
const SettingsButton = ({ to }: SettingButtonProps) => {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useLingui();
|
||||
|
||||
return (
|
||||
<UnstyledButton
|
||||
aria-label='Settings'
|
||||
aria-label={t`Settings`}
|
||||
style={{ cursor: 'pointer', zIndex: 1000, display: 'flex' }}
|
||||
onClick={() => navigate({ to })}
|
||||
pos='absolute'
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
import { HouseIcon, RankingIcon, ShieldIcon, TrophyIcon, UserCircleIcon } from "@phosphor-icons/react";
|
||||
import { useMemo } from "react";
|
||||
import { useLingui } from "@lingui/react/macro";
|
||||
|
||||
export const useLinks = (userId: string | undefined, roles: string[]) =>
|
||||
useMemo(() => {
|
||||
export const useLinks = (userId: string | undefined, roles: string[]) => {
|
||||
const { t } = useLingui();
|
||||
|
||||
return useMemo(() => {
|
||||
const links = [
|
||||
{
|
||||
label: 'Home',
|
||||
label: t`Home`,
|
||||
href: '/',
|
||||
Icon: HouseIcon
|
||||
},
|
||||
{
|
||||
label: 'Statistics',
|
||||
label: t`Statistics`,
|
||||
href: '/stats',
|
||||
Icon: RankingIcon
|
||||
},
|
||||
{
|
||||
label: 'Tournaments',
|
||||
label: t`Tournaments`,
|
||||
href: '/tournaments',
|
||||
Icon: TrophyIcon,
|
||||
exclude: ['/admin/tournaments']
|
||||
},
|
||||
{
|
||||
label: 'Profile',
|
||||
label: t`Profile`,
|
||||
href: `/profile/${userId}`,
|
||||
Icon: UserCircleIcon,
|
||||
include: ['/settings']
|
||||
@@ -30,11 +33,12 @@ export const useLinks = (userId: string | undefined, roles: string[]) =>
|
||||
|
||||
if (roles.includes('Admin')) {
|
||||
links.push({
|
||||
label: 'Admin',
|
||||
label: t`Admin`,
|
||||
href: '/admin',
|
||||
Icon: ShieldIcon
|
||||
})
|
||||
}
|
||||
|
||||
return links;
|
||||
}, [userId, roles]);
|
||||
}, [userId, roles, t]);
|
||||
};
|
||||
@@ -16,14 +16,14 @@ const useRouterConfig = () => {
|
||||
match?.loaderData && 'header' in match.loaderData
|
||||
);
|
||||
|
||||
const headerConfig = matchesWithHeader.reduce((acc, match) => {
|
||||
const headerConfig = matchesWithHeader.reduce<HeaderConfig>((acc, match) => {
|
||||
const loaderData = match?.loaderData;
|
||||
if (loaderData && typeof loaderData === 'object' && 'header' in loaderData) {
|
||||
const header = loaderData.header;
|
||||
if (header && typeof header === 'object') {
|
||||
return {
|
||||
...acc,
|
||||
...header,
|
||||
...(header as HeaderConfig),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
/**
|
||||
* Serializable subset of Lingui's MessageDescriptor — header config passes
|
||||
* through route loaders/beforeLoad, whose results must be serializable.
|
||||
* msg`` descriptors are assignable to this shape.
|
||||
*/
|
||||
interface HeaderTitleMessage {
|
||||
id: string;
|
||||
message?: string;
|
||||
comment?: string;
|
||||
}
|
||||
|
||||
interface HeaderConfig {
|
||||
title?: string;
|
||||
/** Plain strings render as-is (data-derived names); use a msg`` descriptor for translatable titles. */
|
||||
title?: string | HeaderTitleMessage;
|
||||
/** ICU values when title is a descriptor, e.g. msg`Manage {name}` + { name }. */
|
||||
titleValues?: Record<string, string | number>;
|
||||
withBackButton?: boolean;
|
||||
collapsed?: boolean;
|
||||
settingsLink?: string;
|
||||
}
|
||||
|
||||
export type { HeaderConfig };
|
||||
export type { HeaderConfig, HeaderTitleMessage };
|
||||
|
||||
Reference in New Issue
Block a user