From f1e317bd4b2ea00f97cc596f2f75bfe98671815b Mon Sep 17 00:00:00 2001
From: zoi23333 <110458414+zoi23333@users.noreply.github.com>
Date: Fri, 29 Sep 2023 16:44:45 +0200
Subject: [PATCH] Redo road details page structure
---
.gitignore | 1 +
frontend/src/App.tsx | 23 +-
frontend/src/Components/Navbar.test.tsx | 25 --
frontend/src/Components/Navbar.tsx | 32 ---
.../Components/RoadDetails/ImageGallery.tsx | 133 +++++++++++
.../src/Components/RoadDetails/MapArea.tsx | 21 ++
.../src/Components/RoadDetails/RoadImage.tsx | 15 ++
.../src/Components/RoadDetails/TopBar.tsx | 63 +++++
frontend/src/css/road_details.css | 217 ++++++++++++++++++
frontend/src/pages/RoadDetails.tsx | 21 ++
10 files changed, 479 insertions(+), 72 deletions(-)
delete mode 100644 frontend/src/Components/Navbar.test.tsx
delete mode 100644 frontend/src/Components/Navbar.tsx
create mode 100644 frontend/src/Components/RoadDetails/ImageGallery.tsx
create mode 100644 frontend/src/Components/RoadDetails/MapArea.tsx
create mode 100644 frontend/src/Components/RoadDetails/RoadImage.tsx
create mode 100644 frontend/src/Components/RoadDetails/TopBar.tsx
create mode 100644 frontend/src/css/road_details.css
create mode 100644 frontend/src/pages/RoadDetails.tsx
diff --git a/.gitignore b/.gitignore
index 9f11b755..68729d6b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
.idea/
+.DS_Store
\ No newline at end of file
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 2df6e1bd..4571136d 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,30 +1,23 @@
import { FC } from 'react';
-import {
- BrowserRouter as Router,
- Navigate,
- Route,
- Routes,
-} from 'react-router-dom';
-
-import Navbar from './Components/Navbar';
-import RoadConditions from './pages/RoadConditions';
-import Conditions from './pages/Conditions';
+import { BrowserRouter as Router, Navigate } from 'react-router-dom';
import './App.css';
+import { Route, Routes } from 'react-router-dom';
+import RoadDetails from './pages/RoadDetails';
+
+import Conditions from './pages/Conditions';
const App: FC = () => {
return (
-
- } />
-
-
+ } />
+ } />
+ } />
);
};
-
export default App;
diff --git a/frontend/src/Components/Navbar.test.tsx b/frontend/src/Components/Navbar.test.tsx
deleted file mode 100644
index 7e8497b9..00000000
--- a/frontend/src/Components/Navbar.test.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { render, screen } from '@testing-library/react';
-import Navbar from './Navbar';
-import { BrowserRouter as Router } from 'react-router-dom';
-
-function TestRouter() {
- return (
-
-
-
- );
-}
-test('Check links in navbar', () => {
- render();
- const linkConditionsML = screen.getByText(/Conditions \(ML\)/i);
- expect(linkConditionsML).toBeInTheDocument();
- expect(
- screen.getByRole('link', { name: /Conditions \(ML\)/i }),
- ).toHaveAttribute('href', '/conditions');
-
- const linkConditionsGP = screen.getByText(/Conditions \(GP\)/i);
- expect(linkConditionsGP).toBeInTheDocument();
- expect(
- screen.getByRole('link', { name: /Conditions \(GP\)/i }),
- ).toHaveAttribute('href', '/road_conditions');
-});
diff --git a/frontend/src/Components/Navbar.tsx b/frontend/src/Components/Navbar.tsx
deleted file mode 100644
index 9d1398cc..00000000
--- a/frontend/src/Components/Navbar.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { FC } from 'react';
-import { NavLink } from 'react-router-dom';
-
-import '../css/navbar.css';
-
-interface NavBtnProps {
- to: string;
- name: string;
-}
-
-const NavBtn: FC = ({ to, name }) => {
- return (
-
- {name}
-
- );
-};
-
-const Navbar: FC = () => {
- return (
-
- );
-};
-
-export default Navbar;
diff --git a/frontend/src/Components/RoadDetails/ImageGallery.tsx b/frontend/src/Components/RoadDetails/ImageGallery.tsx
new file mode 100644
index 00000000..53732eba
--- /dev/null
+++ b/frontend/src/Components/RoadDetails/ImageGallery.tsx
@@ -0,0 +1,133 @@
+import React, { useState } from 'react';
+
+interface Image {
+ id: number;
+ url: string;
+}
+
+const images: Image[] = [
+ {
+ id: 1,
+ url: 'https://upload.wikimedia.org/wikipedia/commons/4/43/2015-04-02_18_21_50_View_north_along_U.S._Route_95_in_the_Forty_Mile_Desert_of_Churchill_County%2C_Nevada.JPG',
+ },
+ {
+ id: 2,
+ url: 'https://upload.wikimedia.org/wikipedia/commons/4/43/2015-04-02_18_21_50_View_north_along_U.S._Route_95_in_the_Forty_Mile_Desert_of_Churchill_County%2C_Nevada.JPG',
+ },
+ {
+ id: 3,
+ url: 'https://upload.wikimedia.org/wikipedia/commons/4/43/2015-04-02_18_21_50_View_north_along_U.S._Route_95_in_the_Forty_Mile_Desert_of_Churchill_County%2C_Nevada.JPG',
+ },
+ {
+ id: 4,
+ url: 'https://upload.wikimedia.org/wikipedia/commons/4/43/2015-04-02_18_21_50_View_north_along_U.S._Route_95_in_the_Forty_Mile_Desert_of_Churchill_County%2C_Nevada.JPG',
+ },
+ {
+ id: 5,
+ url: 'https://upload.wikimedia.org/wikipedia/commons/4/43/2015-04-02_18_21_50_View_north_along_U.S._Route_95_in_the_Forty_Mile_Desert_of_Churchill_County%2C_Nevada.JPG',
+ },
+ {
+ id: 6,
+ url: 'https://upload.wikimedia.org/wikipedia/commons/4/43/2015-04-02_18_21_50_View_north_along_U.S._Route_95_in_the_Forty_Mile_Desert_of_Churchill_County%2C_Nevada.JPG',
+ },
+ {
+ id: 7,
+ url: 'https://upload.wikimedia.org/wikipedia/commons/4/43/2015-04-02_18_21_50_View_north_along_U.S._Route_95_in_the_Forty_Mile_Desert_of_Churchill_County%2C_Nevada.JPG',
+ },
+ {
+ id: 8,
+ url: 'https://hips.hearstapps.com/hmg-prod/images/1/roadbootie-main-1520457496.jpg?crop=0.848xw:1xh;center,top&resize=1200:*',
+ },
+ {
+ id: 9,
+ url: 'https://hips.hearstapps.com/hmg-prod/images/1/roadbootie-main-1520457496.jpg?crop=0.848xw:1xh;center,top&resize=1200:*',
+ },
+ {
+ id: 10,
+ url: 'https://hips.hearstapps.com/hmg-prod/images/1/roadbootie-main-1520457496.jpg?crop=0.848xw:1xh;center,top&resize=1200:*',
+ },
+ {
+ id: 11,
+ url: 'https://hips.hearstapps.com/hmg-prod/images/1/roadbootie-main-1520457496.jpg?crop=0.848xw:1xh;center,top&resize=1200:*',
+ },
+ {
+ id: 12,
+ url: 'https://hips.hearstapps.com/hmg-prod/images/1/roadbootie-main-1520457496.jpg?crop=0.848xw:1xh;center,top&resize=1200:*',
+ },
+ {
+ id: 13,
+ url: 'https://hips.hearstapps.com/hmg-prod/images/1/roadbootie-main-1520457496.jpg?crop=0.848xw:1xh;center,top&resize=1200:*',
+ },
+ {
+ id: 14,
+ url: 'https://hips.hearstapps.com/hmg-prod/images/1/roadbootie-main-1520457496.jpg?crop=0.848xw:1xh;center,top&resize=1200:*',
+ },
+ {
+ id: 15,
+ url: 'https://hips.hearstapps.com/hmg-prod/images/1/roadbootie-main-1520457496.jpg?crop=0.848xw:1xh;center,top&resize=1200:*',
+ },
+];
+
+const ImageGallery: React.FC = () => {
+ const [scrollPosition, setScrollPosition] = useState(0);
+
+ const openImageInNewTab = (imageUrl: string) => {
+ window.open(imageUrl, '_blank');
+ };
+
+ const handleScroll = (scrollOffset: number) => {
+ const newScrollPosition = scrollPosition + scrollOffset;
+
+ // Calculate the maximum scroll limit based on the total image width
+ const maxScrollLimit = (images.length - 11.4) * 124; // 120 is the width of each image
+
+ // Ensure the scroll stays within bounds
+ const boundedScrollPosition = Math.max(
+ 0,
+ Math.min(newScrollPosition, maxScrollLimit),
+ );
+
+ setScrollPosition(boundedScrollPosition);
+ };
+
+ return (
+
+
+
+ {images.map((image) => (
+
openImageInNewTab(image.url)}
+ className="image-thumbnail"
+ />
+ ))}
+
+
+
+
+
+ );
+};
+
+export default ImageGallery;
diff --git a/frontend/src/Components/RoadDetails/MapArea.tsx b/frontend/src/Components/RoadDetails/MapArea.tsx
new file mode 100644
index 00000000..0d435662
--- /dev/null
+++ b/frontend/src/Components/RoadDetails/MapArea.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import ImageGallery from './ImageGallery';
+import MapWrapper from '../Map/MapWrapper';
+
+/**
+ * The map area op the road details(road inspect) page
+ */
+const MapArea: React.FC = () => {
+ return (
+
+
+
+
+
+ {/* Use the imageGallery component */}
+
+
+ );
+};
+
+export default MapArea;
diff --git a/frontend/src/Components/RoadDetails/RoadImage.tsx b/frontend/src/Components/RoadDetails/RoadImage.tsx
new file mode 100644
index 00000000..640320b1
--- /dev/null
+++ b/frontend/src/Components/RoadDetails/RoadImage.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+
+const maproadStyles = {
+ margin: 0,
+ padding: 20,
+ color: '#333',
+};
+
+const road_area = Road surface image
;
+
+const RoadImage: React.FC = () => {
+ return {road_area}
;
+};
+
+export default RoadImage;
diff --git a/frontend/src/Components/RoadDetails/TopBar.tsx b/frontend/src/Components/RoadDetails/TopBar.tsx
new file mode 100644
index 00000000..774e5e00
--- /dev/null
+++ b/frontend/src/Components/RoadDetails/TopBar.tsx
@@ -0,0 +1,63 @@
+// The TopBar for RoadDetails page
+import React from 'react';
+import { Link, useNavigate } from 'react-router-dom'; // Import useNavigate
+
+interface TopBarProps {
+ /**
+ * The toggle button value
+ */
+ isToggleOn: React.Dispatch>;
+}
+
+const return_btn = (
+
+);
+
+/**
+ * The Topbar with return and toggle button inside
+ */
+const TopBar: React.FC = ({ isToggleOn }) => {
+ const navigate = useNavigate(); // Get the navigate function
+
+ const handleReturn = () => {
+ // Navigate back to the home page when the button is clicked
+ navigate('/');
+ };
+
+ const handleToggleMiddleArea = () => {
+ // Toggle the state to show/hide MiddleArea2
+ isToggleOn((prevState) => !prevState);
+ };
+
+ return (
+
+
+ {return_btn}
+
+
+
+ Map mode
+
+ Road mode
+
+
+
+ );
+};
+
+export default TopBar;
diff --git a/frontend/src/css/road_details.css b/frontend/src/css/road_details.css
new file mode 100644
index 00000000..43eab5fa
--- /dev/null
+++ b/frontend/src/css/road_details.css
@@ -0,0 +1,217 @@
+/* src/styles.css */
+
+/* Define styles for the top bar */
+.top-bar {
+ background-color: #333; /* Example color for the top bar */
+ height: 50px;
+ display: flex; /* Enable flex layout */
+ align-items: center; /* Vertically center content */
+ justify-content: flex-start; /* Align content to the left (40px margin) */
+}
+
+/* Define styles for the middle area */
+.road-image,
+.map-area {
+ /* background-color: #eee; Example color for the middle area */
+ height: 60vh; /* Occupying half of the page vertically */
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+}
+
+/* Define styles for the plot area */
+.plot-area {
+ background-color: #333; /* Grey with 50% opacity */
+ height: 40vh;
+}
+
+/* To center the Return button vertically */
+.btnLinkContainer {
+ display: flex; /* Enable flex layout */
+ align-items: center; /* Vertically center content */
+ justify-content: flex-start; /* Align content to the left (40px margin) */
+ padding-left: 30px;
+ background: none; /* Remove background color */
+ border: none; /* Remove borders */
+ font-size: inherit; /* Inherit font size */
+ color: inherit; /* Inherit text color */
+ cursor: pointer; /* Add a pointer cursor on hover */
+ text-decoration: none; /* Remove underlines on hover */
+}
+
+.btnWhite {
+ color: #fff;
+ text-decoration: 'none';
+ background: none;
+}
+
+/* _____________________________________________________ */
+/* Style for the toggle button */
+.toggle-switch {
+ position: relative;
+ display: inline-block;
+ width: 40px;
+ height: 20px;
+ background-color: #ccc;
+ border-radius: 20px;
+}
+
+/* Style for the slider (the switch itself) */
+.slider {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #2196f3;
+ border-radius: 20px;
+ transition: 0.4s;
+}
+
+/* Style to make the slider round */
+.slider:before {
+ content: '';
+ position: absolute;
+ width: 16px;
+ height: 16px;
+ background-color: white;
+ border-radius: 50%;
+ left: 2px;
+ top: 2px;
+ transition: 0.4s;
+}
+
+/* Style to change the background color when switched on */
+input:checked + .slider {
+ background-color: #4caf50;
+}
+
+/* Style to move the slider to the right when switched on */
+input:checked + .slider:before {
+ transform: translateX(20px);
+}
+
+/* Hide the default checkbox input */
+input[type='checkbox'] {
+ display: none;
+}
+
+/* Style for the toggle button container */
+.topBar-container {
+ display: flex;
+ align-items: center; /* Vertically center items */
+ justify-content: space-between; /* Add space between items */
+}
+
+.toggle-container {
+ padding-right: 30px;
+ display: flex;
+ align-items: center; /* Vertically center items */
+ justify-content: space-between; /* Add space between items */
+}
+
+/* Style for the toggle button label */
+.toggle-label {
+ display: flex;
+ align-items: center; /* Vertically center items */
+}
+
+/* Style for the text on both sides of the switch */
+.toggle-text {
+ margin: 0 10px 0 10px; /* Adjust the spacing as needed */
+}
+
+/* Style for image Gallery */
+
+.image-gallery {
+ display: flex;
+}
+
+.image-thumbnail:hover {
+ transform: scale(1.1); /* Increase the size on hover (optional) */
+}
+
+/* CSS (styles.css or within a styled-components setup) */
+.overlay {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.7); /* Semi-transparent black background */
+ z-index: 999; /* Ensure the overlay appears above other content */
+ justify-content: center;
+ align-items: center;
+}
+
+.overlay img {
+ max-width: 90%; /* Adjust the size of the modal image as needed */
+ max-height: 90vh; /* Limit the height of the modal image to 90% of the viewport height */
+}
+
+/* Image gallery scroll */
+
+.imageGallery_container {
+ background-color: #999;
+ height: 14vh;
+ margin-top: auto;
+ overflow: auto;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.image-gallery-container {
+ display: flex; /* Add display: flex */
+ flex-direction: column; /* Stack children vertically */
+ justify-content: center; /* Center children vertically */
+ position: relative;
+}
+
+.image-gallery-page {
+ display: flex;
+ overflow-x: auto; /* Enable horizontal scrolling */
+ max-width: 100%; /* Set a maximum width */
+}
+
+.image-container {
+ display: flex;
+ align-items: center;
+ margin-left: 0.5vh;
+}
+
+.image-thumbnail {
+ width: 120px; /* Set the fixed width */
+ height: 105px; /* Set a fixed height to maintain aspect ratio */
+ object-fit: cover; /* Preserve aspect ratio and cover the container */
+ cursor: pointer;
+ transition: transform 0.3s ease-in-out;
+ margin-right: 4px;
+ margin-top: 0.5vh;
+ text-align: center;
+}
+
+.arrow-button {
+ background-color: #fff;
+ border: none;
+ height: 50px;
+ width: 50px;
+ border-radius: 50%;
+ position: absolute;
+ box-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 13px;
+ /* color: #222; */
+}
+
+.left-arrow {
+ left: 10px;
+ transform: rotate(180deg);
+}
+
+.right-arrow {
+ right: 10px;
+}
diff --git a/frontend/src/pages/RoadDetails.tsx b/frontend/src/pages/RoadDetails.tsx
new file mode 100644
index 00000000..b6cf86ba
--- /dev/null
+++ b/frontend/src/pages/RoadDetails.tsx
@@ -0,0 +1,21 @@
+import { useState } from 'react';
+
+import '../css/road_details.css'; // Import the CSS file
+import MapArea from '../Components/RoadDetails/MapArea';
+import RoadImage from '../Components/RoadDetails/RoadImage';
+import TopBar from '../Components/RoadDetails/TopBar';
+
+const RoadDetails = () => {
+ const [showMapImageMode, setShowRoadImageMode] = useState(false);
+
+ return (
+
+
+ {showMapImageMode ?
:
}
+ {/* TODO: putting plots here */}
+
{/* Content for the plot area */}
+
+ );
+};
+
+export default RoadDetails;