Skip to content

Commit 11cfed8

Browse files
committed
wip
1 parent 0ba7f62 commit 11cfed8

23 files changed

Lines changed: 559 additions & 86 deletions

File tree

frontend/src/html/pages/test.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
<div id="memoryTimer">Time left to memorise all words: 0s</div>
2323
<div id="layoutfluidTimer">Time left to memorise all words: 0s</div>
2424
<div id="testModesNotice"></div>
25+
<mount data-component="testmodesnotice"></mount>
26+
2527
<div id="liveStatsTextTop" class="timerMain">
2628
<div class="wrapper">
2729
<div class="timerProgress hidden">1:00</div>

frontend/src/ts/collections/results.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@ import { queryOptions } from "@tanstack/solid-query";
2424
import { Accessor } from "solid-js";
2525
import Ape from "../ape";
2626
import { SnapshotResult } from "../constants/default-snapshot";
27+
import { createEffectOn } from "../hooks/effects";
2728
import { queryClient } from "../queries";
2829
import { baseKey } from "../queries/utils/keys";
30+
import { isAuthenticated } from "../states/core";
31+
import { getLastResult, setLastResult } from "../states/snapshot";
2932
import {
30-
__nonReactive as tagsNonReactive,
3133
reconcileLocalTagPB,
3234
saveLocalTagPB,
35+
__nonReactive as tagsNonReactive,
3336
} from "./tags";
34-
import { isAuthenticated } from "../states/core";
35-
import { createEffectOn } from "../hooks/effects";
36-
import { getLastResult, setLastResult } from "../states/snapshot";
3737
import { applyIdWorkaround } from "./utils/misc";
3838

