From 0c65a2e4f1901fa454ec5153d237e4258bc44c18 Mon Sep 17 00:00:00 2001 From: joneugster Date: Mon, 16 Oct 2023 15:20:00 +0200 Subject: [PATCH] reorganise popups --- client/src/components/app_bar.tsx | 2 +- client/src/components/landing_page.tsx | 2 +- client/src/components/level.tsx | 2 +- client/src/components/popup/erase.tsx | 60 +++++++++ client/src/components/popup/game_info.tsx | 23 ++++ .../components/{ => popup}/privacy_policy.tsx | 0 client/src/components/popup/rules_help.tsx | 55 ++++++++ client/src/components/popup/upload.tsx | 70 ++++++++++ client/src/components/welcome.tsx | 125 ++---------------- client/src/components/world_tree.tsx | 6 +- 10 files changed, 221 insertions(+), 124 deletions(-) create mode 100644 client/src/components/popup/erase.tsx create mode 100644 client/src/components/popup/game_info.tsx rename client/src/components/{ => popup}/privacy_policy.tsx (100%) create mode 100644 client/src/components/popup/rules_help.tsx create mode 100644 client/src/components/popup/upload.tsx diff --git a/client/src/components/app_bar.tsx b/client/src/components/app_bar.tsx index 175caebf..530636ee 100644 --- a/client/src/components/app_bar.tsx +++ b/client/src/components/app_bar.tsx @@ -8,7 +8,7 @@ import { useAppDispatch, useAppSelector } from '../hooks' import { Button } from './button' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faDownload, faUpload, faEraser, faBook, faBookOpen, faGlobe, faHome, faArrowRight, faArrowLeft, faXmark, faBars, faCode, faCircleInfo, faTerminal } from '@fortawesome/free-solid-svg-icons' -import { PrivacyPolicyPopup } from './privacy_policy' +import { PrivacyPolicyPopup } from './popup/privacy_policy' import { WorldSelectionMenu, downloadFile } from './world_tree' /** navigation to switch between pages on mobile */ diff --git a/client/src/components/landing_page.tsx b/client/src/components/landing_page.tsx index 2d20ab34..b395c89c 100644 --- a/client/src/components/landing_page.tsx +++ b/client/src/components/landing_page.tsx @@ -11,7 +11,7 @@ import coverRobo from '../assets/covers/formaloversum.png' import bgImage from '../assets/bg.jpg' import Markdown from './markdown'; -import {PrivacyPolicyPopup} from './privacy_policy' +import {PrivacyPolicyPopup} from './popup/privacy_policy' const flag = { 'Dutch': '🇳🇱', diff --git a/client/src/components/level.tsx b/client/src/components/level.tsx index 6e5c475e..bcbafd9e 100644 --- a/client/src/components/level.tsx +++ b/client/src/components/level.tsx @@ -33,7 +33,7 @@ import { DeletedChatContext, InputModeContext, MobileContext, MonacoEditorContex import { DualEditor } from './infoview/main' import { GameHint } from './infoview/rpc_api' import { DeletedHints, Hint, Hints } from './hints' -import { PrivacyPolicyPopup } from './privacy_policy' +import { PrivacyPolicyPopup } from './popup/privacy_policy' import '@fontsource/roboto/300.css' import '@fontsource/roboto/400.css' diff --git a/client/src/components/popup/erase.tsx b/client/src/components/popup/erase.tsx new file mode 100644 index 00000000..73088f83 --- /dev/null +++ b/client/src/components/popup/erase.tsx @@ -0,0 +1,60 @@ +/** + * @fileOverview +*/ +import * as React from 'react' +import { useSelector } from 'react-redux' +import { GameIdContext } from '../../app' +import { useAppDispatch } from '../../hooks' +import { deleteProgress, selectProgress } from '../../state/progress' +import { downloadFile } from '../world_tree' +import { Button } from '../button' + + +/** Pop-up to delete game progress. + * + * `handleClose` is the function to close it again because it's open/closed state is + * controlled by the containing element. + */ +export function ErasePopup ({handleClose}) { + const gameId = React.useContext(GameIdContext) + const gameProgress = useSelector(selectProgress(gameId)) + const dispatch = useAppDispatch() + + /** Download the current progress (i.e. what's saved in the browser store) */ + const downloadProgress = (e) => { + e.preventDefault() + downloadFile({ + data: JSON.stringify(gameProgress, null, 2), + fileName: `lean4game-${gameId}-${new Date().toLocaleDateString()}.json`, + fileType: 'text/json', + }) + } + + const eraseProgress = () => { + dispatch(deleteProgress({game: gameId})) + handleClose() + } + + const downloadAndErase = (e) => { + downloadProgress(e) + eraseProgress() + } + + return
+
+
+
+

Delete Progress?

+ +

Do you want to delete your saved progress irreversibly?

+

+ (This deletes your proofs and your collected inventory. + Saves from other games are not deleted.) +

+ + + + +
+
+} diff --git a/client/src/components/popup/game_info.tsx b/client/src/components/popup/game_info.tsx new file mode 100644 index 00000000..6d1898c0 --- /dev/null +++ b/client/src/components/popup/game_info.tsx @@ -0,0 +1,23 @@ +/** + * @fileOverview +*/ +import * as React from 'react' +import { Typography } from '@mui/material' +import Markdown from '../markdown' + +/** Pop-up that is displaying the Game Info. + * + * `handleClose` is the function to close it again because it's open/closed state is + * controlled by the containing element. + */ +export function InfoPopup ({info, handleClose}: {info: string, handleClose: () => void}) { + return
+
+
+
+ + {info} + +
+
+} diff --git a/client/src/components/privacy_policy.tsx b/client/src/components/popup/privacy_policy.tsx similarity index 100% rename from client/src/components/privacy_policy.tsx rename to client/src/components/popup/privacy_policy.tsx diff --git a/client/src/components/popup/rules_help.tsx b/client/src/components/popup/rules_help.tsx new file mode 100644 index 00000000..e4ed1cd4 --- /dev/null +++ b/client/src/components/popup/rules_help.tsx @@ -0,0 +1,55 @@ +/** + * @fileOverview +*/ +import * as React from 'react' + +/** Pop-up that is displayed when opening the help explaining the game rules. + * + * `handleClose` is the function to close it again because it's open/closed state is + * controlled by the containing element. + */ +export function RulesHelpPopup ({handleClose}: {handleClose: () => void}) { + return
+
+
+
+

Game Rules

+

+ Game rules determine if it is allowed to skip levels and if the games runs checks to only + allow unlocked tactics and theorems in proofs. +

+

+ Note: "Unlocked" tactics (or theorems) are determined by two things: The set of minimal + tactics needed to solve a level, plus any tactics you unlocked in another level. That means + if you unlock simp in a level, you can use it henceforth in any level. +

+

The options are:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
levelstactics
regular🔐🔐
relaxed🔓🔐
none🔓🔓
+
+
+} diff --git a/client/src/components/popup/upload.tsx b/client/src/components/popup/upload.tsx new file mode 100644 index 00000000..cfaae8b8 --- /dev/null +++ b/client/src/components/popup/upload.tsx @@ -0,0 +1,70 @@ +/** + * @fileOverview +*/ +import * as React from 'react' +import { useSelector } from 'react-redux' +import { GameIdContext } from '../../app' +import { useAppDispatch } from '../../hooks' +import { GameProgressState, loadProgress, selectProgress } from '../../state/progress' +import { downloadFile } from '../world_tree' +import { Button } from '../button' + +/** Pop-up that is displaying the Game Info. + * + * `handleClose` is the function to close it again because it's open/closed state is + * controlled by the containing element. + */ +export function UploadPopup ({handleClose}) { + const [file, setFile] = React.useState(); + const gameId = React.useContext(GameIdContext) + const gameProgress = useSelector(selectProgress(gameId)) + const dispatch = useAppDispatch() + + const handleFileChange = (e) => { + if (e.target.files) { + setFile(e.target.files[0]) + } + } + + /** Upload progress from a */ + const uploadProgress = (e) => { + if (!file) {return} + const fileReader = new FileReader() + fileReader.readAsText(file, "UTF-8") + fileReader.onload = (e) => { + const data = JSON.parse(e.target.result.toString()) as GameProgressState + console.debug("Json Data", data) + dispatch(loadProgress({game: gameId, data: data})) + } + handleClose() + } + + /** Download the current progress (i.e. what's saved in the browser store) */ + const downloadProgress = (e) => { + e.preventDefault() + downloadFile({ + data: JSON.stringify(gameProgress, null, 2), + fileName: `lean4game-${gameId}-${new Date().toLocaleDateString()}.json`, + fileType: 'text/json', + }) + } + + + return
+
+
+
+

Upload Saved Progress

+ +

Select a JSON file with the saved game progress to load your progress.

+ +

Warning: This will delete your current game progress! + Consider downloading your current progress first!

+

+ +

+ + +
+
+} diff --git a/client/src/components/welcome.tsx b/client/src/components/welcome.tsx index 0efd1bb4..c6e2b53e 100644 --- a/client/src/components/welcome.tsx +++ b/client/src/components/welcome.tsx @@ -1,27 +1,29 @@ import * as React from 'react' import { useState, useEffect } from 'react' -import { useSelector } from 'react-redux' import Split from 'react-split' -import { Box, Typography, CircularProgress } from '@mui/material' +import { Box, CircularProgress } from '@mui/material' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faGlobe, faArrowRight, faArrowLeft } from '@fortawesome/free-solid-svg-icons' import { GameIdContext } from '../app' import { useAppDispatch } from '../hooks' -import { GameProgressState, changedOpenedIntro, deleteProgress, loadProgress, selectOpenedIntro, selectProgress } from '../state/progress' +import { changedOpenedIntro } from '../state/progress' import { useGetGameInfoQuery, useLoadInventoryOverviewQuery } from '../state/api' import { Button } from './button' import { MobileContext } from './infoview/context' import { InventoryPanel } from './inventory' -import Markdown from './markdown' -import { PrivacyPolicyPopup } from './privacy_policy' +import { ErasePopup } from './popup/erase' +import { InfoPopup } from './popup/game_info' +import { PrivacyPolicyPopup } from './popup/privacy_policy' import { RulesHelpPopup } from './popup/rules_help' -import { WorldTreePanel, downloadFile } from './world_tree' +import { UploadPopup } from './popup/upload' +import { WorldTreePanel } from './world_tree' import './welcome.css' import { WelcomeAppBar } from './app_bar' import { Hint } from './hints' + /** The panel showing the game's introduction text */ function IntroductionPanel({introduction}: {introduction: string}) { const {mobile, setPageNumber} = React.useContext(MobileContext) @@ -63,117 +65,6 @@ function IntroductionPanel({introduction}: {introduction: string}) {
} -export function InfoPopup ({info, handleClose}: {info: string, handleClose: () => void}) { - return
-
-
-
- - {info} - -
-
-} - - -function ErasePopup ({handleClose}) { - const gameId = React.useContext(GameIdContext) - const gameProgress = useSelector(selectProgress(gameId)) - const dispatch = useAppDispatch() - - /** Download the current progress (i.e. what's saved in the browser store) */ - const downloadProgress = (e) => { - e.preventDefault() - downloadFile({ - data: JSON.stringify(gameProgress, null, 2), - fileName: `lean4game-${gameId}-${new Date().toLocaleDateString()}.json`, - fileType: 'text/json', - }) - } - - const eraseProgress = () => { - dispatch(deleteProgress({game: gameId})) - handleClose() - } - - const downloadAndErase = (e) => { - downloadProgress(e) - eraseProgress() - } - - return
-
-
-
-

Delete Progress?

- -

Do you want to delete your saved progress irreversibly?

-

- (This deletes your proofs and your collected inventory. - Saves from other games are not deleted.) -

- - - - -
-
-} - -function UploadPopup ({handleClose}) { - const [file, setFile] = React.useState(); - const gameId = React.useContext(GameIdContext) - const gameProgress = useSelector(selectProgress(gameId)) - const dispatch = useAppDispatch() - - const handleFileChange = (e) => { - if (e.target.files) { - setFile(e.target.files[0]) - } - } - - /** Upload progress from a */ - const uploadProgress = (e) => { - if (!file) {return} - const fileReader = new FileReader() - fileReader.readAsText(file, "UTF-8") - fileReader.onload = (e) => { - const data = JSON.parse(e.target.result.toString()) as GameProgressState - console.debug("Json Data", data) - dispatch(loadProgress({game: gameId, data: data})) - } - handleClose() - } - - /** Download the current progress (i.e. what's saved in the browser store) */ - const downloadProgress = (e) => { - e.preventDefault() - downloadFile({ - data: JSON.stringify(gameProgress, null, 2), - fileName: `lean4game-${gameId}-${new Date().toLocaleDateString()}.json`, - fileType: 'text/json', - }) - } - - - return
-
-
-
-

Upload Saved Progress

- -

Select a JSON file with the saved game progress to load your progress.

- -

Warning: This will delete your current game progress! - Consider downloading your current progress first!

- - - - -
-
-} - /** main page of the game showing amoung others the tree of worlds/levels */ function Welcome() { const gameId = React.useContext(GameIdContext) diff --git a/client/src/components/world_tree.tsx b/client/src/components/world_tree.tsx index e5888343..f9db9089 100644 --- a/client/src/components/world_tree.tsx +++ b/client/src/components/world_tree.tsx @@ -8,14 +8,12 @@ import { Slider } from '@mui/material' import cytoscape, { LayoutOptions } from 'cytoscape' import klay from 'cytoscape-klay' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faDownload, faUpload, faEraser, faGlobe, faArrowLeft, faXmark, faCircleQuestion } from '@fortawesome/free-solid-svg-icons' +import { faXmark, faCircleQuestion } from '@fortawesome/free-solid-svg-icons' import { GameIdContext } from '../app' import { useAppDispatch } from '../hooks' -import { deleteProgress, selectProgress, loadProgress, GameProgressState, - selectDifficulty, changedDifficulty, selectCompleted } from '../state/progress' +import { selectDifficulty, changedDifficulty, selectCompleted } from '../state/progress' import { store } from '../state/store' -import { Button } from './button' import './world_tree.css'