diff --git a/src/backend/electron-api.ts b/src/backend/electron-api.ts index e22d826..90d09ee 100644 --- a/src/backend/electron-api.ts +++ b/src/backend/electron-api.ts @@ -102,7 +102,8 @@ export const electronAPI: Omit< await downloadToFolder( gameState.archiveURL, customPath.filePaths[0], - `${gameState.name}-archive.zip` + `${gameState.name}-archive.zip`, + true ); return { data: null }; diff --git a/src/backend/fs/downloadToFolder.ts b/src/backend/fs/downloadToFolder.ts index 71b487a..7d7a3c6 100644 --- a/src/backend/fs/downloadToFolder.ts +++ b/src/backend/fs/downloadToFolder.ts @@ -4,7 +4,8 @@ import electronDl from "electron-dl"; export async function downloadToFolder( sourceURL: string, targetFolder: string, - targetFilename: string + targetFilename: string, + openFolderWhenDone?: boolean ): Promise { const win = BrowserWindow.getAllWindows(); if (!win.length) { @@ -16,5 +17,6 @@ export async function downloadToFolder( directory: targetFolder, filename: targetFilename, overwrite: true, + openFolderWhenDone: openFolderWhenDone, }); } diff --git a/src/client/api/CommonParametersAPI.ts b/src/client/api/CommonParametersAPI.ts index 30529c6..8420003 100644 --- a/src/client/api/CommonParametersAPI.ts +++ b/src/client/api/CommonParametersAPI.ts @@ -7,7 +7,7 @@ type CommonParameterFromServer = { id: number; label: string; description: string; - gameStateParameterTypeDTO: { + type: { id: string; type: string; }; @@ -30,15 +30,7 @@ export class CommonParametersAPI implements ICommonParametersAPI { ); return { - items: parameters.items.map((parameter) => ({ - id: parameter.id.toString(), - label: parameter.label, - description: parameter.description, - type: { - id: parameter.gameStateParameterTypeDTO.id.toString(), - type: parameter.gameStateParameterTypeDTO.type, - }, - })), + items: parameters.items.map(this.mapToCommonParameter), totalCount: parameters.totalCount, }; }; @@ -48,51 +40,54 @@ export class CommonParametersAPI implements ICommonParametersAPI { `/common-parameters/${parameterId}` ); - return { - id: parameter.id.toString(), - label: parameter.label, - description: parameter.description, - type: { - id: parameter.gameStateParameterTypeDTO.id.toString(), - type: parameter.gameStateParameterTypeDTO.type, - }, - }; + return this.mapToCommonParameter(parameter); }; + private mapToCommonParameter = ( + parameter: CommonParameterFromServer + ): CommonParameter => ({ + id: parameter.id.toString(), + label: parameter.label, + description: parameter.description, + type: { + id: parameter.type.id.toString(), + type: parameter.type.type, + }, + }); + createParameter = async ( parameter: CommonParameter ): Promise => { - const formData = new FormData(); - formData.append( - "commonParameterData", - JSON.stringify({ - label: parameter.label, - description: parameter.description, - gameStateParameterTypeId: parameter.type.id, - }) - ); - - const createdParameter = await this.fetcher.post( + const formData = this.mapToFormData(parameter); + const created = await this.fetcher.post( "/common-parameters", { headers: {}, body: formData, } ); - return { - id: createdParameter.id.toString(), - label: createdParameter.label, - description: createdParameter.description, - type: { - id: parameter.type.id.toString(), - type: parameter.type.type, - }, - }; + return this.mapToCommonParameter(created); }; updateParameter = async ( parameter: CommonParameter ): Promise => { + const formData = this.mapToFormData(parameter); + const updated = await this.fetcher.patch( + `/common-parameters/${parameter.id}`, + { + headers: {}, + body: formData, + } + ); + return this.mapToCommonParameter(updated); + }; + + deleteParameter = async (parameterId: string): Promise => { + await this.fetcher.delete(`/common-parameters/${parameterId}`); + }; + + private mapToFormData(parameter: CommonParameter) { const formData = new FormData(); formData.append( "commonParameterData", @@ -102,28 +97,6 @@ export class CommonParametersAPI implements ICommonParametersAPI { gameStateParameterTypeId: parameter.type.id, }) ); - - const updatedParameter = - await this.fetcher.patch( - `/common-parameters/${parameter.id}`, - { - headers: {}, - body: formData, - } - ); - - return { - id: updatedParameter.id.toString(), - label: updatedParameter.label, - description: updatedParameter.description, - type: { - id: parameter.type.id.toString(), - type: parameter.type.type, - }, - }; - }; - - deleteParameter = async (parameterId: string): Promise => { - await this.fetcher.delete(`/common-parameters/${parameterId}`); - }; + return formData; + } } diff --git a/src/client/api/GameAPI.ts b/src/client/api/GameAPI.ts index a4fc32b..55a8fbd 100644 --- a/src/client/api/GameAPI.ts +++ b/src/client/api/GameAPI.ts @@ -21,9 +21,9 @@ export type GameFromServer = { type: string; label: string; description: string; - commonParameterDTO: { + commonParameter: { id: number; - gameStateParameterTypeDTO: { + type: { id: number; type: string; }; @@ -44,7 +44,6 @@ export class GameAPI implements IGameAPI { getGame = async (gameId: string): Promise => { const game = await this.fetcher.get(`/games/${gameId}`); - return GameAPI.mapGameFromServer(game); }; @@ -65,35 +64,7 @@ export class GameAPI implements IGameAPI { }; addGame = (game: AddGameDTO): Promise => { - const formData = new FormData(); - - formData.append("image", game.icon || new Blob()); - formData.append( - "gameData", - JSON.stringify({ - name: game.name, - description: game.description, - paths: game.paths, - extractionPipeline: game.extractionPipeline, - schema: { - filename: game.gameStateParameters.filename, - gameStateParameters: game.gameStateParameters.parameters.map( - (field) => ({ - key: field.key, - type: field.type.type, - commonParameterDTO: field.commonParameter.id - ? { - id: field.commonParameter.id, - } - : undefined, - label: field.label, - description: field.description, - }) - ), - }, - }) - ); - + const formData = this.mapToFormData(game); return this.fetcher.post("/games", { headers: {}, body: formData, @@ -101,31 +72,35 @@ export class GameAPI implements IGameAPI { }; updateGame = (game: UpdateGameDTO): Promise => { - const formData = new FormData(); + const formData = this.mapToFormData(game); + return this.fetcher.patch(`/games/${game.id}`, { + headers: {}, + body: formData, + }); + }; - // if (game.icon) { - formData.append("image", game.icon || ""); - // } + deleteGame = (gameId: string): Promise => { + return this.fetcher.delete(`/games/${gameId}`); + }; + private mapToFormData(addGameDTO: AddGameDTO) { + const formData = new FormData(); + formData.append("image", addGameDTO.icon || ""); formData.append( "gameData", JSON.stringify({ - name: game.name, - description: game.description, - paths: game.paths, - extractionPipeline: game.extractionPipeline, + name: addGameDTO.name, + description: addGameDTO.description, + paths: addGameDTO.paths, + extractionPipeline: addGameDTO.extractionPipeline, schema: { - filename: game.gameStateParameters.filename, - gameStateParameters: game.gameStateParameters.parameters.map( + filename: addGameDTO.gameStateParameters.filename, + gameStateParameters: addGameDTO.gameStateParameters.parameters.map( (field) => ({ id: field.id, key: field.key, type: field.type.type, - commonParameterDTO: field.commonParameter.id - ? { - id: field.commonParameter.id, - } - : undefined, + commonParameterId: field.commonParameter.id, label: field.label, description: field.description, }) @@ -133,16 +108,8 @@ export class GameAPI implements IGameAPI { }, }) ); - - return this.fetcher.patch(`/games/${game.id}`, { - headers: {}, - body: formData, - }); - }; - - deleteGame = (gameId: string): Promise => { - return this.fetcher.delete(`/games/${gameId}`); - }; + return formData; + } static mapGameFromServer = (game: GameFromServer): Game => { return { @@ -160,15 +127,15 @@ export class GameAPI implements IGameAPI { type: field.type, id: field.type, }, - commonParameter: field.commonParameterDTO + commonParameter: field.commonParameter ? { - id: field.commonParameterDTO.id.toString(), + id: field.commonParameter.id.toString(), type: { - type: field.commonParameterDTO.gameStateParameterTypeDTO.type, - id: field.commonParameterDTO.gameStateParameterTypeDTO.id.toString(), + type: field.commonParameter.type.type, + id: field.commonParameter.type.id.toString(), }, - label: field.commonParameterDTO.label, - description: field.commonParameterDTO.description, + label: field.commonParameter.label, + description: field.commonParameter.description, } : { id: "", diff --git a/src/client/api/GameStateAPI.ts b/src/client/api/GameStateAPI.ts index a9137e6..09d5e95 100644 --- a/src/client/api/GameStateAPI.ts +++ b/src/client/api/GameStateAPI.ts @@ -14,6 +14,10 @@ type GameStateFromServer = { gameStateValues: { id: number; gameStateParameterId: number; + gameStateParameterType: { + id: number; + type: string; + }; value: string; label: string; description: string; @@ -54,7 +58,7 @@ export class GameStateAPI implements IGameStateAPI { getStatePaths = async (): Promise => { const pathsFromServer = await this.fetcher.get<{ items: GamePathFromServer[]; - }>(`/game-paths?pageSize=1000&pageNumber=1&searchQuery=""`); + }>(`/game-paths?pageSize=1000&pageNumber=1&searchQuery=`); const paths: GamePath[] = pathsFromServer.items.map((path) => ({ id: path.id.toString(), @@ -204,7 +208,7 @@ export class GameStateAPI implements IGameStateAPI { gameStateValues: state.gameStateValues.map((value) => ({ value: value.value, gameStateParameterId: value.gameStateParameterId.toString(), - type: "type", + type: value.gameStateParameterType.type, label: value.label, description: value.description, })), diff --git a/src/client/config/paths.tsx b/src/client/config/paths.tsx index 81bde71..e823174 100644 --- a/src/client/config/paths.tsx +++ b/src/client/config/paths.tsx @@ -9,9 +9,9 @@ const profile = path("/"); const mySaves = path("/my-saves"); const localSaves = mySaves.path("/local"); const mySave = mySaves.path("/:gameStateId"); +const sharedSaves = path("/saves/shared"); +const publicSaves = path("/saves/public"); const save = path("/saves/:gameStateId"); -const sharedSaves = path("/shared-saves"); -const publicSaves = path("/public-saves"); const games = path("/games"); const gameAdd = path("/games-add"); @@ -29,9 +29,9 @@ export const paths = { mySaves, localSaves, mySave, - save, sharedSaves, publicSaves, + save, games, game, diff --git a/src/client/config/routes.tsx b/src/client/config/routes.tsx index d783dde..4ee36f6 100644 --- a/src/client/config/routes.tsx +++ b/src/client/config/routes.tsx @@ -1,9 +1,9 @@ import { UserRole } from "@/types"; -import { LoginPage } from "@/client/pages/Login/LoginPage"; -import { RegisterPage } from "@/client/pages/Register/RegisterPage"; -import { RequestPasswordResetPage } from "@/client/pages/RequestPasswordReset/RequestPasswordResetPage"; -import { ResetPasswordPage } from "@/client/pages/ResetPassword/ResetPasswordPage"; +import { LoginPage } from "@/client/pages/auth/Login/LoginPage"; +import { RegisterPage } from "@/client/pages/auth/Register/RegisterPage"; +import { RequestPasswordResetPage } from "@/client/pages/auth/RequestPasswordReset/RequestPasswordResetPage"; +import { ResetPasswordPage } from "@/client/pages/auth/ResetPassword/ResetPasswordPage"; import { ProfilePage } from "@/client/pages/Profile/ProfilePage"; import { MySavesPage } from "@/client/pages/MySaves/MySavesPage"; @@ -117,12 +117,7 @@ export const routes: RouteDescriptor[] = [ access: RouteAccess.AUTHENTICATED, forRoles: [UserRole.USER], }, - { - path: paths.save.pattern, - component: SavePage, - access: RouteAccess.AUTHENTICATED, - forRoles: [UserRole.USER], - }, + { path: paths.sharedSaves.pattern, component: SharedSavesPage, @@ -143,6 +138,12 @@ export const routes: RouteDescriptor[] = [ icon: , }, }, + { + path: paths.save.pattern, + component: SavePage, + access: RouteAccess.AUTHENTICATED, + forRoles: [UserRole.USER], + }, { path: paths.games.pattern, diff --git a/src/client/lib/components/GameCard/GameCard.tsx b/src/client/lib/components/GameCard/GameCard.tsx new file mode 100644 index 0000000..72d1538 --- /dev/null +++ b/src/client/lib/components/GameCard/GameCard.tsx @@ -0,0 +1,53 @@ +import { clsx } from "clsx"; + +import { Game } from "@/types"; +import { useConfirmModal } from "@/client/ui/hooks/useConfirmModal/useConfirmModal"; + +import classes from "./game-card.module.scss"; + +import { Link } from "wouter"; +import { ThreeDotsMenu } from "@/client/ui/molecules/ThreeDotsMenu"; + +export type GameCardProps = { + game: Game; + className?: string; + onDelete?: (gameStateId: string) => void; + href: string; +}; + +export const GameCard = (props: GameCardProps) => { + const { modal, onClick: onDelete } = useConfirmModal({ + onConfirm: () => props.onDelete?.(props.game.id), + }); + + return ( +
+ +
+ {props.onDelete && ( + onDelete(), + children: "Delete", + key: "delete", + }, + ]} + /> + )} + {modal} + +
+

{props.game.name}

+
+
+ +
+ ); +}; diff --git a/src/client/lib/components/GameCard/game-card.module.scss b/src/client/lib/components/GameCard/game-card.module.scss new file mode 100644 index 0000000..3aaf147 --- /dev/null +++ b/src/client/lib/components/GameCard/game-card.module.scss @@ -0,0 +1,53 @@ +.GameCard { + min-width: 200px; + min-height: 250px; + display: flex; + flex-direction: column; + border-radius: 6px; + overflow: hidden; + background-size: cover; +} + +.GameLink { + flex: 1; + display: flex; + flex-direction: column; + text-decoration: none; +} + +.GameCardInner { + flex: 1; + display: flex; + flex-direction: column; + gap: 0.25rem; + padding: 0.75rem 0.75rem 1rem; + + background-image: linear-gradient( + 180deg, + rgba(255, 255, 255, 0.2) 0%, + rgba(0, 0, 0, 0.8) 60%, + rgba(0, 0, 0, 0.9) 100% + ); + background-position: 0% 50%; + background-size: 100% 200%; + transition: background-position 0.3s ease; + + &:hover { + background-position: 0% 60%; + + .GameActions { + opacity: 1; + } + } +} + +.GameActions { + margin-left: auto; + opacity: 0; + transition: opacity 0.3s ease; +} + +.GameInfo { + margin-top: auto; + color: white; +} diff --git a/src/client/lib/components/GameCard/index.ts b/src/client/lib/components/GameCard/index.ts new file mode 100644 index 0000000..94e9c94 --- /dev/null +++ b/src/client/lib/components/GameCard/index.ts @@ -0,0 +1 @@ +export * from "./GameCard"; diff --git a/src/client/lib/components/GameStateCard/GameStateCard.tsx b/src/client/lib/components/GameStateCard/GameStateCard.tsx index 4b419ee..768f233 100644 --- a/src/client/lib/components/GameStateCard/GameStateCard.tsx +++ b/src/client/lib/components/GameStateCard/GameStateCard.tsx @@ -1,12 +1,13 @@ +import { useTranslation } from "react-i18next"; +import { clsx } from "clsx"; + import { GameState } from "@/types"; +import { useConfirmModal } from "@/client/ui/hooks/useConfirmModal/useConfirmModal"; import classes from "./game-state-card.module.scss"; -import { clsx } from "clsx"; + import { Link } from "wouter"; import { ThreeDotsMenu } from "@/client/ui/molecules/ThreeDotsMenu"; -import { useTranslation } from "react-i18next"; -import { syncMap } from "@/client/pages/MySaves/utils"; -import { useConfirmModal } from "@/client/ui/hooks/useConfirmModal/useConfirmModal"; export type GameStateCardProps = { gameState: GameState; @@ -50,7 +51,7 @@ export const GameStateCard = (props: GameStateCardProps) => {

{props.gameState.name}

- {t("sync")}: {t(syncMap[props.gameState.sync])} + {t("sync")}: {t(props.gameState.sync)}

diff --git a/src/client/lib/components/GameStateCard/game-state-card.module.scss b/src/client/lib/components/GameStateCard/game-state-card.module.scss index 4d61ecb..ef6f099 100644 --- a/src/client/lib/components/GameStateCard/game-state-card.module.scss +++ b/src/client/lib/components/GameStateCard/game-state-card.module.scss @@ -5,6 +5,7 @@ flex-direction: column; border-radius: 6px; overflow: hidden; + background-size: cover; } .GameStateLink { @@ -28,16 +29,22 @@ rgba(0, 0, 0, 0.9) 100% ); background-position: 0% 50%; - background-size: 200% 200%; + background-size: 100% 200%; transition: background-position 0.3s ease; &:hover { background-position: 0% 60%; + + .GameStateActions { + opacity: 1; + } } } .GameStateActions { margin-left: auto; + opacity: 0; + transition: opacity 0.3s ease; } .GameStateInfo { diff --git a/src/client/lib/components/Guard/AnonymousPage.tsx b/src/client/lib/components/Guard/AnonymousPage.tsx index 1e25f2c..35cf1c9 100644 --- a/src/client/lib/components/Guard/AnonymousPage.tsx +++ b/src/client/lib/components/Guard/AnonymousPage.tsx @@ -7,7 +7,7 @@ import { paths } from "@/client/config/paths"; import { AuthStatus, useAuthContext } from "@/client/contexts/AuthContext"; import { Spinner } from "@/client/ui/atoms/Spinner"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { UserRole } from "@/types"; export const AnonymousPage = ({ children }: { children: ReactNode }) => { diff --git a/src/client/lib/components/Guard/PrivatePage.tsx b/src/client/lib/components/Guard/PrivatePage.tsx index 6e767b8..12c39ec 100644 --- a/src/client/lib/components/Guard/PrivatePage.tsx +++ b/src/client/lib/components/Guard/PrivatePage.tsx @@ -8,7 +8,7 @@ import { AuthStatus, useAuthContext } from "@/client/contexts/AuthContext"; import { paths } from "@/client/config/paths"; import { H1 } from "@/client/ui/atoms/Typography"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { Spinner } from "@/client/ui/atoms/Spinner"; type PrivatePageProps = { diff --git a/src/client/lib/components/ParametersView/ParametersView.tsx b/src/client/lib/components/ParametersView/ParametersView.tsx index 9595b4c..7ffd822 100644 --- a/src/client/lib/components/ParametersView/ParametersView.tsx +++ b/src/client/lib/components/ParametersView/ParametersView.tsx @@ -12,6 +12,7 @@ export const ParametersView = (props: ParametersViewProps) => { {props.gameStateValues.map((field, idx) => ( ))} + {props.gameStateValues.length === 0 && "-"} ); }; diff --git a/src/client/lib/components/ParametersView/index.ts b/src/client/lib/components/ParametersView/index.ts index e69de29..0e0ffd9 100644 --- a/src/client/lib/components/ParametersView/index.ts +++ b/src/client/lib/components/ParametersView/index.ts @@ -0,0 +1 @@ +export * from "./ParametersView"; diff --git a/src/client/lib/components/SharesWidget/SharesWidget.tsx b/src/client/lib/components/SharesWidget/SharesWidget.tsx index 6dbda01..c833e54 100644 --- a/src/client/lib/components/SharesWidget/SharesWidget.tsx +++ b/src/client/lib/components/SharesWidget/SharesWidget.tsx @@ -6,12 +6,11 @@ import { useAPIContext } from "@/client/contexts/APIContext"; import { useUIContext } from "@/client/contexts/UIContext"; import { useModal } from "@/client/ui/hooks/useModal"; -import { Button } from "@/client/ui/atoms/Button/Button"; -import { List } from "@/client/ui/molecules/List/List"; -import { ConfirmButton } from "@/client/ui/molecules/ConfirmButton/ConfirmButton"; -import { Form, FormConfig, FormData } from "@/client/ui/molecules/Form/Form"; +import { Button, ConfirmButton } from "@/client/ui/atoms/Button"; import { H2 } from "@/client/ui/atoms/Typography"; import { Flex } from "@/client/ui/atoms/Flex"; +import { List } from "@/client/ui/molecules/List/List"; +import { Form, FormConfig, FormData } from "@/client/ui/molecules/Form/Form"; export type SharesWidgetProps = { gameStateId: string; @@ -56,7 +55,6 @@ export const SharesWidget = (props: SharesWidgetProps) => { const onAdd = async (data: FormData) => { try { - console.log(data); if (!data.user.value) return t("select-user"); await gameStateAPI.addShare({ diff --git a/src/client/lib/components/Sidebar/sidebar.module.scss b/src/client/lib/components/Sidebar/sidebar.module.scss index c9309b9..c419418 100644 --- a/src/client/lib/components/Sidebar/sidebar.module.scss +++ b/src/client/lib/components/Sidebar/sidebar.module.scss @@ -5,8 +5,8 @@ width: 4rem; min-height: 100vh; padding: 0.5rem 0.25rem; - border-right: 1px solid var(--deco-color); overflow: hidden; + background: var(--paper-color); } .Logo { diff --git a/src/client/locales/en/forms/gameForm.json b/src/client/locales/en/components/gameForm.json similarity index 100% rename from src/client/locales/en/forms/gameForm.json rename to src/client/locales/en/components/gameForm.json diff --git a/src/client/locales/resources-en.ts b/src/client/locales/resources-en.ts index 556631f..9a17180 100644 --- a/src/client/locales/resources-en.ts +++ b/src/client/locales/resources-en.ts @@ -3,7 +3,6 @@ import register from "./en/pages/register.json"; import resetPassword from "./en/pages/resetPassword.json"; import requestPasswordReset from "./en/pages/requestPasswordReset.json"; -import gameForm from "./en/forms/gameForm.json"; import games from "./en/pages/games.json"; import addGame from "./en/pages/addGame.json"; import game from "./en/pages/game.json"; @@ -15,6 +14,7 @@ import sharedSaves from "./en/pages/sharedSaves.json"; import publicSaves from "./en/pages/publicSaves.json"; import notFound from "./en/pages/notFound.json"; +import gameForm from "./en/components/gameForm.json"; import GameStateCard from "./en/components/GameStateCard.json"; import common from "./en/common.json"; @@ -42,10 +42,8 @@ export const resourcesEN = { notFound, }, - forms: { - gameForm, - }, components: { + gameForm, GameStateCard, }, common: common, diff --git a/src/client/locales/resources-ru.ts b/src/client/locales/resources-ru.ts index 9100770..47ab398 100644 --- a/src/client/locales/resources-ru.ts +++ b/src/client/locales/resources-ru.ts @@ -3,7 +3,6 @@ import register from "./ru/pages/register.json"; import resetPassword from "./ru/pages/resetPassword.json"; import requestPasswordReset from "./ru/pages/requestPasswordReset.json"; -import gameForm from "./ru/forms/gameForm.json"; import games from "./ru/pages/games.json"; import addGame from "./ru/pages/addGame.json"; import game from "./ru/pages/game.json"; @@ -15,6 +14,7 @@ import sharedSaves from "./ru/pages/sharedSaves.json"; import publicSaves from "./ru/pages/publicSaves.json"; import notFound from "./ru/pages/notFound.json"; +import gameForm from "./ru/components/gameForm.json"; import GameStateCard from "./ru/components/GameStateCard.json"; import common from "./ru/common.json"; @@ -42,10 +42,8 @@ export const resourcesRU = { notFound, }, - forms: { - gameForm, - }, components: { + gameForm, GameStateCard, }, common: common, diff --git a/src/client/locales/ru/forms/gameForm.json b/src/client/locales/ru/components/gameForm.json similarity index 91% rename from src/client/locales/ru/forms/gameForm.json rename to src/client/locales/ru/components/gameForm.json index 7eb8a36..f1730d2 100644 --- a/src/client/locales/ru/forms/gameForm.json +++ b/src/client/locales/ru/components/gameForm.json @@ -8,9 +8,9 @@ "save-paths": "Пути к сохранениям", "add-path": "Добавить путь", "extraction-pipeline": "Extraction Pipeline", - "input-filename": "Input filename", - "output-filename": "Output filename", - "add-pipeline-item": "Add pipeline item", + "input-filename": "Входной файл", + "output-filename": "Выходной файл", + "add-pipeline-item": "Добавить pipeline item", "parameters-schema-filename": "Название файла с параметрами", "parameters-schema-filename-0": "Название файла с параметрами", "parameters-schema-fields": "Параметры", diff --git a/src/client/pages/Games/Game/GamePage.tsx b/src/client/pages/Games/Game/GamePage.tsx index 6fdaba2..3a47cbc 100644 --- a/src/client/pages/Games/Game/GamePage.tsx +++ b/src/client/pages/Games/Game/GamePage.tsx @@ -12,9 +12,9 @@ import { navigate } from "@/client/useHashLocation"; import { paths } from "@/client/config/paths"; import { H1 } from "@/client/ui/atoms/Typography"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { GameForm } from "../components/GameForm/GameForm"; -import { ConfirmButton } from "@/client/ui/molecules/ConfirmButton/ConfirmButton"; +import { ConfirmButton } from "@/client/ui/atoms/Button/"; export const GamePage = () => { const { gameAPI } = useAPIContext(); @@ -75,7 +75,7 @@ export const GamePage = () => {

{game.name}

-
+
{ onDelete(game.id); diff --git a/src/client/pages/Games/Game/game-page.module.scss b/src/client/pages/Games/Game/game-page.module.scss index 300f8e5..534f258 100644 --- a/src/client/pages/Games/Game/game-page.module.scss +++ b/src/client/pages/Games/Game/game-page.module.scss @@ -13,3 +13,10 @@ height: 64px; } } + +.Actions { + display: flex; + justify-content: flex-end; + gap: 0.5rem; + margin-bottom: 1rem; +} diff --git a/src/client/pages/Games/GameAdd/GameAddPage.tsx b/src/client/pages/Games/GameAdd/GameAddPage.tsx index 2d7a818..e8ae8a0 100644 --- a/src/client/pages/Games/GameAdd/GameAddPage.tsx +++ b/src/client/pages/Games/GameAdd/GameAddPage.tsx @@ -8,7 +8,7 @@ import { navigate } from "@/client/useHashLocation"; import { paths } from "@/client/config/paths"; import { H1 } from "@/client/ui/atoms/Typography"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { GameForm } from "../components/GameForm/GameForm"; import { AddGameDTO } from "@/client/api/interfaces/IGameAPI"; diff --git a/src/client/pages/Games/GamesPage.tsx b/src/client/pages/Games/GamesPage.tsx index 1f25aba..347dcd5 100644 --- a/src/client/pages/Games/GamesPage.tsx +++ b/src/client/pages/Games/GamesPage.tsx @@ -9,15 +9,14 @@ import { useUIContext } from "@/client/contexts/UIContext"; import { useParameterTypesModal } from "./components/ParameterTypesWidget"; import { useCommonParametersModal } from "./components/CommonParametersWidget"; -import { Link } from "wouter"; import { H1 } from "@/client/ui/atoms/Typography"; -import { Button } from "@/client/ui/atoms/Button/Button"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Button } from "@/client/ui/atoms/Button"; +import { Container } from "@/client/ui/atoms/Container"; import { CommonLink } from "@/client/ui/atoms/NavLink/CommonLink"; -import { List } from "@/client/ui/molecules/List/List"; import { Paginator } from "@/client/ui/molecules/Paginator"; -import { SearchForm } from "@/client/ui/molecules/SearchForm/SearchForm"; -import { ConfirmButton } from "@/client/ui/molecules/ConfirmButton/ConfirmButton"; +import { SearchForm } from "@/client/ui/molecules/SearchForm"; +import { Grid } from "@/client/ui/molecules/Grid"; +import { GameCard } from "@/client/lib/components/GameCard"; export const GamesPage = () => { const { gameAPI } = useAPIContext(); @@ -71,36 +70,16 @@ export const GamesPage = () => { onQueryChange={(searchQuery) => setQuery({ ...query, searchQuery })} /> - game.id} - elementClassName={classes.GameItem} renderElement={(game) => ( - <> - - {game.name} - {game.name} - - -
- { - onDelete(game.id); - }} - color="danger" - > - {t("games-delete-game")}{" "} - -
- + )} /> diff --git a/src/client/pages/Games/components/CommonParametersWidget/CommonParameterForm/CommonParameterForm.tsx b/src/client/pages/Games/components/CommonParametersWidget/CommonParameterForm/CommonParameterForm.tsx index 3ccd5ce..73c2f82 100644 --- a/src/client/pages/Games/components/CommonParametersWidget/CommonParameterForm/CommonParameterForm.tsx +++ b/src/client/pages/Games/components/CommonParametersWidget/CommonParameterForm/CommonParameterForm.tsx @@ -6,8 +6,8 @@ import classes from "./form.module.scss"; import { CommonParameter } from "@/types"; import { useAPIContext } from "@/client/contexts/APIContext"; -import { Input } from "@/client/ui/atoms/Input/Input"; -import { Button } from "@/client/ui/atoms/Button/Button"; +import { Input } from "@/client/ui/atoms/Input"; +import { Button } from "@/client/ui/atoms/Button"; import { ErrorText } from "@/client/ui/atoms/ErrorText/ErrorText"; import { AsyncEntitySelect } from "@/client/ui/atoms/Select/AsyncSelect/AsyncEntitySelect"; diff --git a/src/client/pages/Games/components/CommonParametersWidget/CommonParametersWidget.tsx b/src/client/pages/Games/components/CommonParametersWidget/CommonParametersWidget.tsx index 1b0a2ce..fd7debe 100644 --- a/src/client/pages/Games/components/CommonParametersWidget/CommonParametersWidget.tsx +++ b/src/client/pages/Games/components/CommonParametersWidget/CommonParametersWidget.tsx @@ -10,8 +10,8 @@ import { CommonParameter } from "@/types"; import { Paragraph } from "@/client/ui/atoms/Typography"; import { List } from "@/client/ui/molecules/List/List"; import { Paginator } from "@/client/ui/molecules/Paginator"; -import { SearchForm } from "@/client/ui/molecules/SearchForm/SearchForm"; -import { ConfirmButton } from "@/client/ui/molecules/ConfirmButton/ConfirmButton"; +import { SearchForm } from "@/client/ui/molecules/SearchForm"; +import { ConfirmButton } from "@/client/ui/atoms/Button/"; import { CommonParameterForm } from "./CommonParameterForm"; export const CommonParametersWidget = () => { diff --git a/src/client/pages/Games/components/GameForm/GameForm.tsx b/src/client/pages/Games/components/GameForm/GameForm.tsx index 9894ae0..e2da754 100644 --- a/src/client/pages/Games/components/GameForm/GameForm.tsx +++ b/src/client/pages/Games/components/GameForm/GameForm.tsx @@ -1,4 +1,5 @@ import { useTranslation } from "react-i18next"; +import { clsx } from "clsx"; import classes from "./game-form.module.scss"; @@ -10,11 +11,13 @@ import { useGameForm } from "./useGameForm"; import { Controller } from "react-hook-form"; import { CTAButton } from "@/client/ui/atoms/Button/CTAButton"; import { ErrorText } from "@/client/ui/atoms/ErrorText/ErrorText"; -import { Button } from "@/client/ui/atoms/Button/Button"; -import { Input } from "@/client/ui/atoms/Input/Input"; +import { Button } from "@/client/ui/atoms/Button"; +import { Input } from "@/client/ui/atoms/Input"; +import { Paper } from "@/client/ui/atoms/Paper"; import { Select } from "@/client/ui/atoms/Select/Select"; -import { Field, InputField } from "@/client/ui/molecules/Field"; +import { Paragraph } from "@/client/ui/atoms/Typography"; import { AsyncEntitySelect } from "@/client/ui/atoms/Select/AsyncSelect/AsyncEntitySelect"; +import { InputField } from "@/client/ui/molecules/Field"; export type GameFormProps = { game?: Game; @@ -23,7 +26,7 @@ export type GameFormProps = { export const GameForm = (props: GameFormProps) => { const { commonParametersAPI, parameterTypesAPI } = useAPIContext(); - const { t } = useTranslation(undefined, { keyPrefix: "forms.gameForm" }); + const { t } = useTranslation(undefined, { keyPrefix: "components.gameForm" }); const { register, handleSubmit, @@ -44,59 +47,71 @@ export const GameForm = (props: GameFormProps) => { return (
- - {errors.name && {errors.name.message}} + + + {errors.name && {errors.name.message}} - - {errors.description && ( - {errors.description.message} - )} + + {errors.description && ( + {errors.description.message} + )} - - {iconPreview && ( - {t("game-icon")} - )} - {errors.icon && {errors.icon.message}} + {iconPreview && ( + {t("game-icon")} + )} + {errors.icon && {errors.icon.message}} + - + + {t("save-paths")} {pathFields.map((field, index) => ( -
+
-
))} - - - {errors.paths && errors.paths.root && ( - {errors.paths.root.message} - )} +
+ +
+ {errors.paths && errors.paths.root && ( + {errors.paths.root.message} + )} + - + + + {t("extraction-pipeline")} + {extractionPipelineFields.map((field, index) => ( -
+
{
))} - - - {errors.extractionPipeline && errors.extractionPipeline.root && ( - {errors.extractionPipeline.root.message} - )} - {errors.extractionPipeline?.map - ? errors.extractionPipeline.map((error, idx) => ( - {error?.message} - )) - : null} - - - {errors.gameStateParameters?.filename && - errors.gameStateParameters.filename && ( - {errors.gameStateParameters.filename.message} +
+ +
+ {errors.extractionPipeline && errors.extractionPipeline.root && ( + {errors.extractionPipeline.root.message} )} + {errors.extractionPipeline?.map + ? errors.extractionPipeline.map((error, idx) => ( + {error?.message} + )) + : null} + + + + + {errors.gameStateParameters?.filename && + errors.gameStateParameters.filename && ( + {errors.gameStateParameters.filename.message} + )} + - + + + {t("parameters-schema-fields")} + {gameStateParameters.map((field, index) => ( -
+
{ control={control} render={({ field: selectField }) => ( { - const parameters = await commonParametersAPI.getParameters({ - searchQuery: query, - pageNumber: 1, - pageSize: 25, - }); - return parameters.items.map((parameter) => ({ - value: parameter.id.toString(), - label: parameter.label, - })); - }} onChange={(value) => { selectField.onChange({ label: value.label, @@ -216,6 +230,17 @@ export const GameForm = (props: GameFormProps) => { }} name={selectField.name} placeholder={t("common-parameter")} + loadOptions={async (query) => { + const parameters = await commonParametersAPI.getParameters({ + searchQuery: query, + pageNumber: 1, + pageSize: 25, + }); + return parameters.items.map((parameter) => ({ + value: parameter.id.toString(), + label: parameter.label, + })); + }} /> )} /> @@ -237,35 +262,37 @@ export const GameForm = (props: GameFormProps) => {
))} - - - {errors.gameStateParameters && errors.gameStateParameters.root && ( - {errors.gameStateParameters.root.message} - )} + key: "", + type: { + id: "", + type: "", + }, + commonParameter: { label: "-", id: "" }, + label: "", + description: "", + }) + } + > + {t("add-schema-field")}{" "} + +
+ {errors.gameStateParameters && errors.gameStateParameters.root && ( + {errors.gameStateParameters.root.message} + )} - {errors.gameStateParameters?.parameters?.map - ? errors.gameStateParameters.parameters.map((error, idx) => ( - {error?.message} - )) - : null} + {errors.gameStateParameters?.parameters?.map + ? errors.gameStateParameters.parameters.map((error, idx) => ( + {error?.message} + )) + : null} +
-
+
{t("add-game-submit")}
diff --git a/src/client/pages/Games/components/GameForm/game-form.module.scss b/src/client/pages/Games/components/GameForm/game-form.module.scss index fb6ece0..b3d643a 100644 --- a/src/client/pages/Games/components/GameForm/game-form.module.scss +++ b/src/client/pages/Games/components/GameForm/game-form.module.scss @@ -2,6 +2,14 @@ padding-bottom: 1rem; } +.Label { + display: block; + margin-bottom: 0.25rem; + font-size: 18px; + line-height: 32px; + text-align: left; +} + .AddGameButtons { display: flex; justify-content: flex-end; @@ -10,21 +18,18 @@ .PathItem { display: flex; align-items: stretch; - margin-bottom: 8px; } .PipelineItem { display: flex; align-items: stretch; - margin-bottom: 8px; } .SchemaField { display: flex; flex-direction: column; - gap: 4px; + gap: 0.25rem; align-items: flex-end; - margin-bottom: 8px; } .ImagePreview { diff --git a/src/client/pages/Games/components/GameForm/useGameForm.ts b/src/client/pages/Games/components/GameForm/useGameForm.ts index a0ffd57..b3faaf7 100644 --- a/src/client/pages/Games/components/GameForm/useGameForm.ts +++ b/src/client/pages/Games/components/GameForm/useGameForm.ts @@ -39,7 +39,7 @@ type UseGameFormArgs = { }; export const useGameForm = (args: UseGameFormArgs) => { - const { t } = useTranslation(undefined, { keyPrefix: "forms.gameForm" }); + const { t } = useTranslation(undefined, { keyPrefix: "components.gameForm" }); const { register, handleSubmit, diff --git a/src/client/pages/Games/components/ParameterTypesWidget/ParameterTypeForm/ParameterTypeForm.tsx b/src/client/pages/Games/components/ParameterTypesWidget/ParameterTypeForm/ParameterTypeForm.tsx index 912ead7..f68fbf0 100644 --- a/src/client/pages/Games/components/ParameterTypesWidget/ParameterTypeForm/ParameterTypeForm.tsx +++ b/src/client/pages/Games/components/ParameterTypesWidget/ParameterTypeForm/ParameterTypeForm.tsx @@ -3,8 +3,8 @@ import { useTranslation } from "react-i18next"; import classes from "./form.module.scss"; -import { Input } from "@/client/ui/atoms/Input/Input"; -import { Button } from "@/client/ui/atoms/Button/Button"; +import { Input } from "@/client/ui/atoms/Input"; +import { Button } from "@/client/ui/atoms/Button"; import { ErrorText } from "@/client/ui/atoms/ErrorText/ErrorText"; export type ParameterTypeFormProps = { diff --git a/src/client/pages/Games/components/ParameterTypesWidget/ParameterTypesWidget.tsx b/src/client/pages/Games/components/ParameterTypesWidget/ParameterTypesWidget.tsx index 5208776..f9bfd28 100644 --- a/src/client/pages/Games/components/ParameterTypesWidget/ParameterTypesWidget.tsx +++ b/src/client/pages/Games/components/ParameterTypesWidget/ParameterTypesWidget.tsx @@ -8,9 +8,9 @@ import { useResource } from "@/client/lib/hooks/useResource"; import { Paragraph } from "@/client/ui/atoms/Typography"; import { List } from "@/client/ui/molecules/List/List"; -import { SearchForm } from "@/client/ui/molecules/SearchForm/SearchForm"; +import { SearchForm } from "@/client/ui/molecules/SearchForm"; import { Paginator } from "@/client/ui/molecules/Paginator"; -import { ConfirmButton } from "@/client/ui/molecules/ConfirmButton/ConfirmButton"; +import { ConfirmButton } from "@/client/ui/atoms/Button/"; import { ParameterTypeForm } from "./ParameterTypeForm"; export const ParameterTypesWidget = () => { diff --git a/src/client/pages/Games/games-page.module.scss b/src/client/pages/Games/games-page.module.scss index 433eb5c..7ec697b 100644 --- a/src/client/pages/Games/games-page.module.scss +++ b/src/client/pages/Games/games-page.module.scss @@ -15,23 +15,3 @@ .GamesList { margin: 1rem 0; } - -.GameItem { - display: flex; - align-items: center; - justify-content: space-between; - padding: 0.5rem; - - .GameLink { - display: flex; - align-items: flex-start; - gap: 0.5rem; - text-decoration: none; - color: var(--text-color); - - .GameIcon { - width: 64px; - height: 64px; - } - } -} diff --git a/src/client/pages/MySaves/LocalSaves/LocalSavesPage.tsx b/src/client/pages/MySaves/LocalSaves/LocalSavesPage.tsx index 6b6bfe4..1e74734 100644 --- a/src/client/pages/MySaves/LocalSaves/LocalSavesPage.tsx +++ b/src/client/pages/MySaves/LocalSaves/LocalSavesPage.tsx @@ -8,10 +8,10 @@ import { useAPIContext } from "@/client/contexts/APIContext"; import { useUIContext } from "@/client/contexts/UIContext"; import GamepadIcon from "@/client/ui/icons/Gamepad.svg"; -import { Button } from "@/client/ui/atoms/Button/Button"; -import { Bytes } from "@/client/ui/atoms/Bytes/Bytes"; +import { Button } from "@/client/ui/atoms/Button"; +import { Bytes } from "@/client/ui/atoms/Bytes"; import { H1, Paragraph } from "@/client/ui/atoms/Typography"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { List } from "@/client/ui/molecules/List/List"; function last(arr: string[]) { @@ -138,6 +138,7 @@ export const LocalSavesPage = () => {
file.path} renderElement={(file) => ( diff --git a/src/client/pages/MySaves/MySave/MySavePage.tsx b/src/client/pages/MySaves/MySave/MySavePage.tsx index 34a66f8..bb535a0 100644 --- a/src/client/pages/MySaves/MySave/MySavePage.tsx +++ b/src/client/pages/MySaves/MySave/MySavePage.tsx @@ -10,24 +10,23 @@ import { useUIContext } from "@/client/contexts/UIContext"; import { useAuthContext } from "@/client/contexts/AuthContext"; import { navigate } from "@/client/useHashLocation"; import { paths } from "@/client/config/paths"; -import { syncMap } from "../utils"; import { H1, H2, Paragraph } from "@/client/ui/atoms/Typography"; -import { Bytes } from "@/client/ui/atoms/Bytes/Bytes"; -import { Container } from "@/client/ui/atoms/Container/Container"; -import { Button } from "@/client/ui/atoms/Button/Button"; +import { Bytes } from "@/client/ui/atoms/Bytes"; +import { Container } from "@/client/ui/atoms/Container"; +import { Button, PolyButton, ConfirmButton } from "@/client/ui/atoms/Button"; import { Flex } from "@/client/ui/atoms/Flex"; -import { Modal } from "@/client/ui/molecules/Modal/Modal"; -import { ConfirmButton } from "@/client/ui/molecules/ConfirmButton/ConfirmButton"; -import { PolyButton } from "@/client/ui/molecules/PolyButton/PolyButton"; +import { Paper } from "@/client/ui/atoms/Paper"; +import { Modal } from "@/client/ui/molecules/Modal"; import { SharesWidget } from "@/client/lib/components/SharesWidget"; -import { ParametersView } from "@/client/lib/components/ParametersView/ParametersView"; +import { ParametersView } from "@/client/lib/components/ParametersView"; export const MySavePage = () => { const { gameStateAPI } = useAPIContext(); const { t } = useTranslation(undefined, { keyPrefix: "pages.mySave" }); const [gameState, setGameState] = useState(null); + const [isNameEditing, setIsNameEditing] = useState(false); const { notify } = useUIContext(); const { user } = useAuthContext(); @@ -96,8 +95,7 @@ export const MySavePage = () => { const downloadState = async () => { try { - const response = await gameStateAPI.downloadState(gameState); - console.log(response); + await gameStateAPI.downloadState(gameState); } catch (error) { notify.error(error); } @@ -105,8 +103,7 @@ export const MySavePage = () => { const downloadStateAs = async () => { try { - const response = await gameStateAPI.downloadStateAs(gameState); - console.log(response); + await gameStateAPI.downloadStateAs(gameState); } catch (error) { notify.error(error); } @@ -121,6 +118,38 @@ export const MySavePage = () => { } }; + const onNameChange = async (e: React.FormEvent) => { + try { + e.preventDefault(); + const eventTarget = e.target as unknown as { + gameStateName: HTMLInputElement; + }; + if ( + !eventTarget.gameStateName || + typeof eventTarget.gameStateName.value !== "string" + ) + return; + + const newName = eventTarget.gameStateName.value; + if (newName === gameState.name || !newName.trim()) { + setIsNameEditing(false); + return; + } + + await gameStateAPI.reuploadState({ + ...gameState, + name: newName, + }); + setGameState({ + ...gameState, + name: newName, + }); + setIsNameEditing(false); + } catch (error) { + notify.error(error); + } + }; + return (

@@ -129,16 +158,33 @@ export const MySavePage = () => { alt={gameState.name} className={classes.GameIcon} />{" "} - {gameState?.name || t("save")} + {isNameEditing ? ( +
setIsNameEditing(false)} + > + setIsNameEditing(false)} + className={classes.GameStateNameInput} + name="gameStateName" + autoFocus + /> +
+ ) : ( + setIsNameEditing(true)}>{gameState.name} + )}

-
+
- {t("path")}: {gameState?.localPath} + {t("path")}: {gameState.localPath} - {t("sync")}: {t(syncMap[gameState?.sync])}{" "} + {t("sync")}: {t(gameState.sync)}{" "}
+
{

{t("about")}

- + + + -
+ {t("size")}: @@ -246,7 +294,7 @@ export const MySavePage = () => { {t("download")}
-
+
); }; diff --git a/src/client/pages/MySaves/MySave/my-save-page.module.scss b/src/client/pages/MySaves/MySave/my-save-page.module.scss index 19f7e02..24f662f 100644 --- a/src/client/pages/MySaves/MySave/my-save-page.module.scss +++ b/src/client/pages/MySaves/MySave/my-save-page.module.scss @@ -7,6 +7,7 @@ display: flex; gap: 0.5rem; align-items: center; + margin-bottom: 0.5rem; .GameIcon { width: 8rem; @@ -14,6 +15,33 @@ object-fit: contain; } + + & > span { + width: 100%; + } +} + +.GameStateNameForm { + flex: 1; + height: 100%; + + .GameStateNameInput { + display: block; + width: 100%; + height: 108px; + padding: 0; + margin: 0; + font-family: inherit; + font-size: 3.75rem; + line-height: 1.8; + font-weight: 300; + color: var(--text-color); + background: var(--background-color); + + border: none; + border-bottom: 1px solid var(--deco-color); + outline: none; + } } .GameSaveSettings { @@ -54,7 +82,4 @@ gap: 0.5rem; align-items: center; padding: 1rem 1rem; - - border: 1px solid var(--deco-color); - border-radius: 6px; } diff --git a/src/client/pages/MySaves/MySavesPage.tsx b/src/client/pages/MySaves/MySavesPage.tsx index fefc59a..e7a40ee 100644 --- a/src/client/pages/MySaves/MySavesPage.tsx +++ b/src/client/pages/MySaves/MySavesPage.tsx @@ -1,17 +1,15 @@ import { useTranslation } from "react-i18next"; -import classes from "./my-saves-page.module.scss"; - import { paths } from "@/client/config/paths"; import { useAPIContext } from "@/client/contexts/APIContext"; import { useUIContext } from "@/client/contexts/UIContext"; import { useResource } from "@/client/lib/hooks/useResource"; import { H1, H2 } from "@/client/ui/atoms/Typography"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { CommonLink } from "@/client/ui/atoms/NavLink/CommonLink"; import { Paginator } from "@/client/ui/molecules/Paginator"; -import { SearchForm } from "@/client/ui/molecules/SearchForm/SearchForm"; +import { SearchForm } from "@/client/ui/molecules/SearchForm"; import { Grid } from "@/client/ui/molecules/Grid"; import { GameStateCard } from "@/client/lib/components/GameStateCard"; @@ -22,7 +20,7 @@ export const MySavesPage = () => { const { query, - resource: saves, + resource: gameStates, onSearch, loadResource: loadSaves, setQuery, @@ -52,13 +50,13 @@ export const MySavesPage = () => { /> save.gameId} - renderElement={(save) => ( + className="my-4" + elements={gameStates.items} + getKey={(gameState) => gameState.id} + renderElement={(gameState) => ( )} @@ -68,7 +66,7 @@ export const MySavesPage = () => { scope={3} currentPage={query.pageNumber} pageSize={query.pageSize} - count={saves.totalCount} + count={gameStates.totalCount} onPageSelect={(page) => loadSaves({ ...query, pageNumber: page })} />
diff --git a/src/client/pages/MySaves/my-saves-page.module.scss b/src/client/pages/MySaves/my-saves-page.module.scss deleted file mode 100644 index 15c2117..0000000 --- a/src/client/pages/MySaves/my-saves-page.module.scss +++ /dev/null @@ -1,3 +0,0 @@ -.SavesList { - margin: 0.5rem 0; -} diff --git a/src/client/pages/MySaves/utils.ts b/src/client/pages/MySaves/utils.ts deleted file mode 100644 index a5981ff..0000000 --- a/src/client/pages/MySaves/utils.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { GameStateSync } from "@/types"; - -export const syncMap = { - [GameStateSync.NO]: "no", - [GameStateSync.EVERY_HOUR]: "every-hour", - [GameStateSync.EVERY_DAY]: "every-day", - [GameStateSync.EVERY_WEEK]: "every-week", - [GameStateSync.EVERY_MONTH]: "every-month", -} as const; diff --git a/src/client/pages/NotFound/NotFoundPage.tsx b/src/client/pages/NotFound/NotFoundPage.tsx index fa3e0c8..de66a42 100644 --- a/src/client/pages/NotFound/NotFoundPage.tsx +++ b/src/client/pages/NotFound/NotFoundPage.tsx @@ -2,7 +2,7 @@ import { useTranslation } from "react-i18next"; import classes from "./not-found-page.module.scss"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { H1 } from "@/client/ui/atoms/Typography"; export const NotFoundPage = () => { diff --git a/src/client/pages/Profile/ProfilePage.tsx b/src/client/pages/Profile/ProfilePage.tsx index 1a57257..c94ab38 100644 --- a/src/client/pages/Profile/ProfilePage.tsx +++ b/src/client/pages/Profile/ProfilePage.tsx @@ -3,8 +3,9 @@ import { useTranslation } from "react-i18next"; import { useAuthContext } from "@/client/contexts/AuthContext"; import { useUIContext } from "@/client/contexts/UIContext"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { H1, H2 } from "@/client/ui/atoms/Typography"; +import { Paper } from "@/client/ui/atoms/Paper"; import { Form, FormData } from "@/client/ui/molecules/Form/Form"; export const ProfilePage = () => { @@ -55,19 +56,24 @@ export const ProfilePage = () => {

{t("user-information")}

-

- {t("username")} {user.username} -

-

- {t("email")} {user.email} -

+ +

+ {t("username")} {user.username} +

+

+ {t("email")} {user.email} +

+

{t("change-password")}

-
+ + + +
); diff --git a/src/client/pages/Users/UsersPage.tsx b/src/client/pages/Users/UsersPage.tsx index c46a30a..8125f27 100644 --- a/src/client/pages/Users/UsersPage.tsx +++ b/src/client/pages/Users/UsersPage.tsx @@ -7,11 +7,11 @@ import { useUIContext } from "@/client/contexts/UIContext"; import { useResource } from "@/client/lib/hooks/useResource"; import { H1 } from "@/client/ui/atoms/Typography"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { List } from "@/client/ui/molecules/List/List"; import { Paginator } from "@/client/ui/molecules/Paginator"; -import { SearchForm } from "@/client/ui/molecules/SearchForm/SearchForm"; -import { ConfirmButton } from "@/client/ui/molecules/ConfirmButton/ConfirmButton"; +import { SearchForm } from "@/client/ui/molecules/SearchForm"; +import { ConfirmButton } from "@/client/ui/atoms/Button/"; export const UsersPage = () => { const { usersAPI } = useAPIContext(); diff --git a/src/client/pages/Login/LoginPage.tsx b/src/client/pages/auth/Login/LoginPage.tsx similarity index 69% rename from src/client/pages/Login/LoginPage.tsx rename to src/client/pages/auth/Login/LoginPage.tsx index c043b42..46991eb 100644 --- a/src/client/pages/Login/LoginPage.tsx +++ b/src/client/pages/auth/Login/LoginPage.tsx @@ -5,9 +5,10 @@ import classes from "./login-page.module.scss"; import { paths } from "@/client/config/paths"; import { useAuthContext } from "@/client/contexts/AuthContext"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { H1, Paragraph } from "@/client/ui/atoms/Typography"; import { CommonLink } from "@/client/ui/atoms/NavLink/CommonLink"; +import { Paper } from "@/client/ui/atoms/Paper"; import { Form, FormConfig, FormData } from "@/client/ui/molecules/Form/Form"; export const LoginPage = () => { @@ -49,21 +50,25 @@ export const LoginPage = () => {

{t("form.title")}

- - - {t("prompt-to-sign-up")}{" "} - - {t("link-to-sign-up")}{" "} - - - {t("link-to-forgot-pasword")} - - + + + + + {t("prompt-to-sign-up")}{" "} + + {t("link-to-sign-up")}{" "} + + + {t("link-to-forgot-pasword")} + + +
); diff --git a/src/client/pages/Login/login-page.module.scss b/src/client/pages/auth/Login/login-page.module.scss similarity index 77% rename from src/client/pages/Login/login-page.module.scss rename to src/client/pages/auth/Login/login-page.module.scss index 08f15cc..33ee6e4 100644 --- a/src/client/pages/Login/login-page.module.scss +++ b/src/client/pages/auth/Login/login-page.module.scss @@ -5,3 +5,7 @@ align-items: center; min-height: 100vh; } + +.Form { + width: 100% !important; +} diff --git a/src/client/pages/Register/RegisterPage.tsx b/src/client/pages/auth/Register/RegisterPage.tsx similarity index 79% rename from src/client/pages/Register/RegisterPage.tsx rename to src/client/pages/auth/Register/RegisterPage.tsx index 7d85a1a..ee87c50 100644 --- a/src/client/pages/Register/RegisterPage.tsx +++ b/src/client/pages/auth/Register/RegisterPage.tsx @@ -6,8 +6,9 @@ import { paths } from "@/client/config/paths"; import { useAuthContext } from "@/client/contexts/AuthContext"; import { H1, Paragraph } from "@/client/ui/atoms/Typography"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { CommonLink } from "@/client/ui/atoms/NavLink/CommonLink"; +import { Paper } from "@/client/ui/atoms/Paper"; import { Form, FormConfig, FormData } from "@/client/ui/molecules/Form/Form"; export const RegisterPage = () => { @@ -66,16 +67,22 @@ export const RegisterPage = () => {

{t("form.title")}

- - - {t("prompt-to-sign-in")}{" "} - {t("link-to-sign-in")} - + + + + + {t("prompt-to-sign-in")}{" "} + + {t("link-to-sign-in")} + + +
); diff --git a/src/client/pages/Register/register-page.module.scss b/src/client/pages/auth/Register/register-page.module.scss similarity index 50% rename from src/client/pages/Register/register-page.module.scss rename to src/client/pages/auth/Register/register-page.module.scss index 980aa62..037c4f7 100644 --- a/src/client/pages/Register/register-page.module.scss +++ b/src/client/pages/auth/Register/register-page.module.scss @@ -5,3 +5,12 @@ align-items: center; min-height: 100vh; } + +.Form { + width: 100% !important; + max-width: 100%; + min-width: 400px; + @media (max-width: 500px) { + min-width: auto; + } +} diff --git a/src/client/pages/RequestPasswordReset/RequestPasswordResetPage.tsx b/src/client/pages/auth/RequestPasswordReset/RequestPasswordResetPage.tsx similarity index 72% rename from src/client/pages/RequestPasswordReset/RequestPasswordResetPage.tsx rename to src/client/pages/auth/RequestPasswordReset/RequestPasswordResetPage.tsx index ffb58d1..e6b7144 100644 --- a/src/client/pages/RequestPasswordReset/RequestPasswordResetPage.tsx +++ b/src/client/pages/auth/RequestPasswordReset/RequestPasswordResetPage.tsx @@ -5,9 +5,10 @@ import classes from "./request-password-reset-page.module.scss"; import { paths } from "@/client/config/paths"; import { useAuthContext } from "@/client/contexts/AuthContext"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { H1, Paragraph } from "@/client/ui/atoms/Typography"; import { CommonLink } from "@/client/ui/atoms/NavLink/CommonLink"; +import { Paper } from "@/client/ui/atoms/Paper"; import { Form, FormConfig, FormData } from "@/client/ui/molecules/Form/Form"; export const RequestPasswordResetPage = () => { @@ -45,8 +46,11 @@ export const RequestPasswordResetPage = () => {

{t("form.title")}

- {t("email-sent")} - {t("prompt-to-check-email")} + + + {t("email-sent")} + {t("prompt-to-check-email")} +
); @@ -56,14 +60,21 @@ export const RequestPasswordResetPage = () => {

{t("form.title")}

- - - {t("prompt-to-sign-up")}{" "} - - {t("link-to-sign-up")} - - + + + + + {t("prompt-to-sign-up")}{" "} + + {t("link-to-sign-up")} + + +
); diff --git a/src/client/pages/RequestPasswordReset/request-password-reset-page.module.scss b/src/client/pages/auth/RequestPasswordReset/request-password-reset-page.module.scss similarity index 78% rename from src/client/pages/RequestPasswordReset/request-password-reset-page.module.scss rename to src/client/pages/auth/RequestPasswordReset/request-password-reset-page.module.scss index c2f265f..297a71a 100644 --- a/src/client/pages/RequestPasswordReset/request-password-reset-page.module.scss +++ b/src/client/pages/auth/RequestPasswordReset/request-password-reset-page.module.scss @@ -5,3 +5,7 @@ align-items: center; min-height: 100vh; } + +.Form { + width: 100% !important; +} diff --git a/src/client/pages/ResetPassword/ResetPasswordPage.tsx b/src/client/pages/auth/ResetPassword/ResetPasswordPage.tsx similarity index 78% rename from src/client/pages/ResetPassword/ResetPasswordPage.tsx rename to src/client/pages/auth/ResetPassword/ResetPasswordPage.tsx index fbf971d..218eae8 100644 --- a/src/client/pages/ResetPassword/ResetPasswordPage.tsx +++ b/src/client/pages/auth/ResetPassword/ResetPasswordPage.tsx @@ -6,9 +6,10 @@ import { useSearchParams } from "@/client/useHashLocation"; import { paths } from "@/client/config/paths"; import { useAuthContext } from "@/client/contexts/AuthContext"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { H1, Paragraph } from "@/client/ui/atoms/Typography"; import { Form, FormConfig, FormData } from "@/client/ui/molecules/Form/Form"; +import { Paper } from "@/client/ui/atoms/Paper"; import { CommonLink } from "@/client/ui/atoms/NavLink/CommonLink"; export const ResetPasswordPage = () => { @@ -59,12 +60,15 @@ export const ResetPasswordPage = () => {

{t("form.title")}

- - {t("password-resetted")}{" "} - - {t("link-to-sign-in")} - - + + + + {t("password-resetted")}{" "} + + {t("link-to-sign-in")} + + +
); @@ -74,11 +78,15 @@ export const ResetPasswordPage = () => {

{t("form.title")}

- + + + +
); diff --git a/src/client/pages/ResetPassword/reset-password-page.module.scss b/src/client/pages/auth/ResetPassword/reset-password-page.module.scss similarity index 78% rename from src/client/pages/ResetPassword/reset-password-page.module.scss rename to src/client/pages/auth/ResetPassword/reset-password-page.module.scss index c2f265f..297a71a 100644 --- a/src/client/pages/ResetPassword/reset-password-page.module.scss +++ b/src/client/pages/auth/ResetPassword/reset-password-page.module.scss @@ -5,3 +5,7 @@ align-items: center; min-height: 100vh; } + +.Form { + width: 100% !important; +} diff --git a/src/client/pages/saves/PublicSaves/PublicSavesPage.tsx b/src/client/pages/saves/PublicSaves/PublicSavesPage.tsx index 1e03fee..b52f4a2 100644 --- a/src/client/pages/saves/PublicSaves/PublicSavesPage.tsx +++ b/src/client/pages/saves/PublicSaves/PublicSavesPage.tsx @@ -1,15 +1,13 @@ import { useTranslation } from "react-i18next"; -import classes from "./public-saves-page.module.scss"; - import { useAPIContext } from "@/client/contexts/APIContext"; import { useResource } from "@/client/lib/hooks/useResource"; import { paths } from "@/client/config/paths"; import { H1 } from "@/client/ui/atoms/Typography"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; import { Paginator } from "@/client/ui/molecules/Paginator"; -import { SearchForm } from "@/client/ui/molecules/SearchForm/SearchForm"; +import { SearchForm } from "@/client/ui/molecules/SearchForm"; import { Grid } from "@/client/ui/molecules/Grid"; import { GameStateCard } from "@/client/lib/components/GameStateCard"; @@ -19,7 +17,7 @@ export const PublicSavesPage = () => { const { query, - resource: saves, + resource: gameStates, onSearch, loadResource: loadSaves, setQuery, @@ -36,13 +34,13 @@ export const PublicSavesPage = () => { /> save.gameId} - renderElement={(save) => ( + className="my-4" + elements={gameStates.items} + getKey={(gameState) => gameState.id} + renderElement={(gameState) => ( )} /> @@ -51,7 +49,7 @@ export const PublicSavesPage = () => { scope={3} currentPage={query.pageNumber} pageSize={query.pageSize} - count={saves.totalCount} + count={gameStates.totalCount} onPageSelect={(page) => loadSaves({ ...query, pageNumber: page })} /> diff --git a/src/client/pages/saves/PublicSaves/public-saves-page.module.scss b/src/client/pages/saves/PublicSaves/public-saves-page.module.scss deleted file mode 100644 index 15c2117..0000000 --- a/src/client/pages/saves/PublicSaves/public-saves-page.module.scss +++ /dev/null @@ -1,3 +0,0 @@ -.SavesList { - margin: 0.5rem 0; -} diff --git a/src/client/pages/saves/Save/SavePage.tsx b/src/client/pages/saves/Save/SavePage.tsx index fb5a793..0be0bb8 100644 --- a/src/client/pages/saves/Save/SavePage.tsx +++ b/src/client/pages/saves/Save/SavePage.tsx @@ -8,11 +8,12 @@ import { GameState } from "@/types"; import { useAPIContext } from "@/client/contexts/APIContext"; import { useUIContext } from "@/client/contexts/UIContext"; +import { Bytes } from "@/client/ui/atoms/Bytes"; +import { Paper } from "@/client/ui/atoms/Paper"; +import { PolyButton } from "@/client/ui/atoms/Button"; +import { Container } from "@/client/ui/atoms/Container"; import { H1, H2, Paragraph } from "@/client/ui/atoms/Typography"; -import { Bytes } from "@/client/ui/atoms/Bytes/Bytes"; -import { Container } from "@/client/ui/atoms/Container/Container"; -import { PolyButton } from "@/client/ui/molecules/PolyButton/PolyButton"; -import { ParametersView } from "@/client/lib/components/ParametersView/ParametersView"; +import { ParametersView } from "@/client/lib/components/ParametersView"; export const SavePage = () => { const { gameStateAPI } = useAPIContext(); @@ -72,19 +73,21 @@ export const SavePage = () => { {gameState?.name || t("save")} -
+
{t("path")}: {gameState?.localPath}
-
+

{t("about")}

- + + + -
+ {t("size")}: @@ -106,7 +109,7 @@ export const SavePage = () => { {t("download")}
-
+
); }; diff --git a/src/client/pages/saves/Save/save-page.module.scss b/src/client/pages/saves/Save/save-page.module.scss index f3629b9..1fc091b 100644 --- a/src/client/pages/saves/Save/save-page.module.scss +++ b/src/client/pages/saves/Save/save-page.module.scss @@ -38,7 +38,4 @@ gap: 0.5rem; align-items: center; padding: 1rem 1rem; - - border: 1px solid var(--deco-color); - border-radius: 6px; } diff --git a/src/client/pages/saves/SharedSaves/SharedSavesPage.tsx b/src/client/pages/saves/SharedSaves/SharedSavesPage.tsx index 128858e..4b3ad4e 100644 --- a/src/client/pages/saves/SharedSaves/SharedSavesPage.tsx +++ b/src/client/pages/saves/SharedSaves/SharedSavesPage.tsx @@ -1,14 +1,12 @@ import { useTranslation } from "react-i18next"; -import classes from "./shared-saves-page.module.scss"; - import { useAPIContext } from "@/client/contexts/APIContext"; import { useResource } from "@/client/lib/hooks/useResource"; import { paths } from "@/client/config/paths"; import { H1 } from "@/client/ui/atoms/Typography"; -import { Container } from "@/client/ui/atoms/Container/Container"; -import { SearchForm } from "@/client/ui/molecules/SearchForm/SearchForm"; +import { Container } from "@/client/ui/atoms/Container"; +import { SearchForm } from "@/client/ui/molecules/SearchForm"; import { Paginator } from "@/client/ui/molecules/Paginator"; import { Grid } from "@/client/ui/molecules/Grid"; import { GameStateCard } from "@/client/lib/components/GameStateCard"; @@ -19,7 +17,7 @@ export const SharedSavesPage = () => { const { query, - resource: saves, + resource: gameStates, onSearch, loadResource: loadSaves, setQuery, @@ -36,13 +34,13 @@ export const SharedSavesPage = () => { /> save.gameId} - renderElement={(save) => ( + className="my-4" + elements={gameStates.items} + getKey={(gameState) => gameState.id} + renderElement={(gameState) => ( )} /> @@ -51,7 +49,7 @@ export const SharedSavesPage = () => { scope={3} currentPage={query.pageNumber} pageSize={query.pageSize} - count={saves.totalCount} + count={gameStates.totalCount} onPageSelect={(page) => loadSaves({ ...query, pageNumber: page })} /> diff --git a/src/client/pages/saves/SharedSaves/shared-saves-page.module.scss b/src/client/pages/saves/SharedSaves/shared-saves-page.module.scss deleted file mode 100644 index 15c2117..0000000 --- a/src/client/pages/saves/SharedSaves/shared-saves-page.module.scss +++ /dev/null @@ -1,3 +0,0 @@ -.SavesList { - margin: 0.5rem 0; -} diff --git a/src/client/styles/utility.css b/src/client/styles/utility.css index 5fd1ce1..e9f9b2c 100644 --- a/src/client/styles/utility.css +++ b/src/client/styles/utility.css @@ -1,3 +1,268 @@ .tac { text-align: center; } + +/* Margins. Exported from Tailwind.CSS */ +.m-0 { + margin: 0px; +} +.mx-0 { + margin-left: 0px; + margin-right: 0px; +} +.my-0 { + margin-top: 0px; + margin-bottom: 0px; +} +.mt-0 { + margin-top: 0px; +} +.mr-0 { + margin-right: 0px; +} +.mb-0 { + margin-bottom: 0px; +} +.ml-0 { + margin-left: 0px; +} +.m-px { + margin: 1px; +} +.mx-px { + margin-left: 1px; + margin-right: 1px; +} +.my-px { + margin-top: 1px; + margin-bottom: 1px; +} +.mt-px { + margin-top: 1px; +} +.mr-px { + margin-right: 1px; +} +.mb-px { + margin-bottom: 1px; +} +.ml-px { + margin-left: 1px; +} + +.m-1 { + margin: 0.25rem; +} /* 4px */ +.mx-1 { + margin-left: 0.25rem; + margin-right: 0.25rem; +} /* 4px */ +.my-1 { + margin-top: 0.25rem; + margin-bottom: 0.25rem; +} /* 4px */ +.mt-1 { + margin-top: 0.25rem; +} /* 4px */ +.mr-1 { + margin-right: 0.25rem; +} /* 4px */ +.mb-1 { + margin-bottom: 0.25rem; +} /* 4px */ +.ml-1 { + margin-left: 0.25rem; +} /* 4px */ + +.m-2 { + margin: 0.5rem; +} /* 8px */ +.mx-2 { + margin-left: 0.5rem; + margin-right: 0.5rem; +} /* 8px */ +.my-2 { + margin-top: 0.5rem; + margin-bottom: 0.5rem; +} /* 8px */ +.mt-2 { + margin-top: 0.5rem; +} /* 8px */ +.mr-2 { + margin-right: 0.5rem; +} /* 8px */ +.mb-2 { + margin-bottom: 0.5rem; +} /* 8px */ +.ml-2 { + margin-left: 0.5rem; +} /* 8px */ + +.m-3 { + margin: 0.75rem; +} /* 12px */ +.mx-3 { + margin-left: 0.75rem; + margin-right: 0.75rem; +} /* 12px */ +.my-3 { + margin-top: 0.75rem; + margin-bottom: 0.75rem; +} /* 12px */ +.mt-3 { + margin-top: 0.75rem; +} /* 12px */ +.mr-3 { + margin-right: 0.75rem; +} /* 12px */ +.mb-3 { + margin-bottom: 0.75rem; +} /* 12px */ +.ml-3 { + margin-left: 0.75rem; +} /* 12px */ + +.m-4 { + margin: 1rem; +} /* 16px */ +.mx-4 { + margin-left: 1rem; + margin-right: 1rem; +} /* 16px */ +.my-4 { + margin-top: 1rem; + margin-bottom: 1rem; +} /* 16px */ +.mt-4 { + margin-top: 1rem; +} /* 16px */ +.mr-4 { + margin-right: 1rem; +} /* 16px */ +.mb-4 { + margin-bottom: 1rem; +} /* 16px */ +.ml-4 { + margin-left: 1rem; +} /* 16px */ +.m-5 { + margin: 1.25rem; +} /* 20px */ +.mx-5 { + margin-left: 1.25rem; + margin-right: 1.25rem; +} /* 20px */ +.my-5 { + margin-top: 1.25rem; + margin-bottom: 1.25rem; +} /* 20px */ +.mt-5 { + margin-top: 1.25rem; +} /* 20px */ +.mr-5 { + margin-right: 1.25rem; +} /* 20px */ +.mb-5 { + margin-bottom: 1.25rem; +} /* 20px */ +.ml-5 { + margin-left: 1.25rem; +} /* 20px */ +.m-6 { + margin: 1.5rem; +} /* 24px */ +.mx-6 { + margin-left: 1.5rem; + margin-right: 1.5rem; +} /* 24px */ +.my-6 { + margin-top: 1.5rem; + margin-bottom: 1.5rem; +} /* 24px */ +.mt-6 { + margin-top: 1.5rem; +} /* 24px */ +.mr-6 { + margin-right: 1.5rem; +} /* 24px */ +.mb-6 { + margin-bottom: 1.5rem; +} /* 24px */ +.ml-6 { + margin-left: 1.5rem; +} /* 24px */ +.m-7 { + margin: 1.75rem; +} /* 28px */ +.mx-7 { + margin-left: 1.75rem; + margin-right: 1.75rem; +} /* 28px */ +.my-7 { + margin-top: 1.75rem; + margin-bottom: 1.75rem; +} /* 28px */ +.mt-7 { + margin-top: 1.75rem; +} /* 28px */ +.mr-7 { + margin-right: 1.75rem; +} /* 28px */ +.mb-7 { + margin-bottom: 1.75rem; +} /* 28px */ +.ml-7 { + margin-left: 1.75rem; +} /* 28px */ +.m-8 { + margin: 2rem; +} /* 32px */ +.mx-8 { + margin-left: 2rem; + margin-right: 2rem; +} /* 32px */ +.my-8 { + margin-top: 2rem; + margin-bottom: 2rem; +} /* 32px */ +.mt-8 { + margin-top: 2rem; +} /* 32px */ +.mr-8 { + margin-right: 2rem; +} /* 32px */ +.mb-8 { + margin-bottom: 2rem; +} /* 32px */ +.ml-8 { + margin-left: 2rem; +} /* 32px */ +.m-auto { + margin: auto; +} +.mx-auto { + margin-left: auto; + margin-right: auto; +} +.my-auto { + margin-top: auto; + margin-bottom: auto; +} +.ms-auto { + margin-inline-start: auto; +} +.me-auto { + margin-inline-end: auto; +} +.mt-auto { + margin-top: auto; +} +.mr-auto { + margin-right: auto; +} +.mb-auto { + margin-bottom: auto; +} +.ml-auto { + margin-left: auto; +} diff --git a/src/client/ui/molecules/BurgerButton/burger-button.module.scss b/src/client/ui/atoms/Button/BurgerButton/burger-button.module.scss similarity index 100% rename from src/client/ui/molecules/BurgerButton/burger-button.module.scss rename to src/client/ui/atoms/Button/BurgerButton/burger-button.module.scss diff --git a/src/client/ui/molecules/BurgerButton/index.tsx b/src/client/ui/atoms/Button/BurgerButton/index.tsx similarity index 100% rename from src/client/ui/molecules/BurgerButton/index.tsx rename to src/client/ui/atoms/Button/BurgerButton/index.tsx diff --git a/src/client/ui/molecules/ConfirmButton/ConfirmButton.tsx b/src/client/ui/atoms/Button/ConfirmButton/ConfirmButton.tsx similarity index 72% rename from src/client/ui/molecules/ConfirmButton/ConfirmButton.tsx rename to src/client/ui/atoms/Button/ConfirmButton/ConfirmButton.tsx index c8c12f5..3a2fba6 100644 --- a/src/client/ui/molecules/ConfirmButton/ConfirmButton.tsx +++ b/src/client/ui/atoms/Button/ConfirmButton/ConfirmButton.tsx @@ -1,5 +1,5 @@ -import { Button, ButtonProps } from "@/client/ui/atoms/Button/Button"; -import { useConfirmModal } from "../../hooks/useConfirmModal/useConfirmModal"; +import { Button, ButtonProps } from "@/client/ui/atoms/Button"; +import { useConfirmModal } from "../../../hooks/useConfirmModal/useConfirmModal"; export type ConfirmButtonProps = Omit< ButtonProps, diff --git a/src/client/ui/molecules/PolyButton/PolyButton.tsx b/src/client/ui/atoms/Button/PolyButton/PolyButton.tsx similarity index 95% rename from src/client/ui/molecules/PolyButton/PolyButton.tsx rename to src/client/ui/atoms/Button/PolyButton/PolyButton.tsx index d5a9c8b..2d669a1 100644 --- a/src/client/ui/molecules/PolyButton/PolyButton.tsx +++ b/src/client/ui/atoms/Button/PolyButton/PolyButton.tsx @@ -2,7 +2,7 @@ import { useRef, useState } from "react"; import { clsx } from "clsx"; import classes from "./poly-button.module.scss"; -import { useOnClickOutside } from "../../hooks/useOnClickOutside"; +import { useOnClickOutside } from "../../../hooks/useOnClickOutside"; export type PolyButtonProps = { className?: string; diff --git a/src/client/ui/atoms/Button/PolyButton/index.ts b/src/client/ui/atoms/Button/PolyButton/index.ts new file mode 100644 index 0000000..5169fa3 --- /dev/null +++ b/src/client/ui/atoms/Button/PolyButton/index.ts @@ -0,0 +1 @@ +export * from "./PolyButton"; diff --git a/src/client/ui/molecules/PolyButton/poly-button.module.scss b/src/client/ui/atoms/Button/PolyButton/poly-button.module.scss similarity index 100% rename from src/client/ui/molecules/PolyButton/poly-button.module.scss rename to src/client/ui/atoms/Button/PolyButton/poly-button.module.scss diff --git a/src/client/ui/atoms/Button/index.ts b/src/client/ui/atoms/Button/index.ts new file mode 100644 index 0000000..d1a34f9 --- /dev/null +++ b/src/client/ui/atoms/Button/index.ts @@ -0,0 +1,5 @@ +export * from "./Button"; +export * from "./CTAButton"; +export * from "./BurgerButton"; +export * from "./PolyButton"; +export * from "./ConfirmButton/ConfirmButton"; diff --git a/src/client/ui/atoms/Bytes/index.ts b/src/client/ui/atoms/Bytes/index.ts new file mode 100644 index 0000000..ad54f55 --- /dev/null +++ b/src/client/ui/atoms/Bytes/index.ts @@ -0,0 +1 @@ +export * from "./Bytes"; diff --git a/src/client/ui/atoms/Container/index.ts b/src/client/ui/atoms/Container/index.ts new file mode 100644 index 0000000..a75e925 --- /dev/null +++ b/src/client/ui/atoms/Container/index.ts @@ -0,0 +1 @@ +export * from "./Container"; diff --git a/src/client/ui/atoms/Input/index.ts b/src/client/ui/atoms/Input/index.ts new file mode 100644 index 0000000..be66d76 --- /dev/null +++ b/src/client/ui/atoms/Input/index.ts @@ -0,0 +1 @@ +export * from "./Input"; diff --git a/src/client/ui/atoms/Input/input.module.scss b/src/client/ui/atoms/Input/input.module.scss index 41763a5..13e4186 100644 --- a/src/client/ui/atoms/Input/input.module.scss +++ b/src/client/ui/atoms/Input/input.module.scss @@ -3,7 +3,7 @@ padding: 0.5rem; font-size: 1rem; color: var(--text-color); - background-color: var(--background-color); + background-color: var(--paper-color); border: 2px solid var(--deco-color); border-radius: 6px; outline: none; diff --git a/src/client/ui/atoms/Paper/index.ts b/src/client/ui/atoms/Paper/index.ts new file mode 100644 index 0000000..0cb9213 --- /dev/null +++ b/src/client/ui/atoms/Paper/index.ts @@ -0,0 +1 @@ +export * from "./Paper"; diff --git a/src/client/ui/atoms/Paper/paper.module.scss b/src/client/ui/atoms/Paper/paper.module.scss index 3eac18c..2d7b86d 100644 --- a/src/client/ui/atoms/Paper/paper.module.scss +++ b/src/client/ui/atoms/Paper/paper.module.scss @@ -1,7 +1,5 @@ .Paper { - padding-top: 0.75rem; - padding-bottom: 0.75rem; - padding-left: 1rem; - padding-right: 1rem; - background-color: #ffffff; + padding: 0.75rem 1rem; + background-color: var(--paper-color); + border-radius: 6px; } diff --git a/src/client/ui/atoms/Select/AsyncSelect/AsyncEntitySelect.tsx b/src/client/ui/atoms/Select/AsyncSelect/AsyncEntitySelect.tsx index 07c2aa3..76cb113 100644 --- a/src/client/ui/atoms/Select/AsyncSelect/AsyncEntitySelect.tsx +++ b/src/client/ui/atoms/Select/AsyncSelect/AsyncEntitySelect.tsx @@ -7,7 +7,14 @@ type Callback = (res: SelectOption[]) => void; export type AsyncEntitySelectProps = Pick< AsyncSelectProps, - "option" | "onChange" | "onBlur" | "id" | "name" | "disabled" | "placeholder" + | "option" + | "onChange" + | "onBlur" + | "id" + | "name" + | "disabled" + | "placeholder" + | "className" > & { loadOptions: (inputValue: string) => Promise[]>; }; @@ -60,6 +67,7 @@ export function AsyncEntitySelect(props: AsyncEntitySelectProps) { onBlur={props.onBlur} disabled={props.disabled} placeholder={props.placeholder} + className={props.className} /> ); } diff --git a/src/client/ui/atoms/Select/AsyncSelect/AsyncSelect.tsx b/src/client/ui/atoms/Select/AsyncSelect/AsyncSelect.tsx index cd3677d..2ebf2b3 100644 --- a/src/client/ui/atoms/Select/AsyncSelect/AsyncSelect.tsx +++ b/src/client/ui/atoms/Select/AsyncSelect/AsyncSelect.tsx @@ -28,6 +28,7 @@ export type AsyncSelectProps = { id?: string; name?: string; disabled?: boolean; + className?: string; }; export const AsyncSelect = function (props: AsyncSelectProps) { @@ -50,6 +51,7 @@ export const AsyncSelect = function (props: AsyncSelectProps) { menuPlacement="auto" theme={themeFactory} isDisabled={props.disabled} + className={props.className} />
); @@ -61,8 +63,12 @@ function themeFactory(theme: Theme) { borderRadius: 16, colors: { ...theme.colors, - primary: "var(--accent-color)", + primary: "var(--accent-color)", // border color on focus primary25: "var(--deco-color)", + primary50: "var(--accent-hover-color)", // background on press + neutral0: "var(--paper-color)", // background + neutral20: "var(--deco-color)", // border + neutral30: "var(--deco-color)", }, }; } diff --git a/src/client/ui/atoms/Select/AsyncSelect/async-select.module.scss b/src/client/ui/atoms/Select/AsyncSelect/async-select.module.scss index 25b5291..772e2b2 100644 --- a/src/client/ui/atoms/Select/AsyncSelect/async-select.module.scss +++ b/src/client/ui/atoms/Select/AsyncSelect/async-select.module.scss @@ -5,6 +5,7 @@ overflow: hidden; border-width: 2px; border-radius: 6px; + // border-color: var(--deco-color); } // Control diff --git a/src/client/ui/atoms/Select/select.module.scss b/src/client/ui/atoms/Select/select.module.scss index b3c3986..eb00709 100644 --- a/src/client/ui/atoms/Select/select.module.scss +++ b/src/client/ui/atoms/Select/select.module.scss @@ -6,7 +6,7 @@ font-family: inherit; font-size: 1rem; color: var(--text-color); - background-color: var(--background-color); + background-color: var(--paper-color); line-height: 1; outline: none; transition: border-color 0.1s ease; diff --git a/src/client/ui/hooks/useConfirmModal/useConfirmModal.tsx b/src/client/ui/hooks/useConfirmModal/useConfirmModal.tsx index 632b600..0f27ccd 100644 --- a/src/client/ui/hooks/useConfirmModal/useConfirmModal.tsx +++ b/src/client/ui/hooks/useConfirmModal/useConfirmModal.tsx @@ -2,8 +2,8 @@ import { useState } from "react"; import classes from "./confirm-modal.module.scss"; -import { Modal } from "../../molecules/Modal/Modal"; -import { Button } from "../../atoms/Button/Button"; +import { Modal } from "../../molecules/Modal"; +import { Button } from "../../atoms/Button"; export type UseConfirmModalArgs = { onConfirm?: () => void; diff --git a/src/client/ui/hooks/useModal.tsx b/src/client/ui/hooks/useModal.tsx index 62d0156..b25523a 100644 --- a/src/client/ui/hooks/useModal.tsx +++ b/src/client/ui/hooks/useModal.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; -import { Modal } from "@/client/ui/molecules/Modal/Modal"; +import { Modal } from "@/client/ui/molecules/Modal"; import { ReactTagProps } from "@/client/ui/types"; export type UseModalArgs = { diff --git a/src/client/ui/molecules/AppErrorBoundary.tsx b/src/client/ui/molecules/AppErrorBoundary.tsx index a0127e3..c6dc897 100644 --- a/src/client/ui/molecules/AppErrorBoundary.tsx +++ b/src/client/ui/molecules/AppErrorBoundary.tsx @@ -2,7 +2,7 @@ import { Component, ErrorInfo } from "react"; import { H1 } from "@/client/ui/atoms/Typography"; import { CTAButton } from "@/client/ui/atoms/Button/CTAButton"; -import { Container } from "@/client/ui/atoms/Container/Container"; +import { Container } from "@/client/ui/atoms/Container"; export type AppErrorBoundaryProps = { children: React.ReactNode; diff --git a/src/client/ui/molecules/Field/InputField.tsx b/src/client/ui/molecules/Field/InputField.tsx index 44d77a0..539bdb4 100644 --- a/src/client/ui/molecules/Field/InputField.tsx +++ b/src/client/ui/molecules/Field/InputField.tsx @@ -1,6 +1,6 @@ import React, { forwardRef, useId } from "react"; -import { Input, InputProps } from "@/client/ui/atoms/Input/Input"; +import { Input, InputProps } from "@/client/ui/atoms/Input"; import { Field } from "./Field"; export type InputFieldProps = { diff --git a/src/client/ui/molecules/Field/field.module.scss b/src/client/ui/molecules/Field/field.module.scss index 4874144..169a693 100644 --- a/src/client/ui/molecules/Field/field.module.scss +++ b/src/client/ui/molecules/Field/field.module.scss @@ -1,7 +1,7 @@ .Field { width: 100%; display: block; - padding: 0.5rem 0; + margin: 0.5rem 0; } .label { diff --git a/src/client/ui/molecules/Form/Form.tsx b/src/client/ui/molecules/Form/Form.tsx index 8dd3481..2827518 100644 --- a/src/client/ui/molecules/Form/Form.tsx +++ b/src/client/ui/molecules/Form/Form.tsx @@ -13,8 +13,8 @@ import { useForm, } from "react-hook-form"; import { CTAButton } from "@/client/ui/atoms/Button/CTAButton"; -import { Button } from "../../atoms/Button/Button"; -import { Input } from "@/client/ui/atoms/Input/Input"; +import { Button } from "../../atoms/Button"; +import { Input } from "@/client/ui/atoms/Input"; import { ErrorText } from "@/client/ui/atoms/ErrorText/ErrorText"; import { AsyncEntitySelect } from "@/client/ui/atoms/Select/AsyncSelect/AsyncEntitySelect"; @@ -93,7 +93,6 @@ export function Form(props: FormProps) { reset(); } catch (error) { console.error(error); - alert(error); } finally { setIsLoading(false); } diff --git a/src/client/ui/molecules/Grid/Grid.tsx b/src/client/ui/molecules/Grid/Grid.tsx index 9be4ed0..20feae5 100644 --- a/src/client/ui/molecules/Grid/Grid.tsx +++ b/src/client/ui/molecules/Grid/Grid.tsx @@ -1,6 +1,7 @@ import { clsx } from "clsx"; import classes from "./grid.module.scss"; +import { Paper } from "../../atoms/Paper"; export type GridProps = { elements: E[]; @@ -14,11 +15,10 @@ export function Grid(props: GridProps) { return (
    {props.elements.map((element) => ( -
  • - {props.renderElement(element)} +
  • + + {props.renderElement(element)} +
  • ))}
diff --git a/src/client/ui/molecules/Grid/grid.module.scss b/src/client/ui/molecules/Grid/grid.module.scss index 97beca9..0f35bd7 100644 --- a/src/client/ui/molecules/Grid/grid.module.scss +++ b/src/client/ui/molecules/Grid/grid.module.scss @@ -1,12 +1,11 @@ .Grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 0.75rem; + gap: 1rem; align-items: center; list-style: none; } .GridElement { - border: 1px solid var(--deco-color); - border-radius: 6px; + padding: 0; } diff --git a/src/client/ui/molecules/List/List.tsx b/src/client/ui/molecules/List/List.tsx index 639d84c..52696c6 100644 --- a/src/client/ui/molecules/List/List.tsx +++ b/src/client/ui/molecules/List/List.tsx @@ -1,6 +1,7 @@ import { clsx } from "clsx"; import classes from "./list.module.scss"; +import { Paper } from "../../atoms/Paper"; export type ListProps = { elements: E[]; @@ -14,11 +15,10 @@ export function List(props: ListProps) { return (
    {props.elements.map((element) => ( -
  • - {props.renderElement(element)} +
  • + + {props.renderElement(element)} +
  • ))}
diff --git a/src/client/ui/molecules/List/list.module.scss b/src/client/ui/molecules/List/list.module.scss index 846faa4..89cbe71 100644 --- a/src/client/ui/molecules/List/list.module.scss +++ b/src/client/ui/molecules/List/list.module.scss @@ -1,7 +1,7 @@ .List { display: flex; flex-direction: column; - gap: 0.5rem; + gap: 1rem; list-style: none; } @@ -9,8 +9,4 @@ display: flex; gap: 0.25rem; align-items: center; - padding: 1rem; - border: 1px solid var(--deco-color); - border-radius: 6px; - color: var(--text-color); } diff --git a/src/client/ui/molecules/Modal/Modal.tsx b/src/client/ui/molecules/Modal/Modal.tsx index 1981d9c..708b30e 100644 --- a/src/client/ui/molecules/Modal/Modal.tsx +++ b/src/client/ui/molecules/Modal/Modal.tsx @@ -4,7 +4,7 @@ import classes from "./modal.module.scss"; import { ReactTagProps } from "@/client/ui/types"; -import { Button } from "@/client/ui/atoms/Button/Button"; +import { Button } from "@/client/ui/atoms/Button"; import { ModalPortal } from "./Portal"; export type ModalProps = { diff --git a/src/client/ui/molecules/Modal/modal.module.scss b/src/client/ui/molecules/Modal/modal.module.scss index d512035..11a94e9 100644 --- a/src/client/ui/molecules/Modal/modal.module.scss +++ b/src/client/ui/molecules/Modal/modal.module.scss @@ -35,7 +35,7 @@ max-width: 1200px; min-width: 120px; padding: 0.75rem 0.5rem; - background-color: var(--background-color); + background-color: var(--paper-color); border-radius: 6px; transform: scale3d(0.9, 0.9, 1); diff --git a/src/client/ui/molecules/PolyButton/index.ts b/src/client/ui/molecules/PolyButton/index.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/client/ui/molecules/SearchForm/SearchForm.tsx b/src/client/ui/molecules/SearchForm/SearchForm.tsx index 99aad33..01792b8 100644 --- a/src/client/ui/molecules/SearchForm/SearchForm.tsx +++ b/src/client/ui/molecules/SearchForm/SearchForm.tsx @@ -1,8 +1,8 @@ import classes from "./search-form.module.scss"; import SearchIcon from "@/client/ui/icons/Search.svg"; -import { Button } from "@/client/ui/atoms/Button/Button"; -import { Input } from "@/client/ui/atoms/Input/Input"; +import { Button } from "@/client/ui/atoms/Button"; +import { Input } from "@/client/ui/atoms/Input"; export type SearchFormProps = { searchQuery: string; diff --git a/src/client/ui/molecules/SearchForm/index.ts b/src/client/ui/molecules/SearchForm/index.ts new file mode 100644 index 0000000..2ff8a53 --- /dev/null +++ b/src/client/ui/molecules/SearchForm/index.ts @@ -0,0 +1 @@ +export * from "./SearchForm"; diff --git a/src/client/ui/molecules/Spoiler/spoiler.module.scss b/src/client/ui/molecules/Spoiler/spoiler.module.scss index 8eed102..a1d7577 100644 --- a/src/client/ui/molecules/Spoiler/spoiler.module.scss +++ b/src/client/ui/molecules/Spoiler/spoiler.module.scss @@ -17,7 +17,7 @@ .SpoilerContent { width: 100%; - background-color: var(--background-color); + background-color: var(--paper-color); border: 1px solid var(--deco-color); overflow: hidden; max-height: 0; diff --git a/src/client/ui/molecules/ThreeDotsMenu/ThreeDotsMenu.tsx b/src/client/ui/molecules/ThreeDotsMenu/ThreeDotsMenu.tsx index 6834446..68e702d 100644 --- a/src/client/ui/molecules/ThreeDotsMenu/ThreeDotsMenu.tsx +++ b/src/client/ui/molecules/ThreeDotsMenu/ThreeDotsMenu.tsx @@ -43,7 +43,6 @@ export const ThreeDotsMenu = (props: ThreeDotsMenuProps) => { className={classes.ThreeDotsMenuItem} onClick={item.onClick} key={item.key} - aria-role="button" > {item.children} diff --git a/src/client/ui/styles/theme.css b/src/client/ui/styles/theme.css index a341754..7743b32 100644 --- a/src/client/ui/styles/theme.css +++ b/src/client/ui/styles/theme.css @@ -1,5 +1,6 @@ :root { - --background-color: #fff; + --background-color: #f6f8fa; + --paper-color: #fff; --text-color: #000; --accent-color: #ff770f; --accent-hover-color: #f7a76c; @@ -9,7 +10,8 @@ } .dark-theme:root { - --background-color: #000000; + --background-color: #101010; + --paper-color: #000000; --text-color: #f0f0f0; --accent-color: #ff770f; --accent-hover-color: #f7a76c; diff --git a/src/types.ts b/src/types.ts index 7c9aa62..f155996 100644 --- a/src/types.ts +++ b/src/types.ts @@ -64,10 +64,10 @@ export type GamePath = { export enum GameStateSync { NO = "no", - EVERY_HOUR = "every hour", - EVERY_DAY = "every day", - EVERY_WEEK = "every week", - EVERY_MONTH = "every month", + EVERY_HOUR = "every-hour", + EVERY_DAY = "every-day", + EVERY_WEEK = "every-week", + EVERY_MONTH = "every-month", } export type GameStateValue = {