mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-12-11 13:57:28 +08:00
Merge branch 'newnav'
This commit is contained in:
commit
85dc20e8cd
38 changed files with 1437 additions and 396 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import _ from "lodash";
|
||||
import _, { eq } from "lodash";
|
||||
import * as UserDAL from "../../dal/user";
|
||||
import MonkeyError from "../../utils/error";
|
||||
import Logger from "../../utils/logger";
|
||||
|
|
@ -160,9 +160,14 @@ export async function getUser(
|
|||
const agentLog = buildAgentLog(req);
|
||||
Logger.logToDb("user_data_requested", agentLog, uid);
|
||||
|
||||
let inboxUnreadSize = 0;
|
||||
if (req.ctx.configuration.users.inbox.enabled) {
|
||||
inboxUnreadSize = _.filter(userInfo.inbox, { read: false }).length;
|
||||
}
|
||||
|
||||
const userData = {
|
||||
...getRelevantUserInfo(userInfo),
|
||||
inboxUnreadSize: _.filter(userInfo.inbox, { read: false }).length,
|
||||
inboxUnreadSize: inboxUnreadSize,
|
||||
};
|
||||
|
||||
return new MonkeyResponse("User data retrieved", userData);
|
||||
|
|
@ -520,7 +525,10 @@ export async function getInbox(
|
|||
|
||||
const inbox = await UserDAL.getInbox(uid);
|
||||
|
||||
return new MonkeyResponse("Inbox retrieved", inbox);
|
||||
return new MonkeyResponse("Inbox retrieved", {
|
||||
inbox,
|
||||
maxMail: req.ctx.configuration.users.inbox.maxMail,
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateInbox(
|
||||
|
|
|
|||
|
|
@ -818,7 +818,8 @@ function buildRewardUpdates(
|
|||
if (reward.type === "xp") {
|
||||
totalXp += isNaN(reward.item) ? 0 : reward.item;
|
||||
} else if (reward.type === "badge") {
|
||||
newBadges.push(reward.item);
|
||||
const item = _.omit(reward.item, "selected");
|
||||
newBadges.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -213,8 +213,9 @@ key {
|
|||
}
|
||||
|
||||
.pageLoading {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pageLoading,
|
||||
|
|
@ -356,7 +357,7 @@ key {
|
|||
color: var(--sub-color);
|
||||
cursor: pointer;
|
||||
transition: background 0.125s, color 0.125s;
|
||||
padding: 0.5rem;
|
||||
padding: 0.5em;
|
||||
border-radius: var(--roundness);
|
||||
text-align: center;
|
||||
user-select: none;
|
||||
|
|
@ -364,16 +365,16 @@ key {
|
|||
align-content: center;
|
||||
height: min-content;
|
||||
height: -moz-min-content;
|
||||
line-height: 1.25rem;
|
||||
line-height: 1.25em;
|
||||
appearance: none;
|
||||
border: none;
|
||||
font-family: inherit;
|
||||
font-size: 1rem;
|
||||
font-size: 1em;
|
||||
width: max-content;
|
||||
width: -moz-max-content;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
gap: 0.25rem;
|
||||
gap: 0.25em;
|
||||
text-decoration: none;
|
||||
|
||||
.fas,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
gap: 1rem;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
.side {
|
||||
display: grid;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
}
|
||||
|
||||
.level {
|
||||
transition: 0.125s;
|
||||
width: max-content;
|
||||
font-size: 0.65rem;
|
||||
line-height: 1rem;
|
||||
|
|
@ -78,7 +79,7 @@
|
|||
position: absolute;
|
||||
left: 100%;
|
||||
margin-left: 0.5rem;
|
||||
top: 0;
|
||||
top: 0.2rem;
|
||||
transform: translateY(-50%);
|
||||
font-size: 0.75rem;
|
||||
color: var(--main-color);
|
||||
|
|
@ -97,6 +98,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
&:hover .level {
|
||||
background-color: var(--text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +132,7 @@
|
|||
}
|
||||
|
||||
#top {
|
||||
grid-template-areas: "logo menu config";
|
||||
grid-template-areas: "logo menu";
|
||||
line-height: 2.3rem;
|
||||
font-size: 2.3rem;
|
||||
/* text-align: center; */
|
||||
|
|
@ -136,7 +140,7 @@
|
|||
padding: 0 5px;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
grid-template-columns: auto 1fr;
|
||||
z-index: 2;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
|
@ -168,13 +172,13 @@
|
|||
font-size: 0.65rem;
|
||||
line-height: 0.65rem;
|
||||
color: var(--sub-color);
|
||||
transition: 0.25s;
|
||||
transition: color 0.25s;
|
||||
}
|
||||
position: relative;
|
||||
font-size: 2rem;
|
||||
margin-bottom: 0.4rem;
|
||||
margin-top: -0.4rem;
|
||||
font-family: "Lexend Deca";
|
||||
transition: 0.25s;
|
||||
transition: color 0.25s;
|
||||
}
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
|
|
|
|||
|
|
@ -1324,3 +1324,164 @@
|
|||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
#alertsPopupWrapper {
|
||||
padding: 0;
|
||||
justify-content: end;
|
||||
z-index: 99999999;
|
||||
// padding: 2rem;
|
||||
#alertsPopup {
|
||||
background: var(--bg-color);
|
||||
width: calc(350px + 2rem);
|
||||
right: 0;
|
||||
// height: calc(100vh - 4rem);
|
||||
height: 100%;
|
||||
top: 0;
|
||||
padding: 2rem calc(1rem - 7px) 2rem 1rem; // -7px for the scrollbar
|
||||
// padding: 1rem;
|
||||
// border-radius: var(--roundness);
|
||||
overflow: hidden;
|
||||
margin-right: -10rem;
|
||||
border-radius: var(--roundness) 0 0 var(--roundness);
|
||||
|
||||
.separator {
|
||||
background-color: var(--sub-alt-color);
|
||||
height: 0.25rem;
|
||||
width: 100%;
|
||||
border-radius: calc(var(--roundness) / 2);
|
||||
}
|
||||
|
||||
.scrollWrapper {
|
||||
padding: 0 1rem 0 1rem;
|
||||
overflow-y: scroll;
|
||||
display: grid;
|
||||
gap: 2rem;
|
||||
align-content: baseline;
|
||||
height: 100%;
|
||||
}
|
||||
.accountAlerts > .title,
|
||||
.notificationHistory > .title,
|
||||
.psas > .title {
|
||||
font-size: 1.25rem;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--sub-color);
|
||||
user-select: none;
|
||||
}
|
||||
.list {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
.nothing {
|
||||
width: 100%;
|
||||
color: var(--text-color);
|
||||
font-size: 0.75rem;
|
||||
text-align: center;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
.preloader {
|
||||
width: 100%;
|
||||
color: var(--main-color);
|
||||
text-align: center;
|
||||
font-size: 1rem;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
.item {
|
||||
display: grid;
|
||||
grid-template-areas: "indicator title buttons" "indicator body buttons";
|
||||
grid-template-columns: 0.25rem auto 1rem;
|
||||
gap: 0.25rem 0.5rem;
|
||||
.indicator {
|
||||
grid-area: indicator;
|
||||
background-color: var(--sub-alt-color);
|
||||
width: 0.25rem;
|
||||
height: 100%;
|
||||
border-radius: calc(var(--roundness) / 2);
|
||||
transition: 0.125s;
|
||||
&.main {
|
||||
background-color: var(--main-color);
|
||||
}
|
||||
&.error {
|
||||
background-color: var(--error-color);
|
||||
}
|
||||
&.sub {
|
||||
background-color: var(--sub-color);
|
||||
}
|
||||
}
|
||||
.title {
|
||||
grid-area: title;
|
||||
font-size: 0.75rem;
|
||||
color: var(--sub-color);
|
||||
}
|
||||
.body {
|
||||
grid-area: body;
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-color);
|
||||
transition: 0.125s;
|
||||
opacity: 1;
|
||||
}
|
||||
.buttons {
|
||||
grid-area: buttons;
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-auto-flow: row;
|
||||
gap: 0.5rem;
|
||||
opacity: 0;
|
||||
transition: 0.125s;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
.button {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.5em;
|
||||
line-height: 1.25em;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.buttons {
|
||||
opacity: 1;
|
||||
}
|
||||
.body {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.psas .list .item {
|
||||
grid-template-areas: "indicator body";
|
||||
grid-template-columns: 0.25rem auto;
|
||||
.body {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.notificationHistory .list .item {
|
||||
grid-template-areas: "indicator title" "indicator body";
|
||||
grid-template-columns: 0.25rem auto;
|
||||
.title {
|
||||
font-size: 0.75rem;
|
||||
color: var(--sub-color);
|
||||
}
|
||||
.body {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.accountAlerts {
|
||||
.title {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
.list .item {
|
||||
grid-template-areas: "indicator timestamp buttons" "indicator title buttons" "indicator body buttons";
|
||||
.timestamp {
|
||||
grid-area: timestamp;
|
||||
font-size: 0.6rem;
|
||||
color: var(--sub-color);
|
||||
opacity: 0.5;
|
||||
}
|
||||
.rewards {
|
||||
overflow: hidden;
|
||||
margin-top: 0.35rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -916,6 +916,117 @@
|
|||
}
|
||||
}
|
||||
|
||||
#mobileTestConfig {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 1rem;
|
||||
background: var(--sub-alt-color);
|
||||
border-radius: var(--roundness);
|
||||
width: max-content;
|
||||
justify-self: center;
|
||||
display: none;
|
||||
height: max-content;
|
||||
}
|
||||
|
||||
#testConfig {
|
||||
display: grid;
|
||||
font-size: 0.75rem;
|
||||
gap: 0.5rem;
|
||||
grid-auto-flow: column;
|
||||
height: max-content;
|
||||
width: 100%;
|
||||
justify-content: space-around;
|
||||
transition: 0.125s;
|
||||
margin-bottom: 1rem;
|
||||
.puncAndNum {
|
||||
// transition: 0.25s cubic-bezier(0.37, 0, 0.63, 1);
|
||||
overflow: hidden;
|
||||
max-width: 15rem;
|
||||
opacity: 1;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
// padding: 0 0.5rem;
|
||||
background: var(--sub-alt-color);
|
||||
border-radius: var(--roundness);
|
||||
// width: max-content;
|
||||
}
|
||||
.spacer {
|
||||
height: auto;
|
||||
width: 0.25rem;
|
||||
border-radius: calc(var(--roundness) / 2);
|
||||
background: var(--bg-color);
|
||||
margin: 0.5rem 0;
|
||||
transition: 0.25s;
|
||||
&.scrolled {
|
||||
width: 0;
|
||||
margin: auto 0;
|
||||
}
|
||||
}
|
||||
|
||||
.wordCount,
|
||||
.time {
|
||||
.textButton {
|
||||
line-height: 1rem;
|
||||
span {
|
||||
height: 1.1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mode,
|
||||
.time,
|
||||
.wordCount,
|
||||
.puncAndNum,
|
||||
.quoteLength,
|
||||
.customText,
|
||||
.zen {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
|
||||
.textButton {
|
||||
transition: 0.125s;
|
||||
padding: 0.75rem 0.5rem 0.7rem 0.5rem;
|
||||
|
||||
&:first-child {
|
||||
padding: 0.75rem 0.5rem 0.7rem 1rem;
|
||||
}
|
||||
&:last-child {
|
||||
padding: 0.75rem 1rem 0.7rem 0.5rem;
|
||||
}
|
||||
&:only-child {
|
||||
padding: 0.75rem 1rem 0.7rem 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.time,
|
||||
.wordCount,
|
||||
.customText,
|
||||
.zen,
|
||||
.quoteLength,
|
||||
.puncAndNum {
|
||||
// width: 100%;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
.customText {
|
||||
display: grid;
|
||||
}
|
||||
&.focus {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.pageTest {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: 1fr auto 1fr;
|
||||
}
|
||||
|
||||
#menu {
|
||||
width: 100%;
|
||||
grid-template-columns: auto auto auto 1fr auto;
|
||||
}
|
||||
|
||||
.pageTest {
|
||||
#wordsWrapper {
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -159,6 +159,29 @@
|
|||
}
|
||||
|
||||
@media only screen and (max-width: 900px) {
|
||||
#testConfig {
|
||||
.mode,
|
||||
.time,
|
||||
.wordCount,
|
||||
.puncAndNum,
|
||||
.customText,
|
||||
.zen,
|
||||
.quoteLength {
|
||||
.textButton {
|
||||
padding: 0.75rem 0.3rem 0.7rem 0.3rem;
|
||||
|
||||
&:first-child {
|
||||
padding: 0.75rem 0.3rem 0.7rem 0.6rem;
|
||||
}
|
||||
&:last-child {
|
||||
padding: 0.75rem 0.6rem 0.7rem 0.3rem;
|
||||
}
|
||||
&:only-child {
|
||||
padding: 0.75rem 0.6rem 0.7rem 0.6rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ad.ad-h {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -280,32 +303,97 @@
|
|||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
#testConfig {
|
||||
.spacer {
|
||||
display: none;
|
||||
}
|
||||
.row {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
padding: 0.25rem 1rem;
|
||||
}
|
||||
.mode,
|
||||
.time,
|
||||
.wordCount,
|
||||
.puncAndNum,
|
||||
.customText,
|
||||
.zen,
|
||||
.quoteLength {
|
||||
.textButton {
|
||||
padding: 0.5rem 0.75rem 0.45rem 0.75rem;
|
||||
|
||||
&:first-child {
|
||||
padding: 0.5rem 0.75rem 0.45rem 0.75rem;
|
||||
}
|
||||
&:last-child {
|
||||
padding: 0.5rem 0.75rem 0.45rem 0.75rem;
|
||||
}
|
||||
&:only-child {
|
||||
padding: 0.5rem 0.75rem 0.45rem 0.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#top {
|
||||
.logo {
|
||||
.text {
|
||||
font-size: 1.9rem !important;
|
||||
}
|
||||
.bottom {
|
||||
font-size: 1.9rem;
|
||||
line-height: 1.9rem;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
#menu {
|
||||
gap: 0.1rem;
|
||||
.textButton {
|
||||
padding: 0.25rem;
|
||||
font-size: 0.8rem;
|
||||
line-height: 0.8rem;
|
||||
&.account {
|
||||
margin-top: 0.05rem;
|
||||
.text {
|
||||
display: none;
|
||||
}
|
||||
.avatar {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
.level {
|
||||
line-height: 0.8rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.pageSettings .settingsGroup.quickNav .links {
|
||||
grid-auto-flow: unset;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
justify-items: center;
|
||||
}
|
||||
#centerContent {
|
||||
#top {
|
||||
grid-template-areas:
|
||||
"logo config"
|
||||
"menu config";
|
||||
grid-template-columns: auto auto;
|
||||
.logo {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
// #top {
|
||||
// grid-template-areas:
|
||||
// "logo config"
|
||||
// "menu config";
|
||||
// grid-template-columns: auto auto;
|
||||
// .logo {
|
||||
// margin-bottom: 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
#menu {
|
||||
gap: 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
line-height: 0.8rem;
|
||||
margin-top: -0.5rem;
|
||||
// #menu {
|
||||
// gap: 0.5rem;
|
||||
// font-size: 0.8rem;
|
||||
// line-height: 0.8rem;
|
||||
// margin-top: -0.5rem;
|
||||
|
||||
.textButton {
|
||||
padding: 0.25rem;
|
||||
}
|
||||
}
|
||||
// .textButton {
|
||||
// padding: 0.25rem;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
#contactPopupWrapper #contactPopup .buttons {
|
||||
|
|
@ -640,6 +728,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
#testModesNotice {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
#cookiePopupWrapper {
|
||||
#cookiePopup,
|
||||
.extensionMessage {
|
||||
|
|
@ -728,27 +819,15 @@
|
|||
}
|
||||
|
||||
#top {
|
||||
align-items: self-end;
|
||||
.logo {
|
||||
.icon {
|
||||
width: 1.5rem !important;
|
||||
}
|
||||
grid-template-columns: auto;
|
||||
.text {
|
||||
font-size: 1.5rem !important;
|
||||
margin-bottom: 0.3rem !important;
|
||||
}
|
||||
.bottom {
|
||||
font-size: 1.75rem;
|
||||
line-height: 1.75rem;
|
||||
margin-top: 0;
|
||||
}
|
||||
.top {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
#menu {
|
||||
.textButton {
|
||||
padding: 0;
|
||||
// padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -770,7 +849,7 @@
|
|||
}
|
||||
#centerContent {
|
||||
#top {
|
||||
grid-template-columns: 1fr auto;
|
||||
// grid-template-columns: 1fr auto;
|
||||
.desktopConfig {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -778,6 +857,7 @@
|
|||
display: block;
|
||||
}
|
||||
}
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
#middle {
|
||||
|
|
@ -806,6 +886,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
#testConfig {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mobileTestConfig {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 400px) {
|
||||
#top .config {
|
||||
grid-gap: 0.25rem;
|
||||
|
|
@ -888,6 +978,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
@media (pointer: coarse) and (max-width: 800px) {
|
||||
#testConfig {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mobileTestConfig {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
#commandLineMobileButton {
|
||||
display: block !important;
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
export function show(): void {
|
||||
// $(".signOut").removeClass("hidden").css("opacity", 1);
|
||||
$(".signOut")
|
||||
.stop(true, true)
|
||||
.removeClass("hidden")
|
||||
.css({
|
||||
opacity: 0,
|
||||
transition: "0s",
|
||||
})
|
||||
.animate(
|
||||
{
|
||||
opacity: 1,
|
||||
},
|
||||
125,
|
||||
() => {
|
||||
$(".signOut").css({ transition: "0.25s" });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function hide(): void {
|
||||
$(".signOut")
|
||||
.stop(true, true)
|
||||
.css({
|
||||
opacity: 1,
|
||||
transition: "0s",
|
||||
})
|
||||
.animate(
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
125,
|
||||
() => {
|
||||
$(".signOut").css({ transition: "0.25s" });
|
||||
$(".signOut").addClass("hidden");
|
||||
}
|
||||
);
|
||||
// $(".signOut").css("opacity", 0).addClass("hidden");
|
||||
}
|
||||
|
||||
// $("#liveWpm").removeClass("hidden").css("opacity", 0).animate(
|
||||
// {
|
||||
// opacity: Config.timerOpacity,
|
||||
// },
|
||||
// 125
|
||||
// );
|
||||
|
|
@ -192,4 +192,19 @@ export default class Users {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getInbox(): Promise<Ape.EndpointData> {
|
||||
return await this.httpClient.get(`${BASE_PATH}/inbox`);
|
||||
}
|
||||
|
||||
async updateInbox(options: {
|
||||
mailIdsToDelete?: string[];
|
||||
mailIdsToMarkRead?: string[];
|
||||
}): Promise<Ape.EndpointData> {
|
||||
const payload = {
|
||||
mailIdsToDelete: options.mailIdsToDelete,
|
||||
mailIdsToMarkRead: options.mailIdsToMarkRead,
|
||||
};
|
||||
return await this.httpClient.patch(`${BASE_PATH}/inbox`, { payload });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,11 +96,6 @@ export function setNumbers(numb: boolean, nosave?: boolean): boolean {
|
|||
numb = false;
|
||||
}
|
||||
config.numbers = numb;
|
||||
if (!config.numbers) {
|
||||
$("#top .config .numbersMode .textButton").removeClass("active");
|
||||
} else {
|
||||
$("#top .config .numbersMode .textButton").addClass("active");
|
||||
}
|
||||
saveToLocalStorage("numbers", nosave);
|
||||
ConfigEvent.dispatch("numbers", config.numbers);
|
||||
|
||||
|
|
@ -115,11 +110,6 @@ export function setPunctuation(punc: boolean, nosave?: boolean): boolean {
|
|||
punc = false;
|
||||
}
|
||||
config.punctuation = punc;
|
||||
if (!config.punctuation) {
|
||||
$("#top .config .punctuationMode .textButton").removeClass("active");
|
||||
} else {
|
||||
$("#top .config .punctuationMode .textButton").addClass("active");
|
||||
}
|
||||
saveToLocalStorage("punctuation", nosave);
|
||||
ConfigEvent.dispatch("punctuation", config.punctuation);
|
||||
|
||||
|
|
@ -982,15 +972,8 @@ export function setTimeConfig(
|
|||
|
||||
const newTime = isNaN(time) || time < 0 ? DefaultConfig.time : time;
|
||||
|
||||
$("#top .config .time .textButton").removeClass("active");
|
||||
|
||||
const timeCustom = ![15, 30, 60, 120].includes(newTime) ? "custom" : newTime;
|
||||
|
||||
config.time = newTime;
|
||||
|
||||
$("#top .config .time .textButton[timeConfig='" + timeCustom + "']").addClass(
|
||||
"active"
|
||||
);
|
||||
saveToLocalStorage("time", nosave);
|
||||
ConfigEvent.dispatch("time", config.time);
|
||||
|
||||
|
|
@ -1035,12 +1018,6 @@ export function setQuoteLength(
|
|||
}
|
||||
}
|
||||
// if (!nosave) setMode("quote", nosave);
|
||||
$("#top .config .quoteLength .textButton").removeClass("active");
|
||||
config.quoteLength.forEach((ql) => {
|
||||
$(
|
||||
"#top .config .quoteLength .textButton[quoteLength='" + ql + "']"
|
||||
).addClass("active");
|
||||
});
|
||||
saveToLocalStorage("quoteLength", nosave);
|
||||
ConfigEvent.dispatch("quoteLength", config.quoteLength);
|
||||
|
||||
|
|
@ -1056,17 +1033,8 @@ export function setWordCount(
|
|||
const newWordCount =
|
||||
wordCount < 0 || wordCount > 100000 ? DefaultConfig.words : wordCount;
|
||||
|
||||
$("#top .config .wordCount .textButton").removeClass("active");
|
||||
|
||||
const wordCustom = ![10, 25, 50, 100, 200].includes(newWordCount)
|
||||
? "custom"
|
||||
: newWordCount;
|
||||
|
||||
config.words = newWordCount;
|
||||
|
||||
$(
|
||||
"#top .config .wordCount .textButton[wordCount='" + wordCustom + "']"
|
||||
).addClass("active");
|
||||
saveToLocalStorage("words", nosave);
|
||||
ConfigEvent.dispatch("words", config.words);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,5 +27,6 @@ export const defaultSnap: MonkeyTypes.Snapshot = {
|
|||
addedAt: 0,
|
||||
filterPresets: [],
|
||||
xp: 0,
|
||||
inboxUnreadSize: 0,
|
||||
streak: 0,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import * as TagController from "./tag-controller";
|
|||
import * as ResultTagsPopup from "../popups/result-tags-popup";
|
||||
import * as URLHandler from "../utils/url-handler";
|
||||
import * as Account from "../pages/account";
|
||||
import * as Alerts from "../elements/alerts";
|
||||
import {
|
||||
EmailAuthProvider,
|
||||
GoogleAuthProvider,
|
||||
|
|
@ -238,8 +239,9 @@ export async function loadUser(user: UserType): Promise<void> {
|
|||
if ((await getDataAndInit()) === false) {
|
||||
signOut();
|
||||
}
|
||||
const { discordId, discordAvatar, xp } = DB.getSnapshot();
|
||||
const { discordId, discordAvatar, xp, inboxUnreadSize } = DB.getSnapshot();
|
||||
AccountButton.update(xp, discordId, discordAvatar);
|
||||
Alerts.setBellButtonColored(inboxUnreadSize > 0);
|
||||
// var displayName = user.displayName;
|
||||
// var email = user.email;
|
||||
// var emailVerified = user.emailVerified;
|
||||
|
|
@ -249,6 +251,8 @@ export async function loadUser(user: UserType): Promise<void> {
|
|||
// var providerData = user.providerData;
|
||||
LoginPage.hidePreloader();
|
||||
|
||||
$("#top .signInOut .icon").html(`<i class="fas fa-fw fa-sign-out-alt"></i>`);
|
||||
|
||||
// showFavouriteThemesAtTheTop();
|
||||
|
||||
if (TestLogic.notSignedInLastResult !== null) {
|
||||
|
|
@ -274,8 +278,12 @@ const authListener = Auth.onAuthStateChanged(async function (user) {
|
|||
const hash = window.location.hash;
|
||||
console.log(`auth state changed, user ${user ? true : false}`);
|
||||
if (user) {
|
||||
$("#top .signInOut .icon").html(
|
||||
`<i class="fas fa-fw fa-sign-out-alt"></i>`
|
||||
);
|
||||
await loadUser(user);
|
||||
} else {
|
||||
$("#top .signInOut .icon").html(`<i class="fas fa-fw fa-sign-in-alt"></i>`);
|
||||
if (window.location.pathname == "/account") {
|
||||
window.history.replaceState("", "", "/login");
|
||||
}
|
||||
|
|
@ -472,6 +480,9 @@ export function signOut(): void {
|
|||
DB.setSnapshot(defaultSnap);
|
||||
$(".pageLogin .button").removeClass("disabled");
|
||||
$(".pageLogin input").prop("disabled", false);
|
||||
$("#top .signInOut .icon").html(
|
||||
`<i class="fas fa-fw fa-sign-in-alt"></i>`
|
||||
);
|
||||
hideFavoriteQuoteLength();
|
||||
})
|
||||
.catch(function (error) {
|
||||
|
|
@ -643,8 +654,12 @@ $(".pageLogin .login .button.signInWithGoogle").on("click", () => {
|
|||
// signInWithGitHub();
|
||||
// });
|
||||
|
||||
$(".signOut").on("click", () => {
|
||||
signOut();
|
||||
$("#top .signInOut").on("click", () => {
|
||||
if (Auth.currentUser) {
|
||||
signOut();
|
||||
} else {
|
||||
navigate("/login");
|
||||
}
|
||||
});
|
||||
|
||||
$(".pageLogin .register input").keyup((e) => {
|
||||
|
|
|
|||
|
|
@ -120,3 +120,7 @@ export function getHTMLById(
|
|||
badge.icon ? `<i class="fas ${badge.icon}"></i>` : ""
|
||||
}${noText ? "" : `<div class="text">${badge.name}</div>`}</div>`;
|
||||
}
|
||||
|
||||
export function getById(id: number): MonkeyTypes.UserBadge {
|
||||
return badges[id];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ export async function initSnapshot(): Promise<
|
|||
snap.addedAt = userData.addedAt;
|
||||
snap.inventory = userData.inventory;
|
||||
snap.xp = userData.xp ?? 0;
|
||||
snap.inboxUnreadSize = userData.inboxUnreadSize ?? 0;
|
||||
snap.streak = userData?.streak?.length ?? 0;
|
||||
|
||||
if (userData.lbMemory?.time15 || userData.lbMemory?.time60) {
|
||||
|
|
@ -815,6 +816,17 @@ export function addXp(xp: number): void {
|
|||
setSnapshot(snapshot);
|
||||
}
|
||||
|
||||
export function addBadge(badge: MonkeyTypes.Badge): void {
|
||||
const snapshot = getSnapshot();
|
||||
if (snapshot.inventory === undefined) {
|
||||
snapshot.inventory = {
|
||||
badges: [],
|
||||
};
|
||||
}
|
||||
snapshot.inventory.badges.push(badge);
|
||||
setSnapshot(snapshot);
|
||||
}
|
||||
|
||||
export function setStreak(streak: number): void {
|
||||
const snapshot = getSnapshot();
|
||||
snapshot.streak = streak;
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ export async function update(
|
|||
export async function updateXpBar(
|
||||
currentXp: number,
|
||||
addedXp: number,
|
||||
breakdown: Record<string, number>
|
||||
breakdown?: Record<string, number>
|
||||
): Promise<void> {
|
||||
skipBreakdown = false;
|
||||
const startingLevel = Misc.getLevel(currentXp);
|
||||
|
|
@ -176,8 +176,12 @@ export async function updateXpBar(
|
|||
|
||||
async function animateXpBreakdown(
|
||||
addedXp: number,
|
||||
breakdown: Record<string, number>
|
||||
breakdown?: Record<string, number>
|
||||
): Promise<void> {
|
||||
if (!breakdown) {
|
||||
$("#menu .xpBar .xpGain").text(`+${addedXp}`);
|
||||
return;
|
||||
}
|
||||
const delay = 1000;
|
||||
let total = 0;
|
||||
const xpGain = $("#menu .xpBar .xpGain");
|
||||
|
|
|
|||
371
frontend/src/ts/elements/alerts.ts
Normal file
371
frontend/src/ts/elements/alerts.ts
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
import formatDistanceToNowStrict from "date-fns/formatDistanceToNowStrict";
|
||||
import Ape from "../ape";
|
||||
import { Auth } from "../firebase";
|
||||
import * as AccountButton from "../elements/account-button";
|
||||
import * as DB from "../db";
|
||||
import * as NotificationEvent from "../observables/notification-event";
|
||||
import * as BadgeController from "../controllers/badge-controller";
|
||||
import * as Notifications from "../elements/notifications";
|
||||
|
||||
let accountAlerts: MonkeyTypes.MonkeyMail[] = [];
|
||||
let maxMail = 0;
|
||||
let mailToMarkRead: string[] = [];
|
||||
let mailToDelete: string[] = [];
|
||||
|
||||
export function hide(): void {
|
||||
if (!$("#alertsPopupWrapper").hasClass("hidden")) {
|
||||
setBellButtonColored(false);
|
||||
|
||||
let mailUpdatedPromiseResolve: (value?: unknown) => void;
|
||||
const mailUpdatedPromise = new Promise((resolve) => {
|
||||
mailUpdatedPromiseResolve = resolve;
|
||||
});
|
||||
|
||||
const badgesClaimed: string[] = [];
|
||||
let totalXpClaimed = 0;
|
||||
if (mailToMarkRead.length > 0 || mailToDelete.length > 0) {
|
||||
Ape.users
|
||||
.updateInbox({
|
||||
mailIdsToMarkRead:
|
||||
mailToMarkRead.length > 0 ? mailToMarkRead : undefined,
|
||||
mailIdsToDelete: mailToDelete.length > 0 ? mailToDelete : undefined,
|
||||
})
|
||||
.then(async (updateResponse) => {
|
||||
const status = (await updateResponse).status;
|
||||
const message = (await updateResponse).message;
|
||||
if (status !== 200) {
|
||||
Notifications.add(`Failed to update inbox: ${message}`, -1);
|
||||
return;
|
||||
} else {
|
||||
const rewardsClaimed = accountAlerts
|
||||
.filter((ie) => {
|
||||
return ie.rewards.length > 0 && mailToMarkRead.includes(ie.id);
|
||||
})
|
||||
.map((ie) => ie.rewards)
|
||||
.reduce(function (a, b) {
|
||||
return a.concat(b);
|
||||
}, []);
|
||||
|
||||
for (const r of rewardsClaimed) {
|
||||
if (r.type === "xp") {
|
||||
totalXpClaimed += r.item as number;
|
||||
} else if (r.type === "badge") {
|
||||
const badge = BadgeController.getById(r.item.id);
|
||||
badgesClaimed.push(badge.name);
|
||||
DB.addBadge(r.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
mailUpdatedPromiseResolve();
|
||||
});
|
||||
}
|
||||
|
||||
$("#alertsPopup").animate(
|
||||
{
|
||||
marginRight: "-10rem",
|
||||
},
|
||||
100,
|
||||
"easeInCubic"
|
||||
);
|
||||
$("#alertsPopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 1)
|
||||
.animate(
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
100,
|
||||
() => {
|
||||
mailUpdatedPromise.then(() => {
|
||||
if (badgesClaimed.length > 0) {
|
||||
Notifications.add(
|
||||
`New badge${
|
||||
badgesClaimed.length > 1 ? "s" : ""
|
||||
} unlocked: ${badgesClaimed.join(", ")}`,
|
||||
1,
|
||||
5,
|
||||
"Reward",
|
||||
"gift"
|
||||
);
|
||||
}
|
||||
if (totalXpClaimed > 0) {
|
||||
const snapxp = DB.getSnapshot().xp;
|
||||
AccountButton.updateXpBar(snapxp, totalXpClaimed);
|
||||
DB.addXp(totalXpClaimed);
|
||||
}
|
||||
});
|
||||
$("#alertsPopupWrapper").addClass("hidden");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function show(): Promise<void> {
|
||||
if ($("#alertsPopupWrapper").hasClass("hidden")) {
|
||||
$("#alertsPopup").css("marginRight", "-10rem").animate(
|
||||
{
|
||||
marginRight: 0,
|
||||
},
|
||||
100,
|
||||
"easeOutCubic"
|
||||
);
|
||||
|
||||
if (Auth.currentUser) {
|
||||
$("#alertsPopup .accountAlerts").removeClass("hidden");
|
||||
$("#alertsPopup .separator.accountSeparator").removeClass("hidden");
|
||||
$("#alertsPopup .accountAlerts .list").html(`
|
||||
<div class="preloader"><i class="fas fa-fw fa-spin fa-circle-notch"></i></div>`);
|
||||
} else {
|
||||
$("#alertsPopup .accountAlerts").addClass("hidden");
|
||||
$("#alertsPopup .separator.accountSeparator").addClass("hidden");
|
||||
}
|
||||
|
||||
accountAlerts = [];
|
||||
mailToDelete = [];
|
||||
mailToMarkRead = [];
|
||||
|
||||
$("#alertsPopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 0)
|
||||
.removeClass("hidden")
|
||||
.animate(
|
||||
{
|
||||
opacity: 1,
|
||||
},
|
||||
100,
|
||||
() => {
|
||||
if (Auth.currentUser) {
|
||||
getAccountAlerts();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function getAccountAlerts(): Promise<void> {
|
||||
const inboxResponse = await Ape.users.getInbox();
|
||||
|
||||
$("#alertsPopup .accountAlerts .list").empty();
|
||||
|
||||
if (inboxResponse.status === 503) {
|
||||
$("#alertsPopup .accountAlerts .list").html(`
|
||||
<div class="nothing">
|
||||
Account inboxes are temporarily unavailable.
|
||||
</div>
|
||||
`);
|
||||
return;
|
||||
} else if (inboxResponse.status !== 200) {
|
||||
$("#alertsPopup .accountAlerts .list").html(`
|
||||
<div class="nothing">
|
||||
Error getting inbox: ${inboxResponse.message} Please try again later.
|
||||
</div>
|
||||
`);
|
||||
return;
|
||||
}
|
||||
const inboxData = inboxResponse.data as {
|
||||
inbox: MonkeyTypes.MonkeyMail[];
|
||||
maxMail: number;
|
||||
};
|
||||
|
||||
accountAlerts = inboxData.inbox;
|
||||
|
||||
if (accountAlerts.length === 0) {
|
||||
$("#alertsPopup .accountAlerts .list").html(`
|
||||
<div class="nothing">
|
||||
Nothing to show
|
||||
</div>
|
||||
`);
|
||||
return;
|
||||
}
|
||||
|
||||
maxMail = inboxData.maxMail;
|
||||
|
||||
updateInboxSize();
|
||||
|
||||
for (const ie of accountAlerts) {
|
||||
if (!ie.read && ie.rewards.length == 0) {
|
||||
mailToMarkRead.push(ie.id);
|
||||
}
|
||||
|
||||
let rewardsString = "";
|
||||
|
||||
if (ie.rewards.length > 0 && ie.read === false) {
|
||||
rewardsString = `<div class="rewards">
|
||||
<i class="fas fa-fw fa-gift"></i>
|
||||
<span>${ie.rewards.length}</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
$("#alertsPopup .accountAlerts .list").append(`
|
||||
|
||||
<div class="item" data-id="${ie.id}">
|
||||
<div class="indicator ${ie.read ? "" : "main"}"></div>
|
||||
<div class="timestamp">${formatDistanceToNowStrict(
|
||||
new Date(ie.timestamp)
|
||||
)} ago</div>
|
||||
<div class="title">${ie.subject}</div>
|
||||
<div class="body">
|
||||
${ie.body}\n\n${rewardsString}
|
||||
</div>
|
||||
<div class="buttons">
|
||||
${
|
||||
ie.rewards.length > 0 && ie.read === false
|
||||
? `<div class="markReadAlert textButton" aria-label="Claim" data-balloon-pos="left"><i class="fas fa-gift"></i></div>`
|
||||
: ``
|
||||
}
|
||||
${
|
||||
(ie.rewards.length > 0 && ie.read === true) ||
|
||||
ie.rewards.length == 0
|
||||
? `<div class="deleteAlert textButton" aria-label="Delete" data-balloon-pos="left"><i class="fas fa-trash"></i></div>`
|
||||
: ``
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
export function addPSA(message: string, level: number): void {
|
||||
if ($("#alertsPopup .psas .list .nothing").length > 0) {
|
||||
$("#alertsPopup .psas .list").empty();
|
||||
}
|
||||
|
||||
let levelClass = "";
|
||||
if (level === -1) {
|
||||
levelClass = "error";
|
||||
} else if (level === 1) {
|
||||
levelClass = "main";
|
||||
} else if (level === 0) {
|
||||
levelClass = "sub";
|
||||
}
|
||||
$("#alertsPopup .psas .list").prepend(`
|
||||
<div class="item">
|
||||
<div class="indicator ${levelClass}"></div>
|
||||
<div class="body">
|
||||
${message}
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
function addNotification(
|
||||
message: string,
|
||||
level: number,
|
||||
customTitle?: string
|
||||
): void {
|
||||
if ($("#alertsPopup .notificationHistory .list .nothing").length > 0) {
|
||||
$("#alertsPopup .notificationHistory .list").empty();
|
||||
}
|
||||
|
||||
let title = "Notice";
|
||||
let levelClass = "sub";
|
||||
if (level === -1) {
|
||||
levelClass = "error";
|
||||
title = "Error";
|
||||
} else if (level === 1) {
|
||||
levelClass = "main";
|
||||
title = "Success";
|
||||
}
|
||||
|
||||
if (customTitle) {
|
||||
title = customTitle;
|
||||
}
|
||||
|
||||
$("#alertsPopup .notificationHistory .list").prepend(`
|
||||
<div class="item">
|
||||
<div class="indicator ${levelClass}"></div>
|
||||
<div class="title">${title}</div>
|
||||
<div class="body">
|
||||
${message}
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
if ($("#alertsPopup .notificationHistory .list").length > 25) {
|
||||
$("#alertsPopup .notificationHistory .list .item:last").remove();
|
||||
}
|
||||
}
|
||||
|
||||
export function setBellButtonColored(tf: boolean): void {
|
||||
if (tf) {
|
||||
$("#top #menu .showAlerts").addClass("active");
|
||||
} else {
|
||||
$("#top #menu .showAlerts").removeClass("active");
|
||||
}
|
||||
}
|
||||
|
||||
function updateInboxSize(): void {
|
||||
$("#alertsPopup .accountAlerts .title .right").text(
|
||||
`${accountAlerts.length}/${maxMail}`
|
||||
);
|
||||
}
|
||||
|
||||
$("#top #menu .showAlerts").on("click", () => {
|
||||
show();
|
||||
});
|
||||
|
||||
$("#alertsPopupWrapper").on("mousedown", (e) => {
|
||||
if ($(e.target).attr("id") === "alertsPopupWrapper") {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#alertsPopup .accountAlerts .list").on(
|
||||
"click",
|
||||
".item .buttons .deleteAlert",
|
||||
(e) => {
|
||||
const id = $(e.currentTarget).closest(".item").attr("data-id") as string;
|
||||
mailToDelete.push(id);
|
||||
$(e.currentTarget).closest(".item").remove();
|
||||
accountAlerts = accountAlerts.filter((ie) => ie.id !== id);
|
||||
if (accountAlerts.length === 0) {
|
||||
$("#alertsPopup .accountAlerts .list").html(`
|
||||
<div class="nothing">
|
||||
Nothing to show
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
updateInboxSize();
|
||||
}
|
||||
);
|
||||
|
||||
$("#alertsPopup .accountAlerts .list").on(
|
||||
"click",
|
||||
".item .buttons .markReadAlert",
|
||||
(e) => {
|
||||
const id = $(e.currentTarget).closest(".item").attr("data-id") as string;
|
||||
mailToMarkRead.push(id);
|
||||
const item = $(e.currentTarget).closest(".item");
|
||||
|
||||
item.find(".indicator").removeClass("main");
|
||||
item.find(".buttons").empty();
|
||||
item
|
||||
.find(".buttons")
|
||||
.append(
|
||||
`<div class="deleteAlert textButton" aria-label="Delete" data-balloon-pos="left"><i class="fas fa-trash"></i></div>`
|
||||
);
|
||||
item.find(".rewards").animate(
|
||||
{
|
||||
opacity: 0,
|
||||
height: 0,
|
||||
marginTop: 0,
|
||||
},
|
||||
250,
|
||||
"easeOutCubic",
|
||||
() => {
|
||||
item.find(".rewards").remove();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
$(document).on("keydown", (e) => {
|
||||
if (e.key === "Escape" && !$("#alertsPopupWrapper").hasClass("hidden")) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
NotificationEvent.subscribe((message, level, customTitle) => {
|
||||
addNotification(message, level, customTitle);
|
||||
});
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import { debounce } from "throttle-debounce";
|
||||
import * as Misc from "../utils/misc";
|
||||
import * as BannerEvent from "../observables/banner-event";
|
||||
// import * as Alerts from "./alerts";
|
||||
import * as NotificationEvent from "../observables/notification-event";
|
||||
|
||||
function updateMargin(): void {
|
||||
console.log("updating margin");
|
||||
|
|
@ -231,7 +233,8 @@ export function add(
|
|||
closeCallback?: () => void,
|
||||
allowHTML?: boolean
|
||||
): void {
|
||||
// notificationHistory.push(
|
||||
NotificationEvent.dispatch(message, level, customTitle);
|
||||
|
||||
new Notification(
|
||||
"notification",
|
||||
message,
|
||||
|
|
@ -242,7 +245,6 @@ export function add(
|
|||
closeCallback,
|
||||
allowHTML
|
||||
).show();
|
||||
// );
|
||||
}
|
||||
|
||||
export function addBanner(
|
||||
|
|
@ -253,7 +255,6 @@ export function addBanner(
|
|||
closeCallback?: () => void,
|
||||
allowHTML?: boolean
|
||||
): void {
|
||||
// notificationHistory.push(
|
||||
new Notification(
|
||||
"banner",
|
||||
message,
|
||||
|
|
@ -264,7 +265,6 @@ export function addBanner(
|
|||
closeCallback,
|
||||
allowHTML
|
||||
).show();
|
||||
// );
|
||||
}
|
||||
|
||||
const debouncedMarginUpdate = debounce(100, updateMargin);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import Ape from "../ape";
|
|||
import { secondsToString } from "../utils/misc";
|
||||
import * as Notifications from "./notifications";
|
||||
import format from "date-fns/format";
|
||||
import * as Alerts from "./alerts";
|
||||
|
||||
function clearMemory(): void {
|
||||
window.localStorage.setItem("confirmedPSAs", JSON.stringify([]));
|
||||
|
|
@ -64,10 +65,6 @@ export async function show(): Promise<void> {
|
|||
}
|
||||
const localmemory = getMemory();
|
||||
latest.forEach((psa) => {
|
||||
if (localmemory.includes(psa._id) && (psa.sticky ?? false) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (psa.date) {
|
||||
const dateObj = new Date(psa.date);
|
||||
const diff = psa.date - Date.now();
|
||||
|
|
@ -90,6 +87,12 @@ export async function show(): Promise<void> {
|
|||
);
|
||||
}
|
||||
|
||||
Alerts.addPSA(psa.message, psa.level ?? -1);
|
||||
|
||||
if (localmemory.includes(psa._id) && (psa.sticky ?? false) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
Notifications.addBanner(
|
||||
psa.message,
|
||||
psa.level,
|
||||
|
|
|
|||
26
frontend/src/ts/observables/notification-event.ts
Normal file
26
frontend/src/ts/observables/notification-event.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
type SubscribeFunction = (
|
||||
message: string,
|
||||
level: number,
|
||||
customTitle?: string
|
||||
) => void;
|
||||
|
||||
const subscribers: SubscribeFunction[] = [];
|
||||
|
||||
export function subscribe(fn: SubscribeFunction): void {
|
||||
subscribers.push(fn);
|
||||
}
|
||||
|
||||
export function dispatch(
|
||||
message: string,
|
||||
level: number,
|
||||
customTitle?: string
|
||||
): void {
|
||||
subscribers.forEach((fn) => {
|
||||
try {
|
||||
fn(message, level, customTitle);
|
||||
} catch (e) {
|
||||
console.error("Notification event subscriber threw an error");
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -8,12 +8,10 @@ import * as AllTimeStats from "../account/all-time-stats";
|
|||
import * as PbTables from "../account/pb-tables";
|
||||
import * as LoadingPage from "./loading";
|
||||
import * as Focus from "../test/focus";
|
||||
import * as SignOutButton from "../account/sign-out-button";
|
||||
import * as TodayTracker from "../test/today-tracker";
|
||||
import * as Notifications from "../elements/notifications";
|
||||
import Page from "./page";
|
||||
import * as Misc from "../utils/misc";
|
||||
import * as ActivePage from "../states/active-page";
|
||||
import * as Profile from "../elements/profile";
|
||||
import format from "date-fns/format";
|
||||
|
||||
|
|
@ -842,9 +840,6 @@ function fillContent(): void {
|
|||
applyHistorySmoothing();
|
||||
ChartController.accountActivity.updateColors();
|
||||
LoadingPage.updateBar(100, true);
|
||||
setTimeout(() => {
|
||||
if (ActivePage.get() == "account") SignOutButton.show();
|
||||
}, 125);
|
||||
Focus.set(false);
|
||||
Misc.swapElements(
|
||||
$(".pageAccount .preloader"),
|
||||
|
|
@ -1092,14 +1087,13 @@ export const page = new Page(
|
|||
$(".page.pageAccount"),
|
||||
"/account",
|
||||
async () => {
|
||||
SignOutButton.hide();
|
||||
//
|
||||
},
|
||||
async () => {
|
||||
reset();
|
||||
},
|
||||
async () => {
|
||||
await update();
|
||||
// SignOutButton.show();
|
||||
},
|
||||
async () => {
|
||||
//
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import Config from "../config";
|
|||
import * as TestStats from "../test/test-stats";
|
||||
import * as TestUI from "../test/test-ui";
|
||||
import * as ManualRestart from "../test/manual-restart-tracker";
|
||||
import * as TestConfig from "../test/test-config";
|
||||
import * as TestLogic from "../test/test-logic";
|
||||
import * as Funbox from "../test/funbox";
|
||||
import Page from "./page";
|
||||
|
|
@ -15,7 +14,6 @@ export const page = new Page(
|
|||
async () => {
|
||||
TestLogic.restart();
|
||||
Funbox.clear();
|
||||
TestConfig.hide();
|
||||
$("#wordsInput").focusout();
|
||||
},
|
||||
async () => {
|
||||
|
|
@ -23,7 +21,6 @@ export const page = new Page(
|
|||
},
|
||||
async () => {
|
||||
updateTestPageAds(false);
|
||||
TestConfig.show();
|
||||
TestStats.resetIncomplete();
|
||||
ManualRestart.set();
|
||||
TestLogic.restart({
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ $("#customTestDurationPopup .button").on("click", () => {
|
|||
apply();
|
||||
});
|
||||
|
||||
$(document).on("click", "#top .config .time .textButton", (e) => {
|
||||
$(document).on("click", "#testConfig .time .textButton", (e) => {
|
||||
const mode = $(e.currentTarget).attr("timeConfig");
|
||||
if (mode == "custom") {
|
||||
show();
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ $(document).on("click", `${popup} .wordfilter`, () => {
|
|||
WordFilterPopup.show();
|
||||
});
|
||||
|
||||
$(document).on("click", "#top .config .customText .textButton", () => {
|
||||
$(document).on("click", "#testConfig .customText .textButton", () => {
|
||||
show();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ $("#customWordAmountPopup .button").on("click", () => {
|
|||
apply();
|
||||
});
|
||||
|
||||
$(document).on("click", "#top .config .wordCount .textButton", (e) => {
|
||||
$(document).on("click", "#testConfig .wordCount .textButton", (e) => {
|
||||
const wrd = $(e.currentTarget).attr("wordCount");
|
||||
if (wrd == "custom") {
|
||||
show();
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ $("#mobileTestConfigPopupWrapper").on("click", (e) => {
|
|||
}
|
||||
});
|
||||
|
||||
$("#top .mobileConfig").on("click", () => {
|
||||
$("#mobileTestConfig").on("click", () => {
|
||||
showPopup();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ $(document).on("click", "#toggleShowFavorites", (e) => {
|
|||
searchForQuotes();
|
||||
});
|
||||
|
||||
$(document).on("click", "#top .config .quoteLength .textButton", (e) => {
|
||||
$(document).on("click", "#testConfig .quoteLength .textButton", (e) => {
|
||||
const len = $(e.currentTarget).attr("quoteLength") ?? (0 as number);
|
||||
if (len == -2) {
|
||||
show();
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export function set(foc: boolean, withCursor = false): void {
|
|||
$("#bottom").addClass("focus");
|
||||
if (!withCursor) $("body").css("cursor", "none");
|
||||
$("#middle").addClass("focus");
|
||||
$("#testConfig").addClass("focus");
|
||||
$("#bannerCenter").addClass("focus");
|
||||
$("#capsWarning").addClass("focus");
|
||||
$("#ad-vertical-right-wrapper").addClass("focus");
|
||||
|
|
@ -25,6 +26,7 @@ export function set(foc: boolean, withCursor = false): void {
|
|||
$("#bottom").removeClass("focus");
|
||||
$("body").css("cursor", "default");
|
||||
$("#middle").removeClass("focus");
|
||||
$("#testConfig").removeClass("focus");
|
||||
$("#bannerCenter").removeClass("focus");
|
||||
$("#capsWarning").removeClass("focus");
|
||||
$("#app").removeClass("focus");
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import * as Notifications from "../elements/notifications";
|
|||
import * as Loader from "../elements/loader";
|
||||
import QuotesController from "../controllers/quotes-controller";
|
||||
import * as AdController from "../controllers/ad-controller";
|
||||
import * as TestConfig from "./test-config";
|
||||
import { Chart } from "chart.js";
|
||||
import { Auth } from "../firebase";
|
||||
|
||||
|
|
@ -711,6 +712,8 @@ export async function update(
|
|||
.animate({ scrollTop: 0 }, 250);
|
||||
}
|
||||
|
||||
TestConfig.hide();
|
||||
|
||||
Misc.swapElements(
|
||||
$("#typingTest"),
|
||||
$("#result"),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as ConfigEvent from "../observables/config-event";
|
||||
import * as Misc from "../utils/misc";
|
||||
// import * as Misc from "../utils/misc";
|
||||
|
||||
// export function show() {
|
||||
// $("#top .config").removeClass("hidden").css("opacity", 1);
|
||||
|
|
@ -10,159 +10,312 @@ import * as Misc from "../utils/misc";
|
|||
// }
|
||||
|
||||
export function show(): void {
|
||||
$("#top .config")
|
||||
.css("transition", "unset")
|
||||
.stop(true, true)
|
||||
.removeClass("hidden")
|
||||
.css("opacity", 0)
|
||||
.animate(
|
||||
{
|
||||
opacity: 1,
|
||||
},
|
||||
125,
|
||||
() => {
|
||||
$("#top .config").css("transition", "0.125s");
|
||||
}
|
||||
);
|
||||
$("#testConfig").removeClass("invisible");
|
||||
}
|
||||
|
||||
export function hide(): void {
|
||||
$("#top .config")
|
||||
.css("transition", "unset")
|
||||
.stop(true, true)
|
||||
.css("opacity", 1)
|
||||
.animate(
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
125,
|
||||
() => {
|
||||
$("#top .config").addClass("hidden").css("transition", "0.125s");
|
||||
}
|
||||
);
|
||||
$("#testConfig").addClass("invisible");
|
||||
}
|
||||
|
||||
export function update(
|
||||
export async function update(
|
||||
previous: MonkeyTypes.Mode,
|
||||
current: MonkeyTypes.Mode
|
||||
): void {
|
||||
): Promise<void> {
|
||||
if (previous === current) return;
|
||||
$("#top .config .mode .textButton").removeClass("active");
|
||||
$("#top .config .mode .textButton[mode='" + current + "']").addClass(
|
||||
"active"
|
||||
);
|
||||
$("#testConfig .mode .textButton").removeClass("active");
|
||||
$("#testConfig .mode .textButton[mode='" + current + "']").addClass("active");
|
||||
|
||||
if (current == "time") {
|
||||
// $("#top .config .wordCount").addClass("hidden");
|
||||
// $("#top .config .time").removeClass("hidden");
|
||||
// $("#top .config .customText").addClass("hidden");
|
||||
$("#top .config .punctuationMode").removeClass("disabled");
|
||||
$("#top .config .numbersMode").removeClass("disabled");
|
||||
// $("#top .config .puncAndNum").removeClass("disabled");
|
||||
// $("#top .config .punctuationMode").removeClass("hidden");
|
||||
// $("#top .config .numbersMode").removeClass("hidden");
|
||||
// $("#top .config .quoteLength").addClass("hidden");
|
||||
} else if (current == "words") {
|
||||
// $("#top .config .wordCount").removeClass("hidden");
|
||||
// $("#top .config .time").addClass("hidden");
|
||||
// $("#top .config .customText").addClass("hidden");
|
||||
$("#top .config .punctuationMode").removeClass("disabled");
|
||||
$("#top .config .numbersMode").removeClass("disabled");
|
||||
// $("#top .config .puncAndNum").removeClass("disabled");
|
||||
// $("#top .config .punctuationMode").removeClass("hidden");
|
||||
// $("#top .config .numbersMode").removeClass("hidden");
|
||||
// $("#top .config .quoteLength").addClass("hidden");
|
||||
} else if (current == "custom") {
|
||||
// $("#top .config .wordCount").addClass("hidden");
|
||||
// $("#top .config .time").addClass("hidden");
|
||||
// $("#top .config .customText").removeClass("hidden");
|
||||
$("#top .config .punctuationMode").removeClass("disabled");
|
||||
$("#top .config .numbersMode").removeClass("disabled");
|
||||
// $("#top .config .puncAndNum").removeClass("disabled");
|
||||
// $("#top .config .punctuationMode").removeClass("hidden");
|
||||
// $("#top .config .numbersMode").removeClass("hidden");
|
||||
// $("#top .config .quoteLength").addClass("hidden");
|
||||
} else if (current == "quote") {
|
||||
// $("#top .config .wordCount").addClass("hidden");
|
||||
// $("#top .config .time").addClass("hidden");
|
||||
// $("#top .config .customText").addClass("hidden");
|
||||
$("#top .config .punctuationMode").addClass("disabled");
|
||||
$("#top .config .numbersMode").addClass("disabled");
|
||||
// $("#top .config .puncAndNum").addClass("disabled");
|
||||
// $("#top .config .punctuationMode").removeClass("hidden");
|
||||
// $("#top .config .numbersMode").removeClass("hidden");
|
||||
// $("#result .stats .source").removeClass("hidden");
|
||||
// $("#top .config .quoteLength").removeClass("hidden");
|
||||
} else if (current == "zen") {
|
||||
// $("#top .config .wordCount").addClass("hidden");
|
||||
// $("#top .config .time").addClass("hidden");
|
||||
// $("#top .config .customText").addClass("hidden");
|
||||
// $("#top .config .punctuationMode").addClass("hidden");
|
||||
// $("#top .config .numbersMode").addClass("hidden");
|
||||
// $("#top .config .quoteLength").addClass("hidden");
|
||||
}
|
||||
// if (current == "time") {
|
||||
// $("#testConfig .punctuationMode").removeClass("hidden");
|
||||
// $("#testConfig .numbersMode").removeClass("hidden");
|
||||
// $("#testConfig .leftSpacer").removeClass("hidden");
|
||||
// } else if (current == "words") {
|
||||
// $("#testConfig .punctuationMode").removeClass("hidden");
|
||||
// $("#testConfig .numbersMode").removeClass("hidden");
|
||||
// $("#testConfig .leftSpacer").removeClass("hidden");
|
||||
// } else if (current == "custom") {
|
||||
// $("#testConfig .punctuationMode").removeClass("hidden");
|
||||
// $("#testConfig .numbersMode").removeClass("hidden");
|
||||
// $("#testConfig .leftSpacer").removeClass("hidden");
|
||||
// } else if (current == "quote") {
|
||||
// $("#testConfig .punctuationMode").addClass("hidden");
|
||||
// $("#testConfig .numbersMode").addClass("hidden");
|
||||
// $("#testConfig .leftSpacer").addClass("hidden");
|
||||
// } else if (current == "zen") {
|
||||
// //
|
||||
// }
|
||||
|
||||
const submenu = {
|
||||
time: "time",
|
||||
words: "wordCount",
|
||||
custom: "customText",
|
||||
quote: "quoteLength",
|
||||
zen: "",
|
||||
zen: "zen",
|
||||
};
|
||||
|
||||
const animTime = 250;
|
||||
|
||||
const puncAndNumVisible = {
|
||||
time: true,
|
||||
words: true,
|
||||
custom: true,
|
||||
quote: false,
|
||||
zen: false,
|
||||
};
|
||||
|
||||
if (
|
||||
puncAndNumVisible[previous] == false &&
|
||||
puncAndNumVisible[current] == true
|
||||
) {
|
||||
//show
|
||||
|
||||
$("#testConfig .leftSpacer").removeClass("scrolled");
|
||||
$("#testConfig .puncAndNum")
|
||||
.css({
|
||||
opacity: 0,
|
||||
maxWidth: 0,
|
||||
})
|
||||
.animate(
|
||||
{
|
||||
opacity: 1,
|
||||
maxWidth: "14rem",
|
||||
},
|
||||
animTime,
|
||||
"easeInOutSine"
|
||||
);
|
||||
} else if (
|
||||
puncAndNumVisible[previous] == true &&
|
||||
puncAndNumVisible[current] == false
|
||||
) {
|
||||
//hide
|
||||
$("#testConfig .leftSpacer").addClass("scrolled");
|
||||
$("#testConfig .puncAndNum")
|
||||
.css({
|
||||
opacity: 1,
|
||||
maxWidth: "14rem",
|
||||
})
|
||||
.animate(
|
||||
{
|
||||
opacity: 0,
|
||||
maxWidth: "0",
|
||||
},
|
||||
animTime,
|
||||
"easeInOutSine"
|
||||
);
|
||||
}
|
||||
|
||||
if (current == "zen") {
|
||||
$(`#top .config .${submenu[previous]}`).animate(
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
animTime / 2,
|
||||
() => {
|
||||
$(`#top .config .${submenu[previous]}`).addClass("hidden");
|
||||
}
|
||||
);
|
||||
$(`#top .config .puncAndNum`).animate(
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
animTime / 2,
|
||||
() => {
|
||||
$(`#top .config .puncAndNum`).addClass("invisible");
|
||||
}
|
||||
);
|
||||
return;
|
||||
$("#testConfig .rightSpacer").addClass("scrolled");
|
||||
} else {
|
||||
$("#testConfig .rightSpacer").removeClass("scrolled");
|
||||
}
|
||||
|
||||
if (previous == "zen") {
|
||||
setTimeout(() => {
|
||||
$(`#top .config .${submenu[current]}`).removeClass("hidden");
|
||||
$(`#top .config .${submenu[current]}`)
|
||||
.css({ opacity: 0 })
|
||||
.animate(
|
||||
{
|
||||
opacity: 1,
|
||||
},
|
||||
animTime / 2
|
||||
);
|
||||
$(`#top .config .puncAndNum`).removeClass("invisible");
|
||||
$(`#top .config .puncAndNum`)
|
||||
.css({ opacity: 0 })
|
||||
.animate(
|
||||
{
|
||||
opacity: 1,
|
||||
},
|
||||
animTime / 2
|
||||
);
|
||||
}, animTime / 2);
|
||||
return;
|
||||
}
|
||||
// const currentWidth = Math.round(
|
||||
// document.querySelector("#testConfig .row")?.getBoundingClientRect().width ??
|
||||
// 0
|
||||
// );
|
||||
|
||||
Misc.swapElements(
|
||||
$("#top .config ." + submenu[previous]),
|
||||
$("#top .config ." + submenu[current]),
|
||||
animTime
|
||||
// if (puncAndNumVisible[current]) {
|
||||
// $("#testConfig .punctuationMode").removeClass("hidden");
|
||||
// $("#testConfig .numbersMode").removeClass("hidden");
|
||||
// $("#testConfig .leftSpacer").removeClass("hidden");
|
||||
// } else {
|
||||
// $("#testConfig .punctuationMode").addClass("hidden");
|
||||
// $("#testConfig .numbersMode").addClass("hidden");
|
||||
// $("#testConfig .leftSpacer").addClass("hidden");
|
||||
// }
|
||||
|
||||
// if (current == "zen") {
|
||||
// $("#testConfig .rightSpacer").addClass("hidden");
|
||||
// } else {
|
||||
// $("#testConfig .rightSpacer").removeClass("hidden");
|
||||
// }
|
||||
|
||||
const previousWidth = Math.round(
|
||||
document
|
||||
.querySelector(`#testConfig .${submenu[previous]}`)
|
||||
?.getBoundingClientRect().width ?? 0
|
||||
);
|
||||
|
||||
$(`#testConfig .${submenu[previous]}`).addClass("hidden");
|
||||
|
||||
$(`#testConfig .${submenu[current]}`).removeClass("hidden");
|
||||
|
||||
const currentWidth = Math.round(
|
||||
document
|
||||
.querySelector(`#testConfig .${submenu[current]}`)
|
||||
?.getBoundingClientRect().width ?? 0
|
||||
);
|
||||
|
||||
$(`#testConfig .${submenu[previous]}`).removeClass("hidden");
|
||||
|
||||
$(`#testConfig .${submenu[current]}`).addClass("hidden");
|
||||
|
||||
const widthDifference = currentWidth - previousWidth;
|
||||
|
||||
const widthStep = widthDifference / 2;
|
||||
|
||||
$(`#testConfig .${submenu[previous]}`)
|
||||
.css({
|
||||
opacity: 1,
|
||||
width: previousWidth,
|
||||
})
|
||||
.animate(
|
||||
{
|
||||
width: previousWidth + widthStep,
|
||||
opacity: 0,
|
||||
},
|
||||
animTime / 2,
|
||||
"easeInSine",
|
||||
() => {
|
||||
$(`#testConfig .${submenu[previous]}`)
|
||||
.css({
|
||||
opacity: 1,
|
||||
width: "unset",
|
||||
})
|
||||
.addClass("hidden");
|
||||
$(`#testConfig .${submenu[current]}`)
|
||||
.css({
|
||||
opacity: 0,
|
||||
width: previousWidth + widthStep,
|
||||
})
|
||||
.removeClass("hidden")
|
||||
.animate(
|
||||
{
|
||||
opacity: 1,
|
||||
width: currentWidth,
|
||||
},
|
||||
animTime / 2,
|
||||
"easeOutSine",
|
||||
() => {
|
||||
$(`#testConfig .${submenu[current]}`).css("width", "unset");
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// $(`#testConfig .${submenu[current]}`)
|
||||
// .css({
|
||||
// opacity: 0,
|
||||
// maxWidth: previousWidth,
|
||||
// })
|
||||
// .removeClass("hidden")
|
||||
// .animate(
|
||||
// {
|
||||
// maxWidth: currentWidth,
|
||||
// opacity: 1,
|
||||
// },
|
||||
// 250,
|
||||
// () => {
|
||||
// $(`#testConfig .${submenu[current]}`).css({
|
||||
// opacity: 1,
|
||||
// maxWidth: "unset",
|
||||
// });
|
||||
// }
|
||||
// );
|
||||
|
||||
// const newWidth = Math.round(
|
||||
// document.querySelector("#testConfig .row")?.getBoundingClientRect().width ??
|
||||
// 0
|
||||
// );
|
||||
|
||||
// console.log(submenu[current], animTime, newWidth, currentWidth);
|
||||
|
||||
// if (current == "zen") {
|
||||
// $(`#testConfig .${submenu[previous]}`).animate(
|
||||
// {
|
||||
// opacity: 0,
|
||||
// },
|
||||
// animTime / 2,
|
||||
// () => {
|
||||
// $(`#testConfig .${submenu[previous]}`).addClass("hidden");
|
||||
// }
|
||||
// );
|
||||
// $(`#testConfig .puncAndNum`).animate(
|
||||
// {
|
||||
// opacity: 0,
|
||||
// },
|
||||
// animTime / 2,
|
||||
// () => {
|
||||
// $(`#testConfig .puncAndNum`).addClass("hidden");
|
||||
// }
|
||||
// );
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (previous == "zen") {
|
||||
// setTimeout(() => {
|
||||
// $(`#testConfig .${submenu[current]}`).removeClass("hidden");
|
||||
// $(`#testConfig .${submenu[current]}`)
|
||||
// .css({ opacity: 0 })
|
||||
// .animate(
|
||||
// {
|
||||
// opacity: 1,
|
||||
// },
|
||||
// animTime / 2
|
||||
// );
|
||||
// $(`#testConfig .puncAndNum`).removeClass("hidden");
|
||||
// $(`#testConfig .puncAndNum`)
|
||||
// .css({ opacity: 0 })
|
||||
// .animate(
|
||||
// {
|
||||
// opacity: 1,
|
||||
// },
|
||||
// animTime / 2
|
||||
// );
|
||||
// }, animTime / 2);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Misc.swapElements(
|
||||
// $("#testConfig ." + submenu[previous]),
|
||||
// $("#testConfig ." + submenu[current]),
|
||||
// animTime
|
||||
// );
|
||||
}
|
||||
|
||||
export function updateExtras(
|
||||
key: string,
|
||||
value: MonkeyTypes.ConfigValues
|
||||
): void {
|
||||
if (key == "time") {
|
||||
$("#testConfig .time .textButton").removeClass("active");
|
||||
const timeCustom = ![15, 30, 60, 120].includes(value as number)
|
||||
? "custom"
|
||||
: value;
|
||||
$(
|
||||
"#testConfig .time .textButton[timeConfig='" + timeCustom + "']"
|
||||
).addClass("active");
|
||||
} else if (key == "words") {
|
||||
$("#testConfig .wordCount .textButton").removeClass("active");
|
||||
|
||||
const wordCustom = ![10, 25, 50, 100, 200].includes(value as number)
|
||||
? "custom"
|
||||
: value;
|
||||
|
||||
$(
|
||||
"#testConfig .wordCount .textButton[wordCount='" + wordCustom + "']"
|
||||
).addClass("active");
|
||||
} else if (key == "quoteLength") {
|
||||
$("#testConfig .quoteLength .textButton").removeClass("active");
|
||||
(value as MonkeyTypes.QuoteLength[]).forEach((ql) => {
|
||||
$(
|
||||
"#testConfig .quoteLength .textButton[quoteLength='" + ql + "']"
|
||||
).addClass("active");
|
||||
});
|
||||
} else if (key == "numbers") {
|
||||
if (!value) {
|
||||
$("#testConfig .numbersMode.textButton").removeClass("active");
|
||||
} else {
|
||||
$("#testConfig .numbersMode.textButton").addClass("active");
|
||||
}
|
||||
} else if (key == "punctuation") {
|
||||
if (!value) {
|
||||
$("#testConfig .punctuationMode.textButton").removeClass("active");
|
||||
} else {
|
||||
$("#testConfig .punctuationMode.textButton").addClass("active");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function showFavoriteQuoteLength(): void {
|
||||
|
|
@ -179,5 +332,11 @@ ConfigEvent.subscribe((eventKey, eventValue, _nosave, eventPreviousValue) => {
|
|||
eventPreviousValue as MonkeyTypes.Mode,
|
||||
eventValue as MonkeyTypes.Mode
|
||||
);
|
||||
} else if (
|
||||
["time", "quoteLength", "words", "numbers", "punctuation"].includes(
|
||||
eventKey
|
||||
)
|
||||
) {
|
||||
updateExtras(eventKey, eventValue);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import objectHash from "object-hash";
|
|||
import * as AnalyticsController from "../controllers/analytics-controller";
|
||||
import { Auth } from "../firebase";
|
||||
import * as AdController from "../controllers/ad-controller";
|
||||
import * as TestConfig from "./test-config";
|
||||
|
||||
let failReason = "";
|
||||
const koInputVisual = document.getElementById("koInputVisual") as HTMLElement;
|
||||
|
|
@ -553,6 +554,7 @@ export function restart(options = {} as RestartOptions): void {
|
|||
AdController.updateTestPageAds(false);
|
||||
Focus.set(false);
|
||||
}
|
||||
TestConfig.show();
|
||||
TestUI.focusWords();
|
||||
$("#monkey .fast").stop(true, true).css("opacity", 0);
|
||||
$("#monkey").stop(true, true).css({ animationDuration: "0s" });
|
||||
|
|
@ -1851,7 +1853,17 @@ $(document).on("keypress", "#restartTestButtonWithSameWordset", (event) => {
|
|||
}
|
||||
});
|
||||
|
||||
$(document).on("click", "#top .config .wordCount .textButton", (e) => {
|
||||
$(document).on("click", "#testConfig .mode .textButton", (e) => {
|
||||
if (TestUI.testRestarting) return;
|
||||
if ($(e.currentTarget).hasClass("active")) return;
|
||||
const mode = ($(e.currentTarget).attr("mode") ?? "time") as MonkeyTypes.Mode;
|
||||
if (mode === undefined) return;
|
||||
UpdateConfig.setMode(mode);
|
||||
ManualRestart.set();
|
||||
restart();
|
||||
});
|
||||
|
||||
$(document).on("click", "#testConfig .wordCount .textButton", (e) => {
|
||||
if (TestUI.testRestarting) return;
|
||||
const wrd = $(e.currentTarget).attr("wordCount") ?? "15";
|
||||
if (wrd != "custom") {
|
||||
|
|
@ -1861,7 +1873,7 @@ $(document).on("click", "#top .config .wordCount .textButton", (e) => {
|
|||
}
|
||||
});
|
||||
|
||||
$(document).on("click", "#top .config .time .textButton", (e) => {
|
||||
$(document).on("click", "#testConfig .time .textButton", (e) => {
|
||||
if (TestUI.testRestarting) return;
|
||||
const mode = $(e.currentTarget).attr("timeConfig") ?? "10";
|
||||
if (mode != "custom") {
|
||||
|
|
@ -1871,7 +1883,7 @@ $(document).on("click", "#top .config .time .textButton", (e) => {
|
|||
}
|
||||
});
|
||||
|
||||
$(document).on("click", "#top .config .quoteLength .textButton", (e) => {
|
||||
$(document).on("click", "#testConfig .quoteLength .textButton", (e) => {
|
||||
if (TestUI.testRestarting) return;
|
||||
let len: MonkeyTypes.QuoteLength | MonkeyTypes.QuoteLength[] = <
|
||||
MonkeyTypes.QuoteLength
|
||||
|
|
@ -1886,30 +1898,20 @@ $(document).on("click", "#top .config .quoteLength .textButton", (e) => {
|
|||
}
|
||||
});
|
||||
|
||||
$(document).on("click", "#top .config .punctuationMode .textButton", () => {
|
||||
$(document).on("click", "#testConfig .punctuationMode.textButton", () => {
|
||||
if (TestUI.testRestarting) return;
|
||||
UpdateConfig.setPunctuation(!Config.punctuation);
|
||||
ManualRestart.set();
|
||||
restart();
|
||||
});
|
||||
|
||||
$(document).on("click", "#top .config .numbersMode .textButton", () => {
|
||||
$(document).on("click", "#testConfig .numbersMode.textButton", () => {
|
||||
if (TestUI.testRestarting) return;
|
||||
UpdateConfig.setNumbers(!Config.numbers);
|
||||
ManualRestart.set();
|
||||
restart();
|
||||
});
|
||||
|
||||
$(document).on("click", "#top .config .mode .textButton", (e) => {
|
||||
if (TestUI.testRestarting) return;
|
||||
if ($(e.currentTarget).hasClass("active")) return;
|
||||
const mode = ($(e.currentTarget).attr("mode") ?? "time") as MonkeyTypes.Mode;
|
||||
if (mode === undefined) return;
|
||||
UpdateConfig.setMode(mode);
|
||||
ManualRestart.set();
|
||||
restart();
|
||||
});
|
||||
|
||||
$("#practiseWordsPopup .button.missed").on("click", () => {
|
||||
PractiseWords.hidePopup();
|
||||
PractiseWords.init(true, false);
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ export async function screenshot(): Promise<void> {
|
|||
}
|
||||
|
||||
function revertScreenshot(): void {
|
||||
$("#testConfig").removeClass("invisible");
|
||||
$("#ad-result-wrapper").removeClass("hidden");
|
||||
$("#ad-result-small-wrapper").removeClass("hidden");
|
||||
$("#notificationCenter").removeClass("hidden");
|
||||
|
|
@ -287,6 +288,16 @@ export async function screenshot(): Promise<void> {
|
|||
);
|
||||
}
|
||||
$(".pageTest .buttons").addClass("hidden");
|
||||
$("#testConfig").addClass("invisible");
|
||||
$("#notificationCenter").addClass("hidden");
|
||||
$("#commandLineMobileButton").addClass("hidden");
|
||||
$(".pageTest .loginTip").addClass("hidden");
|
||||
$("noscript").addClass("hidden");
|
||||
$("#nocss").addClass("hidden");
|
||||
$("#ad-result-wrapper").addClass("hidden");
|
||||
$("#ad-result-small-wrapper").addClass("hidden");
|
||||
if (revertCookie) $("#cookiePopupWrapper").addClass("hidden");
|
||||
|
||||
const src = $("#result");
|
||||
const sourceX = src.offset()?.left ?? 0; /*X position from div#target*/
|
||||
const sourceY = src.offset()?.top ?? 0; /*Y position from div#target*/
|
||||
|
|
@ -296,14 +307,6 @@ export async function screenshot(): Promise<void> {
|
|||
const sourceHeight = <number>(
|
||||
src.outerHeight(true)
|
||||
); /*clientHeight/offsetHeight from div#target*/
|
||||
$("#notificationCenter").addClass("hidden");
|
||||
$("#commandLineMobileButton").addClass("hidden");
|
||||
$(".pageTest .loginTip").addClass("hidden");
|
||||
$("noscript").addClass("hidden");
|
||||
$("#nocss").addClass("hidden");
|
||||
$("#ad-result-wrapper").addClass("hidden");
|
||||
$("#ad-result-small-wrapper").addClass("hidden");
|
||||
if (revertCookie) $("#cookiePopupWrapper").addClass("hidden");
|
||||
try {
|
||||
const paddingX = Misc.convertRemToPixels(2);
|
||||
const paddingY = Misc.convertRemToPixels(2);
|
||||
|
|
|
|||
27
frontend/src/ts/types/types.d.ts
vendored
27
frontend/src/ts/types/types.d.ts
vendored
|
|
@ -473,6 +473,7 @@ declare namespace MonkeyTypes {
|
|||
addedAt: number;
|
||||
filterPresets: ResultFilters[];
|
||||
xp: number;
|
||||
inboxUnreadSize: number;
|
||||
streak: number;
|
||||
}
|
||||
|
||||
|
|
@ -739,4 +740,30 @@ declare namespace MonkeyTypes {
|
|||
color?: string;
|
||||
customStyle?: string;
|
||||
}
|
||||
|
||||
interface MonkeyMail {
|
||||
id: string;
|
||||
subject: string;
|
||||
body: string;
|
||||
timestamp: number;
|
||||
read: boolean;
|
||||
rewards: AllRewards[];
|
||||
}
|
||||
|
||||
interface Reward<T> {
|
||||
type: string;
|
||||
item: T;
|
||||
}
|
||||
|
||||
interface XpReward extends Reward<number> {
|
||||
type: "xp";
|
||||
item: number;
|
||||
}
|
||||
|
||||
interface BadgeReward extends Reward<Badge> {
|
||||
type: "badge";
|
||||
item: Badge;
|
||||
}
|
||||
|
||||
type AllRewards = XpReward | BadgeReward;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1443,7 +1443,12 @@
|
|||
<h1>font size</h1>
|
||||
<div class="text">Change the font size of the test words.</div>
|
||||
<div class="inputAndButton">
|
||||
<input type="text" placeholder="font size" class="input" tabindex="0" />
|
||||
<input
|
||||
type="number"
|
||||
placeholder="font size"
|
||||
class="input"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div class="button save" tabindex="0" onclick="this.blur();">
|
||||
<i class="fas fa-save fa-fw"></i>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,122 @@
|
|||
<div class="page pageTest hidden">
|
||||
<div id="testConfig">
|
||||
<div class="row">
|
||||
<div class="puncAndNum">
|
||||
<div class="textButton punctuationMode">
|
||||
<span
|
||||
style="
|
||||
font-weight: 900;
|
||||
width: 1.25rem;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
letter-spacing: -0.1em;
|
||||
font-size: 1.1em;
|
||||
height: 0em;
|
||||
"
|
||||
>
|
||||
!?
|
||||
</span>
|
||||
punctuation
|
||||
</div>
|
||||
<div class="textButton numbersMode">
|
||||
<span
|
||||
style="
|
||||
font-weight: 900;
|
||||
width: 1.25rem;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
letter-spacing: -0.1em;
|
||||
font-size: 1.1em;
|
||||
height: 0em;
|
||||
"
|
||||
>
|
||||
15
|
||||
</span>
|
||||
numbers
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="spacer leftSpacer"></div>
|
||||
|
||||
<div class="mode">
|
||||
<div class="textButton active" mode="time">
|
||||
<i class="fas fa-fw fa-clock"></i>
|
||||
time
|
||||
</div>
|
||||
<div class="textButton" mode="words">
|
||||
<i class="fas fa-fw fa-font"></i>
|
||||
words
|
||||
</div>
|
||||
<div class="textButton" mode="quote">
|
||||
<i class="fas fa-fw fa-quote-left"></i>
|
||||
quote
|
||||
</div>
|
||||
<div class="textButton" mode="zen">
|
||||
<i class="fas fa-fw fa-mountain"></i>
|
||||
zen
|
||||
</div>
|
||||
<div class="textButton" mode="custom">
|
||||
<i class="fas fa-fw fa-wrench"></i>
|
||||
custom
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="spacer rightSpacer"></div>
|
||||
|
||||
<div class="time">
|
||||
<div class="textButton" timeConfig="15"><span>15</span></div>
|
||||
<div class="textButton active" timeConfig="30"><span>30</span></div>
|
||||
<div class="textButton" timeConfig="60"><span>60</span></div>
|
||||
<div class="textButton" timeConfig="120"><span>120</span></div>
|
||||
<div class="textButton" timeConfig="custom">
|
||||
<i class="fas fa-fw fa-tools" style="margin-top: 0.1rem"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wordCount hidden">
|
||||
<div class="textButton" wordCount="10"><span>10</span></div>
|
||||
<div class="textButton" wordCount="25"><span>25</span></div>
|
||||
<div class="textButton active" wordCount="50"><span>50</span></div>
|
||||
<div class="textButton" wordCount="100"><span>100</span></div>
|
||||
<div class="textButton" wordCount="custom">
|
||||
<i class="fas fa-fw fa-tools" style="margin-top: 0.1rem"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="quoteLength hidden">
|
||||
<div class="textButton" quotelength="-1">all</div>
|
||||
<div class="textButton" quotelength="0">short</div>
|
||||
<div class="textButton active" quotelength="1">medium</div>
|
||||
<div class="textButton" quotelength="2">long</div>
|
||||
<div class="textButton" quotelength="3">thicc</div>
|
||||
<div class="textButton favorite" quotelength="-3">
|
||||
<i class="fas fa-heart" style="margin-top: 0.1rem"></i>
|
||||
</div>
|
||||
<div class="textButton" quotelength="-2">
|
||||
<i class="fas fa-search" style="margin-top: 0.1rem"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zen hidden">
|
||||
<div
|
||||
class="textButton"
|
||||
style="width: 0; padding-left: 0; padding-right: 0"
|
||||
>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="customText hidden">
|
||||
<div class="textButton">change</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mobileTestConfig">
|
||||
<div class="textButton">
|
||||
<i class="fas fa-fw fa-cog"></i>
|
||||
Test Settings
|
||||
</div>
|
||||
</div>
|
||||
<div id="typingTest">
|
||||
<div id="capsWarning" class="hidden">
|
||||
<i class="fas fa-lock"></i>
|
||||
|
|
@ -327,4 +445,5 @@
|
|||
</div>
|
||||
<div class="ssWatermark hidden">monkeytype.com</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,36 @@
|
|||
<div id="alertsPopupWrapper" class="popupWrapper hidden">
|
||||
<div id="alertsPopup">
|
||||
<div class="scrollWrapper">
|
||||
<div class="accountAlerts">
|
||||
<div class="title">
|
||||
<div class="left">
|
||||
<i class="fas fa-inbox"></i>
|
||||
Inbox
|
||||
</div>
|
||||
<div class="right"></div>
|
||||
</div>
|
||||
<div class="list"><div class="nothing">Nothing to show</div></div>
|
||||
</div>
|
||||
<div class="separator accountSeparator"></div>
|
||||
<div class="psas">
|
||||
<div class="title">
|
||||
<i class="fas fa-bullhorn"></i>
|
||||
Announcements
|
||||
</div>
|
||||
<div class="list"><div class="nothing">Nothing to show</div></div>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="notificationHistory">
|
||||
<div class="title">
|
||||
<i class="fas fa-comment-alt"></i>
|
||||
Notifications
|
||||
</div>
|
||||
<div class="list"><div class="nothing">Nothing to show</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="simplePopupWrapper" class="popupWrapper hidden">
|
||||
<div id="simplePopup" popupId=""></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@
|
|||
<i class="fas fa-fw fa-cog"></i>
|
||||
</div>
|
||||
</a>
|
||||
<div></div>
|
||||
<a
|
||||
class="textButton hidden account view-account"
|
||||
tabindex="2"
|
||||
|
|
@ -134,98 +135,34 @@
|
|||
<i class="far fa-fw fa-user"></i>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
class="textButton showAlerts"
|
||||
tabindex="2"
|
||||
href=""
|
||||
onclick="this.blur();"
|
||||
data-link
|
||||
>
|
||||
<div class="icon">
|
||||
<i class="fas fa-fw fa-bell"></i>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
class="textButton signInOut"
|
||||
tabindex="2"
|
||||
onclick="this.blur();"
|
||||
data-link
|
||||
>
|
||||
<div class="icon">
|
||||
<i class="fas fa-fw fa-sign-in-alt"></i>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="config hidden">
|
||||
<div class="mobileConfig">
|
||||
<div class="textButton">
|
||||
<i class="fas fa-bars"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="desktopConfig">
|
||||
<div
|
||||
class="puncAndNum"
|
||||
style="display: grid; grid-auto-flow: column; padding-top: 0.1rem"
|
||||
>
|
||||
<div class="group punctuationMode">
|
||||
<!-- <div class="title">time</div> -->
|
||||
<div class="buttons">
|
||||
<div class="textButton toggleButton" tabindex="2">punctuation</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group numbersMode">
|
||||
<!-- <div class="title">time</div> -->
|
||||
<div class="buttons">
|
||||
<div class="textButton toggleButton" tabindex="2">numbers</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group mode">
|
||||
<!-- <div class="title">mode</div> -->
|
||||
<div class="buttons">
|
||||
<div class="textButton active" mode="time" tabindex="2">time</div>
|
||||
<div class="textButton" mode="words" tabindex="2">words</div>
|
||||
<div class="textButton" mode="quote" tabindex="2">quote</div>
|
||||
<div class="textButton" mode="zen" tabindex="2">zen</div>
|
||||
<div class="textButton" mode="custom" tabindex="2">custom</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group wordCount hidden">
|
||||
<!-- <div class="title">words</div> -->
|
||||
<div class="buttons">
|
||||
<div class="textButton" wordCount="10" tabindex="2">10</div>
|
||||
<div class="textButton" wordCount="25" tabindex="2">25</div>
|
||||
<div class="textButton active" wordCount="50" tabindex="2">50</div>
|
||||
<div class="textButton" wordCount="100" tabindex="2">100</div>
|
||||
<div class="textButton" wordCount="custom" tabindex="2">
|
||||
<i class="fas fa-tools"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group time">
|
||||
<!-- <div class="title">time</div> -->
|
||||
<div class="buttons">
|
||||
<div class="textButton" timeConfig="15" tabindex="2">15</div>
|
||||
<div class="textButton active" timeConfig="30" tabindex="2">30</div>
|
||||
<div class="textButton" timeConfig="60" tabindex="2">60</div>
|
||||
<div class="textButton" timeConfig="120" tabindex="2">120</div>
|
||||
<div class="textButton" timeConfig="custom" tabindex="2">
|
||||
<i class="fas fa-tools"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group quoteLength hidden">
|
||||
<!-- <div class="title">time</div> -->
|
||||
<div class="buttons">
|
||||
<div class="textButton" quoteLength="-1" tabindex="2">all</div>
|
||||
<div class="textButton" quoteLength="0" tabindex="2">short</div>
|
||||
<div class="textButton active" quoteLength="1" tabindex="2">
|
||||
medium
|
||||
</div>
|
||||
<div class="textButton" quoteLength="2" tabindex="2">long</div>
|
||||
<div class="textButton" quoteLength="3" tabindex="2">thicc</div>
|
||||
<div class="textButton hidden favorite" quoteLength="-3" tabindex="2">
|
||||
<i class="fas fa-heart"></i>
|
||||
</div>
|
||||
<div class="textButton" quoteLength="-2" tabindex="2">
|
||||
<i class="fas fa-search"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group customText hidden">
|
||||
<!-- <div class="title">time</div> -->
|
||||
<div class="buttons">
|
||||
<div class="textButton">change</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
<!-- <div
|
||||
class="signOut hidden"
|
||||
style="grid-column: 3/4; grid-row: 1/2"
|
||||
tabindex="0"
|
||||
>
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
sign out
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
</div>
|
||||
<div id="centerContent" class="hidden">
|
||||
<%= compilation.assets["html/top.html"].source() %>
|
||||
<div id="middle">
|
||||
<div id="middle" style="height: 100%">
|
||||
<%= compilation.assets["html/pages/loading.html"].source() %> <%=
|
||||
compilation.assets["html/pages/test.html"].source() %> <%=
|
||||
compilation.assets["html/pages/about.html"].source() %> <%=
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue