mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-11 16:58:25 +03:00
Big Commit
This commit is contained in:
+1
-1
@@ -75,7 +75,7 @@
|
||||
"resolve": "1.12.0",
|
||||
"resolve-url-loader": "3.1.0",
|
||||
"socicon": "3.0.5",
|
||||
"tachi-common": "0.2.9"
|
||||
"tachi-common": "0.2.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/humanize-duration": "3.25.1",
|
||||
|
||||
Generated
+4
-4
@@ -77,7 +77,7 @@ specifiers:
|
||||
serve: 11.2.0
|
||||
socicon: 3.0.5
|
||||
style-loader: 1.0.0
|
||||
tachi-common: 0.2.9
|
||||
tachi-common: 0.2.12
|
||||
terser-webpack-plugin: 1.4.1
|
||||
ts-pnp: 1.1.4
|
||||
typescript: 4.3.5
|
||||
@@ -142,7 +142,7 @@ dependencies:
|
||||
resolve: 1.12.0
|
||||
resolve-url-loader: 3.1.0
|
||||
socicon: 3.0.5
|
||||
tachi-common: 0.2.9
|
||||
tachi-common: 0.2.12
|
||||
|
||||
devDependencies:
|
||||
'@types/humanize-duration': 3.25.1
|
||||
@@ -11178,8 +11178,8 @@ packages:
|
||||
strip-ansi: 6.0.0
|
||||
dev: true
|
||||
|
||||
/tachi-common/0.2.9:
|
||||
resolution: {integrity: sha512-Z7oEv5OorOSB9VBJALzM3yaKxBUWNQGSJihLz923CNX5Wndi1L84LlLYgYXOZ5JrrnUFsSK374kaeODd3X/nEQ==}
|
||||
/tachi-common/0.2.12:
|
||||
resolution: {integrity: sha512-xwbQUZefLUs1sus3nrrys84qJyRMWLl/Mb4UzFYd74n0ZmOejrxpwIb18ILWww4J/IxQurPd4Id+DCP12SEW1w==}
|
||||
dependencies:
|
||||
monk: 7.3.4
|
||||
transitivePeerDependencies:
|
||||
|
||||
+2
-5
@@ -169,6 +169,7 @@ function TableFolderTable({
|
||||
return (
|
||||
<TachiTable
|
||||
dataset={dataset}
|
||||
pageLen={25}
|
||||
headers={[
|
||||
["Folder", "Folder", StrSOV(x => x.folder.title)],
|
||||
["Chart Count", "Charts", NumericSOV(x => x.stats.chartCount)],
|
||||
@@ -250,8 +251,6 @@ function TableBarChart({
|
||||
return arr.reverse();
|
||||
}, [dataMap, mode]);
|
||||
|
||||
console.log(dataset);
|
||||
|
||||
return (
|
||||
<Card header="Overview">
|
||||
<div className="row">
|
||||
@@ -321,8 +320,6 @@ function OverviewBarChart({
|
||||
[dataset]
|
||||
);
|
||||
|
||||
console.log(longestTitle);
|
||||
|
||||
return (
|
||||
<ResponsiveBar
|
||||
indexBy="folder"
|
||||
@@ -352,7 +349,7 @@ function OverviewBarChart({
|
||||
minValue={0}
|
||||
maxValue={100}
|
||||
valueFormat={v => `${v.toFixed(2)}%`}
|
||||
margin={{ left: 10 + longestTitle.length * 10, bottom: 50, top: 20, right: 20 }}
|
||||
margin={{ left: 10 + longestTitle.length * 7, bottom: 50, top: 20, right: 20 }}
|
||||
layout="horizontal"
|
||||
axisBottom={{
|
||||
tickSize: 5,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { FormatGame, GetGameConfig, PublicUserDocument } from "tachi-common";
|
||||
import { GamePT } from "types/react";
|
||||
import FolderSelectPage from "./FolderSelectPage";
|
||||
import FolderTablePage from "./FolderTablePage";
|
||||
import SpecificFolderPage from "./SpecificFolderPage";
|
||||
|
||||
type Props = { reqUser: PublicUserDocument } & GamePT;
|
||||
|
||||
@@ -47,6 +48,12 @@ export default function FoldersMainPage({ reqUser, game, playtype }: Props) {
|
||||
>
|
||||
<FolderSelectPage {...{ reqUser, game, playtype }} />
|
||||
</Route>
|
||||
<Route
|
||||
exact
|
||||
path="/dashboard/users/:userID/games/:game/:playtype/folders/:folderID"
|
||||
>
|
||||
<SpecificFolderPage {...{ reqUser, game, playtype }} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
import { ResponsiveBar } from "@nivo/bar";
|
||||
import { BarChartTooltip } from "components/charts/ChartTooltip";
|
||||
import Card from "components/layout/page/Card";
|
||||
import FolderTable from "components/tables/folders/FolderTable";
|
||||
import ApiError from "components/util/ApiError";
|
||||
import Divider from "components/util/Divider";
|
||||
import Loading from "components/util/Loading";
|
||||
import useApiQuery from "components/util/query/useApiQuery";
|
||||
import React, { useMemo } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { Game, GetGamePTConfig, PublicUserDocument } from "tachi-common";
|
||||
import { UGPTFolderReturns } from "types/api-returns";
|
||||
import { FolderDataset } from "types/tables";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { DEFAULT_BAR_PROPS } from "util/charts";
|
||||
import { ChangeOpacity } from "util/color-opacity";
|
||||
import { CreateChartIDMap, CreateSongMap } from "util/data";
|
||||
import { ComposeExpFn, ComposeInverseExpFn } from "util/misc";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
|
||||
interface Props {
|
||||
reqUser: PublicUserDocument;
|
||||
game: Game;
|
||||
playtype: Playtype;
|
||||
}
|
||||
|
||||
export default function SpecificFolderPage({ reqUser, game, playtype }: Props) {
|
||||
const { folderID } = useParams<{ folderID: string }>();
|
||||
|
||||
const { data, isLoading, error } = useApiQuery<UGPTFolderReturns>(
|
||||
`/users/${reqUser.id}/games/${game}/${playtype}/folders/${folderID}`
|
||||
);
|
||||
|
||||
const folderDataset = useMemo(() => {
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const songMap = CreateSongMap(data.songs);
|
||||
const pbMap = CreateChartIDMap(data.pbs);
|
||||
|
||||
const folderDataset: FolderDataset = [];
|
||||
|
||||
for (const chart of data.charts) {
|
||||
folderDataset.push({
|
||||
...chart,
|
||||
__related: {
|
||||
pb: pbMap.get(chart.chartID) ?? null,
|
||||
song: songMap.get(chart.songID)!,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
folderDataset.sort(StrSOV(x => x.__related.song.title));
|
||||
|
||||
return folderDataset;
|
||||
}, [data]);
|
||||
|
||||
if (isLoading || !data || !folderDataset) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <ApiError error={error} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<Divider className="mb-4" />
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<FolderInfoHeader {...{ folderDataset, data, game, playtype, reqUser }} />
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<Divider className="my-4" />
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<FolderTable
|
||||
dataset={folderDataset}
|
||||
game={game}
|
||||
playtype={playtype}
|
||||
reqUser={reqUser}
|
||||
indexCol={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function FolderInfoHeader({
|
||||
game,
|
||||
playtype,
|
||||
reqUser,
|
||||
folderDataset,
|
||||
data,
|
||||
}: Props & { folderDataset: FolderDataset; data: UGPTFolderReturns }) {
|
||||
const dataset = [];
|
||||
|
||||
const expScale = 1;
|
||||
|
||||
const expFn = ComposeExpFn(expScale);
|
||||
const invExpFn = ComposeInverseExpFn(expScale);
|
||||
|
||||
for (const data of folderDataset) {
|
||||
const value = data.__related.pb ? expFn(data.__related.pb.scoreData.percent) : 0;
|
||||
dataset.push({
|
||||
chartID: data.chartID,
|
||||
expValue: expFn(value),
|
||||
value,
|
||||
grade: data.__related.pb?.scoreData.grade,
|
||||
});
|
||||
}
|
||||
|
||||
dataset.sort(NumericSOV(x => x.expValue));
|
||||
|
||||
const dataMap = CreateChartIDMap(folderDataset);
|
||||
|
||||
const gptConfig = GetGamePTConfig(game, playtype);
|
||||
|
||||
return (
|
||||
<Card header={`${reqUser.username}'s ${data.folder.title} Breakdown`}>
|
||||
<div style={{ height: 400 }}>
|
||||
<ResponsiveBar
|
||||
indexBy="chartID"
|
||||
tooltip={d => (
|
||||
<BarChartTooltip
|
||||
point={d}
|
||||
renderFn={d => {
|
||||
const data = dataMap.get(d.indexValue as string)!;
|
||||
|
||||
return (
|
||||
<div className="w-100 text-center">
|
||||
{data.__related.song.title}
|
||||
<br />
|
||||
{data.__related.pb?.scoreData.percent.toFixed(2)}%
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
key={"value"}
|
||||
// @ts-expect-error temp
|
||||
|
||||
colors={k => ChangeOpacity(gptConfig.gradeColours[k.data.grade], 0.5)}
|
||||
// @ts-expect-error temp
|
||||
|
||||
borderColor={k => gptConfig.gradeColours[k.data.grade]}
|
||||
borderWidth={1}
|
||||
padding={0.2}
|
||||
// @ts-expect-error temp
|
||||
data={dataset}
|
||||
minValue={0}
|
||||
maxValue={expFn(100)}
|
||||
margin={{ left: 50, top: 20, bottom: 20 }}
|
||||
axisLeft={{
|
||||
tickValues: gptConfig.gradeBoundaries.map(e => (e === 0 ? 0 : expFn(e))),
|
||||
format: x => {
|
||||
let nearest;
|
||||
|
||||
const lgv = invExpFn(x);
|
||||
|
||||
for (const [i, gradeBnd] of gptConfig.gradeBoundaries.entries()) {
|
||||
if (Math.abs(gradeBnd - lgv) < 0.00005) {
|
||||
nearest = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return gptConfig.grades[nearest];
|
||||
},
|
||||
}}
|
||||
axisBottom={null}
|
||||
{...DEFAULT_BAR_PROPS}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -36,14 +36,14 @@ export default function ClassBadge<I extends IDStrings = IDStrings>({
|
||||
|
||||
if (data.mouseover && showSetOnHover) {
|
||||
return (
|
||||
<QuickTooltip text={`${UppercaseFirst(classSet)}: ${data.mouseover}`}>
|
||||
<QuickTooltip tooltipContent={`${UppercaseFirst(classSet)}: ${data.mouseover}`}>
|
||||
{badgeComponent}
|
||||
</QuickTooltip>
|
||||
);
|
||||
} else if (data.mouseover) {
|
||||
return <QuickTooltip text={data.mouseover}>{badgeComponent}</QuickTooltip>;
|
||||
return <QuickTooltip tooltipContent={data.mouseover}>{badgeComponent}</QuickTooltip>;
|
||||
} else if (showSetOnHover) {
|
||||
<QuickTooltip text={UppercaseFirst(classSet)}>{badgeComponent}</QuickTooltip>;
|
||||
<QuickTooltip tooltipContent={UppercaseFirst(classSet)}>{badgeComponent}</QuickTooltip>;
|
||||
}
|
||||
|
||||
return badgeComponent;
|
||||
|
||||
@@ -63,7 +63,7 @@ function GPTSearchResult({
|
||||
}}
|
||||
>
|
||||
<QuickTooltip
|
||||
text={`Go to ${user.username}'s ${FormatGame(
|
||||
tooltipContent={`Go to ${user.username}'s ${FormatGame(
|
||||
game,
|
||||
playtype
|
||||
)} profile, if they have one.`}
|
||||
|
||||
@@ -5,10 +5,10 @@ import { JustChildren } from "types/react";
|
||||
|
||||
export default function QuickTooltip({
|
||||
children,
|
||||
text,
|
||||
}: { text: string } & { children: JSX.Element }) {
|
||||
tooltipContent,
|
||||
}: { tooltipContent: React.ReactChild } & { children: JSX.Element }) {
|
||||
return (
|
||||
<OverlayTrigger placement="top" overlay={<Tooltip id={nanoid()}>{text}</Tooltip>}>
|
||||
<OverlayTrigger placement="top" overlay={<Tooltip id={nanoid()}>{tooltipContent}</Tooltip>}>
|
||||
{children}
|
||||
</OverlayTrigger>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import { OverlayTrigger } from "react-bootstrap";
|
||||
import { Link } from "react-router-dom";
|
||||
import QuickTooltip from "../misc/QuickTooltip";
|
||||
|
||||
@@ -17,7 +16,7 @@ export default function CardNavButton({
|
||||
}
|
||||
|
||||
return (
|
||||
<QuickTooltip text={hoverText}>
|
||||
<QuickTooltip tooltipContent={hoverText}>
|
||||
<Link className={`fas fa-${type} h3 card-nav-icon`} to={to} />
|
||||
</QuickTooltip>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import React from "react";
|
||||
import { ChartDocument, Game, COLOUR_SET } from "tachi-common";
|
||||
import { ChangeOpacity } from "util/color-opacity";
|
||||
import { FormatBMSTables } from "util/misc";
|
||||
import TierlistInfoPart from "./TierlistInfoPart";
|
||||
|
||||
export default function BMSDifficultyCell({
|
||||
chart,
|
||||
@@ -20,8 +21,9 @@ export default function BMSDifficultyCell({
|
||||
}}
|
||||
>
|
||||
<span>{levelText}</span>
|
||||
<TierlistInfoPart chart={chart} />
|
||||
{!chart.isPrimary && (
|
||||
<QuickTooltip text="This chart is an alternate, old chart.">
|
||||
<QuickTooltip tooltipContent="This chart is an alternate, old chart.">
|
||||
<div>
|
||||
<Icon type="exclamation-triangle" />
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import QuickTooltip from "components/layout/misc/QuickTooltip";
|
||||
import Icon from "components/util/Icon";
|
||||
import Muted from "components/util/Muted";
|
||||
import React from "react";
|
||||
import {
|
||||
ChartDocument,
|
||||
@@ -9,6 +10,7 @@ import {
|
||||
GetGamePTConfig,
|
||||
} from "tachi-common";
|
||||
import { ChangeOpacity } from "util/color-opacity";
|
||||
import TierlistInfoPart from "./TierlistInfoPart";
|
||||
|
||||
export default function DifficultyCell({
|
||||
game,
|
||||
@@ -28,13 +30,18 @@ export default function DifficultyCell({
|
||||
}}
|
||||
>
|
||||
{!alwaysShort && (
|
||||
<span className="d-none d-lg-block">{FormatDifficulty(chart, game)}</span>
|
||||
<>
|
||||
<span className="d-none d-lg-block">{FormatDifficulty(chart, game)}</span>
|
||||
{Object.keys(chart.tierlistInfo).length > 0 && (
|
||||
<TierlistInfoPart chart={chart} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<span className={!alwaysShort ? "d-lg-none" : ""}>
|
||||
{FormatDifficultyShort(chart, game)}
|
||||
</span>
|
||||
{!chart.isPrimary && (
|
||||
<QuickTooltip text="This chart is an alternate, old chart.">
|
||||
<QuickTooltip tooltipContent="This chart is an alternate, old chart.">
|
||||
<div>
|
||||
<Icon type="exclamation-triangle" />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import React from "react";
|
||||
import { ChangeOpacity } from "util/color-opacity";
|
||||
|
||||
export default function IndicatorsCell({ highlight }: { highlight: boolean }) {
|
||||
return (
|
||||
<td
|
||||
style={{
|
||||
backgroundColor: highlight ? ChangeOpacity("#e6a303", 0.5) : "#383838",
|
||||
maxWidth: 5,
|
||||
}}
|
||||
></td>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import QuickTooltip from "components/layout/misc/QuickTooltip";
|
||||
import Icon from "components/util/Icon";
|
||||
import Muted from "components/util/Muted";
|
||||
import React from "react";
|
||||
import { ChartDocument } from "tachi-common";
|
||||
import MiniTable from "../components/MiniTable";
|
||||
|
||||
// I hate the fact object.keys doesnt infer types.
|
||||
type K = keyof ChartDocument["tierlistInfo"];
|
||||
|
||||
export default function TierlistInfoPart({ chart }: { chart: ChartDocument }) {
|
||||
const keys = Object.keys(chart.tierlistInfo) as K[];
|
||||
|
||||
return (
|
||||
<QuickTooltip
|
||||
tooltipContent={
|
||||
<MiniTable className="table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tierlist</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{keys.map(k => (
|
||||
<tr key={k}>
|
||||
<td>{k}</td>
|
||||
<td>
|
||||
{chart.tierlistInfo[k]!.text} ({chart.tierlistInfo[k]!.value})
|
||||
{chart.tierlistInfo[k]!.individualDifference && (
|
||||
<>
|
||||
<br />
|
||||
<Icon type="balance-scale-left" />
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</MiniTable>
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<Muted>{keys.map(k => chart.tierlistInfo[k]!.text).join(" / ")}</Muted>
|
||||
</div>
|
||||
</QuickTooltip>
|
||||
);
|
||||
}
|
||||
@@ -7,7 +7,11 @@ import React, { useState } from "react";
|
||||
import { Modal, OverlayTrigger, Tooltip } from "react-bootstrap";
|
||||
import { GetValueGetter, ValueGetterOrHybrid } from "util/ztable/search";
|
||||
|
||||
function AdditionalTableProps({ value }: { value: string | number | [string, number] | null }) {
|
||||
function AdditionalTableProps({
|
||||
value,
|
||||
}: {
|
||||
value: string | number | [string, number] | boolean | null;
|
||||
}) {
|
||||
let typeName;
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
@@ -16,6 +20,8 @@ function AdditionalTableProps({ value }: { value: string | number | [string, num
|
||||
typeName = "Text";
|
||||
} else if (value === null) {
|
||||
typeName = "Cannot Infer :(";
|
||||
} else if (typeof value === "boolean") {
|
||||
typeName = "Presence";
|
||||
} else {
|
||||
typeName = "Number";
|
||||
}
|
||||
@@ -23,7 +29,13 @@ function AdditionalTableProps({ value }: { value: string | number | [string, num
|
||||
return (
|
||||
<>
|
||||
<td>{typeName}</td>
|
||||
<td>{Array.isArray(value) ? `${value[0]} (${value[1]})` : value}</td>
|
||||
<td>
|
||||
{typeof value === "boolean"
|
||||
? "Yes/No/True/False"
|
||||
: Array.isArray(value)
|
||||
? `${value[0]} (${value[1]})`
|
||||
: value}
|
||||
</td>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ export default function SelectableRating<I extends IDStrings>({
|
||||
color: "#ffffff",
|
||||
fontSize: "inherit",
|
||||
font: "inherit",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{gptConfig[key].map(s => (
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { PBScoreDocument, ScoreDocument } from "tachi-common";
|
||||
import { PBDataset, ScoreDataset } from "types/tables";
|
||||
|
||||
export function useScoreState(sc: ScoreDataset[0]) {
|
||||
@@ -13,7 +14,7 @@ export function useScoreState(sc: ScoreDataset[0]) {
|
||||
return { highlight, comment, setHighlight, setComment };
|
||||
}
|
||||
|
||||
export function usePBState(pb: PBDataset[0]) {
|
||||
export function usePBState(pb: PBScoreDocument) {
|
||||
const [highlight, setHighlight] = useState(pb.highlight);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { APIFetchV1 } from "util/api";
|
||||
import { SpecificSessionReturns } from "types/api-returns";
|
||||
import Loading from "components/util/Loading";
|
||||
import DebugContent from "components/util/DebugContent";
|
||||
import { CreateChartMap, CreateScoreMap, CreateSongMap } from "util/data";
|
||||
import { CreateChartMap, CreateChartIDMap, CreateSongMap } from "util/data";
|
||||
import {
|
||||
Lamps,
|
||||
Grades,
|
||||
@@ -236,7 +236,7 @@ function SessionScoreStatBreakdown({
|
||||
}) {
|
||||
const songMap = CreateSongMap(sessionData.songs);
|
||||
const chartMap = CreateChartMap(sessionData.charts);
|
||||
const scoreMap = CreateScoreMap(sessionData.scores);
|
||||
const scoreMap = CreateChartIDMap(sessionData.scores);
|
||||
|
||||
const [newLamps, newGrades] = useMemo(() => {
|
||||
const newLamps: Partial<Record<
|
||||
|
||||
@@ -34,14 +34,14 @@ export default function ScoreEditButtons({
|
||||
<div className="btn-group">
|
||||
{comment ? (
|
||||
<>
|
||||
<QuickTooltip text="Edit your comment on this score.">
|
||||
<QuickTooltip tooltipContent="Edit your comment on this score.">
|
||||
<Button variant="outline-secondary" onClick={() => setShow(true)}>
|
||||
<Icon noPad type="file-signature" />
|
||||
</Button>
|
||||
</QuickTooltip>
|
||||
</>
|
||||
) : (
|
||||
<QuickTooltip text="Comment on this score.">
|
||||
<QuickTooltip tooltipContent="Comment on this score.">
|
||||
<Button variant="outline-secondary" onClick={() => setShow(true)}>
|
||||
<Icon noPad type="file-signature" />
|
||||
</Button>
|
||||
@@ -49,7 +49,7 @@ export default function ScoreEditButtons({
|
||||
)}
|
||||
|
||||
{highlight ? (
|
||||
<QuickTooltip text="Unhighlight this score.">
|
||||
<QuickTooltip tooltipContent="Unhighlight this score.">
|
||||
<Button
|
||||
variant="success"
|
||||
onClick={() =>
|
||||
@@ -65,7 +65,7 @@ export default function ScoreEditButtons({
|
||||
</Button>
|
||||
</QuickTooltip>
|
||||
) : (
|
||||
<QuickTooltip text="Highlight this score.">
|
||||
<QuickTooltip tooltipContent="Highlight this score.">
|
||||
<Button
|
||||
variant="outline-secondary"
|
||||
onClick={() =>
|
||||
@@ -167,7 +167,7 @@ function CommentModal({
|
||||
</div>
|
||||
</Form.Group>
|
||||
|
||||
<QuickTooltip text="Remove your comment on this score.">
|
||||
<QuickTooltip tooltipContent="Remove your comment on this score.">
|
||||
<Button
|
||||
variant="outline-danger"
|
||||
onClick={() =>
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
import React from "react";
|
||||
import { Game, PublicUserDocument } from "tachi-common";
|
||||
import { FolderDataset } from "types/tables";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { CreateDefaultFolderSearchParams } from "util/tables/create-search";
|
||||
import BMSDifficultyCell from "../cells/BMSDifficultyCell";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import { usePBState } from "../components/UseScoreState";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import BMSScoreCoreCells from "../game-core-cells/BMSScoreCoreCells";
|
||||
import { FolderIndicatorHeader } from "../headers/IndicatorHeader";
|
||||
|
||||
export default function BMSFolderTable({
|
||||
dataset,
|
||||
reqUser,
|
||||
game,
|
||||
playtype,
|
||||
}: {
|
||||
dataset: FolderDataset<"bms:7K" | "bms:14K">;
|
||||
reqUser: PublicUserDocument;
|
||||
game: Game;
|
||||
playtype: Playtype;
|
||||
}) {
|
||||
const headers: Header<FolderDataset<"bms:7K" | "bms:14K">[0]>[] = [
|
||||
[
|
||||
"Chart",
|
||||
"Ch.",
|
||||
NumericSOV(
|
||||
x =>
|
||||
x.tierlistInfo["sgl-EC"]?.value ?? x.tierlistInfo["sgl-HC"]?.value ?? x.levelNum
|
||||
),
|
||||
],
|
||||
FolderIndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.__related.pb?.scoreData.percent ?? -Infinity)],
|
||||
["Deltas", "Deltas", NumericSOV(x => x.__related.pb?.scoreData.percent ?? -Infinity)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.__related.pb?.scoreData.lampIndex ?? -Infinity)],
|
||||
["Sieglinde", "sgl.", NumericSOV(x => x.__related.pb?.calculatedData.sieglinde ?? 0)],
|
||||
[
|
||||
"Site Ranking",
|
||||
"Site Rank",
|
||||
NumericSOV(x => x.__related.pb?.rankingData.rank ?? -Infinity),
|
||||
],
|
||||
["Last Raised", "Last Raised", NumericSOV(x => x.__related.pb?.timeAchieved ?? 0)],
|
||||
];
|
||||
|
||||
return (
|
||||
<TachiTable
|
||||
dataset={dataset}
|
||||
headers={headers}
|
||||
entryName="Charts"
|
||||
searchFunctions={CreateDefaultFolderSearchParams(game, playtype)}
|
||||
rowFunction={data => (
|
||||
<Row data={data} key={data.chartID} reqUser={reqUser} game={game} />
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function Row({
|
||||
data,
|
||||
reqUser,
|
||||
game,
|
||||
}: {
|
||||
data: FolderDataset<"bms:7K" | "bms:14K">[0];
|
||||
reqUser: PublicUserDocument;
|
||||
game: Game;
|
||||
}) {
|
||||
const score = data.__related.pb;
|
||||
|
||||
if (!score) {
|
||||
return (
|
||||
<tr>
|
||||
<BMSDifficultyCell chart={data} />
|
||||
<IndicatorsCell highlight={false} />
|
||||
<TitleCell song={data.__related.song} chart={data} game={game} />
|
||||
<td colSpan={6}>Not Played.</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
// screw the rules of hooks
|
||||
const scoreState = usePBState(score);
|
||||
|
||||
return (
|
||||
<DropdownRow
|
||||
dropdown={
|
||||
<GenericPBDropdown
|
||||
chart={data}
|
||||
reqUser={reqUser}
|
||||
game={game}
|
||||
playtype={data.playtype}
|
||||
scoreState={scoreState}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<BMSDifficultyCell chart={data} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell song={data.__related.song} chart={data} game={game} />
|
||||
<BMSScoreCoreCells sc={score} />
|
||||
<RankingCell rankingData={score.rankingData} />
|
||||
<TimestampCell time={score.timeAchieved} />
|
||||
</DropdownRow>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from "react";
|
||||
import { IDStrings, PublicUserDocument, ScoreCalculatedDataLookup } from "tachi-common";
|
||||
import { GamePT } from "types/react";
|
||||
import { FolderDataset } from "types/tables";
|
||||
import BMSFolderTable from "./BMSFolderTable";
|
||||
import GenericFolderTable from "./GenericFolderTable";
|
||||
import IIDXFolderTable from "./IIDXFolderTable";
|
||||
import MusecaFolderTable from "./MusecaFolderTable";
|
||||
import SDVXFolderTable from "./SDVXFolderTable";
|
||||
|
||||
export default function FolderTable({
|
||||
dataset,
|
||||
indexCol = true,
|
||||
reqUser,
|
||||
playtype,
|
||||
showPlaycount,
|
||||
game,
|
||||
alg,
|
||||
}: {
|
||||
dataset: FolderDataset;
|
||||
indexCol?: boolean;
|
||||
showPlaycount?: boolean;
|
||||
reqUser: PublicUserDocument;
|
||||
alg?: ScoreCalculatedDataLookup[IDStrings];
|
||||
} & GamePT) {
|
||||
// We're just going to ignore all these errors
|
||||
// and assume we just won't make a mistake.
|
||||
// ever.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const props = { dataset, indexCol, reqUser, playtype, showPlaycount, alg, game } as any;
|
||||
|
||||
if (game === "iidx") {
|
||||
return <IIDXFolderTable {...props} />;
|
||||
} else if (game === "bms") {
|
||||
return <BMSFolderTable {...props} />;
|
||||
} else if (game === "sdvx" || game === "usc") {
|
||||
return <SDVXFolderTable {...props} />;
|
||||
} else if (game === "maimai") {
|
||||
return <GenericFolderTable {...props} game={game} playtype={playtype} showScore={false} />;
|
||||
} else if (game === "museca") {
|
||||
return <MusecaFolderTable {...props} />;
|
||||
}
|
||||
|
||||
return <GenericFolderTable {...props} />;
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
import React from "react";
|
||||
import { COLOUR_SET, Game, GetGamePTConfig, PublicUserDocument } from "tachi-common";
|
||||
import { FolderDataset } from "types/tables";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { ChangeOpacity } from "util/color-opacity";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { CreateDefaultFolderSearchParams } from "util/tables/create-search";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import RatingCell from "../cells/RatingCell";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import { usePBState } from "../components/UseScoreState";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import { FolderIndicatorHeader } from "../headers/IndicatorHeader";
|
||||
|
||||
export default function GenericFolderTable({
|
||||
dataset,
|
||||
reqUser,
|
||||
game,
|
||||
playtype,
|
||||
showScore,
|
||||
}: {
|
||||
dataset: FolderDataset;
|
||||
reqUser: PublicUserDocument;
|
||||
game: Game;
|
||||
playtype: Playtype;
|
||||
showScore?: boolean;
|
||||
}) {
|
||||
const gptConfig = GetGamePTConfig(game, playtype);
|
||||
|
||||
const headers: Header<FolderDataset[0]>[] = [
|
||||
["Chart", "Ch.", NumericSOV(x => x.levelNum)],
|
||||
FolderIndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.__related.pb?.scoreData.percent ?? -Infinity)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.__related.pb?.scoreData.lampIndex ?? -Infinity)],
|
||||
[
|
||||
gptConfig.defaultScoreRatingAlg,
|
||||
gptConfig.defaultScoreRatingAlg,
|
||||
NumericSOV(
|
||||
x => x.__related.pb?.calculatedData[gptConfig.defaultScoreRatingAlg] ?? -Infinity
|
||||
),
|
||||
],
|
||||
[
|
||||
"Site Ranking",
|
||||
"Site Rank",
|
||||
NumericSOV(x => x.__related.pb?.rankingData.rank ?? -Infinity),
|
||||
],
|
||||
["Last Raised", "Last Raised", NumericSOV(x => x.__related.pb?.timeAchieved ?? -Infinity)],
|
||||
];
|
||||
|
||||
return (
|
||||
<TachiTable
|
||||
dataset={dataset}
|
||||
headers={headers}
|
||||
entryName="Charts"
|
||||
searchFunctions={CreateDefaultFolderSearchParams(game, playtype)}
|
||||
rowFunction={data => (
|
||||
<Row
|
||||
data={data}
|
||||
key={data.chartID}
|
||||
reqUser={reqUser}
|
||||
showScore={showScore}
|
||||
game={game}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function Row({
|
||||
data,
|
||||
reqUser,
|
||||
showScore,
|
||||
game,
|
||||
}: {
|
||||
data: FolderDataset[0];
|
||||
reqUser: PublicUserDocument;
|
||||
showScore?: boolean;
|
||||
game: Game;
|
||||
}) {
|
||||
const score = data.__related.pb;
|
||||
|
||||
if (!score) {
|
||||
return (
|
||||
<tr>
|
||||
<DifficultyCell game={game} chart={data} />
|
||||
<IndicatorsCell highlight={false} />
|
||||
<TitleCell song={data.__related.song} chart={data} game={game} />
|
||||
<td colSpan={5}>Not Played.</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
// screw the rules of hooks
|
||||
const scoreState = usePBState(score);
|
||||
|
||||
return (
|
||||
<DropdownRow
|
||||
dropdown={
|
||||
<GenericPBDropdown
|
||||
chart={data}
|
||||
reqUser={reqUser}
|
||||
game={game}
|
||||
playtype={data.playtype}
|
||||
scoreState={scoreState}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<DifficultyCell game={game} chart={data} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell song={data.__related.song} chart={data} game={game} />
|
||||
<ScoreCell score={score} showScore={showScore} />
|
||||
<LampCell score={score} />
|
||||
<RatingCell score={score} />
|
||||
<RankingCell rankingData={score.rankingData} />
|
||||
<TimestampCell time={score.timeAchieved} />
|
||||
</DropdownRow>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
import useScoreRatingAlg from "components/util/useScoreRatingAlg";
|
||||
import { nanoid } from "nanoid";
|
||||
import React, { useState } from "react";
|
||||
import { Game, PublicUserDocument, ScoreCalculatedDataLookup } from "tachi-common";
|
||||
import { FolderDataset } from "types/tables";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { CreateDefaultFolderSearchParams } from "util/tables/create-search";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import SelectableRating from "../components/SelectableRating";
|
||||
import TachiTable, { Header, ZTableTHProps } from "../components/TachiTable";
|
||||
import { usePBState } from "../components/UseScoreState";
|
||||
import IIDXPBDropdown from "../dropdowns/IIDXPBDropdown";
|
||||
import IIDXScoreCoreCells from "../game-core-cells/IIDXScoreCoreCells";
|
||||
import { FolderIndicatorHeader } from "../headers/IndicatorHeader";
|
||||
|
||||
export default function IIDXFolderTable({
|
||||
dataset,
|
||||
reqUser,
|
||||
game,
|
||||
playtype,
|
||||
}: {
|
||||
dataset: FolderDataset<"iidx:SP" | "iidx:DP">;
|
||||
reqUser: PublicUserDocument;
|
||||
game: Game;
|
||||
playtype: Playtype;
|
||||
}) {
|
||||
const defaultRating = useScoreRatingAlg<"iidx:SP" | "iidx:DP">("iidx", playtype);
|
||||
|
||||
const [rating, setRating] = useState<ScoreCalculatedDataLookup["iidx:SP" | "iidx:DP"]>(
|
||||
defaultRating
|
||||
);
|
||||
|
||||
const headers: Header<FolderDataset<"iidx:SP" | "iidx:DP">[0]>[] = [
|
||||
[
|
||||
"Chart",
|
||||
"Ch.",
|
||||
NumericSOV(
|
||||
x => x.tierlistInfo["kt-NC"]?.value ?? x.tierlistInfo["kt-HC"]?.value ?? x.levelNum
|
||||
),
|
||||
],
|
||||
FolderIndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.__related.pb?.scoreData.percent ?? -Infinity)],
|
||||
["Deltas", "Deltas", NumericSOV(x => x.__related.pb?.scoreData.percent ?? -Infinity)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.__related.pb?.scoreData.lampIndex ?? -Infinity)],
|
||||
[
|
||||
"Rating",
|
||||
"Rating",
|
||||
NumericSOV(x => x.__related.pb?.calculatedData[rating] ?? 0),
|
||||
(thProps: ZTableTHProps) => (
|
||||
<SelectableRating<"iidx:SP" | "iidx:DP">
|
||||
key={nanoid()}
|
||||
game="iidx"
|
||||
playtype="SP"
|
||||
rating={rating}
|
||||
setRating={setRating}
|
||||
{...thProps}
|
||||
/>
|
||||
),
|
||||
],
|
||||
[
|
||||
"Site Ranking",
|
||||
"Site Rank",
|
||||
NumericSOV(x => x.__related.pb?.rankingData.rank ?? -Infinity),
|
||||
],
|
||||
["Last Raised", "Last Raised", NumericSOV(x => x.__related.pb?.timeAchieved ?? 0)],
|
||||
];
|
||||
|
||||
return (
|
||||
<TachiTable
|
||||
dataset={dataset}
|
||||
headers={headers}
|
||||
entryName="Charts"
|
||||
searchFunctions={CreateDefaultFolderSearchParams(game, playtype)}
|
||||
rowFunction={data => (
|
||||
<Row rating={rating} data={data} key={data.chartID} reqUser={reqUser} game={game} />
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function Row({
|
||||
data,
|
||||
reqUser,
|
||||
rating,
|
||||
game,
|
||||
}: {
|
||||
data: FolderDataset<"iidx:SP" | "iidx:DP">[0];
|
||||
reqUser: PublicUserDocument;
|
||||
rating: ScoreCalculatedDataLookup["iidx:SP" | "iidx:DP"];
|
||||
game: Game;
|
||||
}) {
|
||||
const score = data.__related.pb;
|
||||
|
||||
if (!score) {
|
||||
return (
|
||||
<tr>
|
||||
<DifficultyCell game={game} chart={data} />
|
||||
<IndicatorsCell highlight={false} />
|
||||
<TitleCell song={data.__related.song} chart={data} game={game} />
|
||||
<td colSpan={6}>Not Played.</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
// screw the rules of hooks
|
||||
const scoreState = usePBState(score);
|
||||
|
||||
return (
|
||||
<DropdownRow
|
||||
dropdown={
|
||||
<IIDXPBDropdown
|
||||
chart={data}
|
||||
reqUser={reqUser}
|
||||
game={game}
|
||||
playtype={data.playtype}
|
||||
scoreState={scoreState}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<DifficultyCell game={game} chart={data} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell song={data.__related.song} chart={data} game={game} />
|
||||
<IIDXScoreCoreCells sc={score} rating={rating} />
|
||||
<RankingCell rankingData={score.rankingData} />
|
||||
<TimestampCell time={score.timeAchieved} />
|
||||
</DropdownRow>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import React from "react";
|
||||
import { Game, PublicUserDocument } from "tachi-common";
|
||||
import { FolderDataset } from "types/tables";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { CreateDefaultFolderSearchParams } from "util/tables/create-search";
|
||||
import BMSDifficultyCell from "../cells/BMSDifficultyCell";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import { usePBState } from "../components/UseScoreState";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import BMSScoreCoreCells from "../game-core-cells/BMSScoreCoreCells";
|
||||
import MusecaScoreCoreCells from "../game-core-cells/MusecaScoreCoreCells";
|
||||
import SDVXScoreCoreCells from "../game-core-cells/SDVXCoreCells";
|
||||
import { FolderIndicatorHeader } from "../headers/IndicatorHeader";
|
||||
|
||||
export default function MusecaFolderTable({
|
||||
dataset,
|
||||
reqUser,
|
||||
game,
|
||||
playtype,
|
||||
}: {
|
||||
dataset: FolderDataset<"museca:Single">;
|
||||
reqUser: PublicUserDocument;
|
||||
game: Game;
|
||||
playtype: Playtype;
|
||||
}) {
|
||||
const headers: Header<FolderDataset<"museca:Single">[0]>[] = [
|
||||
["Chart", "Ch.", NumericSOV(x => x.levelNum)],
|
||||
FolderIndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.__related.pb?.scoreData.percent ?? -Infinity)],
|
||||
["Near - Miss", "Nr. Ms.", NumericSOV(x => x.__related.pb?.scoreData.percent ?? -Infinity)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.__related.pb?.scoreData.lampIndex ?? -Infinity)],
|
||||
["ktRating", "ktRating", NumericSOV(x => x.__related.pb?.calculatedData.ktRating ?? 0)],
|
||||
[
|
||||
"Site Ranking",
|
||||
"Site Rank",
|
||||
NumericSOV(x => x.__related.pb?.rankingData.rank ?? -Infinity),
|
||||
],
|
||||
["Last Raised", "Last Raised", NumericSOV(x => x.__related.pb?.timeAchieved ?? 0)],
|
||||
];
|
||||
|
||||
return (
|
||||
<TachiTable
|
||||
dataset={dataset}
|
||||
headers={headers}
|
||||
entryName="Charts"
|
||||
searchFunctions={CreateDefaultFolderSearchParams(game, playtype)}
|
||||
rowFunction={data => (
|
||||
<Row data={data} key={data.chartID} reqUser={reqUser} game={game} />
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function Row({
|
||||
data,
|
||||
reqUser,
|
||||
game,
|
||||
}: {
|
||||
data: FolderDataset<"museca:Single">[0];
|
||||
reqUser: PublicUserDocument;
|
||||
game: Game;
|
||||
}) {
|
||||
const score = data.__related.pb;
|
||||
|
||||
if (!score) {
|
||||
return (
|
||||
<tr>
|
||||
<DifficultyCell chart={data} game={game} />
|
||||
<IndicatorsCell highlight={false} />
|
||||
<TitleCell song={data.__related.song} chart={data} game={game} />
|
||||
<td colSpan={6}>Not Played.</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
// screw the rules of hooks
|
||||
const scoreState = usePBState(score);
|
||||
|
||||
return (
|
||||
<DropdownRow
|
||||
dropdown={
|
||||
<GenericPBDropdown
|
||||
chart={data}
|
||||
reqUser={reqUser}
|
||||
game={game}
|
||||
playtype={data.playtype}
|
||||
scoreState={scoreState}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<DifficultyCell chart={data} game={game} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell song={data.__related.song} chart={data} game={game} />
|
||||
<MusecaScoreCoreCells sc={score} />
|
||||
<RankingCell rankingData={score.rankingData} />
|
||||
<TimestampCell time={score.timeAchieved} />
|
||||
</DropdownRow>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import React from "react";
|
||||
import { Game, PublicUserDocument } from "tachi-common";
|
||||
import { FolderDataset } from "types/tables";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { CreateDefaultFolderSearchParams } from "util/tables/create-search";
|
||||
import BMSDifficultyCell from "../cells/BMSDifficultyCell";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import { usePBState } from "../components/UseScoreState";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import BMSScoreCoreCells from "../game-core-cells/BMSScoreCoreCells";
|
||||
import SDVXScoreCoreCells from "../game-core-cells/SDVXCoreCells";
|
||||
import { FolderIndicatorHeader } from "../headers/IndicatorHeader";
|
||||
|
||||
export default function SDVXFolderTable({
|
||||
dataset,
|
||||
reqUser,
|
||||
game,
|
||||
playtype,
|
||||
}: {
|
||||
dataset: FolderDataset<"sdvx:Single">;
|
||||
reqUser: PublicUserDocument;
|
||||
game: Game;
|
||||
playtype: Playtype;
|
||||
}) {
|
||||
const headers: Header<FolderDataset<"sdvx:Single">[0]>[] = [
|
||||
["Chart", "Ch.", NumericSOV(x => x.levelNum)],
|
||||
FolderIndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.__related.pb?.scoreData.percent ?? -Infinity)],
|
||||
["Near - Miss", "Nr. Ms.", NumericSOV(x => x.__related.pb?.scoreData.percent ?? -Infinity)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.__related.pb?.scoreData.lampIndex ?? -Infinity)],
|
||||
["VF6", "sgl.", NumericSOV(x => x.__related.pb?.calculatedData.VF6 ?? 0)],
|
||||
[
|
||||
"Site Ranking",
|
||||
"Site Rank",
|
||||
NumericSOV(x => x.__related.pb?.rankingData.rank ?? -Infinity),
|
||||
],
|
||||
["Last Raised", "Last Raised", NumericSOV(x => x.__related.pb?.timeAchieved ?? 0)],
|
||||
];
|
||||
|
||||
return (
|
||||
<TachiTable
|
||||
dataset={dataset}
|
||||
headers={headers}
|
||||
entryName="Charts"
|
||||
searchFunctions={CreateDefaultFolderSearchParams(game, playtype)}
|
||||
rowFunction={data => (
|
||||
<Row data={data} key={data.chartID} reqUser={reqUser} game={game} />
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function Row({
|
||||
data,
|
||||
reqUser,
|
||||
game,
|
||||
}: {
|
||||
data: FolderDataset<"sdvx:Single">[0];
|
||||
reqUser: PublicUserDocument;
|
||||
game: Game;
|
||||
}) {
|
||||
const score = data.__related.pb;
|
||||
|
||||
if (!score) {
|
||||
return (
|
||||
<tr>
|
||||
<DifficultyCell chart={data} game={game} />
|
||||
<IndicatorsCell highlight={false} />
|
||||
<TitleCell song={data.__related.song} chart={data} game={game} />
|
||||
<td colSpan={6}>Not Played.</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
// screw the rules of hooks
|
||||
const scoreState = usePBState(score);
|
||||
|
||||
return (
|
||||
<DropdownRow
|
||||
dropdown={
|
||||
<GenericPBDropdown
|
||||
chart={data}
|
||||
reqUser={reqUser}
|
||||
game={game}
|
||||
playtype={data.playtype}
|
||||
scoreState={scoreState}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<DifficultyCell chart={data} game={game} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell song={data.__related.song} chart={data} game={game} />
|
||||
<SDVXScoreCoreCells sc={score} />
|
||||
<RankingCell rankingData={score.rankingData} />
|
||||
<TimestampCell time={score.timeAchieved} />
|
||||
</DropdownRow>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
import React from "react";
|
||||
import { ScoreDocument } from "tachi-common";
|
||||
import { PBScoreDocument, ScoreDocument } from "tachi-common";
|
||||
import DeltaCell from "../cells/DeltaCell";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import RatingCell from "../cells/RatingCell";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
|
||||
export default function BMSScoreCoreCells({ sc }: { sc: ScoreDocument<"bms:7K" | "bms:14K"> }) {
|
||||
export default function BMSScoreCoreCells({
|
||||
sc,
|
||||
}: {
|
||||
sc: PBScoreDocument<"bms:7K" | "bms:14K"> | ScoreDocument<"bms:7K" | "bms:14K">;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<ScoreCell score={sc} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { ScoreDocument, ScoreCalculatedDataLookup } from "tachi-common";
|
||||
import { ScoreDocument, ScoreCalculatedDataLookup, PBScoreDocument } from "tachi-common";
|
||||
import { IsNullish } from "util/misc";
|
||||
import DeltaCell from "../cells/DeltaCell";
|
||||
import IIDXLampCell from "../cells/IIDXLampCell";
|
||||
@@ -9,7 +9,7 @@ export default function IIDXScoreCoreCells({
|
||||
sc,
|
||||
rating,
|
||||
}: {
|
||||
sc: ScoreDocument<"iidx:SP" | "iidx:DP">;
|
||||
sc: PBScoreDocument<"iidx:SP" | "iidx:DP"> | ScoreDocument<"iidx:SP" | "iidx:DP">;
|
||||
rating: ScoreCalculatedDataLookup["iidx:SP" | "iidx:DP"];
|
||||
}) {
|
||||
return (
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import React from "react";
|
||||
import { ScoreDocument } from "tachi-common";
|
||||
import { PBScoreDocument, ScoreDocument } from "tachi-common";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import MillionsScoreCell from "../cells/MillionsScoreCell";
|
||||
import MusecaJudgementCell from "../cells/MusecaJudgementCell";
|
||||
import RatingCell from "../cells/RatingCell";
|
||||
|
||||
export default function MusecaScoreCoreCells({ sc }: { sc: ScoreDocument<"museca:Single"> }) {
|
||||
export default function MusecaScoreCoreCells({
|
||||
sc,
|
||||
}: {
|
||||
sc: ScoreDocument<"museca:Single"> | PBScoreDocument<"museca:Single">;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<MillionsScoreCell score={sc} />
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import React from "react";
|
||||
import { ScoreDocument } from "tachi-common";
|
||||
import { PBScoreComposedReference, PBScoreDocument, ScoreDocument } from "tachi-common";
|
||||
import { IsNullish } from "util/misc";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import MillionsScoreCell from "../cells/MillionsScoreCell";
|
||||
import SDVXJudgementCell from "../cells/SDVXJudgementCell";
|
||||
|
||||
export default function SDVXScoreCoreCells({ sc }: { sc: ScoreDocument<"sdvx:Single"> }) {
|
||||
export default function SDVXScoreCoreCells({
|
||||
sc,
|
||||
}: {
|
||||
sc: ScoreDocument<"sdvx:Single"> | PBScoreDocument<"sdvx:Single">;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<MillionsScoreCell score={sc} />
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import React from "react";
|
||||
import { PBScoreDocument, ScoreDocument } from "tachi-common";
|
||||
import { FolderDataset, PBDataset, ScoreDataset } from "types/tables";
|
||||
import { NumericSOV } from "util/sorts";
|
||||
import { Header } from "../components/TachiTable";
|
||||
|
||||
const IndicatorHeader: Header<PBDataset[0] | ScoreDataset[0]> = [
|
||||
"Indicators",
|
||||
"Id.",
|
||||
NumericSOV<ScoreDocument | PBScoreDocument>(x => Number(x.highlight)),
|
||||
() => <td key={nanoid()} style={{ maxWidth: 5, padding: 0 }}></td>,
|
||||
];
|
||||
|
||||
export const FolderIndicatorHeader: Header<FolderDataset[0]> = [
|
||||
"Indicators",
|
||||
"Id.",
|
||||
NumericSOV<FolderDataset[0]>(x => Number(x.__related.pb?.highlight)),
|
||||
() => <td key={nanoid()} style={{ maxWidth: 5, padding: 0 }}></td>,
|
||||
];
|
||||
|
||||
export default IndicatorHeader;
|
||||
@@ -1,23 +1,26 @@
|
||||
import React, { useState } from "react";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import React from "react";
|
||||
import { ChartDocument, PublicUserDocument } from "tachi-common";
|
||||
import { PBDataset } from "types/tables";
|
||||
import { PublicUserDocument, ChartDocument } from "tachi-common";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
import IndexCell from "../cells/IndexCell";
|
||||
import DeltaCell from "../cells/DeltaCell";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import { FormatBMSTables, IsNullish } from "util/misc";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import BMSDifficultyCell from "../cells/BMSDifficultyCell";
|
||||
import { BMS_TABLES } from "util/constants/bms-tables";
|
||||
import { FormatBMSTables, IsNullish } from "util/misc";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import { CreateDefaultPBSearchParams } from "util/tables/create-search";
|
||||
import { ValueGetterOrHybrid } from "util/ztable/search";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import BMSDifficultyCell from "../cells/BMSDifficultyCell";
|
||||
import DeltaCell from "../cells/DeltaCell";
|
||||
import IndexCell from "../cells/IndexCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import { usePBState } from "../components/UseScoreState";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import IndicatorHeader from "../headers/IndicatorHeader";
|
||||
|
||||
function GetBMSTableVal(chart: ChartDocument<"bms:7K" | "bms:14K">, key: string) {
|
||||
for (const table of chart.data.tableFolders) {
|
||||
@@ -43,7 +46,17 @@ export default function BMSPBTable({
|
||||
playtype: "7K" | "14K";
|
||||
}) {
|
||||
const headers: Header<PBDataset<"bms:7K" | "bms:14K">[0]>[] = [
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
[
|
||||
"Chart",
|
||||
"Ch.",
|
||||
NumericSOV(
|
||||
x =>
|
||||
x.__related.chart.tierlistInfo["sgl-EC"]?.value ??
|
||||
x.__related.chart.tierlistInfo["sgl-HC"]?.value ??
|
||||
x.__related.chart.levelNum
|
||||
),
|
||||
],
|
||||
IndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Deltas", "Deltas", NumericSOV(x => x.scoreData.percent)],
|
||||
@@ -91,23 +104,7 @@ export default function BMSPBTable({
|
||||
dataset={dataset}
|
||||
headers={headers}
|
||||
entryName="PBs"
|
||||
searchFunctions={{
|
||||
artist: x => x.__related.song.artist,
|
||||
title: x => x.__related.song.title,
|
||||
difficulty: x => FormatBMSTables(x.__related.chart.data.tableFolders),
|
||||
...tableSearchFns,
|
||||
score: x => x.scoreData.score,
|
||||
percent: x => x.scoreData.percent,
|
||||
ranking: x => x.rankingData.rank,
|
||||
lamp: {
|
||||
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
|
||||
strToNum: HumanFriendlyStrToLampIndex("bms", playtype),
|
||||
},
|
||||
grade: {
|
||||
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
|
||||
strToNum: HumanFriendlyStrToGradeIndex("bms", playtype),
|
||||
},
|
||||
}}
|
||||
searchFunctions={CreateDefaultPBSearchParams("bms", playtype)}
|
||||
defaultSortMode={indexCol ? "#" : undefined}
|
||||
rowFunction={pb => (
|
||||
<Row
|
||||
@@ -150,6 +147,7 @@ function Row({
|
||||
>
|
||||
{indexCol && <IndexCell index={pb.__related.index} />}
|
||||
<BMSDifficultyCell chart={pb.__related.chart} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell song={pb.__related.song} chart={pb.__related.chart} game="bms" />
|
||||
<ScoreCell score={pb} />
|
||||
<DeltaCell
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
import React from "react";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { PBDataset } from "types/tables";
|
||||
import { Game, GetGamePTConfig, PublicUserDocument } from "tachi-common";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import IndexCell from "../cells/IndexCell";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
import RatingCell from "../cells/RatingCell";
|
||||
import { PBDataset } from "types/tables";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import { CreateDefaultPBSearchParams } from "util/tables/create-search";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import IndexCell from "../cells/IndexCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import RatingCell from "../cells/RatingCell";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import { usePBState } from "../components/UseScoreState";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import IndicatorHeader from "../headers/IndicatorHeader";
|
||||
|
||||
export default function GenericPBTable({
|
||||
dataset,
|
||||
@@ -38,13 +41,14 @@ export default function GenericPBTable({
|
||||
|
||||
const headers: Header<PBDataset[0]>[] = [
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
IndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
[
|
||||
gptConfig.defaultScoreRatingAlg,
|
||||
gptConfig.defaultScoreRatingAlg,
|
||||
NumericSOV(x => x.calculatedData[gptConfig.defaultScoreRatingAlg] ?? 0),
|
||||
NumericSOV(x => x.calculatedData[gptConfig.defaultScoreRatingAlg] ?? -Infinity),
|
||||
],
|
||||
["Site Ranking", "Site Rank", NumericSOV(x => x.rankingData.rank)],
|
||||
["Last Raised", "Last Raised", NumericSOV(x => x.timeAchieved ?? 0)],
|
||||
@@ -63,23 +67,7 @@ export default function GenericPBTable({
|
||||
dataset={dataset}
|
||||
headers={headers}
|
||||
entryName="PBs"
|
||||
searchFunctions={{
|
||||
artist: x => x.__related.song.artist,
|
||||
title: x => x.__related.song.title,
|
||||
difficulty: x => x.__related.chart.difficulty,
|
||||
level: x => x.__related.chart.levelNum,
|
||||
score: x => x.scoreData.score,
|
||||
percent: x => x.scoreData.percent,
|
||||
ranking: x => x.rankingData.rank,
|
||||
lamp: {
|
||||
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
|
||||
strToNum: HumanFriendlyStrToLampIndex(game, playtype),
|
||||
},
|
||||
grade: {
|
||||
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
|
||||
strToNum: HumanFriendlyStrToGradeIndex(game, playtype),
|
||||
},
|
||||
}}
|
||||
searchFunctions={CreateDefaultPBSearchParams(game, playtype)}
|
||||
defaultSortMode={indexCol ? "#" : undefined}
|
||||
rowFunction={pb => (
|
||||
<Row
|
||||
@@ -125,6 +113,7 @@ function Row({
|
||||
>
|
||||
{indexCol && <IndexCell index={pb.__related.index} />}
|
||||
<DifficultyCell game={pb.game} chart={pb.__related.chart} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell song={pb.__related.song} chart={pb.__related.chart} game={pb.game} />
|
||||
<ScoreCell score={pb} showScore={showScore} />
|
||||
<LampCell score={pb} />
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
import React, { useState } from "react";
|
||||
import { FormatDifficulty } from "tachi-common/js/utils/util";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import SelectableRating from "../components/SelectableRating";
|
||||
import { PBDataset } from "types/tables";
|
||||
import { PublicUserDocument, ScoreCalculatedDataLookup } from "tachi-common";
|
||||
import TachiTable, { Header, ZTableTHProps } from "../components/TachiTable";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
import IndexCell from "../cells/IndexCell";
|
||||
import DeltaCell from "../cells/DeltaCell";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import { nanoid } from "nanoid";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import IIDXPBDropdown from "../dropdowns/IIDXPBDropdown";
|
||||
import IIDXLampCell from "../cells/IIDXLampCell";
|
||||
import { IsNullish } from "util/misc";
|
||||
import { usePBState } from "../components/UseScoreState";
|
||||
import useScoreRatingAlg from "components/util/useScoreRatingAlg";
|
||||
import { nanoid } from "nanoid";
|
||||
import React, { useState } from "react";
|
||||
import { PublicUserDocument, ScoreCalculatedDataLookup } from "tachi-common";
|
||||
import { FormatDifficulty } from "tachi-common/js/utils/util";
|
||||
import { PBDataset } from "types/tables";
|
||||
import { IsNullish } from "util/misc";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import { CreateDefaultPBSearchParams } from "util/tables/create-search";
|
||||
import DeltaCell from "../cells/DeltaCell";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import IIDXLampCell from "../cells/IIDXLampCell";
|
||||
import IndexCell from "../cells/IndexCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import SelectableRating from "../components/SelectableRating";
|
||||
import TachiTable, { Header, ZTableTHProps } from "../components/TachiTable";
|
||||
import { usePBState } from "../components/UseScoreState";
|
||||
import IIDXPBDropdown from "../dropdowns/IIDXPBDropdown";
|
||||
import IndicatorHeader from "../headers/IndicatorHeader";
|
||||
|
||||
export default function IIDXPBTable({
|
||||
dataset,
|
||||
@@ -43,7 +46,17 @@ export default function IIDXPBTable({
|
||||
);
|
||||
|
||||
const headers: Header<PBDataset<"iidx:SP" | "iidx:DP">[0]>[] = [
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
[
|
||||
"Chart",
|
||||
"Ch.",
|
||||
NumericSOV(
|
||||
x =>
|
||||
x.__related.chart.tierlistInfo["kt-NC"]?.value ??
|
||||
x.__related.chart.tierlistInfo["kt-HC"]?.value ??
|
||||
x.__related.chart.levelNum
|
||||
),
|
||||
],
|
||||
IndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Deltas", "Deltas", NumericSOV(x => x.scoreData.percent)],
|
||||
@@ -80,23 +93,7 @@ export default function IIDXPBTable({
|
||||
dataset={dataset}
|
||||
headers={headers}
|
||||
entryName="PBs"
|
||||
searchFunctions={{
|
||||
artist: x => x.__related.song.artist,
|
||||
title: x => x.__related.song.title,
|
||||
difficulty: x => FormatDifficulty(x.__related.chart, "iidx"),
|
||||
level: x => x.__related.chart.levelNum,
|
||||
score: x => x.scoreData.score,
|
||||
percent: x => x.scoreData.percent,
|
||||
ranking: x => x.rankingData.rank,
|
||||
lamp: {
|
||||
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
|
||||
strToNum: HumanFriendlyStrToLampIndex("iidx", playtype),
|
||||
},
|
||||
grade: {
|
||||
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
|
||||
strToNum: HumanFriendlyStrToGradeIndex("iidx", playtype),
|
||||
},
|
||||
}}
|
||||
searchFunctions={CreateDefaultPBSearchParams("iidx", playtype)}
|
||||
defaultSortMode={indexCol ? "#" : undefined}
|
||||
rowFunction={pb => (
|
||||
<Row
|
||||
@@ -138,10 +135,10 @@ function Row({
|
||||
scoreState={scoreState}
|
||||
/>
|
||||
}
|
||||
className={scoreState.highlight ? "highlighted-row" : ""}
|
||||
>
|
||||
{indexCol && <IndexCell index={pb.__related.index} />}
|
||||
<DifficultyCell chart={pb.__related.chart} game={"iidx"} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell song={pb.__related.song} chart={pb.__related.chart} game="iidx" />
|
||||
<ScoreCell score={pb} />
|
||||
<DeltaCell
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
import React from "react";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { PBDataset } from "types/tables";
|
||||
import { PublicUserDocument } from "tachi-common";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import IndexCell from "../cells/IndexCell";
|
||||
import { PBDataset } from "types/tables";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import { CreateDefaultPBSearchParams } from "util/tables/create-search";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import IndexCell from "../cells/IndexCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import MillionsScoreCell from "../cells/MillionsScoreCell";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import RatingCell from "../cells/RatingCell";
|
||||
import MusecaJudgementCell from "../cells/MusecaJudgementCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import RatingCell from "../cells/RatingCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import { usePBState } from "../components/UseScoreState";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import IndicatorHeader from "../headers/IndicatorHeader";
|
||||
|
||||
export default function MusecaPBTable({
|
||||
dataset,
|
||||
@@ -32,9 +35,10 @@ export default function MusecaPBTable({
|
||||
}) {
|
||||
const headers: Header<PBDataset<"museca:Single">[0]>[] = [
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
IndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Near - Miss", "Nr-Ms", NumericSOV(x => x.scoreData.percent)],
|
||||
["Near - Miss", "Nr. Ms.", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
["ktRating", "ktRating", NumericSOV(x => x.calculatedData.ktRating ?? 0)],
|
||||
["Site Ranking", "Site Rank", NumericSOV(x => x.rankingData.rank)],
|
||||
@@ -54,23 +58,7 @@ export default function MusecaPBTable({
|
||||
dataset={dataset}
|
||||
headers={headers}
|
||||
entryName="PBs"
|
||||
searchFunctions={{
|
||||
artist: x => x.__related.song.artist,
|
||||
title: x => x.__related.song.title,
|
||||
difficulty: x => x.__related.chart.difficulty,
|
||||
level: x => x.__related.chart.levelNum,
|
||||
score: x => x.scoreData.score,
|
||||
percent: x => x.scoreData.percent,
|
||||
ranking: x => x.rankingData.rank,
|
||||
lamp: {
|
||||
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
|
||||
strToNum: HumanFriendlyStrToLampIndex("museca", playtype),
|
||||
},
|
||||
grade: {
|
||||
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
|
||||
strToNum: HumanFriendlyStrToGradeIndex("museca", playtype),
|
||||
},
|
||||
}}
|
||||
searchFunctions={CreateDefaultPBSearchParams("museca", playtype)}
|
||||
defaultSortMode={indexCol ? "#" : undefined}
|
||||
rowFunction={pb => (
|
||||
<Row
|
||||
@@ -113,6 +101,7 @@ function Row({
|
||||
>
|
||||
{indexCol && <IndexCell index={pb.__related.index} />}
|
||||
<DifficultyCell game="museca" chart={pb.__related.chart} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell song={pb.__related.song} chart={pb.__related.chart} game="museca" />
|
||||
<MillionsScoreCell score={pb} />
|
||||
<MusecaJudgementCell score={pb} />
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React from "react";
|
||||
import { IDStrings, PublicUserDocument, ScoreCalculatedDataLookup } from "tachi-common";
|
||||
import { GamePT } from "types/react";
|
||||
import { PBDataset } from "types/tables";
|
||||
import { IDStrings, PublicUserDocument, ScoreCalculatedDataLookup } from "tachi-common";
|
||||
import IIDXPBTable from "./IIDXPBTable";
|
||||
import BMSPBTable from "./BMSPBTable";
|
||||
import SDVXPBTable from "./SDVXPBTable";
|
||||
import GenericPBTable from "./GenericPBTable";
|
||||
import IIDXPBTable from "./IIDXPBTable";
|
||||
import MusecaPBTable from "./MusecaPBTable";
|
||||
import SDVXPBTable from "./SDVXPBTable";
|
||||
|
||||
export default function PBTable({
|
||||
dataset,
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
import React from "react";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { PBDataset } from "types/tables";
|
||||
import { PublicUserDocument } from "tachi-common";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import IndexCell from "../cells/IndexCell";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import { PBDataset } from "types/tables";
|
||||
import { IsNullish } from "util/misc";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { CreateDefaultPBSearchParams } from "util/tables/create-search";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import IndexCell from "../cells/IndexCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import MillionsScoreCell from "../cells/MillionsScoreCell";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import RankingCell from "../cells/RankingCell";
|
||||
import SDVXJudgementCell from "../cells/SDVXJudgementCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import { usePBState } from "../components/UseScoreState";
|
||||
import GenericPBDropdown from "../dropdowns/GenericPBDropdown";
|
||||
import IndicatorHeader from "../headers/IndicatorHeader";
|
||||
|
||||
export default function SDVXPBTable({
|
||||
dataset,
|
||||
@@ -32,9 +34,10 @@ export default function SDVXPBTable({
|
||||
}) {
|
||||
const headers: Header<PBDataset<"sdvx:Single">[0]>[] = [
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
IndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Near - Miss", "Nr-Ms", NumericSOV(x => x.scoreData.percent)],
|
||||
["Near - Miss", "Nr. Ms.", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
["VF6", "VF6", NumericSOV(x => x.calculatedData.VF6 ?? 0)],
|
||||
["Site Ranking", "Site Rank", NumericSOV(x => x.rankingData.rank)],
|
||||
@@ -54,23 +57,7 @@ export default function SDVXPBTable({
|
||||
dataset={dataset}
|
||||
headers={headers}
|
||||
entryName="PBs"
|
||||
searchFunctions={{
|
||||
artist: x => x.__related.song.artist,
|
||||
title: x => x.__related.song.title,
|
||||
difficulty: x => x.__related.chart.difficulty,
|
||||
level: x => x.__related.chart.levelNum,
|
||||
score: x => x.scoreData.score,
|
||||
percent: x => x.scoreData.percent,
|
||||
ranking: x => x.rankingData.rank,
|
||||
lamp: {
|
||||
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
|
||||
strToNum: HumanFriendlyStrToLampIndex("sdvx", playtype),
|
||||
},
|
||||
grade: {
|
||||
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
|
||||
strToNum: HumanFriendlyStrToGradeIndex("sdvx", playtype),
|
||||
},
|
||||
}}
|
||||
searchFunctions={CreateDefaultPBSearchParams("sdvx", playtype)}
|
||||
defaultSortMode={indexCol ? "#" : undefined}
|
||||
rowFunction={pb => (
|
||||
<Row
|
||||
@@ -113,6 +100,7 @@ function Row({
|
||||
>
|
||||
{indexCol && <IndexCell index={pb.__related.index} />}
|
||||
<DifficultyCell game="sdvx" chart={pb.__related.chart} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell song={pb.__related.song} chart={pb.__related.chart} game="sdvx" />
|
||||
<MillionsScoreCell score={pb} />
|
||||
<SDVXJudgementCell score={pb} />
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
import React, { useState } from "react";
|
||||
import { FormatDifficulty } from "tachi-common/js/utils/util";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import React from "react";
|
||||
import { integer, Playtypes, PublicUserDocument } from "tachi-common";
|
||||
import { ScoreDataset } from "types/tables";
|
||||
import { integer, PublicUserDocument, Playtypes, ScoreDocument } from "tachi-common";
|
||||
import TachiTable from "../components/TachiTable";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
import DeltaCell from "../cells/DeltaCell";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import { IsNullish } from "util/misc";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import BMSDifficultyCell from "../cells/BMSDifficultyCell";
|
||||
import { Playtype } from "types/tachi";
|
||||
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
|
||||
import SDVXJudgementCell from "../cells/SDVXJudgementCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { CreateDefaultScoreSearchParams } from "util/tables/create-search";
|
||||
import BMSDifficultyCell from "../cells/BMSDifficultyCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import { useScoreState } from "../components/UseScoreState";
|
||||
import RatingCell from "../cells/RatingCell";
|
||||
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
|
||||
import BMSScoreCoreCells from "../game-core-cells/BMSScoreCoreCells";
|
||||
import { CreateDefaultScoreSearch } from "util/tables";
|
||||
import IndicatorHeader from "../headers/IndicatorHeader";
|
||||
|
||||
export default function BMSScoreTable({
|
||||
reqUser,
|
||||
@@ -36,18 +30,30 @@ export default function BMSScoreTable({
|
||||
<TachiTable
|
||||
dataset={dataset}
|
||||
pageLen={pageLen}
|
||||
headers={[
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Deltas", "Deltas", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
["Sieglinde", "sgl.", NumericSOV(x => x.calculatedData.sieglinde ?? 0)],
|
||||
headers={
|
||||
[
|
||||
[
|
||||
"Chart",
|
||||
"Ch.",
|
||||
NumericSOV(
|
||||
x =>
|
||||
x.__related.chart.tierlistInfo["sgl-EC"]?.value ??
|
||||
x.__related.chart.tierlistInfo["sgl-HC"]?.value ??
|
||||
x.__related.chart.levelNum
|
||||
),
|
||||
],
|
||||
IndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Deltas", "Deltas", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
["Sieglinde", "sgl.", NumericSOV(x => x.calculatedData.sieglinde ?? 0)],
|
||||
|
||||
["Timestamp", "Timestamp", NumericSOV(x => x.timeAchieved ?? 0)],
|
||||
]}
|
||||
["Timestamp", "Timestamp", NumericSOV(x => x.timeAchieved ?? 0)],
|
||||
] as Header<ScoreDataset<"bms:7K" | "bms:14K">[0]>[]
|
||||
}
|
||||
entryName="Scores"
|
||||
searchFunctions={CreateDefaultScoreSearch<"bms:7K" | "bms:14K">("bms", playtype)}
|
||||
searchFunctions={CreateDefaultScoreSearchParams("bms", playtype)}
|
||||
rowFunction={sc => (
|
||||
<Row playtype={playtype} key={sc.scoreID} sc={sc} reqUser={reqUser} />
|
||||
)}
|
||||
@@ -81,6 +87,7 @@ function Row({
|
||||
}
|
||||
>
|
||||
<BMSDifficultyCell chart={sc.__related.chart} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell
|
||||
song={sc.__related.song}
|
||||
chart={sc.__related.chart}
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
import React, { useState } from "react";
|
||||
import { FormatDifficulty } from "tachi-common/js/utils/util";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import React from "react";
|
||||
import { Game, GetGamePTConfig, integer, PublicUserDocument } from "tachi-common";
|
||||
import { ScoreDataset } from "types/tables";
|
||||
import { integer, PublicUserDocument, Playtypes, Game, GetGamePTConfig } from "tachi-common";
|
||||
import TachiTable from "../components/TachiTable";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import { IsNullish } from "util/misc";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import MillionsScoreCell from "../cells/MillionsScoreCell";
|
||||
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
|
||||
import RatingCell from "../cells/RatingCell";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { CreateDefaultScoreSearchParams } from "util/tables/create-search";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import TachiTable from "../components/TachiTable";
|
||||
import { useScoreState } from "../components/UseScoreState";
|
||||
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
|
||||
import GenericScoreCoreCells from "../game-core-cells/GenericScoreCoreCells";
|
||||
import { CreateDefaultScoreSearch } from "util/tables";
|
||||
import IndicatorHeader from "../headers/IndicatorHeader";
|
||||
|
||||
export default function GenericScoreTable({
|
||||
reqUser,
|
||||
@@ -43,6 +37,7 @@ export default function GenericScoreTable({
|
||||
pageLen={pageLen}
|
||||
headers={[
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
IndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
@@ -54,7 +49,7 @@ export default function GenericScoreTable({
|
||||
["Timestamp", "Timestamp", NumericSOV(x => x.timeAchieved ?? 0)],
|
||||
]}
|
||||
entryName="Scores"
|
||||
searchFunctions={CreateDefaultScoreSearch(game, playtype)}
|
||||
searchFunctions={CreateDefaultScoreSearchParams(game, playtype)}
|
||||
rowFunction={sc => (
|
||||
<Row key={sc.scoreID} sc={sc} reqUser={reqUser} showScore={showScore} />
|
||||
)}
|
||||
@@ -88,6 +83,7 @@ function Row({
|
||||
}
|
||||
>
|
||||
<DifficultyCell chart={sc.__related.chart} game={sc.game} />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<GenericScoreCoreCells sc={sc} showScore={showScore} />
|
||||
<TimestampCell time={sc.timeAchieved} service={sc.service} />
|
||||
</DropdownRow>
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import React, { useState } from "react";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import SelectableRating from "../components/SelectableRating";
|
||||
import { ScoreDataset } from "types/tables";
|
||||
import { integer, ScoreCalculatedDataLookup, PublicUserDocument, Playtypes } from "tachi-common";
|
||||
import TachiTable, { ZTableTHProps } from "../components/TachiTable";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import { nanoid } from "nanoid";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import IIDXScoreDropdown from "../dropdowns/IIDXScoreDropdown";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { useScoreState } from "../components/UseScoreState";
|
||||
import IIDXScoreCoreCells from "../game-core-cells/IIDXScoreCoreCells";
|
||||
import { CreateDefaultScoreSearch } from "util/tables";
|
||||
import useScoreRatingAlg from "components/util/useScoreRatingAlg";
|
||||
import { nanoid } from "nanoid";
|
||||
import React, { useState } from "react";
|
||||
import { integer, Playtypes, PublicUserDocument, ScoreCalculatedDataLookup } from "tachi-common";
|
||||
import { ScoreDataset } from "types/tables";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { CreateDefaultScoreSearchParams } from "util/tables/create-search";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import SelectableRating from "../components/SelectableRating";
|
||||
import TachiTable, { Header, ZTableTHProps } from "../components/TachiTable";
|
||||
import { useScoreState } from "../components/UseScoreState";
|
||||
import IIDXScoreDropdown from "../dropdowns/IIDXScoreDropdown";
|
||||
import IIDXScoreCoreCells from "../game-core-cells/IIDXScoreCoreCells";
|
||||
import IndicatorHeader from "../headers/IndicatorHeader";
|
||||
|
||||
export default function IIDXScoreTable({
|
||||
reqUser,
|
||||
@@ -36,31 +38,43 @@ export default function IIDXScoreTable({
|
||||
<TachiTable
|
||||
dataset={dataset}
|
||||
pageLen={pageLen}
|
||||
headers={[
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Deltas", "Deltas", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
headers={
|
||||
[
|
||||
"Rating",
|
||||
"Rating",
|
||||
NumericSOV(x => x.calculatedData[rating] ?? 0),
|
||||
(thProps: ZTableTHProps) => (
|
||||
<SelectableRating<"iidx:SP" | "iidx:DP">
|
||||
key={nanoid()}
|
||||
game="iidx"
|
||||
playtype={playtype}
|
||||
rating={rating}
|
||||
setRating={setRating}
|
||||
{...thProps}
|
||||
/>
|
||||
),
|
||||
],
|
||||
["Timestamp", "Timestamp", NumericSOV(x => x.timeAchieved ?? 0)],
|
||||
]}
|
||||
[
|
||||
"Chart",
|
||||
"Ch.",
|
||||
NumericSOV(
|
||||
x =>
|
||||
x.__related.chart.tierlistInfo["kt-NC"]?.value ??
|
||||
x.__related.chart.tierlistInfo["kt-HC"]?.value ??
|
||||
x.__related.chart.levelNum
|
||||
),
|
||||
],
|
||||
IndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Deltas", "Deltas", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
[
|
||||
"Rating",
|
||||
"Rating",
|
||||
NumericSOV(x => x.calculatedData[rating] ?? 0),
|
||||
(thProps: ZTableTHProps) => (
|
||||
<SelectableRating<"iidx:SP" | "iidx:DP">
|
||||
key={nanoid()}
|
||||
game="iidx"
|
||||
playtype={playtype}
|
||||
rating={rating}
|
||||
setRating={setRating}
|
||||
{...thProps}
|
||||
/>
|
||||
),
|
||||
],
|
||||
["Timestamp", "Timestamp", NumericSOV(x => x.timeAchieved ?? 0)],
|
||||
] as Header<ScoreDataset<"iidx:SP" | "iidx:DP">[0]>[]
|
||||
}
|
||||
entryName="Scores"
|
||||
searchFunctions={CreateDefaultScoreSearch<"iidx:SP" | "iidx:DP">("iidx", playtype)}
|
||||
searchFunctions={CreateDefaultScoreSearchParams("iidx", playtype)}
|
||||
rowFunction={sc => (
|
||||
<Row
|
||||
key={sc.scoreID}
|
||||
@@ -102,6 +116,7 @@ function Row({
|
||||
}
|
||||
>
|
||||
<DifficultyCell chart={sc.__related.chart} game="iidx" />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell
|
||||
song={sc.__related.song}
|
||||
comment={sc.comment}
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { FormatDifficulty } from "tachi-common/js/utils/util";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import React from "react";
|
||||
import { integer, Playtypes, PublicUserDocument } from "tachi-common";
|
||||
import { ScoreDataset } from "types/tables";
|
||||
import { integer, PublicUserDocument, Playtypes, ScoreDocument } from "tachi-common";
|
||||
import TachiTable from "../components/TachiTable";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { CreateDefaultScoreSearchParams } from "util/tables/create-search";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import { IsNullish } from "util/misc";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import MillionsScoreCell from "../cells/MillionsScoreCell";
|
||||
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
|
||||
import RatingCell from "../cells/RatingCell";
|
||||
import MusecaJudgementCell from "../cells/MusecaJudgementCell";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import { useScoreState } from "../components/UseScoreState";
|
||||
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
|
||||
import MusecaScoreCoreCells from "../game-core-cells/MusecaScoreCoreCells";
|
||||
import { CreateDefaultScoreSearch } from "util/tables";
|
||||
import IndicatorHeader from "../headers/IndicatorHeader";
|
||||
|
||||
export default function MusecaScoreTable({
|
||||
reqUser,
|
||||
@@ -34,18 +28,21 @@ export default function MusecaScoreTable({
|
||||
<TachiTable
|
||||
dataset={dataset}
|
||||
pageLen={pageLen}
|
||||
headers={[
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Near-Miss", "Nr-Ms", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
["KtRating", "KtRating", NumericSOV(x => x.calculatedData.ktRating ?? 0)],
|
||||
headers={
|
||||
[
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
IndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Near-Miss", "Nr. Ms.", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
["KtRating", "KtRating", NumericSOV(x => x.calculatedData.ktRating ?? 0)],
|
||||
|
||||
["Timestamp", "Timestamp", NumericSOV(x => x.timeAchieved ?? 0)],
|
||||
]}
|
||||
["Timestamp", "Timestamp", NumericSOV(x => x.timeAchieved ?? 0)],
|
||||
] as Header<ScoreDataset<"museca:Single">[0]>[]
|
||||
}
|
||||
entryName="Scores"
|
||||
searchFunctions={CreateDefaultScoreSearch<"museca:Single">("museca", "Single")}
|
||||
searchFunctions={CreateDefaultScoreSearchParams("museca", "Single")}
|
||||
rowFunction={sc => <Row key={sc.scoreID} sc={sc} reqUser={reqUser} />}
|
||||
/>
|
||||
);
|
||||
@@ -75,6 +72,7 @@ function Row({
|
||||
}
|
||||
>
|
||||
<DifficultyCell chart={sc.__related.chart} game="museca" />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell
|
||||
song={sc.__related.song}
|
||||
comment={sc.comment}
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
import React, { useState } from "react";
|
||||
import { FormatDifficulty } from "tachi-common/js/utils/util";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import React from "react";
|
||||
import { integer, Playtypes, PublicUserDocument } from "tachi-common";
|
||||
import { ScoreDataset } from "types/tables";
|
||||
import { integer, PublicUserDocument, Playtypes, ScoreDocument } from "tachi-common";
|
||||
import TachiTable from "../components/TachiTable";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { CreateDefaultScoreSearchParams } from "util/tables/create-search";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import IndicatorsCell from "../cells/IndicatorsCell";
|
||||
import TimestampCell from "../cells/TimestampCell";
|
||||
import TitleCell from "../cells/TitleCell";
|
||||
import DropdownRow from "../components/DropdownRow";
|
||||
import { IsNullish } from "util/misc";
|
||||
import LampCell from "../cells/LampCell";
|
||||
import MillionsScoreCell from "../cells/MillionsScoreCell";
|
||||
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
|
||||
import SDVXJudgementCell from "../cells/SDVXJudgementCell";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import { useScoreState } from "../components/UseScoreState";
|
||||
import GenericScoreDropdown from "../dropdowns/GenericScoreDropdown";
|
||||
import SDVXScoreCoreCells from "../game-core-cells/SDVXCoreCells";
|
||||
import { CreateDefaultScoreSearch } from "util/tables";
|
||||
import IndicatorHeader from "../headers/IndicatorHeader";
|
||||
|
||||
export default function SDVXScoreTable({
|
||||
reqUser,
|
||||
@@ -33,18 +28,21 @@ export default function SDVXScoreTable({
|
||||
<TachiTable
|
||||
dataset={dataset}
|
||||
pageLen={pageLen}
|
||||
headers={[
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Near - Miss", "Nr-Ms", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
["VF6", "VF6", NumericSOV(x => x.calculatedData.VF6 ?? 0)],
|
||||
headers={
|
||||
[
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
IndicatorHeader,
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
["Score", "Score", NumericSOV(x => x.scoreData.percent)],
|
||||
["Near - Miss", "Nr. Ms.", NumericSOV(x => x.scoreData.percent)],
|
||||
["Lamp", "Lamp", NumericSOV(x => x.scoreData.lampIndex)],
|
||||
["VF6", "VF6", NumericSOV(x => x.calculatedData.VF6 ?? 0)],
|
||||
|
||||
["Timestamp", "Timestamp", NumericSOV(x => x.timeAchieved ?? 0)],
|
||||
]}
|
||||
["Timestamp", "Timestamp", NumericSOV(x => x.timeAchieved ?? 0)],
|
||||
] as Header<ScoreDataset<"sdvx:Single">[0]>[]
|
||||
}
|
||||
entryName="Scores"
|
||||
searchFunctions={CreateDefaultScoreSearch<"sdvx:Single">("sdvx", "Single")}
|
||||
searchFunctions={CreateDefaultScoreSearchParams("museca", "Single")}
|
||||
rowFunction={sc => <Row key={sc.scoreID} sc={sc} reqUser={reqUser} />}
|
||||
/>
|
||||
);
|
||||
@@ -68,6 +66,7 @@ function Row({ sc, reqUser }: { sc: ScoreDataset<"sdvx:Single">[0]; reqUser: Pub
|
||||
}
|
||||
>
|
||||
<DifficultyCell chart={sc.__related.chart} game="sdvx" />
|
||||
<IndicatorsCell highlight={scoreState.highlight} />
|
||||
<TitleCell
|
||||
song={sc.__related.song}
|
||||
comment={sc.comment}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import {
|
||||
ChartDocument,
|
||||
FolderDocument,
|
||||
Grades,
|
||||
IDStrings,
|
||||
IDStringToGame,
|
||||
integer,
|
||||
Lamps,
|
||||
PBScoreDocument,
|
||||
PublicUserDocument,
|
||||
ScoreDocument,
|
||||
UserGameStats,
|
||||
SessionDocument,
|
||||
ShowcaseStatChart,
|
||||
ShowcaseStatFolder,
|
||||
UserGameStatsSnapshot,
|
||||
SessionDocument,
|
||||
IDStringToGame,
|
||||
ChartDocument,
|
||||
SongDocument,
|
||||
PBScoreDocument,
|
||||
UGSRatingsLookup,
|
||||
Grades,
|
||||
Lamps,
|
||||
TableDocument,
|
||||
UGSRatingsLookup,
|
||||
UserGameStats,
|
||||
UserGameStatsSnapshot,
|
||||
} from "tachi-common";
|
||||
|
||||
export interface UGPTStatsReturn<I extends IDStrings = IDStrings> {
|
||||
@@ -114,3 +114,10 @@ export interface UGPTTableReturns {
|
||||
stats: FolderStatsInfo[];
|
||||
table: TableDocument;
|
||||
}
|
||||
|
||||
export interface UGPTFolderReturns<I extends IDStrings = IDStrings> {
|
||||
folder: FolderDocument;
|
||||
songs: SongDocument<IDStringToGame[I]>[];
|
||||
charts: ChartDocument<I>[];
|
||||
pbs: PBScoreDocument<I>[];
|
||||
}
|
||||
|
||||
@@ -16,3 +16,10 @@ export type PBDataset<I extends IDStrings = IDStrings> = (PBScoreDocument<I> & {
|
||||
export type ScoreDataset<I extends IDStrings = IDStrings> = (ScoreDocument<I> & {
|
||||
__related: { chart: ChartDocument<I>; song: SongDocument<IDStringToGame[I]>; index: integer };
|
||||
})[];
|
||||
|
||||
export type FolderDataset<I extends IDStrings = IDStrings> = (ChartDocument<I> & {
|
||||
__related: {
|
||||
pb: PBScoreDocument<I> | null;
|
||||
song: SongDocument<IDStringToGame[I]>;
|
||||
};
|
||||
})[];
|
||||
|
||||
@@ -3,6 +3,7 @@ import { TACHI_CHART_THEME } from "./constants/chart-theme";
|
||||
export const DEFAULT_BAR_PROPS = {
|
||||
labelTextColor: "black",
|
||||
labelSkipHeight: 12,
|
||||
labelSkipWidth: 30,
|
||||
theme: TACHI_CHART_THEME,
|
||||
motionConfig: "stiff",
|
||||
};
|
||||
|
||||
+10
-10
@@ -22,6 +22,16 @@ export function CreateSongMap<G extends Game = Game>(songs: SongDocument<G>[]) {
|
||||
return songMap;
|
||||
}
|
||||
|
||||
export function CreateChartIDMap<T extends { chartID: string }>(arr: T[]): Map<string, T> {
|
||||
const map = new Map();
|
||||
|
||||
for (const t of arr) {
|
||||
map.set(t.chartID, t);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
export function CreateChartMap<I extends IDStrings = IDStrings>(charts: ChartDocument<I>[]) {
|
||||
const chartMap = new Map<string, ChartDocument<I>>();
|
||||
|
||||
@@ -32,16 +42,6 @@ export function CreateChartMap<I extends IDStrings = IDStrings>(charts: ChartDoc
|
||||
return chartMap;
|
||||
}
|
||||
|
||||
export function CreateScoreMap<I extends IDStrings = IDStrings>(scores: ScoreDocument<I>[]) {
|
||||
const scoreMap = new Map<string, ScoreDocument<I>>();
|
||||
|
||||
for (const score of scores) {
|
||||
scoreMap.set(score.scoreID, score);
|
||||
}
|
||||
|
||||
return scoreMap;
|
||||
}
|
||||
|
||||
export function CreateChartLink(chart: ChartDocument, game: Game) {
|
||||
if (chart.isPrimary) {
|
||||
return `/dashboard/games/${game}/${chart.playtype}/songs/${
|
||||
|
||||
@@ -115,3 +115,15 @@ export function StepFromToMax(max: integer, step: integer = 50) {
|
||||
arr.push(max);
|
||||
return arr;
|
||||
}
|
||||
|
||||
export function ComposeExpFn(pow: number) {
|
||||
return (x: number) => Math.pow(x, pow);
|
||||
}
|
||||
|
||||
export function ComposeInverseExpFn(pow: number) {
|
||||
return (x: number) => Math.pow(x, 1 / pow);
|
||||
}
|
||||
|
||||
export function ComposeLogFn(base: number) {
|
||||
return (x: number) => Math.log(x) / Math.log(base);
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { FormatDifficulty, Game, IDStrings } from "tachi-common";
|
||||
import { ScoreDataset } from "types/tables";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { HumanFriendlyStrToLampIndex, HumanFriendlyStrToGradeIndex } from "./str-to-num";
|
||||
import { ValueGetterOrHybrid } from "./ztable/search";
|
||||
|
||||
export function CreateDefaultScoreSearch<I extends IDStrings = IDStrings>(
|
||||
game: Game,
|
||||
playtype: Playtype
|
||||
): Record<string, ValueGetterOrHybrid<ScoreDataset<I>[0]>> {
|
||||
return {
|
||||
artist: x => x.__related.song.artist,
|
||||
title: x => x.__related.song.title,
|
||||
difficulty: x => FormatDifficulty(x.__related.chart, game),
|
||||
level: x => x.__related.chart.levelNum,
|
||||
score: x => x.scoreData.score,
|
||||
percent: x => x.scoreData.percent,
|
||||
lamp: {
|
||||
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
|
||||
strToNum: HumanFriendlyStrToLampIndex(game, playtype),
|
||||
},
|
||||
grade: {
|
||||
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
|
||||
strToNum: HumanFriendlyStrToGradeIndex(game, playtype),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import { Game, GamePTConfig, GetGamePTConfig, IDStrings } from "tachi-common";
|
||||
import { FolderDataset, PBDataset, ScoreDataset } from "types/tables";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import { ValueGetterOrHybrid } from "util/ztable/search";
|
||||
|
||||
export function CreateDefaultScoreSearchParams<I extends IDStrings = IDStrings>(
|
||||
game: Game,
|
||||
playtype: Playtype
|
||||
) {
|
||||
const gptConfig = GetGamePTConfig(game, playtype);
|
||||
|
||||
const searchFunctions: Record<string, ValueGetterOrHybrid<ScoreDataset<I>[0]>> = {
|
||||
artist: x => x.__related.song.artist,
|
||||
title: x => x.__related.song.title,
|
||||
difficulty: x => x.__related.chart.difficulty,
|
||||
level: x => x.__related.chart.levelNum,
|
||||
score: x => x.scoreData.score,
|
||||
percent: x => x.scoreData.percent,
|
||||
highlight: x => !!x.highlight,
|
||||
lamp: {
|
||||
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
|
||||
strToNum: HumanFriendlyStrToLampIndex(game, playtype),
|
||||
},
|
||||
grade: {
|
||||
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
|
||||
strToNum: HumanFriendlyStrToGradeIndex(game, playtype),
|
||||
},
|
||||
...CreateCalcDataSearchFns(gptConfig),
|
||||
};
|
||||
|
||||
return searchFunctions;
|
||||
}
|
||||
|
||||
export function CreateDefaultPBSearchParams<I extends IDStrings = IDStrings>(
|
||||
game: Game,
|
||||
playtype: Playtype
|
||||
) {
|
||||
const gptConfig = GetGamePTConfig(game, playtype);
|
||||
|
||||
const searchFunctions: Record<string, ValueGetterOrHybrid<PBDataset<I>[0]>> = {
|
||||
artist: x => x.__related.song.artist,
|
||||
title: x => x.__related.song.title,
|
||||
difficulty: x => x.__related.chart.difficulty,
|
||||
level: x => x.__related.chart.levelNum,
|
||||
score: x => x.scoreData.score,
|
||||
percent: x => x.scoreData.percent,
|
||||
ranking: x => x.rankingData.rank,
|
||||
highlight: x => !!x.highlight,
|
||||
lamp: {
|
||||
valueGetter: x => [x.scoreData.lamp, x.scoreData.lampIndex],
|
||||
strToNum: HumanFriendlyStrToLampIndex(game, playtype),
|
||||
},
|
||||
grade: {
|
||||
valueGetter: x => [x.scoreData.grade, x.scoreData.gradeIndex],
|
||||
strToNum: HumanFriendlyStrToGradeIndex(game, playtype),
|
||||
},
|
||||
...CreateCalcDataSearchFns(gptConfig),
|
||||
};
|
||||
|
||||
return searchFunctions;
|
||||
}
|
||||
|
||||
export function CreateDefaultFolderSearchParams<I extends IDStrings = IDStrings>(
|
||||
game: Game,
|
||||
playtype: Playtype
|
||||
) {
|
||||
const gptConfig = GetGamePTConfig(game, playtype);
|
||||
|
||||
const searchFunctions: Record<string, ValueGetterOrHybrid<FolderDataset<I>[0]>> = {
|
||||
artist: x => x.__related.song.artist,
|
||||
title: x => x.__related.song.title,
|
||||
difficulty: x => x.difficulty,
|
||||
level: x => x.levelNum,
|
||||
score: x => x.__related.pb?.scoreData.score ?? -Infinity,
|
||||
percent: x => x.__related.pb?.scoreData.percent ?? -Infinity,
|
||||
ranking: x => x.__related.pb?.rankingData.rank ?? -Infinity,
|
||||
highlight: x => !!x.__related.pb?.highlight,
|
||||
played: x => !!x.__related.pb,
|
||||
lamp: {
|
||||
valueGetter: x =>
|
||||
x.__related.pb
|
||||
? [x.__related.pb.scoreData.lamp, x.__related.pb.scoreData.lampIndex]
|
||||
: null,
|
||||
strToNum: HumanFriendlyStrToLampIndex(game, playtype),
|
||||
},
|
||||
grade: {
|
||||
valueGetter: x =>
|
||||
x.__related.pb
|
||||
? [x.__related.pb.scoreData.grade, x.__related.pb.scoreData.gradeIndex]
|
||||
: null,
|
||||
strToNum: HumanFriendlyStrToGradeIndex(game, playtype),
|
||||
},
|
||||
...CreateFolderCalcDataSearchFns(gptConfig),
|
||||
};
|
||||
|
||||
return searchFunctions;
|
||||
}
|
||||
|
||||
function CreateFolderCalcDataSearchFns(gptConfig: GamePTConfig) {
|
||||
return Object.fromEntries(
|
||||
gptConfig.scoreRatingAlgs.map(e => [
|
||||
e.toLowerCase(),
|
||||
(x: FolderDataset[0]) => x.__related.pb?.calculatedData[e] ?? null,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
function CreateCalcDataSearchFns(gptConfig: GamePTConfig) {
|
||||
return Object.fromEntries(
|
||||
gptConfig.scoreRatingAlgs.map(
|
||||
e => [e.toLowerCase(), (x: PBDataset[0]) => x.calculatedData[e]] ?? null
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -38,7 +38,7 @@ export function ParseDirectives(search: string): Directive[] {
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [_wholeMatch, key, mode, value] = ps;
|
||||
const [wholeMatch, key, mode, value] = ps;
|
||||
|
||||
let v = value;
|
||||
|
||||
@@ -101,6 +101,14 @@ const Matchers: Record<DirectiveModes, MatchFn> = {
|
||||
|
||||
const NeutralMatch = (sv: string, dv: string) => dv.toLowerCase().includes(sv.toLowerCase());
|
||||
|
||||
const BooleanMatch = (sv: string, dv: boolean) => {
|
||||
if (dv) {
|
||||
return ["yes", "true"].some(x => x.startsWith(sv.toLowerCase()));
|
||||
}
|
||||
|
||||
return ["no", "false"].some(x => x.startsWith(sv.toLowerCase()));
|
||||
};
|
||||
|
||||
function GetStrData(dataValue: string | number | [string, number]) {
|
||||
if (typeof dataValue === "string") {
|
||||
return dataValue;
|
||||
@@ -128,13 +136,23 @@ function GetData(dataValue: string | number | [string, number]) {
|
||||
*/
|
||||
function DirectiveMatch(
|
||||
directive: Directive,
|
||||
dataValue: string | number | [string, number] | null,
|
||||
dataValue: string | number | boolean | [string, number] | null,
|
||||
directiveNumValue?: number
|
||||
) {
|
||||
if (dataValue === undefined) {
|
||||
console.warn(`Unexpected undefined for dataValue ${directive}. Casting to null.`);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
dataValue = null;
|
||||
}
|
||||
|
||||
if (dataValue === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof dataValue === "boolean") {
|
||||
return BooleanMatch(directive.value, dataValue);
|
||||
}
|
||||
|
||||
if (!directive.mode) {
|
||||
return NeutralMatch(directive.value, GetStrData(dataValue));
|
||||
}
|
||||
@@ -164,7 +182,7 @@ function DirectiveMatch(
|
||||
* a number for >= style comparisons. The value getter must return a tri-tuple of its string value,
|
||||
* its numerical value, and a function to convert the users string request to a number.
|
||||
*/
|
||||
export type ValueGetter<D> = (data: D) => string | number | null;
|
||||
export type ValueGetter<D> = (data: D) => string | number | boolean | null;
|
||||
|
||||
export type ValueGetterOrHybrid<D> =
|
||||
| {
|
||||
@@ -193,10 +211,22 @@ export function ComposeSearchFunction<D>(
|
||||
return allGetters.some(vgOrHybrid => {
|
||||
const v = GetValueGetter(vgOrHybrid)(data);
|
||||
|
||||
if (v === undefined) {
|
||||
console.warn(
|
||||
`Unexpected undefined in directive ${vgOrHybrid}, casting to null.`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (v === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// These don't make sense for a neutral.
|
||||
if (typeof v === "boolean") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return NeutralMatch(search, GetStrData(v));
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user