From ffb48872463d9f924235f99d6515c53f06598bdb Mon Sep 17 00:00:00 2001 From: Alessandro Kreslin Date: Mon, 27 Apr 2026 08:47:04 -0400 Subject: [PATCH 01/15] trip planner images --- public/assets/tripPlannerLogos/aubin-app.png | Bin 0 -> 54641 bytes public/assets/tripPlannerLogos/gmaps.png | Bin 0 -> 33391 bytes public/assets/tripPlannerLogos/motis.png | Bin 0 -> 3493 bytes .../assets/tripPlannerLogos/opentripplanner.png | Bin 0 -> 6008 bytes public/assets/tripPlannerLogos/transitapp.png | Bin 0 -> 6062 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/assets/tripPlannerLogos/aubin-app.png create mode 100644 public/assets/tripPlannerLogos/gmaps.png create mode 100644 public/assets/tripPlannerLogos/motis.png create mode 100644 public/assets/tripPlannerLogos/opentripplanner.png create mode 100644 public/assets/tripPlannerLogos/transitapp.png diff --git a/public/assets/tripPlannerLogos/aubin-app.png b/public/assets/tripPlannerLogos/aubin-app.png new file mode 100644 index 0000000000000000000000000000000000000000..7d85218181b9337ebaf3602d56e995f6eba6eac7 GIT binary patch literal 54641 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 literal 0 HcmV?d00001 diff --git a/public/assets/tripPlannerLogos/gmaps.png b/public/assets/tripPlannerLogos/gmaps.png new file mode 100644 index 0000000000000000000000000000000000000000..a66e95ea1f287c2ebb502aa6abb262023a836ad3 GIT binary patch literal 33391 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 P#Gke@v%^=Jdc^z}RUmS6 literal 0 HcmV?d00001 diff --git a/public/assets/tripPlannerLogos/opentripplanner.png b/public/assets/tripPlannerLogos/opentripplanner.png new file mode 100644 index 0000000000000000000000000000000000000000..ab8d4d54b30ca28398fc8fea6f654752416dea2c GIT binary patch literal 6008 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 Xn)G1m@BeNd;ef8Dk;WS}$JqY?S*acN literal 0 HcmV?d00001 diff --git a/public/assets/tripPlannerLogos/transitapp.png b/public/assets/tripPlannerLogos/transitapp.png new file mode 100644 index 0000000000000000000000000000000000000000..8f745290a679dac59ea0d6cbd6e07e8a5bd1b723 GIT binary patch literal 6062 zcmV;f7g6YmP)^NUvQ(u3#pm zUOug2HLPJvuv|p1UqY^7yyVUC`Sf_mnM<~KUcH6a@8O%)wED39Xaw-QNFAr?N^Ob(dg_!!hLa4L&)s5;Fyl_^lV5Qg=2Rj?K<8zc){Ixv6iyE+xtDIz#|a6mTVGE zMzKj$@v3eC@k(^Mhn=A#ewI4}9)aN9qP4^YIiuSN@aWul7*o3f9#VS(w_;^?GRH%j z6=R<#^mw;$MJMgZ;8w=NSg-~>!+GMWD>{jXv0w+`)&lR%insfu*!$&qJdE>%3J;|t1~|knbUPFtog1&XTm#|ZbtmJ9 z)Y=^ikLcWZh7~LDY;G*4$7?e^!P_X76rBg&(D4FJ?e^GUC0@uY*+dw4VAIYim70?= zz?tx{iteZ8Fp4fu>3BGJE{9mAgKddr63zsmyev$&Aiht#P*+c$pLDq@=;6kx z$Z72SN5zwxs`7k4QdHnwQAWiNLwGy_!ecf?<*D5822Y!fil0|3FdpR96Rtd8Jjo{U zFh<1-@R&`R)z7;9SM0{4;)xI)5AQsYO_k?=8=C|282~R>MpN)z?or^m-#lr5p2$g5 zo(~?of#JQI4`Unyp6}I@5ve8445tLVO!2@Abe<5E=Zsf$tK#8Y7Bei_%kQL;8{E{+ zNXKEf437tTZ^x_hwz}^`BLQ_M+}au38sZTW-drPl;c0e>VCRXoEwM~;ImGI3vU|70 zvhX^da>eG^&yKhH{1j~A$-6#s`6TH@%&QDD;v~Zn&E%!@9n!2X;%GGmJ}rLz0#4+QE?aES3KSCPfTxi zmtW)g)P^UGUoL277Zo?=)h?^NL3ltn1W)?QbK?DT!}SE`K!?NyDokmWg$&0Vv$ea2 z`L)%idqc+tcd2GhMw$G5#UXVEc;j#JoMgJZ#;eZ<@dWokzn3LY^HOvGHwbV1VX^DC zyy+bOd~9~YuOMH^?Co>WjdW9M$oRuz_fYtcPRF)(JOF$>NrRYZ=WDf71f2TtraE3M z;Dvi-p#ZxUy$wtZtvt2L0p8$e#@>AaFWwJa!}2g++T!@TnHXDi{dhpvkH@QcP;SG5Gl{fzANe3Qv=)jm5^JB^`4AB-D_Ci>P@$XJ>3t zZ#EUY{-XO~2Y3UHo>cLQat}P2iq#|p%-KPYMdS*1RL4TdfUO?(Lb*Nc}|-dx4QU-A+)t6Lr&j$YvYo}A7?hJL&lRNm}T3}FhvCpQ=H z1f;xCSqwo>6}#eQWxy(t;f=fZ1S-$@KqVLV`<*MQf?qCC;dsn9?R&*76$eu#Jk7c8 z?bs1`^@Fj|-{l>CZMeMpfL5L{3@{*3qjVdIMXLL^5W^&t1h+CCcg2@H6i$Fpa*YhQCpc{n;av5EJ!)mGj z9NtyN8NJvVkM{zoeiKhVg$%y;j#^TirPw}pWBF7tXm!dHf6khIO%yB&4fmcsw$J$58&|5sA@ak&@ z;E|K?>aTd69cw%B+U^#+(saS&ZLx1p#p`e@G^|;EGKpB8d2(608yrRpWR7# zCvNQ^_Rrwek2)0x{2UJIS6Ju>FnQhEJ&wqe0&n|4YJPugvtH>&84yyj(v*M~=sV1g84b=;(%7+(%Fbl6V4d5)>6h4;e@FAwOHFivHcQ$i@pWL`+U+9?G24{$u4MdCZ4{L;GJ8XOVQjk z>AV)xxZP7M-NoBa!y}%Ij7!N5_U6bJreWLyPdy1LxmWePeL@ypMg(YMUu8($X zYtj8tJSw)|-rlg^CMn#WhDVr3@1f#-699afuo>Rq&)YFPdO^AP`R52{#<#DwNbH18 zy&~fWif*s&@@3*r<5_=Md=QjTt+i#8gtT1ZNq7XBHjAUJM*y;-`*6JX)9^mV5aau4 z_

