mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-03-21 18:04:39 -05:00
Maps page initial
This commit is contained in:
parent
36280db0b1
commit
87bca7aa44
|
|
@ -51,3 +51,4 @@ export type {
|
|||
SpecialWeaponId,
|
||||
} from "./types";
|
||||
export { isAbility } from "./utils";
|
||||
export { stageIds } from "./stage-ids";
|
||||
|
|
|
|||
15
app/modules/in-game-lists/stage-ids.ts
Normal file
15
app/modules/in-game-lists/stage-ids.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// when adding new stage id also create new language dicts via create-misc.json.ts
|
||||
export const stageIds = [
|
||||
0, // Scorch Gorge
|
||||
1, // Eeltail Alley
|
||||
2, // Hagglefish Market
|
||||
3, // Undertow Spillway
|
||||
4, // Mincemeat Metalworks
|
||||
5, // Hammerhead Bridge
|
||||
6, // Museum d'Alfonsino
|
||||
7, // Mahi-Mahi Resort
|
||||
8, // Inkblot Art Academy
|
||||
9, // Sturgeon Shipyard
|
||||
10, // MakoMart
|
||||
11, // Wahoo World
|
||||
] as const;
|
||||
55
app/routes/maps.tsx
Normal file
55
app/routes/maps.tsx
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import type { LinksFunction } from "@remix-run/node";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Image } from "~/components/Image";
|
||||
import { Main } from "~/components/Main";
|
||||
import { modes, stageIds } from "~/modules/in-game-lists";
|
||||
import styles from "~/styles/maps.css";
|
||||
import { modeImageUrl } from "~/utils/urls";
|
||||
|
||||
export const links: LinksFunction = () => {
|
||||
return [{ rel: "stylesheet", href: styles }];
|
||||
};
|
||||
|
||||
export const handle = {
|
||||
i18n: "game-misc",
|
||||
};
|
||||
|
||||
export default function MapListPage() {
|
||||
return (
|
||||
<Main halfWidth>
|
||||
<MapPoolSelector />
|
||||
</Main>
|
||||
);
|
||||
}
|
||||
|
||||
function MapPoolSelector() {
|
||||
const { t } = useTranslation(["game-misc"]);
|
||||
|
||||
return (
|
||||
<div className="stack md">
|
||||
{stageIds.map((stageId) => (
|
||||
<div key={stageId} className="maps__stage-row">
|
||||
<div>{t(`game-misc:STAGE_${stageId}`)}</div>
|
||||
<div className="stack horizontal sm">
|
||||
{modes
|
||||
.filter((mode) => mode.short !== "TW")
|
||||
.map((mode) => (
|
||||
<button
|
||||
key={mode.short}
|
||||
className="maps__mode-button outline-theme"
|
||||
type="button"
|
||||
>
|
||||
<Image
|
||||
alt={mode.long}
|
||||
path={modeImageUrl(mode.short)}
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
22
app/styles/maps.css
Normal file
22
app/styles/maps.css
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
.maps__stage-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: var(--bg-lighter);
|
||||
border-radius: var(--rounded);
|
||||
font-size: var(--fonts-xs);
|
||||
font-weight: var(--semi-bold);
|
||||
gap: var(--s-0-5);
|
||||
padding-block: var(--s-1-5);
|
||||
padding-inline: var(--s-3);
|
||||
}
|
||||
|
||||
.maps__mode-button {
|
||||
padding: 0;
|
||||
padding: var(--s-1-5);
|
||||
border: none;
|
||||
background-color: var(--bg-darker);
|
||||
border-radius: var(--rounded);
|
||||
color: var(--theme);
|
||||
outline: initial;
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
"rename-badge": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/rename-badge.ts",
|
||||
"create-weapon-json": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/create-weapon-json.ts",
|
||||
"create-gear-json": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/create-gear-json.ts",
|
||||
"create-misc-json": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/create-misc-json.ts",
|
||||
"create-analyzer-json": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/create-analyzer-json.ts",
|
||||
"check-translation-jsons": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/check-translation-jsons.ts && npm run prettier:write",
|
||||
"replace-img-names": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/replace-img-names.ts",
|
||||
|
|
|
|||
14
public/locales/da/game-misc.json
Normal file
14
public/locales/da/game-misc.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"STAGE_0": "Scorch Gorge",
|
||||
"STAGE_1": "Eeltail Alley",
|
||||
"STAGE_2": "Hagglefish Market",
|
||||
"STAGE_3": "Undertow Spillway",
|
||||
"STAGE_4": "Mincemeat Metalworks",
|
||||
"STAGE_5": "Hammerhead Bridge",
|
||||
"STAGE_6": "Museum d'Alfonsino",
|
||||
"STAGE_7": "Mahi-Mahi Resort",
|
||||
"STAGE_8": "Inkblot Art Academy",
|
||||
"STAGE_9": "Sturgeon Shipyard",
|
||||
"STAGE_10": "MakoMart",
|
||||
"STAGE_11": "Wahoo World"
|
||||
}
|
||||
14
public/locales/de/game-misc.json
Normal file
14
public/locales/de/game-misc.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"STAGE_0": "Sengkluft",
|
||||
"STAGE_1": "Streifenaal-Straße",
|
||||
"STAGE_2": "Schnapperchen-Basar",
|
||||
"STAGE_3": "Schwertmuschel-Reservoir",
|
||||
"STAGE_4": "Aalstahl-Metallwerk",
|
||||
"STAGE_5": "Makrelenbrücke",
|
||||
"STAGE_6": "Pinakoithek",
|
||||
"STAGE_7": "Mahi-Mahi-Resort",
|
||||
"STAGE_8": "Perlmutt-Akademie",
|
||||
"STAGE_9": "Störwerft",
|
||||
"STAGE_10": "Cetacea-Markt",
|
||||
"STAGE_11": "Flunder-Funpark"
|
||||
}
|
||||
14
public/locales/en/game-misc.json
Normal file
14
public/locales/en/game-misc.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"STAGE_0": "Scorch Gorge",
|
||||
"STAGE_1": "Eeltail Alley",
|
||||
"STAGE_2": "Hagglefish Market",
|
||||
"STAGE_3": "Undertow Spillway",
|
||||
"STAGE_4": "Mincemeat Metalworks",
|
||||
"STAGE_5": "Hammerhead Bridge",
|
||||
"STAGE_6": "Museum d'Alfonsino",
|
||||
"STAGE_7": "Mahi-Mahi Resort",
|
||||
"STAGE_8": "Inkblot Art Academy",
|
||||
"STAGE_9": "Sturgeon Shipyard",
|
||||
"STAGE_10": "MakoMart",
|
||||
"STAGE_11": "Wahoo World"
|
||||
}
|
||||
14
public/locales/es/game-misc.json
Normal file
14
public/locales/es/game-misc.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"STAGE_0": "Desfiladero Fumarola",
|
||||
"STAGE_1": "Callejones Crustáceo",
|
||||
"STAGE_2": "Mercado Lenguado",
|
||||
"STAGE_3": "Cisterna Navajuela",
|
||||
"STAGE_4": "Desguace Mero",
|
||||
"STAGE_5": "Puente Salmón",
|
||||
"STAGE_6": "Museo del Pargo",
|
||||
"STAGE_7": "Spa Cala Bacalao",
|
||||
"STAGE_8": "Instituto Coralino",
|
||||
"STAGE_9": "Astillero Beluga",
|
||||
"STAGE_10": "Ultramarinos Orca",
|
||||
"STAGE_11": "Pirañalandia"
|
||||
}
|
||||
14
public/locales/fr/game-misc.json
Normal file
14
public/locales/fr/game-misc.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"STAGE_0": "Canyon aux colonnes",
|
||||
"STAGE_1": "Banlieue Balibot",
|
||||
"STAGE_2": "Marché Grefin",
|
||||
"STAGE_3": "Réservoir Rigadelle",
|
||||
"STAGE_4": "Casse Rascasse",
|
||||
"STAGE_5": "Pont Esturgeon",
|
||||
"STAGE_6": "Galeries Guppy",
|
||||
"STAGE_7": "Club Ca$halot",
|
||||
"STAGE_8": "Institut Calam'arts",
|
||||
"STAGE_9": "Chantier Narval",
|
||||
"STAGE_10": "Supermarché Cétacé",
|
||||
"STAGE_11": "Parc Carapince"
|
||||
}
|
||||
14
public/locales/it/game-misc.json
Normal file
14
public/locales/it/game-misc.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"STAGE_0": "Grank Canyon",
|
||||
"STAGE_1": "Sobborgo Siluriano",
|
||||
"STAGE_2": "Mercato Fruttato",
|
||||
"STAGE_3": "Cisterna Cernia",
|
||||
"STAGE_4": "Discarica Tritatutto",
|
||||
"STAGE_5": "Ponte Sgombro",
|
||||
"STAGE_6": "Museo di Cefalò",
|
||||
"STAGE_7": "Villanguilla",
|
||||
"STAGE_8": "Campus Hippocampus",
|
||||
"STAGE_9": "Cantiere Pinnenere",
|
||||
"STAGE_10": "Mercatotano",
|
||||
"STAGE_11": "Soglioland"
|
||||
}
|
||||
14
public/locales/ja/game-misc.json
Normal file
14
public/locales/ja/game-misc.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"STAGE_0": "ユノハナ大渓谷",
|
||||
"STAGE_1": "ゴンズイ地区",
|
||||
"STAGE_2": "ヤガラ市場",
|
||||
"STAGE_3": "マテガイ放水路",
|
||||
"STAGE_4": "ナメロウ金属",
|
||||
"STAGE_5": "マサバ海峡大橋",
|
||||
"STAGE_6": "キンメダイ美術館",
|
||||
"STAGE_7": "マヒマヒリゾート&スパ",
|
||||
"STAGE_8": "海女美術大学",
|
||||
"STAGE_9": "チョウザメ造船",
|
||||
"STAGE_10": "ザトウマーケット",
|
||||
"STAGE_11": "スメーシーワールド"
|
||||
}
|
||||
14
public/locales/ko/game-misc.json
Normal file
14
public/locales/ko/game-misc.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"STAGE_0": "석순 대협곡",
|
||||
"STAGE_1": "메기 지구",
|
||||
"STAGE_2": "대치 시장",
|
||||
"STAGE_3": "맛조개 방수로",
|
||||
"STAGE_4": "나메로우 금속",
|
||||
"STAGE_5": "고등어 해협 대교",
|
||||
"STAGE_6": "도미 미술관",
|
||||
"STAGE_7": "만새기 리조트&스파",
|
||||
"STAGE_8": "해녀 미술 대학",
|
||||
"STAGE_9": "철갑상어 조선소",
|
||||
"STAGE_10": "혹등 마켓",
|
||||
"STAGE_11": "초밥 월드"
|
||||
}
|
||||
14
public/locales/nl/game-misc.json
Normal file
14
public/locales/nl/game-misc.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"STAGE_0": "Roggentrog",
|
||||
"STAGE_1": "Forelviaduct",
|
||||
"STAGE_2": "Boter-bij-de-vismarkt",
|
||||
"STAGE_3": "Baarsreservoir",
|
||||
"STAGE_4": "Zilversmelt-hoogovens",
|
||||
"STAGE_5": "Brandingbrug",
|
||||
"STAGE_6": "Galerie Le Guppy",
|
||||
"STAGE_7": "El Dorade-resort",
|
||||
"STAGE_8": "Koraalcampus",
|
||||
"STAGE_9": "Walruswerf",
|
||||
"STAGE_10": "Bultrugbazaar",
|
||||
"STAGE_11": "Waterwonderland"
|
||||
}
|
||||
14
public/locales/ru/game-misc.json
Normal file
14
public/locales/ru/game-misc.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"STAGE_0": "Опаленное ущелье",
|
||||
"STAGE_1": "Угрево-Скатово",
|
||||
"STAGE_2": "Рынок «Свисторыб»",
|
||||
"STAGE_3": "Приливослив",
|
||||
"STAGE_4": "Цех «Тартар»",
|
||||
"STAGE_5": "Акулий мост",
|
||||
"STAGE_6": "Галерея «Де Берикс»",
|
||||
"STAGE_7": "Спа-курорт «Золотая рыбка»",
|
||||
"STAGE_8": "Академия «Лепота»",
|
||||
"STAGE_9": "Осетровые верфи",
|
||||
"STAGE_10": "«Горбуша-Маркет»",
|
||||
"STAGE_11": "Луна-парк «Язь»"
|
||||
}
|
||||
14
public/locales/zh/game-misc.json
Normal file
14
public/locales/zh/game-misc.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"STAGE_0": "温泉花大峡谷",
|
||||
"STAGE_1": "鳗鲶区",
|
||||
"STAGE_2": "烟管鱼市场",
|
||||
"STAGE_3": "竹蛏疏洪道",
|
||||
"STAGE_4": "鱼肉碎金属",
|
||||
"STAGE_5": "真鲭跨海大桥",
|
||||
"STAGE_6": "金眼鲷美术馆",
|
||||
"STAGE_7": "鬼头刀SPA度假区",
|
||||
"STAGE_8": "海女美术大学",
|
||||
"STAGE_9": "鲟鱼造船厂",
|
||||
"STAGE_10": "座头购物中心",
|
||||
"STAGE_11": "醋饭海洋世界"
|
||||
}
|
||||
69
scripts/create-misc-json.ts
Normal file
69
scripts/create-misc-json.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import { LANG_JSONS_TO_CREATE, loadLangDicts } from "./utils";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
// ⚠️ keep same order as https://github.com/IPLSplatoon/IPLMapGen2/blob/splat3/data.js
|
||||
const stages = [
|
||||
"Scorch Gorge",
|
||||
"Eeltail Alley",
|
||||
"Hagglefish Market",
|
||||
"Undertow Spillway",
|
||||
"Mincemeat Metalworks",
|
||||
"Hammerhead Bridge",
|
||||
"Museum d'Alfonsino",
|
||||
"Mahi-Mahi Resort",
|
||||
"Inkblot Art Academy",
|
||||
"Sturgeon Shipyard",
|
||||
"MakoMart",
|
||||
"Wahoo World",
|
||||
] as const;
|
||||
|
||||
async function main() {
|
||||
const langDicts = await loadLangDicts();
|
||||
|
||||
const englishLangDict = langDicts.find(
|
||||
([langCode]) => langCode === "EUen"
|
||||
)?.[1];
|
||||
invariant(englishLangDict);
|
||||
|
||||
const codeNames = stages.map((stage) => {
|
||||
const codeName = Object.entries(
|
||||
englishLangDict["CommonMsg/VS/VSStageName"]
|
||||
).find(([_key, value]) => value === stage)?.[0];
|
||||
|
||||
invariant(codeName, `Could not find code name for stage ${stage}`);
|
||||
|
||||
return codeName;
|
||||
});
|
||||
|
||||
for (const langCode of LANG_JSONS_TO_CREATE) {
|
||||
const langDict = langDicts.find(([code]) => code === langCode)?.[1];
|
||||
invariant(langDict, `Missing translations for ${langCode}`);
|
||||
|
||||
const translationsMap = Object.fromEntries(
|
||||
stages.map((_, i) => {
|
||||
const codeName = codeNames[
|
||||
i
|
||||
] as keyof typeof langDict["CommonMsg/VS/VSStageName"];
|
||||
invariant(codeName);
|
||||
|
||||
return [`STAGE_${i}`, langDict["CommonMsg/VS/VSStageName"][codeName]];
|
||||
})
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"public",
|
||||
"locales",
|
||||
langCode.slice(2),
|
||||
`game-misc.json`
|
||||
),
|
||||
JSON.stringify(translationsMap, null, 2) + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void main();
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
import type euEn from "./dicts/langs/EUen.json";
|
||||
|
||||
const LANG_DICTS_PATH = path.join(__dirname, "dicts", "langs");
|
||||
|
||||
|
|
@ -17,9 +18,7 @@ export const LANG_JSONS_TO_CREATE = [
|
|||
];
|
||||
|
||||
export async function loadLangDicts() {
|
||||
const result: Array<
|
||||
[langCode: string, translations: Record<string, Record<string, string>>]
|
||||
> = [];
|
||||
const result: Array<[langCode: string, translations: typeof euEn]> = [];
|
||||
|
||||
const files = await fs.promises.readdir(LANG_DICTS_PATH);
|
||||
for (const file of files) {
|
||||
|
|
|
|||
2
types/react-i18next.d.ts
vendored
2
types/react-i18next.d.ts
vendored
|
|
@ -11,6 +11,7 @@ import type weapons from "../public/locales/en/weapons.json";
|
|||
import type gear from "../public/locales/en/gear.json";
|
||||
import type builds from "../public/locales/en/builds.json";
|
||||
import type analyzer from "../public/locales/en/analyzer.json";
|
||||
import type gameMisc from "../public/locales/en/game-misc.json";
|
||||
|
||||
declare module "react-i18next" {
|
||||
interface CustomTypeOptions {
|
||||
|
|
@ -27,6 +28,7 @@ declare module "react-i18next" {
|
|||
gear: typeof gear;
|
||||
builds: typeof builds;
|
||||
analyzer: typeof analyzer;
|
||||
"game-misc": typeof gameMisc;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user