3939
export type ResultsQueryState = {
@@ -549,7 +549,23 @@ export type CurrentSettingsFilter = {
549549
lazyMode: boolean;
550550
};
551551

552-
export async function getUserAverage10(
552+
// oxlint-disable-next-line typescript/explicit-function-return-type
553+
export function useUserAverage10LiveQuery(options: CurrentSettingsFilter) {
554+
return useLiveQuery((q) =>
555+
q
556+
.from({
557+
//we use sub-query to filter first and then aggregate
558+
last10: buildSettingsResultsQuery(options, {
559+
tagIds: tagsNonReactive.getActiveTags().map((it) => it._id),
560+
})
561+
.orderBy(({ r }) => r.timestamp, "desc")
562+
.limit(10),
563+
})
564+
.select(({ last10 }) => ({ wpm: avg(last10.wpm), acc: avg(last10.acc) })),
565+
);
566+
}
567+
568+
export async function getUserAverage10Once(
553569
options: CurrentSettingsFilter,
554570
): Promise<{ wpm: number; acc: number }> {
555571
//exit early if there is no user. Don't init the result collection

frontend/src/ts/collections/tags.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { queryCollectionOptions } from "@tanstack/query-db-collection";
33
import {
44
createCollection,
55
createOptimisticAction,
6+
eq,
67
useLiveQuery,
78
} from "@tanstack/solid-db";
89
import { z } from "zod";
@@ -60,6 +61,16 @@ export function useTagsLiveQuery() {
6061
});
6162
}
6263

64+
// oxlint-disable-next-line typescript/explicit-function-return-type
65+
export function useActiveTagsLiveQuery() {
66+
return useLiveQuery((q) => {
67+
return q
68+
.from({ tag: tagsCollection })
69+
.where(({ tag }) => eq(tag.active, true))
70+
.orderBy(({ tag }) => tag.name, "asc");
71+
});
72+
}
73+
6374
type ActionType = {
6475
insertTag: {
6576
name: string;

frontend/src/ts/commandline/lists/bail-out.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { Config } from "../../config/store";
2+
import { getCustomTextIndicator } from "../../states/core";
23
import * as CustomText from "../../test/custom-text";
34
import * as TestLogic from "../../test/test-logic";
45
import * as TestState from "../../test/test-state";
5-
import * as CustomTextState from "../../legacy-states/custom-text-name";
66
import { Command, CommandsSubgroup } from "../types";
77

88
function canBailOut(): boolean {
99
return (
10-
(Config.mode === "custom" && CustomTextState.isCustomTextLong() === true) ||
10+
(Config.mode === "custom" && getCustomTextIndicator()?.isLong === true) ||
1111
(Config.mode === "custom" &&
1212
(CustomText.getLimitMode() === "word" ||
1313
CustomText.getLimitMode() === "section") &&

frontend/src/ts/components/modals/CustomTextModal.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import type { FaSolidIcon } from "../../types/font-awesome";
88
import { setConfig } from "../../config/setters";
99
import { Config } from "../../config/store";
1010
import { restartTestEvent } from "../../events/test";
11-
import * as CustomTextState from "../../legacy-states/custom-text-name";
11+
import {
12+
getCustomTextIndicator,
13+
setCustomTextIndicator,
14+
} from "../../states/core";
1215
import { hideModalAndClearChain, showModal } from "../../states/modals";
1316
import {
1417
showNoticeNotification,
@@ -276,7 +279,7 @@ export function CustomTextModal(): JSXElement {
276279
});
277280
});
278281

279-
setLongTextWarning(CustomTextState.isCustomTextLong() ?? false);
282+
setLongTextWarning(getCustomTextIndicator()?.isLong ?? false);
280283
setChallengeWarning(getLoadedChallenge() !== null);
281284
};
282285

@@ -285,8 +288,8 @@ export function CustomTextModal(): JSXElement {
285288
if (data === null) return;
286289
setIncomingChainedData(null);
287290

288-
if (data.long !== true && CustomTextState.isCustomTextLong()) {
289-
CustomTextState.setCustomTextName("", undefined);
291+
if (data.long !== true && getCustomTextIndicator()?.isLong) {
292+
setCustomTextIndicator(undefined);
290293
showNoticeNotification("Disabled long custom text progress tracking", {
291294
durationMs: 5000,
292295
});
@@ -358,11 +361,8 @@ export function CustomTextModal(): JSXElement {
358361
if (e.code === "Enter" && e.ctrlKey) {
359362
void form.handleSubmit();
360363
}
361-
if (
362-
CustomTextState.isCustomTextLong() &&
363-
CustomTextState.getCustomTextName() !== ""
364-
) {
365-
CustomTextState.setCustomTextName("", undefined);
364+
if (getCustomTextIndicator()?.isLong) {
365+
setCustomTextIndicator(undefined);
366366
setLongTextWarning(false);
367367
showNoticeNotification("Disabled long custom text progress tracking", {
368368
durationMs: 5000,

frontend/src/ts/components/modals/SaveCustomTextModal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createForm } from "@tanstack/solid-form";
22
import { Accessor, JSXElement } from "solid-js";
33
import { z } from "zod";
44

5-
import * as CustomTextState from "../../legacy-states/custom-text-name";
5+
import { setCustomTextIndicator } from "../../states/core";
66
import { hideModal } from "../../states/modals";
77
import {
88
showNoticeNotification,
@@ -42,7 +42,7 @@ export function SaveCustomTextModal(props: {
4242

4343
const saved = CustomText.setCustomText(value.name, text, value.isLong);
4444
if (saved) {
45-
CustomTextState.setCustomTextName(value.name, value.isLong);
45+
setCustomTextIndicator(value);
4646
showSuccessNotification("Custom text saved");
4747
hideModal("SaveCustomText");
4848
} else {

frontend/src/ts/components/modals/SavedTextsModal.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createSignal, For, Index, JSXElement, Setter, Show } from "solid-js";
22

3-
import * as CustomTextState from "../../legacy-states/custom-text-name";
3+
import { setCustomTextIndicator } from "../../states/core";
44
import { hideModal } from "../../states/modals";
55
import { showSimpleModal } from "../../states/simple-modal";
66
import * as CustomText from "../../test/custom-text";
@@ -40,7 +40,7 @@ export function SavedTextsModal(props: {
4040
};
4141

4242
const handleNameClick = (name: string, long: boolean) => {
43-
CustomTextState.setCustomTextName(name, long);
43+
setCustomTextIndicator({ name, isLong: long });
4444
const text = getSavedText(name, long);
4545
props.setChainedData({ text, long });
4646
hideModal("SavedTexts");
@@ -53,7 +53,7 @@ export function SavedTextsModal(props: {
5353
buttonText: "delete",
5454
execFn: async () => {
5555
CustomText.deleteCustomText(name, long);
56-
CustomTextState.setCustomTextName("", undefined);
56+
setCustomTextIndicator(undefined);
5757
refresh();
5858
return {
5959
status: "success",

frontend/src/ts/components/mount.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { ProfilePage } from "./pages/profile/ProfilePage";
2020
import { ProfileSearchPage } from "./pages/profile/ProfileSearchPage";
2121
import { TestConfig } from "./pages/test/TestConfig";
2222
import { Popups } from "./popups/Popups";
23+
import { TestModesNotice } from "./test/modes-notice/TestModesNotice";
2324

2425
const components: Record<string, () => JSXElement> = {
2526
footer: () => <Footer />,
@@ -38,6 +39,7 @@ const components: Record<string, () => JSXElement> = {
3839
devtools: () => <DevTools />,
3940
testconfig: () => <TestConfig />,
4041
commandlinehotkey: () => <CommandlineHotkey />,
42+
testmodesnotice: () => <TestModesNotice />,
4143
};
4244

4345
function mountToMountpoint(name: string, component: () => JSXElement): void {
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { createMemo, JSXElement, Show } from "solid-js";
2+
3+
import { getConfig } from "../../../config/store";
4+
import {
5+
isAuthenticated,
6+
showCommandLineForConfig,
7+
} from "../../../states/core";
8+
import { Formatting } from "../../../utils/format";
9+
import { Button } from "../../common/Button";
10+
11+
export function Last10Average(): JSXElement {
12+
const _format = createMemo(() => new Formatting(getConfig));
13+
14+
return (
15+
<Show when={isAuthenticated() && getConfig.showAverage !== "off"}>
16+
average
17+
<Button
18+
variant="text"
19+
fa={{ icon: "fa-chart-bar" }}
20+
onClick={() => showCommandLineForConfig("showAverage")}
21+
>
22+
avg:
23+
{/*}
24+
<Show
25+
when={
26+
getConfig.showAverage === "speed" ||
27+
getConfig.showAverage === "both"
28+
}
29+
>
30+
<span>
31+
{format().typingSpeed(last10()?.wpm)} {getConfig.typingSpeedUnit}
32+
</span>
33+
</Show>
34+
<Show
35+
when={
36+
getConfig.showAverage === "acc" || getConfig.showAverage === "both"
37+
}
38+
>
39+
<span>{format().accuracy(last10()?.acc)} acc</span>
40+
</Show>
41+
{*/}
42+
</Button>
43+
</Show>
44+
);
45+
}

0 commit comments

Comments
 (0)