From 7ac6902876113d3aa02cbb877324b0187c7c9f02 Mon Sep 17 00:00:00 2001 From: "Rong \"Mantle\" Bao" Date: Sat, 8 Jul 2023 09:46:45 +0800 Subject: [PATCH] feat: add nav to settings --- src/common/__tests__/queryPath.test.ts | 71 ++++++++++++++++++++++++++ src/common/index.ts | 2 + src/common/queryPath.ts | 29 +++++++++++ src/i18n/locales/en/index.json | 2 +- src/i18n/locales/en/settings.json | 4 ++ src/i18n/locales/zh/index.json | 2 +- src/i18n/locales/zh/settings.json | 4 ++ src/pages/index.tsx | 11 ++-- src/pages/settings.tsx | 49 +++++++++++++++++- 9 files changed, 163 insertions(+), 11 deletions(-) create mode 100644 src/common/__tests__/queryPath.test.ts create mode 100644 src/common/queryPath.ts diff --git a/src/common/__tests__/queryPath.test.ts b/src/common/__tests__/queryPath.test.ts new file mode 100644 index 0000000..a5b2c8f --- /dev/null +++ b/src/common/__tests__/queryPath.test.ts @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021-present Rong "Mantle" Bao + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/ . + */ + +import { queryPath } from "../queryPath" + +describe("queryPath", () => { + it("should get correct path by ID", () => { + const routes = [ + { + path: "/path_2", + id: 2, + }, + { + path: "/path_1", + id: 1, + }, + ] as const + const result = queryPath(routes, 1) + expect(result).toStrictEqual("/path_1") + }) + + it("should return first match if multiple entries have the same ID", () => { + const routes = [ + { + path: "/path_0", + id: 0, + }, + { + path: "/path_1_1", + id: 1, + }, + { + path: "/path_2", + id: 2, + }, + { + path: "/path_1_2", + id: 1, + }, + ] as const + const result = queryPath(routes, 1) + expect(result).toStrictEqual("/path_1_1") + }) + + it("should handle erroneous inputs gracefully", () => { + const routes = [ + { + path: null, + id: 1, + }, + ] as const + expect(queryPath(null, 1)).toStrictEqual("#") + expect(queryPath(undefined, 1)).toStrictEqual("#") + expect(queryPath([], 1)).toStrictEqual("#") + expect(queryPath(routes, 1)).toStrictEqual("#") + }) +}) diff --git a/src/common/index.ts b/src/common/index.ts index 8adf64b..78845c4 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -31,6 +31,7 @@ import { import { flushed } from "./flushed" import { formatDuration } from "./formatDuration" import { isNil } from "./isNil" +import { queryPath } from "./queryPath" import { rearrange } from "./rearrange" import { waitForEvent } from "./waitForEvent" @@ -54,5 +55,6 @@ export { waitForEvent, isNil, formatDuration, + queryPath, } export type { ISize, TPosition } diff --git a/src/common/queryPath.ts b/src/common/queryPath.ts new file mode 100644 index 0000000..58680e4 --- /dev/null +++ b/src/common/queryPath.ts @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021-present Rong "Mantle" Bao + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/ . + */ + +import { filter, head } from "lodash" + +export type TRoute = { + readonly id: number | null + readonly path: string | null +} | null + +export type TRoutes = readonly TRoute[] | null | undefined + +export function queryPath(routes: TRoutes, id: number): string { + return head(filter(routes, (r) => r?.id === id))?.path ?? "#" +} diff --git a/src/i18n/locales/en/index.json b/src/i18n/locales/en/index.json index dcef92f..a04e8cb 100644 --- a/src/i18n/locales/en/index.json +++ b/src/i18n/locales/en/index.json @@ -1,5 +1,5 @@ { - "cap_start": "START", + "cap_start": "START GAME", "typ_version": "Version {{version}}", "cap_settings": "Settings", "cap_about": "About", diff --git a/src/i18n/locales/en/settings.json b/src/i18n/locales/en/settings.json index d66ecb0..5434c16 100644 --- a/src/i18n/locales/en/settings.json +++ b/src/i18n/locales/en/settings.json @@ -1,4 +1,8 @@ { + "typ_h_settings": "Settings", + "cap_home": "Home", + "cap_game": "Start game", + "typ_helper_save": "All changes made on this page will be saved immediately to local storage.", "cap_open_button": "Open file...", "msg_color_scheme_invalid": "Invalid color scheme file. Please check your file format.", "msg_game_map_invalid": "Invalid game map file. Please check your file format.", diff --git a/src/i18n/locales/zh/index.json b/src/i18n/locales/zh/index.json index ad2a529..d868865 100644 --- a/src/i18n/locales/zh/index.json +++ b/src/i18n/locales/zh/index.json @@ -1,5 +1,5 @@ { - "cap_start": "开始", + "cap_start": "开始游戏", "typ_version": "版本 {{version}}", "cap_settings": "设置", "cap_about": "关于", diff --git a/src/i18n/locales/zh/settings.json b/src/i18n/locales/zh/settings.json index c12d8aa..060f11f 100644 --- a/src/i18n/locales/zh/settings.json +++ b/src/i18n/locales/zh/settings.json @@ -1,4 +1,8 @@ { + "typ_h_settings": "设置", + "cap_home": "主页", + "cap_game": "开始游戏", + "typ_helper_save": "本页面上的更改会实时保存至本地存储。", "cap_open_button": "打开文件...", "msg_color_scheme_invalid": "选择的主题文件无效。请检查格式。", "msg_game_map_invalid": "选择的布局文件无效。请检查格式。", diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 446838d..6ba988d 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -17,7 +17,6 @@ import { graphql, Link, PageProps } from "gatsby" import { useI18next } from "gatsby-plugin-react-i18next" -import { filter, head } from "lodash" import React from "react" import FavoriteIcon from "@mui/icons-material/Favorite" @@ -32,17 +31,15 @@ import Stack from "@mui/material/Stack" import Tooltip from "@mui/material/Tooltip" import Typography from "@mui/material/Typography" +import { queryPath } from "../common" import { CommonHead } from "../components" import { PageID } from "../PageID" const App = ({ data }: PageProps) => { const routes = data.site?.siteMetadata?.navRoutes - const gamePagePath = - head(filter(routes, (r) => r?.id === PageID.PAGE_GAME))?.path ?? "#" - const settingsPagePath = - head(filter(routes, (r) => r?.id === PageID.PAGE_SETTINGS))?.path ?? "#" - const aboutPagePath = - head(filter(routes, (r) => r?.id === PageID.PAGE_ABOUT))?.path ?? "#" + const gamePagePath = queryPath(routes, PageID.PAGE_GAME) + const settingsPagePath = queryPath(routes, PageID.PAGE_SETTINGS) + const aboutPagePath = queryPath(routes, PageID.PAGE_ABOUT) const { t } = useI18next() diff --git a/src/pages/settings.tsx b/src/pages/settings.tsx index 849f2ba..8800eaf 100644 --- a/src/pages/settings.tsx +++ b/src/pages/settings.tsx @@ -19,11 +19,13 @@ import validateColorScheme from "ajv-json-loader!../json/schema/ColorScheme.json import validateMap from "ajv-json-loader!../json/schema/Map.json.schema" import FileSaver from "file-saver" -import { graphql } from "gatsby" +import { Link, PageProps, graphql } from "gatsby" import { useI18next } from "gatsby-plugin-react-i18next" import { useSnackbar } from "notistack" import React from "react" +import HomeIcon from "@mui/icons-material/Home" +import PlayArrowIcon from "@mui/icons-material/PlayArrow" import Button from "@mui/material/Button" import Container from "@mui/material/Container" import FormControl from "@mui/material/FormControl" @@ -34,6 +36,9 @@ import Stack from "@mui/material/Stack" import TextField from "@mui/material/TextField" import Typography from "@mui/material/Typography" +import { IconButton, Tooltip } from "@mui/material" +import { PageID } from "../PageID" +import { queryPath } from "../common" import { CommonHead, FileFormControl, NumberFormControl } from "../components" import { customizationFacade } from "../customization" @@ -42,9 +47,13 @@ const tryParseInt = (s: string): readonly [boolean, number] => { return [!isNaN(v), v] } -const App = () => { +const App = ({ data }: PageProps) => { const { t, changeLanguage, languages, language } = useI18next() + const routes = data.site?.siteMetadata?.navRoutes + const homePagePath = queryPath(routes, PageID.PAGE_HOME) + const gamePagePath = queryPath(routes, PageID.PAGE_GAME) + const assistanceGridAppearanceOptions = [ { value: "visible", @@ -78,6 +87,34 @@ const App = () => { }} > + + + + + + + {t("typ_h_settings")} + + + + + + + {t("typ_helper_save")}