Changeset 0c6b92a for imaps-frontend/src/pages
- Timestamp:
- 12/12/24 17:06:06 (5 weeks ago)
- Branches:
- main
- Parents:
- d565449
- Location:
- imaps-frontend/src/pages
- Files:
-
- 13 added
- 4 deleted
- 12 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
imaps-frontend/src/pages/BrowseMaps/Maps.module.css
rd565449 r0c6b92a 1 2 1 3 .container { 2 4 max-width: 1200px; … … 7 9 8 10 h1 { 11 font-family: exo, sans-serif; 9 12 font-size: 2.5rem; 10 color: # 34495e;13 color: #0f71da; 11 14 margin-bottom: 20px; 12 15 } … … 62 65 } 63 66 67 .favorite{ 68 position: absolute; 69 top: 20px; 70 right: 20px; 71 cursor: pointer; 72 } 73 64 74 /* When dragging a tile */ 65 75 .dragging { -
imaps-frontend/src/pages/Draw/Draw.jsx
rd565449 r0c6b92a 1 import { useEffect, useState } from "react"; 2 import { MapBuilder } from "../../scripts/main/MapBuilder.js"; 1 import { useContext, useEffect, useState } from "react"; 3 2 import styles from "./Draw.module.css"; 4 import RoomModal from "../../components/RoomModal/RoomModal.jsx"; 5 import SideBar from "../../components/SideBar/SideBar.jsx"; 6 import EntranceModal from "../../components/EntranceModal/EntranceModal.jsx"; 3 import RoomModal from "../../components/Modals/RoomModal/RoomModal.jsx"; 4 import EntranceModal from "../../components/Modals/EntranceModal/EntranceModal.jsx"; 7 5 import DrawGuide from "../../components/DrawGuide/DrawGuide.jsx"; 8 import RoomTypeModal from "../../components/RoomTypeModal/RoomTypeModal.jsx"; 9 import InfoPinModal from "../../components/InfoPinModal/InfoPinModal.jsx"; 6 import RoomTypeModal from "../../components/Modals/RoomTypeModal/RoomTypeModal.jsx"; 7 import InfoPinModal from "../../components/Modals/InfoPinModal/InfoPinModal.jsx"; 8 import SaveMap from "../../components/SaveMap/SaveMap.jsx"; 9 import Logo from "../../components/Logo/Logo.jsx"; 10 import { Link, useNavigate, useParams, useSearchParams } from "react-router-dom"; 11 import Profile from "../../components/Profile/Profile.jsx"; 10 12 import HttpService from "../../scripts/net/HttpService.js"; 11 import SaveMap from "../../components/SaveMap/SaveMap.jsx"; 12 import logo from "../../assets/logo_icon.png"; 13 import MapTemplateSelector from "../../components/MapTemplateSelector/LoadMap.jsx"; 14 import KeymapPanel from "../../components/KeyMappingsGuidePanel/KeymapPanel.jsx"; 15 import { Link } from "react-router-dom"; 13 import StairsModal from "../../components/Modals/StairsModal/StairsModal.jsx"; 14 import useMapLoader from "./Hooks/useMapLoader.js"; 15 import {FloorSelector} from "./FloorSelector.jsx"; 16 import {useRoomTypesLoader} from "./Hooks/useRoomTypesLoader.js"; 17 import {useAppContext} from "../../components/AppContext/AppContext.jsx"; 18 import config from "../../scripts/net/netconfig.js"; 19 import ShapeRegistry from "../../scripts/util/ShapeRegistry.js"; 16 20 17 21 function Draw() { 18 const [selectedFloor, setSelectedFloor] = useState(1); 19 const [app, setApp] = useState(null); 22 const { mapName } = useParams(); 23 const { username } = useAppContext(); 24 20 25 const [isPopupVisible, setIsPopupVisible] = useState(false); 26 const [errorMessage, setErrorMessage] = useState("Error"); 27 const [hasError, setHasError] = useState(false); 28 const [searchParams, setSearchParams] = useSearchParams(); 29 30 const[roomTypes,setRoomTypes] = useState([]); 31 32 const {app,floors,saveFloor,setFloors} = useMapLoader(mapName,username,searchParams,setSearchParams) 33 const {addRoomType} = useRoomTypesLoader(setRoomTypes,mapName,username); 34 35 const addFloorHandler = async (newFloorNum) => { 36 const httpService = new HttpService(); 37 httpService.setAuthenticated(); 38 39 const payload = { 40 num: newFloorNum, 41 mapName: mapName, 42 }; 43 44 try { 45 await httpService.put(`${config.floors.add}`, payload); 46 console.log(`Added floor ${newFloorNum}`); 47 setFloors((prevFloors) => [...prevFloors, { num: newFloorNum }]); 48 } catch (error) { 49 console.error("Error adding floor:", error); 50 } 51 }; 52 53 const deleteFloorHandler = async (floorNum) => { 54 if(floorNum === 0) return 55 56 const httpService = new HttpService(); 57 httpService.setAuthenticated(); 58 59 try { 60 await httpService.delete(`${config.floors.delete}?floorNum=${floorNum}&mapName=${mapName}`); 61 setFloors((prevFloors) => prevFloors.filter(f => f.num !== floorNum)) 62 63 const currFloor = searchParams.get("floor"); 64 if(currFloor == floorNum){ 65 setSearchParams({floor:"0"},{replace:true}) 66 } 67 console.log(`Deleted floor ${floorNum}`); 68 } catch (error) { 69 console.error("Error deleting floor:", error); 70 } 71 }; 72 21 73 useEffect(() => { 22 const app = new MapBuilder("container");23 setApp(app);24 // fpsCounterLoop();74 return () => { 75 ShapeRegistry.clear(); 76 } 25 77 }, []); 26 78 27 const handleFloorChange = (event) => {28 setSelectedFloor(event.target.value);29 console.log(`Floor changed to: ${event.target.value}`);30 };31 79 32 const handleRenderClick = () => { 33 setIsPopupVisible(true); 80 const handleSaveClick = async () => { 81 saveFloor().then(r => { 82 floors.forEach(flr => { 83 setIsPopupVisible(true); 84 setTimeout(() => { 85 setIsPopupVisible(false);}, 86 3000); 87 console.log("floor after save: " + JSON.stringify(flr)) 88 }) 89 }); 34 90 35 setTimeout(() => {36 setIsPopupVisible(false);37 }, 3000);38 };39 91 40 const handleSaveClick = async (mapName) => {41 const resp = await app.saveMap(mapName);42 };43 const handleLoadMapClick = (data) => {44 app.deserializeMap(data);45 92 }; 46 93 47 94 return ( 48 95 <div className={styles.wrapper} id="wrapper"> 49 <SideBar></SideBar> 96 {/* <SideBar></SideBar> */} 97 <Logo></Logo> 50 98 <div id="container" className={styles.cont}></div> 51 99 <div className={styles.panel}> 52 <Link to="/"> 53 <img src={logo} alt="Finki Logo" className={styles.logo} /> 100 <div className={styles.topPanelH}> 101 <Profile position="inline"></Profile> 102 </div> 103 <Link to={`/myMaps/${mapName}/View`} className={styles.titleLink}> 104 <h1 className={styles.title}>{mapName}</h1> 54 105 </Link> 55 <h1 className={styles.title}>Map Builder</h1>56 {/* <div id="fpscont" className={styles.fpscounter}>57 <p id="fpsCounter"></p>58 </div> */}59 106 <div className={styles.guideWrapper}> 60 <DrawGuide 107 <DrawGuide/> 61 108 </div> 62 63 {/* <div className={styles.floorSelector}> 64 <label htmlFor="floorSelect">Select Floor:</label> 65 <select 66 id="floorSelect" 67 value={selectedFloor} 68 onChange={handleFloorChange} 69 className={styles.floorDropdown} 70 > 71 <option value={1}>1st Floor</option> 72 <option value={2}>2nd Floor</option> 73 <option value={3}>3rd Floor</option> 74 <option value={4}>4th Floor</option> 75 </select> 76 </div> */} 77 {/* <h2 className={styles.paragraph}>Objects:</h2> */} 109 <hr/> 110 <br/> 111 {/* {<h2 className={styles.paragraph}>Objects:</h2>} */} 78 112 <ul className={styles.shapeOptions} id="shapeOptions"> 79 113 <li data-info="Entrance" className={`${styles.shapeOption} ${styles.entrance}`}></li> 80 114 <li data-info="Wall" className={`${styles.shapeOption} ${styles.wall}`} id="wall"></li> 81 115 <li data-info="Room" className={`${styles.shapeOption} ${styles.room}`} id="room"></li> 116 <li data-info="Stairs" className={`${styles.shapeOption} ${styles.stairs}`} id="stairs"></li> 82 117 </ul> 83 <br /> 84 <RoomTypeModal map={app}></RoomTypeModal> 118 <RoomTypeModal map={app} roomTypes={roomTypes} addRoomTypeDB={addRoomType}></RoomTypeModal> 119 <br/> 120 <hr/> 121 <br/> 122 <FloorSelector floorConfig={{ 123 floors,searchParams, 124 setSearchParams,addFloorHandler, 125 deleteFloorHandler 126 }}></FloorSelector> 85 127 86 <div id="render" className={styles.buttonContainer}> 87 <button 88 id="render-button" 89 type="button" 90 className={styles.renderButton} 91 onClick={handleRenderClick} 92 > 93 Render 94 </button> 95 </div> 128 <br/> 129 130 <hr/> 131 <br/> 132 {hasError && <p style={{color: "red", textAlign: "center"}}>{errorMessage}</p>} 96 133 <div className={styles.templateCont}> 97 134 <SaveMap submitHandler={handleSaveClick}></SaveMap> 98 <MapTemplateSelector loadHandler={handleLoadMapClick}></MapTemplateSelector>99 135 </div> 100 136 101 137 <div className={styles.hide}> 102 <RoomModal map={app} ></RoomModal>138 <RoomModal map={app} roomTypes={roomTypes}></RoomModal> 103 139 <EntranceModal map={app}></EntranceModal> 104 140 <InfoPinModal map={app}></InfoPinModal> 141 <StairsModal map={app}></StairsModal> 105 142 </div> 106 143 </div> 107 144 108 145 {isPopupVisible && ( 109 <div className={styles.popup}> 110 <div className={styles.popupContent}> 111 <h2>Map Rendered!</h2> 112 <p>Your map has been successfully rendered.</p> 146 <div className={styles.popup}> 147 <div className={styles.popupContent}> 148 <h2>Map Saved!</h2> 149 <p>Your map has been successfully saved.</p> 150 </div> 113 151 </div> 114 </div>115 152 )} 116 153 </div> -
imaps-frontend/src/pages/Draw/Draw.module.css
rd565449 r0c6b92a 4 4 padding: 0; 5 5 height: 100%; 6 overflow : hidden;6 overflow-x: hidden; 7 7 background-color: #141414; 8 8 } 9 9 10 .topPanelH { 11 width: 100%; 12 display: flex; 13 justify-content: center; 14 align-items: center; 15 margin-bottom: 20px; 16 } 17 10 18 .logo { 11 width: 100px; 12 margin: 10px; 13 align-self: center; 19 width: 80px; 14 20 } 15 21 16 22 .title { 17 margin-top: 20px; 18 color: #804047; 19 font-size: 120%; 23 text-align: center; 24 font-size: 2.5em; 25 font-weight: 700; 26 text-transform: uppercase; 27 color: #333333; 28 font-family: "Oswald", sans-serif; 29 margin-bottom: 0; 30 text-decoration: none; 31 } 32 33 .titleLink { 34 text-decoration: none; 35 } 36 .titleLink:hover{ 37 text-decoration: none; 20 38 } 21 39 … … 23 41 color: #cccccc; 24 42 } 43 25 44 .guideWrapper { 26 45 display: flex; … … 28 47 align-items: center; 29 48 margin: 0; 49 width: 100%; 30 50 } 31 51 … … 51 71 display: flex; 52 72 flex-direction: column; 73 align-items: center; /* Center elements horizontally */ 53 74 padding: 20px; 54 75 background-color: #1c1c1c; … … 58 79 margin-right: 10px; 59 80 border-radius: 20px; 81 overflow-x: hidden; 60 82 } 61 83 62 84 .buttonContainer { 63 85 display: flex; 64 justify-content: space-between;86 justify-content: center; 65 87 align-items: center; 66 88 margin-top: 2rem; 67 89 gap: 10px; 68 } 69 70 /* .hide { 71 visibility: hidden; 72 } */ 90 width: 100%; 91 } 73 92 74 93 .renderButton { … … 104 123 list-style: none; 105 124 padding: 0; 106 margin: 0 0;107 display: flex;108 flex-direction: column;125 margin: 0; 126 display: grid; 127 grid-template-columns: repeat(2, 1fr); 109 128 gap: 15px; 129 justify-items: center; 110 130 align-items: center; 111 131 } … … 127 147 } 128 148 129 .templateCont {130 display: flex;131 flex-direction: column;132 }133 134 149 .shapeOption:hover { 135 150 background-color: #94183b; … … 137 152 } 138 153 154 .templateCont { 155 display: flex; 156 flex-direction: column; 157 align-items: center; /* Center section horizontally */ 158 width: 100%; 159 } 160 139 161 .fpscounter { 140 162 border: 1px solid #00b822; 141 163 margin: 20px 0; 164 text-align: center; 165 width: 100%; 142 166 } 143 167 … … 145 169 color: #00740c; 146 170 font-weight: bold; 147 text-align: center;148 171 margin: 0; 149 172 padding: 5px 0; 150 173 } 151 174 152 .floorSelector {153 margin-bottom: 20px;154 display: flex;155 flex-direction: column;156 gap: 8px;157 color: #ffffff;158 }159 160 .floorSelector label {161 font-size: 14px;162 }163 164 .floorDropdown {165 padding: 8px;166 font-size: 14px;167 border-radius: 5px;168 border: 1px solid #ccc;169 background-color: #3a3a3a;170 color: #ffffff;171 cursor: pointer;172 width: 100%;173 transition: border-color 0.3s;174 }175 176 .floorDropdown:focus {177 outline: none;178 border-color: #1e90ff;179 }180 175 181 176 .popup { … … 226 221 background-image: url("./shapeImages/room_icon.png"); 227 222 } 223 .stairs { 224 background-image: url("./shapeImages/stairs_icon.png"); 225 } 226 .floorSection { 227 display: flex; 228 flex-direction: column; 229 align-items: center; 230 gap: 20px; 231 background-color: #2d2d2d; 232 padding: 20px; 233 border-radius: 8px; 234 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); 235 width: 100%; 236 } 237 238 .floorLabel { 239 font-size: 16px; 240 font-weight: bold; 241 color: #ffffff; 242 margin-bottom: 10px; 243 text-align: center; 244 } 245 246 .floorList { 247 display: flex; 248 flex-direction: column; 249 align-items: center; 250 gap: 15px; 251 width: 100%; 252 } 253 254 .floorItems { 255 display: flex; 256 flex-direction: column; 257 align-items: center; 258 gap: 10px; 259 width: 100%; 260 } 261 262 .addFloorButton { 263 background-color: #e67e22; 264 border: none; 265 border-radius: 50%; 266 width: 40px; 267 height: 40px; 268 display: flex; 269 justify-content: center; 270 align-items: center; 271 cursor: pointer; 272 transition: background-color 0.3s, transform 0.2s; 273 } 274 275 .addFloorButton:hover { 276 background-color: #d2691e; 277 transform: scale(1.1); 278 } 279 280 .addFloorButton:active { 281 background-color: #b35418; 282 transform: scale(0.95); 283 } 284 285 .icon { 286 width: 20px; 287 height: 20px; 288 filter: invert(1); 289 } 290 291 .floorButton { 292 padding: 10px 15px; 293 font-size: 14px; 294 color: #ffffff; 295 background-color: #3a3a3a; 296 border: 1px solid #555555; 297 border-radius: 8px; 298 width: 100%; 299 text-align: center; 300 cursor: pointer; 301 transition: background-color 0.3s, transform 0.2s; 302 } 303 304 .floorButton:hover { 305 background-color: #4a4a4a; 306 } 307 308 .floorButton.active { 309 background-color: #1e90ff; 310 color: #ffffff; 311 font-weight: bold; 312 } 313 314 .floorInput { 315 width: 60%; 316 padding: 8px; 317 font-size: 14px; 318 border: 1px solid #ccc; 319 border-radius: 5px; 320 background-color: #3a3a3a; 321 color: #ffffff; 322 text-align: center; 323 transition: border-color 0.3s; 324 } 325 326 .floorInput:focus { 327 outline: none; 328 border-color: #1e90ff; 329 } 330 331 .floorActions { 332 display: flex; 333 gap: 10px; 334 justify-content: center; 335 align-items: center; 336 margin-top: 10px; 337 } 338 339 .errorMessage { 340 color: red; 341 font-size: 12px; 342 margin-top: 10px; 343 text-align: center; 344 } 345 .floorItemWrapper { 346 display: flex; 347 align-items: center; 348 gap: 10px; 349 width: 100%; 350 } 351 352 .floorItem { 353 padding: 10px 15px; 354 font-size: 14px; 355 color: #ffffff; 356 background-color: #3a3a3a; 357 border: 1px solid #555555; 358 border-radius: 8px; 359 text-align: center; 360 cursor: pointer; 361 flex-grow: 1; 362 transition: background-color 0.3s; 363 } 364 365 .floorItem:hover { 366 background-color: #4a4a4a; 367 } 368 369 .activeFloor { 370 background-color: #1e90ff; 371 color: #ffffff; 372 font-weight: bold; 373 } 374 375 .deleteFloorButton { 376 background-color: #ff4d4d; 377 border: none; 378 border-radius: 8px; 379 padding: 10px; 380 color: white; 381 cursor: pointer; 382 transition: background-color 0.3s, transform 0.2s; 383 } 384 385 .deleteFloorButton:hover { 386 background-color: #e60000; 387 transform: scale(1.1); 388 } 389 390 .deleteFloorButton:active { 391 background-color: #cc0000; 392 transform: scale(0.95); 393 } -
imaps-frontend/src/pages/IMaps/IMaps.jsx
rd565449 r0c6b92a 4 4 import styles from "./IMaps.module.css"; 5 5 import Home from "./components/pages/Home"; 6 import Profile from "../../components/Profile/Profile"; 7 import Logo from "../../components/Logo/Logo"; 8 import Cards from "./components/Cards"; 6 9 7 10 function IMaps() { 8 11 return ( 9 <> 10 <div className={styles.home}> 11 <Navbar></Navbar> 12 <Home></Home> 13 </div> 14 </> 12 <div className="homebg"> 13 <Navbar></Navbar> 14 <Home></Home> 15 </div> 15 16 ); 16 17 } -
imaps-frontend/src/pages/IMaps/IMaps.module.css
rd565449 r0c6b92a 5 5 html, 6 6 body { 7 overflow: auto; 8 overflow-x: hidden; 7 margin: 0; 9 8 } -
imaps-frontend/src/pages/IMaps/components/Button.css
rd565449 r0c6b92a 1 @import url(https://fonts.googleapis.com/css?family=Exo:500); 1 2 :root { 2 --primary: # fff;3 --primary: #252627; 3 4 } 4 5 5 6 .btn { 6 7 padding: 8px 20px; 7 8 font-family: exo, sans-serif; 8 9 border-radius: 20px; 9 10 outline: none; … … 14 15 .btn--primary { 15 16 background-color: var(--primary); 16 17 color: #242424; 17 color: #ffffff; 18 18 border: 1px solid var(--primary); 19 19 } … … 24 24 color: #fff; 25 25 padding: 8px 20px; 26 border: 1px solid var(--primary);26 /* border: 1px solid var(--primary); */ 27 27 transition: all 0.3s ease-out; 28 28 } … … 30 30 .btn--medium { 31 31 padding: 8px 20px; 32 font-size: 18px;32 font-size: 22px; 33 33 } 34 34 35 35 .btn--large { 36 36 padding: 12px 26px; 37 font-size: 2 0px;37 font-size: 24px; 38 38 } 39 39 … … 41 41 .btn--medium:hover { 42 42 transition: all 0.3s ease-out; 43 background: #fff ;44 color: # 242424;43 background: #ffffffc2; 44 color: #000000; 45 45 transition: 250ms; 46 46 } -
imaps-frontend/src/pages/IMaps/components/HeroSection.css
rd565449 r0c6b92a 1 @import url(https://fonts.googleapis.com/css?family=Exo:500); 2 1 3 video { 2 4 object-fit: cover; … … 7 9 } 8 10 11 12 13 9 14 .hero-container { 10 background: url("../images/img-home.jpg") center center/cover no-repeat;11 15 height: 100vh; 12 16 width: 100%; … … 15 19 justify-content: center; 16 20 align-items: center; 17 box-shadow: inset 0 0 0 1000px rgba(0, 0, 0, 0.4); 21 18 22 object-fit: contain; 23 24 25 19 26 } 20 27 … … 23 30 font-size: 100px; 24 31 margin-top: -100px; 32 font-family: exo, sans-serif; 33 text-transform: uppercase; 34 text-shadow: 1px 1px 0px #ef404e, 35 1px 2px 0px #ef404e, 36 1px 3px 0px #ef404e, 37 1px 4px 0px #ef404e, 38 1px 5px 0px #ef404e, 39 1px 6px 0px #ef404e, 40 1px 10px 5px rgba(16, 16, 16, 0.5), 41 1px 15px 10px rgba(16, 16, 16, 0.4), 42 1px 20px 30px rgba(16, 16, 16, 0.3), 43 1px 25px 50px rgba(16, 16, 16, 0.2); 25 44 } 26 45 -
imaps-frontend/src/pages/IMaps/components/HeroSection.jsx
rd565449 r0c6b92a 7 7 function HeroSection() { 8 8 return ( 9 <div className="hero-container">10 <h1>Map Your World</h1>11 <p>Create and explore detailed indoor maps.</p>12 <div className="hero-btns">13 <Link to="/Maps/FinkiMaps/Draw">14 <Button className="btns" buttonStyle="btn--outline" buttonSize="btn--large">15 Create maps16 </Button>17 </Link>18 <Link to="/Maps">19 <Button20 className="btns"21 buttonStyle="btn--primary"22 buttonSize="btn--large"23 onClick={console.log("hey")}24 >25 Browse Maps <i className="far fa-play-circle" />26 </Button>27 </Link>9 <div className="hero-container"> 10 <h1>Map Your World</h1> 11 <p>Create and explore detailed indoor maps.</p> 12 <div className="hero-btns"> 13 <Link to="/myMaps"> 14 <Button className="btns" buttonStyle="btn--outline" buttonSize="btn--large"> 15 Create maps 16 </Button> 17 </Link> 18 <Link to="/Maps"> 19 <Button 20 className="btns" 21 buttonStyle="btn--primary" 22 buttonSize="btn--large" 23 > 24 Browse Maps <i className="far fa-play-circle"/> 25 </Button> 26 </Link> 27 </div> 28 28 </div> 29 </div>30 29 ); 31 30 } -
imaps-frontend/src/pages/IMaps/components/Navbar.css
rd565449 r0c6b92a 1 .navbar { 2 background: linear-gradient(90deg, rgb(28, 27, 27) 0%, rgb(26, 23, 23) 100%); 3 height: 80px; 1 .modern-navbar { 2 /*background-color: #ffffff;*/ 3 /*background: linear-gradient(*/ 4 /* 90deg,*/ 5 /* #fafafa 0%,*/ 6 /* #c07e7e 25%,*/ 7 /* #af2525 50%,*/ 8 /* #443a3a 75%,*/ 9 /* #8d1010 100%*/ 10 /*);*/ 11 /*background: linear-gradient(to right, #ffffff, #c12c2c);*/ 12 /*background: linear-gradient(90deg, #3b3131, #ffffff);*/ 13 background: linear-gradient(90deg, #9b1818, #efefef); 14 color: #ffffff; 15 /*color: #333333;*/ 4 16 display: flex; 5 17 justify-content: center; 6 18 align-items: center; 7 font-size: 1.2rem; 19 padding: 0.8rem 1.5rem; 20 box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1); 8 21 position: sticky; 9 22 top: 0; 10 z-index: 999; 11 } 12 13 .pad-bot { 14 /* padding-bottom: 1.5rem; */ 23 z-index: 1000; 24 border-radius: 8px; 25 margin: 5px; 15 26 } 16 27 17 28 .navbar-container { 18 29 display: flex; 19 justify-content: center;30 justify-content: space-between; 20 31 align-items: center; 21 32 width: 100%; 33 max-width: 1200px; 22 34 } 23 35 24 .navbar-logo { 25 color: #fff; 26 justify-self: start; 27 margin-left: 20px; 28 cursor: pointer; 29 text-decoration: none; 30 font-size: 2rem; 36 .navbar-left { 31 37 display: flex; 32 38 align-items: center; 39 gap: 1rem; 33 40 } 34 41 35 .fa-typo3 { 36 margin-left: 0.5rem; 37 font-size: 1.8rem; 42 .navbar-title { 43 font-size: 1.6rem; 44 font-weight: 700; 45 color: #ffffff; 46 margin: 0; 47 font-family: "exo", sans-serif; 38 48 } 39 49 40 .nav-menu { 41 display: grid; 42 grid-template-columns: repeat(4, auto); 43 grid-gap: 10px; 44 list-style: none; 45 text-align: center; 46 width: 70vw; 47 justify-content: end; 48 margin-right: 2rem; 50 .navbar-right { 51 display: flex; 52 align-items: center; 53 gap: 1rem; 49 54 } 50 55 51 .nav-item { 52 height: 80px; 56 .navbar-btn { 57 padding: 0.4rem 1.5rem; 58 font-size: 0.9rem; 59 border: 2px solid transparent; 60 border-radius: 20px; 61 text-decoration: none; 62 color: #ffffff; 63 font-weight: 500; 64 transition: all 0.3s ease-in-out; 65 font-family: "exo", sans-serif; 66 cursor: pointer; 67 margin-left: 4em; 68 margin-right: 1em; 53 69 } 54 70 55 .nav-links { 56 color: #fff; 57 display: flex; 58 align-items: center; 59 text-decoration: none; 60 padding: 0.5rem 1rem; 61 height: 100%; 71 .navbar-login { 72 background-color: #252627; 73 border: 2px solid #3f3232; 62 74 } 63 75 64 .nav-links:hover { 65 border-bottom: 4px solid #fff; 66 transition: all 0.2s ease-out; 76 .navbar-login:hover { 77 background-color: #ffffff; 78 color: #212121; 79 border: 1px solid rgba(19, 18, 18, 0.82); 67 80 } 68 81 69 .fa-bars { 70 color: #fff; 82 .navbar-signup { 83 background-color: #252627; 84 color: #ffffff; 85 border: 2px solid #343a40; 71 86 } 72 87 73 .nav-links-mobile { 74 display: none; 88 .navbar-signup:hover { 89 background-color: #ffffff; 90 color: #343a40; 91 border: 2px solid #343a40; 75 92 } 76 77 .menu-icon {78 display: none;79 }80 81 @media screen and (max-width: 960px) {82 .NavbarItems {83 position: relative;84 }85 86 .nav-menu {87 display: flex;88 flex-direction: column;89 width: 100%;90 height: 90vh;91 position: absolute;92 top: 80px;93 left: -100%;94 opacity: 1;95 transition: all 0.5s ease;96 }97 98 .nav-menu.active {99 background: #242222;100 left: 0;101 opacity: 1;102 transition: all 0.5s ease;103 z-index: 1;104 }105 106 .nav-links {107 text-align: center;108 padding: 2rem;109 width: 100%;110 display: table;111 }112 113 .nav-links:hover {114 background-color: #fff;115 color: #242424;116 border-radius: 0;117 }118 119 .navbar-logo {120 position: absolute;121 top: 0;122 left: 0;123 transform: translate(25%, 50%);124 }125 126 .menu-icon {127 display: block;128 position: absolute;129 top: 0;130 right: 0;131 transform: translate(-100%, 60%);132 font-size: 1.8rem;133 cursor: pointer;134 }135 136 .fa-times {137 color: #fff;138 font-size: 2rem;139 }140 141 .nav-links-mobile {142 display: block;143 text-align: center;144 margin: 2rem auto;145 border-radius: 4px;146 width: 80%;147 text-decoration: none;148 font-size: 1.5rem;149 background-color: transparent;150 color: #fff;151 padding: 14px 20px;152 border: 1px solid #fff;153 transition: all 0.3s ease-out;154 }155 156 .nav-links-mobile:hover {157 background: #fff;158 color: #242424;159 transition: 250ms;160 }161 } -
imaps-frontend/src/pages/IMaps/components/Navbar.jsx
rd565449 r0c6b92a 1 import React, { useState, useEffect } from "react"; 2 import { Button } from "./Button"; 1 import React, {useContext, useState} from "react"; 2 import { Link } from "react-router-dom"; 3 import logo_icon from "../../../assets/logo_icon.png"; 4 //import { AuthContext } from "../../../components/AuthContext/AuthContext"; 5 import Logo from "../../../components/Logo/Logo.jsx"; 6 import Profile from "../../../components/Profile/Profile.jsx"; 7 import {useAppContext} from "../../../components/AppContext/AppContext.jsx"; 3 8 import "./Navbar.css"; 4 import { Link } from "react-router-dom";5 import logo from "../../../assets/logo_icon.png";6 9 7 10 function Navbar() { … … 12 15 const closeMobileMenu = () => setClick(false); 13 16 14 const showButton = () => { 15 if (window.innerWidth <= 960) { 16 setButton(false); 17 } else { 18 setButton(true); 19 } 20 }; 17 const { isAuthenticated } = useAppContext(); 21 18 22 useEffect(() => { 23 showButton(); 24 }, []); 19 return ( 20 <nav className="modern-navbar"> 21 <div className="navbar-container"> 22 {/* Left Section - Logo and Title */} 23 <div className="navbar-left"> 24 <Logo position="relative"/> 25 <h1 className="navbar-title">iMaps</h1> 26 </div> 25 27 26 window.addEventListener("resize", showButton); 27 28 return ( 29 <> 30 <nav className="navbar"> 31 <div className="navbar-container"> 32 <a href="#" className="navbar-logo pad-bot" onClick={closeMobileMenu}> 33 iMaps 34 </a> 35 <div className="menu-icon" onClick={handleClick}> 36 <i className={click ? "fas fa-times" : "fas fa-bars"} /> 37 </div> 38 <ul className={click ? "nav-menu active" : "nav-menu"}> 39 <Link to="/Signup"> 40 <li className="nav-item"> 41 <a href="#" className="nav-links" onClick={closeMobileMenu}> 42 SignUp 43 </a> 44 </li> 45 </Link> 46 </ul> 47 <div className="pad-bot"> 48 <Link to="/Login">{button && <Button buttonStyle="btn--outline">LOG IN</Button>}</Link> 49 </div> 50 </div> 51 </nav> 52 </> 53 ); 28 {/* Right Section - Login/Signup or Profile */} 29 <div className="navbar-right"> 30 {isAuthenticated ? ( 31 <Profile position="relative"/> 32 ) : ( 33 <> 34 <Link to="/Login" className="navbar-btn navbar-login"> 35 Log In 36 </Link> 37 <Link to="/Signup" className="navbar-btn navbar-signup"> 38 Sign Up 39 </Link> 40 </> 41 )} 42 </div> 43 </div> 44 </nav> 45 ); 54 46 } 55 47 -
imaps-frontend/src/pages/IMaps/components/pages/Home.jsx
rd565449 r0c6b92a 1 1 import React from "react"; 2 import "./Home.css"; 3 import Cards from "../Cards"; 4 import HeroSection from "../HeroSection"; 5 import Footer from "../Footer"; 2 import "./Home.scss"; 3 import { Link } from "react-router-dom"; 4 import { Button } from "../Button.jsx"; 5 import Cards from "../Cards.jsx"; 6 import Footer from "../Footer.jsx"; 7 import sl from "../../../../assets/bg-home-light-gray.png" 6 8 7 9 function Home() { 8 10 return ( 9 <> 10 <div className="home"> 11 <HeroSection /> 12 {/* <Cards /> */} 13 <Footer /> 11 <div className="home"> 12 <div className="hero-container"> 13 <h1>Map Your World</h1> 14 <h2 className="description">Create and explore detailed indoor maps.</h2> 15 <div className="hero-btns"> 16 <Link to="/myMaps"> 17 <Button className="btns" buttonSize="btn--large"> 18 Create Maps 19 </Button> 20 </Link> 21 <Link to="/Maps"> 22 <Button className="btns" buttonSize="btn--large"> 23 Browse Maps <i className="far fa-play-circle" /> 24 </Button> 25 </Link> 26 </div> 14 27 </div> 15 </> 28 <Cards /> 29 <Footer></Footer> 30 </div> 16 31 ); 17 32 } -
imaps-frontend/src/pages/Login/Login.jsx
rd565449 r0c6b92a 1 import React, { useState} from "react";2 import { Link, useNavigate} from "react-router-dom";1 import React, {useContext, useState} from "react"; 2 import {Link, useLocation, useNavigate} from "react-router-dom"; 3 3 import styles from "./Login.module.css"; 4 4 import illustration from "../../assets/illustration_img.png"; 5 import Logo from "../../components/Logo/Logo.jsx"; 6 import HttpService from "../../scripts/net/HttpService.js"; 7 import {useAppContext} from "../../components/AppContext/AppContext.jsx"; 8 import config from "../../scripts/net/netconfig.js"; 5 9 6 const LoginPage = ({onLogin}) => { 7 const [username, setUsername] = useState(""); 8 const [password, setPassword] = useState(""); 9 const [error, setError] = useState(null); 10 const navigate = useNavigate(); 10 const LoginPage = () => { 11 const [formUsername, setFormUsername] = useState(""); 12 const [password, setPassword] = useState(""); 13 const [error, setError] = useState(null); 14 const navigate = useNavigate(); 15 const location = useLocation(); 11 16 12 const payload = { 13 username: username, 14 password: password 15 }; 17 const {setUsername, setIsAuthenticated} = useAppContext(); 16 18 17 const handleLogin = (e) => { 18 e.preventDefault(); 19 const {targetPath} = location.state || {targetPath: {pathname: "/"}}; 19 20 20 fetch("http://localhost:8080/api/auth/login", { 21 method: "POST", 22 headers: { 23 "Content-Type": "application/json", 24 }, 25 body: JSON.stringify(payload), 26 }) 27 .then((response) => { 28 if (!response.ok) { 29 throw new Error("Login failed: resp = " + response.statusText); 30 } 31 return response.json(); 32 }) 33 .then((data) => { 34 if (data.token) { 35 navigate("/Maps/FinkiMaps/Draw"); 36 onLogin(data.token) 37 } else { 38 setError("Invalid username or password."); 39 } 40 }) 41 .catch((error) => { 42 console.error("Login failed", error); 43 setError("Login failed. Please try again."); 44 }); 45 46 }; 21 const payload = { 22 username: formUsername, 23 password: password, 24 }; 47 25 48 return ( 49 <div className={styles.wrapper}> 50 <div className={styles.illustration}> 51 <img src={illustration} alt="illustration" /> 52 </div> 53 <div className={styles.form}> 54 <div className={styles.heading}>LOGIN</div> 55 <form onSubmit={handleLogin}> 56 <div> 57 <label htmlFor="username">Username</label> 58 <input 59 type="text" 60 id="name" 61 placeholder="Enter your username" 62 onChange={(e) => setUsername(e.target.value)} 63 value={username} 64 required 65 /> 66 </div> 67 <div> 68 <label htmlFor="password">Password</label> 69 <input 70 type="password" 71 id="password" 72 placeholder="Enter your password" 73 onChange={(e) => setPassword(e.target.value)} 74 value={password} 75 required 76 /> 77 </div> 78 {error && <p className={styles.error}>{error}</p>} 79 <button type="submit">Submit</button> 80 </form> 81 <p> 82 Don't have an account? <Link to="/Signup"> Sign Up </Link> 83 </p> 84 </div> 85 </div> 86 ); 26 const handleLogin = async () => { 27 const httpService = new HttpService(); 28 return httpService.post(config.auth.login, payload) 29 30 }; 31 32 33 const login = async (e) => { 34 e.preventDefault(); 35 36 handleLogin() 37 .then(resp => { 38 if (resp.token) { 39 navigate(targetPath) 40 localStorage.setItem("token", resp.token); 41 setUsername(resp.username); 42 setIsAuthenticated(true); 43 console.log("ROLES",resp.roles) 44 } else { 45 setError("Invalid username or password."); 46 } 47 }).catch(reason => { 48 console.error("Login failed", reason); 49 setError("Login failed. Please try again.") 50 }) 51 52 // fetch("http://localhost:8080/api/auth/login", { 53 // method: "POST", 54 // headers: { 55 // "Content-Type": "application/json", 56 // }, 57 // body: JSON.stringify(payload), 58 // }) 59 // .then((response) => { 60 // if (!response.ok) { 61 // throw new Error("Login failed: resp = " + response.statusText); 62 // } 63 // return response.json(); 64 // }) 65 // .then((data) => { 66 // if (data.token) { 67 // navigate(targetPath); 68 // handleLogin(data); 69 // } else { 70 // setError("Invalid username or password."); 71 // } 72 // }) 73 // .catch((error) => { 74 // console.error("Login failed", error); 75 // setError("Login failed. Please try again."); 76 // }); 77 }; 78 79 return ( 80 <div className={styles.wrapper}> 81 <Logo></Logo> 82 <div className={styles.illustration}> 83 <img src={illustration} alt="illustration"/> 84 </div> 85 <div className={styles.form}> 86 <div className={styles.heading}>LOGIN</div> 87 <form onSubmit={login}> 88 <div> 89 <label htmlFor="username">Username</label> 90 <input 91 type="text" 92 id="name" 93 placeholder="Enter your username" 94 onChange={(e) => setFormUsername(e.target.value)} 95 value={formUsername} 96 required 97 /> 98 </div> 99 <div> 100 <label htmlFor="password">Password</label> 101 <input 102 type="password" 103 id="password" 104 placeholder="Enter your password" 105 onChange={(e) => setPassword(e.target.value)} 106 value={password} 107 required 108 /> 109 </div> 110 {error && <p className={styles.error}>{error}</p>} 111 <button type="submit">Submit</button> 112 </form> 113 <p> 114 Don't have an account? <Link to="/Signup"> Sign Up </Link> 115 </p> 116 </div> 117 </div> 118 ); 87 119 }; 88 120 -
imaps-frontend/src/pages/Signup/Signup.jsx
rd565449 r0c6b92a 3 3 import illustration from "../../assets/illustration_img.png"; 4 4 import styles from "./Signup.module.css"; 5 import Logo from "../../components/Logo/Logo"; 5 6 6 7 export default function Signup() { … … 54 55 return ( 55 56 <div className={styles.wrapper}> 57 <Logo></Logo> 56 58 <div className={styles.illustration}> 57 59 <img src={illustration} alt="illustration" />
Note:
See TracChangeset
for help on using the changeset viewer.