4;X&ykaCJQSif2oBBi#V+k$Ilqe-4IG)V6b~U{IE%C?Tsh?k~c-6Bf)veu!;SoYc;KAWy(tuYfI$-O@ z1G&EyPyL`%>ko999bRc&)qLOp)A zyGiyper)iRqt@{lqh#2}75CzCUc}qTUMo*=EtZ{wMD}+^#dSe4s^|vbty<5Orxd?= z6ffO)`ze4r9y^9-{xUqMJhlCDi(at8Gqmr`9b3U;fOq!pB!BwEVLZMC$J^>n{3P7M z8Fq}#Gu|~Su4f<~8HcB~Z_u=x-YsHH3vy@Su?%m(C&xD9fn4P^Z~LYIZ>>E)7wl-E z=z6awAQ;}ct1RR!y!@^wsJ$h7PWUA#?rS={n?fbu(D z4%djs2I7$;L5?LSMhbReMy^v!9Se9_0B>h%*I#s72w?R#ZT(~I^!Mh@us4ku2E!l+ zaZ;j8qF=fe`u~6CAcMZp%h|DgE_m(Mi7(ruH)s2elY3w4+&4ejEu6PH_TaT(;MrGf zJUoDtV(Bo(SA7uQrsQLv-6>6TZYp?ctC$qW#==vqR)FJUouL zIa+)PZSCdS_8TfdS51P7!(7%8VHX@RxIFY`w5lu5a~@VJzz-e;giA?$!nH& zet1UZZP0dU-4~>RINXd>i%0vO>X+juVm$C(OW6T)5!K#iJa1MA#6ac4$ zSJTP3Xt`qmWd(S^76cE_Y|3j_0ch!=#H${7hXHt`AP0Dg6>CwR;F!qlN(=6eCmEi- zpYX#ohz;;;^ssX+9r5(Tqd<57rzDsVpm)--8#z}zZF?i}$6Wl?i65R-d8tEh`}VHL z6|{JEr#$wmr`|a706em>%Q=t1+pMR&mNn97#d10#&+?P8HGg%g!|mkkC;aeco}CdL z3{QgL$;JCyPJ^caYCg_YyD##}w27{f13Z6CEW-mn43==RqeB`$%%0z8d+J-UIthhm zu89*Ln@XQNzSGApr!;;82WXNs^Udb(u zW58^G2uZOykHAAoY)Z2{zEpOb1HJXU)LM z@BgFH{;+%d{5+oH^YhP!_Eb{p^%L?D&r))}Tt4!)-ER*y97U>qoJ7a%-Y}%g? zP>sQ}r-=dCVH!IvzOLAMV+^d~C%{9ZFoh_)>mTij2YfSlo$90%@QHv&+Q@khZJY=*!;x_M0YJs z(oJ{(Hv*5#6p^9>DhVFKraVbwNUv@F>%Q^42Zwb~qjDdTss$cCk;NsU^TRX9PDrt^0km(99X+LJ zKYL>DC#Zb~Di5{YE!FCJu~&xIi50m)YzcMoO8rFd$`~a);)CNB4-YAJ*BI(*;;Jj{ z0<254@y=;izymom zJfNeHe!>rrmEB{C<(e_w{)D!Pr2yA14j#59%B>$u$-ZK_>Lki4mSh*LyhaTcG3c%N zIsmz$V89vSN#WoIr?^0X*3ymcqQHMOzCe zGEv;)Gxie+*PoUY@It^}bUVjOyZ>JZ2A()Z(exMb7Rqxx%V*Cdt=M~d7N>Z3`NGD| z%J5nU-2BZLqKOW|li4BkPVtqRt``&C&iH|r{3DbT*(qJ~YqDmFgM7Cb;Kf_TBjBL8A$WDh4O7?aO#$>i0=#&u7%5iH zu{=DvvTI*LMa)cOOYlbac8rfZ$+N@K?Bf%acPF~qJq7T+T6dbK-ShhiyJv^G7{S2n zFWZ}Ma{cadQ*Q1|T6jyMqu9qC`mtWjq18KX(!>tnb%PxNh!@>haYDQU0Ce*ZC!XLH zGu9KsjY+Z3gf}EQs7{7g@r@k{44$al353T1;Q9$0JQ~WfU}sWZBiAr$v&17l`Oesg zQ;I9NCkPf^o$1c3Jb;UYM`n0q?g`l0l!v$O6wm&I^Y{t_(zsygu` zfJSt)4`0t`-{0-;n3M0LJbrp7#=W&M>>xVb`xI>1uDX&0zm>RP@?1VNp zWO~B6V!=%b4+eXK1_1_46^FrNMdxiNSW61qJNG|HRxyIV2mlc^1>he&X{1?*#5&3=F-JUw(UYK2c8=m~GS&x= z;|6#(t5|?XPukpp>f+$V9|O?mSl94GqXyZ9!Yg4`F~Sc|6KG>2;nk{hPbT&2#X`<0 z`Zss7A71Um3y5wlpFMWjR`a=H2R!mw#d4w$=1=kp@WgA1rm-~fLZ=iJUa=7#*lDfe z7l#MYEvhSf;mPRayTyF37xTm0_vy*zNff+A<7s-{DMdW!#Ah8-+C{_TtYR%ZS{vSs z++NsIjDuG_S5O{a@M!G*91OQuc2&$W*%f&UKqbHqG)Z_8Pn`WW8Gd6w-fZU=( z#KU7cvFQm`F^$$IGP?kH>em6h&@GDlb2t*LAD;Sk055cZ=RRizy%&ZT^0<4cnmAH< o6f`mRy7XRHc@Um$a3? Date: Mon, 27 Apr 2026 09:25:02 -0400 Subject: [PATCH 02/15] new header which includes tools Co-authored-by: Copilot --- src/app/components/Footer.tsx | 8 +- src/app/components/Header.style.ts | 36 ++- src/app/components/Header.tsx | 276 +++++++++++++--------- src/app/components/HeaderMobileDrawer.tsx | 116 ++++++--- 4 files changed, 286 insertions(+), 150 deletions(-) diff --git a/src/app/components/Footer.tsx b/src/app/components/Footer.tsx index 4785aa5f..7f951d30 100644 --- a/src/app/components/Footer.tsx +++ b/src/app/components/Footer.tsx @@ -146,10 +146,9 @@ const Footer: React.FC = () => { - {/* Validators column */} - + {/* Tools column — validators + analytics */} - {t('columns.validators')} + {t('columns.tools')} { )} + + {t('links.gtfsFeatureTracker')} + {/* Company column */} diff --git a/src/app/components/Header.style.ts b/src/app/components/Header.style.ts index 7cde0766..443925a5 100644 --- a/src/app/components/Header.style.ts +++ b/src/app/components/Header.style.ts @@ -1,4 +1,6 @@ -import { type Theme } from '@mui/material'; +import type React from 'react'; +import { MenuItem, Typography, type Theme } from '@mui/material'; +import { styled } from '@mui/material/styles'; import { type SystemStyleObject } from '@mui/system'; import { fontFamily } from '../Theme'; @@ -47,3 +49,35 @@ export const animatedButtonStyling = ( pointerEvents: 'none', }, }); + +export const headerDropdownMenuHeader = (): SystemStyleObject => ({ + px: 2, + pt: 1.5, + pb: 0.5, + display: 'block', + color: 'text.disabled', + lineHeight: 2, +}); + +export const HeaderMenuItemHeader = styled(Typography)(({ theme }) => ({ + paddingLeft: theme.spacing(2), + paddingRight: theme.spacing(2), + paddingTop: theme.spacing(1), + color: theme.vars.palette.primary.main, + fontWeight: 700, + fontFamily: fontFamily.secondary, +})); + +export const HeaderMenuItem = styled(MenuItem)<{ + component?: React.ElementType; + href?: string; + target?: string; + rel?: string; +}>(() => ({ + fontFamily: fontFamily.secondary, + opacity: 0.8, + fontWeight: 500, + '&:hover': { + opacity: 1, + }, +})) as typeof MenuItem; diff --git a/src/app/components/Header.tsx b/src/app/components/Header.tsx index 6be8221e..5291fbf8 100644 --- a/src/app/components/Header.tsx +++ b/src/app/components/Header.tsx @@ -9,12 +9,13 @@ import { Divider, Drawer, IconButton, - ListSubheader, Toolbar, Typography, Button, Menu, + MenuList, MenuItem, + Popover, Select, Alert, AlertTitle, @@ -36,7 +37,12 @@ import { OpenInNew } from '@mui/icons-material'; import { useRemoteConfig } from '../context/RemoteConfigProvider'; import { fontFamily } from '../Theme'; import { defaultRemoteConfigValues } from '../interface/RemoteConfig'; -import { animatedButtonStyling } from './Header.style'; +import { + animatedButtonStyling, + headerDropdownMenuHeader, + HeaderMenuItem, + HeaderMenuItemHeader, +} from './Header.style'; import ThemeToggle from './ThemeToggle'; import HeaderSearchBar from './HeaderSearchBar'; import { useTranslations, useLocale } from 'next-intl'; @@ -133,19 +139,20 @@ export default function DrawerAppBar(): React.ReactElement { const container = typeof window !== 'undefined' ? () => window.document.body : undefined; - const [validatorAnchorEl, setValidatorAnchorEl] = - React.useState(null); - const validatorCloseTimer = + const [toolsAnchorEl, setToolsAnchorEl] = React.useState( + null, + ); + const toolsCloseTimer = React.useRef>(undefined); - const handleValidatorOpen = (e: React.MouseEvent): void => { - clearTimeout(validatorCloseTimer.current); - setValidatorAnchorEl(e.currentTarget); + const handleToolsOpen = (e: React.MouseEvent): void => { + clearTimeout(toolsCloseTimer.current); + setToolsAnchorEl(e.currentTarget); }; - const handleValidatorClose = (): void => { - validatorCloseTimer.current = setTimeout(() => { - setValidatorAnchorEl(null); + const handleToolsClose = (): void => { + toolsCloseTimer.current = setTimeout(() => { + setToolsAnchorEl(null); }, 80); }; @@ -167,7 +174,7 @@ export default function DrawerAppBar(): React.ReactElement { React.useEffect(() => { return () => { - clearTimeout(validatorCloseTimer.current); + clearTimeout(toolsCloseTimer.current); clearTimeout(accountCloseTimer.current); }; }, []); @@ -293,84 +300,174 @@ export default function DrawerAppBar(): React.ReactElement { -

