NavBar.jsx 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. import React from "react";
  2. import styled from "styled-components";
  3. import { useTranslation } from "react-i18next";
  4. import { useHistory, useRouteMatch } from "react-router-dom";
  5. import { confirmAlert } from "react-confirm-alert";
  6. import { useWire, useBoardConfig } from "react-sync-board";
  7. import UserList from "../../users/UserList";
  8. import Touch from "../../ui/Touch";
  9. import WebConferenceButton from "../../webconf/WebConferenceButton";
  10. import { getBestTranslationFromConfig } from "../../utils/api";
  11. import useLocalStorage from "../../hooks/useLocalStorage";
  12. import InfoModal from "./InfoModal";
  13. import LoadGameModal from "./LoadGameModal";
  14. import LoadSessionModal from "./LoadSessionModal";
  15. import ChangeGameModal from "./ChangeGameModal";
  16. import ExportModal from "./ExportModal";
  17. import SaveExportModal from "./SaveExportModal";
  18. import WelcomeModal from "./WelcomeModal";
  19. import useSession from "../../hooks/useSession";
  20. const StyledNavBar = styled.div.attrs(() => ({ className: "nav" }))`
  21. position: fixed;
  22. top: 0;
  23. width: 100%;
  24. z-index: 205;
  25. background-color: #19202ce0;
  26. box-shadow: 0px 3px 6px #00000029;
  27. color: var(--font-color);
  28. & .nav-center {
  29. display: relative;
  30. & h3 {
  31. position: absolute;
  32. top: 0;
  33. margin: 0;
  34. padding: 0 2em;
  35. background-color: ${({ edit }) =>
  36. edit ? "var(--color-primary)" : "var(--color-blueGrey)"};
  37. box-shadow: 0px 3px 6px #00000029;
  38. line-height: 80px;
  39. letter-spacing: 0px;
  40. font-size: 24px;
  41. text-transform: uppercase;
  42. transform: perspective(280px) rotateX(-20deg);
  43. }
  44. }
  45. & .nav-right,
  46. & .nav-center,
  47. & .nav-left {
  48. align-items: center;
  49. }
  50. & .nav-left {
  51. & > div {
  52. padding-right: 1em;
  53. }
  54. padding-left: 40px;
  55. justify-content: flex-start;
  56. }
  57. & .nav-right {
  58. justify-content: flex-end;
  59. padding-right: 1em;
  60. gap: 1em;
  61. }
  62. & .spacer {
  63. flex: 1;
  64. max-width: 1em;
  65. }
  66. @media screen and (max-width: 640px) {
  67. & .nav-left {
  68. flex: 1;
  69. padding-left: 5px;
  70. & > div {
  71. padding-right: 2px;
  72. }
  73. }
  74. & .nav-center h3 {
  75. position: relative;
  76. padding: 0;
  77. background-color: transparent;
  78. box-shadow: none;
  79. line-height: 1.2em;
  80. font-size: 1.2em;
  81. transform: none;
  82. }
  83. & .nav-right {
  84. display: none;
  85. }
  86. & .spacer {
  87. flex: 0;
  88. }
  89. & {
  90. flex-direction: row;
  91. }
  92. & .save {
  93. display: none;
  94. }
  95. & .info {
  96. margin: 0;
  97. padding: 0;
  98. width: 24px;
  99. height: 24px;
  100. }
  101. & .help {
  102. margin: 0;
  103. padding: 0;
  104. width: 24px;
  105. height: 24px;
  106. }
  107. & h3 {
  108. font-size: 1.2em;
  109. }
  110. }
  111. `;
  112. const NavBar = ({ editMode, title }) => {
  113. const { t, i18n } = useTranslation();
  114. const { sessionId: room } = useSession();
  115. const [boardConfig] = useBoardConfig();
  116. const { isMaster } = useWire("board");
  117. const history = useHistory();
  118. const match = useRouteMatch();
  119. const [showLoadGameModal, setShowLoadGameModal] = React.useState(false);
  120. const [showSaveGameModal, setShowSaveGameModal] = React.useState(false);
  121. const [showChangeGameModal, setShowChangeGameModal] = React.useState(false);
  122. const [showInfoModal, setShowInfoModal] = React.useState(false);
  123. const [showLink, setShowLink] = React.useState(false);
  124. const translation = React.useMemo(
  125. () => getBestTranslationFromConfig(boardConfig, i18n.languages),
  126. [boardConfig, i18n.languages]
  127. );
  128. const handleBack = React.useCallback(() => {
  129. // If inside session
  130. if (match.path === "/session/:sessionId" && history.length > 2) {
  131. // Go to previous if exists
  132. // Previous can be home or studio
  133. // Yes history should be greater than 2 for any reason...
  134. history.goBack();
  135. return;
  136. }
  137. // If inside room, go back to that room
  138. if (match.path === "/room/:roomId/session/:sessionId") {
  139. history.push(`/room/${match.params.roomId}`);
  140. return;
  141. }
  142. // Otherwise, go back to home
  143. history.push("/games");
  144. }, [history, match.params.roomId, match.path]);
  145. const handleBackWithConfirm = React.useCallback(() => {
  146. confirmAlert({
  147. title: t("Confirmation"),
  148. message: t("Do you really want to quit game edition?"),
  149. buttons: [
  150. {
  151. label: t("Yes"),
  152. onClick: async () => {
  153. history.push("/studio");
  154. },
  155. },
  156. {
  157. label: t("No"),
  158. onClick: () => {},
  159. },
  160. ],
  161. });
  162. }, [history, t]);
  163. return (
  164. <>
  165. <StyledNavBar edit={editMode}>
  166. <div className="nav-left">
  167. {!editMode && (
  168. <>
  169. <Touch
  170. onClick={handleBack}
  171. alt={t("Go back")}
  172. title={t("Go back")}
  173. icon={"chevron-left"}
  174. style={{ display: "inline" }}
  175. />
  176. {isMaster && (
  177. <>
  178. <Touch
  179. onClick={() => setShowChangeGameModal((prev) => !prev)}
  180. alt={t("Change game")}
  181. title={t("Change game")}
  182. icon="https://icongr.am/material/cards-playing-outline.svg?size=24&color=f9fbfa"
  183. />
  184. <ChangeGameModal
  185. show={showChangeGameModal}
  186. setShow={setShowChangeGameModal}
  187. />
  188. </>
  189. )}
  190. </>
  191. )}
  192. {editMode && (
  193. <Touch
  194. onClick={handleBackWithConfirm}
  195. alt={t("Go back to studio")}
  196. title={t("Go back to studio")}
  197. icon={"chevron-left"}
  198. style={{ display: "inline" }}
  199. />
  200. )}
  201. </div>
  202. <div className="nav-center">
  203. <h3>
  204. {translation.name ? translation.name : title || "Air Board Game"}
  205. </h3>
  206. </div>
  207. <div className="nav-right">
  208. {!editMode && (
  209. <>
  210. <UserList />
  211. <Touch
  212. onClick={() => {
  213. setShowLink(true);
  214. }}
  215. icon="add-user"
  216. title={t("Invite more player")}
  217. />
  218. <WebConferenceButton room={room} />
  219. </>
  220. )}
  221. <div className="spacer" />
  222. {(isMaster || editMode) && (
  223. <Touch
  224. onClick={() => setShowLoadGameModal((prev) => !prev)}
  225. alt={editMode ? t("Load game") : t("Load session")}
  226. title={editMode ? t("Load game") : t("Load session")}
  227. icon={"upload-to-cloud"}
  228. />
  229. )}
  230. <Touch
  231. onClick={() => setShowSaveGameModal((prev) => !prev)}
  232. alt={t("Save")}
  233. title={editMode ? t("Save game") : t("Save session")}
  234. icon={editMode ? "save" : "download"}
  235. />
  236. <div className="spacer" />
  237. <Touch
  238. onClick={() => setShowInfoModal((prev) => !prev)}
  239. alt={t("Help & info")}
  240. title={t("Help & info")}
  241. icon={"info"}
  242. />
  243. </div>
  244. </StyledNavBar>
  245. <InfoModal show={showInfoModal} setShow={setShowInfoModal} />
  246. {!editMode && (
  247. <WelcomeModal show={showLink} setShow={setShowLink} welcome={false} />
  248. )}
  249. {!editMode && (
  250. <LoadSessionModal
  251. show={showLoadGameModal}
  252. setShow={setShowLoadGameModal}
  253. edit={editMode}
  254. />
  255. )}
  256. {editMode && (
  257. <LoadGameModal
  258. show={showLoadGameModal}
  259. setShow={setShowLoadGameModal}
  260. edit={editMode}
  261. />
  262. )}
  263. {!editMode && (
  264. <ExportModal show={showSaveGameModal} setShow={setShowSaveGameModal} />
  265. )}
  266. {editMode && (
  267. <SaveExportModal
  268. show={showSaveGameModal}
  269. setShow={setShowSaveGameModal}
  270. />
  271. )}
  272. </>
  273. );
  274. };
  275. export default NavBar;