mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-07-30 23:56:50 -05:00
Add relative time to recent results, support i18n in formatDistance
Closes #2418
This commit is contained in:
parent
819ac4dc26
commit
6a88daf921
|
|
@ -1,6 +1,5 @@
|
|||
import { Link } from "@remix-run/react";
|
||||
import clsx from "clsx";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Avatar } from "~/components/Avatar";
|
||||
|
|
@ -171,6 +170,7 @@ function ImagePreview({
|
|||
}) {
|
||||
const [imageLoaded, setImageLoaded] = React.useState(false);
|
||||
const { t } = useTranslation(["common", "art"]);
|
||||
const { formatDistanceToNow } = useTimeFormat();
|
||||
|
||||
const img = (
|
||||
// biome-ignore lint/a11y/noStaticElementInteractions: Biome v2 migration
|
||||
|
|
|
|||
|
|
@ -19,12 +19,14 @@ import styles from "./TournamentCard.module.css";
|
|||
export function TournamentCard({
|
||||
tournament,
|
||||
className,
|
||||
withRelativeTime = false,
|
||||
}: {
|
||||
tournament: CalendarEvent | ShowcaseCalendarEvent;
|
||||
className?: string;
|
||||
withRelativeTime?: boolean;
|
||||
}) {
|
||||
const isMounted = useIsMounted();
|
||||
const { formatDateTime } = useTimeFormat();
|
||||
const { formatDateTime, formatDistanceToNow } = useTimeFormat();
|
||||
|
||||
const isShowcase = tournament.type === "showcase";
|
||||
const isCalendar = tournament.type === "calendar";
|
||||
|
|
@ -35,6 +37,13 @@ export function TournamentCard({
|
|||
if (!isMounted) return "Placeholder";
|
||||
|
||||
const date = databaseTimestampToDate(tournament.startTime);
|
||||
|
||||
if (withRelativeTime) {
|
||||
return formatDistanceToNow(date, {
|
||||
addSuffix: true,
|
||||
});
|
||||
}
|
||||
|
||||
return formatDateTime(date, {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
|
|
|
|||
|
|
@ -283,7 +283,11 @@ function ResultHighlights() {
|
|||
</h2>
|
||||
<div className={styles.tournamentCardsSpacer}>
|
||||
{data.tournaments.results.map((tournament) => (
|
||||
<TournamentCard key={tournament.id} tournament={tournament} />
|
||||
<TournamentCard
|
||||
key={tournament.id}
|
||||
tournament={tournament}
|
||||
withRelativeTime
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { Link, useFetcher } from "@remix-run/react";
|
||||
import clsx from "clsx";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Avatar } from "~/components/Avatar";
|
||||
|
|
@ -260,7 +259,7 @@ function PostTime({
|
|||
updatedAt: number;
|
||||
}) {
|
||||
const { t } = useTranslation(["lfg"]);
|
||||
const { formatDate } = useTimeFormat();
|
||||
const { formatDate, formatDistanceToNow } = useTimeFormat();
|
||||
|
||||
const createdAtDate = databaseTimestampToDate(createdAt);
|
||||
const updatedAtDate = databaseTimestampToDate(updatedAt);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { formatDistanceToNow as formatDistanceToNowUtil } from "~/utils/dates";
|
||||
|
||||
const H12_TIME_OPTIONS: Intl.DateTimeFormatOptions = {
|
||||
hour12: true,
|
||||
|
|
@ -94,7 +95,17 @@ export function useTimeFormat() {
|
|||
return date.toLocaleDateString(i18n.language, options);
|
||||
};
|
||||
|
||||
return { formatDateTime, formatTime, formatDate };
|
||||
const formatDistanceToNow = (
|
||||
date: Parameters<typeof formatDistanceToNowUtil>[0],
|
||||
options?: Omit<Parameters<typeof formatDistanceToNowUtil>[1], "language">,
|
||||
) => {
|
||||
return formatDistanceToNowUtil(date, {
|
||||
...options,
|
||||
language: i18n.language,
|
||||
});
|
||||
};
|
||||
|
||||
return { formatDateTime, formatTime, formatDate, formatDistanceToNow };
|
||||
}
|
||||
|
||||
// Example: "09:00" -> "9:00"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,64 @@
|
|||
import { CalendarDateTime, parseDate } from "@internationalized/date";
|
||||
import { getWeek } from "date-fns";
|
||||
import type { Locale } from "date-fns";
|
||||
import {
|
||||
formatDistanceToNow as dateFnsFormatDistanceToNow,
|
||||
getWeek,
|
||||
} from "date-fns";
|
||||
import { da } from "date-fns/locale/da";
|
||||
import { de } from "date-fns/locale/de";
|
||||
import { enUS } from "date-fns/locale/en-US";
|
||||
import { es } from "date-fns/locale/es";
|
||||
import { fr } from "date-fns/locale/fr";
|
||||
import { frCA } from "date-fns/locale/fr-CA";
|
||||
import { he } from "date-fns/locale/he";
|
||||
import { it } from "date-fns/locale/it";
|
||||
import { ja } from "date-fns/locale/ja";
|
||||
import { ko } from "date-fns/locale/ko";
|
||||
import { nl } from "date-fns/locale/nl";
|
||||
import { pl } from "date-fns/locale/pl";
|
||||
import { ptBR } from "date-fns/locale/pt-BR";
|
||||
import { ru } from "date-fns/locale/ru";
|
||||
import { zhCN } from "date-fns/locale/zh-CN";
|
||||
import type { MonthYear } from "~/features/plus-voting/core";
|
||||
import type { LanguageCode } from "~/modules/i18n/config";
|
||||
import type { DayMonthYear } from "./zod";
|
||||
|
||||
const LOCALE_MAP: Record<LanguageCode, Locale> = {
|
||||
da,
|
||||
de,
|
||||
en: enUS,
|
||||
"es-ES": es,
|
||||
"es-US": es,
|
||||
"fr-CA": frCA,
|
||||
"fr-EU": fr,
|
||||
he,
|
||||
it,
|
||||
ja,
|
||||
ko,
|
||||
nl,
|
||||
pl,
|
||||
"pt-BR": ptBR,
|
||||
ru,
|
||||
zh: zhCN,
|
||||
};
|
||||
|
||||
export function getDateFnsLocale(language: string) {
|
||||
return LOCALE_MAP[language as keyof typeof LOCALE_MAP] ?? enUS;
|
||||
}
|
||||
|
||||
export function formatDistanceToNow(
|
||||
date: Parameters<typeof dateFnsFormatDistanceToNow>[0],
|
||||
options: Omit<
|
||||
NonNullable<Parameters<typeof dateFnsFormatDistanceToNow>[1]>,
|
||||
"locale"
|
||||
> & { language: string },
|
||||
) {
|
||||
return dateFnsFormatDistanceToNow(date, {
|
||||
...options,
|
||||
locale: getDateFnsLocale(options.language),
|
||||
});
|
||||
}
|
||||
|
||||
export function databaseTimestampToDate(timestamp: number) {
|
||||
return new Date(databaseTimestampToJavascriptTimestamp(timestamp));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user