mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-19 13:40:41 -05:00
* Kysely initial * Badges initial * Badge routes migrated * Badges migrated * Calendar work * Fix one type problem * Calendar work * findResultsByUserId work * Calendar reworking finished * PlusSuggestions work * Migrated suggestions * Builds progress * Migrated builds * Admin migrated * Migrate articles * User search * Faster getUser * Selectable/insertable as global * Refresh prod db script + patronTier index * identifierToUserId * updateProfile * findByIdentifier * More indexes * User upsert * upsertLite * findAllPlusMembers * updateResultHighlights * updateMany * User finished migration * Fix types * Fix PlusVotingResult typing * PlusVotingRepository WIP * Migrated resultsByMonthYear * Migrated plusVotes (done with db. related migrations) * Plus code to features folder * Fix TODOs * Export * Fix range * Migrate some user pages * Move rest user routes * Move /play * Map list generator * Front page * Move map list generation logic * Move plus voting logic * Info * API * Adjust TODOs * theme * Auth * Remove TODO
141 lines
3.5 KiB
TypeScript
141 lines
3.5 KiB
TypeScript
import clsx from "clsx";
|
|
import * as React from "react";
|
|
import { type AxisOptions, Chart as ReactChart } from "react-charts";
|
|
import type { TooltipRendererProps } from "react-charts/types/components/TooltipRenderer";
|
|
import { useTranslation } from "~/hooks/useTranslation";
|
|
import { useIsMounted } from "~/hooks/useIsMounted";
|
|
import { Theme, useTheme } from "~/features/theme/core/provider";
|
|
|
|
export default function Chart({
|
|
options,
|
|
containerClassName,
|
|
headerSuffix,
|
|
valueSuffix,
|
|
}: {
|
|
options: [
|
|
{ label: string; data: Array<{ primary: Date; secondary: number }> },
|
|
];
|
|
containerClassName?: string;
|
|
headerSuffix?: string;
|
|
valueSuffix?: string;
|
|
}) {
|
|
const theme = useTheme();
|
|
const isMounted = useIsMounted();
|
|
|
|
const primaryAxis = React.useMemo<
|
|
AxisOptions<(typeof options)[number]["data"][number]>
|
|
>(
|
|
() => ({
|
|
getValue: (datum) => datum.primary,
|
|
}),
|
|
[],
|
|
);
|
|
|
|
const secondaryAxes = React.useMemo<
|
|
AxisOptions<(typeof options)[number]["data"][number]>[]
|
|
>(
|
|
() => [
|
|
{
|
|
getValue: (datum) => datum.secondary,
|
|
},
|
|
],
|
|
[],
|
|
);
|
|
|
|
if (!isMounted) {
|
|
return <div className={clsx("chart__container", containerClassName)} />;
|
|
}
|
|
|
|
return (
|
|
<div className={clsx("chart__container", containerClassName)}>
|
|
<ReactChart
|
|
options={{
|
|
data: options,
|
|
tooltip: {
|
|
render: (props) => (
|
|
<ChartTooltip
|
|
{...props}
|
|
headerSuffix={headerSuffix}
|
|
valueSuffix={valueSuffix}
|
|
/>
|
|
),
|
|
},
|
|
primaryAxis,
|
|
secondaryAxes,
|
|
dark: theme.htmlThemeClass === Theme.DARK,
|
|
defaultColors: [
|
|
"var(--theme)",
|
|
"var(--theme-secondary)",
|
|
"var(--theme-info)",
|
|
],
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface ChartTooltipProps extends TooltipRendererProps<any> {
|
|
headerSuffix?: string;
|
|
valueSuffix?: string;
|
|
}
|
|
|
|
function ChartTooltip({
|
|
focusedDatum,
|
|
headerSuffix = "",
|
|
valueSuffix = "",
|
|
}: ChartTooltipProps) {
|
|
const { i18n } = useTranslation();
|
|
const dataPoints = focusedDatum?.interactiveGroup ?? [];
|
|
|
|
const header = () => {
|
|
const primaryValue = dataPoints[0]?.primaryValue;
|
|
if (!primaryValue) return null;
|
|
|
|
if (primaryValue instanceof Date) {
|
|
return primaryValue.toLocaleDateString(i18n.language, {
|
|
weekday: "short",
|
|
day: "numeric",
|
|
month: "long",
|
|
});
|
|
}
|
|
|
|
return primaryValue;
|
|
};
|
|
|
|
return (
|
|
<div className="chart__tooltip">
|
|
<h3 className="text-center text-md">
|
|
{header()}
|
|
{headerSuffix}
|
|
</h3>
|
|
{dataPoints.map((dataPoint, index) => {
|
|
const color = dataPoint.style?.fill ?? "var(--theme)";
|
|
|
|
return (
|
|
<div key={index} className="stack horizontal items-center sm">
|
|
<div
|
|
className={clsx("chart__dot", {
|
|
chart__dot__focused:
|
|
focusedDatum?.seriesId === dataPoint.seriesId,
|
|
})}
|
|
style={
|
|
{
|
|
"--dot-color": color,
|
|
"--dot-color-outline": color.replace(")", "-transparent)"),
|
|
} as any
|
|
}
|
|
/>
|
|
<div className="chart__tooltip__label">
|
|
{dataPoint.originalSeries.label}
|
|
</div>
|
|
<div className="chart__tooltip__value">
|
|
{dataPoint.secondaryValue}
|
|
{valueSuffix}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|