mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-09 12:46:10 -05:00
Migrate to Vite
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
PORT=5800
|
||||
BASE_URL=http://localhost:5800
|
||||
BASE_URL=http://localhost:5173
|
||||
DB_PATH=db.sqlite3
|
||||
LOHI_TOKEN=salmon
|
||||
SESSION_SECRET=secret
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
/**
|
||||
* @type {import('prettier').Config}
|
||||
*/
|
||||
module.exports = {
|
||||
// defaults only so far
|
||||
};
|
||||
@@ -52,7 +52,7 @@ There is a sequence of commands you need to run:
|
||||
3. Make a copy of `.env.example` that's called `.env`. Filling additional values is not necessary unless you want to use real Discord authentication or develop the Lohi bot.
|
||||
4. `npm run migrate up` to set up the database tables.
|
||||
5. `npm run dev` to run the project in development mode.
|
||||
6. Navigate to `http://localhost:5800/admin`. There press the seed button to fill the DB with test data. You can also impersonate any user (Sendou#0043 = admin).
|
||||
6. Navigate to `http://localhost:5173/admin`. There press the seed button to fill the DB with test data. You can also impersonate any user (Sendou#0043 = admin).
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -217,7 +217,7 @@ Note: This is only useful if you have access to a production running on Render.c
|
||||
11. Fill new weapon IDs by category to `weapon-ids.ts` (easy to take from the diff of English weapons.json)
|
||||
12. Get gear IDs for each slot from /output folder and update `gear-ids.ts`.
|
||||
13. Replace `object-dmg.json` with the `object-dmg.json` in /output folder
|
||||
14. Replace `weapon-params.json` with the `params.json` in /output folder
|
||||
14. Replace `weapon-params.ts` with the `params.json` in /output folder
|
||||
15. Delete all images inside `main-weapons`, `main-weapons-outlined`, `main-weapons-outlined-2` and `gear` folders.
|
||||
16. Replace with images from Lean's repository.
|
||||
17. Run the `npm run replace-img-names` command
|
||||
|
||||
@@ -8,7 +8,7 @@ import type {
|
||||
UserWithPlusTier,
|
||||
} from "~/db/types";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import type {
|
||||
Ability as AbilityType,
|
||||
ModeShort,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { isRouteErrorResponse, useRouteError } from "@remix-run/react";
|
||||
import { Button } from "~/components/Button";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import {
|
||||
ERROR_GIRL_IMAGE_PATH,
|
||||
LOG_IN_URL,
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
import clsx from "clsx";
|
||||
import type * as React from "react";
|
||||
import { useMatches } from "react-router";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import type { RootLoaderData } from "~/root";
|
||||
import { SideNav } from "app/components/layout/SideNav";
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useSearchParams } from "@remix-run/react";
|
||||
import type * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { languages } from "~/modules/i18n";
|
||||
import { LinkButton } from "../Button";
|
||||
import { GlobeIcon } from "../icons/Globe";
|
||||
import { Popover } from "../Popover";
|
||||
import { languages } from "~/modules/i18n/config";
|
||||
|
||||
const addUniqueParam = (
|
||||
oldParams: URLSearchParams,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Link } from "@remix-run/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { userPage } from "~/utils/urls";
|
||||
import { Avatar } from "../Avatar";
|
||||
import { LogInIcon } from "../icons/LogIn";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import allTags from "~/features/calendar/tags.json";
|
||||
import type { CalendarEventTag } from "./db/types";
|
||||
import { tags } from "./features/calendar/calendar-constants";
|
||||
import type { BuildAbilitiesTupleWithUnknown } from "./modules/in-game-lists";
|
||||
|
||||
export const TWEET_LENGTH_MAX_LENGTH = 280;
|
||||
@@ -24,7 +24,7 @@ export const CALENDAR_EVENT = {
|
||||
DISCORD_INVITE_CODE_MAX_LENGTH: 50,
|
||||
BRACKET_URL_MAX_LENGTH: 200,
|
||||
MAX_AMOUNT_OF_DATES: 5,
|
||||
TAGS: Object.keys(allTags) as Array<CalendarEventTag>,
|
||||
TAGS: Object.keys(tags) as Array<CalendarEventTag>,
|
||||
};
|
||||
|
||||
export const CALENDAR_EVENT_RESULT = {
|
||||
|
||||
@@ -5,7 +5,6 @@ import { nanoid } from "nanoid";
|
||||
import invariant from "tiny-invariant";
|
||||
import { ADMIN_DISCORD_ID, ADMIN_ID, INVITE_CODE_LENGTH } from "~/constants";
|
||||
import { db, sql } from "~/db/sql";
|
||||
import allTags from "~/features/calendar/tags.json";
|
||||
import { MapPool } from "~/features/map-list-generator/core/map-pool";
|
||||
import {
|
||||
lastCompletedVoting,
|
||||
@@ -70,6 +69,7 @@ import {
|
||||
import placements from "./placements.json";
|
||||
import { BANNED_MAPS } from "~/features/sendouq-settings/banned-maps";
|
||||
import { AMOUNT_OF_MAPS_IN_POOL_PER_MODE } from "~/features/sendouq-settings/q-settings-constants";
|
||||
import { tags } from "~/features/calendar/calendar-constants";
|
||||
|
||||
const calendarEventWithToToolsRegOpen = () =>
|
||||
calendarEventWithToTools("PICNIC", true);
|
||||
@@ -667,7 +667,9 @@ function calendarEvents() {
|
||||
const userIds = userIdsInRandomOrder();
|
||||
|
||||
for (let id = 1; id <= AMOUNT_OF_CALENDAR_EVENTS; id++) {
|
||||
const tags = shuffle(Object.keys(allTags)).filter((tag) => tag !== "BADGE");
|
||||
const shuffledTags = shuffle(Object.keys(tags)).filter(
|
||||
(tag) => tag !== "BADGE",
|
||||
);
|
||||
|
||||
sql
|
||||
.prepare(
|
||||
@@ -702,7 +704,7 @@ function calendarEvents() {
|
||||
authorId: id === 1 ? NZAP_TEST_ID : userIds.pop(),
|
||||
tags:
|
||||
Math.random() > 0.2
|
||||
? tags
|
||||
? shuffledTags
|
||||
.slice(
|
||||
0,
|
||||
faker.helpers.arrayElement([
|
||||
|
||||
@@ -6,8 +6,8 @@ import type {
|
||||
RankedModeShort,
|
||||
StageId,
|
||||
} from "~/modules/in-game-lists";
|
||||
import type allTags from "~/features/calendar/tags.json";
|
||||
import type { TieredSkill } from "~/features/mmr/tiered.server";
|
||||
import type { tags } from "~/features/calendar/calendar-constants";
|
||||
|
||||
export interface User {
|
||||
id: number;
|
||||
@@ -135,7 +135,7 @@ export interface CalendarEvent {
|
||||
tournamentId: number | null;
|
||||
}
|
||||
|
||||
export type CalendarEventTag = keyof typeof allTags;
|
||||
export type CalendarEventTag = keyof typeof tags;
|
||||
|
||||
export interface CalendarEventDate {
|
||||
id: number;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { RemixBrowser } from "@remix-run/react";
|
||||
import { hydrateRoot } from "react-dom/client";
|
||||
import { i18nLoader } from "./modules/i18n";
|
||||
import i18next from "i18next";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import { i18nLoader } from "./modules/i18n/loader";
|
||||
|
||||
if ("serviceWorker" in navigator) {
|
||||
window.addEventListener("load", () => {
|
||||
|
||||
@@ -11,10 +11,10 @@ import { isbot } from "isbot";
|
||||
import cron from "node-cron";
|
||||
import { renderToPipeableStream } from "react-dom/server";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import { getUser } from "./features/auth/core";
|
||||
import { i18Instance } from "./modules/i18n";
|
||||
import { getUser } from "./features/auth/core/user.server";
|
||||
import { updatePatreonData } from "./modules/patreon";
|
||||
import { noticeError, setTransactionName } from "./utils/newrelic.server";
|
||||
import { i18Instance } from "./modules/i18n/loader.server";
|
||||
|
||||
const ABORT_DELAY = 5000;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { db, sql } from "~/db/sql";
|
||||
import { syncXPBadges } from "../badges";
|
||||
import type { Tables } from "~/db/tables";
|
||||
import { dateToDatabaseTimestamp } from "~/utils/dates";
|
||||
import invariant from "tiny-invariant";
|
||||
import { syncXPBadges } from "../badges/queries/syncXPBadges.server";
|
||||
|
||||
const removeOldLikesStm = sql.prepare(/*sql*/ `
|
||||
delete from
|
||||
|
||||
@@ -17,8 +17,7 @@ import { Main } from "~/components/Main";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { UserSearch } from "~/components/UserSearch";
|
||||
import * as AdminRepository from "~/features/admin/AdminRepository.server";
|
||||
import { makeArtist } from "~/features/art";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import {
|
||||
getUserId,
|
||||
isImpersonating,
|
||||
@@ -35,6 +34,7 @@ import { assertUnreachable } from "~/utils/types";
|
||||
import { SEED_URL, STOP_IMPERSONATING_URL, impersonateUrl } from "~/utils/urls";
|
||||
import { adminActionSchema } from "../admin-schemas.server";
|
||||
import { plusTiersFromVotingAndLeaderboard } from "../core/plus-tier.server";
|
||||
import { makeArtist } from "~/features/art/queries/makeArtist.server";
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
return [{ title: makeTitle("Admin page") }];
|
||||
|
||||
@@ -4,10 +4,10 @@ import { db } from "~/db/sql";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix";
|
||||
import { id } from "~/utils/zod";
|
||||
import type { GetTournamentMatchResponse } from "../schema";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { jsonArrayFrom } from "kysely/helpers/sqlite";
|
||||
import { resolveMapList } from "~/features/tournament-bracket/core/mapList.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import i18next from "~/modules/i18n/i18next.server";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
id,
|
||||
|
||||
@@ -6,8 +6,8 @@ import { id } from "~/utils/zod";
|
||||
import type { GetTournamentTeamsResponse } from "../schema";
|
||||
import { databaseTimestampToDate } from "~/utils/dates";
|
||||
import { jsonArrayFrom } from "kysely/helpers/sqlite";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import i18next from "~/modules/i18n/i18next.server";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
id,
|
||||
|
||||
@@ -5,7 +5,8 @@ import { safeNumberParse } from "~/utils/number";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix";
|
||||
import type { GetUserResponse } from "../schema";
|
||||
import { jsonArrayFrom } from "kysely/helpers/sqlite";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
("~/modules/i18n");
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
||||
@@ -21,4 +21,4 @@ export interface ListedArt {
|
||||
}
|
||||
|
||||
export const ART_SOURCES = ["ALL", "MADE-BY", "MADE-OF"] as const;
|
||||
export type ArtSouce = (typeof ART_SOURCES)[number];
|
||||
export type ArtSource = (typeof ART_SOURCES)[number];
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
export { ArtGrid } from "./components/ArtGrid";
|
||||
export { artsByUserId } from "./queries/artsByUserId.server";
|
||||
export { countArtByUserId } from "./queries/countArtByUserId.server";
|
||||
export { makeArtist } from "./queries/makeArtist.server";
|
||||
export { deleteArt } from "./queries/deleteArt.server";
|
||||
export { findArtById } from "./queries/findArtById.server";
|
||||
export type { ListedArt, ArtSouce } from "./art-types";
|
||||
export { ART_SOURCES } from "./art-types";
|
||||
export { NEW_ART_EXISTING_SEARCH_PARAM_KEY } from "./art-constants";
|
||||
export { deleteArtSchema } from "./art-schemas.server";
|
||||
@@ -21,7 +21,7 @@ import { Toggle } from "~/components/Toggle";
|
||||
import { CrossIcon } from "~/components/icons/Cross";
|
||||
import { s3UploadHandler } from "~/features/img-upload";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { requireUser } from "~/features/auth/core";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
import { dateToDatabaseTimestamp } from "~/utils/dates";
|
||||
import {
|
||||
validate,
|
||||
|
||||
@@ -10,7 +10,6 @@ import { Label } from "~/components/Label";
|
||||
import { Main } from "~/components/Main";
|
||||
import { Toggle } from "~/components/Toggle";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { type SendouRouteHandle } from "~/utils/remix";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
import { artPage, navIconUrl } from "~/utils/urls";
|
||||
@@ -22,6 +21,7 @@ import {
|
||||
} from "../queries/showcaseArts.server";
|
||||
import { Button } from "~/components/Button";
|
||||
import { CrossIcon } from "~/components/icons/Cross";
|
||||
import i18next from "~/modules/i18n/i18next.server";
|
||||
|
||||
const FILTERED_TAG_KEY = "tag";
|
||||
const OPEN_COMMISIONS_KEY = "open";
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Main } from "~/components/Main";
|
||||
import type { LinksFunction } from "@remix-run/node";
|
||||
import { json } from "@remix-run/node";
|
||||
import { mostRecentArticles } from "../core/list.server";
|
||||
import styles from "~/styles/front.css";
|
||||
import styles from "~/styles/front.css?url";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { SendouRouteHandle } from "~/utils/remix";
|
||||
import { articlePage, ARTICLES_MAIN_PAGE, navIconUrl } from "~/utils/urls";
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
export {
|
||||
callbackLoader,
|
||||
impersonateAction,
|
||||
stopImpersonatingAction,
|
||||
logInAction,
|
||||
logOutAction,
|
||||
createLogInLinkAction,
|
||||
logInViaLinkLoader,
|
||||
} from "./routes.server";
|
||||
|
||||
export { getUser, requireUser } from "./user.server";
|
||||
|
||||
export { useUser } from "./user";
|
||||
|
||||
export type { AuthErrorCode } from "./errors";
|
||||
@@ -1 +1 @@
|
||||
export { callbackLoader as loader } from "~/features/auth/core";
|
||||
export { callbackLoader as loader } from "~/features/auth/core/routes.server";
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { createLogInLinkAction as action } from "~/features/auth/core";
|
||||
export { createLogInLinkAction as action } from "~/features/auth/core/routes.server";
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { stopImpersonatingAction as action } from "~/features/auth/core";
|
||||
export { stopImpersonatingAction as action } from "~/features/auth/core/routes.server";
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { impersonateAction as action } from "~/features/auth/core";
|
||||
export { impersonateAction as action } from "~/features/auth/core/routes.server";
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { logInViaLinkLoader as loader } from "~/features/auth/core";
|
||||
export { logInViaLinkLoader as loader } from "~/features/auth/core/routes.server";
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { logOutAction as action } from "~/features/auth/core";
|
||||
export { logOutAction as action } from "~/features/auth/core/routes.server";
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { logInAction as action } from "~/features/auth/core";
|
||||
export { logInAction as action } from "~/features/auth/core/routes.server";
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { syncXPBadges } from "./queries/syncXPBadges.server";
|
||||
@@ -9,7 +9,7 @@ import { Label } from "~/components/Label";
|
||||
import { UserSearch } from "~/components/UserSearch";
|
||||
import { TrashIcon } from "~/components/icons/Trash";
|
||||
import type { User } from "~/db/types";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { requireUserId } from "~/features/auth/core/user.server";
|
||||
import { canEditBadgeManagers, canEditBadgeOwners } from "~/permissions";
|
||||
import { atOrError } from "~/utils/arrays";
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Badge } from "~/components/Badge";
|
||||
import { LinkButton } from "~/components/Button";
|
||||
import { Redirect } from "~/components/Redirect";
|
||||
import { type Badge as BadgeDBType } from "~/db/types";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { canEditBadgeOwners, isMod } from "~/permissions";
|
||||
import { BADGES_PAGE } from "~/utils/urls";
|
||||
import { type BadgesLoaderData } from "./badges";
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { LinksFunction, SerializeFrom } from "@remix-run/node";
|
||||
import { Link, NavLink, Outlet, useLoaderData } from "@remix-run/react";
|
||||
import { Badge } from "~/components/Badge";
|
||||
import { Main } from "~/components/Main";
|
||||
import styles from "~/styles/badges.css";
|
||||
import styles from "~/styles/badges.css?url";
|
||||
import {
|
||||
BADGES_PAGE,
|
||||
BORZOIC_TWITTER,
|
||||
|
||||
@@ -5,10 +5,10 @@ import type {
|
||||
SubWeaponId,
|
||||
} from "~/modules/in-game-lists";
|
||||
import type { SPECIAL_EFFECTS } from "./core/specialEffects";
|
||||
import type weaponParams from "./core/weapon-params.json";
|
||||
import type abilityValues from "./core/ability-values.json";
|
||||
import type { DAMAGE_TYPE } from "./analyzer-constants";
|
||||
import type { AbilityWithUnknown } from "~/modules/in-game-lists/types";
|
||||
import type { weaponParams } from "./core/weapon-params";
|
||||
import type { abilityValues } from "./core/utils";
|
||||
|
||||
type Overwrites = Record<
|
||||
string,
|
||||
@@ -113,7 +113,7 @@ export interface DistanceDamage {
|
||||
|
||||
export interface SubWeaponParams {
|
||||
overwrites?: Overwrites;
|
||||
SubInkSaveLv: 0 | 1 | 2 | 3;
|
||||
SubInkSaveLv: 0 | 1 | 2 | 3 | 4;
|
||||
/** How much ink one usage of the sub consumes */
|
||||
InkConsume: number;
|
||||
/** Amount of frames white ink (=no ink recovery during this time) takes */
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
{
|
||||
"ConsumeRt_Main": [0.55, 0.775, 1.0],
|
||||
"ConsumeRt_Sub_Lv0": [0.8, 0.9, 1.0],
|
||||
"ConsumeRt_Sub_Lv1": [0.7, 0.85, 1.0],
|
||||
"ConsumeRt_Sub_Lv2": [0.65, 0.825, 1.0],
|
||||
"ConsumeRt_Sub_Lv3": [0.6, 0.8, 1.0],
|
||||
"ConsumeRt_Sub_Lv4": [0.71111, 0.85555, 1.0],
|
||||
"DamageRt_BombH": [0.5, 0.75, 1.0],
|
||||
"DamageRt_BombL": [0.6, 0.75, 1.0],
|
||||
"DamageRt_LineMarker": [0.5, 0.75, 1.0],
|
||||
"DamageRt_Shield": [0.5, 0.75, 1.0],
|
||||
"DamageRt_Sprinkler": [0.5, 0.75, 1.0],
|
||||
"Dying_AroundFrm": [30.0, 60.0, 90.0],
|
||||
"Dying_ChaseFrm": [90.0, 180.0, 270.0],
|
||||
"IncreaseRt_Special": [1.3, 1.15, 1.0],
|
||||
"InkRecoverFrm_Std": [220.0, 410.0, 600.0],
|
||||
"InkRecoverFrm_Stealth": [117.0, 148.5, 180.0],
|
||||
"MarkingTimeRt": [0.1, 0.43, 1.0],
|
||||
"MarkingTimeRt_Trap": [0.1, 0.55, 1.0],
|
||||
"MoveDownRt_PoisonMist": [0.5, 0.75, 1.0],
|
||||
"MoveVelRt_Shot": [1.25, 1.125, 1.0],
|
||||
"MoveVel_Human": [0.144, 0.12, 0.096],
|
||||
"MoveVel_Human_Fast": [0.144, 0.124, 0.104],
|
||||
"MoveVel_Human_Slow": [0.144, 0.116, 0.088],
|
||||
"MoveVel_Stealth": [0.24, 0.216, 0.192],
|
||||
"MoveVel_Stealth_Fast": [0.24, 0.2208, 0.2016],
|
||||
"MoveVel_Stealth_Slow": [0.24, 0.216, 0.1728],
|
||||
"OpInk_ArmorHP": [39.0, 26.0, 0.0],
|
||||
"OpInk_DamageLmt": [0.2, 0.3, 0.4],
|
||||
"OpInk_DamagePerFrame": [0.0015, 0.0022, 0.003],
|
||||
"OpInk_JumpVel": [0.11, 0.098, 0.08],
|
||||
"OpInk_MoveVel": [0.0768, 0.0557, 0.024],
|
||||
"OpInk_MoveVel_Shot": [0.042, 0.033, 0.012],
|
||||
"OpInk_MoveVel_ShotK": [1.0, 0.75, 0.5],
|
||||
"Overwrite_ConsumeRt_Main": [-1.0, -1.0, -1.0],
|
||||
"Overwrite_MoveVelRt_Shot": [-1.0, -1.0, -1.0],
|
||||
"Somersault_MoveVelKd": [1.0, 0.925, 0.85],
|
||||
"SpecialGaugeRt_Restart": [1.0, 0.8, 0.5],
|
||||
"SuperJump_ChargeFrm": [20.0, 35.0, 80.0],
|
||||
"SuperJump_MoveFrm": [96.6, 132.3, 138.0],
|
||||
"WallJumpChargeFrm": [5.0, 18.0, 45.0],
|
||||
"ReduceJumpSwerveRate": [1.0, 0.75, 0.0],
|
||||
"SpawnSpeedZSpecUp": [0.0, 0.0, 0.0],
|
||||
"MoveSpeed": [0.0, 0.0, 0.0],
|
||||
"SubSpecUpParam": [0.0, 0.0, 0.0],
|
||||
"PeriodFirst": [0.0, 0.0, 0.0],
|
||||
"PeriodSecond": [0.0, 0.0, 0.0],
|
||||
"MarkingFrameSubSpec": [0.0, 0.0, 0.0],
|
||||
"SensorRadius": [0.0, 0.0, 0.0],
|
||||
"ExplosionRadius": [0.0, 0.0, 0.0],
|
||||
"MaxHP": [0.0, 0.0, 0.0],
|
||||
"SpecialDurationFrame": [0.0, 0.0, 0.0],
|
||||
"DistanceDamageDistanceRate": [0.0, 0.0, 0.0],
|
||||
"PaintRadius": [0.0, 0.0, 0.0],
|
||||
"MaxFieldHP": [0.0, 0.0, 0.0],
|
||||
"InkConsume_Hook": [0.0, 0.0, 0.0],
|
||||
"InkConsume_PerSec": [0.0, 0.0, 0.0],
|
||||
"TargetInCircleRadius": [0.0, 0.0, 0.0],
|
||||
"RainyFrame": [0.0, 0.0, 0.0],
|
||||
"ChargeRateAutoPerFrame": [0.0, 0.0, 0.0],
|
||||
"MaxFrame": [0.0, 0.0, 0.0],
|
||||
"MaxRadius": [0.0, 0.0, 0.0],
|
||||
"RadiusMax": [0.0, 0.0, 0.0],
|
||||
"RadiusMin": [0.0, 0.0, 0.0],
|
||||
"LaserFrame": [0.0, 0.0, 0.0],
|
||||
"SplashAroundVelocityMin": [0.0, 0.0, 0.0],
|
||||
"SplashAroundVelocityMax": [0.0, 0.0, 0.0],
|
||||
"SplashAroundPaintRadius": [0.0, 0.0, 0.0],
|
||||
"SpecialTotalFrame": [0.0, 0.0, 0.0],
|
||||
"PowerUpFrame": [0.0, 0.0, 0.0],
|
||||
"CrossPaintRadius": [0.0, 0.0, 0.0]
|
||||
}
|
||||
72
app/features/build-analyzer/core/ability-values.ts
Normal file
72
app/features/build-analyzer/core/ability-values.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
export const abilityValues = {
|
||||
ConsumeRt_Main: [0.55, 0.775, 1.0],
|
||||
ConsumeRt_Sub_Lv0: [0.8, 0.9, 1.0],
|
||||
ConsumeRt_Sub_Lv1: [0.7, 0.85, 1.0],
|
||||
ConsumeRt_Sub_Lv2: [0.65, 0.825, 1.0],
|
||||
ConsumeRt_Sub_Lv3: [0.6, 0.8, 1.0],
|
||||
ConsumeRt_Sub_Lv4: [0.71111, 0.85555, 1.0],
|
||||
DamageRt_BombH: [0.5, 0.75, 1.0],
|
||||
DamageRt_BombL: [0.6, 0.75, 1.0],
|
||||
DamageRt_LineMarker: [0.5, 0.75, 1.0],
|
||||
DamageRt_Shield: [0.5, 0.75, 1.0],
|
||||
DamageRt_Sprinkler: [0.5, 0.75, 1.0],
|
||||
Dying_AroundFrm: [30.0, 60.0, 90.0],
|
||||
Dying_ChaseFrm: [90.0, 180.0, 270.0],
|
||||
IncreaseRt_Special: [1.3, 1.15, 1.0],
|
||||
InkRecoverFrm_Std: [220.0, 410.0, 600.0],
|
||||
InkRecoverFrm_Stealth: [117.0, 148.5, 180.0],
|
||||
MarkingTimeRt: [0.1, 0.43, 1.0],
|
||||
MarkingTimeRt_Trap: [0.1, 0.55, 1.0],
|
||||
MoveDownRt_PoisonMist: [0.5, 0.75, 1.0],
|
||||
MoveVelRt_Shot: [1.25, 1.125, 1.0],
|
||||
MoveVel_Human: [0.144, 0.12, 0.096],
|
||||
MoveVel_Human_Fast: [0.144, 0.124, 0.104],
|
||||
MoveVel_Human_Slow: [0.144, 0.116, 0.088],
|
||||
MoveVel_Stealth: [0.24, 0.216, 0.192],
|
||||
MoveVel_Stealth_Fast: [0.24, 0.2208, 0.2016],
|
||||
MoveVel_Stealth_Slow: [0.24, 0.216, 0.1728],
|
||||
OpInk_ArmorHP: [39.0, 26.0, 0.0],
|
||||
OpInk_DamageLmt: [0.2, 0.3, 0.4],
|
||||
OpInk_DamagePerFrame: [0.0015, 0.0022, 0.003],
|
||||
OpInk_JumpVel: [0.11, 0.098, 0.08],
|
||||
OpInk_MoveVel: [0.0768, 0.0557, 0.024],
|
||||
OpInk_MoveVel_Shot: [0.042, 0.033, 0.012],
|
||||
OpInk_MoveVel_ShotK: [1.0, 0.75, 0.5],
|
||||
Overwrite_ConsumeRt_Main: [-1.0, -1.0, -1.0],
|
||||
Overwrite_MoveVelRt_Shot: [-1.0, -1.0, -1.0],
|
||||
Somersault_MoveVelKd: [1.0, 0.925, 0.85],
|
||||
SpecialGaugeRt_Restart: [1.0, 0.8, 0.5],
|
||||
SuperJump_ChargeFrm: [20.0, 35.0, 80.0],
|
||||
SuperJump_MoveFrm: [96.6, 132.3, 138.0],
|
||||
WallJumpChargeFrm: [5.0, 18.0, 45.0],
|
||||
ReduceJumpSwerveRate: [1.0, 0.75, 0.0],
|
||||
SpawnSpeedZSpecUp: [0.0, 0.0, 0.0],
|
||||
MoveSpeed: [0.0, 0.0, 0.0],
|
||||
SubSpecUpParam: [0.0, 0.0, 0.0],
|
||||
PeriodFirst: [0.0, 0.0, 0.0],
|
||||
PeriodSecond: [0.0, 0.0, 0.0],
|
||||
MarkingFrameSubSpec: [0.0, 0.0, 0.0],
|
||||
SensorRadius: [0.0, 0.0, 0.0],
|
||||
ExplosionRadius: [0.0, 0.0, 0.0],
|
||||
MaxHP: [0.0, 0.0, 0.0],
|
||||
SpecialDurationFrame: [0.0, 0.0, 0.0],
|
||||
DistanceDamageDistanceRate: [0.0, 0.0, 0.0],
|
||||
PaintRadius: [0.0, 0.0, 0.0],
|
||||
MaxFieldHP: [0.0, 0.0, 0.0],
|
||||
InkConsume_Hook: [0.0, 0.0, 0.0],
|
||||
InkConsume_PerSec: [0.0, 0.0, 0.0],
|
||||
TargetInCircleRadius: [0.0, 0.0, 0.0],
|
||||
RainyFrame: [0.0, 0.0, 0.0],
|
||||
ChargeRateAutoPerFrame: [0.0, 0.0, 0.0],
|
||||
MaxFrame: [0.0, 0.0, 0.0],
|
||||
MaxRadius: [0.0, 0.0, 0.0],
|
||||
RadiusMax: [0.0, 0.0, 0.0],
|
||||
RadiusMin: [0.0, 0.0, 0.0],
|
||||
LaserFrame: [0.0, 0.0, 0.0],
|
||||
SplashAroundVelocityMin: [0.0, 0.0, 0.0],
|
||||
SplashAroundVelocityMax: [0.0, 0.0, 0.0],
|
||||
SplashAroundPaintRadius: [0.0, 0.0, 0.0],
|
||||
SpecialTotalFrame: [0.0, 0.0, 0.0],
|
||||
PowerUpFrame: [0.0, 0.0, 0.0],
|
||||
CrossPaintRadius: [0.0, 0.0, 0.0],
|
||||
};
|
||||
@@ -52,7 +52,7 @@ import {
|
||||
roundToNDecimalPlaces,
|
||||
sumArray,
|
||||
} from "~/utils/number";
|
||||
import type abilityValuesJson from "./ability-values.json";
|
||||
import type { abilityValues as abilityValuesJson } from "./ability-values";
|
||||
|
||||
export function buildStats({
|
||||
weaponSplId,
|
||||
|
||||
@@ -30,11 +30,11 @@ import type {
|
||||
SubWeaponDamage,
|
||||
SubWeaponParams,
|
||||
} from "../analyzer-types";
|
||||
import abilityValuesJson from "./ability-values.json";
|
||||
import weaponParamsJson from "./weapon-params.json";
|
||||
import { abilityValues as abilityValuesJson } from "./ability-values";
|
||||
import { weaponParams as rawWeaponParams } from "./weapon-params";
|
||||
|
||||
export function weaponParams(): ParamsJson {
|
||||
return weaponParamsJson as ParamsJson;
|
||||
return rawWeaponParams as ParamsJson;
|
||||
}
|
||||
|
||||
export function buildToAbilityPoints(build: BuildAbilitiesTupleWithUnknown) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2354
app/features/build-analyzer/core/weapon-params.ts
Normal file
2354
app/features/build-analyzer/core/weapon-params.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -22,4 +22,3 @@ export {
|
||||
subStats,
|
||||
} from "./core/stats";
|
||||
export { DAMAGE_TYPE, damageTypeToWeaponType } from "./analyzer-constants";
|
||||
export { default as weaponParams } from "./core/weapon-params.json";
|
||||
|
||||
@@ -17,7 +17,7 @@ import { BeakerIcon } from "~/components/icons/Beaker";
|
||||
import { MAX_AP } from "~/constants";
|
||||
import { useSetTitle } from "~/hooks/useSetTitle";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import type { Ability as AbilityType } from "~/modules/in-game-lists";
|
||||
import {
|
||||
ANGLE_SHOOTER_ID,
|
||||
@@ -59,7 +59,7 @@ import type {
|
||||
Stat,
|
||||
SubWeaponDamage,
|
||||
} from "../analyzer-types";
|
||||
import styles from "../analyzer.css";
|
||||
import styles from "../analyzer.css?url";
|
||||
import {
|
||||
ABILITIES_WITHOUT_CHUNKS,
|
||||
getAbilityChunksMapAsArray,
|
||||
|
||||
@@ -9,7 +9,7 @@ import clsx from "clsx";
|
||||
import { Ability } from "~/components/Ability";
|
||||
import { Main } from "~/components/Main";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { notFoundIfNullLike, type SendouRouteHandle } from "~/utils/remix";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
import { weaponNameSlugToId } from "~/utils/unslugify.server";
|
||||
|
||||
@@ -10,7 +10,7 @@ import { weaponNameSlugToId } from "~/utils/unslugify.server";
|
||||
import { averageAbilityPoints } from "../queries/averageAbilityPoints.server";
|
||||
import { abilityPointCountsToAverages } from "../build-stats-utils";
|
||||
import { Ability } from "~/components/Ability";
|
||||
import styles from "../build-stats.css";
|
||||
import styles from "../build-stats.css?url";
|
||||
import { WeaponImage } from "~/components/Image";
|
||||
import { notFoundIfNullLike, type SendouRouteHandle } from "~/utils/remix";
|
||||
import { MAX_AP, ONE_HOUR_IN_MS } from "~/constants";
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
outlinedMainWeaponImageUrl,
|
||||
weaponBuildPage,
|
||||
} from "~/utils/urls";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
import { cache, ttl } from "~/utils/cache.server";
|
||||
import { cachified } from "@epic-web/cachified";
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
ONE_HOUR_IN_MS,
|
||||
PATCHES,
|
||||
} from "~/constants";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { weaponIdIsNotAlt } from "~/modules/in-game-lists";
|
||||
import { cache, ttl } from "~/utils/cache.server";
|
||||
import { safeJSONParse } from "~/utils/json";
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
weaponCategoryUrl,
|
||||
} from "~/utils/urls";
|
||||
import { type SendouRouteHandle } from "~/utils/remix";
|
||||
import styles from "~/styles/builds.css";
|
||||
import styles from "~/styles/builds.css?url";
|
||||
import type { LinksFunction, MetaFunction } from "@remix-run/node";
|
||||
import { Main } from "~/components/Main";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
|
||||
50
app/features/calendar/calendar-constants.ts
Normal file
50
app/features/calendar/calendar-constants.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
export const tags = {
|
||||
BADGE: {
|
||||
color: "#000",
|
||||
},
|
||||
SPECIAL: {
|
||||
color: "#CE93D8",
|
||||
},
|
||||
ART: {
|
||||
color: "#C158F6",
|
||||
},
|
||||
MONEY: {
|
||||
color: "#96F29D",
|
||||
},
|
||||
REGION: {
|
||||
color: "#FF8C8C",
|
||||
},
|
||||
LOW: {
|
||||
color: "#BBDEFB",
|
||||
},
|
||||
COUNT: {
|
||||
color: "#62E8F5",
|
||||
},
|
||||
LAN: {
|
||||
color: "#FFF",
|
||||
},
|
||||
QUALIFIER: {
|
||||
color: "#FFC0CB",
|
||||
},
|
||||
SZ: {
|
||||
color: "#F44336",
|
||||
},
|
||||
TW: {
|
||||
color: "#D50000",
|
||||
},
|
||||
S1: {
|
||||
color: "#E5E4E2",
|
||||
},
|
||||
S2: {
|
||||
color: "#388E3C",
|
||||
},
|
||||
SR: {
|
||||
color: "#FBCEB1",
|
||||
},
|
||||
CARDS: {
|
||||
color: "#E4D00A",
|
||||
},
|
||||
FULL_TOURNAMENT: {
|
||||
color: "#FFC0CB",
|
||||
},
|
||||
};
|
||||
103
app/features/calendar/calendar-schemas.server.ts
Normal file
103
app/features/calendar/calendar-schemas.server.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { z } from "zod";
|
||||
import { CALENDAR_EVENT } from "~/constants";
|
||||
import type { CalendarEventTag } from "~/db/types";
|
||||
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
|
||||
import {
|
||||
FORMATS_SHORT,
|
||||
TOURNAMENT,
|
||||
} from "~/features/tournament/tournament-constants";
|
||||
import {
|
||||
actualNumber,
|
||||
checkboxValueToBoolean,
|
||||
date,
|
||||
falsyToNull,
|
||||
id,
|
||||
processMany,
|
||||
removeDuplicates,
|
||||
safeJSONParse,
|
||||
toArray,
|
||||
} from "~/utils/zod";
|
||||
import { calendarEventMaxDate, calendarEventMinDate } from "./calendar-utils";
|
||||
|
||||
export const newCalendarEventActionSchema = z
|
||||
.object({
|
||||
eventToEditId: z.preprocess(actualNumber, id.nullish()),
|
||||
name: z
|
||||
.string()
|
||||
.min(CALENDAR_EVENT.NAME_MIN_LENGTH)
|
||||
.max(CALENDAR_EVENT.NAME_MAX_LENGTH),
|
||||
description: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(CALENDAR_EVENT.DESCRIPTION_MAX_LENGTH).nullable(),
|
||||
),
|
||||
date: z.preprocess(
|
||||
toArray,
|
||||
z
|
||||
.array(
|
||||
z.preprocess(
|
||||
date,
|
||||
z.date().min(calendarEventMinDate()).max(calendarEventMaxDate()),
|
||||
),
|
||||
)
|
||||
.min(1)
|
||||
.max(CALENDAR_EVENT.MAX_AMOUNT_OF_DATES),
|
||||
),
|
||||
bracketUrl: z
|
||||
.string()
|
||||
.url()
|
||||
.max(CALENDAR_EVENT.BRACKET_URL_MAX_LENGTH)
|
||||
.default("https://sendou.ink"),
|
||||
discordInviteCode: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(CALENDAR_EVENT.DISCORD_INVITE_CODE_MAX_LENGTH).nullable(),
|
||||
),
|
||||
tags: z.preprocess(
|
||||
processMany(safeJSONParse, removeDuplicates),
|
||||
z
|
||||
.array(
|
||||
z
|
||||
.string()
|
||||
.refine((val) =>
|
||||
CALENDAR_EVENT.TAGS.includes(val as CalendarEventTag),
|
||||
),
|
||||
)
|
||||
.nullable(),
|
||||
),
|
||||
badges: z.preprocess(
|
||||
processMany(safeJSONParse, removeDuplicates),
|
||||
z.array(id).nullable(),
|
||||
),
|
||||
pool: z.string().optional(),
|
||||
toToolsEnabled: z.preprocess(checkboxValueToBoolean, z.boolean()),
|
||||
toToolsMode: z.enum(["ALL", "SZ", "TC", "RM", "CB"]).optional(),
|
||||
//
|
||||
// tournament format related fields
|
||||
//
|
||||
format: z.enum(FORMATS_SHORT).nullish(),
|
||||
withUndergroundBracket: z.preprocess(checkboxValueToBoolean, z.boolean()),
|
||||
teamsPerGroup: z.coerce
|
||||
.number()
|
||||
.min(TOURNAMENT.MIN_GROUP_SIZE)
|
||||
.max(TOURNAMENT.MAX_GROUP_SIZE)
|
||||
.nullish(),
|
||||
advancingCount: z.coerce
|
||||
.number()
|
||||
.min(1)
|
||||
.max(TOURNAMENT.MAX_GROUP_SIZE)
|
||||
.nullish(),
|
||||
})
|
||||
.refine(
|
||||
async (schema) => {
|
||||
if (schema.eventToEditId) {
|
||||
const eventToEdit = await CalendarRepository.findById({
|
||||
id: schema.eventToEditId,
|
||||
});
|
||||
return schema.date.length === 1 || !eventToEdit?.tournamentId;
|
||||
} else {
|
||||
return schema.date.length === 1 || !schema.toToolsEnabled;
|
||||
}
|
||||
},
|
||||
{
|
||||
message: "Tournament must have exactly one date",
|
||||
},
|
||||
);
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { z } from "zod";
|
||||
import { isAdmin } from "~/permissions";
|
||||
import type { newCalendarEventActionSchema } from "./routes/calendar.new";
|
||||
import type { TournamentSettings } from "~/db/tables";
|
||||
import { BRACKET_NAMES } from "../tournament/tournament-constants";
|
||||
import { nullFilledArray } from "~/utils/arrays";
|
||||
import type { newCalendarEventActionSchema } from "./calendar-schemas.server";
|
||||
|
||||
const usersWithTournamentPerms =
|
||||
process.env["TOURNAMENT_PERMS"]?.split(",").map(Number) ?? [];
|
||||
|
||||
@@ -12,3 +12,10 @@ export function bracketProgressionToShortTournamentFormat(
|
||||
|
||||
return "RR_TO_SE";
|
||||
}
|
||||
|
||||
export const calendarEventMinDate = () => new Date(Date.UTC(2015, 4, 28));
|
||||
export const calendarEventMaxDate = () => {
|
||||
const result = new Date();
|
||||
result.setFullYear(result.getFullYear() + 1);
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -5,8 +5,8 @@ import { Badge } from "~/components/Badge";
|
||||
import { Button } from "~/components/Button";
|
||||
import { CrossIcon } from "~/components/icons/Cross";
|
||||
import type { CalendarEventTag } from "~/db/types";
|
||||
import allTags from "../tags.json";
|
||||
import type * as CalendarRepository from "../CalendarRepository.server";
|
||||
import { tags as allTags } from "../calendar-constants";
|
||||
|
||||
export function Tags({
|
||||
tags,
|
||||
|
||||
@@ -21,17 +21,17 @@ import { Placement } from "~/components/Placement";
|
||||
import { Section } from "~/components/Section";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { requireUserId } from "~/features/auth/core/user.server";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { MapPool } from "~/features/map-list-generator/core/map-pool";
|
||||
import {
|
||||
canDeleteCalendarEvent,
|
||||
canEditCalendarEvent,
|
||||
canReportCalendarEventWinners,
|
||||
} from "~/permissions";
|
||||
import calendarStyles from "~/styles/calendar-event.css";
|
||||
import mapsStyles from "~/styles/maps.css";
|
||||
import calendarStyles from "~/styles/calendar-event.css?url";
|
||||
import mapsStyles from "~/styles/maps.css?url";
|
||||
import { databaseTimestampToDate } from "~/utils/dates";
|
||||
import {
|
||||
notFoundIfFalsy,
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
import { json, redirect } from "@remix-run/node";
|
||||
import type {
|
||||
SerializeFrom,
|
||||
ActionFunction,
|
||||
LinksFunction,
|
||||
LoaderFunctionArgs,
|
||||
MetaFunction,
|
||||
SerializeFrom,
|
||||
} from "@remix-run/node";
|
||||
import { json, redirect } from "@remix-run/node";
|
||||
import { Form, useLoaderData } from "@remix-run/react";
|
||||
import clsx from "clsx";
|
||||
import * as React from "react";
|
||||
import { z } from "zod";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { AlertVariation } from "~/components/Alert";
|
||||
import { Alert } from "~/components/Alert";
|
||||
import { Badge } from "~/components/Badge";
|
||||
import { Button } from "~/components/Button";
|
||||
import { DateInput } from "~/components/DateInput";
|
||||
import { Divider } from "~/components/Divider";
|
||||
import { FormMessage } from "~/components/FormMessage";
|
||||
import { CrossIcon } from "~/components/icons/Cross";
|
||||
import { TrashIcon } from "~/components/icons/Trash";
|
||||
import { Input } from "~/components/Input";
|
||||
import { Label } from "~/components/Label";
|
||||
import { Main } from "~/components/Main";
|
||||
@@ -25,16 +24,29 @@ import { MapPoolSelector } from "~/components/MapPoolSelector";
|
||||
import { RequiredHiddenInput } from "~/components/RequiredHiddenInput";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { Toggle } from "~/components/Toggle";
|
||||
import { CrossIcon } from "~/components/icons/Cross";
|
||||
import { TrashIcon } from "~/components/icons/Trash";
|
||||
import { CALENDAR_EVENT } from "~/constants";
|
||||
import type { Tables } from "~/db/tables";
|
||||
import type { Badge as BadgeType, CalendarEventTag } from "~/db/types";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import * as BadgeRepository from "~/features/badges/BadgeRepository.server";
|
||||
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
|
||||
import { MapPool } from "~/features/map-list-generator/core/map-pool";
|
||||
import type { Tournament } from "~/features/tournament-bracket/core/Tournament";
|
||||
import { tournamentFromDB } from "~/features/tournament-bracket/core/Tournament.server";
|
||||
import {
|
||||
BRACKET_NAMES,
|
||||
TOURNAMENT,
|
||||
type TournamentFormatShort,
|
||||
} from "~/features/tournament/tournament-constants";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import type { RankedModeShort } from "~/modules/in-game-lists";
|
||||
import { rankedModesShort } from "~/modules/in-game-lists/modes";
|
||||
import { canEditCalendarEvent } from "~/permissions";
|
||||
import calendarNewStyles from "~/styles/calendar-new.css";
|
||||
import mapsStyles from "~/styles/maps.css";
|
||||
import calendarNewStyles from "~/styles/calendar-new.css?url";
|
||||
import mapsStyles from "~/styles/maps.css?url";
|
||||
import { isDefined } from "~/utils/arrays";
|
||||
import {
|
||||
databaseTimestampToDate,
|
||||
@@ -50,45 +62,18 @@ import {
|
||||
} from "~/utils/remix";
|
||||
import { makeTitle, pathnameFromPotentialURL } from "~/utils/strings";
|
||||
import { calendarEventPage, tournamentBracketsPage } from "~/utils/urls";
|
||||
import {
|
||||
actualNumber,
|
||||
checkboxValueToBoolean,
|
||||
date,
|
||||
falsyToNull,
|
||||
id,
|
||||
processMany,
|
||||
removeDuplicates,
|
||||
safeJSONParse,
|
||||
toArray,
|
||||
} from "~/utils/zod";
|
||||
import { Tags } from "../components/Tags";
|
||||
import type { RankedModeShort } from "~/modules/in-game-lists";
|
||||
import { rankedModesShort } from "~/modules/in-game-lists/modes";
|
||||
import * as BadgeRepository from "~/features/badges/BadgeRepository.server";
|
||||
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
|
||||
import { newCalendarEventActionSchema } from "../calendar-schemas.server";
|
||||
import {
|
||||
bracketProgressionToShortTournamentFormat,
|
||||
calendarEventMaxDate,
|
||||
calendarEventMinDate,
|
||||
canAddNewEvent,
|
||||
} from "../calendar-utils";
|
||||
import {
|
||||
canCreateTournament,
|
||||
formValuesToBracketProgression,
|
||||
} from "../calendar-utils.server";
|
||||
import { tournamentFromDB } from "~/features/tournament-bracket/core/Tournament.server";
|
||||
import type { Tournament } from "~/features/tournament-bracket/core/Tournament";
|
||||
import type { Tables } from "~/db/tables";
|
||||
import { Divider } from "~/components/Divider";
|
||||
import {
|
||||
BRACKET_NAMES,
|
||||
FORMATS_SHORT,
|
||||
TOURNAMENT,
|
||||
type TournamentFormatShort,
|
||||
} from "~/features/tournament/tournament-constants";
|
||||
|
||||
const MIN_DATE = new Date(Date.UTC(2015, 4, 28));
|
||||
|
||||
const MAX_DATE = new Date();
|
||||
MAX_DATE.setFullYear(MAX_DATE.getFullYear() + 1);
|
||||
import { Tags } from "../components/Tags";
|
||||
|
||||
export const links: LinksFunction = () => {
|
||||
return [
|
||||
@@ -105,84 +90,6 @@ export const meta: MetaFunction = (args) => {
|
||||
return [{ title: data.title }];
|
||||
};
|
||||
|
||||
export const newCalendarEventActionSchema = z
|
||||
.object({
|
||||
eventToEditId: z.preprocess(actualNumber, id.nullish()),
|
||||
name: z
|
||||
.string()
|
||||
.min(CALENDAR_EVENT.NAME_MIN_LENGTH)
|
||||
.max(CALENDAR_EVENT.NAME_MAX_LENGTH),
|
||||
description: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(CALENDAR_EVENT.DESCRIPTION_MAX_LENGTH).nullable(),
|
||||
),
|
||||
date: z.preprocess(
|
||||
toArray,
|
||||
z
|
||||
.array(z.preprocess(date, z.date().min(MIN_DATE).max(MAX_DATE)))
|
||||
.min(1)
|
||||
.max(CALENDAR_EVENT.MAX_AMOUNT_OF_DATES),
|
||||
),
|
||||
bracketUrl: z
|
||||
.string()
|
||||
.url()
|
||||
.max(CALENDAR_EVENT.BRACKET_URL_MAX_LENGTH)
|
||||
.default("https://sendou.ink"),
|
||||
discordInviteCode: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(CALENDAR_EVENT.DISCORD_INVITE_CODE_MAX_LENGTH).nullable(),
|
||||
),
|
||||
tags: z.preprocess(
|
||||
processMany(safeJSONParse, removeDuplicates),
|
||||
z
|
||||
.array(
|
||||
z
|
||||
.string()
|
||||
.refine((val) =>
|
||||
CALENDAR_EVENT.TAGS.includes(val as CalendarEventTag),
|
||||
),
|
||||
)
|
||||
.nullable(),
|
||||
),
|
||||
badges: z.preprocess(
|
||||
processMany(safeJSONParse, removeDuplicates),
|
||||
z.array(id).nullable(),
|
||||
),
|
||||
pool: z.string().optional(),
|
||||
toToolsEnabled: z.preprocess(checkboxValueToBoolean, z.boolean()),
|
||||
toToolsMode: z.enum(["ALL", "SZ", "TC", "RM", "CB"]).optional(),
|
||||
//
|
||||
// tournament format related fields
|
||||
//
|
||||
format: z.enum(FORMATS_SHORT).nullish(),
|
||||
withUndergroundBracket: z.preprocess(checkboxValueToBoolean, z.boolean()),
|
||||
teamsPerGroup: z.coerce
|
||||
.number()
|
||||
.min(TOURNAMENT.MIN_GROUP_SIZE)
|
||||
.max(TOURNAMENT.MAX_GROUP_SIZE)
|
||||
.nullish(),
|
||||
advancingCount: z.coerce
|
||||
.number()
|
||||
.min(1)
|
||||
.max(TOURNAMENT.MAX_GROUP_SIZE)
|
||||
.nullish(),
|
||||
})
|
||||
.refine(
|
||||
async (schema) => {
|
||||
if (schema.eventToEditId) {
|
||||
const eventToEdit = await CalendarRepository.findById({
|
||||
id: schema.eventToEditId,
|
||||
});
|
||||
return schema.date.length === 1 || !eventToEdit?.tournamentId;
|
||||
} else {
|
||||
return schema.date.length === 1 || !schema.toToolsEnabled;
|
||||
}
|
||||
},
|
||||
{
|
||||
message: "Tournament must have exactly one date",
|
||||
},
|
||||
);
|
||||
|
||||
export const action: ActionFunction = async ({ request }) => {
|
||||
const user = await requireUser(request);
|
||||
const data = await parseRequestFormData({
|
||||
@@ -501,8 +408,8 @@ function DatesInput({ allowMultiDate }: { allowMultiDate?: boolean }) {
|
||||
id={`date-input-${key}`}
|
||||
name="date"
|
||||
defaultValue={date ?? undefined}
|
||||
min={MIN_DATE}
|
||||
max={MAX_DATE}
|
||||
min={calendarEventMinDate()}
|
||||
max={calendarEventMaxDate()}
|
||||
required
|
||||
onChange={(newDate: Date | null) => {
|
||||
setDatesInputState((current) =>
|
||||
|
||||
@@ -16,10 +16,10 @@ import { LinkButton } from "~/components/Button";
|
||||
import { Main } from "~/components/Main";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { getUserId } from "~/features/auth/core/user.server";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import styles from "~/styles/calendar.css";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import styles from "~/styles/calendar.css?url";
|
||||
import { joinListToNaturalString } from "~/utils/arrays";
|
||||
import {
|
||||
databaseTimestampToDate,
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
{
|
||||
"BADGE": {
|
||||
"color": "#000"
|
||||
},
|
||||
"SPECIAL": {
|
||||
"color": "#CE93D8"
|
||||
},
|
||||
"ART": {
|
||||
"color": "#C158F6"
|
||||
},
|
||||
"MONEY": {
|
||||
"color": "#96F29D"
|
||||
},
|
||||
"REGION": {
|
||||
"color": "#FF8C8C"
|
||||
},
|
||||
"LOW": {
|
||||
"color": "#BBDEFB"
|
||||
},
|
||||
"COUNT": {
|
||||
"color": "#62E8F5"
|
||||
},
|
||||
"LAN": {
|
||||
"color": "#FFF"
|
||||
},
|
||||
"QUALIFIER": {
|
||||
"color": "#FFC0CB"
|
||||
},
|
||||
"SZ": {
|
||||
"color": "#F44336"
|
||||
},
|
||||
"TW": {
|
||||
"color": "#D50000"
|
||||
},
|
||||
"S1": {
|
||||
"color": "#E5E4E2"
|
||||
},
|
||||
"S2": {
|
||||
"color": "#388E3C"
|
||||
},
|
||||
"SR": {
|
||||
"color": "#FBCEB1"
|
||||
},
|
||||
"CARDS": {
|
||||
"color": "#E4D00A"
|
||||
},
|
||||
"FULL_TOURNAMENT": {
|
||||
"color": "#FFC0CB"
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { Avatar } from "../../../components/Avatar";
|
||||
import * as React from "react";
|
||||
import { SubmitButton } from "../../../components/SubmitButton";
|
||||
import type { User } from "~/db/types";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { nanoid } from "nanoid";
|
||||
import clsx from "clsx";
|
||||
import { Button } from "../../../components/Button";
|
||||
|
||||
@@ -12,13 +12,11 @@ import {
|
||||
} from "~/utils/urls";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { LinksFunction } from "@remix-run/node";
|
||||
import styles from "~/styles/front.css";
|
||||
import styles from "~/styles/front.css?url";
|
||||
import { Link } from "@remix-run/react";
|
||||
import { GlobeIcon } from "~/components/icons/Globe";
|
||||
import { LanguageChanger } from "~/components/layout/LanguageChanger";
|
||||
import { Avatar } from "~/components/Avatar";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { languages } from "~/modules/i18n";
|
||||
import { Button } from "~/components/Button";
|
||||
import { LogOutIcon } from "~/components/icons/LogOut";
|
||||
import { LogInButtonContainer } from "~/components/layout/LogInButtonContainer";
|
||||
@@ -28,6 +26,8 @@ import { ThemeChanger } from "~/components/layout/ThemeChanger";
|
||||
import { SelectedThemeIcon } from "~/components/layout/SelectedThemeIcon";
|
||||
import { useRootLoaderData } from "~/hooks/useRootLoaderData";
|
||||
import { useTheme } from "~/features/theme/core/provider";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { languages } from "~/modules/i18n/config";
|
||||
|
||||
export const links: LinksFunction = () => {
|
||||
return [{ rel: "stylesheet", href: styles }];
|
||||
|
||||
@@ -17,7 +17,7 @@ import Compressor from "compressorjs";
|
||||
import invariant from "tiny-invariant";
|
||||
import { Button } from "~/components/Button";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { requireUser } from "~/features/auth/core";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
import { dateToDatabaseTimestamp } from "~/utils/dates";
|
||||
import { validate } from "~/utils/remix";
|
||||
import { teamPage } from "~/utils/urls";
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { MetaFunction } from "@remix-run/node";
|
||||
import { Trans } from "react-i18next";
|
||||
import { Main } from "~/components/Main";
|
||||
import { useSetTitle } from "~/hooks/useSetTitle";
|
||||
import { languages } from "~/modules/i18n";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
import {
|
||||
ANTARISKA_TWITTER,
|
||||
@@ -18,6 +17,7 @@ import {
|
||||
import { type SendouRouteHandle } from "~/utils/remix";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import * as React from "react";
|
||||
import { languages } from "~/modules/i18n/config";
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
return [{ title: makeTitle("Contributions") }];
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { LinksFunction, MetaFunction } from "@remix-run/node";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Main } from "~/components/Main";
|
||||
import { useSetTitle } from "~/hooks/useSetTitle";
|
||||
import styles from "~/styles/faq.css";
|
||||
import styles from "~/styles/faq.css?url";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
import { type SendouRouteHandle } from "~/utils/remix";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { LinksFunction, MetaFunction } from "@remix-run/node";
|
||||
import { Main } from "~/components/Main";
|
||||
import styles from "../support.css";
|
||||
import styles from "../support.css?url";
|
||||
import * as React from "react";
|
||||
import { CheckmarkIcon } from "~/components/icons/Checkmark";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
DEFAULT_LEADERBOARD_MAX_SIZE,
|
||||
MATCHES_COUNT_NEEDED_FOR_LEADERBOARD,
|
||||
} from "./leaderboards-constants";
|
||||
import { ordinalToSp } from "../mmr";
|
||||
import { ordinalToSp } from "../mmr/mmr-utils";
|
||||
|
||||
function addPowers<T extends { ordinal: number }>(entries: T[]) {
|
||||
return entries.map((entry) => ({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { sql } from "~/db/sql";
|
||||
import { MATCHES_COUNT_NEEDED_FOR_LEADERBOARD } from "../leaderboards-constants";
|
||||
import type { PlusTier, User } from "~/db/types";
|
||||
import { ordinalToSp } from "~/features/mmr";
|
||||
import { ordinalToSp } from "~/features/mmr/mmr-utils";
|
||||
|
||||
const stm = sql.prepare(/* sql */ `
|
||||
select
|
||||
|
||||
@@ -12,16 +12,15 @@ import { Avatar } from "~/components/Avatar";
|
||||
import { TierImage, WeaponImage } from "~/components/Image";
|
||||
import { Main } from "~/components/Main";
|
||||
import { HALF_HOUR_IN_MS } from "~/constants";
|
||||
import { getUser } from "~/features/auth/core";
|
||||
import { getUser } from "~/features/auth/core/user.server";
|
||||
import * as LeaderboardRepository from "~/features/leaderboards/LeaderboardRepository.server";
|
||||
import { ordinalToSp } from "~/features/mmr";
|
||||
import {
|
||||
allSeasons,
|
||||
currentOrPreviousSeason,
|
||||
currentSeason,
|
||||
} from "~/features/mmr/season";
|
||||
import type { SkillTierInterval } from "~/features/mmr/tiered.server";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import {
|
||||
weaponCategories,
|
||||
type MainWeaponId,
|
||||
@@ -40,7 +39,7 @@ import {
|
||||
userSeasonsPage,
|
||||
userSubmittedImage,
|
||||
} from "~/utils/urls";
|
||||
import styles from "../../top-search/top-search.css";
|
||||
import styles from "../../top-search/top-search.css?url";
|
||||
import { TopTenPlayer } from "../components/TopTenPlayer";
|
||||
import {
|
||||
cachedFullUserLeaderboard,
|
||||
@@ -59,6 +58,7 @@ import {
|
||||
weaponXPLeaderboard,
|
||||
type XPLeaderboardItem,
|
||||
} from "../queries/XPLeaderboard.server";
|
||||
import { ordinalToSp } from "~/features/mmr/mmr-utils";
|
||||
|
||||
export const handle: SendouRouteHandle = {
|
||||
i18n: ["vods"],
|
||||
|
||||
@@ -18,9 +18,9 @@ import { Toggle } from "~/components/Toggle";
|
||||
import type { CalendarEvent } from "~/db/types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getUserId } from "~/features/auth/core/user.server";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { stageIds, type ModeWithStage } from "~/modules/in-game-lists";
|
||||
import styles from "~/styles/maps.css";
|
||||
import styles from "~/styles/maps.css?url";
|
||||
import { type SendouRouteHandle } from "~/utils/remix";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
import {
|
||||
|
||||
@@ -4,7 +4,6 @@ import randomInt from "just-random-integer";
|
||||
import * as React from "react";
|
||||
import { usePlannerBg } from "~/hooks/usePlannerBg";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { LanguageCode } from "~/modules/i18n";
|
||||
import type { ModeShort, StageId } from "~/modules/in-game-lists";
|
||||
import {
|
||||
specialWeaponIds,
|
||||
@@ -27,6 +26,7 @@ import { Button } from "../../../components/Button";
|
||||
import { Image } from "../../../components/Image";
|
||||
import type { StageBackgroundStyle } from "../plans-types";
|
||||
import clsx from "clsx";
|
||||
import type { LanguageCode } from "~/modules/i18n/config";
|
||||
|
||||
export default function Planner() {
|
||||
const { t } = useTranslation(["common"]);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { lazy } from "react";
|
||||
import type { LinksFunction, MetaFunction } from "@remix-run/node";
|
||||
import styles from "../plans.css";
|
||||
import styles from "../plans.css?url";
|
||||
import type { SendouRouteHandle } from "~/utils/remix";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { navIconUrl, PLANNER_URL } from "~/utils/urls";
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
export {
|
||||
queryCurrentUserRating,
|
||||
queryCurrentTeamRating,
|
||||
} from "./mmr-utils.server";
|
||||
|
||||
export { rate, userIdsToIdentifier, ordinalToSp } from "./mmr-utils";
|
||||
|
||||
export { currentSeason } from "./season";
|
||||
@@ -9,12 +9,12 @@ import {
|
||||
specialFieldHp,
|
||||
subStats,
|
||||
hpDivided,
|
||||
weaponParams,
|
||||
type AbilityPoints,
|
||||
type SpecialWeaponParams,
|
||||
type SubWeaponParams,
|
||||
} from "~/features/build-analyzer";
|
||||
import type { HitPoints } from "../calculator-types";
|
||||
import { weaponParams } from "~/features/build-analyzer/core/weapon-params";
|
||||
|
||||
const WAVE_BREAKER_HP = 400;
|
||||
const SPRINKLER_HP = 120;
|
||||
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
} from "~/utils/urls";
|
||||
import { useObjectDamage } from "../calculator-hooks";
|
||||
import type { DamageReceiver } from "../calculator-types";
|
||||
import styles from "../calculator.css";
|
||||
import styles from "../calculator.css?url";
|
||||
|
||||
export const CURRENT_PATCH = "6.1";
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
nextNonCompletedVoting,
|
||||
rangeToMonthYear,
|
||||
} from "~/features/plus-voting/core";
|
||||
import { requireUser, useUser } from "~/features/auth/core";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
import {
|
||||
canAddCommentToSuggestionBE,
|
||||
canAddCommentToSuggestionFE,
|
||||
@@ -22,6 +22,7 @@ import { actualNumber, trimmedString } from "~/utils/zod";
|
||||
import type { PlusSuggestionsLoaderData } from "./plus.suggestions";
|
||||
import { CommentTextarea } from "./plus.suggestions.new";
|
||||
import * as PlusSuggestionRepository from "~/features/plus-suggestions/PlusSuggestionRepository.server";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
|
||||
const commentActionSchema = z.object({
|
||||
comment: z.preprocess(
|
||||
|
||||
@@ -32,11 +32,12 @@ import {
|
||||
import type { UserWithPlusTier } from "~/db/types";
|
||||
import { FormMessage } from "~/components/FormMessage";
|
||||
import { atOrError } from "~/utils/arrays";
|
||||
import { requireUser, useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { UserSearch } from "~/components/UserSearch";
|
||||
import * as PlusSuggestionRepository from "~/features/plus-suggestions/PlusSuggestionRepository.server";
|
||||
import * as UserRepository from "~/features/user-page/UserRepository.server";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
|
||||
const commentActionSchema = z.object({
|
||||
tier: z.preprocess(
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
} from "~/features/plus-voting/core";
|
||||
import type { PlusSuggestion, User } from "~/db/types";
|
||||
import * as PlusSuggestionRepository from "~/features/plus-suggestions/PlusSuggestionRepository.server";
|
||||
import { requireUser, useUser } from "~/features/auth/core";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
import {
|
||||
canAddCommentToSuggestionFE,
|
||||
canDeleteComment,
|
||||
@@ -35,6 +35,7 @@ import { makeTitle } from "~/utils/strings";
|
||||
import { assertUnreachable } from "~/utils/types";
|
||||
import { userPage } from "~/utils/urls";
|
||||
import { _action, actualNumber } from "~/utils/zod";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
return [
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { LinksFunction } from "@remix-run/node";
|
||||
import { Outlet } from "@remix-run/react";
|
||||
import { Main } from "~/components/Main";
|
||||
import { SubNav, SubNavLink } from "~/components/SubNav";
|
||||
import styles from "~/styles/plus.css";
|
||||
import styles from "~/styles/plus.css?url";
|
||||
import { type SendouRouteHandle } from "~/utils/remix";
|
||||
import { navIconUrl, plusSuggestionPage } from "~/utils/urls";
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ import clsx from "clsx";
|
||||
import invariant from "tiny-invariant";
|
||||
import type { UserWithPlusTier } from "~/db/types";
|
||||
import * as PlusVotingRepository from "~/features/plus-voting/PlusVotingRepository.server";
|
||||
import { getUser } from "~/features/auth/core";
|
||||
import { getUser } from "~/features/auth/core/user.server";
|
||||
import { lastCompletedVoting } from "~/features/plus-voting/core";
|
||||
import styles from "~/styles/plus-history.css";
|
||||
import styles from "~/styles/plus-history.css?url";
|
||||
import { roundToNDecimalPlaces } from "~/utils/number";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
import { PLUS_SERVER_DISCORD_URL, userPage } from "~/utils/urls";
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Button } from "~/components/Button";
|
||||
import { CheckmarkIcon } from "~/components/icons/Checkmark";
|
||||
import { RelativeTime } from "~/components/RelativeTime";
|
||||
import { PLUS_DOWNVOTE, PLUS_UPVOTE } from "~/constants";
|
||||
import { getUser, requireUser } from "~/features/auth/core";
|
||||
import { getUser, requireUser } from "~/features/auth/core/user.server";
|
||||
import type { PlusVoteFromFE } from "~/features/plus-voting/core";
|
||||
import {
|
||||
rangeToMonthYear,
|
||||
|
||||
@@ -48,7 +48,7 @@ import {
|
||||
SENDOUQ_WEAPON_POOL_MAX_SIZE,
|
||||
} from "../q-settings-constants";
|
||||
import { settingsActionSchema } from "../q-settings-schemas.server";
|
||||
import styles from "../q-settings.css";
|
||||
import styles from "../q-settings.css?url";
|
||||
|
||||
export const links: LinksFunction = () => {
|
||||
return [{ rel: "stylesheet", href: styles }];
|
||||
|
||||
@@ -5,7 +5,7 @@ import { twitchThumbnailUrlToSrc } from "~/modules/twitch/utils";
|
||||
import { FAQ_PAGE, sendouQMatchPage, twitchUrl, userPage } from "~/utils/urls";
|
||||
import { cachedStreams } from "../core/streams.server";
|
||||
import { Avatar } from "~/components/Avatar";
|
||||
import styles from "~/features/sendouq/q.css";
|
||||
import styles from "~/features/sendouq/q.css?url";
|
||||
import type { LinksFunction } from "@remix-run/node";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
|
||||
@@ -18,7 +18,7 @@ import { StarIcon } from "~/components/icons/Star";
|
||||
import { StarFilledIcon } from "~/components/icons/StarFilled";
|
||||
import { TrashIcon } from "~/components/icons/Trash";
|
||||
import type { GroupMember as GroupMemberType, ParsedMemento } from "~/db/types";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { MATCHES_COUNT_NEEDED_FOR_LEADERBOARD } from "~/features/leaderboards/leaderboards-constants";
|
||||
import { ordinalToRoundedSp } from "~/features/mmr/mmr-utils";
|
||||
import type { TieredSkill } from "~/features/mmr/tiered.server";
|
||||
|
||||
@@ -12,12 +12,14 @@ import type {
|
||||
import { MATCHES_COUNT_NEEDED_FOR_LEADERBOARD } from "~/features/leaderboards/leaderboards-constants";
|
||||
import {
|
||||
ordinalToSp,
|
||||
queryCurrentTeamRating,
|
||||
queryCurrentUserRating,
|
||||
rate,
|
||||
userIdsToIdentifier,
|
||||
} from "~/features/mmr";
|
||||
import { queryTeamPlayerRatingAverage } from "~/features/mmr/mmr-utils.server";
|
||||
} from "~/features/mmr/mmr-utils";
|
||||
import {
|
||||
queryCurrentTeamRating,
|
||||
queryCurrentUserRating,
|
||||
queryTeamPlayerRatingAverage,
|
||||
} from "~/features/mmr/mmr-utils.server";
|
||||
import { currentOrPreviousSeason } from "~/features/mmr/season";
|
||||
import { roundToNDecimalPlaces } from "~/utils/number";
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Image } from "~/components/Image";
|
||||
import { Main } from "~/components/Main";
|
||||
import { NewTabs } from "~/components/NewTabs";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { getUser, requireUser } from "~/features/auth/core/user.server";
|
||||
import * as NotificationService from "~/features/chat/NotificationService.server";
|
||||
import { Chat, useChat } from "~/features/chat/components/Chat";
|
||||
@@ -63,7 +63,7 @@ import { FULL_GROUP_SIZE } from "../q-constants";
|
||||
import { lookingSchema } from "../q-schemas.server";
|
||||
import type { LookingGroupWithInviteCode } from "../q-types";
|
||||
import { groupRedirectLocationByCurrentLocation } from "../q-utils";
|
||||
import styles from "../q.css";
|
||||
import styles from "../q.css?url";
|
||||
import { addLike } from "../queries/addLike.server";
|
||||
import { addManagerRole } from "../queries/addManagerRole.server";
|
||||
import { chatCodeByGroupId } from "../queries/chatCodeByGroupId.server";
|
||||
|
||||
@@ -35,11 +35,10 @@ import type { GroupMember, ReportedWeapon } from "~/db/types";
|
||||
import * as NotificationService from "~/features/chat/NotificationService.server";
|
||||
import type { ChatMessage } from "~/features/chat/chat-types";
|
||||
import { type ChatProps, Chat, useChat } from "~/features/chat/components/Chat";
|
||||
import { currentSeason } from "~/features/mmr";
|
||||
import { resolveRoomPass } from "~/features/tournament-bracket/tournament-bracket-utils";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { getUserId, requireUser } from "~/features/auth/core/user.server";
|
||||
import type { MainWeaponId } from "~/modules/in-game-lists";
|
||||
import { isMod } from "~/permissions";
|
||||
@@ -79,7 +78,7 @@ import {
|
||||
import { FULL_GROUP_SIZE, USER_SKILLS_CACHE_KEY } from "../q-constants";
|
||||
import { matchSchema } from "../q-schemas.server";
|
||||
import { matchIdFromParams, winnersArrayToWinner } from "../q-utils";
|
||||
import styles from "../q.css";
|
||||
import styles from "../q.css?url";
|
||||
import { addDummySkill } from "../queries/addDummySkill.server";
|
||||
import { addMapResults } from "../queries/addMapResults.server";
|
||||
import { addPlayerResults } from "../queries/addPlayerResults.server";
|
||||
@@ -106,6 +105,7 @@ import cachified from "@epic-web/cachified";
|
||||
import { refreshStreamsCache } from "~/features/sendouq-streams/core/streams.server";
|
||||
import { CrossIcon } from "~/components/icons/Cross";
|
||||
import { SPLATTERCOLOR_SCREEN_ID } from "~/modules/in-game-lists/weapon-ids";
|
||||
import { currentSeason } from "~/features/mmr/season";
|
||||
|
||||
export const meta: MetaFunction = (args) => {
|
||||
const data = args.data as SerializeFrom<typeof loader> | null;
|
||||
|
||||
@@ -11,7 +11,7 @@ import invariant from "tiny-invariant";
|
||||
import { Main } from "~/components/Main";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { getUser, requireUser } from "~/features/auth/core/user.server";
|
||||
import { currentSeason } from "~/features/mmr";
|
||||
import { currentSeason } from "~/features/mmr/season";
|
||||
import * as QMatchRepository from "~/features/sendouq-match/QMatchRepository.server";
|
||||
import { useAutoRefresh } from "~/hooks/useAutoRefresh";
|
||||
import type { SendouRouteHandle } from "~/utils/remix";
|
||||
@@ -30,7 +30,7 @@ import { hasGroupManagerPerms } from "../core/groups";
|
||||
import { FULL_GROUP_SIZE } from "../q-constants";
|
||||
import { preparingSchema } from "../q-schemas.server";
|
||||
import { groupRedirectLocationByCurrentLocation } from "../q-utils";
|
||||
import styles from "../q.css";
|
||||
import styles from "../q.css?url";
|
||||
import { addMember } from "../queries/addMember.server";
|
||||
import { findCurrentGroupByUserId } from "../queries/findCurrentGroupByUserId.server";
|
||||
import { findPreparingGroup } from "../queries/findPreparingGroup.server";
|
||||
|
||||
@@ -24,9 +24,9 @@ import { UserIcon } from "~/components/icons/User";
|
||||
import { UsersIcon } from "~/components/icons/Users";
|
||||
import { sql } from "~/db/sql";
|
||||
import type { GroupMember } from "~/db/types";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { getUserId, requireUserId } from "~/features/auth/core/user.server";
|
||||
import { currentSeason } from "~/features/mmr";
|
||||
import { currentSeason } from "~/features/mmr/season";
|
||||
import type { RankingSeason } from "~/features/mmr/season";
|
||||
import { nextSeason } from "~/features/mmr/season";
|
||||
import * as QRepository from "~/features/sendouq/QRepository.server";
|
||||
@@ -58,7 +58,7 @@ import {
|
||||
import { FULL_GROUP_SIZE, JOIN_CODE_SEARCH_PARAM_KEY } from "../q-constants";
|
||||
import { frontPageSchema } from "../q-schemas.server";
|
||||
import { groupRedirectLocationByCurrentLocation } from "../q-utils";
|
||||
import styles from "../q.css";
|
||||
import styles from "../q.css?url";
|
||||
import { addMember } from "../queries/addMember.server";
|
||||
import { deleteLikesByGroupId } from "../queries/deleteLikesByGroupId.server";
|
||||
import { findCurrentGroupByUserId } from "../queries/findCurrentGroupByUserId.server";
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useLoaderData } from "@remix-run/react";
|
||||
import { TierImage } from "~/components/Image";
|
||||
import { Main } from "~/components/Main";
|
||||
import { ordinalToSp } from "~/features/mmr";
|
||||
import {
|
||||
TEAM_LEADERBOARD_MIN_ENTRIES_FOR_LEVIATHAN,
|
||||
TIERS,
|
||||
@@ -11,6 +10,7 @@ import { currentOrPreviousSeason } from "~/features/mmr/season";
|
||||
import { userSkills } from "~/features/mmr/tiered.server";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { SendouRouteHandle } from "~/utils/remix";
|
||||
import { ordinalToSp } from "~/features/mmr/mmr-utils";
|
||||
|
||||
export const handle: SendouRouteHandle = {
|
||||
i18n: ["q"],
|
||||
|
||||
@@ -39,7 +39,7 @@ import { findByIdentifier } from "../queries/findByIdentifier.server";
|
||||
import { TEAM } from "../team-constants";
|
||||
import { editTeamSchema, teamParamsSchema } from "../team-schemas.server";
|
||||
import { canAddCustomizedColors, isTeamOwner } from "../team-utils";
|
||||
import styles from "../team.css";
|
||||
import styles from "../team.css?url";
|
||||
import { Input } from "~/components/Input";
|
||||
|
||||
export const links: LinksFunction = () => {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Main } from "~/components/Main";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { INVITE_CODE_LENGTH } from "~/constants";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { requireUser } from "~/features/auth/core";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
import {
|
||||
notFoundIfFalsy,
|
||||
validate,
|
||||
@@ -24,7 +24,7 @@ import type { DetailedTeam } from "../team-types";
|
||||
import { isTeamFull, isTeamMember } from "../team-utils";
|
||||
import * as UserRepository from "~/features/user-page/UserRepository.server";
|
||||
|
||||
import styles from "../team.css";
|
||||
import styles from "../team.css?url";
|
||||
|
||||
export const links: LinksFunction = () => {
|
||||
return [{ rel: "stylesheet", href: styles }];
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Main } from "~/components/Main";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { useBaseUrl } from "~/hooks/useBaseUrl";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { requireUserId } from "~/features/auth/core/user.server";
|
||||
import type { SendouRouteHandle } from "~/utils/remix";
|
||||
import { notFoundIfFalsy, parseRequestFormData, validate } from "~/utils/remix";
|
||||
@@ -39,7 +39,7 @@ import { TEAM_MEMBER_ROLES } from "../team-constants";
|
||||
import { manageRosterSchema, teamParamsSchema } from "../team-schemas.server";
|
||||
import type { DetailedTeamMember } from "../team-types";
|
||||
import { isTeamFull, isTeamOwner } from "../team-utils";
|
||||
import styles from "../team.css";
|
||||
import styles from "../team.css?url";
|
||||
|
||||
export const links: LinksFunction = () => {
|
||||
return [{ rel: "stylesheet", href: styles }];
|
||||
|
||||
@@ -19,7 +19,7 @@ import { WeaponImage } from "~/components/Image";
|
||||
import { Main } from "~/components/Main";
|
||||
import { Placement } from "~/components/Placement";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { requireUserId } from "~/features/auth/core/user.server";
|
||||
import {
|
||||
notFoundIfFalsy,
|
||||
@@ -46,7 +46,7 @@ import {
|
||||
isTeamMember,
|
||||
isTeamOwner,
|
||||
} from "../team-utils";
|
||||
import styles from "../team.css";
|
||||
import styles from "../team.css?url";
|
||||
|
||||
export const meta: MetaFunction<typeof loader> = ({ data }) => {
|
||||
if (!data) return [];
|
||||
|
||||
@@ -21,9 +21,9 @@ import { Input } from "~/components/Input";
|
||||
import { Main } from "~/components/Main";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { getUserId, requireUserId } from "~/features/auth/core/user.server";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { joinListToNaturalString } from "~/utils/arrays";
|
||||
import type { SendouRouteHandle } from "~/utils/remix";
|
||||
import { parseRequestFormData, validate } from "~/utils/remix";
|
||||
@@ -39,7 +39,7 @@ import { allTeams } from "../queries/allTeams.server";
|
||||
import { createNewTeam } from "../queries/createNewTeam.server";
|
||||
import { TEAM, TEAMS_PER_PAGE } from "../team-constants";
|
||||
import { createTeamSchema } from "../team-schemas.server";
|
||||
import styles from "../team.css";
|
||||
import styles from "../team.css?url";
|
||||
import { usePagination } from "~/hooks/usePagination";
|
||||
import { Pagination } from "~/components/Pagination";
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Main } from "~/components/Main";
|
||||
import { type SendouRouteHandle, notFoundIfFalsy } from "~/utils/remix";
|
||||
import { PlacementsTable } from "../components/Placements";
|
||||
import { findPlacementsByPlayerId } from "../queries/findPlacements.server";
|
||||
import styles from "../top-search.css";
|
||||
import styles from "../top-search.css?url";
|
||||
import { removeDuplicates } from "~/utils/arrays";
|
||||
import {
|
||||
navIconUrl,
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
topSearchPlayerPage,
|
||||
userPage,
|
||||
} from "~/utils/urls";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import type {
|
||||
import { useLoaderData, useSearchParams } from "@remix-run/react";
|
||||
import { Main } from "~/components/Main";
|
||||
import { findPlacementsOfMonth } from "../queries/findPlacements.server";
|
||||
import styles from "../top-search.css";
|
||||
import styles from "../top-search.css?url";
|
||||
import { PlacementsTable } from "../components/Placements";
|
||||
import { rankedModesShort } from "~/modules/in-game-lists/modes";
|
||||
import type { XRankPlacement } from "~/db/types";
|
||||
@@ -16,7 +16,7 @@ import { nanoid } from "nanoid";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import invariant from "tiny-invariant";
|
||||
import type { MonthYear } from "../top-search-utils";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
import { monthYears } from "../queries/monthYears";
|
||||
import type { SendouRouteHandle } from "~/utils/remix";
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import { Link, useFetcher } from "@remix-run/react";
|
||||
import { tournamentMatchPage, tournamentStreamsPage } from "~/utils/urls";
|
||||
import clsx from "clsx";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import type { Bracket } from "../../core/Bracket";
|
||||
import { Popover } from "~/components/Popover";
|
||||
import * as React from "react";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { InfoPopover } from "~/components/InfoPopover";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { LockIcon } from "~/components/icons/Lock";
|
||||
import { UnlockIcon } from "~/components/icons/Unlock";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { useTournament } from "~/features/tournament/routes/to.$id";
|
||||
|
||||
const lockingInfo =
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { Image } from "~/components/Image";
|
||||
import { NewTabs } from "~/components/NewTabs";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { useUser } from "~/features/auth/core";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { Chat, useChat } from "~/features/chat/components/Chat";
|
||||
import { useTournament } from "~/features/tournament/routes/to.$id";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
|
||||
@@ -9,7 +9,7 @@ import { removeDuplicates } from "~/utils/arrays";
|
||||
import { BRACKET_NAMES } from "~/features/tournament/tournament-constants";
|
||||
import { logger } from "~/utils/logger";
|
||||
import type { Round } from "~/modules/brackets-model";
|
||||
import { getTournamentManager } from "..";
|
||||
import { getTournamentManager } from "./brackets-manager";
|
||||
|
||||
interface CreateBracketArgs {
|
||||
id: number;
|
||||
@@ -93,7 +93,7 @@ export abstract class Bracket {
|
||||
return;
|
||||
|
||||
try {
|
||||
const manager = getTournamentManager("IN_MEMORY");
|
||||
const manager = getTournamentManager();
|
||||
|
||||
manager.import(this.data);
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Tournament } from "./Tournament";
|
||||
import { getTournamentManager } from "..";
|
||||
import * as TournamentRepository from "~/features/tournament/TournamentRepository.server";
|
||||
import { notFoundIfFalsy } from "~/utils/remix";
|
||||
import type { Unwrapped } from "~/utils/types";
|
||||
import { getServerTournamentManager } from "./brackets-manager/manager.server";
|
||||
|
||||
const manager = getTournamentManager("SQL");
|
||||
const manager = getServerTournamentManager();
|
||||
|
||||
export type TournamentData = Unwrapped<typeof tournamentData>;
|
||||
export type TournamentDataTeam = TournamentData["ctx"]["teams"][number];
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user