{ - setValidatorAnchorEl(null); + setToolsAnchorEl(null); }} disableScrollLock disableRestoreFocus + anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} + transformOrigin={{ vertical: 'top', horizontal: 'right' }} sx={{ pointerEvents: 'none' }} slotProps={{ paper: { onMouseEnter: () => { - clearTimeout(validatorCloseTimer.current); + clearTimeout(toolsCloseTimer.current); }, - onMouseLeave: handleValidatorClose, + onMouseLeave: handleToolsClose, sx: { pointerEvents: 'auto' }, }, }} > - - {tCommon('gtfsValidator')} - - - - {tCommon('gtfsRtValidator')} - - - {config.gbfsValidator ? ( - { - setValidatorAnchorEl(null); - handleNavigation('/gbfs-validator'); - }} - > - {tCommon('gbfsValidator')} - - ) : ( - - {tCommon('gbfsValidator')} - - - )} - + + {/* Validators column */} + + + Validators + + + + {tCommon('gtfsValidator')} + + + + {tCommon('gtfsRtValidator')} + + + {config.gbfsValidator ? ( + { + setToolsAnchorEl(null); + handleNavigation('/gbfs-validator'); + }} + > + {tCommon('gbfsValidator')} + + ) : ( + + {tCommon('gbfsValidator')} + + + )} + + + + {/* Analytics column */} + + + Analytics + + + + GTFS Feature Tracker + + + + {/* Metrics column — admin only */} + {metricsOptionsEnabled ? ( + <> + + + + Metrics - Admin Only + + + + GTFS + + {gtfsMetricsNavItems.map((item) => ( + { + setToolsAnchorEl(null); + }} + > + {item.title} + + ))} + + GBFS + + {gbfsMetricsNavItems.map((item) => ( + { + setToolsAnchorEl(null); + }} + > + {item.title} + + ))} + + + + ) : null} + + {isAuthenticated ? ( @@ -439,57 +536,6 @@ export default function DrawerAppBar(): React.ReactElement { > {tCommon('signOut')} - {metricsOptionsEnabled && [ - , - - {tCommon('metricsAdminOnly')} - , - - GTFS - , - ...gtfsMetricsNavItems.map((item) => ( - { - setAccountAnchorEl(null); - handleNavigation(item.target); - }} - > - {item.title} - - )), - - GBFS - , - ...gbfsMetricsNavItems.map((item) => ( - { - setAccountAnchorEl(null); - handleNavigation(item.target); - }} - > - {item.title} - - )), - ]} ) : ( diff --git a/src/app/components/HeaderMobileDrawer.tsx b/src/app/components/HeaderMobileDrawer.tsx index e7d4d53d..1cd10117 100644 --- a/src/app/components/HeaderMobileDrawer.tsx +++ b/src/app/components/HeaderMobileDrawer.tsx @@ -155,53 +155,107 @@ export default function DrawerContent({ ))} - {config.gbfsValidator && ( - - } - aria-controls='validators-content' - id='validators-content' + + } + aria-controls='tools-content' + id='tools-header' + > + - - {t('validators')} - - - + Tools + + + + {/* Validators sub-section */} + + {t('validators')} + + + + {config.gbfsValidator ? ( + ) : ( - - - - )} + )} + + {/* Analytics sub-section */} + + Analytics + + + + {metricsOptionsEnabled && ( <> From f1931adf55dc22d7031860b77aba535d91cfc0f1 Mon Sep 17 00:00:00 2001 From: Alessandro Kreslin Date: Mon, 27 Apr 2026 09:25:15 -0400 Subject: [PATCH 03/15] gtfs feature tracker Co-authored-by: Copilot --- messages/en.json | 4 +- messages/fr.json | 4 +- .../[locale]/feeds/components/FeedsScreen.tsx | 18 +- .../components/GtfsFeatureTracker.helpers.tsx | 163 +++++ .../components/GtfsFeatureTracker.tsx | 611 ++++++++++++++++++ .../gtfs-feature-tracker/components/types.ts | 65 ++ .../lib/fetchTrackerData.ts | 200 ++++++ .../[locale]/gtfs-feature-tracker/page.tsx | 48 ++ 8 files changed, 1108 insertions(+), 5 deletions(-) create mode 100644 src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.helpers.tsx create mode 100644 src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx create mode 100644 src/app/[locale]/gtfs-feature-tracker/components/types.ts create mode 100644 src/app/[locale]/gtfs-feature-tracker/lib/fetchTrackerData.ts create mode 100644 src/app/[locale]/gtfs-feature-tracker/page.tsx diff --git a/messages/en.json b/messages/en.json index 77b3d33a..eb17c312 100644 --- a/messages/en.json +++ b/messages/en.json @@ -138,6 +138,7 @@ "resultsFor": "{startResult}-{endResult} of {totalResults} results", "deprecated": "Deprecated", "searchPlaceholder": "Transit provider, feed name, or location", + "featureTrackerBanner": "See which trip planners use these features", "noResults": "We're sorry, we found no search results for ''{activeSearch}''.", "searchSuggestions": "Search suggestions: ", "searchTips": { @@ -539,7 +540,7 @@ "copyright": "© {year} MobilityDatabase. All rights reserved.", "columns": { "platform": "Platform", - "validators": "Validators", + "tools": "Tools", "company": "Company", "legal": "Legal" }, @@ -547,6 +548,7 @@ "feeds": "Feeds", "addFeed": "Add a Feed", "apiDocs": "API Docs", + "gtfsFeatureTracker": "GTFS Feature Tracker", "gtfsValidator": "GTFS Validator", "gtfsRtValidator": "GTFS-RT Validator", "gbfsValidator": "GBFS Validator", diff --git a/messages/fr.json b/messages/fr.json index 0450aa9d..a01798ad 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -138,6 +138,7 @@ "resultsFor": "{startResult}-{endResult} of {totalResults} results", "deprecated": "Deprecated", "searchPlaceholder": "Transit provider, feed name, or location", + "featureTrackerBanner": "Voir quels planificateurs d’itinéraires utilisent ces fonctionnalités", "noResults": "We're sorry, we found no search results for ''{activeSearch}''.", "searchSuggestions": "Search suggestions: ", "searchTips": { @@ -539,7 +540,7 @@ "copyright": "© {year} MobilityDatabase. Tous droits réservés.", "columns": { "platform": "Plateforme", - "validators": "Validateurs", + "tools": "Outils", "company": "Entreprise", "legal": "Légal" }, @@ -547,6 +548,7 @@ "feeds": "Flux", "addFeed": "Ajouter un flux", "apiDocs": "Docs API", + "gtfsFeatureTracker": "Suivi des fonctionnalités GTFS", "gtfsValidator": "Validateur GTFS", "gtfsRtValidator": "Validateur GTFS-RT", "gbfsValidator": "Validateur GBFS", diff --git a/src/app/[locale]/feeds/components/FeedsScreen.tsx b/src/app/[locale]/feeds/components/FeedsScreen.tsx index ead7f206..f5f4e01e 100644 --- a/src/app/[locale]/feeds/components/FeedsScreen.tsx +++ b/src/app/[locale]/feeds/components/FeedsScreen.tsx @@ -6,7 +6,6 @@ import { Button, Chip, Container, - CssBaseline, Grid, InputAdornment, LinearProgress, @@ -19,8 +18,9 @@ import { Typography, useTheme, } from '@mui/material'; -import { Search } from '@mui/icons-material'; +import { OpenInNew, Search } from '@mui/icons-material'; import { useSearchParams, useRouter, usePathname } from 'next/navigation'; +import NextLink from 'next/link'; import SearchTable from '../../../screens/Feeds/SearchTable'; import { useTranslations } from 'next-intl'; import { @@ -179,7 +179,6 @@ export default function FeedsScreen(): React.ReactElement { position: 'relative', }} > - + {selectedFeatures.length > 0 && ( + + )} {selectedFeedTypes.gtfs && ( ; + if (n.startsWith('no')) + return ; + if (n === 'integration planned') + return ; + if (n === 'test in progress') + return ; + if (n === 'partial integration') + return ; + if (n === 'some fields are ignored') + return ; + return ; +} + +export function isStatusSupported(raw: string): boolean { + return raw.toLowerCase().trim().startsWith('yes'); +} + +export function computeCategoryProgress( + features: Feature[], + consumers: Consumer[], +): number { + let supported = 0; + let total = 0; + for (const feature of features) { + for (const consumer of consumers) { + const raw = feature.support[consumer.id]?.rawStatus ?? ''; + if (raw) { + total++; + if (isStatusSupported(raw)) supported++; + } + } + } + return total > 0 ? Math.round((supported / total) * 100) : 0; +} + +export function formatDate(dateStr: string): string { + if (!dateStr) return ''; + const d = new Date(dateStr); + if (isNaN(d.getTime())) return dateStr; + return d.toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', + }); +} + +export function tokenizeDetail( + text: string, + knownFieldsSet: Set, +): Token[] { + if (!text) return []; + const tokens: Array = []; + + // 1. Markdown links [label](url) + const mdRe = /\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g; + let m: RegExpExecArray | null; + while ((m = mdRe.exec(text)) !== null) { + tokens.push({ + type: 'mdlink', + label: m[1], + url: m[2], + start: m.index, + end: m.index + m[0].length, + }); + } + + // 2. Bare URLs + const urlRe = /https?:\/\/[^\s,)]+/g; + while ((m = urlRe.exec(text)) !== null) { + const overlaps = tokens.some( + (t) => m!.index >= t.start && m!.index < t.end, + ); + if (!overlaps) + tokens.push({ + type: 'url', + value: m[0], + start: m.index, + end: m.index + m[0].length, + }); + } + + // 3. .txt file names + const fileRe = /\b[a-z_]+\.txt\b/g; + while ((m = fileRe.exec(text)) !== null) { + const overlaps = tokens.some( + (t) => m!.index >= t.start && m!.index < t.end, + ); + if (!overlaps) + tokens.push({ + type: 'file', + value: m[0], + start: m.index, + end: m.index + m[0].length, + }); + } + + // 4. Known GTFS field names + const fieldRe = /\b[a-z][a-z0-9_]*[a-z0-9]\b|\b[a-z]{2,}\b/g; + while ((m = fieldRe.exec(text)) !== null) { + if (!knownFieldsSet.has(m[0])) continue; + const overlaps = tokens.some( + (t) => m!.index >= t.start && m!.index < t.end, + ); + if (!overlaps) + tokens.push({ + type: 'field', + value: m[0], + start: m.index, + end: m.index + m[0].length, + }); + } + + tokens.sort((a, b) => a.start - b.start); + + const segments: Token[] = []; + let cursor = 0; + for (const tok of tokens) { + if (tok.start > cursor) + segments.push({ type: 'text', value: text.slice(cursor, tok.start) }); + segments.push(tok); + cursor = tok.end; + } + if (cursor < text.length) + segments.push({ type: 'text', value: text.slice(cursor) }); + return segments; +} diff --git a/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx b/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx new file mode 100644 index 00000000..ad329a72 --- /dev/null +++ b/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx @@ -0,0 +1,611 @@ +'use client'; + +import { useState, useMemo, memo, type ReactElement, Fragment } from 'react'; +import { + Box, + Typography, + Chip, + Button, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + IconButton, + Collapse, + LinearProgress, + Paper, + Tooltip, + Link as MuiLink, + Divider, +} from '@mui/material'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import ExpandLessIcon from '@mui/icons-material/ExpandLess'; +import OpenInNewIcon from '@mui/icons-material/OpenInNew'; +import MenuBookIcon from '@mui/icons-material/MenuBook'; +import DatasetIcon from '@mui/icons-material/Dataset'; +import FilterAltIcon from '@mui/icons-material/FilterAlt'; +import AddIcon from '@mui/icons-material/Add'; +import Image from 'next/image'; +import type { Feature, GtfsFeatureTrackerProps } from './types'; +import { + getStatusText, + getStatusIcon, + computeCategoryProgress, + formatDate, + tokenizeDetail, +} from './GtfsFeatureTracker.helpers'; + +const CONTRIBUTE_URL = 'https://forms.gle/W3iJGgoaPDYLypZ38'; + +const CONSUMER_TYPES = [ + 'Journey Planner', + 'Open Source Journey Planner', + 'Specialized Journey Planner', +] as const; + +const CONSUMER_LOGOS: Record = { + google: '/assets/tripPlannerLogos/gmaps.png', + transitapp: '/assets/tripPlannerLogos/transitapp.png', + motis: '/assets/tripPlannerLogos/motis.png', + opentripplanner: '/assets/tripPlannerLogos/opentripplanner.png', + aubin: '/assets/tripPlannerLogos/aubin-app.png', +}; + +// ── FeatureDetail ───────────────────────────────────────────────────────────── +// Extracted as a memo component (rerender-memo) so each cell only re-renders +// when its own text or the knownFields set changes. + +const FeatureDetail = memo(function FeatureDetail({ + text, + knownFieldsSet, +}: { + text: string; + knownFieldsSet: Set; +}): ReactElement { + const segments = tokenizeDetail(text, knownFieldsSet); + return ( + + {segments.map((seg, i) => { + if (seg.type === 'mdlink') + return ( + + {seg.label} + + + ); + if (seg.type === 'url') + return ( + + Learn more + + + ); + if (seg.type === 'file') + return ( + + {seg.value} + + ); + if (seg.type === 'field') + return ( + + {seg.value} + + ); + return {seg.value}; + })} + + ); +}); + +// ── Main component ──────────────────────────────────────────────────────────── + +export default function GtfsFeatureTracker({ + features, + consumers, + knownFields, +}: GtfsFeatureTrackerProps): ReactElement { + const [selectedType, setSelectedType] = useState(null); + const [expandedCategories, setExpandedCategories] = useState< + Record + >({}); + + const knownFieldsSet = useMemo(() => new Set(knownFields), [knownFields]); + + const filteredConsumers = useMemo(() => { + if (selectedType === null) return consumers; + return consumers.filter((c) => c.type === selectedType); + }, [consumers, selectedType]); + + // Combined into one loop (js-combine-iterations): avoids iterating `features` twice + const { categories, featuresByCategory } = useMemo(() => { + const cats: string[] = []; + const map: Record = {}; + for (const f of features) { + if (map[f.category] === undefined) { + cats.push(f.category); + map[f.category] = []; + } + map[f.category].push(f); + } + return { categories: cats, featuresByCategory: map }; + }, [features]); + + const toggleCategory = (category: string): void => { + setExpandedCategories((prev) => ({ + ...prev, + [category]: !(prev[category] ?? true), + })); + }; + + const isCategoryExpanded = (category: string): boolean => { + return expandedCategories[category] ?? true; + }; + + return ( + ({ + maxWidth: theme.breakpoints.values.xl, + mx: 'auto', + })} + > + ({ + maxWidth: theme.breakpoints.values.xl, + mx: 3, + mb: 3, + })} + > + GTFS Features Adoption Tracker + + + + Consumers + + {/* Consumer Legend */} + + {filteredConsumers.map((consumer) => ( + + {consumer.name} + + {consumer.name} + + + ))} + + + + {CONSUMER_TYPES.map((type) => ( + { + setSelectedType(selectedType === type ? null : type); + }} + /> + ))} + + + + + + + + {/* Category Sections */} + {categories.map((category) => { + const categoryFeatures = featuresByCategory[category] ?? []; + const progress = computeCategoryProgress( + categoryFeatures, + filteredConsumers, + ); + const expanded = isCategoryExpanded(category); + + return ( + + {/* Category Header */} + { + toggleCategory(category); + }} + sx={{ + display: 'flex', + alignItems: 'center', + gap: 2, + cursor: 'pointer', + backgroundColor: 'background.default', + + px: 3, + py: 1.5, + userSelect: 'none', + }} + > + + {expanded ? : } + + + {category} + + ({ + bgcolor: `rgba(${theme.vars.palette.common.onBackgroundChannel} / 0.1)`, + })} + /> + + + + + + {progress}% + + + + + + {/* Feature Table */} + + + + + + + Feature + + {filteredConsumers.map((consumer) => ( + + + + + + {consumer.name} + + + {consumer.lastUpdate != null ? ( + + {`Updated ${formatDate(consumer.lastUpdate)}`} + + ) : null} + + + ))} + + + + {categoryFeatures.map((feature) => ( + + + + + {feature.name} + + + {feature.documentationUrl != null ? ( + + ) : null} + {feature.category.toLowerCase() !== 'base' && ( + + )} + + + + {filteredConsumers.map((consumer) => { + const support = feature.support[consumer.id] ?? { + rawStatus: '', + details: '', + }; + const statusText = getStatusText(support.rawStatus); + return ( + + + + {getStatusIcon(support.rawStatus)} + + {statusText} + + + {support.details != null && + support.details !== '' ? ( + + ) : null} + + + ); + })} + + ))} + +
+
+
+
+ ); + })} +
+
+ ); +} diff --git a/src/app/[locale]/gtfs-feature-tracker/components/types.ts b/src/app/[locale]/gtfs-feature-tracker/components/types.ts new file mode 100644 index 00000000..84cc6717 --- /dev/null +++ b/src/app/[locale]/gtfs-feature-tracker/components/types.ts @@ -0,0 +1,65 @@ +export interface TokenBase { + start: number; + end: number; +} + +export interface MdLinkToken extends TokenBase { + type: 'mdlink'; + label: string; + url: string; +} + +export interface UrlToken extends TokenBase { + type: 'url'; + value: string; +} + +export interface FileToken extends TokenBase { + type: 'file'; + value: string; +} + +export interface FieldToken extends TokenBase { + type: 'field'; + value: string; +} + +export interface TextToken { + type: 'text'; + value: string; +} + +export type Token = MdLinkToken | UrlToken | FileToken | FieldToken | TextToken; + +export interface GtfsFeatureTrackerProps { + features: Feature[]; + consumers: Consumer[]; + knownFields: string[]; +} + +export interface Consumer { + id: string; + name: string; + type: string; + lastUpdate: string; +} + +export interface FeatureSupport { + /** Raw status from CSV (e.g. "YES - for every feed", "Some fields are ignored") */ + rawStatus: string; + details: string; +} + +export interface Feature { + name: string; + category: string; + description: string; + documentationUrl: string | null; + support: Record; +} + +export interface TrackerData { + features: Feature[]; + consumers: Consumer[]; + knownFields: string[]; +} diff --git a/src/app/[locale]/gtfs-feature-tracker/lib/fetchTrackerData.ts b/src/app/[locale]/gtfs-feature-tracker/lib/fetchTrackerData.ts new file mode 100644 index 00000000..1a62d122 --- /dev/null +++ b/src/app/[locale]/gtfs-feature-tracker/lib/fetchTrackerData.ts @@ -0,0 +1,200 @@ +/* eslint-disable */ +// This file currently retrieves all data to display gtfs feature tracking information +// In the future when this data will come from the database, this file can be removed and the data fetching logic can be moved to the page.tsx file + +import type { + Consumer, + Feature, + FeatureSupport, + TrackerData, +} from '../components/types'; + +const CSV_URL = + 'https://docs.google.com/spreadsheets/d/e/2PACX-1vSu9_3lyF9caXrDdlGCtO1Bg17Uhkh_L9l-REYkYVUINvrEEaVwrx1mSZ--_iKAGcJ2x8bFBzYHVU74/pub?output=csv'; +const CATEGORIES_CSV_URL = + 'https://docs.google.com/spreadsheets/d/e/2PACX-1vSu9_3lyF9caXrDdlGCtO1Bg17Uhkh_L9l-REYkYVUINvrEEaVwrx1mSZ--_iKAGcJ2x8bFBzYHVU74/pub?gid=1998786437&single=true&output=csv'; +const FIELDS_CSV_URL = + 'https://docs.google.com/spreadsheets/d/e/2PACX-1vSu9_3lyF9caXrDdlGCtO1Bg17Uhkh_L9l-REYkYVUINvrEEaVwrx1mSZ--_iKAGcJ2x8bFBzYHVU74/pub?gid=1909638109&single=true&output=csv'; + +const GTFS_DOCS_BASE = 'https://gtfs.org/documentation/schedule/reference/'; + +export const DOCS_URL_MAP: Record = { + Agency: `${GTFS_DOCS_BASE}#agencytxt`, + Stops: `${GTFS_DOCS_BASE}#stopstxt`, + Routes: `${GTFS_DOCS_BASE}#routestxt`, + 'Service Dates': `${GTFS_DOCS_BASE}#calendartxt`, + Trips: `${GTFS_DOCS_BASE}#tripstxt`, + 'Stop Times': `${GTFS_DOCS_BASE}#stop_timestxt`, + 'Feed Information': `${GTFS_DOCS_BASE}#feed_infotxt`, + Shapes: `${GTFS_DOCS_BASE}#shapestxt`, + 'Route Colors': `${GTFS_DOCS_BASE}#routestxt`, + 'Bike Allowed': `${GTFS_DOCS_BASE}#tripstxt`, + Headsigns: `${GTFS_DOCS_BASE}#tripstxt`, + 'Location Types': `${GTFS_DOCS_BASE}#stopstxt`, + Frequencies: `${GTFS_DOCS_BASE}#frequenciestxt`, + Transfers: `${GTFS_DOCS_BASE}#transferstxt`, + Translations: `${GTFS_DOCS_BASE}#translationstxt`, + Attributions: `${GTFS_DOCS_BASE}#attributionstxt`, + 'Stops Wheelchair Accessibility': `${GTFS_DOCS_BASE}#stopstxt`, + 'Trips Wheelchair Accessibility': `${GTFS_DOCS_BASE}#tripstxt`, + 'Text-to-Speech': `${GTFS_DOCS_BASE}#stopstxt`, + 'Fare Products': `${GTFS_DOCS_BASE}#fare_productstxt`, + 'Fare Media': `${GTFS_DOCS_BASE}#fare_mediatxt`, + 'Rider Categories': `${GTFS_DOCS_BASE}#rider_categoriestxt`, + 'Route-Based Fares': `${GTFS_DOCS_BASE}#fare_rulestxt`, + 'Time-Based Fares': `${GTFS_DOCS_BASE}#fare_leg_rulestxt`, + 'Zone-Based Fares': `${GTFS_DOCS_BASE}#fare_leg_rulestxt`, + 'Fare Transfers': `${GTFS_DOCS_BASE}#fare_transfer_rulestxt`, + 'Fares V1': `${GTFS_DOCS_BASE}#fare_attributestxt`, + 'Pathway Connections': `${GTFS_DOCS_BASE}#pathwaystxt`, + 'Pathway Details': `${GTFS_DOCS_BASE}#pathwaystxt`, + 'In-Station Traversal Time': `${GTFS_DOCS_BASE}#pathwaystxt`, + 'Pathway Signs': `${GTFS_DOCS_BASE}#pathwaystxt`, + Levels: `${GTFS_DOCS_BASE}#levelstxt`, + 'Continuous Stops': `${GTFS_DOCS_BASE}#stopstxt`, + 'Booking Rules': `${GTFS_DOCS_BASE}#booking_rulestxt`, + 'Predefined Routes with Deviation': `${GTFS_DOCS_BASE}#stop_timestxt`, + 'Zone-based Demand Responsive Services': `${GTFS_DOCS_BASE}#locationstxt`, + 'Fixed-Stops Demand Responsive Services': `${GTFS_DOCS_BASE}#stop_timestxt`, +}; + +// RFC-4180 compliant CSV parser handling quoted fields with embedded commas/newlines +function parseCSVText(text: string): Array> { + const rows: string[][] = []; + let row: string[] = []; + let field = ''; + let inQ = false; + + for (let i = 0; i < text.length; i++) { + const c = text[i]; + const n = text[i + 1]; + if (inQ) { + if (c === '"' && n === '"') { + field += '"'; + i++; + } else if (c === '"') { + inQ = false; + } else { + field += c; + } + } else { + if (c === '"') { + inQ = true; + } else if (c === ',') { + row.push(field.trim()); + field = ''; + } else if (c === '\r' && n === '\n') { + row.push(field.trim()); + if (row.some((v) => v)) rows.push(row); + row = []; + field = ''; + i++; + } else if (c === '\n' || c === '\r') { + row.push(field.trim()); + if (row.some((v) => v)) rows.push(row); + row = []; + field = ''; + } else { + field += c; + } + } + } + row.push(field.trim()); + if (row.some((v) => v)) rows.push(row); + + if (rows.length === 0) return []; + const headers = rows[0]; + return rows.slice(1).map((r) => { + const obj: Record = {}; + headers.forEach((h, idx) => { + obj[h] = r[idx] ?? ''; + }); + return obj; + }); +} + +function formatConsumerName(id: string): string { + const names: Record = { + google: 'Google', + transitapp: 'Transit', + motis: 'Motis', + opentripplanner: 'OpenTripPlanner', + aubin: 'Aubin', + }; + return names[id.toLowerCase()] ?? id; +} + +export async function fetchTrackerData(): Promise { + const [featuresRes, categoriesRes, fieldsRes] = await Promise.all([ + fetch(CSV_URL, { next: { revalidate: 3600 } }), + fetch(CATEGORIES_CSV_URL, { next: { revalidate: 3600 } }), + fetch(FIELDS_CSV_URL, { next: { revalidate: 3600 } }), + ]); + + const [featuresText, categoriesText, fieldsText] = await Promise.all([ + featuresRes.text(), + categoriesRes.text(), + fieldsRes.text(), + ]); + + // Parse known GTFS field names + const fieldsRows = parseCSVText(fieldsText); + const knownFields = Array.from( + new Set(fieldsRows.map((r) => r.field_name?.trim()).filter(Boolean)), + ); + + // Parse categories → consumers with types and dates + const categoriesRows = parseCSVText(categoriesText); + const consumerDates: Record = {}; + const consumerTypes: Record = {}; + for (const row of categoriesRows) { + const c = (row.consumer ?? '').trim(); + if (!c) continue; + const key = c.toLowerCase().replace(/\s+/g, ''); + consumerTypes[key] = (row.type ?? '').trim(); + consumerDates[key] = (row.last_update ?? '').trim(); + } + + // Parse features CSV — header driven + const featureRows = parseCSVText(featuresText); + if (featureRows.length === 0) { + return { features: [], consumers: [], knownFields }; + } + + // Extract consumer IDs from header columns (pattern: {id}_use) + const headers = Object.keys(featureRows[0]); + const consumerIds = headers + .filter((h) => h.endsWith('_use')) + .map((h) => h.replace('_use', '')); + + // Build consumer list preserving CSV column order + const consumers: Consumer[] = consumerIds.map((id) => { + const key = id.toLowerCase().replace(/\s+/g, ''); + return { + id, + name: formatConsumerName(id), + type: consumerTypes[key] ?? '', + lastUpdate: consumerDates[key] ?? '', + }; + }); + + const features: Feature[] = featureRows.map((row) => { + const support: Record = {}; + for (const cId of consumerIds) { + const cLow = cId.toLowerCase(); + support[cId] = { + rawStatus: (row[`${cId}_use`] ?? row[`${cLow}_use`] ?? '').trim(), + details: (row[`${cId}_details`] ?? row[`${cLow}_details`] ?? '').trim(), + }; + } + return { + name: row.Feature ?? '', + category: row.Type ?? 'Other', + description: row.Description ?? '', + documentationUrl: DOCS_URL_MAP[row.Feature ?? ''] ?? null, + support, + }; + }); + + return { features, consumers, knownFields }; +} diff --git a/src/app/[locale]/gtfs-feature-tracker/page.tsx b/src/app/[locale]/gtfs-feature-tracker/page.tsx new file mode 100644 index 00000000..b8391c8f --- /dev/null +++ b/src/app/[locale]/gtfs-feature-tracker/page.tsx @@ -0,0 +1,48 @@ +import { type ReactElement } from 'react'; +import { setRequestLocale } from 'next-intl/server'; +import { type Locale, routing } from '../../../i18n/routing'; +import { type Metadata } from 'next'; +import GtfsFeatureTracker from './components/GtfsFeatureTracker'; +import { fetchTrackerData } from './lib/fetchTrackerData'; + +export const dynamic = 'force-static'; +export const revalidate = 86400; // Revalidate every day + +export const metadata: Metadata = { + title: 'GTFS Features Adoption Tracker | MobilityDatabase', + description: + 'Track the adoption of GTFS features across major journey planners including Google, Transit, Motis, OpenTripPlanner, and more.', + openGraph: { + title: 'GTFS Features Adoption Tracker | MobilityDatabase', + description: + 'Track the adoption of GTFS features across major journey planners including Google, Transit, Motis, OpenTripPlanner, and more.', + url: 'https://mobilitydatabase.org/gtfs-feature-tracker', + siteName: 'MobilityDatabase', + type: 'website', + }, +}; + +export function generateStaticParams(): Array<{ locale: Locale }> { + return routing.locales.map((locale) => ({ locale })); +} + +interface PageProps { + params: Promise<{ locale: string }>; +} + +export default async function GtfsFeatureTrackerPage({ + params, +}: PageProps): Promise { + const { locale } = await params; + setRequestLocale(locale); + + const { features, consumers, knownFields } = await fetchTrackerData(); + + return ( + + ); +} From a566cf9b3aefbd9315c5cc53c1e6ee89f2e58337 Mon Sep 17 00:00:00 2001 From: Alessandro Kreslin Date: Mon, 27 Apr 2026 10:29:23 -0400 Subject: [PATCH 04/15] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../components/GtfsFeatureTracker.tsx | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx b/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx index ad329a72..5d85e982 100644 --- a/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx +++ b/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx @@ -234,23 +234,41 @@ export default function GtfsFeatureTracker({ alignItems: 'center', }} > - {filteredConsumers.map((consumer) => ( - - {consumer.name} - - {consumer.name} - - - ))} + {filteredConsumers.map((consumer) => { + const consumerLogoSrc = CONSUMER_LOGOS[consumer.id.toLowerCase()]; + + return ( + + {consumerLogoSrc ? ( + {consumer.name} + ) : ( + ({ + width: 28, + height: 28, + borderRadius: 2, + bgcolor: theme.palette.grey[200], + border: `1px solid ${theme.palette.divider}`, + flexShrink: 0, + })} + /> + )} + + {consumer.name} + + + ); + })} Date: Mon, 27 Apr 2026 14:32:17 +0000 Subject: [PATCH 05/15] fix: use locale-aware Link for GTFS Feature Tracker in mobile drawer Agent-Logs-Url: https://github.com/MobilityData/mobilitydatabase-web/sessions/1cf1ffaf-3a8a-4ba1-80e6-4e5bab377495 Co-authored-by: Alessandro100 <18631060+Alessandro100@users.noreply.github.com> --- src/app/components/HeaderMobileDrawer.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/components/HeaderMobileDrawer.tsx b/src/app/components/HeaderMobileDrawer.tsx index 1cd10117..1ab63d39 100644 --- a/src/app/components/HeaderMobileDrawer.tsx +++ b/src/app/components/HeaderMobileDrawer.tsx @@ -33,6 +33,7 @@ import { useRemoteConfig } from '../context/RemoteConfigProvider'; import { useTranslations } from 'next-intl'; import Image from 'next/image'; import ThemeToggle from './ThemeToggle'; +import { Link as LocaleLink } from '../../i18n/navigation'; const websiteTile = 'MobilityDatabase'; @@ -249,6 +250,7 @@ export default function DrawerContent({ - Validators + {tCommon('validators')} - Analytics + {tCommon('analytics')} - GTFS Feature Tracker + {tCommon('gtfsFeatureTracker')} @@ -429,11 +429,11 @@ export default function DrawerAppBar(): React.ReactElement { variant='overline' sx={headerDropdownMenuHeader} > - Metrics - Admin Only + {tCommon('metricsAdminOnly')} - GTFS + {tCommon('gtfs')} {gtfsMetricsNavItems.map((item) => ( ))} - GBFS + {tCommon('gbfs')} {gbfsMetricsNavItems.map((item) => ( - Tools + {t('tools')} @@ -245,7 +245,7 @@ export default function DrawerContent({ color: 'text.secondary', }} > - Analytics + {t('analytics')}
@@ -270,7 +270,7 @@ export default function DrawerContent({ variant={'subtitle1'} sx={{ fontFamily: fontFamily.secondary }} > - GTFS Metrics + {`${t('gtfs')} ${t('metrics')}`} @@ -296,7 +296,7 @@ export default function DrawerContent({ variant={'subtitle1'} sx={{ fontFamily: fontFamily.secondary }} > - GBFS Metrics + {`${t('gbfs')} ${t('metrics')}`} @@ -326,7 +326,7 @@ export default function DrawerContent({ variant={'subtitle1'} sx={{ fontFamily: fontFamily.secondary }} > - Account + {t('account')} @@ -335,20 +335,20 @@ export default function DrawerContent({ sx={mobileNavElementStyle} href={ACCOUNT_TARGET} > - Account Details + {t('accountDetails')} ) : ( )} From 5dd0c91ec01733a4eea860190411093ce9d12940 Mon Sep 17 00:00:00 2001 From: Alessandro Kreslin Date: Mon, 27 Apr 2026 11:35:51 -0400 Subject: [PATCH 10/15] lint fix Co-authored-by: Copilot --- .../components/GtfsFeatureTracker.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx b/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx index 9e791e43..689603b7 100644 --- a/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx +++ b/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx @@ -242,7 +242,7 @@ export default function GtfsFeatureTracker({ key={consumer.id} sx={{ display: 'flex', alignItems: 'center', gap: 1 }} > - {consumerLogoSrc ? ( + {consumerLogoSrc != null && consumerLogoSrc !== '' ? ( {consumer.name} )} - + {consumer.name} @@ -432,7 +436,9 @@ export default function GtfsFeatureTracker({ sx={{ minWidth: '150px', width: - 'calc(100% / ' + filteredConsumers.length + ')', + 'calc(100% / ' + + filteredConsumers.length + + ')', }} > - {consumerLogo ? ( + {consumerLogo != null && + consumerLogo !== '' ? ( {consumer.name} - {consumer.name?.charAt(0).toUpperCase() ?? '?'} + {consumer.name?.charAt(0).toUpperCase() ?? + '?'} )} From f3d0cc5c73f9afd834171d6ee8fbdff331c25840 Mon Sep 17 00:00:00 2001 From: Alessandro Kreslin Date: Mon, 27 Apr 2026 13:22:45 -0400 Subject: [PATCH 11/15] stronger messaging for single selected feature Co-authored-by: Copilot --- messages/en.json | 1 + messages/fr.json | 1 + .../[locale]/feeds/components/FeedsScreen.tsx | 15 +- .../components/GtfsFeatureTracker.tsx | 321 +++++++++++------- src/app/utils/featureAnchor.ts | 11 + 5 files changed, 226 insertions(+), 123 deletions(-) create mode 100644 src/app/utils/featureAnchor.ts diff --git a/messages/en.json b/messages/en.json index 05b6f806..3b815be7 100644 --- a/messages/en.json +++ b/messages/en.json @@ -144,6 +144,7 @@ "deprecated": "Deprecated", "searchPlaceholder": "Transit provider, feed name, or location", "featureTrackerBanner": "See which trip planners use these features", + "featureTrackerBannerSingle": "See which trip planners use {feature}", "noResults": "We're sorry, we found no search results for ''{activeSearch}''.", "searchSuggestions": "Search suggestions: ", "searchTips": { diff --git a/messages/fr.json b/messages/fr.json index 06a94178..f24fa020 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -144,6 +144,7 @@ "deprecated": "Deprecated", "searchPlaceholder": "Transit provider, feed name, or location", "featureTrackerBanner": "Voir quels planificateurs d’itinéraires utilisent ces fonctionnalités", + "featureTrackerBannerSingle": "Voir quels planificateurs d’itinéraires utilisent {feature}", "noResults": "We're sorry, we found no search results for ''{activeSearch}''.", "searchSuggestions": "Search suggestions: ", "searchTips": { diff --git a/src/app/[locale]/feeds/components/FeedsScreen.tsx b/src/app/[locale]/feeds/components/FeedsScreen.tsx index f5f4e01e..cbbc43d6 100644 --- a/src/app/[locale]/feeds/components/FeedsScreen.tsx +++ b/src/app/[locale]/feeds/components/FeedsScreen.tsx @@ -39,6 +39,7 @@ import { deriveFilterFlags, buildSearchUrl, } from '../lib/useFeedsSearch'; +import { toFeatureAnchor } from '../../../utils/featureAnchor'; export default function FeedsScreen(): React.ReactElement { const theme = useTheme(); @@ -68,6 +69,16 @@ export default function FeedsScreen(): React.ReactElement { areGBFSFiltersEnabled, } = deriveFilterFlags(selectedFeedTypes); + const featureTrackerHref = + selectedFeatures.length === 1 + ? `/gtfs-feature-tracker#${toFeatureAnchor(selectedFeatures[0])}` + : '/gtfs-feature-tracker'; + + const featureTrackerLabel = + selectedFeatures.length === 1 + ? t('featureTrackerBannerSingle', { feature: selectedFeatures[0] }) + : t('featureTrackerBanner'); + // SWR-powered data fetching - keyed off URL params const { feedsData, isLoading, isValidating, isError, searchLimit } = useFeedsSearch(searchParams); @@ -321,14 +332,14 @@ export default function FeedsScreen(): React.ReactElement { {selectedFeatures.length > 0 && ( )} {selectedFeedTypes.gtfs && ( diff --git a/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx b/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx index 689603b7..049dafa2 100644 --- a/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx +++ b/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx @@ -1,6 +1,14 @@ 'use client'; -import { useState, useMemo, memo, type ReactElement, Fragment } from 'react'; +import { + useState, + useMemo, + useEffect, + useRef, + memo, + type ReactElement, + Fragment, +} from 'react'; import { Box, Typography, @@ -36,6 +44,7 @@ import { formatDate, tokenizeDetail, } from './GtfsFeatureTracker.helpers'; +import { toFeatureAnchor } from '../../../utils/featureAnchor'; const CONTRIBUTE_URL = 'https://forms.gle/W3iJGgoaPDYLypZ38'; @@ -160,9 +169,15 @@ export default function GtfsFeatureTracker({ knownFields, }: GtfsFeatureTrackerProps): ReactElement { const [selectedType, setSelectedType] = useState(null); + const [highlightedFeatureAnchor, setHighlightedFeatureAnchor] = useState< + string | null + >(null); const [expandedCategories, setExpandedCategories] = useState< Record >({}); + const highlightTimeoutRef = useRef | null>( + null, + ); const knownFieldsSet = useMemo(() => new Set(knownFields), [knownFields]); @@ -196,6 +211,42 @@ export default function GtfsFeatureTracker({ return expandedCategories[category] ?? true; }; + useEffect(function highlightRowFromAnchor() { + const clearHighlightTimeout = (): void => { + if (highlightTimeoutRef.current != null) { + clearTimeout(highlightTimeoutRef.current); + highlightTimeoutRef.current = null; + } + }; + + const revealFromHash = (): void => { + const hash = window.location.hash; + if (hash === '') return; + + const anchor = decodeURIComponent(hash.replace(/^#/, '')); + if (anchor === '') return; + + const targetElement = document.getElementById(anchor); + if (targetElement == null) return; + + setHighlightedFeatureAnchor(anchor); + targetElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); + + clearHighlightTimeout(); + highlightTimeoutRef.current = setTimeout(() => { + setHighlightedFeatureAnchor((prev) => (prev === anchor ? null : prev)); + }, 2800); + }; + + revealFromHash(); + window.addEventListener('hashchange', revealFromHash); + + return () => { + clearHighlightTimeout(); + window.removeEventListener('hashchange', revealFromHash); + }; + }, []); + return ( ({ @@ -507,147 +558,175 @@ export default function GtfsFeatureTracker({ - {categoryFeatures.map((feature) => ( - - { + const featureAnchor = toFeatureAnchor(feature.name); + const isHighlighted = + highlightedFeatureAnchor === featureAnchor; + + return ( + ({ + borderBottom: '1px solid', + borderColor: 'divider', + height: 72, + ...(isHighlighted + ? { + animation: + 'feature-row-highlight 2.8s cubic-bezier(0.22, 1, 0.36, 1) 1', + '@keyframes feature-row-highlight': { + '0%': { + backgroundColor: `rgba(${theme.vars.palette.warning.mainChannel} / 0.36)`, + }, + '100%': { + backgroundColor: 'transparent', + }, + }, + } + : null), + '&:hover .feature-links': { + opacity: 1, + }, + })} > - ({ + position: 'sticky', + left: 0, + zIndex: 10, + bgcolor: isHighlighted + ? `rgba(${theme.vars.palette.warning.mainChannel} / 0.20)` + : 'background.default', + verticalAlign: 'middle', + minWidth: 210, + })} > - - {feature.name} - - {feature.documentationUrl != null ? ( - - ) : null} - {feature.category.toLowerCase() !== 'base' && ( - - )} - - - - {filteredConsumers.map((consumer) => { - const support = feature.support[consumer.id] ?? { - rawStatus: '', - details: '', - }; - const statusText = getStatusText(support.rawStatus); - return ( - + + {feature.name} + + {feature.documentationUrl != null ? ( + + ) : null} + {feature.category.toLowerCase() !== + 'base' && ( + + )} + + + + {filteredConsumers.map((consumer) => { + const support = feature.support[consumer.id] ?? { + rawStatus: '', + details: '', + }; + const statusText = getStatusText( + support.rawStatus, + ); + return ( + ({ + verticalAlign: 'middle', + backgroundColor: isHighlighted + ? `rgba(${theme.vars.palette.warning.mainChannel} / 0.14)` + : 'background.default', + })} > - {getStatusIcon(support.rawStatus)} - - {statusText} - + {getStatusIcon(support.rawStatus)} + + {statusText} + + + {support.details != null && + support.details !== '' ? ( + + ) : null} - {support.details != null && - support.details !== '' ? ( - - ) : null} - - - ); - })} - - ))} + + ); + })} + + ); + })} diff --git a/src/app/utils/featureAnchor.ts b/src/app/utils/featureAnchor.ts new file mode 100644 index 00000000..ea20b895 --- /dev/null +++ b/src/app/utils/featureAnchor.ts @@ -0,0 +1,11 @@ +export function toFeatureAnchor(featureName: string): string { + const normalized = featureName + .trim() + .toLowerCase() + .normalize('NFKD') + .replace(/[\u0300-\u036f]/g, '') + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, ''); + + return normalized === '' ? 'feature' : normalized; +} From ec335a3b37c318c73fbe490ca203a38ab6eca83f Mon Sep 17 00:00:00 2001 From: Alessandro Kreslin Date: Mon, 27 Apr 2026 13:41:43 -0400 Subject: [PATCH 12/15] feature tracker button position updated Co-authored-by: Copilot --- .../[locale]/feeds/components/FeedsScreen.tsx | 49 ++++++++++++------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/app/[locale]/feeds/components/FeedsScreen.tsx b/src/app/[locale]/feeds/components/FeedsScreen.tsx index cbbc43d6..60f96390 100644 --- a/src/app/[locale]/feeds/components/FeedsScreen.tsx +++ b/src/app/[locale]/feeds/components/FeedsScreen.tsx @@ -329,19 +329,6 @@ export default function FeedsScreen(): React.ReactElement { - {selectedFeatures.length > 0 && ( - - )} {selectedFeedTypes.gtfs && ( - - {getSearchResultNumbers()} - + + {getSearchResultNumbers()} + + {selectedFeatures.length > 0 && ( + + )} + + Date: Mon, 27 Apr 2026 14:15:17 -0400 Subject: [PATCH 13/15] update comment --- .../gtfs-feature-tracker/components/GtfsFeatureTracker.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx b/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx index 049dafa2..e3b56f5e 100644 --- a/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx +++ b/src/app/[locale]/gtfs-feature-tracker/components/GtfsFeatureTracker.tsx @@ -64,7 +64,7 @@ const CONSUMER_LOGOS: Record = { // ── FeatureDetail ───────────────────────────────────────────────────────────── // Extracted as a memo component (rerender-memo) so each cell only re-renders -// when its own text or the knownFields set changes. +// when its own text or the knownFields set changes const FeatureDetail = memo(function FeatureDetail({ text, From ec63120512830f2263a04f3c5430043319d2bf42 Mon Sep 17 00:00:00 2001 From: Alessandro Kreslin Date: Mon, 27 Apr 2026 14:24:42 -0400 Subject: [PATCH 14/15] style update --- src/app/[locale]/feeds/components/FeedsScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/[locale]/feeds/components/FeedsScreen.tsx b/src/app/[locale]/feeds/components/FeedsScreen.tsx index 60f96390..400a3c40 100644 --- a/src/app/[locale]/feeds/components/FeedsScreen.tsx +++ b/src/app/[locale]/feeds/components/FeedsScreen.tsx @@ -557,7 +557,7 @@ export default function FeedsScreen(): React.ReactElement { Date: Mon, 27 Apr 2026 14:33:44 -0400 Subject: [PATCH 15/15] extra protection logic feeds search --- .../[locale]/feeds/components/FeedsScreen.tsx | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/app/[locale]/feeds/components/FeedsScreen.tsx b/src/app/[locale]/feeds/components/FeedsScreen.tsx index 400a3c40..aa71c9e9 100644 --- a/src/app/[locale]/feeds/components/FeedsScreen.tsx +++ b/src/app/[locale]/feeds/components/FeedsScreen.tsx @@ -570,19 +570,20 @@ export default function FeedsScreen(): React.ReactElement { > {getSearchResultNumbers()} - {selectedFeatures.length > 0 && ( - - )} + {selectedFeatures.length > 0 && + areFeatureFiltersEnabled && ( + + )}