mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2024-09-20 07:16:17 +08:00
build: replace webpack with vite (#5096)
This commit is contained in:
parent
c29220323b
commit
8f6bfbb708
4
.github/workflows/monkey-ci.yml
vendored
4
.github/workflows/monkey-ci.yml
vendored
|
@ -95,7 +95,7 @@ jobs:
|
|||
|
||||
- name: Create stub firebase config
|
||||
working-directory: ./frontend/src/ts/constants
|
||||
run: mv ./firebase-config-example.ts ./firebase-config-live.ts
|
||||
run: mv ./firebase-config-example.ts ./firebase-config.ts && cp ./firebase-config.ts ./firebase-config-live.ts
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci & cd frontend && npm ci
|
||||
|
@ -107,7 +107,7 @@ jobs:
|
|||
run: npm run lint-fe
|
||||
|
||||
- name: Build
|
||||
run: npm run pr-check-ts
|
||||
run: npm run pr-check-build-fe
|
||||
|
||||
- name: Test
|
||||
run: npm run test-fe
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -87,6 +87,7 @@ dist/
|
|||
frontend/public/
|
||||
backend/globalConfig.json
|
||||
backend/server.version
|
||||
vite-build/
|
||||
|
||||
#cloudflare y
|
||||
.cloudflareKey.txt
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
"before:init": [
|
||||
"npm run lint-fe",
|
||||
"npm run test-fe",
|
||||
"cd frontend && npx gulp build-production"
|
||||
"cd frontend && npm run validate-json && npm run build"
|
||||
],
|
||||
"before:release": [
|
||||
"cd frontend && npm run deploy-live",
|
||||
"cd frontend && firebase deploy -P live --only hosting",
|
||||
"sh ./bin/purgeCfCache.sh"
|
||||
]
|
||||
},
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
"before:init": [
|
||||
"npm run lint",
|
||||
"npm run test",
|
||||
"cd frontend && npx gulp build-production"
|
||||
"cd frontend && npm run validate-json && npm run build"
|
||||
],
|
||||
"before:release": [
|
||||
"sh ./bin/deployBackend.sh",
|
||||
"cd frontend && npm run deploy-live",
|
||||
"cd frontend && firebase deploy -P live --only hosting",
|
||||
"sh ./bin/purgeCfCache.sh"
|
||||
]
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"hosting": {
|
||||
"public": "public",
|
||||
"public": "dist",
|
||||
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
|
||||
"rewrites": [
|
||||
{
|
||||
|
|
|
@ -1,91 +1,43 @@
|
|||
const { webpack } = require("webpack");
|
||||
const eslint = require("gulp-eslint-new");
|
||||
const { task, src, series, watch } = require("gulp");
|
||||
const { resolve } = require("path");
|
||||
const fs = require("fs");
|
||||
const webpackDevConfig = require("./webpack/config.dev.js");
|
||||
const webpackProdConfig = require("./webpack/config.prod.js");
|
||||
|
||||
const JSONValidation = require("./scripts/json-validation");
|
||||
import eslint, { format, failAfterError } from "gulp-eslint-new";
|
||||
import gulp from "gulp";
|
||||
import {
|
||||
validateAll,
|
||||
validateQuotes,
|
||||
validateLanguages,
|
||||
validateOthers,
|
||||
} from "./scripts/json-validation.cjs";
|
||||
const eslintConfig = "../.eslintrc.json";
|
||||
|
||||
const { task, src, series } = gulp;
|
||||
|
||||
task("lint", function () {
|
||||
return src(["./src/ts/**/*.ts"])
|
||||
.pipe(eslint(eslintConfig))
|
||||
.pipe(eslint.format())
|
||||
.pipe(eslint.failAfterError());
|
||||
.pipe(format())
|
||||
.pipe(failAfterError());
|
||||
});
|
||||
|
||||
task("lint-json", function () {
|
||||
return src("./static/**/*.json")
|
||||
.pipe(eslint(eslintConfig))
|
||||
.pipe(eslint.format())
|
||||
.pipe(eslint.failAfterError());
|
||||
.pipe(format())
|
||||
.pipe(failAfterError());
|
||||
});
|
||||
|
||||
task("validate-json-schema", function () {
|
||||
return JSONValidation.validateAll();
|
||||
return validateAll();
|
||||
});
|
||||
|
||||
const taskWithWebpackConfig = (webpackConfig) => {
|
||||
return async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
webpack(webpackConfig, (err, stats) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
if (stats.hasErrors()) {
|
||||
return reject(new Error(stats.compilation.errors.join("\n")));
|
||||
}
|
||||
console.log(
|
||||
`Finished building in ${
|
||||
(stats.endTime - stats.startTime) / 1000
|
||||
} second(s)`
|
||||
);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
task("webpack", taskWithWebpackConfig(webpackDevConfig));
|
||||
task("webpack-production", taskWithWebpackConfig(webpackProdConfig));
|
||||
|
||||
task("compile", series("lint", "lint-json", "webpack"));
|
||||
|
||||
task(
|
||||
"compile-production",
|
||||
series("lint", "lint-json", "validate-json-schema", "webpack-production")
|
||||
);
|
||||
|
||||
task("watch", function () {
|
||||
watch(["./src/ts/**/*.ts", "./src/ts/*.ts"], series("lint"));
|
||||
watch(["./static/**/*.*", "./static/*.*"], series("lint-json"));
|
||||
});
|
||||
|
||||
task("build", series("compile"));
|
||||
|
||||
task("build-production", series("compile-production"));
|
||||
|
||||
//PR CHECK
|
||||
|
||||
task("validate-quote-json-schema", function () {
|
||||
return JSONValidation.validateQuotes();
|
||||
task("pr-check-quote-json", function () {
|
||||
return validateQuotes();
|
||||
});
|
||||
|
||||
task("validate-language-json-schema", function () {
|
||||
return JSONValidation.validateLanguages();
|
||||
task("pr-check-language-json", function () {
|
||||
return validateLanguages();
|
||||
});
|
||||
|
||||
task("validate-other-json-schema", function () {
|
||||
return JSONValidation.validateOthers();
|
||||
task("pr-check-other-json", function () {
|
||||
return validateOthers();
|
||||
});
|
||||
|
||||
task("pr-check-lint-json", series("lint-json"));
|
||||
task("pr-check-quote-json", series("validate-quote-json-schema"));
|
||||
task("pr-check-language-json", series("validate-language-json-schema"));
|
||||
task("pr-check-other-json", series("validate-other-json-schema"));
|
||||
|
||||
task("pr-check-lint", series("lint"));
|
||||
|
||||
task("pr-check-ts", series("webpack-production"));
|
||||
|
|
16459
frontend/package-lock.json
generated
16459
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -2,15 +2,18 @@
|
|||
"name": "monkeytype-frontend",
|
||||
"license": "GPL-3.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"live": "npm run build-live && cd public && npx serve -p 3000",
|
||||
"audit": "npx webpack --config ./webpack/config.audit.js",
|
||||
"lint": "eslint \"./**/*.ts\"",
|
||||
"validate-json": "npx gulp validate-json-schema",
|
||||
"audit": "vite-bundle-visualizer",
|
||||
"dep-graph": "madge -c -i \"dep-graph.png\" ./src/ts",
|
||||
"build": "npx gulp build",
|
||||
"build-live": "export COMMIT_HASH=`git rev-parse --short HEAD` && npx gulp build-production",
|
||||
"dev": "concurrently \"webpack serve --config=./webpack/config.dev.js\" \"npx gulp watch\"",
|
||||
"deploy-live": "npm run build-live && firebase deploy -P live --only hosting",
|
||||
"deploy-preview": "npm run build-live && firebase hosting:channel:deploy preview -P live --expires 2h",
|
||||
"build": "npm run madge && vite build",
|
||||
"madge": " madge --circular --extensions ts ./",
|
||||
"live": "npm run build && vite preview --port 3000",
|
||||
"dev": "vite dev",
|
||||
"deploy-live": "npm run validate-json && npm run build && firebase deploy -P live --only hosting",
|
||||
"deploy-preview": "npm run validate-json && npm run build && firebase hosting:channel:deploy preview -P live --expires 2h",
|
||||
"test": "jest --verbose --collect-coverage --runInBand",
|
||||
"tsc": "tsc",
|
||||
"knip": "knip"
|
||||
|
@ -32,50 +35,28 @@
|
|||
"@types/node": "18.19.1",
|
||||
"@types/object-hash": "2.2.1",
|
||||
"@types/throttle-debounce": "2.1.0",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"autoprefixer": "10.4.14",
|
||||
"buffer": "6.0.3",
|
||||
"circular-dependency-plugin": "5.2.2",
|
||||
"concurrently": "7.4.0",
|
||||
"copy-webpack-plugin": "10.2.4",
|
||||
"css-loader": "6.7.1",
|
||||
"css-minimizer-webpack-plugin": "3.4.1",
|
||||
"dotenv": "16.3.1",
|
||||
"dotenv": "16.4.5",
|
||||
"eslint": "8.43.0",
|
||||
"eslint-webpack-plugin": "3.1.1",
|
||||
"extra-watch-webpack-plugin": "1.0.3",
|
||||
"filemanager-webpack-plugin": "8.0.0",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-eslint-new": "1.4.2",
|
||||
"html-minimizer-webpack-plugin": "3.5.0",
|
||||
"html-webpack-plugin": "5.5.0",
|
||||
"gulp-eslint-new": "1.9.1",
|
||||
"jest": "29.7.0",
|
||||
"jest-environment-jsdom": "29.7.0",
|
||||
"jest-environment-node": "29.7.0",
|
||||
"json-minimizer-webpack-plugin": "3.3.0",
|
||||
"jsonschema": "1.4.0",
|
||||
"madge": "5.0.1",
|
||||
"memfs": "4.2.1",
|
||||
"mini-css-extract-plugin": "2.6.0",
|
||||
"normalize.css": "8.0.1",
|
||||
"postcss": "8.4.27",
|
||||
"postcss-loader": "7.3.3",
|
||||
"postcss-scss": "4.0.6",
|
||||
"sass-loader": "12.6.0",
|
||||
"serve": "13.0.2",
|
||||
"stream-browserify": "3.0.0",
|
||||
"string-replace-loader": "3.1.0",
|
||||
"style-loader": "3.3.3",
|
||||
"sass": "1.70.0",
|
||||
"ts-jest": "29.1.2",
|
||||
"ts-loader": "9.2.6",
|
||||
"ts-node-dev": "2.0.0",
|
||||
"typescript": "5.3.3",
|
||||
"webpack": "5.72.0",
|
||||
"webpack-bundle-analyzer": "4.5.0",
|
||||
"webpack-cli": "4.10.0",
|
||||
"webpack-dev-server": "4.15.1",
|
||||
"webpack-merge": "5.8.0",
|
||||
"workbox-webpack-plugin": "6.5.4"
|
||||
"vite": "5.1.2",
|
||||
"vite-bundle-visualizer": "1.0.1",
|
||||
"vite-plugin-checker": "0.6.4",
|
||||
"vite-plugin-filter-replace": "0.1.13",
|
||||
"vite-plugin-html-inject": "1.1.2",
|
||||
"vite-plugin-inspect": "0.8.3",
|
||||
"vite-plugin-pwa": "0.19.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "1.6.4",
|
||||
|
@ -85,7 +66,6 @@
|
|||
"chartjs-plugin-annotation": "1.4.0",
|
||||
"chartjs-plugin-trendline": "1.0.2",
|
||||
"color-blend": "4.0.0",
|
||||
"crypto-browserify": "3.12.0",
|
||||
"damerau-levenshtein": "1.0.8",
|
||||
"date-fns": "2.28.0",
|
||||
"firebase": "10.8.0",
|
||||
|
@ -100,7 +80,6 @@
|
|||
"object-hash": "3.0.0",
|
||||
"slim-select": "2.8.1",
|
||||
"stemmer": "2.0.0",
|
||||
"throttle-debounce": "3.0.1",
|
||||
"workbox-window": "6.5.4"
|
||||
"throttle-debounce": "3.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
parser: "postcss-scss",
|
||||
plugins: [require("autoprefixer")],
|
||||
};
|
||||
|
||||
module.exports = config;
|
|
@ -5,7 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Email Handler | Monkeytype</title>
|
||||
<!-- <link rel="stylesheet" href="css/fa.css" /> -->
|
||||
<link rel="stylesheet" href="css/balloon.css" />
|
||||
<link rel="stylesheet" href="css/balloon.min.css" />
|
||||
<link rel="stylesheet" href="themes/serika_dark.css" id="currentTheme" />
|
||||
<link rel="stylesheet" href="" id="funBoxTheme" />
|
||||
<link id="favicon" rel="shortcut icon" href="images/fav.png" />
|
||||
|
@ -17,9 +17,7 @@
|
|||
crossorigin="anonymous"
|
||||
referrerpolicy="no-referrer"
|
||||
/>
|
||||
<% for (var css in htmlWebpackPlugin.files.css) { %>
|
||||
<link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[css] %>" />
|
||||
<% } %>
|
||||
<link rel="stylesheet" href="styles/index.scss" />
|
||||
<meta name="name" content="Monkeytype" />
|
||||
<meta name="image" content="https://monkeytype.com/mtsocial.png" />
|
||||
<meta
|
||||
|
@ -164,21 +162,10 @@
|
|||
</main>
|
||||
</div>
|
||||
</body>
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.7.1.slim.min.js"
|
||||
integrity="sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8="
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<script src="/__/firebase/8.4.2/firebase-app.js"></script>
|
||||
<script type="module">
|
||||
import $ from "jquery";
|
||||
import { app as firebase } from "./ts/firebase";
|
||||
|
||||
<script src="/__/firebase/8.4.2/firebase-analytics.js"></script>
|
||||
<script src="/__/firebase/8.4.2/firebase-auth.js"></script>
|
||||
<script src="/__/firebase/8.4.2/firebase-firestore.js"></script>
|
||||
<script src="/__/firebase/8.4.2/firebase-functions.js"></script>
|
||||
|
||||
<!-- Initialize Firebase -->
|
||||
<script src="/__/firebase/init.js?useEmulator=true'"></script>
|
||||
<script defer>
|
||||
function isPasswordStrong(password) {
|
||||
const hasCapital = !!password.match(/[A-Z]/);
|
||||
const hasNumber = !!password.match(/[\d]/);
|
|
@ -55,15 +55,15 @@
|
|||
<i class="fab fa-fw fa-twitter"></i>
|
||||
<div class="text">Twitter</div>
|
||||
</a>
|
||||
<a href="/./terms-of-service.html" class="textButton" target="_blank">
|
||||
<a href="/terms-of-service.html" class="textButton" target="_blank">
|
||||
<i class="fas fa-fw fa-file-contract"></i>
|
||||
<div class="text">Terms</div>
|
||||
</a>
|
||||
<a href="/./security-policy.html" class="textButton" target="_blank">
|
||||
<a href="/security-policy.html" class="textButton" target="_blank">
|
||||
<i class="fas fa-fw fa-shield-alt"></i>
|
||||
<div class="text">Security</div>
|
||||
</a>
|
||||
<a href="/./privacy-policy.html" class="textButton" target="_blank">
|
||||
<a href="/privacy-policy.html" class="textButton" target="_blank">
|
||||
<i class="fas fa-fw fa-lock"></i>
|
||||
<div class="text">Privacy</div>
|
||||
</a>
|
|
@ -26,22 +26,22 @@
|
|||
rel="icon"
|
||||
type="image/x-icon"
|
||||
sizes="32x32"
|
||||
href="/./images/favicon/favicon.ico"
|
||||
href="/images/favicon/favicon.ico"
|
||||
/>
|
||||
<link
|
||||
id="favicon"
|
||||
rel="shortcut icon"
|
||||
type="image/svg+xml"
|
||||
href="/./images/favicon/favicon.svg"
|
||||
href="/images/favicon/favicon.svg"
|
||||
/>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/./images/favicon/apple-touch-icon.png"
|
||||
href="/images/favicon/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="mask-icon"
|
||||
href="/./images/favicon/safari-pinned-tab.svg"
|
||||
href="/images/favicon/safari-pinned-tab.svg"
|
||||
color="#eee"
|
||||
/>
|
||||
<meta name="msapplication-TileColor" content="#e2b714" />
|
||||
|
@ -50,7 +50,7 @@
|
|||
content="/images/favicon/browserconfig.xml"
|
||||
/>
|
||||
<meta id="metaThemeColor" name="theme-color" content="#e2b714" />
|
||||
<link rel="manifest" href="/./manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<meta
|
||||
name="name"
|
||||
content="Monkeytype | A minimalistic, customizable typing test"
|
||||
|
@ -90,4 +90,5 @@
|
|||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="darkreader-lock" />
|
||||
<meta http-equiv="Cache-Control" content="no-store" />
|
||||
<link rel="stylesheet" href="styles/index.scss" />
|
||||
</head>
|
|
@ -1,9 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<%= compilation.assets["html/head.html"].source() %>
|
||||
<load src="html/head.html" />
|
||||
|
||||
<body>
|
||||
<%= compilation.assets["html/warnings.html"].source() %>
|
||||
<load src="html/warnings.html" />
|
||||
<div id="fpsCounter" class="hidden"></div>
|
||||
<div class="customBackground"></div>
|
||||
<div id="backgroundLoader" style="display: none"></div>
|
||||
|
@ -19,7 +19,7 @@
|
|||
<div id="timer" class="timerMain"></div>
|
||||
</div>
|
||||
<div id="popups">
|
||||
<%= compilation.assets["html/popups.html"].source() %>
|
||||
<load src="html/popups.html" />
|
||||
</div>
|
||||
<!-- <div id="div-gpt-ad-mkt-0" style="height: 100vh"></div> -->
|
||||
<div id="app" class="focus">
|
||||
|
@ -30,19 +30,19 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="contentWrapper" class="hidden">
|
||||
<%= compilation.assets["html/header.html"].source() %>
|
||||
<load src="html/header.html" />
|
||||
<main style="height: 100%">
|
||||
<%= compilation.assets["html/pages/loading.html"].source() %> <%=
|
||||
compilation.assets["html/pages/about.html"].source() %> <%=
|
||||
compilation.assets["html/pages/settings.html"].source() %> <%=
|
||||
compilation.assets["html/pages/login.html"].source() %> <%=
|
||||
compilation.assets["html/pages/account.html"].source() %> <%=
|
||||
compilation.assets["html/pages/profile.html"].source() %> <%=
|
||||
compilation.assets["html/pages/test.html"].source() %> <%=
|
||||
compilation.assets["html/pages/404.html"].source() %>
|
||||
<load src="html/pages/loading.html" />
|
||||
<load src="html/pages/about.html" />
|
||||
<load src="html/pages/settings.html" />
|
||||
<load src="html/pages/login.html" />
|
||||
<load src="html/pages/account.html" />
|
||||
<load src="html/pages/profile.html" />
|
||||
<load src="html/pages/test.html" />
|
||||
<load src="html/pages/404.html" />
|
||||
</main>
|
||||
|
||||
<%= compilation.assets["html/footer.html"].source() %>
|
||||
<load src="html/footer.html" />
|
||||
|
||||
<div id="ad-footer-wrapper" class="ad advertisement ad-h focus">
|
||||
<div class="icon"><i class="fas fa-ad"></i></div>
|
||||
|
@ -65,8 +65,9 @@
|
|||
async
|
||||
defer
|
||||
></script>
|
||||
<link rel="stylesheet" href="/./themes/serika_dark.css" id="currentTheme" />
|
||||
<link rel="stylesheet" href="/themes/serika_dark.css" id="currentTheme" />
|
||||
<link rel="stylesheet" href="" id="funBoxTheme" />
|
||||
<link rel="stylesheet" href="" id="globalFunBoxTheme" type="text/css" />
|
||||
<script type="module" src="ts/index.ts"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -5,14 +5,12 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Privacy Policy | Monkeytype</title>
|
||||
<!-- <link rel="stylesheet" href="css/fa.css" /> -->
|
||||
<link rel="stylesheet" href="css/balloon.css" />
|
||||
<link rel="stylesheet" href="css/balloon.min.css" />
|
||||
<link rel="stylesheet" href="themes/serika_dark.css" id="currentTheme" />
|
||||
<link rel="stylesheet" href="" id="funBoxTheme" />
|
||||
<link id="favicon" rel="shortcut icon" href="images/fav.png" />
|
||||
<link rel="shortcut icon" href="images/fav.png" />
|
||||
<% for (var css in htmlWebpackPlugin.files.css) { %>
|
||||
<link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[css] %>" />
|
||||
<% } %>
|
||||
<link rel="stylesheet" href="styles/index.scss" />
|
||||
<meta name="name" content="Monkeytype" />
|
||||
<meta name="image" content="https://monkeytype.com/mtsocial.png" />
|
||||
<meta
|
||||
|
@ -46,15 +44,15 @@
|
|||
}
|
||||
|
||||
h1 {
|
||||
font-weight: unset;
|
||||
color: var(--main-color);
|
||||
font-size: 2rem;
|
||||
margin-top: 3rem;
|
||||
font-weight: unset !important;
|
||||
color: var(--main-color) !important;
|
||||
font-size: 2rem !important;
|
||||
margin-top: 3rem !important;
|
||||
}
|
||||
|
||||
body {
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
justify-content: center !important;
|
||||
display: flex !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
|
@ -5,14 +5,12 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Security Policy | Monkeytype</title>
|
||||
<!-- <link rel="stylesheet" href="css/fa.css" /> -->
|
||||
<link rel="stylesheet" href="css/balloon.css" />
|
||||
<link rel="stylesheet" href="css/balloon.min.css" />
|
||||
<link rel="stylesheet" href="themes/serika_dark.css" id="currentTheme" />
|
||||
<link rel="stylesheet" href="" id="funBoxTheme" />
|
||||
<link id="favicon" rel="shortcut icon" href="images/fav.png" />
|
||||
<link rel="shortcut icon" href="images/fav.png" />
|
||||
<% for (var css in htmlWebpackPlugin.files.css) { %>
|
||||
<link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[css] %>" />
|
||||
<% } %>
|
||||
<link rel="stylesheet" href="styles/index.scss" />
|
||||
<meta name="name" content="Monkeytype" />
|
||||
<meta name="image" content="https://monkeytype.com/mtsocial.png" />
|
||||
<meta
|
||||
|
@ -46,19 +44,19 @@
|
|||
}
|
||||
|
||||
#contentWrapper {
|
||||
align-items: flex-start;
|
||||
align-items: flex-start !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: unset;
|
||||
color: var(--main-color);
|
||||
font-size: 2rem;
|
||||
margin-top: 3rem;
|
||||
font-weight: unset !important;
|
||||
color: var(--main-color) !important;
|
||||
font-size: 2rem !important;
|
||||
margin-top: 3rem !important;
|
||||
}
|
||||
|
||||
body {
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
justify-content: center !important;
|
||||
display: flex !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
|
@ -12,7 +12,7 @@
|
|||
.image {
|
||||
width: 100%;
|
||||
align-self: center;
|
||||
background-image: url("./../images/monkeymeme.jpg");
|
||||
background-image: url("/images/monkeymeme.jpg");
|
||||
aspect-ratio: 300/199;
|
||||
background-size: contain;
|
||||
border-radius: var(--roundness);
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
&.carrot {
|
||||
background-color: transparent;
|
||||
background-image: url("../images/carrot.png");
|
||||
background-image: url("/images/carrot.png");
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
|
@ -39,7 +39,7 @@
|
|||
|
||||
&.banana {
|
||||
background-color: transparent;
|
||||
background-image: url("../images/banana.png");
|
||||
background-image: url("/images/banana.png");
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/SourceCodePro-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/SourceCodePro-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -11,7 +11,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/JetBrainsMono-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/JetBrainsMono-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -19,7 +19,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Montserrat-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/Montserrat-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -27,7 +27,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Roboto-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/Roboto-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -35,7 +35,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/TitilliumWeb-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/TitilliumWeb-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -43,7 +43,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Oxygen-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/Oxygen-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -51,7 +51,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Itim-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/Itim-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -59,7 +59,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Comfortaa-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/Comfortaa-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -67,7 +67,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/ComingSoon-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/ComingSoon-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -75,7 +75,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/AtkinsonHyperlegible-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/AtkinsonHyperlegible-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -83,7 +83,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Lato-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/Lato-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -91,7 +91,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Lalezar-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/Lalezar-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -99,7 +99,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/NotoNaskhArabic-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/NotoNaskhArabic-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -107,7 +107,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Vazirmatn-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/Vazirmatn-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -115,7 +115,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Ubuntu-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/Ubuntu-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -123,7 +123,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/UbuntuMono-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/UbuntuMono-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -131,7 +131,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Inconsolata-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/Inconsolata-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -139,7 +139,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: block;
|
||||
src: url("../webfonts/IBMPlexSans-SemiBold.ttf") format("truetype");
|
||||
src: url("/webfonts/IBMPlexSans-SemiBold.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -147,7 +147,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/LexendDeca-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/LexendDeca-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -155,7 +155,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/FiraCode-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/FiraCode-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -163,7 +163,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Nunito-Bold.ttf") format("truetype");
|
||||
src: url("/webfonts/Nunito-Bold.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -171,7 +171,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/RobotoMono-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/RobotoMono-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -179,8 +179,8 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/Boon-400.ttf") format("truetype"),
|
||||
url("../webfonts/Boon-400.otf") format("opentype");
|
||||
src: url("/webfonts/Boon-400.ttf") format("truetype"),
|
||||
url("/webfonts/Boon-400.otf") format("opentype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -188,7 +188,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/OpenDyslexic.otf") format("opentype");
|
||||
src: url("/webfonts/OpenDyslexic.otf") format("opentype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -196,7 +196,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/CascadiaMono-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/CascadiaMono-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -204,7 +204,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/IBMPlexMono-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/IBMPlexMono-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -212,7 +212,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/OverpassMono-VariableFont_wght.ttf") format("truetype");
|
||||
src: url("/webfonts/OverpassMono-VariableFont_wght.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -220,7 +220,7 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/HackNerdFont-Regular.ttf") format("truetype");
|
||||
src: url("/webfonts/HackNerdFont-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -228,5 +228,5 @@
|
|||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/CommitMono-400-Regular.otf") format("opentype");
|
||||
src: url("/webfonts/CommitMono-400-Regular.otf") format("opentype");
|
||||
}
|
||||
|
|
|
@ -9,29 +9,29 @@
|
|||
position: fixed;
|
||||
}
|
||||
.up {
|
||||
background-image: url("../images/monkey/m3.png");
|
||||
background-image: url("/images/monkey/m3.png");
|
||||
}
|
||||
.left {
|
||||
background-image: url("../images/monkey/m1.png");
|
||||
background-image: url("/images/monkey/m1.png");
|
||||
}
|
||||
.right {
|
||||
background-image: url("../images/monkey/m2.png");
|
||||
background-image: url("/images/monkey/m2.png");
|
||||
}
|
||||
.both {
|
||||
background-image: url("../images/monkey/m4.png");
|
||||
background-image: url("/images/monkey/m4.png");
|
||||
}
|
||||
.fast {
|
||||
.up {
|
||||
background-image: url("../images/monkey/m3_fast.png");
|
||||
background-image: url("/images/monkey/m3_fast.png");
|
||||
}
|
||||
.left {
|
||||
background-image: url("../images/monkey/m1_fast.png");
|
||||
background-image: url("/images/monkey/m1_fast.png");
|
||||
}
|
||||
.right {
|
||||
background-image: url("../images/monkey/m2_fast.png");
|
||||
background-image: url("/images/monkey/m2_fast.png");
|
||||
}
|
||||
.both {
|
||||
background-image: url("../images/monkey/m4_fast.png");
|
||||
background-image: url("/images/monkey/m4_fast.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,12 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Terms of Service | Monkeytype</title>
|
||||
<!-- <link rel="stylesheet" href="css/fa.css" /> -->
|
||||
<link rel="stylesheet" href="css/balloon.css" />
|
||||
<link rel="stylesheet" href="css/balloon.min.css" />
|
||||
<link rel="stylesheet" href="themes/serika_dark.css" id="currentTheme" />
|
||||
<link rel="stylesheet" href="" id="funBoxTheme" />
|
||||
<link id="favicon" rel="shortcut icon" href="images/fav.png" />
|
||||
<link rel="shortcut icon" href="images/fav.png" />
|
||||
<% for (var css in htmlWebpackPlugin.files.css) { %>
|
||||
<link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[css] %>" />
|
||||
<% } %>
|
||||
<link rel="stylesheet" href="styles/index.scss" />
|
||||
<meta name="name" content="Monkeytype" />
|
||||
<meta name="image" content="https://monkeytype.com/mtsocial.png" />
|
||||
<meta
|
||||
|
@ -38,23 +36,23 @@
|
|||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<style>
|
||||
header {
|
||||
font-size: 2.5rem;
|
||||
font-size: 2.5rem !important;
|
||||
}
|
||||
|
||||
main {
|
||||
color: var(--text-color);
|
||||
color: var(--text-color) !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: unset;
|
||||
color: var(--main-color);
|
||||
font-size: 2rem;
|
||||
margin-top: 3rem;
|
||||
font-weight: unset !important;
|
||||
color: var(--main-color) !important;
|
||||
font-size: 2rem !important;
|
||||
margin-top: 3rem !important;
|
||||
}
|
||||
|
||||
body {
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
justify-content: center !important;
|
||||
display: flex !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
|
@ -1,7 +1,7 @@
|
|||
import { getAuthenticatedUser, isAuthenticated } from "../../firebase";
|
||||
import { getIdToken } from "firebase/auth";
|
||||
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
|
||||
import { CLIENT_VERSION } from "../../version";
|
||||
import { envConfig } from "../../constants/env-config";
|
||||
|
||||
type AxiosClientMethod = (
|
||||
endpoint: string,
|
||||
|
@ -29,7 +29,7 @@ async function adaptRequestOptions<TQuery, TPayload>(
|
|||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
...(idToken && { Authorization: `Bearer ${idToken}` }),
|
||||
"X-Client-Version": CLIENT_VERSION,
|
||||
"X-Client-Version": envConfig.clientVersion,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -18,11 +18,11 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
display: "click",
|
||||
configValue: "1",
|
||||
hover: (): void => {
|
||||
SoundController.previewClick("1");
|
||||
void SoundController.previewClick("1");
|
||||
},
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnClick("1");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -30,11 +30,11 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
display: "beep",
|
||||
configValue: "2",
|
||||
hover: (): void => {
|
||||
SoundController.previewClick("2");
|
||||
void SoundController.previewClick("2");
|
||||
},
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnClick("2");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -42,11 +42,11 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
display: "pop",
|
||||
configValue: "3",
|
||||
hover: (): void => {
|
||||
SoundController.previewClick("3");
|
||||
void SoundController.previewClick("3");
|
||||
},
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnClick("3");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -54,11 +54,11 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
display: "nk creams",
|
||||
configValue: "4",
|
||||
hover: (): void => {
|
||||
SoundController.previewClick("4");
|
||||
void SoundController.previewClick("4");
|
||||
},
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnClick("4");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -66,11 +66,11 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
display: "typewriter",
|
||||
configValue: "5",
|
||||
hover: (): void => {
|
||||
SoundController.previewClick("5");
|
||||
void SoundController.previewClick("5");
|
||||
},
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnClick("5");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -78,11 +78,11 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
display: "osu",
|
||||
configValue: "6",
|
||||
hover: (): void => {
|
||||
SoundController.previewClick("6");
|
||||
void SoundController.previewClick("6");
|
||||
},
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnClick("6");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -90,11 +90,11 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
display: "hitmarker",
|
||||
configValue: "7",
|
||||
hover: (): void => {
|
||||
SoundController.previewClick("7");
|
||||
void SoundController.previewClick("7");
|
||||
},
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnClick("7");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -174,11 +174,11 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
display: "fist fight",
|
||||
configValue: "14",
|
||||
hover: (): void => {
|
||||
SoundController.previewClick("14");
|
||||
void SoundController.previewClick("14");
|
||||
},
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnClick("14");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -186,11 +186,11 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
display: "rubber keys",
|
||||
configValue: "15",
|
||||
hover: (): void => {
|
||||
SoundController.previewClick("15");
|
||||
void SoundController.previewClick("15");
|
||||
},
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnClick("15");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -19,7 +19,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
configValue: "1",
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnError("1");
|
||||
SoundController.playError();
|
||||
void SoundController.playError();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
configValue: "2",
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnError("2");
|
||||
SoundController.playError();
|
||||
void SoundController.playError();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -37,7 +37,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
configValue: "3",
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnError("3");
|
||||
SoundController.playError();
|
||||
void SoundController.playError();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -46,7 +46,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
configValue: "4",
|
||||
exec: (): void => {
|
||||
UpdateConfig.setPlaySoundOnError("4");
|
||||
SoundController.playError();
|
||||
void SoundController.playError();
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -11,7 +11,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
configValue: "0.1",
|
||||
exec: (): void => {
|
||||
UpdateConfig.setSoundVolume("0.1");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
configValue: "0.5",
|
||||
exec: (): void => {
|
||||
UpdateConfig.setSoundVolume("0.5");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -29,7 +29,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
|
|||
configValue: "1.0",
|
||||
exec: (): void => {
|
||||
UpdateConfig.setSoundVolume("1.0");
|
||||
SoundController.playClick();
|
||||
void SoundController.playClick();
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
type Config = {
|
||||
backendUrl: string;
|
||||
isDevelopment: boolean;
|
||||
clientVersion: string;
|
||||
};
|
||||
|
||||
// @ts-expect-error
|
||||
//@ts-expect-error these get replaced by vite
|
||||
const backendUrl = BACKEND_URL;
|
||||
// @ts-expect-error
|
||||
const isDevelopment = IS_DEVELOPMENT;
|
||||
// @ts-expect-error
|
||||
const clientVersion = CLIENT_VERSION;
|
||||
|
||||
export const envConfig: Config = {
|
||||
backendUrl,
|
||||
isDevelopment,
|
||||
clientVersion,
|
||||
};
|
||||
|
|
|
@ -223,7 +223,7 @@ function handleSpace(): void {
|
|||
TestInput.incrementKeypressCount();
|
||||
TestInput.pushKeypressWord(TestWords.words.currentIndex);
|
||||
if (!nospace) {
|
||||
Sound.playClick();
|
||||
void Sound.playClick();
|
||||
}
|
||||
Replay.addReplayEvent("submitCorrectWord");
|
||||
if (TestWords.words.currentIndex === TestWords.words.length) {
|
||||
|
@ -234,9 +234,9 @@ function handleSpace(): void {
|
|||
} else {
|
||||
if (!nospace) {
|
||||
if (Config.playSoundOnError === "off" || Config.blindMode) {
|
||||
Sound.playClick();
|
||||
void Sound.playClick();
|
||||
} else {
|
||||
Sound.playError();
|
||||
void Sound.playError();
|
||||
}
|
||||
}
|
||||
TestInput.pushMissedWord(TestWords.words.getCurrent());
|
||||
|
@ -583,12 +583,12 @@ function handleChar(
|
|||
);
|
||||
|
||||
if (thisCharCorrect) {
|
||||
Sound.playClick();
|
||||
void Sound.playClick();
|
||||
} else {
|
||||
if (Config.playSoundOnError === "off" || Config.blindMode) {
|
||||
Sound.playClick();
|
||||
void Sound.playClick();
|
||||
} else {
|
||||
Sound.playError();
|
||||
void Sound.playError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1000,7 +1000,7 @@ $(document).on("keydown", async (event) => {
|
|||
|
||||
//blocking firefox from going back in history with backspace
|
||||
if (event.key === "Backspace") {
|
||||
Sound.playClick();
|
||||
void Sound.playClick();
|
||||
const t = /INPUT|SELECT|TEXTAREA/i;
|
||||
if (
|
||||
!t.test((event.target as unknown as Element).tagName)
|
||||
|
@ -1068,7 +1068,7 @@ $(document).on("keydown", async (event) => {
|
|||
|
||||
//show dead keys
|
||||
if (event.key === "Dead" && !CompositionState.getComposing()) {
|
||||
Sound.playClick();
|
||||
void Sound.playClick();
|
||||
const word: HTMLElement | null = document.querySelector<HTMLElement>(
|
||||
"#words .word.active"
|
||||
);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import Config from "../config";
|
||||
import { Howler, Howl } from "howler";
|
||||
import * as ConfigEvent from "../observables/config-event";
|
||||
import {
|
||||
createErrorMessage,
|
||||
|
@ -10,6 +9,12 @@ import { leftState, rightState } from "../test/shift-tracker";
|
|||
import { capsState } from "../test/caps-warning";
|
||||
import * as Notifications from "../elements/notifications";
|
||||
|
||||
import type { Howl } from "howler";
|
||||
|
||||
async function gethowler(): Promise<typeof import("howler")> {
|
||||
return await import("howler");
|
||||
}
|
||||
|
||||
type ClickSounds = Record<
|
||||
string,
|
||||
{
|
||||
|
@ -29,7 +34,8 @@ type ErrorSounds = Record<
|
|||
let errorSounds: ErrorSounds | null = null;
|
||||
let clickSounds: ClickSounds | null = null;
|
||||
|
||||
function initErrorSound(): void {
|
||||
async function initErrorSound(): Promise<void> {
|
||||
const Howl = (await gethowler()).Howl;
|
||||
if (errorSounds !== null) return;
|
||||
errorSounds = {
|
||||
1: [
|
||||
|
@ -76,9 +82,11 @@ function initErrorSound(): void {
|
|||
},
|
||||
],
|
||||
};
|
||||
Howler.volume(parseFloat(Config.soundVolume));
|
||||
}
|
||||
|
||||
function init(): void {
|
||||
async function init(): Promise<void> {
|
||||
const Howl = (await gethowler()).Howl;
|
||||
if (clickSounds !== null) return;
|
||||
clickSounds = {
|
||||
1: [
|
||||
|
@ -380,10 +388,11 @@ function init(): void {
|
|||
},
|
||||
],
|
||||
};
|
||||
Howler.volume(parseFloat(Config.soundVolume));
|
||||
}
|
||||
|
||||
export function previewClick(val: string): void {
|
||||
if (clickSounds === null) init();
|
||||
export async function previewClick(val: string): Promise<void> {
|
||||
if (clickSounds === null) await init();
|
||||
|
||||
const safeClickSounds = clickSounds as ClickSounds;
|
||||
|
||||
|
@ -525,8 +534,8 @@ function createPreviewScale(scaleName: ValidScales): () => void {
|
|||
direction: 1,
|
||||
};
|
||||
|
||||
return () => {
|
||||
if (clickSounds === null) init();
|
||||
return async () => {
|
||||
if (clickSounds === null) await init();
|
||||
playScale(scaleName, scale);
|
||||
};
|
||||
}
|
||||
|
@ -632,7 +641,7 @@ export function playNote(
|
|||
oscillatorNode.stop(audioCtx.currentTime + 0.5);
|
||||
}
|
||||
|
||||
export function playClick(codeOverride?: string): void {
|
||||
export async function playClick(codeOverride?: string): Promise<void> {
|
||||
if (Config.playSoundOnClick === "off") return;
|
||||
|
||||
if (Config.playSoundOnClick in scaleConfigurations) {
|
||||
|
@ -649,7 +658,7 @@ export function playClick(codeOverride?: string): void {
|
|||
return;
|
||||
}
|
||||
|
||||
if (clickSounds === null) init();
|
||||
if (clickSounds === null) await init();
|
||||
|
||||
const sounds = (clickSounds as ClickSounds)[Config.playSoundOnClick];
|
||||
|
||||
|
@ -664,9 +673,9 @@ export function playClick(codeOverride?: string): void {
|
|||
soundToPlay.play();
|
||||
}
|
||||
|
||||
export function playError(): void {
|
||||
export async function playError(): Promise<void> {
|
||||
if (Config.playSoundOnError === "off") return;
|
||||
if (errorSounds === null) initErrorSound();
|
||||
if (errorSounds === null) await initErrorSound();
|
||||
|
||||
const sounds = (errorSounds as ErrorSounds)[Config.playSoundOnError];
|
||||
if (sounds === undefined) throw new Error("Invalid error sound ID");
|
||||
|
@ -681,10 +690,14 @@ export function playError(): void {
|
|||
}
|
||||
|
||||
function setVolume(val: number): void {
|
||||
Howler.volume(val);
|
||||
try {
|
||||
Howler.volume(val);
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
ConfigEvent.subscribe((eventKey, eventValue) => {
|
||||
if (eventKey === "playSoundOnClick" && eventValue !== "off") init();
|
||||
if (eventKey === "playSoundOnClick" && eventValue !== "off") void init();
|
||||
if (eventKey === "soundVolume") setVolume(parseFloat(eventValue as string));
|
||||
});
|
||||
|
|
|
@ -114,9 +114,9 @@ export async function loadStyle(name: string): Promise<void> {
|
|||
resolve();
|
||||
};
|
||||
if (name === "custom") {
|
||||
link.href = `/./themes/serika_dark.css`;
|
||||
link.href = `/themes/serika_dark.css`;
|
||||
} else {
|
||||
link.href = `/./themes/${name}.css`;
|
||||
link.href = `/themes/${name}.css`;
|
||||
}
|
||||
|
||||
if (headScript === null) {
|
||||
|
|
|
@ -255,3 +255,15 @@ export async function update(): Promise<void> {
|
|||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (import.meta.hot !== undefined) {
|
||||
import.meta.hot.dispose(() => {
|
||||
//
|
||||
});
|
||||
import.meta.hot.accept(() => {
|
||||
//
|
||||
});
|
||||
import.meta.hot.on("vite:afterUpdate", () => {
|
||||
void update();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { CLIENT_VERSION } from "../version";
|
||||
import { envConfig } from "../constants/env-config";
|
||||
|
||||
$("#nocss .requestedStylesheets").html(
|
||||
"Requested stylesheets:<br>" +
|
||||
|
@ -19,7 +19,7 @@ $("#nocss .requestedJs").html(
|
|||
.filter((l) => /(\/js\/mon|\/js\/vendor)/gi.test(l))
|
||||
.join("<br>") +
|
||||
"<br><br>Client version:<br>" +
|
||||
CLIENT_VERSION
|
||||
envConfig.clientVersion
|
||||
);
|
||||
|
||||
if (window.navigator.userAgent.toLowerCase().includes("mac")) {
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
// this file should be concatenated at the top of the legacy ts files
|
||||
|
||||
import "jquery";
|
||||
import "jquery-color";
|
||||
import "jquery.easing";
|
||||
|
||||
import "../styles/index.scss";
|
||||
import "./firebase";
|
||||
|
||||
import * as Logger from "./utils/logger";
|
||||
|
@ -44,35 +41,32 @@ import "./states/connection";
|
|||
import "./test/tts";
|
||||
import "./elements/fps-counter";
|
||||
import "./controllers/profile-search-controller";
|
||||
import "./version";
|
||||
import { isDevEnvironment } from "./utils/misc";
|
||||
|
||||
type ExtendedGlobal = typeof globalThis & MonkeyTypes.Global;
|
||||
function addToGlobal(items: Record<string, unknown>): void {
|
||||
for (const [name, item] of Object.entries(items)) {
|
||||
//@ts-expect-error
|
||||
window[name] = item;
|
||||
}
|
||||
}
|
||||
|
||||
const extendedGlobal = global as ExtendedGlobal;
|
||||
|
||||
extendedGlobal.snapshot = DB.getSnapshot;
|
||||
|
||||
extendedGlobal.config = Config;
|
||||
|
||||
extendedGlobal.toggleFilterDebug = Account.toggleFilterDebug;
|
||||
|
||||
extendedGlobal.glarsesMode = enable;
|
||||
|
||||
extendedGlobal.stats = TestStats.getStats;
|
||||
|
||||
extendedGlobal.replay = Replay.getReplayExport;
|
||||
|
||||
extendedGlobal.enableTimerDebug = TestTimer.enableTimerDebug;
|
||||
|
||||
extendedGlobal.getTimerStats = TestTimer.getTimerStats;
|
||||
|
||||
extendedGlobal.toggleUnsmoothedRaw = Result.toggleUnsmoothedRaw;
|
||||
|
||||
extendedGlobal.egVideoListener = egVideoListener;
|
||||
|
||||
extendedGlobal.toggleDebugLogs = Logger.toggleDebugLogs;
|
||||
addToGlobal({
|
||||
snapshot: DB.getSnapshot,
|
||||
config: Config,
|
||||
toggleFilterDebug: Account.toggleFilterDebug,
|
||||
glarsesMode: enable,
|
||||
stats: TestStats.getStats,
|
||||
replay: Replay.getReplayExport,
|
||||
enableTimerDebug: TestTimer.enableTimerDebug,
|
||||
getTimerStats: TestTimer.getTimerStats,
|
||||
toggleUnsmoothedRaw: Result.toggleUnsmoothedRaw,
|
||||
egVideoListener: egVideoListener,
|
||||
toggleDebugLogs: Logger.toggleDebugLogs,
|
||||
});
|
||||
|
||||
if (isDevEnvironment()) {
|
||||
//@ts-expect-error
|
||||
extendedGlobal.$ = $;
|
||||
void import("jquery").then((jq) => {
|
||||
addToGlobal({ $: jq.default });
|
||||
});
|
||||
}
|
||||
|
|
|
@ -270,7 +270,7 @@ async function initGroups(): Promise<void> {
|
|||
UpdateConfig.setPlaySoundOnError,
|
||||
"button",
|
||||
() => {
|
||||
if (Config.playSoundOnError !== "off") Sound.playError();
|
||||
if (Config.playSoundOnError !== "off") void Sound.playError();
|
||||
}
|
||||
) as SettingsGroup<SharedTypes.ConfigValue>;
|
||||
groups["playSoundOnClick"] = new SettingsGroup(
|
||||
|
@ -278,7 +278,7 @@ async function initGroups(): Promise<void> {
|
|||
UpdateConfig.setPlaySoundOnClick,
|
||||
"button",
|
||||
() => {
|
||||
if (Config.playSoundOnClick !== "off") Sound.playClick("KeyQ");
|
||||
if (Config.playSoundOnClick !== "off") void Sound.playClick("KeyQ");
|
||||
}
|
||||
) as SettingsGroup<SharedTypes.ConfigValue>;
|
||||
groups["showAllLines"] = new SettingsGroup(
|
||||
|
|
|
@ -8,7 +8,6 @@ import * as Focus from "./test/focus";
|
|||
import * as CookiePopup from "./popups/cookie-popup";
|
||||
import * as PSA from "./elements/psa";
|
||||
import * as ConnectionState from "./states/connection";
|
||||
import { Workbox } from "workbox-window";
|
||||
import * as FunboxList from "./test/funbox/funbox-list";
|
||||
//@ts-expect-error
|
||||
import Konami from "konami";
|
||||
|
@ -37,9 +36,9 @@ void UpdateConfig.loadFromLocalStorage();
|
|||
Focus.set(true, true);
|
||||
|
||||
$(document).ready(() => {
|
||||
Misc.loadCSS("/./css/slimselect.min.css", true);
|
||||
Misc.loadCSS("/./css/balloon.min.css", true);
|
||||
Misc.loadCSS("/./css/fa.min.css", true);
|
||||
Misc.loadCSS("/css/slimselect.min.css", true);
|
||||
Misc.loadCSS("/css/balloon.min.css", true);
|
||||
Misc.loadCSS("/css/fa.min.css", true);
|
||||
|
||||
CookiePopup.check();
|
||||
|
||||
|
@ -95,67 +94,6 @@ $(document).ready(() => {
|
|||
new Konami("https://keymash.io/");
|
||||
});
|
||||
|
||||
if ("serviceWorker" in navigator) {
|
||||
window.addEventListener("load", () => {
|
||||
// disabling service workers on localhost - they dont really work well with local development
|
||||
// and cause issues with hot reloading
|
||||
if (Misc.isDevEnvironment()) {
|
||||
void navigator.serviceWorker
|
||||
.getRegistrations()
|
||||
.then(function (registrations) {
|
||||
for (const registration of registrations) {
|
||||
// if (registration.scope !== "https://monkeytype.com/")
|
||||
void registration.unregister();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const wb = new Workbox("/service-worker.js");
|
||||
|
||||
let updateBannerId: number;
|
||||
|
||||
// Add an event listener to detect when the registered
|
||||
// service worker has installed but is waiting to activate.
|
||||
wb.addEventListener("waiting", (event) => {
|
||||
// set up a listener that will show a banner as soon as
|
||||
// the previously waiting service worker has taken control.
|
||||
wb.addEventListener("controlling", (event2) => {
|
||||
if (
|
||||
(event.isUpdate || event2.isUpdate) &&
|
||||
updateBannerId === undefined
|
||||
) {
|
||||
// updateBannerId = Notifications.addBanner(
|
||||
// "Update ready - please refresh",
|
||||
// 1,
|
||||
// "gift",
|
||||
// true
|
||||
// );
|
||||
}
|
||||
});
|
||||
|
||||
wb.messageSkipWaiting();
|
||||
});
|
||||
|
||||
wb.register()
|
||||
.then((registration) => {
|
||||
// if (registration?.waiting) {
|
||||
// //@ts-ignore
|
||||
// registration?.onupdatefound = (): void => {
|
||||
// Notifications.add("Downloading update...", 1, 0, "Update");
|
||||
// };
|
||||
// }
|
||||
console.log("Service worker registration succeeded:", registration);
|
||||
|
||||
setInterval(() => {
|
||||
void wb.update(); //check for updates every 15 minutes
|
||||
}, 900000);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("Service worker registration failed:", e);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.onerror = function (message, url, line, column, error): void {
|
||||
void log("error", {
|
||||
error: error?.stack ?? "",
|
||||
|
|
|
@ -88,12 +88,12 @@ export function pauseReplay(): void {
|
|||
function playSound(error = false): void {
|
||||
if (error) {
|
||||
if (config.playSoundOnError !== "off") {
|
||||
Sound.playError();
|
||||
void Sound.playError();
|
||||
} else {
|
||||
Sound.playClick();
|
||||
void Sound.playClick();
|
||||
}
|
||||
} else {
|
||||
Sound.playClick();
|
||||
void Sound.playClick();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,12 @@ import * as FunboxList from "./funbox/funbox-list";
|
|||
import { debounce } from "throttle-debounce";
|
||||
import * as ResultWordHighlight from "../elements/result-word-highlight";
|
||||
import * as ActivePage from "../states/active-page";
|
||||
import html2canvas from "html2canvas";
|
||||
import Format from "../utils/format";
|
||||
import * as Loader from "../elements/loader";
|
||||
|
||||
async function gethtml2canvas(): Promise<typeof import("html2canvas").default> {
|
||||
return (await import("html2canvas")).default;
|
||||
}
|
||||
|
||||
const debouncedZipfCheck = debounce(250, async () => {
|
||||
const supports = await Misc.checkIfLanguageSupportsZipf(Config.language);
|
||||
|
@ -398,6 +402,7 @@ export function colorful(tc: boolean): void {
|
|||
|
||||
let firefoxClipboardNotificatoinShown = false;
|
||||
export async function screenshot(): Promise<void> {
|
||||
Loader.show();
|
||||
let revealReplay = false;
|
||||
|
||||
let revertCookie = false;
|
||||
|
@ -409,6 +414,7 @@ export async function screenshot(): Promise<void> {
|
|||
}
|
||||
|
||||
function revertScreenshot(): void {
|
||||
Loader.hide();
|
||||
$("#ad-result-wrapper").removeClass("hidden");
|
||||
$("#ad-result-small-wrapper").removeClass("hidden");
|
||||
$("#testConfig").removeClass("hidden");
|
||||
|
@ -488,7 +494,10 @@ export async function screenshot(): Promise<void> {
|
|||
try {
|
||||
const paddingX = Misc.convertRemToPixels(2);
|
||||
const paddingY = Misc.convertRemToPixels(2);
|
||||
const canvas = await html2canvas(document.body, {
|
||||
|
||||
const canvas = await (
|
||||
await gethtml2canvas()
|
||||
)(document.body, {
|
||||
backgroundColor: await ThemeColors.get("bg"),
|
||||
width: sourceWidth + paddingX * 2,
|
||||
height: sourceHeight + paddingY * 2,
|
||||
|
|
17
frontend/src/ts/types/types.d.ts
vendored
17
frontend/src/ts/types/types.d.ts
vendored
|
@ -248,23 +248,6 @@ declare namespace MonkeyTypes {
|
|||
nextDelay: number;
|
||||
};
|
||||
|
||||
type Global = {
|
||||
snapshot(): Snapshot | undefined;
|
||||
config: SharedTypes.Config;
|
||||
toggleFilterDebug(): void;
|
||||
glarsesMode(): void;
|
||||
stats(): void;
|
||||
replay(): string;
|
||||
enableTimerDebug(): void;
|
||||
getTimerStats(): TimerStats[];
|
||||
toggleUnsmoothedRaw(): void;
|
||||
enableSpacingDebug(): void;
|
||||
noGoogleNoMo(): void;
|
||||
egVideoListener(options: Record<string, string>): void;
|
||||
wpmCalculationDebug(): void;
|
||||
toggleDebugLogs(): void;
|
||||
};
|
||||
|
||||
type GithubRelease = {
|
||||
url: string;
|
||||
assets_url: string;
|
||||
|
|
|
@ -4,7 +4,7 @@ const nativeLog = console.log;
|
|||
const nativeWarn = console.warn;
|
||||
const nativeError = console.error;
|
||||
|
||||
let debugLogs = localStorage.getItem("debugLogs") === "true" ?? false;
|
||||
let debugLogs = localStorage.getItem("debugLogs") === "true";
|
||||
|
||||
if (isDevEnvironment()) {
|
||||
debugLogs = true;
|
||||
|
|
|
@ -26,7 +26,7 @@ export const cachedFetchJson = memoizeAsync<string, typeof fetchJson>(
|
|||
export async function getLayoutsList(): Promise<MonkeyTypes.Layouts> {
|
||||
try {
|
||||
const layoutsList = await cachedFetchJson<MonkeyTypes.Layouts>(
|
||||
"/./layouts/_list.json"
|
||||
"/layouts/_list.json"
|
||||
);
|
||||
return layoutsList;
|
||||
} catch (e) {
|
||||
|
@ -52,7 +52,7 @@ let themesList: MonkeyTypes.Theme[] | undefined;
|
|||
export async function getThemesList(): Promise<MonkeyTypes.Theme[]> {
|
||||
if (!themesList) {
|
||||
let themes = await cachedFetchJson<MonkeyTypes.Theme[]>(
|
||||
"/./themes/_list.json"
|
||||
"/themes/_list.json"
|
||||
);
|
||||
|
||||
themes = themes.sort(function (a: MonkeyTypes.Theme, b: MonkeyTypes.Theme) {
|
||||
|
@ -94,7 +94,7 @@ export async function getSortedThemesList(): Promise<MonkeyTypes.Theme[]> {
|
|||
export async function getLanguageList(): Promise<string[]> {
|
||||
try {
|
||||
const languageList = await cachedFetchJson<string[]>(
|
||||
"/./languages/_list.json"
|
||||
"/languages/_list.json"
|
||||
);
|
||||
return languageList;
|
||||
} catch (e) {
|
||||
|
@ -108,7 +108,7 @@ export async function getLanguageGroups(): Promise<
|
|||
try {
|
||||
const languageGroupList = await cachedFetchJson<
|
||||
MonkeyTypes.LanguageGroup[]
|
||||
>("/./languages/_groups.json");
|
||||
>("/languages/_groups.json");
|
||||
return languageGroupList;
|
||||
} catch (e) {
|
||||
throw new Error("Language groups JSON fetch failed");
|
||||
|
@ -122,7 +122,7 @@ export async function getLanguage(
|
|||
// try {
|
||||
if (currentLanguage === undefined || currentLanguage.name !== lang) {
|
||||
currentLanguage = await cachedFetchJson<MonkeyTypes.LanguageObject>(
|
||||
`/./languages/${lang}.json`
|
||||
`/languages/${lang}.json`
|
||||
);
|
||||
}
|
||||
return currentLanguage;
|
||||
|
@ -130,7 +130,7 @@ export async function getLanguage(
|
|||
// console.error(`error getting language`);
|
||||
// console.error(e);
|
||||
// currentLanguage = await cachedFetchJson<MonkeyTypes.LanguageObject>(
|
||||
// `/./language/english.json`
|
||||
// `/language/english.json`
|
||||
// );
|
||||
// return currentLanguage;
|
||||
// }
|
||||
|
@ -161,7 +161,7 @@ let funboxList: MonkeyTypes.FunboxMetadata[] | undefined;
|
|||
export async function getFunboxList(): Promise<MonkeyTypes.FunboxMetadata[]> {
|
||||
if (!funboxList) {
|
||||
let list = await cachedFetchJson<MonkeyTypes.FunboxMetadata[]>(
|
||||
"/./funbox/_list.json"
|
||||
"/funbox/_list.json"
|
||||
);
|
||||
list = list.sort(function (
|
||||
a: MonkeyTypes.FunboxMetadata,
|
||||
|
@ -193,7 +193,7 @@ let fontsList: MonkeyTypes.FontObject[] | undefined;
|
|||
export async function getFontsList(): Promise<MonkeyTypes.FontObject[]> {
|
||||
if (!fontsList) {
|
||||
let list = await cachedFetchJson<MonkeyTypes.FontObject[]>(
|
||||
"/./fonts/_list.json"
|
||||
"/fonts/_list.json"
|
||||
);
|
||||
list = list.sort(function (
|
||||
a: MonkeyTypes.FontObject,
|
||||
|
@ -215,7 +215,7 @@ export async function getFontsList(): Promise<MonkeyTypes.FontObject[]> {
|
|||
export async function getChallengeList(): Promise<MonkeyTypes.Challenge[]> {
|
||||
try {
|
||||
const data = await cachedFetchJson<MonkeyTypes.Challenge[]>(
|
||||
"/./challenges/_list.json"
|
||||
"/challenges/_list.json"
|
||||
);
|
||||
return data;
|
||||
} catch (e) {
|
||||
|
@ -225,7 +225,7 @@ export async function getChallengeList(): Promise<MonkeyTypes.Challenge[]> {
|
|||
|
||||
export async function getSupportersList(): Promise<string[]> {
|
||||
try {
|
||||
const data = await cachedFetchJson<string[]>("/./about/supporters.json");
|
||||
const data = await cachedFetchJson<string[]>("/about/supporters.json");
|
||||
return data;
|
||||
} catch (e) {
|
||||
throw new Error("Supporters list JSON fetch failed");
|
||||
|
@ -234,7 +234,7 @@ export async function getSupportersList(): Promise<string[]> {
|
|||
|
||||
export async function getContributorsList(): Promise<string[]> {
|
||||
try {
|
||||
const data = await cachedFetchJson<string[]>("/./about/contributors.json");
|
||||
const data = await cachedFetchJson<string[]>("/about/contributors.json");
|
||||
return data;
|
||||
} catch (e) {
|
||||
throw new Error("Contributors list JSON fetch failed");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export const CLIENT_VERSION = "DEVELOPMENT-CLIENT";
|
||||
import { envConfig } from "./constants/env-config";
|
||||
|
||||
$(document.body).on("click", ".currentVersion", (e) => {
|
||||
if (e.shiftKey) {
|
||||
alert(CLIENT_VERSION);
|
||||
alert(envConfig.clientVersion);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"short_name": "Monkeytype",
|
||||
"name": "Monkeytype",
|
||||
"start_url": "/",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/images/icons/maskable_icon_x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/images/icons/general_icon_x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
}
|
||||
],
|
||||
"background_color": "#323437",
|
||||
"display": "standalone",
|
||||
"theme_color": "#323437"
|
||||
}
|
|
@ -2,9 +2,9 @@
|
|||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"module": "CommonJS",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"types": ["node", "jest"],
|
||||
"types": ["vite/client", "node", "jest", "jquery"],
|
||||
"allowUmdGlobalAccess": true,
|
||||
"resolveJsonModule": true,
|
||||
"outDir": "./build",
|
||||
|
@ -12,6 +12,7 @@
|
|||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
|
|
200
frontend/vite.config.js
Normal file
200
frontend/vite.config.js
Normal file
|
@ -0,0 +1,200 @@
|
|||
import { defineConfig, splitVendorChunkPlugin, mergeConfig } from "vite";
|
||||
import path from "node:path";
|
||||
import injectHTML from "vite-plugin-html-inject";
|
||||
import childProcess from "child_process";
|
||||
import { checker } from "vite-plugin-checker";
|
||||
import { VitePWA } from "vite-plugin-pwa";
|
||||
import replace from "vite-plugin-filter-replace";
|
||||
import Inspect from "vite-plugin-inspect";
|
||||
import autoprefixer from "autoprefixer";
|
||||
import "dotenv/config";
|
||||
|
||||
function pad(numbers, maxLength, fillString) {
|
||||
return numbers.map((number) =>
|
||||
number.toString().padStart(maxLength, fillString)
|
||||
);
|
||||
}
|
||||
|
||||
function buildClientVersion() {
|
||||
const date = new Date();
|
||||
const versionPrefix = pad(
|
||||
[date.getFullYear(), date.getMonth() + 1, date.getDate()],
|
||||
2,
|
||||
"0"
|
||||
).join(".");
|
||||
const versionSuffix = pad([date.getHours(), date.getMinutes()], 2, "0").join(
|
||||
"."
|
||||
);
|
||||
const version = [versionPrefix, versionSuffix].join("_");
|
||||
|
||||
const commitHash = childProcess
|
||||
.execSync("git rev-parse --short HEAD")
|
||||
.toString();
|
||||
|
||||
return `${version}.${commitHash}`;
|
||||
}
|
||||
|
||||
/** @type {import("vite").UserConfig} */
|
||||
const BASE_CONFIG = {
|
||||
plugins: [
|
||||
{
|
||||
name: "simple-jquery-inject",
|
||||
async transform(src, id) {
|
||||
if (id.endsWith(".ts")) {
|
||||
//check if file has a jQuery or $() call
|
||||
if (/(?:jQuery|\$)\([^)]*\)/.test(src)) {
|
||||
//if file has "use strict"; at the top, add it below that line, if not, add it at the very top
|
||||
if (src.startsWith(`"use strict";`)) {
|
||||
return src.replace(
|
||||
/("use strict";)/,
|
||||
`$1\nimport $ from "jquery";`
|
||||
);
|
||||
} else {
|
||||
return `import $ from "jquery";\n${src}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
checker({
|
||||
typescript: {
|
||||
root: path.resolve(__dirname, "./"),
|
||||
},
|
||||
eslint: {
|
||||
lintCommand: `eslint "${path.resolve(__dirname, "./src/ts/**/*.ts")}"`,
|
||||
},
|
||||
overlay: {
|
||||
initialIsOpen: false,
|
||||
},
|
||||
}),
|
||||
injectHTML(),
|
||||
Inspect(),
|
||||
],
|
||||
server: {
|
||||
open: true,
|
||||
port: 3000,
|
||||
host: process.env.BACKEND_URL !== undefined,
|
||||
},
|
||||
root: "src",
|
||||
publicDir: "../static",
|
||||
css: {
|
||||
devSourcemap: true,
|
||||
postcss: {
|
||||
plugins: [autoprefixer({})],
|
||||
},
|
||||
},
|
||||
envDir: "../",
|
||||
build: {
|
||||
emptyOutDir: true,
|
||||
outDir: "../dist",
|
||||
rollupOptions: {
|
||||
input: {
|
||||
monkeytype: path.resolve(__dirname, "src/index.html"),
|
||||
email: path.resolve(__dirname, "src/email-handler.html"),
|
||||
privacy: path.resolve(__dirname, "src/privacy-policy.html"),
|
||||
security: path.resolve(__dirname, "src/security-policy.html"),
|
||||
terms: path.resolve(__dirname, "src/terms-of-service.html"),
|
||||
},
|
||||
output: {
|
||||
assetFileNames: (assetInfo) => {
|
||||
let extType = assetInfo.name.split(".").at(1);
|
||||
if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
|
||||
extType = "images";
|
||||
}
|
||||
return `${extType}/[name].[hash][extname]`;
|
||||
},
|
||||
chunkFileNames: "js/[name].[hash].js",
|
||||
entryFileNames: "js/[name].[hash].js",
|
||||
},
|
||||
},
|
||||
},
|
||||
// resolve: {
|
||||
// alias: {
|
||||
// "/src": path.resolve(process.cwd(), "src"),
|
||||
// $: "jquery",
|
||||
// },
|
||||
// },
|
||||
define: {
|
||||
BACKEND_URL: JSON.stringify(
|
||||
process.env.BACKEND_URL || "http://localhost:5005"
|
||||
),
|
||||
IS_DEVELOPMENT: JSON.stringify(true),
|
||||
CLIENT_VERSION: JSON.stringify("DEVELOPMENT_CLIENT"),
|
||||
},
|
||||
optimizeDeps: {
|
||||
include: ["jquery"],
|
||||
},
|
||||
};
|
||||
|
||||
/** @type {import("vite").UserConfig} */
|
||||
const BUILD_CONFIG = {
|
||||
plugins: [
|
||||
splitVendorChunkPlugin(),
|
||||
VitePWA({
|
||||
registerType: "autoUpdate",
|
||||
manifest: {
|
||||
short_name: "Monkeytype",
|
||||
name: "Monkeytype",
|
||||
start_url: "/",
|
||||
icons: [
|
||||
{
|
||||
src: "/images/icons/maskable_icon_x512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png",
|
||||
purpose: "maskable",
|
||||
},
|
||||
{
|
||||
src: "/images/icons/general_icon_x512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png",
|
||||
purpose: "any",
|
||||
},
|
||||
],
|
||||
background_color: "#323437",
|
||||
display: "standalone",
|
||||
theme_color: "#323437",
|
||||
},
|
||||
manifestFilename: "manifest.json",
|
||||
workbox: {
|
||||
clientsClaim: true,
|
||||
cleanupOutdatedCaches: true,
|
||||
globIgnores: ["**/.*"],
|
||||
globPatterns: [],
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: ({ request, url }) => {
|
||||
const sameOrigin =
|
||||
new URL(request.url).origin === new URL(url).origin;
|
||||
const isApi = request.url.includes("api.monkeytype.com");
|
||||
return sameOrigin && !isApi;
|
||||
},
|
||||
handler: "NetworkFirst",
|
||||
options: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
replace([
|
||||
{
|
||||
filter: /firebase\.ts$/,
|
||||
replace: {
|
||||
from: /\.\/constants\/firebase-config/gi,
|
||||
to: "./constants/firebase-config-live",
|
||||
},
|
||||
},
|
||||
]),
|
||||
],
|
||||
define: {
|
||||
BACKEND_URL: JSON.stringify("https://api.monkeytype.com"),
|
||||
IS_DEVELOPMENT: JSON.stringify(false),
|
||||
CLIENT_VERSION: JSON.stringify(buildClientVersion()),
|
||||
},
|
||||
};
|
||||
|
||||
export default defineConfig(({ command }) => {
|
||||
if (command === "build") {
|
||||
return mergeConfig(BASE_CONFIG, BUILD_CONFIG);
|
||||
} else {
|
||||
return BASE_CONFIG;
|
||||
}
|
||||
});
|
|
@ -1,11 +0,0 @@
|
|||
const { merge } = require("webpack-merge");
|
||||
const BundleAnalyzerPlugin =
|
||||
require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
|
||||
const PROD_CONFIG = require("./config.prod");
|
||||
|
||||
/** @type { import('webpack').Configuration } */
|
||||
const AUDIT_CONFIG = {
|
||||
plugins: [new BundleAnalyzerPlugin()],
|
||||
};
|
||||
|
||||
module.exports = merge(PROD_CONFIG, AUDIT_CONFIG);
|
|
@ -1,137 +0,0 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { resolve } = require("path");
|
||||
const webpack = require("webpack");
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
const CircularDependencyPlugin = require("circular-dependency-plugin");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
|
||||
let circularImports = 0;
|
||||
|
||||
const htmlWebpackPlugins = [
|
||||
"terms-of-service",
|
||||
"security-policy",
|
||||
"privacy-policy",
|
||||
"email-handler",
|
||||
].map((name) => {
|
||||
return new HtmlWebpackPlugin({
|
||||
filename: `${name}.html`,
|
||||
template: resolve(__dirname, `../static/${name}.html`),
|
||||
inject: false,
|
||||
});
|
||||
});
|
||||
|
||||
/** @type { import('webpack').Configuration } */
|
||||
const BASE_CONFIG = {
|
||||
entry: {
|
||||
monkeytype: resolve(__dirname, "../src/ts/index.ts"),
|
||||
},
|
||||
resolve: { extensions: [".ts", ".js"] },
|
||||
output: {
|
||||
publicPath: "/",
|
||||
filename: "./js/[name].[chunkhash:8].js",
|
||||
path: resolve(__dirname, "../public/"),
|
||||
clean: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
loader: "ts-loader",
|
||||
options: {
|
||||
transpileOnly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.s[ac]ss$/i,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
url: false,
|
||||
importLoaders: 2,
|
||||
sourceMap: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: "postcss-loader",
|
||||
},
|
||||
{
|
||||
loader: "sass-loader",
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
chunks: "all",
|
||||
minChunks: 1,
|
||||
maxAsyncRequests: 30,
|
||||
maxInitialRequests: 30,
|
||||
enforceSizeThreshold: 50000,
|
||||
cacheGroups: {
|
||||
defaultVendors: {
|
||||
name: "vendor",
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
priority: -10,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
new CircularDependencyPlugin({
|
||||
exclude: /node_modules/,
|
||||
include: /./,
|
||||
failOnError: true,
|
||||
allowAsyncCycles: false,
|
||||
cwd: process.cwd(),
|
||||
onStart() {
|
||||
circularImports = 0;
|
||||
},
|
||||
onDetected({ paths }) {
|
||||
circularImports++;
|
||||
const joinedPaths = paths.join("\u001b[31m -> \u001b[0m");
|
||||
console.log(`\u001b[31mCircular import found: \u001b[0m${joinedPaths}`);
|
||||
},
|
||||
onEnd() {
|
||||
const colorCode = circularImports === 0 ? 32 : 31;
|
||||
const countWithColor = `\u001b[${colorCode}m${circularImports}\u001b[0m`;
|
||||
console.log(`Found ${countWithColor} circular imports`);
|
||||
},
|
||||
}),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: resolve(__dirname, "../static"),
|
||||
to: "./",
|
||||
globOptions: {
|
||||
ignore: ["**/static/*.html"],
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
new webpack.ProvidePlugin({
|
||||
$: "jquery",
|
||||
jQuery: "jquery",
|
||||
jQueryColor: "jquery-color",
|
||||
jQueryEasing: "jquery.easing",
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: "./index.html",
|
||||
template: resolve(__dirname, "../static/main.html"),
|
||||
inject: "body",
|
||||
}),
|
||||
...htmlWebpackPlugins,
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "./css/style.[chunkhash:8].css",
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = BASE_CONFIG;
|
|
@ -1,35 +0,0 @@
|
|||
const { resolve } = require("path");
|
||||
const { merge } = require("webpack-merge");
|
||||
const BASE_CONFIG = require("./config.base");
|
||||
const ExtraWatchWebpackPlugin = require("extra-watch-webpack-plugin");
|
||||
const webpack = require("webpack");
|
||||
require("dotenv").config();
|
||||
|
||||
/** @type { import('webpack').Configuration } */
|
||||
const DEV_CONFIG = {
|
||||
mode: "development",
|
||||
devtool: "inline-source-map",
|
||||
devServer: {
|
||||
compress: true,
|
||||
port: 3000,
|
||||
open: true,
|
||||
hot: false,
|
||||
historyApiFallback: true,
|
||||
client: {
|
||||
overlay: false,
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
new ExtraWatchWebpackPlugin({
|
||||
dirs: [resolve(__dirname, "../static/html")],
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
BACKEND_URL: JSON.stringify(
|
||||
process.env.BACKEND_URL || "http://localhost:5005"
|
||||
),
|
||||
IS_DEVELOPMENT: JSON.stringify(true),
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = merge(BASE_CONFIG, DEV_CONFIG);
|
|
@ -1,171 +0,0 @@
|
|||
const { resolve } = require("path");
|
||||
const { merge } = require("webpack-merge");
|
||||
const FilemanagerPlugin = require("filemanager-webpack-plugin");
|
||||
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
|
||||
const HtmlMinimizerPlugin = require("html-minimizer-webpack-plugin");
|
||||
const JsonMinimizerPlugin = require("json-minimizer-webpack-plugin");
|
||||
const WorkboxPlugin = require("workbox-webpack-plugin");
|
||||
|
||||
const BASE_CONFIG = require("./config.base");
|
||||
const webpack = require("webpack");
|
||||
|
||||
function pad(numbers, maxLength, fillString) {
|
||||
return numbers.map((number) =>
|
||||
number.toString().padStart(maxLength, fillString)
|
||||
);
|
||||
}
|
||||
|
||||
const { COMMIT_HASH = "NO_HASH" } = process.env;
|
||||
|
||||
/** @type { import('webpack').Configuration } */
|
||||
const PRODUCTION_CONFIG = {
|
||||
mode: "production",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /version\.ts$/,
|
||||
loader: "string-replace-loader",
|
||||
options: {
|
||||
search: /^export const CLIENT_VERSION =.*/,
|
||||
replace() {
|
||||
const date = new Date();
|
||||
|
||||
const versionPrefix = pad(
|
||||
[date.getFullYear(), date.getMonth() + 1, date.getDate()],
|
||||
2,
|
||||
"0"
|
||||
).join(".");
|
||||
const versionSuffix = pad(
|
||||
[date.getHours(), date.getMinutes()],
|
||||
2,
|
||||
"0"
|
||||
).join(".");
|
||||
const version = [versionPrefix, versionSuffix].join("_");
|
||||
|
||||
return `export const CLIENT_VERSION = "${version}.${COMMIT_HASH}";`;
|
||||
},
|
||||
flags: "g",
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /firebase\.ts$/,
|
||||
loader: "string-replace-loader",
|
||||
options: {
|
||||
search: /\.\/constants\/firebase-config/,
|
||||
replace() {
|
||||
return "./constants/firebase-config-live";
|
||||
},
|
||||
flags: "g",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
`...`,
|
||||
new HtmlMinimizerPlugin(),
|
||||
new JsonMinimizerPlugin(),
|
||||
new CssMinimizerPlugin(),
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new FilemanagerPlugin({
|
||||
events: {
|
||||
onEnd: {
|
||||
delete: [resolve(__dirname, "../public/html")],
|
||||
},
|
||||
},
|
||||
}),
|
||||
new WorkboxPlugin.GenerateSW({
|
||||
// these options encourage the ServiceWorkers to get in there fast
|
||||
// and not allow any straggling "old" SWs to hang around
|
||||
clientsClaim: true,
|
||||
skipWaiting: false,
|
||||
//include the generated css and js files
|
||||
maximumFileSizeToCacheInBytes: 11000000,
|
||||
cleanupOutdatedCaches: true,
|
||||
exclude: [
|
||||
// /html\/.*\.html/,
|
||||
// /LICENSE\.txt/,
|
||||
// /\.DS_Store/,
|
||||
// /\.map$/,
|
||||
// /^manifest.*\.js$/,
|
||||
// /languages\/.*\.json/,
|
||||
// /quotes\/.*\.json/,
|
||||
// /themes\/.*\.css/,
|
||||
// /challenges\/.*\.txt/,
|
||||
// /sound\/.*\.wav/,
|
||||
// /images\/.*\.(png|jpg)/,
|
||||
// /webfonts\/.+/,
|
||||
/./,
|
||||
],
|
||||
runtimeCaching: [
|
||||
// {
|
||||
// urlPattern: /.+\.(jpg|jpeg|gif|png|svg)/,
|
||||
// handler: "CacheFirst",
|
||||
// },
|
||||
// {
|
||||
// urlPattern: /.+\.(eot|otf|ttf|ttc|woff|woff2)/,
|
||||
// handler: "CacheFirst",
|
||||
// },
|
||||
// // {
|
||||
// // urlPattern: /.+\.(json|wav|txt|css)/,
|
||||
// // handler: "NetworkFirst",
|
||||
// // },
|
||||
// {
|
||||
// urlPattern: /.+\.min\.(js|css)/,
|
||||
// handler: "CacheFirst",
|
||||
// },
|
||||
// {
|
||||
// urlPattern: /.+\..{8}\.(js|css)/,
|
||||
// handler: "CacheFirst",
|
||||
// },
|
||||
{
|
||||
urlPattern: /\/\/monkeytype.com.+/,
|
||||
handler: "NetworkFirst",
|
||||
options: {},
|
||||
},
|
||||
|
||||
// {
|
||||
// urlPattern: /languages\/.*/,
|
||||
// handler: "StaleWhileRevalidate",
|
||||
// },
|
||||
// {
|
||||
// urlPattern: /quotes\/.*/,
|
||||
// handler: "StaleWhileRevalidate",
|
||||
// },
|
||||
// {
|
||||
// urlPattern: /themes\/.*/,
|
||||
// handler: "StaleWhileRevalidate",
|
||||
// },
|
||||
// {
|
||||
// urlPattern: /challenges\/.*/,
|
||||
// handler: "StaleWhileRevalidate",
|
||||
// },
|
||||
// {
|
||||
// urlPattern: /layouts\/.*/,
|
||||
// handler: "StaleWhileRevalidate",
|
||||
// },
|
||||
// {
|
||||
// urlPattern: /sound\/.*\.wav/,
|
||||
// handler: "StaleWhileRevalidate",
|
||||
// },
|
||||
// {
|
||||
// urlPattern: /images\/.*\.(png|jpg)/,
|
||||
// handler: "StaleWhileRevalidate",
|
||||
// },
|
||||
// {
|
||||
// urlPattern: /webfonts\/.+/,
|
||||
// handler: "CacheFirst",
|
||||
// },
|
||||
],
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
BACKEND_URL: JSON.stringify("https://api.monkeytype.com"),
|
||||
IS_DEVELOPMENT: JSON.stringify(false),
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = merge(BASE_CONFIG, PRODUCTION_CONFIG);
|
|
@ -22,17 +22,17 @@
|
|||
"release": "release-it -c .release-it.json",
|
||||
"release-fe": "release-it -c .release-it-fe.json",
|
||||
"hotfix": "cd frontend && npm run deploy-live && cd .. && sh ./bin/purgeCfCache.sh",
|
||||
"build-fe": "cd ./frontend && npm run build-live",
|
||||
"build-fe": "cd ./frontend && npm run build",
|
||||
"pretty": "prettier --check \"./backend/**/*.{ts,json,js,css,html}\" \"./frontend/**/*.{ts,js,scss}\" \"./frontend/static/**/*.{json,html,css}\"",
|
||||
"pretty-code": "prettier --check \"./backend/**/*.{ts,js,json,css,html}\" \"./frontend/**/*.{ts,js}\" \"./frontend/src/**/*.scss\"",
|
||||
"pretty-code-be": "prettier --check \"./backend/**/*.{ts,js,json,css,html}\"",
|
||||
"pretty-code-fe": "prettier --check \"./frontend/**/*.{ts,js}\" \"./frontend/src/**/*.scss\"",
|
||||
"pretty-fix": "prettier --write \"./backend/**/*.{ts,json,js,css,html}\" \"./frontend/**/*.{ts,js,scss}\" \"./frontend/static/**/*.{json,html,css}\"",
|
||||
"pr-check-lint-json": "cd frontend && npx gulp pr-check-lint-json",
|
||||
"pr-check-lint-json": "cd frontend && eslint './static/**/*.json'",
|
||||
"pr-check-quote-json": "cd frontend && npx gulp pr-check-quote-json",
|
||||
"pr-check-language-json": "cd frontend && npx gulp pr-check-language-json",
|
||||
"pr-check-other-json": "cd frontend && npx gulp pr-check-other-json",
|
||||
"pr-check-ts": "cd frontend && npx gulp pr-check-ts",
|
||||
"pr-check-build-fe": "cd frontend && npm run build",
|
||||
"pr-check-build-be": "cd backend && npm run build"
|
||||
},
|
||||
"engines": {
|
||||
|
|
Loading…
Reference in a new issue