From 9821ea948aa1d22a1f03b75773802c48de810c8e Mon Sep 17 00:00:00 2001 From: Alessandro Kreslin Date: Fri, 20 Dec 2024 08:45:56 -0500 Subject: [PATCH 1/2] style poc improvements --- web-app/src/app/Theme.ts | 4 + web-app/src/app/screens/About.tsx | 156 +++-- web-app/src/app/screens/Account.tsx | 2 - web-app/src/app/screens/ChangePassword.tsx | 2 - web-app/src/app/screens/ContactUs.tsx | 162 +++--- web-app/src/app/screens/FAQ.tsx | 255 ++++----- .../src/app/screens/FeedSubmission/index.tsx | 46 +- web-app/src/app/screens/Feeds/Feeds.styles.ts | 59 ++ web-app/src/app/screens/Feeds/index.tsx | 536 ++++++++---------- web-app/src/app/screens/Feeds/styles.tsx | 18 - web-app/src/app/styles/PageHeader.style.ts | 11 + web-app/src/app/styles/PageLayout.style.ts | 8 + web-app/src/index.tsx | 2 + 13 files changed, 597 insertions(+), 664 deletions(-) create mode 100644 web-app/src/app/screens/Feeds/Feeds.styles.ts delete mode 100644 web-app/src/app/screens/Feeds/styles.tsx create mode 100644 web-app/src/app/styles/PageHeader.style.ts create mode 100644 web-app/src/app/styles/PageLayout.style.ts diff --git a/web-app/src/app/Theme.ts b/web-app/src/app/Theme.ts index 565a6f599..da0678222 100644 --- a/web-app/src/app/Theme.ts +++ b/web-app/src/app/Theme.ts @@ -100,6 +100,10 @@ export const theme = createTheme({ border: `2px solid ${palette.primary.main}`, color: palette.primary.main, }, + '&.MuiButton-outlinedPrimary': { + border: `2px solid ${palette.primary.main}`, + padding: '6px 16px', + }, '&.MuiButton-outlinedPrimary:hover': { backgroundColor: palette.primary.main, color: palette.primary.contrastText, diff --git a/web-app/src/app/screens/About.tsx b/web-app/src/app/screens/About.tsx index 9c26b9792..242ceebe1 100644 --- a/web-app/src/app/screens/About.tsx +++ b/web-app/src/app/screens/About.tsx @@ -1,105 +1,83 @@ import * as React from 'react'; -import CssBaseline from '@mui/material/CssBaseline'; -import Box from '@mui/material/Box'; + import Container from '@mui/material/Container'; import { Button, Typography } from '@mui/material'; import { OpenInNew } from '@mui/icons-material'; -import { theme } from '../Theme'; +import { MainPageHeader } from '../styles/PageHeader.style'; +import { ColoredContainer } from '../styles/PageLayout.style'; export default function About(): React.ReactElement { return ( - - + About + + + The Mobility Database is hosted and supported by MobilityData, a + non-profit organization that improves and extends mobility data + formats, including GTFS, GTFS Realtime and GBFS. +

+ MobilityData is currently working on the Mobility Database because of + the need for a sustainable, community-supported hub for international + mobility datasets. +
+ + + The History + + + Discoverability is at the heart of mobility: travelers need to know + the mobility options available and understand their intricacies to + plan their journey; app creators need simplified access to data to + relay to app users. Discoverability is the cement of the community + that MobilityData is building around open data formats (such as GTFS + and GBFS) and their datasets. +
+
+ A need to improve discoverability gave rise to the TransitFeeds.com + project, which made it easier to find and query accurate and + up-to-date GTFS, GTFS Realtime, GBFS, and datasets. This project was + housed by MobilityData following a transition from ActionFigure + (formerly TransitScreen). +
+
+ MobilityData created a long-term roadmap for the project, taking into + account the repeated historic challenges the GTFS repositories have + encountered and the need to expand to accommodate additional modes of + transport and data formats. +
- About{' '} + About MobilityData - + MobilityData began in 2015 as a Rocky Mountain Institute project and + became a Canadian non-profit in 2019 with the mission to improve + traveler information. Building on the strength of nearly 20 employees, + MobilityData brings together and supports mobility stakeholders such + as transport agencies, software vendors, mobility apps, and cities to + standardize and expand data formats for public transport (GTFS) and + shared mobility (GBFS). + + - -
+ Learn more about MobilityData + +
); } diff --git a/web-app/src/app/screens/Account.tsx b/web-app/src/app/screens/Account.tsx index 7ca061468..dfcc3f698 100644 --- a/web-app/src/app/screens/Account.tsx +++ b/web-app/src/app/screens/Account.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import CssBaseline from '@mui/material/CssBaseline'; import '../styles/Account.css'; import { useNavigate } from 'react-router-dom'; import { useTheme } from '@mui/material/styles'; @@ -298,7 +297,6 @@ export default function APIAccount(): React.ReactElement { {t('accessToken.refreshSuccess')} - - ({ padding: theme.spacing(2), @@ -48,97 +49,88 @@ const SlackSvg = ( export default function ContactUs(): React.ReactElement { const { t } = useTranslation('contactUs'); return ( - - - - {t('title')} - - - - - - - {t('email.title')} - - - - {t('email.description')}{' '} - api@mobilitydata.org + + {t('title')} + + + + + + {t('email.title')} - + + + {t('email.description')}{' '} + api@mobilitydata.org + + - - - {SlackSvg} - - {t('slack.title')} - - - {t('slack.description')} - - + + + {SlackSvg} + + {t('slack.title')} + + + {t('slack.description')} + + - - - - - {t('contribute.title')} - - - - {t('contribute.description')} + + + + + {t('contribute.title')} - - + + + {t('contribute.description')} + + + - - - - - {t('addFeeds.title')} - - - - {t('addFeeds.description')} + + + + + {t('addFeeds.title')} - - - + + + {t('addFeeds.description')} + + + ); diff --git a/web-app/src/app/screens/FAQ.tsx b/web-app/src/app/screens/FAQ.tsx index 8e3951e6c..d32b9c974 100644 --- a/web-app/src/app/screens/FAQ.tsx +++ b/web-app/src/app/screens/FAQ.tsx @@ -1,154 +1,127 @@ import * as React from 'react'; -import CssBaseline from '@mui/material/CssBaseline'; -import Box from '@mui/material/Box'; import Container from '@mui/material/Container'; import '../styles/FAQ.css'; import { Typography } from '@mui/material'; import { WEB_VALIDATOR_LINK } from '../constants/Navigation'; -import { theme } from '../Theme'; +import { MainPageHeader } from '../styles/PageHeader.style'; +import { ColoredContainer } from '../styles/PageLayout.style'; export default function FAQ(): React.ReactElement { return ( - - - - Frequently Asked Questions (FAQ){' '} + Frequently Asked Questions (FAQ) + + + Why use the Mobility Database? - - - Why use the Mobility Database? - - - The Mobility Database is a catalog that makes it easy to find over - 2,000 GTFS and GTFS Realtime feeds, including more accurate and - newer feeds not found on TransitFeeds. The Mobility Database - integrates with{' '} - - the Canonical GTFS Schedule Validator - {' '} - to provide data quality insights. - - - How do I use the Mobility Database? - - - There are 3 ways to use the Mobility Database: -
-
- 1. The feed search on the website, where you can discover feeds and - see details on their bounding box, data quality, and historical - data. -
- 2. The API, where you can pull feed information to display in your - own application or for research analysis -
- 3. The{' '} - - spreadsheet export available here - - . You can find{' '} - - the GTFS Schedule and Realtime schemas for the spreadsheet here - - . -
- - Why are you making this change? - - - The mobility community has created several hubs for international - GTFS feeds over the years (including the GTFS Data Exchange and - legacy TransitFeeds site). There have been consistent issues with - sustaining these platforms in the long term, and creating community - processes so it's clear how decisions are made and how - stakeholders across the mobility industry can contribute to the - platform. -

- That's the need we're working to meet with the Mobility - Database, so more stakeholders can trust the longevity of this - platform and it can become an increasingly valuable source for - creating and improving mobility data as a community. -

- As TransitFeeds becomes increasingly stale and difficult to - maintain, it becomes more critical that the consumers have - up-to-date data to share with travelers and make planning decisions. - The catalogs will be a starting point for providing up-to-date data - the community can easily leverage and contribute to while we explore - longer term solutions for the architecture that require more - community investment. -
- What about TransitFeeds? - - TransitFeeds.com is still available to access historical data before - February 2024 and see feed visualizations. It will be deprecated - once both these features are available on the Mobility Database. We - commit to giving 6 months notice once the decision is finalized. -

- How quickly we scale the architecture to add these features depends - on how much engagement and contribution we get from the community in - this phase. -
- - What about the TransitFeeds API? - - - You can use{' '} - - the Mobility Database API - {' '} - instead to access up-to-date GTFS and GTFS Realtime data. The API is - providing historical data from the time of launch (February 2024). - If you need to access historical data from previous years from the - TransitFeeds API, you are still able to. Your systems will be - unaffected until the to-be-determined deprecation date, when the - TransitFeeds API will no longer be available. - - What’s coming next? - - The MobilityData team is working to add historical data and route - and stop visualizations to the Mobility Database. -

- - You can add ideas and vote on our current roadmap - - . We anticipate an influx of new feedback as we transition away from - TransitFeeds and intend to adapt our plan to the emerging needs of - the community. How quickly we scale the Mobility Database - architecture depends on how much engagement and contribution we get - from the community in this phase. -
- - How often do you check for feed updates? - - - The Mobility Database checks for feed updates twice a week using the - producer's URL, on Mondays and Thursdays. We store the new feed - version if we detect a change. - -
-
+ + The Mobility Database is a catalog that makes it easy to find over + 2,000 GTFS and GTFS Realtime feeds, including more accurate and newer + feeds not found on TransitFeeds. The Mobility Database integrates with{' '} + + the Canonical GTFS Schedule Validator + {' '} + to provide data quality insights. + + + How do I use the Mobility Database? + + + There are 3 ways to use the Mobility Database: +
+
+ 1. The feed search on the website, where you can discover feeds and + see details on their bounding box, data quality, and historical data. +
+ 2. The API, where you can pull feed information to display in your own + application or for research analysis +
+ 3. The{' '} + + spreadsheet export available here + + . You can find{' '} + + the GTFS Schedule and Realtime schemas for the spreadsheet here + + . +
+ + Why are you making this change? + + + The mobility community has created several hubs for international GTFS + feeds over the years (including the GTFS Data Exchange and legacy + TransitFeeds site). There have been consistent issues with sustaining + these platforms in the long term, and creating community processes so + it's clear how decisions are made and how stakeholders across the + mobility industry can contribute to the platform. +

+ That's the need we're working to meet with the Mobility + Database, so more stakeholders can trust the longevity of this + platform and it can become an increasingly valuable source for + creating and improving mobility data as a community. +

+ As TransitFeeds becomes increasingly stale and difficult to maintain, + it becomes more critical that the consumers have up-to-date data to + share with travelers and make planning decisions. The catalogs will be + a starting point for providing up-to-date data the community can + easily leverage and contribute to while we explore longer term + solutions for the architecture that require more community investment. +
+ What about TransitFeeds? + + TransitFeeds.com is still available to access historical data before + February 2024 and see feed visualizations. It will be deprecated once + both these features are available on the Mobility Database. We commit + to giving 6 months notice once the decision is finalized. +

+ How quickly we scale the architecture to add these features depends on + how much engagement and contribution we get from the community in this + phase. +
+ + What about the TransitFeeds API? + + + You can use{' '} + + the Mobility Database API + {' '} + instead to access up-to-date GTFS and GTFS Realtime data. The API is + providing historical data from the time of launch (February 2024). If + you need to access historical data from previous years from the + TransitFeeds API, you are still able to. Your systems will be + unaffected until the to-be-determined deprecation date, when the + TransitFeeds API will no longer be available. + + What’s coming next? + + The MobilityData team is working to add historical data and route and + stop visualizations to the Mobility Database. +

+ + You can add ideas and vote on our current roadmap + + . We anticipate an influx of new feedback as we transition away from + TransitFeeds and intend to adapt our plan to the emerging needs of the + community. How quickly we scale the Mobility Database architecture + depends on how much engagement and contribution we get from the + community in this phase. +
+ + How often do you check for feed updates? + + + The Mobility Database checks for feed updates twice a week using the + producer's URL, on Mondays and Thursdays. We store the new feed + version if we detect a change. + +
); } diff --git a/web-app/src/app/screens/FeedSubmission/index.tsx b/web-app/src/app/screens/FeedSubmission/index.tsx index f656344d6..93f750da4 100644 --- a/web-app/src/app/screens/FeedSubmission/index.tsx +++ b/web-app/src/app/screens/FeedSubmission/index.tsx @@ -7,7 +7,6 @@ import { Container, CssBaseline, Typography, - colors, } from '@mui/material'; import CheckIcon from '@mui/icons-material/Check'; import { selectIsAuthenticated } from '../../store/profile-selectors'; @@ -16,7 +15,8 @@ import Contribute from '../Contribute'; import { useTranslation } from 'react-i18next'; import { useLocation } from 'react-router-dom'; import FeedSubmissionForm from './Form'; -import { theme } from '../../Theme'; +import { MainPageHeader } from '../../styles/PageHeader.style'; +import { ColoredContainer } from '../../styles/PageLayout.style'; function Component(): React.ReactElement { const { t } = useTranslation('feeds'); @@ -36,13 +36,7 @@ function Component(): React.ReactElement { > {!isAuthenticated && ( <> - - {t('form.addOrUpdateFeed')} - + {t('form.addOrUpdateFeed')} {t('form.signUp')} - + - - + - {t('dataType')} + { + setActivePagination(1); + setSelectedFeedTypes({ + ...selectedFeedTypes, + gtfs: checkboxData[0].checked, + gtfs_rt: checkboxData[1].checked, + }); }} - > - {t('dataType')} - { - setActivePagination(1); - setSelectedFeedTypes({ - ...selectedFeedTypes, - gtfs: checkboxData[0].checked, - gtfs_rt: checkboxData[1].checked, - }); - }} - > - {config.enableFeatureFilterSearch && ( - <> - Features - { - const newExpandGroup: Record = {}; - checkboxData.forEach((cd) => { - if (cd.seeChildren !== undefined) { - newExpandGroup[cd.title] = cd.seeChildren; - } - }); - setExpandedElements({ - ...expandedElements, - ...newExpandGroup, - }); - }} - onCheckboxChange={(checkboxData) => { - const selelectedFeatures: string[] = []; - checkboxData.forEach((checkbox) => { - if (checkbox.children !== undefined) { - checkbox.children.forEach((child) => { - if (child.checked) { - selelectedFeatures.push(child.title); - } - }); - } - }); - setActivePagination(1); - setSelectedFeatures([...selelectedFeatures]); - }} - /> - - )} - + > + {config.enableFeatureFilterSearch && ( + <> + Features + { + const newExpandGroup: Record = {}; + checkboxData.forEach((cd) => { + if (cd.seeChildren !== undefined) { + newExpandGroup[cd.title] = cd.seeChildren; + } + }); + setExpandedElements({ + ...expandedElements, + ...newExpandGroup, + }); + }} + onCheckboxChange={(checkboxData) => { + const selelectedFeatures: string[] = []; + checkboxData.forEach((checkbox) => { + if (checkbox.children !== undefined) { + checkbox.children.forEach((child) => { + if (child.checked) { + selelectedFeatures.push(child.title); + } + }); + } + }); + setActivePagination(1); + setSelectedFeatures([...selelectedFeatures]); + }} + /> + + )} + - - - {selectedFeedTypes.gtfs && ( - { - setActivePagination(1); - setSelectedFeedTypes({ - ...selectedFeedTypes, - gtfs: false, - }); - }} - /> - )} - {selectedFeedTypes.gtfs_rt && ( - { - setActivePagination(1); - setSelectedFeedTypes({ - ...selectedFeedTypes, - gtfs_rt: false, - }); - }} - /> - )} - {selectedFeatures.map((feature) => ( - { - setSelectedFeatures([ - ...selectedFeatures.filter((sf) => sf !== feature), - ]); - }} - /> - ))} - {(selectedFeatures.length > 0 || - selectedFeedTypes.gtfs_rt || - selectedFeedTypes.gtfs) && ( - - )} - - {feedStatus === 'loading' && ( - - - - - - + + + {selectedFeedTypes.gtfs && ( + { + setActivePagination(1); + setSelectedFeedTypes({ + ...selectedFeedTypes, + gtfs: false, + }); + }} + /> )} - - {feedStatus === 'error' && ( - -

{t('common:errors.generic')}

- - - Please check your internet connection and try again. If - the problem persists{' '} -
contact us for - for further assistance. - -
- + {selectedFeedTypes.gtfs_rt && ( + { + setActivePagination(1); + setSelectedFeedTypes({ + ...selectedFeedTypes, + gtfs_rt: false, + }); + }} + /> + )} + {selectedFeatures.map((feature) => ( + { + setSelectedFeatures([ + ...selectedFeatures.filter((sf) => sf !== feature), + ]); + }} + /> + ))} + {(selectedFeatures.length > 0 || + selectedFeedTypes.gtfs_rt || + selectedFeedTypes.gtfs) && ( + )} + + {feedStatus === 'loading' && ( + + + + + + + )} + + {feedStatus === 'error' && ( + +

{t('common:errors.generic')}

+ + + Please check your internet connection and try again. If + the problem persists{' '} + contact us for + for further assistance. + + +
+ )} - {feedsData !== undefined && feedStatus === 'loaded' && ( - <> - {feedsData?.results?.length === 0 && - activeSearch.trim().length > 0 && ( + {feedsData !== undefined && feedStatus === 'loaded' && ( + <> + {feedsData?.results?.length === 0 && + activeSearch.trim().length > 0 && ( + +

{t('noResults', { activeSearch })}

+ {t('searchSuggestions')} +
    +
  • + {t('searchTips.twoDigit')} +
  • +
  • + {t('searchTips.fullName')} +
  • +
  • + + {t('searchTips.checkSpelling')} + +
  • +
+
+ )} + {feedsData?.results !== undefined && + feedsData?.results !== null && + feedsData?.results?.length > 0 && ( + -

{t('noResults', { activeSearch })}

- {t('searchSuggestions')} -
    -
  • - - {t('searchTips.twoDigit')} - -
  • -
  • - - {t('searchTips.fullName')} - -
  • -
  • - - {t('searchTips.checkSpelling')} - -
  • -
+ + {getSearchResultNumbers()} +
- )} - {feedsData?.results !== undefined && - feedsData?.results !== null && - feedsData?.results?.length > 0 && ( - - - - {getSearchResultNumbers()} - - - - { - event.preventDefault(); - setActivePagination(value); - }} - /> - - )} - - )} - + + { + event.preventDefault(); + setActivePagination(value); + }} + /> +
+ )} + + )} - - + + ); diff --git a/web-app/src/app/screens/Feeds/styles.tsx b/web-app/src/app/screens/Feeds/styles.tsx deleted file mode 100644 index 05cd87490..000000000 --- a/web-app/src/app/screens/Feeds/styles.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { styled, type SxProps, Typography } from '@mui/material'; - -export const SearchHeader = styled(Typography)(({ theme }) => ({ - '&:not(:first-of-type)': { - marginTop: theme.spacing(2), - }, - '&:after': { - content: '""', - display: 'block', - height: '3px', - width: '104px', - background: theme.palette.text.primary, - }, -})); - -export const stickyHeaderStyle: SxProps = { - boxShadow: '0 6px 22px rgba(15,39,65,.1),0 5px 20px rgba(57,89,250,.08)', -}; diff --git a/web-app/src/app/styles/PageHeader.style.ts b/web-app/src/app/styles/PageHeader.style.ts new file mode 100644 index 000000000..4433e7734 --- /dev/null +++ b/web-app/src/app/styles/PageHeader.style.ts @@ -0,0 +1,11 @@ +import { styled, Typography, type TypographyProps } from '@mui/material'; + +export const MainPageHeader = styled(Typography)({ + fontWeight: 700, +}); + +MainPageHeader.defaultProps = { + variant: 'h4', + color: 'primary', + component: 'h1', +}; diff --git a/web-app/src/app/styles/PageLayout.style.ts b/web-app/src/app/styles/PageLayout.style.ts new file mode 100644 index 000000000..029445ace --- /dev/null +++ b/web-app/src/app/styles/PageLayout.style.ts @@ -0,0 +1,8 @@ +import { Container, styled } from '@mui/material'; + +export const ColoredContainer = styled(Container)(({ theme }) => ({ + background: theme.palette.background.paper, + borderRadius: '6px', + paddingTop: theme.spacing(3), + paddingBottom: theme.spacing(3), +})); diff --git a/web-app/src/index.tsx b/web-app/src/index.tsx index 25762dc00..750eaa5d8 100644 --- a/web-app/src/index.tsx +++ b/web-app/src/index.tsx @@ -7,6 +7,7 @@ import { ThemeProvider } from '@mui/material/styles'; import ReactGA from 'react-ga4'; import { getEnvConfig } from './app/utils/config'; import ContextProviders from './app/components/Context'; +import { CssBaseline } from '@mui/material'; const gaId = getEnvConfig('REACT_APP_GOOGLE_ANALYTICS_ID'); if (gaId.length > 0) { @@ -20,6 +21,7 @@ const root = ReactDOM.createRoot( root.render( + From f23f2a06820382fcc61ffd501a6d0b5d6e1286d8 Mon Sep 17 00:00:00 2001 From: Alessandro Kreslin Date: Fri, 20 Dec 2024 08:58:11 -0500 Subject: [PATCH 2/2] styling chnages feeds --- web-app/src/app/screens/Feeds/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/web-app/src/app/screens/Feeds/index.tsx b/web-app/src/app/screens/Feeds/index.tsx index e32c38626..75a5dfb40 100644 --- a/web-app/src/app/screens/Feeds/index.tsx +++ b/web-app/src/app/screens/Feeds/index.tsx @@ -314,9 +314,7 @@ export default function Feed(): React.ReactElement { container spacing={1} sx={{ - color: 'black', fontSize: '18px', - fontWeight: 700, mt: 0, flexWrap: { xs: 'wrap', md: 'nowrap' }, }}