impr(result): add new crown states (error, warning, ineligible, normal)

This commit is contained in:
Miodec 2024-05-28 17:11:10 +02:00
parent aa2466a0d1
commit bc3ecb25eb
6 changed files with 235 additions and 66 deletions

View file

@ -181,8 +181,16 @@
<div class="group wpm">
<div class="top">
<div class="text">wpm</div>
<div class="crown hidden" aria-label="" data-balloon-pos="up">
<div
class="crown hidden"
aria-label=""
data-balloon-pos="up"
data-balloon-length="medium"
>
<i class="fas fa-question"></i>
<i class="fas fa-crown"></i>
<i class="fas fa-slash"></i>
<i class="fas fa-exclamation-triangle"></i>
</div>
</div>
<div class="bottom" aria-label="" data-balloon-pos="up">-</div>

View file

@ -822,32 +822,76 @@
font-size: 2rem;
line-height: 1.5rem;
display: flex;
// margin-top: -0.5rem;
// .crownWrapper {
// width: 1.7rem;
// overflow: hidden;
// height: 1.7rem;
// margin-left: 0.5rem;
// // margin-top: 0.98rem;
// margin-top: -0.5rem;
.crown {
height: 1.7rem;
width: 1.7rem;
--main: var(--main-color);
--alt: var(--bg-color);
margin-left: 0.5rem;
margin-top: -0.2rem;
font-size: 0.7rem;
line-height: 1.7rem;
background: var(--main-color);
color: var(--bg-color);
border-radius: 0.6rem;
text-align: center;
align-self: center;
background: var(--main);
color: var(--alt);
width: 1.7rem;
height: 1.7rem;
border-radius: var(--roundness);
display: grid;
grid-template-areas: "icon";
align-items: center;
justify-items: center;
transition: opacity 0.125s, background 0.125s, color 0.125s,
outline 0.125s;
i {
grid-area: icon;
}
.fa-slash {
color: var(--main);
font-size: 1.2rem;
opacity: 0;
}
.fa-question,
.fa-exclamation-triangle {
color: var(--alt);
opacity: 0;
}
&.half {
--main: var(--bg-color);
--alt: var(--main-color);
outline: 0.2em solid var(--main-color);
}
&.broken {
--main: var(--sub-color);
--alt: var(--bg-color);
.fa-slash {
opacity: 1;
}
}
&.error {
--main: var(--error-color);
--alt: var(--bg-color);
.fa-crown {
opacity: 0;
}
.fa-question {
opacity: 1;
}
}
&.warning {
--main: var(--sub-color);
--alt: var(--bg-color);
.fa-crown {
opacity: 0;
}
.fa-exclamation-triangle {
opacity: 1;
}
}
}
// }
}
.bottom {

View file

@ -1,16 +1,36 @@
export function hide(): void {
visible = false;
$("#result .stats .wpm .crown").css("opacity", 0).addClass("hidden");
}
export function show(): void {
$("#result .stats .wpm .crown")
.removeClass("hidden")
.css("opacity", "0")
.animate(
{
opacity: 1,
},
250,
"easeOutCubic"
);
export type CrownType = "normal" | "broken" | "half" | "error" | "warning";
let visible = false;
let currentType: CrownType = "normal";
export function getCurrentType(): CrownType {
return currentType;
}
export function show(): void {
if (visible) return;
visible = true;
const el = $("#result .stats .wpm .crown");
el.removeClass("hidden").css("opacity", "0").animate(
{
opacity: 1,
},
250,
"easeOutCubic"
);
}
export function update(type: CrownType): void {
currentType = type;
const el = $("#result .stats .wpm .crown");
el.removeClass("broken");
el.removeClass("half");
el.removeClass("error");
el.removeClass("warning");
el.addClass(type);
}

View file

@ -363,8 +363,134 @@ function updateKey(): void {
);
}
export function showCrown(): void {
export function showCrown(type: PbCrown.CrownType): void {
PbCrown.show();
PbCrown.update(type);
}
export function updateCrownType(type: PbCrown.CrownType): void {
PbCrown.update(type);
}
export async function updateCrown(): Promise<void> {
if (Config.mode === "quote") {
hideCrown();
return;
}
let pbDiff = 0;
const canGetPb = await resultCanGetPb();
if (canGetPb.value) {
const lpb = await DB.getLocalPB(
Config.mode,
result.mode2,
Config.punctuation,
Config.numbers,
Config.language,
Config.difficulty,
Config.lazyMode,
Config.funbox
);
pbDiff = result.wpm - lpb;
if (pbDiff <= 0) {
hideCrown();
} else {
//show half crown as the pb is not confirmed by the server
showCrown("half");
$("#result .stats .wpm .crown").attr(
"aria-label",
"+" + Format.typingSpeed(pbDiff, { showDecimalPlaces: true })
);
}
} else {
const lpb = await DB.getLocalPB(
Config.mode,
result.mode2,
Config.punctuation,
Config.numbers,
Config.language,
Config.difficulty,
Config.lazyMode,
"none"
);
pbDiff = result.wpm - lpb;
if (pbDiff <= 0) {
// hideCrown();
showCrown("warning");
$("#result .stats .wpm .crown").attr(
"aria-label",
`This result is not eligible for a new PB (${canGetPb.reason})`
);
} else {
showCrown("broken");
$("#result .stats .wpm .crown").attr(
"aria-label",
`You could've gotten a new PB (+${Format.typingSpeed(pbDiff, {
showDecimalPlaces: true,
})}), but your config does not allow it (${canGetPb.reason})`
);
}
}
}
export function hideCrown(): void {
PbCrown.hide();
$("#result .stats .wpm .crown").attr("aria-label", "");
}
export function showErrorCrownIfNeeded(): void {
if (PbCrown.getCurrentType() !== "half") return;
PbCrown.show();
PbCrown.update("error");
$("#result .stats .wpm .crown").attr(
"aria-label",
`Local PB data is out of sync with the server - please refresh (pb mismatch)`
);
}
type CanGetPbObject =
| {
value: true;
}
| {
value: false;
reason: string;
};
async function resultCanGetPb(): Promise<CanGetPbObject> {
const funboxes = result.funbox?.split("#") ?? [];
const funboxObjects = await Promise.all(
funboxes.map(async (f) => JSONData.getFunbox(f))
);
const allFunboxesCanGetPb = funboxObjects.every((f) => f?.canGetPb);
const funboxesOk =
result.funbox === "none" || funboxes.length === 0 || allFunboxesCanGetPb;
const notUsingStopOnLetter = Config.stopOnError !== "letter";
if (funboxesOk && notUsingStopOnLetter) {
return {
value: true,
};
} else {
if (!funboxesOk) {
return {
value: false,
reason: "funbox",
};
}
if (!notUsingStopOnLetter) {
return {
value: false,
reason: "stop on letter",
};
}
return {
value: false,
reason: "unknown",
};
}
}
export function showConfetti(): void {
@ -399,30 +525,6 @@ export function showConfetti(): void {
})();
}
export function hideCrown(): void {
PbCrown.hide();
$("#result .stats .wpm .crown").attr("aria-label", "");
}
export async function updateCrown(): Promise<void> {
let pbDiff = 0;
const lpb = await DB.getLocalPB(
Config.mode,
result.mode2,
Config.punctuation,
Config.numbers,
Config.language,
Config.difficulty,
Config.lazyMode,
Config.funbox
);
pbDiff = Math.abs(result.wpm - lpb);
$("#result .stats .wpm .crown").attr(
"aria-label",
"+" + Format.typingSpeed(pbDiff, { showDecimalPlaces: true })
);
}
async function updateTags(dontSave: boolean): Promise<void> {
const activeTags: MonkeyTypes.UserTag[] = [];
const userTagsCount = DB.getSnapshot()?.tags?.length ?? 0;
@ -451,14 +553,6 @@ async function updateTags(dontSave: boolean): Promise<void> {
);
$("#result .stats .tags .editTagsButton").addClass("invisible");
const funboxes = result.funbox?.split("#") ?? [];
const funboxObjects = await Promise.all(
funboxes.map(async (f) => JSONData.getFunbox(f))
);
const allFunboxesCanGetPb = funboxObjects.every((f) => f?.canGetPb);
let annotationSide = "start";
let labelAdjust = 15;
activeTags.forEach(async (tag) => {
@ -479,7 +573,7 @@ async function updateTags(dontSave: boolean): Promise<void> {
if (
Config.mode !== "quote" &&
!dontSave &&
(result.funbox === "none" || funboxes.length === 0 || allFunboxesCanGetPb)
(await resultCanGetPb()).value
) {
if (tpb < result.wpm) {
//new pb for that tag
@ -763,6 +857,7 @@ export async function update(
updateTestType(randomQuote);
updateQuoteSource(randomQuote);
updateQuoteFavorite(randomQuote);
await updateCrown();
await updateGraph();
await updateGraphPBLine();
await updateTags(dontSave);

View file

@ -1195,8 +1195,7 @@ async function saveResult(
) {
Result.showConfetti();
}
Result.showCrown();
await Result.updateCrown();
Result.showCrown("normal");
await DB.saveLocalPB(
Config.mode,
completedEvent.mode2,
@ -1210,6 +1209,8 @@ async function saveResult(
completedEvent.rawWpm,
completedEvent.consistency
);
} else {
Result.showErrorCrownIfNeeded();
}
// if (response.data.dailyLeaderboardRank) {

View file

@ -237,6 +237,7 @@ declare namespace SharedTypes {
charTotal: number;
stringified?: string;
hash?: string;
stopOnLetter: boolean;
}
type CustomTextMode = "repeat" | "random" | "shuffle";