mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-08 06:48:04 +03:00
More big updates (just incase hdd dies or something)
This commit is contained in:
@@ -33,12 +33,24 @@ export default function TimelineChart({
|
||||
style={{ height: mobileHeight, width: mobileWidth }}
|
||||
>
|
||||
<div className="d-flex h-100 justify-content-center align-items-center">
|
||||
Not Enough Data... Yet.
|
||||
<div className="text-center">
|
||||
Not Enough Data... Yet.
|
||||
<br />
|
||||
<small className="text-muted">
|
||||
(You need atleast 7 days worth of data)
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-none d-md-block" style={{ height, width }}>
|
||||
<div className="d-flex h-100 justify-content-center align-items-center">
|
||||
Not Enough Data... Yet.
|
||||
<div className="text-center">
|
||||
Not Enough Data... Yet.
|
||||
<br />
|
||||
<small className="text-muted">
|
||||
(You need atleast 7 days worth of data)
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import QuickTooltip from "components/layout/misc/QuickTooltip";
|
||||
import React from "react";
|
||||
import { Badge } from "react-bootstrap";
|
||||
import { GetGamePTConfig, IDStrings, integer } from "tachi-common";
|
||||
import { GameClassSets } from "tachi-common/js/game-classes";
|
||||
import { GamePT } from "types/react";
|
||||
import { UppercaseFirst } from "util/misc";
|
||||
|
||||
export default function ClassBadge<I extends IDStrings = IDStrings>({
|
||||
game,
|
||||
playtype,
|
||||
classSet,
|
||||
classValue,
|
||||
showSetOnHover = true,
|
||||
}: {
|
||||
classSet: GameClassSets[I];
|
||||
classValue: integer;
|
||||
showSetOnHover?: boolean;
|
||||
} & GamePT) {
|
||||
const gptConfig = GetGamePTConfig(game, playtype);
|
||||
|
||||
const data = gptConfig.classHumanisedFormat[classSet][classValue];
|
||||
|
||||
if (!data) {
|
||||
throw new Error(`Unknown class value ${classSet}:${classValue}`);
|
||||
}
|
||||
|
||||
let badgeComponent;
|
||||
if (data.variant) {
|
||||
badgeComponent = <Badge variant={data.variant}>{data.display}</Badge>;
|
||||
} else if (data.css) {
|
||||
badgeComponent = <Badge style={data.css}>{data.display}</Badge>;
|
||||
} else {
|
||||
badgeComponent = <Badge variant="secondary">{data.display}</Badge>;
|
||||
}
|
||||
|
||||
if (data.mouseover && showSetOnHover) {
|
||||
return (
|
||||
<QuickTooltip text={`${UppercaseFirst(classSet)}: ${data.mouseover}`}>
|
||||
{badgeComponent}
|
||||
</QuickTooltip>
|
||||
);
|
||||
} else if (data.mouseover) {
|
||||
return <QuickTooltip text={data.mouseover}>{badgeComponent}</QuickTooltip>;
|
||||
} else if (showSetOnHover) {
|
||||
<QuickTooltip text={UppercaseFirst(classSet)}>{badgeComponent}</QuickTooltip>;
|
||||
}
|
||||
|
||||
return badgeComponent;
|
||||
}
|
||||
@@ -17,7 +17,11 @@ export function Footer() {
|
||||
</div>
|
||||
|
||||
<div className="nav nav-dark order-1 order-md-2 justify-content-center">
|
||||
<Link to="/dashboard/credits" className="nav-link px-3">
|
||||
<Link
|
||||
to="/dashboard/credits"
|
||||
className="nav-link px-3"
|
||||
onClick={() => window.scrollTo(0, 0)}
|
||||
>
|
||||
Credits
|
||||
</Link>
|
||||
<a
|
||||
|
||||
@@ -21,5 +21,5 @@ export default function AllGames() {
|
||||
}
|
||||
}
|
||||
|
||||
return <MenuDropdown name="All Games">{links}</MenuDropdown>;
|
||||
return <MenuDropdown name="Games">{links}</MenuDropdown>;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ export function HeaderMenu() {
|
||||
{/* <MenuLink name="Dashboard" to="/dashboard" /> */}
|
||||
|
||||
{user && ugs && ugs.length !== 0 && (
|
||||
<MenuDropdown name="My Games">
|
||||
<MenuDropdown name="Your Profiles">
|
||||
{ugs.map(e => (
|
||||
<MenuLink
|
||||
key={`${e.game}:${e.playtype}`}
|
||||
|
||||
@@ -10,7 +10,9 @@ export default function MiniTable({
|
||||
colSpan = 1,
|
||||
}: { className?: string; headers: string[]; colSpan?: integer } & JustChildren) {
|
||||
return (
|
||||
<table className={`table table-hover table-striped ${className}`}>
|
||||
<table
|
||||
className={`table table-hover table-striped table-vertical-center text-center ${className}`}
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
{headers.map(e => (
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ChangeOpacity } from "util/color-opacity";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import SelectableRating from "../components/SelectableRating";
|
||||
import { ScoreDataset } from "types/tables";
|
||||
import { GetGamePTConfig, ScoreCalculatedDataLookup } from "tachi-common";
|
||||
import { GetGamePTConfig, integer, ScoreCalculatedDataLookup } from "tachi-common";
|
||||
import TachiTable, { Header } from "../components/TachiTable";
|
||||
import DifficultyCell from "../cells/DifficultyCell";
|
||||
import ScoreCell from "../cells/ScoreCell";
|
||||
@@ -15,7 +15,13 @@ import DeltaCell from "../cells/DeltaCell";
|
||||
import { HumanFriendlyStrToGradeIndex, HumanFriendlyStrToLampIndex } from "util/str-to-num";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
export default function IIDXScoreTable({ dataset }: { dataset: ScoreDataset<"iidx:SP"> }) {
|
||||
export default function IIDXScoreTable({
|
||||
dataset,
|
||||
pageLen,
|
||||
}: {
|
||||
dataset: ScoreDataset<"iidx:SP">;
|
||||
pageLen?: integer;
|
||||
}) {
|
||||
const gptConfig = GetGamePTConfig<"iidx:SP">("iidx", "SP");
|
||||
|
||||
const [rating, setRating] = useState<ScoreCalculatedDataLookup["iidx:SP"]>(
|
||||
@@ -25,6 +31,7 @@ export default function IIDXScoreTable({ dataset }: { dataset: ScoreDataset<"iid
|
||||
return (
|
||||
<TachiTable
|
||||
dataset={dataset}
|
||||
pageLen={pageLen}
|
||||
headers={[
|
||||
["Chart", "Ch.", NumericSOV(x => x.__related.chart.levelNum)],
|
||||
["Song", "Song", StrSOV(x => x.__related.song.title)],
|
||||
@@ -85,7 +92,27 @@ export default function IIDXScoreTable({ dataset }: { dataset: ScoreDataset<"iid
|
||||
>
|
||||
<strong>{sc.scoreData.lamp}</strong>
|
||||
<br />
|
||||
<small>[BP: {sc.scoreData.hitMeta.bp ?? "No Data"}]</small>
|
||||
<small>
|
||||
[BP: {sc.scoreData.hitMeta.bp ?? "No Data"}
|
||||
{sc.scoreData.hitMeta.comboBreak
|
||||
? `, CBRK: ${sc.scoreData.hitMeta.comboBreak}`
|
||||
: ""}
|
||||
]
|
||||
</small>
|
||||
{sc.scoreData.lamp === "FAILED" && (
|
||||
<>
|
||||
<br />
|
||||
<small className="text-muted">
|
||||
{sc.scoreData.hitMeta.gsm
|
||||
? `EC: ${sc.scoreData.hitMeta.gsm.EASY}, NC: ${sc.scoreData.hitMeta.gsm.NORMAL}`
|
||||
: sc.scoreMeta.gauge === "EASY"
|
||||
? `EC: ${sc.scoreData.hitMeta.gauge}`
|
||||
: sc.scoreMeta.gauge === "NORMAL"
|
||||
? `NC: ${sc.scoreMeta.gauge}`
|
||||
: ""}
|
||||
</small>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
{rating === "BPI" ? (
|
||||
<BPICell bpi={sc.calculatedData.BPI} />
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
SessionScoreInfo,
|
||||
} from "tachi-common";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { GetPBs } from "util/data";
|
||||
import { NumericSOV, StrSOV } from "util/sorts";
|
||||
import { FormatDuration, FormatTime, MillisToSince } from "util/time";
|
||||
import IndexCell from "../cells/IndexCell";
|
||||
@@ -87,7 +88,3 @@ export default function GenericSessionTable({
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function GetPBs(scoreInfo: SessionScoreInfo[]) {
|
||||
return scoreInfo.map(e => e.isNewScore === true || e.lampDelta > 0 || e.scoreDelta > 0);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import MiniTable from "components/tables/components/MiniTable";
|
||||
import Divider from "components/util/Divider";
|
||||
import React from "react";
|
||||
import { Game, GetGameConfig, PublicUserDocument } from "tachi-common";
|
||||
import { Game, GetGameConfig, GetGamePTConfig, PublicUserDocument } from "tachi-common";
|
||||
import { UGPTStatsReturn } from "types/api-returns";
|
||||
import { Playtype } from "types/tachi";
|
||||
import { MillisToSince } from "util/time";
|
||||
import ProfilePicture from "./ProfilePicture";
|
||||
import Navbar from "components/nav/Navbar";
|
||||
import NavItem from "components/nav/NavItem";
|
||||
import ClassBadge from "components/game/ClassBadge";
|
||||
import { UppercaseFirst } from "util/misc";
|
||||
|
||||
export default function UGPTHeader({
|
||||
reqUser,
|
||||
@@ -21,6 +23,7 @@ export default function UGPTHeader({
|
||||
stats: UGPTStatsReturn;
|
||||
}) {
|
||||
const gameConfig = GetGameConfig(game);
|
||||
const gptConfig = GetGamePTConfig(game, playtype);
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
@@ -77,18 +80,31 @@ export default function UGPTHeader({
|
||||
colSpan={2}
|
||||
>
|
||||
<>
|
||||
{gptConfig.supportedClasses.map(k => (
|
||||
<tr key={k}>
|
||||
<td>{UppercaseFirst(k)}</td>
|
||||
<td>
|
||||
{stats.gameStats.classes[k] ? (
|
||||
<ClassBadge
|
||||
showSetOnHover={false}
|
||||
key={`${k}:${stats.gameStats.classes[k]}`}
|
||||
game={game}
|
||||
playtype={playtype}
|
||||
classSet={k}
|
||||
classValue={stats.gameStats.classes[k]!}
|
||||
/>
|
||||
) : (
|
||||
"No Data"
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{Object.entries(stats.gameStats.ratings).map(([k, v]) => (
|
||||
<tr key={k}>
|
||||
<td>{k}</td>
|
||||
<td>{v.toFixed(2)}</td>
|
||||
</tr>
|
||||
))}
|
||||
{Object.entries(stats.gameStats.classes).map(([k, v]) => (
|
||||
<tr key={k}>
|
||||
<td>{k}</td>
|
||||
<td>{v}</td>
|
||||
</tr>
|
||||
))}
|
||||
</>
|
||||
</MiniTable>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@ export default function AsyncLoader<T = unknown>({
|
||||
}: {
|
||||
promiseFn?: () => Promise<T>;
|
||||
promise?: Promise<T>;
|
||||
children: (data: T) => JSX.Element;
|
||||
children: (data: T) => JSX.Element | null | string | (JSX.Element | string)[];
|
||||
}) {
|
||||
const Component = children;
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user