diff options
Diffstat (limited to 'frontend/src/components')
| -rw-r--r-- | frontend/src/components/ConfirmDialog.tsx | 32 | ||||
| -rw-r--r-- | frontend/src/components/Discussions.tsx | 16 | ||||
| -rw-r--r-- | frontend/src/components/GameCategory.tsx | 22 | ||||
| -rw-r--r-- | frontend/src/components/GameEntry.tsx | 6 | ||||
| -rw-r--r-- | frontend/src/components/Leaderboards.tsx | 144 | ||||
| -rw-r--r-- | frontend/src/components/Login.tsx | 10 | ||||
| -rw-r--r-- | frontend/src/components/MapEntry.tsx | 10 | ||||
| -rw-r--r-- | frontend/src/components/MessageDialog.tsx | 30 | ||||
| -rw-r--r-- | frontend/src/components/MessageDialogLoad.tsx | 30 | ||||
| -rw-r--r-- | frontend/src/components/ModMenu.tsx | 18 | ||||
| -rw-r--r-- | frontend/src/components/RankingEntry.tsx | 58 | ||||
| -rw-r--r-- | frontend/src/components/Sidebar.tsx | 42 | ||||
| -rw-r--r-- | frontend/src/components/Summary.tsx | 12 | ||||
| -rw-r--r-- | frontend/src/components/UploadRunDialog.tsx | 22 |
14 files changed, 226 insertions, 226 deletions
diff --git a/frontend/src/components/ConfirmDialog.tsx b/frontend/src/components/ConfirmDialog.tsx index 44a653b..d8784d2 100644 --- a/frontend/src/components/ConfirmDialog.tsx +++ b/frontend/src/components/ConfirmDialog.tsx | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | 2 | ||
| 3 | import "@css/Dialog.css" | 3 | import "@css/Dialog.css" |
| 4 | 4 | ||
| @@ -10,22 +10,22 @@ interface ConfirmDialogProps { | |||
| 10 | }; | 10 | }; |
| 11 | 11 | ||
| 12 | const ConfirmDialog: React.FC<ConfirmDialogProps> = ({ title, subtitle, onConfirm, onCancel }) => { | 12 | const ConfirmDialog: React.FC<ConfirmDialogProps> = ({ title, subtitle, onConfirm, onCancel }) => { |
| 13 | return ( | 13 | return ( |
| 14 | <div className='dimmer'> | 14 | <div className='dimmer'> |
| 15 | <div className='dialog'> | 15 | <div className='dialog'> |
| 16 | <div className='dialog-element dialog-header'> | 16 | <div className='dialog-element dialog-header'> |
| 17 | <span>{title}</span> | 17 | <span>{title}</span> |
| 18 | </div> | ||
| 19 | <div className='dialog-element dialog-description'> | ||
| 20 | <span>{subtitle}</span> | ||
| 21 | </div> | ||
| 22 | <div className='dialog-element dialog-btns-container'> | ||
| 23 | <button onClick={onCancel}>Cancel</button> | ||
| 24 | <button onClick={onConfirm}>Confirm</button> | ||
| 25 | </div> | ||
| 26 | </div> | ||
| 27 | </div> | 18 | </div> |
| 28 | ) | 19 | <div className='dialog-element dialog-description'> |
| 20 | <span>{subtitle}</span> | ||
| 21 | </div> | ||
| 22 | <div className='dialog-element dialog-btns-container'> | ||
| 23 | <button onClick={onCancel}>Cancel</button> | ||
| 24 | <button onClick={onConfirm}>Confirm</button> | ||
| 25 | </div> | ||
| 26 | </div> | ||
| 27 | </div> | ||
| 28 | ) | ||
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | export default ConfirmDialog; | 31 | export default ConfirmDialog; |
diff --git a/frontend/src/components/Discussions.tsx b/frontend/src/components/Discussions.tsx index 17ae586..0c37355 100644 --- a/frontend/src/components/Discussions.tsx +++ b/frontend/src/components/Discussions.tsx | |||
| @@ -1,12 +1,12 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | 2 | ||
| 3 | import { MapDiscussion, MapDiscussions, MapDiscussionsDetail } from '@customTypes/Map'; | 3 | import { MapDiscussion, MapDiscussions, MapDiscussionsDetail } from "@customTypes/Map"; |
| 4 | import { MapDiscussionCommentContent, MapDiscussionContent } from '@customTypes/Content'; | 4 | import { MapDiscussionContent } from "@customTypes/Content"; |
| 5 | import { time_ago } from '@utils/Time'; | 5 | import { time_ago } from "@utils/Time"; |
| 6 | import { API } from '@api/Api'; | 6 | import { API } from "@api/Api"; |
| 7 | import "@css/Maps.css" | 7 | import "@css/Maps.css" |
| 8 | import { Link } from 'react-router-dom'; | 8 | import { Link } from "react-router-dom"; |
| 9 | import useConfirm from '@hooks/UseConfirm'; | 9 | import useConfirm from "@hooks/UseConfirm"; |
| 10 | 10 | ||
| 11 | interface DiscussionsProps { | 11 | interface DiscussionsProps { |
| 12 | token?: string | 12 | token?: string |
| @@ -141,7 +141,7 @@ const Discussions: React.FC<DiscussionsProps> = ({ token, data, isModerator, map | |||
| 141 | data ? | 141 | data ? |
| 142 | (<> | 142 | (<> |
| 143 | {data.discussions.filter(f => f.title.includes(discussionSearch)).sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()) | 143 | {data.discussions.filter(f => f.title.includes(discussionSearch)).sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()) |
| 144 | .map((e, i) => ( | 144 | .map((e) => ( |
| 145 | <div id='discussion-post'> | 145 | <div id='discussion-post'> |
| 146 | <button key={e.id} onClick={() => _open_map_discussion(e.id)}> | 146 | <button key={e.id} onClick={() => _open_map_discussion(e.id)}> |
| 147 | <span>{e.title}</span> | 147 | <span>{e.title}</span> |
diff --git a/frontend/src/components/GameCategory.tsx b/frontend/src/components/GameCategory.tsx index d8879ef..0d76d3e 100644 --- a/frontend/src/components/GameCategory.tsx +++ b/frontend/src/components/GameCategory.tsx | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | import { Link } from "react-router-dom"; | 2 | import { Link } from "react-router-dom"; |
| 3 | 3 | ||
| 4 | import { Game, GameCategoryPortals } from '@customTypes/Game'; | 4 | import { Game, GameCategoryPortals } from "@customTypes/Game"; |
| 5 | import "@css/Games.css" | 5 | import "@css/Games.css" |
| 6 | 6 | ||
| 7 | interface GameCategoryProps { | 7 | interface GameCategoryProps { |
| @@ -10,15 +10,15 @@ interface GameCategoryProps { | |||
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | const GameCategory: React.FC<GameCategoryProps> = ({cat, game}) => { | 12 | const GameCategory: React.FC<GameCategoryProps> = ({cat, game}) => { |
| 13 | return ( | 13 | return ( |
| 14 | <Link className="games-page-item-body-item" to={"/games/" + game.id + "?cat=" + cat.category.id}> | 14 | <Link className="games-page-item-body-item" to={"/games/" + game.id + "?cat=" + cat.category.id}> |
| 15 | <div> | 15 | <div> |
| 16 | <span className='games-page-item-body-item-title'>{cat.category.name}</span> | 16 | <span className='games-page-item-body-item-title'>{cat.category.name}</span> |
| 17 | <br /> | 17 | <br /> |
| 18 | <span className='games-page-item-body-item-num'>{cat.portal_count}</span> | 18 | <span className='games-page-item-body-item-num'>{cat.portal_count}</span> |
| 19 | </div> | 19 | </div> |
| 20 | </Link> | 20 | </Link> |
| 21 | ) | 21 | ) |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | export default GameCategory; | 24 | export default GameCategory; |
diff --git a/frontend/src/components/GameEntry.tsx b/frontend/src/components/GameEntry.tsx index 3bd2842..454efb1 100644 --- a/frontend/src/components/GameEntry.tsx +++ b/frontend/src/components/GameEntry.tsx | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | import { Link } from "react-router-dom"; | 2 | import { Link } from "react-router-dom"; |
| 3 | 3 | ||
| 4 | import { Game, GameCategoryPortals } from '@customTypes/Game'; | 4 | import { Game, GameCategoryPortals } from "@customTypes/Game"; |
| 5 | import "@css/Games.css" | 5 | import "@css/Games.css" |
| 6 | 6 | ||
| 7 | import GameCategory from '@components/GameCategory'; | 7 | import GameCategory from "@components/GameCategory"; |
| 8 | 8 | ||
| 9 | interface GameEntryProps { | 9 | interface GameEntryProps { |
| 10 | game: Game; | 10 | game: Game; |
diff --git a/frontend/src/components/Leaderboards.tsx b/frontend/src/components/Leaderboards.tsx index fb614fa..5d4045a 100644 --- a/frontend/src/components/Leaderboards.tsx +++ b/frontend/src/components/Leaderboards.tsx | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | import { Link, useNavigate } from 'react-router-dom'; | 2 | import { Link, useNavigate } from "react-router-dom"; |
| 3 | 3 | ||
| 4 | import { DownloadIcon, ThreedotIcon } from '@images/Images'; | 4 | import { DownloadIcon, ThreedotIcon } from "@images/Images"; |
| 5 | import { MapLeaderboard } from '@customTypes/Map'; | 5 | import { MapLeaderboard } from "@customTypes/Map"; |
| 6 | import { ticks_to_time, time_ago } from '@utils/Time'; | 6 | import { ticks_to_time, time_ago } from "@utils/Time"; |
| 7 | import { API } from "@api/Api"; | 7 | import { API } from "@api/Api"; |
| 8 | import useMessage from "@hooks/UseMessage"; | 8 | import useMessage from "@hooks/UseMessage"; |
| 9 | import "@css/Maps.css" | 9 | import "@css/Maps.css" |
| @@ -46,80 +46,80 @@ const Leaderboards: React.FC<LeaderboardsProps> = ({ mapID }) => { | |||
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | return ( | 48 | return ( |
| 49 | <div> | 49 | <div> |
| 50 | {MessageDialogComponent} | 50 | {MessageDialogComponent} |
| 51 | <section id='section6' className='summary2'> | 51 | <section id='section6' className='summary2'> |
| 52 | |||
| 53 | <div id='leaderboard-top' | ||
| 54 | style={data.map.is_coop ? { gridTemplateColumns: "7.5% 40% 7.5% 15% 15% 15%" } : { gridTemplateColumns: "7.5% 30% 10% 20% 17.5% 15%" }} | ||
| 55 | > | ||
| 56 | <span>Place</span> | ||
| 57 | 52 | ||
| 58 | {data.map.is_coop ? ( | 53 | <div id='leaderboard-top' |
| 59 | <div id='runner'> | 54 | style={data.map.is_coop ? { gridTemplateColumns: "7.5% 40% 7.5% 15% 15% 15%" } : { gridTemplateColumns: "7.5% 30% 10% 20% 17.5% 15%" }} |
| 60 | <span>Blue</span> | 55 | > |
| 61 | <span>Orange</span> | 56 | <span>Place</span> |
| 62 | </div> | 57 | |
| 63 | ) : ( | 58 | {data.map.is_coop ? ( |
| 64 | <span>Runner</span> | 59 | <div id='runner'> |
| 65 | )} | 60 | <span>Blue</span> |
| 66 | 61 | <span>Orange</span> | |
| 67 | <span>Portals</span> | 62 | </div> |
| 68 | <span>Time</span> | 63 | ) : ( |
| 69 | <span>Date</span> | 64 | <span>Runner</span> |
| 70 | <div id='page-number'> | 65 | )} |
| 71 | <div> | 66 | |
| 72 | 67 | <span>Portals</span> | |
| 73 | <button onClick={() => pageNumber === 1 ? null : setPageNumber(prevPageNumber => prevPageNumber - 1)} | 68 | <span>Time</span> |
| 74 | ><i className='triangle' style={{ position: 'relative', left: '-5px', }}></i> </button> | 69 | <span>Date</span> |
| 75 | <span>{data.pagination.current_page}/{data.pagination.total_pages}</span> | 70 | <div id='page-number'> |
| 76 | <button onClick={() => pageNumber === data.pagination.total_pages ? null : setPageNumber(prevPageNumber => prevPageNumber + 1)} | 71 | <div> |
| 77 | ><i className='triangle' style={{ position: 'relative', left: '5px', transform: 'rotate(180deg)' }}></i> </button> | 72 | |
| 73 | <button onClick={() => pageNumber === 1 ? null : setPageNumber(prevPageNumber => prevPageNumber - 1)} | ||
| 74 | ><i className='triangle' style={{ position: "relative", left: "-5px", }}></i> </button> | ||
| 75 | <span>{data.pagination.current_page}/{data.pagination.total_pages}</span> | ||
| 76 | <button onClick={() => pageNumber === data.pagination.total_pages ? null : setPageNumber(prevPageNumber => prevPageNumber + 1)} | ||
| 77 | ><i className='triangle' style={{ position: "relative", left: "5px", transform: "rotate(180deg)" }}></i> </button> | ||
| 78 | </div> | ||
| 78 | </div> | 79 | </div> |
| 79 | </div> | 80 | </div> |
| 80 | </div> | 81 | <hr /> |
| 81 | <hr /> | 82 | <div id='leaderboard-records'> |
| 82 | <div id='leaderboard-records'> | 83 | {data.records.map((r, index) => ( |
| 83 | {data.records.map((r, index) => ( | 84 | <span className='leaderboard-record' key={index} |
| 84 | <span className='leaderboard-record' key={index} | 85 | style={data.map.is_coop ? { gridTemplateColumns: "3% 4.5% 40% 4% 3.5% 15% 15% 14.5%" } : { gridTemplateColumns: "3% 4.5% 30% 4% 6% 20% 17% 15%" }} |
| 85 | style={data.map.is_coop ? { gridTemplateColumns: "3% 4.5% 40% 4% 3.5% 15% 15% 14.5%" } : { gridTemplateColumns: "3% 4.5% 30% 4% 6% 20% 17% 15%" }} | 86 | > |
| 86 | > | 87 | <span>{r.placement}</span> |
| 87 | <span>{r.placement}</span> | 88 | <span> </span> |
| 88 | <span> </span> | 89 | {r.kind === "multiplayer" ? ( |
| 89 | {r.kind === "multiplayer" ? ( | 90 | <div> |
| 90 | <div> | ||
| 91 | <Link to={`/users/${r.host.steam_id}`}><span><img src={r.host.avatar_link} alt='' /> {r.host.user_name}</span></Link> | 91 | <Link to={`/users/${r.host.steam_id}`}><span><img src={r.host.avatar_link} alt='' /> {r.host.user_name}</span></Link> |
| 92 | <Link to={`/users/${r.partner.steam_id}`}><span><img src={r.partner.avatar_link} alt='' /> {r.partner.user_name}</span></Link> | 92 | <Link to={`/users/${r.partner.steam_id}`}><span><img src={r.partner.avatar_link} alt='' /> {r.partner.user_name}</span></Link> |
| 93 | </div> | 93 | </div> |
| 94 | ) : r.kind === "singleplayer" && ( | 94 | ) : r.kind === "singleplayer" && ( |
| 95 | <div> | 95 | <div> |
| 96 | <Link to={`/users/${r.user.steam_id}`}><span><img src={r.user.avatar_link} alt='' /> {r.user.user_name}</span></Link> | 96 | <Link to={`/users/${r.user.steam_id}`}><span><img src={r.user.avatar_link} alt='' /> {r.user.user_name}</span></Link> |
| 97 | </div> | 97 | </div> |
| 98 | )} | 98 | )} |
| 99 | 99 | ||
| 100 | <span>{r.score_count}</span> | 100 | <span>{r.score_count}</span> |
| 101 | <span> </span> | 101 | <span> </span> |
| 102 | <span className='hover-popup' popup-text={(r.score_time) + " ticks"}>{ticks_to_time(r.score_time)}</span> | 102 | <span className='hover-popup' popup-text={(r.score_time) + " ticks"}>{ticks_to_time(r.score_time)}</span> |
| 103 | <span className='hover-popup' popup-text={r.record_date.replace("T", ' ').split(".")[0]}>{time_ago(new Date(r.record_date.replace("T", " ").replace("Z", "")))}</span> | 103 | <span className='hover-popup' popup-text={r.record_date.replace("T", " ").split(".")[0]}>{time_ago(new Date(r.record_date.replace("T", " ").replace("Z", "")))}</span> |
| 104 | 104 | ||
| 105 | {r.kind === "multiplayer" ? ( | 105 | {r.kind === "multiplayer" ? ( |
| 106 | <span> | 106 | <span> |
| 107 | <button onClick={() => { message("Demo Information", `Host Demo ID: ${r.host_demo_id} \nParnter Demo ID: ${r.partner_demo_id}`) }}><img src={ThreedotIcon} alt="demo_id" /></button> | 107 | <button onClick={() => { message("Demo Information", `Host Demo ID: ${r.host_demo_id} \nParnter Demo ID: ${r.partner_demo_id}`) }}><img src={ThreedotIcon} alt="demo_id" /></button> |
| 108 | <button onClick={() => window.location.href = `/api/v1/demos?uuid=${r.partner_demo_id}`}><img src={DownloadIcon} alt="download" style={{ filter: "hue-rotate(160deg) contrast(60%) saturate(1000%)" }} /></button> | 108 | <button onClick={() => window.location.href = `/api/v1/demos?uuid=${r.partner_demo_id}`}><img src={DownloadIcon} alt="download" style={{ filter: "hue-rotate(160deg) contrast(60%) saturate(1000%)" }} /></button> |
| 109 | <button onClick={() => window.location.href = `/api/v1/demos?uuid=${r.host_demo_id}`}><img src={DownloadIcon} alt="download" style={{ filter: "hue-rotate(300deg) contrast(60%) saturate(1000%)" }} /></button> | 109 | <button onClick={() => window.location.href = `/api/v1/demos?uuid=${r.host_demo_id}`}><img src={DownloadIcon} alt="download" style={{ filter: "hue-rotate(300deg) contrast(60%) saturate(1000%)" }} /></button> |
| 110 | </span> | 110 | </span> |
| 111 | ) : r.kind === "singleplayer" && ( | 111 | ) : r.kind === "singleplayer" && ( |
| 112 | 112 | ||
| 113 | <span> | 113 | <span> |
| 114 | <button onClick={() => { message("Demo Information", `Demo ID: ${r.demo_id}`) }}><img src={ThreedotIcon} alt="demo_id" /></button> | 114 | <button onClick={() => { message("Demo Information", `Demo ID: ${r.demo_id}`) }}><img src={ThreedotIcon} alt="demo_id" /></button> |
| 115 | <button onClick={() => window.location.href = `/api/v1/demos?uuid=${r.demo_id}`}><img src={DownloadIcon} alt="download" /></button> | 115 | <button onClick={() => window.location.href = `/api/v1/demos?uuid=${r.demo_id}`}><img src={DownloadIcon} alt="download" /></button> |
| 116 | </span> | 116 | </span> |
| 117 | )} | 117 | )} |
| 118 | </span> | 118 | </span> |
| 119 | ))} | 119 | ))} |
| 120 | </div> | 120 | </div> |
| 121 | </section> | 121 | </section> |
| 122 | </div> | 122 | </div> |
| 123 | ); | 123 | ); |
| 124 | }; | 124 | }; |
| 125 | 125 | ||
diff --git a/frontend/src/components/Login.tsx b/frontend/src/components/Login.tsx index f1628b2..89a37e1 100644 --- a/frontend/src/components/Login.tsx +++ b/frontend/src/components/Login.tsx | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | import { Link, useNavigate } from 'react-router-dom'; | 2 | import { Link, useNavigate } from "react-router-dom"; |
| 3 | 3 | ||
| 4 | import { ExitIcon, UserIcon, LoginIcon } from '@images/Images'; | 4 | import { ExitIcon, UserIcon, LoginIcon } from "@images/Images"; |
| 5 | import { UserProfile } from '@customTypes/Profile'; | 5 | import { UserProfile } from "@customTypes/Profile"; |
| 6 | import { API } from '@api/Api'; | 6 | import { API } from "@api/Api"; |
| 7 | import "@css/Login.css"; | 7 | import "@css/Login.css"; |
| 8 | 8 | ||
| 9 | interface LoginProps { | 9 | interface LoginProps { |
diff --git a/frontend/src/components/MapEntry.tsx b/frontend/src/components/MapEntry.tsx index 0f494ad..88137d8 100644 --- a/frontend/src/components/MapEntry.tsx +++ b/frontend/src/components/MapEntry.tsx | |||
| @@ -1,12 +1,12 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | import { Link } from "react-router-dom"; | 2 | import { Link } from "react-router-dom"; |
| 3 | 3 | ||
| 4 | const MapEntry: React.FC = () => { | 4 | const MapEntry: React.FC = () => { |
| 5 | return ( | 5 | return ( |
| 6 | <div> | 6 | <div> |
| 7 | 7 | ||
| 8 | </div> | 8 | </div> |
| 9 | ) | 9 | ) |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | export default MapEntry; | 12 | export default MapEntry; |
diff --git a/frontend/src/components/MessageDialog.tsx b/frontend/src/components/MessageDialog.tsx index 5c85189..ae95f8d 100644 --- a/frontend/src/components/MessageDialog.tsx +++ b/frontend/src/components/MessageDialog.tsx | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | 2 | ||
| 3 | import "@css/Dialog.css" | 3 | import "@css/Dialog.css" |
| 4 | 4 | ||
| @@ -9,21 +9,21 @@ interface MessageDialogProps { | |||
| 9 | }; | 9 | }; |
| 10 | 10 | ||
| 11 | const MessageDialog: React.FC<MessageDialogProps> = ({ title, subtitle, onClose }) => { | 11 | const MessageDialog: React.FC<MessageDialogProps> = ({ title, subtitle, onClose }) => { |
| 12 | return ( | 12 | return ( |
| 13 | <div className='dimmer'> | 13 | <div className='dimmer'> |
| 14 | <div className='dialog'> | 14 | <div className='dialog'> |
| 15 | <div className='dialog-element dialog-header'> | 15 | <div className='dialog-element dialog-header'> |
| 16 | <span>{title}</span> | 16 | <span>{title}</span> |
| 17 | </div> | ||
| 18 | <div className='dialog-element dialog-description'> | ||
| 19 | <span>{subtitle}</span> | ||
| 20 | </div> | ||
| 21 | <div className='dialog-element dialog-btns-container'> | ||
| 22 | <button onClick={onClose}>Close</button> | ||
| 23 | </div> | ||
| 24 | </div> | ||
| 25 | </div> | 17 | </div> |
| 26 | ) | 18 | <div className='dialog-element dialog-description'> |
| 19 | <span>{subtitle}</span> | ||
| 20 | </div> | ||
| 21 | <div className='dialog-element dialog-btns-container'> | ||
| 22 | <button onClick={onClose}>Close</button> | ||
| 23 | </div> | ||
| 24 | </div> | ||
| 25 | </div> | ||
| 26 | ) | ||
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | export default MessageDialog; | 29 | export default MessageDialog; |
diff --git a/frontend/src/components/MessageDialogLoad.tsx b/frontend/src/components/MessageDialogLoad.tsx index 966e064..000a2ab 100644 --- a/frontend/src/components/MessageDialogLoad.tsx +++ b/frontend/src/components/MessageDialogLoad.tsx | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | 2 | ||
| 3 | import "@css/Dialog.css" | 3 | import "@css/Dialog.css" |
| 4 | 4 | ||
| @@ -8,22 +8,22 @@ interface MessageDialogLoadProps { | |||
| 8 | }; | 8 | }; |
| 9 | 9 | ||
| 10 | const MessageDialogLoad: React.FC<MessageDialogLoadProps> = ({ title, onClose }) => { | 10 | const MessageDialogLoad: React.FC<MessageDialogLoadProps> = ({ title, onClose }) => { |
| 11 | return ( | 11 | return ( |
| 12 | <div className='dimmer'> | 12 | <div className='dimmer'> |
| 13 | <div className='dialog'> | 13 | <div className='dialog'> |
| 14 | <div className='dialog-element dialog-header'> | 14 | <div className='dialog-element dialog-header'> |
| 15 | <span>{title}</span> | 15 | <span>{title}</span> |
| 16 | </div> | 16 | </div> |
| 17 | <div className='dialog-element dialog-description'> | 17 | <div className='dialog-element dialog-description'> |
| 18 | <div style={{display: "flex", justifyContent: "center"}}> | 18 | <div style={{display: "flex", justifyContent: "center"}}> |
| 19 | <span className="loader"></span> | 19 | <span className="loader"></span> |
| 20 | </div> | 20 | </div> |
| 21 | </div> | 21 | </div> |
| 22 | <div className='dialog-element dialog-btns-container'> | 22 | <div className='dialog-element dialog-btns-container'> |
| 23 | </div> | ||
| 24 | </div> | ||
| 25 | </div> | 23 | </div> |
| 26 | ) | 24 | </div> |
| 25 | </div> | ||
| 26 | ) | ||
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | export default MessageDialogLoad; | 29 | export default MessageDialogLoad; |
diff --git a/frontend/src/components/ModMenu.tsx b/frontend/src/components/ModMenu.tsx index 925b8a8..19ce0ce 100644 --- a/frontend/src/components/ModMenu.tsx +++ b/frontend/src/components/ModMenu.tsx | |||
| @@ -1,12 +1,12 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | import ReactMarkdown from 'react-markdown'; | 2 | import ReactMarkdown from "react-markdown"; |
| 3 | import { useNavigate } from 'react-router-dom'; | 3 | import { useNavigate } from "react-router-dom"; |
| 4 | 4 | ||
| 5 | import { MapSummary } from '@customTypes/Map'; | 5 | import { MapSummary } from "@customTypes/Map"; |
| 6 | import { ModMenuContent } from '@customTypes/Content'; | 6 | import { ModMenuContent } from "@customTypes/Content"; |
| 7 | import { API } from '@api/Api'; | 7 | import { API } from "@api/Api"; |
| 8 | import "@css/ModMenu.css" | 8 | import "@css/ModMenu.css" |
| 9 | import useConfirm from '@hooks/UseConfirm'; | 9 | import useConfirm from "@hooks/UseConfirm"; |
| 10 | 10 | ||
| 11 | interface ModMenuProps { | 11 | interface ModMenuProps { |
| 12 | token?: string; | 12 | token?: string; |
| @@ -55,10 +55,10 @@ const ModMenu: React.FC<ModMenuProps> = ({ token, data, selectedRun, mapID }) => | |||
| 55 | width *= 320 / height; | 55 | width *= 320 / height; |
| 56 | height = 320; | 56 | height = 320; |
| 57 | } | 57 | } |
| 58 | const canvas = document.createElement('canvas'); | 58 | const canvas = document.createElement("canvas"); |
| 59 | canvas.width = width; | 59 | canvas.width = width; |
| 60 | canvas.height = height; | 60 | canvas.height = height; |
| 61 | canvas.getContext('2d')!.drawImage(img, 0, 0, width, height); | 61 | canvas.getContext("2d")!.drawImage(img, 0, 0, width, height); |
| 62 | resolve(canvas.toDataURL(file.type, 0.6)); | 62 | resolve(canvas.toDataURL(file.type, 0.6)); |
| 63 | }; | 63 | }; |
| 64 | } | 64 | } |
diff --git a/frontend/src/components/RankingEntry.tsx b/frontend/src/components/RankingEntry.tsx index b899965..9ad9e1c 100644 --- a/frontend/src/components/RankingEntry.tsx +++ b/frontend/src/components/RankingEntry.tsx | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | import { Link } from "react-router-dom"; | 2 | import { Link } from "react-router-dom"; |
| 3 | import { RankingType, SteamRanking, SteamRankingType } from '@customTypes/Ranking'; | 3 | import { RankingType, SteamRankingType } from "@customTypes/Ranking"; |
| 4 | 4 | ||
| 5 | enum RankingCategories { | 5 | enum RankingCategories { |
| 6 | rankings_overall, | 6 | rankings_overall, |
| @@ -14,33 +14,33 @@ interface RankingEntryProps { | |||
| 14 | }; | 14 | }; |
| 15 | 15 | ||
| 16 | const RankingEntry: React.FC<RankingEntryProps> = (prop) => { | 16 | const RankingEntry: React.FC<RankingEntryProps> = (prop) => { |
| 17 | if ("placement" in prop.curRankingData) { | 17 | if ("placement" in prop.curRankingData) { |
| 18 | return ( | 18 | return ( |
| 19 | <div className='leaderboard-entry'> | 19 | <div className='leaderboard-entry'> |
| 20 | <span>{prop.curRankingData.placement}</span> | 20 | <span>{prop.curRankingData.placement}</span> |
| 21 | <div> | 21 | <div> |
| 22 | <Link to={`/users/${prop.curRankingData.user.steam_id}`}> | 22 | <Link to={`/users/${prop.curRankingData.user.steam_id}`}> |
| 23 | <img src={prop.curRankingData.user.avatar_link}></img> | 23 | <img src={prop.curRankingData.user.avatar_link}></img> |
| 24 | <span>{prop.curRankingData.user.user_name}</span> | 24 | <span>{prop.curRankingData.user.user_name}</span> |
| 25 | </Link> | 25 | </Link> |
| 26 | </div> | 26 | </div> |
| 27 | <span>{prop.curRankingData.total_score}</span> | 27 | <span>{prop.curRankingData.total_score}</span> |
| 28 | </div> | 28 | </div> |
| 29 | ) | 29 | ) |
| 30 | } else { | 30 | } else { |
| 31 | return ( | 31 | return ( |
| 32 | <div className='leaderboard-entry'> | 32 | <div className='leaderboard-entry'> |
| 33 | <span>{prop.currentLeaderboardType == RankingCategories.rankings_singleplayer ? prop.curRankingData.sp_rank : prop.currentLeaderboardType == RankingCategories.rankings_multiplayer ? prop.curRankingData.mp_rank : prop.curRankingData.overall_rank}</span> | 33 | <span>{prop.currentLeaderboardType == RankingCategories.rankings_singleplayer ? prop.curRankingData.sp_rank : prop.currentLeaderboardType == RankingCategories.rankings_multiplayer ? prop.curRankingData.mp_rank : prop.curRankingData.overall_rank}</span> |
| 34 | <div> | 34 | <div> |
| 35 | <Link to={`/users/${prop.curRankingData.steam_id}`}> | 35 | <Link to={`/users/${prop.curRankingData.steam_id}`}> |
| 36 | <img src={prop.curRankingData.avatar_link}></img> | 36 | <img src={prop.curRankingData.avatar_link}></img> |
| 37 | <span>{prop.curRankingData.user_name}</span> | 37 | <span>{prop.curRankingData.user_name}</span> |
| 38 | </Link> | 38 | </Link> |
| 39 | </div> | 39 | </div> |
| 40 | <span>{prop.currentLeaderboardType == RankingCategories.rankings_singleplayer ? prop.curRankingData.sp_score : prop.currentLeaderboardType == RankingCategories.rankings_multiplayer ? prop.curRankingData.mp_score : prop.curRankingData.overall_score}</span> | 40 | <span>{prop.currentLeaderboardType == RankingCategories.rankings_singleplayer ? prop.curRankingData.sp_score : prop.currentLeaderboardType == RankingCategories.rankings_multiplayer ? prop.curRankingData.mp_score : prop.curRankingData.overall_score}</span> |
| 41 | </div> | 41 | </div> |
| 42 | ) | 42 | ) |
| 43 | } | 43 | } |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | export default RankingEntry; | 46 | export default RankingEntry; |
diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index f972c6f..eef5bca 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | import { Link, useLocation } from 'react-router-dom'; | 2 | import { Link, useLocation } from "react-router-dom"; |
| 3 | 3 | ||
| 4 | import { BookIcon, FlagIcon, HelpIcon, HomeIcon, LogoIcon, PortalIcon, SearchIcon, UploadIcon } from '@images/Images'; | 4 | import { BookIcon, FlagIcon, HelpIcon, HomeIcon, LogoIcon, PortalIcon, SearchIcon, UploadIcon } from "@images/Images"; |
| 5 | import Login from '@components/Login'; | 5 | import Login from "@components/Login"; |
| 6 | import { UserProfile } from '@customTypes/Profile'; | 6 | import { UserProfile } from "@customTypes/Profile"; |
| 7 | import { Search } from '@customTypes/Search'; | 7 | import { Search } from "@customTypes/Search"; |
| 8 | import { API } from '@api/Api'; | 8 | import { API } from "@api/Api"; |
| 9 | import "@css/Sidebar.css"; | 9 | import "@css/Sidebar.css"; |
| 10 | 10 | ||
| 11 | interface SidebarProps { | 11 | interface SidebarProps { |
| @@ -39,7 +39,7 @@ const Sidebar: React.FC<SidebarProps> = ({ setToken, profile, setProfile, onUplo | |||
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | const _handle_sidebar_hide = () => { | 41 | const _handle_sidebar_hide = () => { |
| 42 | var btn = document.querySelectorAll("button.sidebar-button") as NodeListOf<HTMLElement> | 42 | const btn = document.querySelectorAll("button.sidebar-button") as NodeListOf<HTMLElement> |
| 43 | const span = document.querySelectorAll("button.sidebar-button>span") as NodeListOf<HTMLElement> | 43 | const span = document.querySelectorAll("button.sidebar-button>span") as NodeListOf<HTMLElement> |
| 44 | const side = document.querySelector("#sidebar-list") as HTMLElement; | 44 | const side = document.querySelector("#sidebar-list") as HTMLElement; |
| 45 | const searchbar = document.querySelector("#searchbar") as HTMLInputElement; | 45 | const searchbar = document.querySelector("#searchbar") as HTMLInputElement; |
| @@ -140,13 +140,13 @@ const Sidebar: React.FC<SidebarProps> = ({ setToken, profile, setProfile, onUplo | |||
| 140 | </div> | 140 | </div> |
| 141 | </div> | 141 | </div> |
| 142 | </Link> | 142 | </Link> |
| 143 | <button id='hamburger-menu' onClick={_toggle_mobile_menu} className={isMobileMenuOpen ? 'open' : ''}> | 143 | <button id='hamburger-menu' onClick={_toggle_mobile_menu} className={isMobileMenuOpen ? "open" : ""}> |
| 144 | <span></span> | 144 | <span></span> |
| 145 | <span></span> | 145 | <span></span> |
| 146 | <span></span> | 146 | <span></span> |
| 147 | </button> | 147 | </button> |
| 148 | </div> | 148 | </div> |
| 149 | <div id='sidebar' className={isMobileMenuOpen ? 'mobile-open' : ''}> | 149 | <div id='sidebar' className={isMobileMenuOpen ? "mobile-open" : ""}> |
| 150 | <Link to="/" tabIndex={-1}> | 150 | <Link to="/" tabIndex={-1}> |
| 151 | <div id='logo'> {/* logo */} | 151 | <div id='logo'> {/* logo */} |
| 152 | <img src={LogoIcon} alt="" height={"80px"} /> | 152 | <img src={LogoIcon} alt="" height={"80px"} /> |
| @@ -204,7 +204,7 @@ const Sidebar: React.FC<SidebarProps> = ({ setToken, profile, setProfile, onUplo | |||
| 204 | </Link> | 204 | </Link> |
| 205 | </div> | 205 | </div> |
| 206 | </div> | 206 | </div> |
| 207 | <div id='search-panel' className={isMobileSearchOpen ? 'mobile-search-open' : ''}> | 207 | <div id='search-panel' className={isMobileSearchOpen ? "mobile-search-open" : ""}> |
| 208 | <input type="text" id='searchbar' placeholder='Search for map or a player...' onChange={(e) => _handle_search_change(e.target.value)} /> | 208 | <input type="text" id='searchbar' placeholder='Search for map or a player...' onChange={(e) => _handle_search_change(e.target.value)} /> |
| 209 | <div className='mobile-search-header'> | 209 | <div className='mobile-search-header'> |
| 210 | <button className='mobile-search-close' onClick={_close_mobile_search}>✕</button> | 210 | <button className='mobile-search-close' onClick={_close_mobile_search}>✕</button> |
| @@ -220,15 +220,15 @@ const Sidebar: React.FC<SidebarProps> = ({ setToken, profile, setProfile, onUplo | |||
| 220 | </Link> | 220 | </Link> |
| 221 | ))} | 221 | ))} |
| 222 | {searchData?.players.map((q, index) => | 222 | {searchData?.players.map((q, index) => |
| 223 | ( | 223 | ( |
| 224 | <Link to={ | 224 | <Link to={ |
| 225 | profile && q.steam_id === profile.steam_id ? `/profile` : | 225 | profile && q.steam_id === profile.steam_id ? "/profile" : |
| 226 | `/users/${q.steam_id}` | 226 | `/users/${q.steam_id}` |
| 227 | } className='search-player' key={index} onClick={_close_mobile_search}> | 227 | } className='search-player' key={index} onClick={_close_mobile_search}> |
| 228 | <img src={q.avatar_link} alt='pfp'></img> | 228 | <img src={q.avatar_link} alt='pfp'></img> |
| 229 | <span style={{ fontSize: `${36 - q.user_name.length * 0.8}px` }}>{q.user_name}</span> | 229 | <span style={{ fontSize: `${36 - q.user_name.length * 0.8}px` }}>{q.user_name}</span> |
| 230 | </Link> | 230 | </Link> |
| 231 | ))} | 231 | ))} |
| 232 | 232 | ||
| 233 | </div> | 233 | </div> |
| 234 | </div> | 234 | </div> |
diff --git a/frontend/src/components/Summary.tsx b/frontend/src/components/Summary.tsx index 7da2f1e..72b5bf0 100644 --- a/frontend/src/components/Summary.tsx +++ b/frontend/src/components/Summary.tsx | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | import ReactMarkdown from 'react-markdown'; | 2 | import ReactMarkdown from "react-markdown"; |
| 3 | 3 | ||
| 4 | import { MapSummary } from '@customTypes/Map'; | 4 | import { MapSummary } from "@customTypes/Map"; |
| 5 | import "@css/Maps.css" | 5 | import "@css/Maps.css" |
| 6 | 6 | ||
| 7 | interface SummaryProps { | 7 | interface SummaryProps { |
| @@ -16,7 +16,7 @@ const Summary: React.FC<SummaryProps> = ({ selectedRun, setSelectedRun, data }) | |||
| 16 | const [historySelected, setHistorySelected] = React.useState<boolean>(false); | 16 | const [historySelected, setHistorySelected] = React.useState<boolean>(false); |
| 17 | 17 | ||
| 18 | function _select_run(idx: number, category_id: number) { | 18 | function _select_run(idx: number, category_id: number) { |
| 19 | let r = document.querySelectorAll("button.record"); | 19 | const r = document.querySelectorAll("button.record"); |
| 20 | r.forEach(e => (e as HTMLElement).style.backgroundColor = "#2b2e46"); | 20 | r.forEach(e => (e as HTMLElement).style.backgroundColor = "#2b2e46"); |
| 21 | (r[idx] as HTMLElement).style.backgroundColor = "#161723" | 21 | (r[idx] as HTMLElement).style.backgroundColor = "#161723" |
| 22 | 22 | ||
| @@ -66,7 +66,7 @@ const Summary: React.FC<SummaryProps> = ({ selectedRun, setSelectedRun, data }) | |||
| 66 | style={data.map.image === "" ? { backgroundColor: "#202232" } : {}}> | 66 | style={data.map.image === "" ? { backgroundColor: "#202232" } : {}}> |
| 67 | <img src={data.map.image} alt="" id='category-image'></img> | 67 | <img src={data.map.image} alt="" id='category-image'></img> |
| 68 | <p><span className='portal-count'>{data.summary.routes[selectedRun].history.score_count}</span> | 68 | <p><span className='portal-count'>{data.summary.routes[selectedRun].history.score_count}</span> |
| 69 | {data.summary.routes[selectedRun].history.score_count === 1 ? ` portal` : ` portals`}</p> | 69 | {data.summary.routes[selectedRun].history.score_count === 1 ? " portal" : " portals"}</p> |
| 70 | {data.map.is_coop ? // TODO: make this part dynamic | 70 | {data.map.is_coop ? // TODO: make this part dynamic |
| 71 | ( | 71 | ( |
| 72 | <span style={{ gridTemplateColumns: "1fr 1fr 1fr" }}> | 72 | <span style={{ gridTemplateColumns: "1fr 1fr 1fr" }}> |
| @@ -109,7 +109,7 @@ const Summary: React.FC<SummaryProps> = ({ selectedRun, setSelectedRun, data }) | |||
| 109 | _select_run(index, r.category.id); | 109 | _select_run(index, r.category.id); |
| 110 | }}> | 110 | }}> |
| 111 | <span>{new Date(r.history.date).toLocaleDateString( | 111 | <span>{new Date(r.history.date).toLocaleDateString( |
| 112 | "en-US", { month: 'long', day: 'numeric', year: 'numeric' } | 112 | "en-US", { month: "long", day: "numeric", year: "numeric" } |
| 113 | )}</span> | 113 | )}</span> |
| 114 | <span>{r.history.score_count}</span> | 114 | <span>{r.history.score_count}</span> |
| 115 | <span>{r.history.runner_name}</span> | 115 | <span>{r.history.runner_name}</span> |
diff --git a/frontend/src/components/UploadRunDialog.tsx b/frontend/src/components/UploadRunDialog.tsx index c02fdb8..dd609a1 100644 --- a/frontend/src/components/UploadRunDialog.tsx +++ b/frontend/src/components/UploadRunDialog.tsx | |||
| @@ -1,15 +1,15 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | import { UploadRunContent } from '@customTypes/Content'; | 2 | import { UploadRunContent } from "@customTypes/Content"; |
| 3 | import { ScoreboardTempUpdate, SourceDemoParser, NetMessages } from '@nekz/sdp'; | 3 | import { ScoreboardTempUpdate, SourceDemoParser, NetMessages } from "@nekz/sdp"; |
| 4 | 4 | ||
| 5 | import '@css/UploadRunDialog.css'; | 5 | import "@css/UploadRunDialog.css"; |
| 6 | import { Game } from '@customTypes/Game'; | 6 | import { Game } from "@customTypes/Game"; |
| 7 | import { API } from '@api/Api'; | 7 | import { API } from "@api/Api"; |
| 8 | import { useNavigate } from 'react-router-dom'; | 8 | import { useNavigate } from "react-router-dom"; |
| 9 | import useMessage from '@hooks/UseMessage'; | 9 | import useMessage from "@hooks/UseMessage"; |
| 10 | import useConfirm from '@hooks/UseConfirm'; | 10 | import useConfirm from "@hooks/UseConfirm"; |
| 11 | import useMessageLoad from "@hooks/UseMessageLoad"; | 11 | import useMessageLoad from "@hooks/UseMessageLoad"; |
| 12 | import { MapNames } from '@customTypes/MapNames'; | 12 | import { MapNames } from "@customTypes/MapNames"; |
| 13 | 13 | ||
| 14 | interface UploadRunDialogProps { | 14 | interface UploadRunDialogProps { |
| 15 | token?: string; | 15 | token?: string; |