├── .codecov.yml ├── .dockerignore ├── .eslintignore ├── .eslintrc.js ├── .git-blame-ignore-revs ├── .github ├── pull_request_template.md └── workflows │ ├── dev-pipeline.yml │ ├── prod-pipeline.yml │ └── scripts │ ├── push_prod.sh │ └── slack_message.sh ├── .gitignore ├── .lvimrc ├── .nvmrc ├── .nycrc.json ├── .stylelintrc.json ├── .yarn ├── plugins │ └── @yarnpkg │ │ ├── plugin-interactive-tools.cjs │ │ └── plugin-version.cjs ├── releases │ └── yarn-3.4.1.cjs └── versions │ └── 41447b25.yml ├── .yarnrc.yml ├── COPYING ├── Dockerfile ├── LICENSE-AGPL.txt ├── LICENSE-EUPL.txt ├── README.md ├── app ├── action │ ├── CanceledLegsBarActions.js │ ├── CountryActions.js │ ├── FavouriteActions.js │ ├── FutureRoutesActions.js │ ├── MapLayerActions.js │ ├── MessageActions.js │ ├── PositionActions.js │ ├── SearchActions.js │ ├── SearchSettingsActions.js │ ├── ViaPointActions.js │ ├── destinationActions.js │ ├── originActions.js │ ├── realTimeClientAction.js │ ├── userActions.js │ └── userPreferencesActions.js ├── app.js ├── buildInfo.js ├── client.js ├── component │ ├── 404.js │ ├── AboutPage.js │ ├── AddressRow.js │ ├── AgencyInfo.js │ ├── AlertBanner.js │ ├── AlertList.js │ ├── AlertRow.js │ ├── AppBar.js │ ├── AppBarContainer.js │ ├── AppBarHsl.js │ ├── Availability.js │ ├── BackButton.js │ ├── BubbleDialog.js │ ├── CanceledLegsBar.js │ ├── CapacityModal.js │ ├── Card.js │ ├── CardHeader.js │ ├── Checkbox.js │ ├── CookieSettingsButton.js │ ├── CustomInputTime.js │ ├── DTModal.js │ ├── DatetimepickerContainer.js │ ├── DepartureListContainer.js │ ├── DepartureRow.js │ ├── DesktopView.js │ ├── DisruptionBanner.js │ ├── DisruptionBannerAlert.js │ ├── DisruptionInfo.js │ ├── DisruptionInfoButton.js │ ├── DisruptionInfoButtonContainer.js │ ├── DisruptionListContainer.js │ ├── ErrorBoundary.js │ ├── ErrorHandlerSSR.js │ ├── ExternalLink.js │ ├── Favourite.js │ ├── FavouriteStopContainer.js │ ├── FavouriteVehicleRentalStationContainer.js │ ├── FavouritesContainer.js │ ├── FromMapModal.js │ ├── Geolocator.js │ ├── Geomover.js │ ├── Icon.js │ ├── IconWithBigCaution.js │ ├── IconWithIcon.js │ ├── IndexPage.js │ ├── IndexPageMeta.js │ ├── LangSelect.js │ ├── LazilyLoad.js │ ├── Loading.js │ ├── LoadingPage.js │ ├── LoginButton.js │ ├── LogoSmall.js │ ├── MainMenu.js │ ├── MainMenuContainer.js │ ├── MainMenuLinks.js │ ├── MapLayersDialogContent.js │ ├── MapRoutingButton.js │ ├── MenuDrawer.js │ ├── MenuItem.js │ ├── Message.js │ ├── MessageBar.js │ ├── MessageBarMessage.js │ ├── MobileFooter.js │ ├── MobileView.js │ ├── NetworkError.js │ ├── ParkAndRideContent.js │ ├── ParkContainer.js │ ├── ParkOrStationHeader.js │ ├── PlatformNumber.js │ ├── RentalVehicle.js │ ├── RentalVehicleContent.js │ ├── RentalVehiclePageMapContainer.js │ ├── RouteNumber.js │ ├── RouteNumberContainer.js │ ├── ScrollableWrapper.js │ ├── SecondaryButton.js │ ├── Select.js │ ├── SelectFromMapHeader.js │ ├── SelectedStopPopupContent.js │ ├── ServiceAlertIcon.js │ ├── Slider.js │ ├── SplitBars.js │ ├── StopCode.js │ ├── SwipeableTabs.js │ ├── Title.js │ ├── Toggle.js │ ├── ToggleMapTracking.js │ ├── TopLevel.js │ ├── TruncatedMessage.js │ ├── UserMenu.js │ ├── VehicleIcon.js │ ├── VehicleParkMapContainer.js │ ├── VehicleRentalAvailability.js │ ├── VehicleRentalStation.js │ ├── VehicleRentalStationContent.js │ ├── VehicleRentalStationMapContainer.js │ ├── WithSearchContext.js │ ├── ZoneIcon.js │ ├── alert-banner.scss │ ├── app-bar-hsl.scss │ ├── bike-park-rental-station.scss │ ├── bubble-dialog.scss │ ├── checkbox.scss │ ├── city-bike.scss │ ├── date-select.scss │ ├── departure.scss │ ├── disruption.scss │ ├── embedded │ │ ├── EmbeddedSearch.js │ │ ├── EmbeddedSearchContainer.js │ │ ├── EmbeddedSearchGenerator.js │ │ ├── embedded-search-generator.scss │ │ ├── embedded-search.scss │ │ └── hooks │ │ │ └── useUTMCampaignParams.js │ ├── favourite-icon-table.scss │ ├── from-map-modal.scss │ ├── front-page.scss │ ├── itinerary │ │ ├── AirplaneLeg.js │ │ ├── AirportCheckInLeg.js │ │ ├── AirportCollectLuggageLeg.js │ │ ├── AlternativeItineraryBar.js │ │ ├── AlternativeLegsInfo.js │ │ ├── BicycleLeg.js │ │ ├── BikeParkLeg.js │ │ ├── CallAgencyLeg.js │ │ ├── CarLeg.js │ │ ├── CarParkLeg.js │ │ ├── ChangeDepartureTimeLink.js │ │ ├── CustomizeSearch.js │ │ ├── Duration.js │ │ ├── Emissions.js │ │ ├── EmissionsInfo.js │ │ ├── EndLeg.js │ │ ├── ErrorCard.js │ │ ├── FareDisclaimer.js │ │ ├── FeedbackPrompt.js │ │ ├── InterlineInfo.js │ │ ├── IntermediateLeg.js │ │ ├── ItinerariesNotFound.js │ │ ├── Itinerary.js │ │ ├── ItineraryCircleLine.js │ │ ├── ItineraryCircleLineLong.js │ │ ├── ItineraryCircleLineWithIcon.js │ │ ├── ItineraryDetails.js │ │ ├── ItineraryDistance.js │ │ ├── ItineraryList.js │ │ ├── ItineraryListContainer.js │ │ ├── ItineraryListHeader.js │ │ ├── ItineraryMapAction.js │ │ ├── ItineraryNotification.js │ │ ├── ItineraryPage.js │ │ ├── ItineraryPageContainer.js │ │ ├── ItineraryPageControls.js │ │ ├── ItineraryPageMeta.js │ │ ├── ItineraryPageTitle.js │ │ ├── ItineraryPageUtils.js │ │ ├── ItinerarySummary.js │ │ ├── ItineraryTabs.js │ │ ├── LegAgencyInfo.js │ │ ├── LegInfo.js │ │ ├── Legs.js │ │ ├── MobileTicketPurchaseInformation.js │ │ ├── NationalServiceLink.js │ │ ├── NearestQuery.js │ │ ├── NoItinerariesNote.js │ │ ├── OriginDestinationBar.js │ │ ├── PastLink.js │ │ ├── Profile.js │ │ ├── RightOffcanvasToggle.js │ │ ├── ScooterLinkContainer.js │ │ ├── SearchSettings.js │ │ ├── StartNavi.js │ │ ├── StopInfo.js │ │ ├── StreetModeSelectorButton.js │ │ ├── StreetModeSelectorShimmer.js │ │ ├── StreetModeSelectorWeather.js │ │ ├── StreetSummary.js │ │ ├── TaxiLeg.js │ │ ├── TaxiLinkContainer.js │ │ ├── TicketInformation.js │ │ ├── TimeSummary.js │ │ ├── TransitLeg.js │ │ ├── VehicleRentalDurationInfo.js │ │ ├── VehicleRentalLeg.js │ │ ├── ViaLeg.js │ │ ├── WaitLeg.js │ │ ├── WalkLeg.js │ │ ├── WeatherDetailsPopup.js │ │ ├── ZoneTicket.js │ │ ├── alt-travel-bar.scss │ │ ├── customize-search.scss │ │ ├── customizesearch │ │ │ ├── AccessibilityOptionSection.js │ │ │ ├── BikingOptionsSection.js │ │ │ ├── FareZoneSelector.js │ │ │ ├── MinTransferTimeSection.js │ │ │ ├── RentalNetworkSelector.js │ │ │ ├── RestoreDefaultSettingSection.js │ │ │ ├── ScooterNetworkSelector.js │ │ │ ├── SearchSettingsDropdown.js │ │ │ ├── StreetModeSelectorPanel.js │ │ │ ├── TaxiOptionsSection.js │ │ │ ├── TransferOptionsSection.js │ │ │ ├── TransportModesSection.js │ │ │ └── WalkingOptionsSection.js │ │ ├── errorCardProperties.js │ │ ├── findErrorMessageIds.js │ │ ├── itinerary-list-header.scss │ │ ├── itinerary-page.scss │ │ ├── itinerary-profile.scss │ │ ├── itinerary-summary.scss │ │ ├── itinerary.scss │ │ ├── mobile-ticket-purchase-information.scss │ │ ├── navigator │ │ │ ├── BoardingInfo.js │ │ │ ├── NaviBottom.js │ │ │ ├── NaviCard.js │ │ │ ├── NaviCardContainer.js │ │ │ ├── NaviCardExtension.js │ │ │ ├── NaviContainer.js │ │ │ ├── NaviInstructions.js │ │ │ ├── NaviMessage.js │ │ │ ├── NaviStack.js │ │ │ ├── NaviStarter.js │ │ │ ├── NaviUtils.js │ │ │ ├── NavigatorModal.js │ │ │ ├── hooks │ │ │ │ ├── useLegState.js │ │ │ │ ├── useLogo.js │ │ │ │ ├── usePrevious.js │ │ │ │ ├── useRealtimeLegs.js │ │ │ │ └── utils │ │ │ │ │ └── realtimeLegUtils.js │ │ │ ├── navigator.scss │ │ │ ├── navigatorgeolocation │ │ │ │ ├── NaviGeolocationInfo.js │ │ │ │ ├── NaviGeolocationInfoModal.js │ │ │ │ └── navigator-geolocation.scss │ │ │ ├── navigatorintro │ │ │ │ ├── NavigatorIntro.js │ │ │ │ ├── NavigatorIntroFeature.js │ │ │ │ ├── NavigatorIntroModal.js │ │ │ │ └── navigator-intro.scss │ │ │ └── navigatoroutro │ │ │ │ ├── NavigatorOutro.js │ │ │ │ ├── NavigatorOutroModal.js │ │ │ │ └── navigator-outro.scss │ │ ├── origin-destination-bar.scss │ │ ├── queries │ │ │ ├── ItineraryDetailsFragment.js │ │ │ ├── ItineraryFragment.js │ │ │ ├── ItineraryListContainerPlanEdges.js │ │ │ ├── ItineraryListPlanEdges.js │ │ │ ├── LegAgencyInfoFragment.js │ │ │ ├── LegQuery.js │ │ │ └── PlanConnection.js │ │ ├── search-settings-dropdown.scss │ │ ├── settings-panel.scss │ │ ├── street-mode-selector-button.scss │ │ ├── street-mode-selector-shimmer.scss │ │ ├── street-mode-selector.scss │ │ └── weather-details.scss │ ├── map │ │ ├── ConfirmLocationFromMapButton.js │ │ ├── EntranceMarker.js │ │ ├── GenericMarker.js │ │ ├── GeoJSON.js │ │ ├── IconMarker.js │ │ ├── IndexPageMap.js │ │ ├── ItineraryLine.js │ │ ├── ItineraryPageMap.js │ │ ├── Line.js │ │ ├── LocationMarker.js │ │ ├── LocationMarkerWithPermanentTooltip.js │ │ ├── Map.js │ │ ├── MapBottomsheetContext.js │ │ ├── MapContainer.js │ │ ├── MapWithTracking.js │ │ ├── MarkerPopupBottom.js │ │ ├── NearYouMap.js │ │ ├── PointFeatureMarker.js │ │ ├── PopupHeader.js │ │ ├── PositionMarker.js │ │ ├── RoutePageMap.js │ │ ├── SelectFromMap.js │ │ ├── SpeechBubble.js │ │ ├── StopPageMap.js │ │ ├── VehicleMarkerContainer.js │ │ ├── WalkQuery.js │ │ ├── map.scss │ │ ├── non-tile-layer │ │ │ ├── LegMarker.js │ │ │ ├── StopMarker.js │ │ │ ├── TransitLegMarkers.js │ │ │ ├── VehicleMarker.js │ │ │ └── VehicleMarkerContainer.js │ │ ├── popups │ │ │ ├── LocationPopup.js │ │ │ ├── SelectedStopPopup.js │ │ │ ├── ViaPointPopup.js │ │ │ └── marker-popup.scss │ │ ├── route │ │ │ ├── PopupHeader.js │ │ │ ├── RouteLine.js │ │ │ └── TripMarkerPopup.js │ │ ├── tile-layer │ │ │ ├── MarkerSelectPopup.js │ │ │ ├── ParkAndRide.js │ │ │ ├── ParkAndRideForBikes.js │ │ │ ├── ParkAndRideForCars.js │ │ │ ├── RentalVehicles.js │ │ │ ├── SelectParkAndRideRow.js │ │ │ ├── SelectRentalVehicleClusterRow.js │ │ │ ├── SelectStopRow.js │ │ │ ├── SelectTerminalRow.js │ │ │ ├── SelectVehicleContainer.js │ │ │ ├── SelectVehicleRentalRow.js │ │ │ ├── SelectVehicleRow.js │ │ │ ├── Stops.js │ │ │ ├── TileContainer.js │ │ │ ├── TileLayerContainer.js │ │ │ ├── VectorTileLayerContainer.js │ │ │ └── VehicleRentalStations.js │ │ └── withGeojsonObjects.js │ ├── navigation.scss │ ├── nearyou │ │ ├── NearYouPage.js │ │ ├── NearYouPageMeta.js │ │ ├── StopNearYou.js │ │ ├── StopNearYouContainer.js │ │ ├── StopNearYouDepartureRowContainer.js │ │ ├── StopNearYouHeader.js │ │ ├── StopsNearYouContainer.js │ │ ├── StopsNearYouFavorites.js │ │ ├── StopsNearYouFavoritesMapContainer.js │ │ ├── StopsNearYouFavouritesContainer.js │ │ ├── StopsNearYouMapContainer.js │ │ ├── StopsNearYouSearch.js │ │ ├── VehicleRentalStationNearYou.js │ │ └── stops-near-you.scss │ ├── no-favourites-panel.scss │ ├── nolocation-panel.scss │ ├── rental-vehicle-content.scss │ ├── routepage │ │ ├── CallAgencyWarning.js │ │ ├── DepartureTime.js │ │ ├── FavouriteRouteContainer.js │ │ ├── FuzzyTripLink.js │ │ ├── PatternRedirector.js │ │ ├── PatternStopsContainer.js │ │ ├── RouteAgencyInfo.js │ │ ├── RouteAlertsContainer.js │ │ ├── RouteControlPanel.js │ │ ├── RouteNotification.js │ │ ├── RoutePage.js │ │ ├── RoutePageMeta.js │ │ ├── RoutePatternSelect.js │ │ ├── RouteStop.js │ │ ├── RouteStopListContainer.js │ │ ├── RouteTitle.js │ │ ├── ScheduleContainer.js │ │ ├── ScheduleDebugData.js │ │ ├── ScheduleDropdown.js │ │ ├── ScheduleHeader.js │ │ ├── ScheduleTripRow.js │ │ ├── TripLink.js │ │ ├── TripLinkWithScroll.js │ │ ├── TripRouteStop.js │ │ ├── TripStopListContainer.js │ │ ├── TripStopsContainer.js │ │ ├── route-schedule-dropdown.scss │ │ └── route.scss │ ├── select-maplayers-dialog.scss │ ├── stop │ │ ├── DateSelect.js │ │ ├── FilterTimeTableModal.js │ │ ├── StopAlerts.js │ │ ├── StopAlertsContainer.js │ │ ├── StopCardHeader.js │ │ ├── StopCardHeaderContainer.js │ │ ├── StopPageContentContainer.js │ │ ├── StopPageHeader.js │ │ ├── StopPageHeaderContainer.js │ │ ├── StopPageMapContainer.js │ │ ├── StopPageMeta.js │ │ ├── StopPageTabContainer.js │ │ ├── StopPageTabs.js │ │ ├── StopTimetablePage.js │ │ ├── StopTitle.js │ │ ├── TerminalAlertsContainer.js │ │ ├── TerminalPageContentContainer.js │ │ ├── TerminalPageHeaderContainer.js │ │ ├── TerminalPageMapContainer.js │ │ ├── TerminalPageMeta.js │ │ ├── TerminalPageTabContainer.js │ │ ├── TerminalTimetablePage.js │ │ ├── TerminalTitle.js │ │ ├── TimeTableOptionsPanel.js │ │ ├── Timetable.js │ │ ├── TimetableRow.js │ │ ├── queries │ │ │ └── TimetableFragment.js │ │ ├── stop-cards.scss │ │ └── stop.scss │ ├── timetable.scss │ ├── toggle.scss │ ├── util.scss │ ├── visual │ │ ├── OverlayWithSpinner.js │ │ ├── index.scss │ │ └── overlay-with-spinner.scss │ └── zone-icon.scss ├── config.js ├── configurations │ ├── config.default.js │ ├── config.hameenlinna.js │ ├── config.hsl.js │ ├── config.joensuu.js │ ├── config.jyvaskyla.js │ ├── config.kela.js │ ├── config.kotka.js │ ├── config.kouvola.js │ ├── config.kuopio.js │ ├── config.lahti.js │ ├── config.lappeenranta.js │ ├── config.matka.js │ ├── config.mikkeli.js │ ├── config.oulu.js │ ├── config.pori.js │ ├── config.raasepori.js │ ├── config.rovaniemi.js │ ├── config.tampere.js │ ├── config.turku.js │ ├── config.vaasa.js │ ├── config.varely.js │ ├── config.waltti.js │ ├── config.walttiOpas.js │ ├── images │ │ ├── default │ │ │ ├── default-favicon.png │ │ │ ├── digitransit-logo.png │ │ │ ├── dotted-line-bg.png │ │ │ ├── dotted-line-bg2.png │ │ │ └── dotted-line.svg │ │ ├── hameenlinna │ │ │ ├── hameenlinna-favicon.png │ │ │ ├── logo.png │ │ │ └── secondary-logo.png │ │ ├── hsl │ │ │ ├── geolocation.svg │ │ │ ├── hsl-favicon.png │ │ │ ├── navigator-logo.svg │ │ │ ├── reittiopas-logo.svg │ │ │ ├── thumbs-up.svg │ │ │ └── traffic-light.svg │ │ ├── joensuu │ │ │ ├── joensuu-favicon.png │ │ │ └── jojo-logo.png │ │ ├── jyvaskyla │ │ │ └── jyvaskyla-favicon.png │ │ ├── kotka │ │ │ └── kotka.png │ │ ├── kouvola │ │ │ ├── kouvola-favicon.png │ │ │ ├── logo.png │ │ │ └── secondary-logo.png │ │ ├── kuopio │ │ │ ├── kuopio-favicon.png │ │ │ ├── logo.png │ │ │ └── secondary-logo.png │ │ ├── lahti │ │ │ ├── lahti-favicon.png │ │ │ ├── lahti-logo.png │ │ │ └── secondary-lahti-logo.png │ │ ├── lappeenranta │ │ │ ├── lappeenranta-favicon.jpg │ │ │ ├── logo.png │ │ │ └── secondary-logo.png │ │ ├── matka │ │ │ ├── matka-favicon.svg │ │ │ └── matka-logo.svg │ │ ├── oulu │ │ │ ├── oulu-favicon.png │ │ │ ├── oulu-logo.png │ │ │ └── secondary-oulu-logo.png │ │ ├── pori │ │ │ ├── pori-favicon.png │ │ │ └── pori_logo.svg │ │ ├── raasepori │ │ │ ├── raasepori-favicon.png │ │ │ ├── raasepori_logo_musta.png │ │ │ └── raasepori_logo_valkoinen.png │ │ ├── rovaniemi │ │ │ ├── rovaniemi-favicon.png │ │ │ └── rovaniemi-logo.svg │ │ ├── tampere │ │ │ ├── tampere-favicon.png │ │ │ └── tampere-logo.png │ │ ├── turku │ │ │ ├── foli-logo.png │ │ │ └── turku-favicon.png │ │ ├── vaasa │ │ │ ├── secondary-logo.png │ │ │ └── vaasa-favicon.png │ │ ├── varely │ │ │ ├── seutuplus-logo-white.svg │ │ │ ├── seutuplus-logo.svg │ │ │ └── varely-favicon.png │ │ └── walttiOpas │ │ │ ├── waltti-logo-secondary.png │ │ │ ├── waltti-logo.png │ │ │ └── walttiOpas-favicon.png │ ├── realtimeUtils.js │ └── timetableConfigUtils.js ├── constants.js ├── hooks │ └── useWindowSize.js ├── meta.js ├── routeRoutes.js ├── routes.js ├── server.js ├── ssrmeta.json ├── stopRoutes.js ├── store │ ├── CanceledLegsBarStore.js │ ├── CountryStore.js │ ├── DestinationStore.js │ ├── FavouriteStore.js │ ├── FutureRouteStore.js │ ├── GeoJsonStore.js │ ├── MapLayerStore.js │ ├── MessageStore.js │ ├── OldSearchesStore.js │ ├── OriginStore.js │ ├── PositionStore.js │ ├── PreferencesStore.js │ ├── RealTimeInformationStore.js │ ├── RoutingSettingsStore.js │ ├── TimeStore.js │ ├── UserStore.js │ ├── ViaPointStore.js │ ├── localStorage.js │ └── sessionStorage.js ├── translations.js └── util │ ├── DTSearchContextInitializer.js │ ├── ParkAndRideUtils.js │ ├── StoreListeningIntlProvider.js │ ├── alertUtils.js │ ├── analyticsUtils.js │ ├── apiUtils.js │ ├── browser.js │ ├── colorUtils.js │ ├── configMerger.js │ ├── configure-moment.js │ ├── configureCountry.js │ ├── dateParamUtils.js │ ├── emissions.js │ ├── envUtils.js │ ├── events.js │ ├── fareUtils.js │ ├── feedScopedIdUtils.js │ ├── feedbackly.js │ ├── fetchUtils.js │ ├── filterUtils.js │ ├── font-sw.js │ ├── geo-utils.js │ ├── geolocationMessages.js │ ├── get-selector.js │ ├── getIterator.js │ ├── glfun.js │ ├── gtfs.js │ ├── gtfsRtParser.js │ ├── gtfsrt.js │ ├── hashUtil.js │ ├── jankmeter.js │ ├── legUtils.js │ ├── manifestUtils.js │ ├── mapIconUtils.js │ ├── mapLayerUtils.js │ ├── messageUtils.js │ ├── metaUtils.js │ ├── modeUtils.js │ ├── mqttClient.js │ ├── occupancyUtil.js │ ├── oldParamParser.js │ ├── otpStrings.js │ ├── path.js │ ├── patternUtils.js │ ├── planParamUtil.js │ ├── publicPath.js │ ├── queryUtils.js │ ├── relayUtils.js │ ├── route-compare.js │ ├── routePatternSelectUtil.js │ ├── routerUtils.js │ ├── safeJsonParser.js │ ├── scheduleParamUtils.js │ ├── scroll.js │ ├── searchContext.js │ ├── searchRoutes.js │ ├── shapes.js │ ├── slicedToArray.js │ ├── sortUtils.js │ ├── storeUtils.js │ ├── supportsInputType.js │ ├── timeUtils.js │ ├── urlUtils.js │ ├── vehicleRentalUtils.js │ ├── vehicleStateUtils.js │ ├── withBreakpoint.js │ ├── xhrPromise.js │ └── zoneIconUtils.js ├── babel.config.js ├── build ├── add-theme.js ├── check_translations.js ├── contextHelper.js ├── generate-schema.js ├── schema.graphql └── template.waltti.js ├── config ├── babel.config.js └── rollup.config.js ├── digitransit-component ├── CONTRIBUTING.md ├── packages │ ├── digitransit-component-abtesting │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-autosuggest-panel │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── helpers │ │ │ │ ├── Select.js │ │ │ │ ├── select.scss │ │ │ │ ├── styles.scss │ │ │ │ └── translations.js │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-autosuggest │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── helpers │ │ │ │ ├── MobileNoScroll.scss │ │ │ │ ├── MobileSearch.js │ │ │ │ ├── MobileSearch.scss │ │ │ │ ├── styles.scss │ │ │ │ ├── translations.js │ │ │ │ └── withScrollLock.js │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-control-panel │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── helpers │ │ │ │ ├── styles.js │ │ │ │ ├── styles.scss │ │ │ │ └── translations.js │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-datetimepicker │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── helpers │ │ │ │ ├── Datetimepicker.js │ │ │ │ ├── DesktopDatetimepicker.js │ │ │ │ ├── MobileDatepicker.js │ │ │ │ ├── MobilePickerModal.js │ │ │ │ ├── MobileTimepicker.js │ │ │ │ ├── dateTimeInputIsSupported.js │ │ │ │ ├── mobileDetection.js │ │ │ │ ├── styles.scss │ │ │ │ ├── translations.js │ │ │ │ └── utils.js │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-dialog-modal │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── helpers │ │ │ │ ├── styles.scss │ │ │ │ └── translations.js │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-favourite-bar │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── helpers │ │ │ │ ├── styles.scss │ │ │ │ └── translations.js │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-favourite-editing-modal │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── helpers │ │ │ │ ├── ModalContent.js │ │ │ │ ├── modal-content.scss │ │ │ │ ├── styles.scss │ │ │ │ └── translations.js │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-favourite-modal │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── helpers │ │ │ │ ├── DesktopModal.js │ │ │ │ ├── MobileModal.js │ │ │ │ ├── desktop.scss │ │ │ │ ├── mobile.scss │ │ │ │ ├── styles.scss │ │ │ │ └── translations.js │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-icon │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── assets │ │ │ │ ├── airplane.svg │ │ │ │ ├── arrow.svg │ │ │ │ ├── attention.svg │ │ │ │ ├── bike-park.svg │ │ │ │ ├── bus-express.svg │ │ │ │ ├── bus-local.svg │ │ │ │ ├── bus-waltti.svg │ │ │ │ ├── bus.svg │ │ │ │ ├── bus_stop.svg │ │ │ │ ├── calendar.svg │ │ │ │ ├── car-park.svg │ │ │ │ ├── caution_white_exclamation.svg │ │ │ │ ├── check.svg │ │ │ │ ├── city.svg │ │ │ │ ├── citybike-stop-default-secondary.svg │ │ │ │ ├── citybike-stop-default.svg │ │ │ │ ├── citybike-stop-digitransit-secondary.svg │ │ │ │ ├── citybike-stop-digitransit.svg │ │ │ │ ├── citybike-waltti.svg │ │ │ │ ├── citybike.svg │ │ │ │ ├── close.svg │ │ │ │ ├── dropdown.svg │ │ │ │ ├── edit.svg │ │ │ │ ├── ellipsis.svg │ │ │ │ ├── ferry-waltti.svg │ │ │ │ ├── ferry.svg │ │ │ │ ├── funicular.svg │ │ │ │ ├── home.svg │ │ │ │ ├── icon-route.svg │ │ │ │ ├── locate.svg │ │ │ │ ├── map.svg │ │ │ │ ├── mapmarker-via.svg │ │ │ │ ├── mapmarker.svg │ │ │ │ ├── mode_airplane.svg │ │ │ │ ├── mode_bus.svg │ │ │ │ ├── mode_citybike.svg │ │ │ │ ├── mode_digi_citybike.svg │ │ │ │ ├── mode_digi_funicular.svg │ │ │ │ ├── mode_digi_tram.svg │ │ │ │ ├── mode_ferry.svg │ │ │ │ ├── mode_rail.svg │ │ │ │ ├── mode_tram.svg │ │ │ │ ├── opposite.svg │ │ │ │ ├── place.svg │ │ │ │ ├── plus.svg │ │ │ │ ├── position.svg │ │ │ │ ├── rail-waltti.svg │ │ │ │ ├── rail.svg │ │ │ │ ├── school.svg │ │ │ │ ├── search-airplane-digitransit.svg │ │ │ │ ├── search-bus-station-digitransit.svg │ │ │ │ ├── search-bus-stop-default.svg │ │ │ │ ├── search-bus-stop-digitransit.svg │ │ │ │ ├── search-bus-stop-express-default.svg │ │ │ │ ├── search-bustram-stop-digitransit.svg │ │ │ │ ├── search-ferry-default.svg │ │ │ │ ├── search-ferry-digitransit.svg │ │ │ │ ├── search-ferry-stop-default.svg │ │ │ │ ├── search-ferry-stop-digitransit.svg │ │ │ │ ├── search-rail-station-digitransit.svg │ │ │ │ ├── search-rail-stop-default.svg │ │ │ │ ├── search-rail-stop-digitransit.svg │ │ │ │ ├── search-speedtram-stop-default.svg │ │ │ │ ├── search-streetname.svg │ │ │ │ ├── search-tram-stop-default.svg │ │ │ │ ├── search-tram-stop-digitransit.svg │ │ │ │ ├── search.svg │ │ │ │ ├── select-from-map.svg │ │ │ │ ├── shopping.svg │ │ │ │ ├── speedtram.svg │ │ │ │ ├── sport.svg │ │ │ │ ├── star.svg │ │ │ │ ├── station.svg │ │ │ │ ├── subway.svg │ │ │ │ ├── time.svg │ │ │ │ ├── tram-waltti.svg │ │ │ │ ├── tram.svg │ │ │ │ ├── trash.svg │ │ │ │ ├── viapoint.svg │ │ │ │ └── work.svg │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-suggestion-item │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── helpers │ │ │ │ └── styles.scss │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-traffic-now-link │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src │ │ │ ├── helpers │ │ │ │ ├── styles.scss │ │ │ │ └── translations.js │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-component-with-breakpoint │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ └── index.js │ │ └── test.js │ └── digitransit-component │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── index.mjs │ │ ├── package.json │ │ └── test.js └── scripts │ ├── create-new-module │ ├── generate-readmes │ └── installation.md ├── digitransit-search-util ├── CONTRIBUTING.md ├── packages │ ├── digitransit-search-util-distance │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-search-util-execute-search-immidiate │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-search-util-filter-matching-to-input │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-search-util-get-geocoding-results │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-search-util-get-json │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-search-util-get-label │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-search-util-helpers │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-search-util-is-duplicate │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-search-util-query-utils │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── package.json │ │ ├── schema │ │ │ └── schema.graphql │ │ ├── src │ │ │ └── index.js │ │ └── test.js │ ├── digitransit-search-util-route-name-compare │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-search-util-serialize │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-search-util-suggestion-to-location │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-search-util-tru-eq │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ └── digitransit-search-util-uniq-by-label │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js └── scripts │ ├── create-new-module │ ├── generate-readmes │ └── installation.md ├── digitransit-store ├── CONTRIBUTING.md ├── packages │ ├── digitransit-store-common-functions │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── mock-localstorage.js │ │ ├── package.json │ │ ├── src │ │ │ └── index.js │ │ └── test.js │ └── digitransit-store-future-route │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── mock-localstorage.js │ │ ├── package.json │ │ ├── src │ │ └── index.js │ │ └── test.js └── scripts │ ├── create-new-module │ ├── generate-readmes │ └── installation.md ├── digitransit-util ├── CONTRIBUTING.md ├── packages │ ├── digitransit-util-day-range-allowed-diff │ │ ├── CHANGELOG.md │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-util-day-range-pattern │ │ ├── CHANGELOG.md │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-util-enrich-patterns │ │ ├── CHANGELOG.md │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ ├── digitransit-util-route-pattern-option-text │ │ ├── CHANGELOG.md │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── README.md │ │ ├── helpers │ │ │ └── translations.js │ │ ├── index.js │ │ ├── package.json │ │ └── test.js │ └── digitransit-util │ │ ├── CHANGELOG.md │ │ ├── LICENSE-AGPL.txt │ │ ├── LICENSE-EUPL.txt │ │ ├── index.mjs │ │ ├── package.json │ │ └── test.js └── scripts │ ├── create-new-module │ ├── generate-readmes │ └── installation.md ├── docs ├── Architecture.md ├── Docker.md ├── GeoJson.md ├── GraphQL.md ├── Installation.md ├── JSBenchmark.md ├── Location.md ├── Navigation.md ├── Position.md ├── Terms.md ├── Tests.md ├── Themes.md ├── ZIndex.md └── images │ ├── architecture.png │ ├── hierarchy.png │ ├── location.png │ ├── position.png │ └── up.png ├── lerna.json ├── package.json ├── postcss.config.js ├── sass ├── _main.scss ├── base │ ├── _base.scss │ ├── _button.scss │ ├── _elements.scss │ ├── _form.scss │ ├── _helper-classes-after-foundations.scss │ ├── _helper-classes.scss │ ├── _helper-mixins.scss │ ├── _radius.scss │ ├── _spacing.scss │ ├── _waltti.scss │ └── _zindex.scss └── themes │ ├── default │ ├── _theme.scss │ ├── default-spinner.png │ └── main.scss │ ├── hameenlinna │ ├── _theme.scss │ └── main.scss │ ├── hsl │ ├── _theme.scss │ ├── hsl-spinner.png │ └── main.scss │ ├── joensuu │ ├── _theme.scss │ └── main.scss │ ├── jyvaskyla │ ├── _theme.scss │ └── main.scss │ ├── kela │ ├── _theme.scss │ └── main.scss │ ├── kotka │ ├── _theme.scss │ └── main.scss │ ├── kouvola │ ├── _theme.scss │ └── main.scss │ ├── kuopio │ ├── _theme.scss │ └── main.scss │ ├── lahti │ ├── _theme.scss │ └── main.scss │ ├── lappeenranta │ ├── _theme.scss │ └── main.scss │ ├── matka │ ├── _theme.scss │ └── main.scss │ ├── mikkeli │ ├── _theme.scss │ └── main.scss │ ├── oulu │ ├── _theme.scss │ └── main.scss │ ├── pori │ ├── _theme.scss │ └── main.scss │ ├── raasepori │ ├── _theme.scss │ └── main.scss │ ├── rovaniemi │ ├── _theme.scss │ └── main.scss │ ├── tampere │ ├── _theme.scss │ └── main.scss │ ├── turku │ ├── _theme.scss │ ├── foli-spinner.png │ └── main.scss │ ├── vaasa │ ├── _theme.scss │ └── main.scss │ ├── varely │ ├── _theme.scss │ └── main.scss │ └── walttiOpas │ ├── _theme.scss │ └── main.scss ├── scripts ├── README.md └── ui.sh ├── server ├── passport-openid-connect │ ├── Strategy.js │ ├── User.js │ └── openidConnect.js ├── proxyTester.js ├── reittiopasParameterMiddleware.js ├── server.js └── swInjection.js ├── static ├── assets │ ├── geojson │ │ ├── hml_zone_lines_20230214.geojson │ │ ├── hsl_zone_lines_20190508.geojson │ │ ├── jkl_zone_lines_20240531.geojson │ │ ├── joensuu_zone_lines_20250402.geojson │ │ ├── kotka_zone_lines_20250114.geojson │ │ ├── kuopio_zone_lines_20240508.geojson │ │ ├── lahti_zone_lines_20230105.geojson │ │ ├── lpr_zone_lines_20250515.geojson │ │ ├── oulu_zone_lines_20241011.geojson │ │ ├── tre_zone_lines_20250606.geojson │ │ └── vaasa_zone_lines_20231220.geojson │ ├── svg-sprite.default.svg │ ├── svg-sprite.hsl.svg │ └── temporary │ │ └── tampere-servicepoints-20250305.geojson ├── crossdomain.xml ├── favicon.ico ├── hsl_zone_areas.json ├── hsl_zone_lines.json ├── img │ ├── default-social-share.png │ ├── hsl-social-share.png │ ├── nearby-stop_animation.gif │ └── nearby-stop_desktop-animation.gif └── robots.txt ├── test ├── accessibility.sh ├── accessibility │ └── run-test.js ├── e2e │ ├── FrontPage.test.js │ ├── RoutePage.test.js │ ├── StopPage.test.js │ ├── SummaryPage.test.js │ ├── __image_snapshots__ │ │ ├── chromium │ │ │ ├── hsl │ │ │ │ ├── front-page-desktop-snap.png │ │ │ │ ├── front-page-mobile-snap.png │ │ │ │ ├── itinerary-details-desktop-snap.png │ │ │ │ ├── itinerary-details-mobile-snap.png │ │ │ │ ├── itinerary-suggestions-desktop-snap.png │ │ │ │ ├── itinerary-suggestions-mobile-snap.png │ │ │ │ ├── route-page-stop-list-desktop-snap.png │ │ │ │ ├── route-page-stop-list-mobile-snap.png │ │ │ │ ├── stop-page-departure-list-desktop-snap.png │ │ │ │ └── stop-page-departure-list-mobile-snap.png │ │ │ ├── matka │ │ │ │ ├── front-page-desktop-snap.png │ │ │ │ ├── front-page-mobile-snap.png │ │ │ │ ├── itinerary-details-desktop-snap.png │ │ │ │ ├── itinerary-details-mobile-snap.png │ │ │ │ ├── itinerary-suggestions-desktop-snap.png │ │ │ │ ├── itinerary-suggestions-mobile-snap.png │ │ │ │ ├── route-page-stop-list-desktop-snap.png │ │ │ │ ├── route-page-stop-list-mobile-snap.png │ │ │ │ ├── stop-page-departure-list-desktop-snap.png │ │ │ │ └── stop-page-departure-list-mobile-snap.png │ │ │ └── tampere │ │ │ │ ├── front-page-desktop-snap.png │ │ │ │ ├── front-page-mobile-snap.png │ │ │ │ ├── itinerary-details-desktop-snap.png │ │ │ │ ├── itinerary-details-mobile-snap.png │ │ │ │ ├── itinerary-suggestions-desktop-snap.png │ │ │ │ ├── itinerary-suggestions-mobile-snap.png │ │ │ │ ├── route-page-stop-list-desktop-snap.png │ │ │ │ ├── route-page-stop-list-mobile-snap.png │ │ │ │ ├── stop-page-departure-list-desktop-snap.png │ │ │ │ └── stop-page-departure-list-mobile-snap.png │ │ ├── firefox │ │ │ ├── hsl │ │ │ │ ├── front-page-desktop-snap.png │ │ │ │ ├── itinerary-details-desktop-snap.png │ │ │ │ ├── itinerary-suggestions-desktop-snap.png │ │ │ │ ├── route-page-stop-list-desktop-snap.png │ │ │ │ └── stop-page-departure-list-desktop-snap.png │ │ │ ├── matka │ │ │ │ ├── front-page-desktop-snap.png │ │ │ │ ├── itinerary-details-desktop-snap.png │ │ │ │ ├── itinerary-suggestions-desktop-snap.png │ │ │ │ ├── route-page-stop-list-desktop-snap.png │ │ │ │ └── stop-page-departure-list-desktop-snap.png │ │ │ └── tampere │ │ │ │ ├── front-page-desktop-snap.png │ │ │ │ ├── itinerary-details-desktop-snap.png │ │ │ │ ├── itinerary-suggestions-desktop-snap.png │ │ │ │ ├── route-page-stop-list-desktop-snap.png │ │ │ │ └── stop-page-departure-list-desktop-snap.png │ │ └── webkit │ │ │ ├── hsl │ │ │ ├── front-page-desktop-snap.png │ │ │ ├── front-page-mobile-snap.png │ │ │ ├── itinerary-details-desktop-snap.png │ │ │ ├── itinerary-details-mobile-snap.png │ │ │ ├── itinerary-suggestions-desktop-snap.png │ │ │ ├── itinerary-suggestions-mobile-snap.png │ │ │ ├── route-page-stop-list-desktop-snap.png │ │ │ ├── route-page-stop-list-mobile-snap.png │ │ │ ├── stop-page-departure-list-desktop-snap.png │ │ │ └── stop-page-departure-list-mobile-snap.png │ │ │ ├── matka │ │ │ ├── front-page-desktop-snap.png │ │ │ ├── front-page-mobile-snap.png │ │ │ ├── itinerary-details-desktop-snap.png │ │ │ ├── itinerary-details-mobile-snap.png │ │ │ ├── itinerary-suggestions-desktop-snap.png │ │ │ ├── itinerary-suggestions-mobile-snap.png │ │ │ ├── route-page-stop-list-desktop-snap.png │ │ │ ├── route-page-stop-list-mobile-snap.png │ │ │ ├── stop-page-departure-list-desktop-snap.png │ │ │ └── stop-page-departure-list-mobile-snap.png │ │ │ └── tampere │ │ │ ├── front-page-desktop-snap.png │ │ │ ├── front-page-mobile-snap.png │ │ │ ├── itinerary-details-desktop-snap.png │ │ │ ├── itinerary-details-mobile-snap.png │ │ │ ├── itinerary-suggestions-desktop-snap.png │ │ │ ├── itinerary-suggestions-mobile-snap.png │ │ │ ├── route-page-stop-list-desktop-snap.png │ │ │ ├── route-page-stop-list-mobile-snap.png │ │ │ ├── stop-page-departure-list-desktop-snap.png │ │ │ └── stop-page-departure-list-mobile-snap.png │ ├── helpers │ │ ├── image-reporter.js │ │ ├── image-snapshot-config.js │ │ └── mock-request-helper.js │ ├── jest-playwright-desktop.config.js │ ├── jest-playwright-mobile.config.js │ ├── jest.config.js │ ├── jest.image.js │ └── mock-data │ │ ├── RoutePageStopListQueryResponse.json │ │ ├── RoutePageStopListTampereResponse.json │ │ ├── StopPageContenQueryResponse.json │ │ ├── SummaryPageQueryResponse.json │ │ ├── WalkBikeQueryResponse.json │ │ └── weatherMock.xml ├── install.sh └── unit │ ├── .eslintrc.js │ ├── AppBar.test.js │ ├── AppBarHsl.test.js │ ├── CanceledLegsBar.test.js │ ├── Checkbox.test.js │ ├── ItineraryDetails.test.js │ ├── ItinerarySummary.test.js │ ├── LogoSmall.test.js │ ├── OldSearchesStore.test.js │ ├── PlatformNumber.test.js │ ├── Select.test.js │ ├── TicketInformation.test.js │ ├── WalkLeg.test.js │ ├── browser.test.js │ ├── component │ ├── AboutPage.test.js │ ├── AlertList.test.js │ ├── AlertsRow.test.js │ ├── Availability.test.js │ ├── BicycleLeg.test.js │ ├── BubbleDialog.test.js │ ├── CardHeader.test.js │ ├── DateSelect.test.js │ ├── DepartureTime.test.js │ ├── DisruptionBanner.test.js │ ├── DisruptionListContainer.test.js │ ├── FuzzyTripLink.test.js │ ├── Icon.test.js │ ├── IconWithBigCaution.test.js │ ├── IconWithIcon.test.js │ ├── IntermediateLeg.test.js │ ├── LangSelect.test.js │ ├── Legs.test.js │ ├── MapLayersDialogContent.test.js │ ├── MessageBar.test.js │ ├── MessageBarMessage.test.js │ ├── NoItinerariesNote.test.js │ ├── Profile.test.js │ ├── RouteAlertsContainer.test.js │ ├── RouteControlPanel.test.js │ ├── RouteNumber.test.js │ ├── RoutePatternSelect.test.js │ ├── RouteStop.test.js │ ├── RouteStopListContainer.test.js │ ├── ScheduleContainer.test.js │ ├── ScheduleTripRow.test.js │ ├── SearchSettings.test.js │ ├── ServiceAlertIcon.test.js │ ├── StopAlerts.test.js │ ├── StopCardHeader.test.js │ ├── StopPageContentContainer.test.js │ ├── StopPageMap.test.js │ ├── StopPageTabs.test.js │ ├── Timetable.test.js │ ├── TimetableRow.test.js │ ├── TransitLeg.test.js │ ├── TripLink.test.js │ ├── TripRouteStop.test.js │ ├── TripStopListContainer.test.js │ ├── TripStopsContainer.test.js │ ├── UserMenu.test.js │ ├── VehicleIcon.test.js │ ├── VehicleRentalStationAvailability.test.js │ ├── ZoneIcon.test.js │ └── map │ │ ├── GenericMarker.test.js │ │ ├── GeoJSON.test.js │ │ ├── LocationMarker.test.js │ │ ├── MapWithTracking.test.js │ │ ├── MarkerPopupBottom.test.js │ │ ├── PointFeatureMarker.test.js │ │ ├── VehicleMarkerContainer.test.js │ │ ├── route │ │ └── TripMarkerPopup.test.js │ │ └── tile-layer │ │ ├── MarkerSelectPopup.test.js │ │ ├── SelectVehicleRentalStationRow.test.js │ │ ├── Stops.test.js │ │ ├── TileLayerContainer.test.js │ │ └── non-tile-layer │ │ └── StopMarker.test.js │ ├── config.test.js │ ├── configurations │ ├── config.default.test.js │ ├── config.hsl.test.js │ └── config.tampere.test.js │ ├── helpers │ ├── babel-register.js │ ├── init.js │ ├── mock-context.js │ ├── mock-intl-enzyme.js │ └── mock-router.js │ ├── hooks │ └── useWindowSize.test.js │ ├── localStorage.test.js │ ├── reittiopasParameterMiddleware.test.js │ ├── sessionStorage.test.js │ ├── store │ ├── GeoJsonStore.test.js │ ├── MessageStore.test.js │ ├── PositionStore.test.js │ ├── RealTimeInformationStore.test.js │ └── ViaPointsStore.test.js │ ├── test-data │ ├── dcw12.js │ ├── dcw28.js │ ├── dcw31.js │ ├── dt2587.js │ ├── dt2715a.js │ ├── dt2715b.js │ ├── dt2720.js │ ├── dt2734.js │ ├── dt2830.js │ ├── dt2831.js │ ├── dt2887.js │ └── dt2887b.js │ ├── translations.test.js │ ├── util │ ├── alertUtils.test.js │ ├── analyticsUtils.test.js │ ├── configMerger.test.js │ ├── fareUtils.test.js │ ├── fetchUtil.test.js │ ├── findErrorMessageIds.test.js │ ├── geo-utils.test.js │ ├── gtfsRtParser.test.js │ ├── hashUtil.test.js │ ├── legUtils.test.js │ ├── manifestUtils.test.js │ ├── mapLayerUtils.test.js │ ├── messageUtils.test.js │ ├── metaUtils.test.js │ ├── modeUtils.test.js │ ├── mqttClient.test.js │ ├── otpStrings.test.js │ ├── path.test.js │ ├── planParamUtil.test.js │ ├── queryUtils.test.js │ ├── suggestionUtils.test.js │ ├── timeUtils.test.js │ ├── timetableConfigUtils.test.js │ └── vehiclerental.test.js │ └── views │ └── ItineraryPage │ ├── ItineraryPageUtils.test.js │ └── component │ ├── Itinerary.test.js │ ├── ItineraryList.test.js │ └── NavigatorIntro.test.js ├── webpack.config.babel.js ├── win-launch-scripts ├── hsl-win-launch-script.bat └── national-win-launch-script.bat └── yarn.lock /.codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "app/util/gtfsrt.js" # this file is auto-generated by pbf v3.1.0 -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | .*swp 4 | 5 | .github 6 | 7 | LICENSE* 8 | Changelog.md 9 | win-launch-scripts/ 10 | docs/ 11 | /test 12 | 13 | /Dockerfile 14 | 15 | node_modules 16 | /.yarn 17 | # todo: keep? 18 | # !/.yarn/install-state.gz 19 | !/.yarn/plugins 20 | !/.yarn/releases 21 | !/.yarn/versions 22 | 23 | _static 24 | /app/__generated__ 25 | /app/**/__generated__ 26 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | _static 3 | static 4 | app/buildInfo.js 5 | build/schema.graphql 6 | digitransit-search-util/packages/digitransit-search-util-query-utils/schema/schema.graphql 7 | digitransit-component/packages/**/lib 8 | digitransit-store/packages/**/lib 9 | digitransit-search-util/packages/**/lib 10 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # Prettier style formatting 2 | f6e7192cc6e45b4aafb0798ab0e2ee50c8ba1408 3 | 6ae10969b173ee5b5465976883c265ca83e5a5c0 4 | 5 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Proposed Changes 2 | 3 | - 4 | 5 | ## Pull Request Check List 6 | 7 | - A reasonable set of unit tests is included 8 | - Console does not show new warnings/errors 9 | - Changes are documented or they are self explanatory 10 | - This pull request does not have any merge conflicts 11 | - All existing tests pass in CI build 12 | 13 | ## Review 14 | 15 | - Read and verify the code changes 16 | - Test the functionality by running the UI locally with all popular browsers available in your platform 17 | - Check that the implementation matches the design, when such one is defined in a Jira issue 18 | - Merge the pull request 19 | -------------------------------------------------------------------------------- /.github/workflows/scripts/push_prod.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | DOCKER_IMAGE="hsldevcom/digitransit-ui" 5 | DOCKER_TAG=${DOCKER_BASE_TAG:-prod} 6 | DOCKER_DEV_TAG=${DOCKER_DEV_TAG:-latest} 7 | 8 | COMMIT_HASH=$(git rev-parse --short "$GITHUB_SHA") 9 | 10 | DOCKER_TAG_LONG=$DOCKER_TAG-$(date +"%Y-%m-%dT%H.%M.%S")-$COMMIT_HASH 11 | DOCKER_IMAGE_TAG=$DOCKER_IMAGE:$DOCKER_TAG 12 | DOCKER_IMAGE_TAG_LONG=$DOCKER_IMAGE:$DOCKER_TAG_LONG 13 | DOCKER_IMAGE_DEV=$DOCKER_IMAGE:$DOCKER_DEV_TAG 14 | 15 | docker login -u $DOCKER_USER -p $DOCKER_AUTH 16 | 17 | echo "processing prod release" 18 | docker pull $DOCKER_IMAGE_DEV 19 | docker tag $DOCKER_IMAGE_DEV $DOCKER_IMAGE_TAG 20 | docker tag $DOCKER_IMAGE_DEV $DOCKER_IMAGE_TAG_LONG 21 | docker push $DOCKER_IMAGE_TAG 22 | docker push $DOCKER_IMAGE_TAG_LONG 23 | 24 | echo Build completed 25 | -------------------------------------------------------------------------------- /.github/workflows/scripts/slack_message.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [ -n "${SLACK_CHANNEL_ID}" ]; then 5 | MSG='{"channel": "'$SLACK_CHANNEL_ID'","text":"'"${PUBLISHED_PACKAGES}"'\n", "username": "NPM publisher"}' 6 | curl -X POST -H 'Content-Type: application/json' -H "Authorization: Bearer $SLACK_ACCESS_TOKEN" -H 'Accept: */*' -d "$MSG" 'https://slack.com/api/chat.postMessage' 7 | fi 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | _static 3 | npm-debug.log 4 | node_modules 5 | filesizes.html 6 | stats.json 7 | manifest.json 8 | test/credentials.json 9 | test/binaries 10 | *.swp 11 | .idea 12 | .vscode 13 | *.iml 14 | *~ 15 | test_output 16 | test/binaries 17 | selenium-debug.log 18 | tags 19 | .nyc_output 20 | coverage 21 | sessions/ 22 | run*.sh 23 | app/**/__generated__ 24 | digitransit-component/packages/**/*.generated 25 | digitransit-component/packages/**/lib 26 | digitransit-search-util/packages/**/__generated__ 27 | digitransit-search-util/packages/**/lib/ 28 | digitransit-store/packages/**/*.generated 29 | digitransit-store/packages/**/lib 30 | yarn-error.log 31 | dump.rdb 32 | .yarn/* 33 | !.yarn/patches 34 | !.yarn/releases 35 | !.yarn/plugins 36 | !.yarn/sdks 37 | !.yarn/versions 38 | .pnp.* 39 | .npmrc 40 | -------------------------------------------------------------------------------- /.lvimrc: -------------------------------------------------------------------------------- 1 | set tabstop=2 2 | set shiftwidth=2 3 | set softtabstop=2 4 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20 2 | -------------------------------------------------------------------------------- /.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "all": true, 3 | "sourceMap": false, 4 | "instrument": false, 5 | "require": [ 6 | "@babel/register" 7 | ], 8 | "include": [ 9 | "app/**/*.js" 10 | ], 11 | "reporter": [ 12 | "lcovonly", 13 | "html", 14 | "text-summary" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright 2015 Finnish Transport Agency and Helsinki Regional Transport Authority HSL 2 | 3 | The source code of this program is dual-licensed under the EUPL v1.2 and AGPLv3 licenses. 4 | -------------------------------------------------------------------------------- /app/action/CanceledLegsBarActions.js: -------------------------------------------------------------------------------- 1 | export default function updateShowCanceledLegsBannerState(actionContext, val) { 2 | actionContext.dispatch('updateShowCanceledLegsBannerState', val); 3 | } 4 | -------------------------------------------------------------------------------- /app/action/CountryActions.js: -------------------------------------------------------------------------------- 1 | export const updateCountries = (actionContext, countries) => { 2 | actionContext.dispatch('UpdateCountries', countries); 3 | }; 4 | 5 | export default updateCountries; 6 | -------------------------------------------------------------------------------- /app/action/FutureRoutesActions.js: -------------------------------------------------------------------------------- 1 | export function saveFutureRoute(actionContext, futureRoute) { 2 | actionContext.dispatch('saveFutureRoute', futureRoute); 3 | } 4 | -------------------------------------------------------------------------------- /app/action/MapLayerActions.js: -------------------------------------------------------------------------------- 1 | export const updateMapLayers = (actionContext, mapLayerSettings) => { 2 | actionContext.dispatch('UpdateMapLayers', mapLayerSettings); 3 | }; 4 | 5 | export default updateMapLayers; 6 | -------------------------------------------------------------------------------- /app/action/MessageActions.js: -------------------------------------------------------------------------------- 1 | export function addMessage(actionContext, message) { 2 | actionContext.dispatch('AddMessage', message); 3 | } 4 | 5 | export function markMessageAsRead(actionContext, id) { 6 | actionContext.dispatch('MarkMessageAsRead', id); 7 | } 8 | -------------------------------------------------------------------------------- /app/action/SearchActions.js: -------------------------------------------------------------------------------- 1 | export function saveSearch(actionContext, endpoint) { 2 | actionContext.dispatch('SaveSearch', endpoint); 3 | } 4 | 5 | export function removeSearch(actionContext, endpoint) { 6 | actionContext.dispatch('RemoveSearch', endpoint); 7 | } 8 | 9 | export function saveSearchItems(actionContext, items) { 10 | actionContext.dispatch('SaveSearchItems', items); 11 | } 12 | -------------------------------------------------------------------------------- /app/action/SearchSettingsActions.js: -------------------------------------------------------------------------------- 1 | export function saveRoutingSettings(actionContext, settings) { 2 | actionContext.dispatch('saveRoutingSettings', settings); 3 | } 4 | -------------------------------------------------------------------------------- /app/action/ViaPointActions.js: -------------------------------------------------------------------------------- 1 | export function addViaPoint(actionContext, val) { 2 | actionContext.dispatch('addViaPoint', val); 3 | } 4 | 5 | export function setViaPoints(actionContext, points) { 6 | actionContext.dispatch('setViaPoints', points); 7 | } 8 | -------------------------------------------------------------------------------- /app/action/destinationActions.js: -------------------------------------------------------------------------------- 1 | export default function storeDestination(actionContext, destination) { 2 | actionContext.dispatch('SetDestination', destination); 3 | } 4 | -------------------------------------------------------------------------------- /app/action/originActions.js: -------------------------------------------------------------------------------- 1 | export default function storeOrigin(actionContext, origin) { 2 | actionContext.dispatch('SetOrigin', origin); 3 | } 4 | -------------------------------------------------------------------------------- /app/action/realTimeClientAction.js: -------------------------------------------------------------------------------- 1 | import { startMqttClient, changeTopics } from '../util/mqttClient'; 2 | 3 | export function startRealTimeClient(actionContext, settings, done) { 4 | /* settings may have changed, so reset old store content */ 5 | if (actionContext.config.NODE_ENV === 'test') { 6 | return; 7 | } 8 | actionContext.dispatch('RealTimeClientReset'); 9 | startMqttClient(settings, actionContext).then(data => { 10 | actionContext.dispatch('RealTimeClientStarted', data); 11 | done(); 12 | }); 13 | } 14 | 15 | export function stopRealTimeClient(actionContext, client, done) { 16 | client.end(); 17 | actionContext.dispatch('RealTimeClientStopped'); 18 | done(); 19 | } 20 | 21 | export function changeRealTimeClientTopics(actionContext, settings, done) { 22 | // remove existing vehicles/topics 23 | actionContext.dispatch('RealTimeClientReset'); 24 | 25 | changeTopics(settings, actionContext); 26 | done(); 27 | } 28 | -------------------------------------------------------------------------------- /app/action/userActions.js: -------------------------------------------------------------------------------- 1 | export default function setUser(actionContext, user) { 2 | actionContext.dispatch('setUser', user); 3 | } 4 | -------------------------------------------------------------------------------- /app/action/userPreferencesActions.js: -------------------------------------------------------------------------------- 1 | export function setLanguage(actionContext, language) { 2 | actionContext.dispatch('SetLanguage', language); 3 | } 4 | -------------------------------------------------------------------------------- /app/buildInfo.js: -------------------------------------------------------------------------------- 1 | export const COMMIT_ID = 'unset'; 2 | export const BUILD_TIME = 'unset'; 3 | -------------------------------------------------------------------------------- /app/component/AgencyInfo.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | import ExternalLink from './ExternalLink'; 5 | 6 | function AgencyInfo({ agencyName, url }) { 7 | if (agencyName && url) { 8 | const link = url.indexOf('://') === -1 ? `//${url}` : url; 9 | 10 | return ( 11 |
12 | 13 |
30 ? 'overflow-fade' : ''}> 14 | {agencyName} 15 |
16 |
17 |
18 | ); 19 | } 20 | return null; 21 | } 22 | 23 | AgencyInfo.propTypes = { 24 | agencyName: PropTypes.string.isRequired, 25 | url: PropTypes.string.isRequired, 26 | }; 27 | 28 | export default AgencyInfo; 29 | -------------------------------------------------------------------------------- /app/component/Card.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import cx from 'classnames'; 4 | 5 | export default function Card({ className, children }) { 6 | return
{children}
; 7 | } 8 | 9 | Card.displayName = 'Card'; 10 | 11 | Card.propTypes = { 12 | className: PropTypes.string, 13 | children: PropTypes.node.isRequired, 14 | }; 15 | 16 | Card.defaultProps = { className: undefined }; 17 | -------------------------------------------------------------------------------- /app/component/CookieSettingsButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { FormattedMessage } from 'react-intl'; 3 | 4 | export default function CookieSettingsButton() { 5 | return ( 6 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /app/component/DTModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const DTModal = ({ show, children }) => { 5 | const showClassname = show ? 'dtmodal display-block' : 'modal display-none'; 6 | 7 | return ( 8 |
9 |
{children}
10 |
11 | ); 12 | }; 13 | 14 | DTModal.propTypes = { 15 | show: PropTypes.bool.isRequired, 16 | children: PropTypes.node, 17 | }; 18 | 19 | DTModal.defaultProps = { 20 | children: [], 21 | }; 22 | 23 | export default DTModal; 24 | -------------------------------------------------------------------------------- /app/component/ErrorHandlerSSR.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { FormattedMessage } from 'react-intl'; 4 | import Icon from './Icon'; 5 | 6 | export default function ErrorHandlerSSR() { 7 | return ( 8 |
9 | 10 |

11 | 15 |

16 |

17 | 27 |

28 |
29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /app/component/IndexPageMeta.js: -------------------------------------------------------------------------------- 1 | import { Helmet } from 'react-helmet'; 2 | import compose from 'recompose/compose'; 3 | import getContext from 'recompose/getContext'; 4 | import mapProps from 'recompose/mapProps'; 5 | import { configShape } from '../util/shapes'; 6 | import { generateManifestUrl } from '../util/manifestUtils'; 7 | import { isBrowser } from '../util/browser'; 8 | 9 | export default compose( 10 | getContext({ config: configShape }), 11 | mapProps(({ config }) => { 12 | if (!isBrowser) { 13 | return false; 14 | } 15 | return { 16 | link: [ 17 | { 18 | rel: 'manifest', 19 | href: generateManifestUrl(config, window.location, { 20 | ignorePathname: true, 21 | }), 22 | }, 23 | ], 24 | }; 25 | }), 26 | )(Helmet); 27 | -------------------------------------------------------------------------------- /app/component/Loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { FormattedMessage } from 'react-intl'; 4 | import ContainerSpinner from '@hsl-fi/container-spinner'; 5 | 6 | const defaultMessage = ( 7 | 8 | 9 | 10 | ); 11 | 12 | export default function Loading(props) { 13 | return ( 14 | 15 | {props?.children || defaultMessage} 16 | 17 | ); 18 | } 19 | 20 | Loading.displayName = 'Loading'; 21 | 22 | Loading.propTypes = { children: PropTypes.node }; 23 | Loading.defaultProps = { children: undefined }; 24 | -------------------------------------------------------------------------------- /app/component/LoadingPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Loading from './Loading'; 3 | 4 | export default function LoadingPage() { 5 | return ( 6 |
7 | 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /app/component/LoginButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Icon from './Icon'; 4 | 5 | const LoginButton = ({ loginUrl }) => { 6 | const loginClick = event => { 7 | event.preventDefault(); 8 | window.location.href = loginUrl; 9 | }; 10 | 11 | return ( 12 |
13 | 16 |
17 | ); 18 | }; 19 | 20 | LoginButton.propTypes = { 21 | loginUrl: PropTypes.string.isRequired, 22 | }; 23 | 24 | export default LoginButton; 25 | -------------------------------------------------------------------------------- /app/component/MainMenuContainer.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React, { Suspense, lazy } from 'react'; 3 | 4 | const MenuDrawer = lazy(() => import('./MenuDrawer')); 5 | const MainMenu = lazy(() => import('./MainMenu')); 6 | 7 | export default function MainMenuContainer({ breakpoint, closeMenu, ...rest }) { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | } 16 | 17 | MainMenuContainer.propTypes = { 18 | breakpoint: PropTypes.string, 19 | closeMenu: PropTypes.func.isRequired, 20 | }; 21 | 22 | MainMenuContainer.defaultProps = { 23 | breakpoint: 'small', 24 | }; 25 | -------------------------------------------------------------------------------- /app/component/Message.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { FormattedMessage } from 'react-intl'; 4 | 5 | export default function Message({ labelId, defaultMessage }) { 6 | if (labelId) { 7 | return ; 8 | } 9 | if (defaultMessage) { 10 | return {defaultMessage} ; 11 | } 12 | return null; 13 | } 14 | 15 | Message.propTypes = { 16 | labelId: PropTypes.string, 17 | defaultMessage: PropTypes.string, 18 | }; 19 | 20 | Message.defaultProps = { 21 | labelId: undefined, 22 | defaultMessage: undefined, 23 | }; 24 | -------------------------------------------------------------------------------- /app/component/NetworkError.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { matchShape } from 'found'; 4 | 5 | import { FormattedMessage } from 'react-intl'; 6 | import Link from 'found/Link'; 7 | import Icon from './Icon'; 8 | 9 | const NetworkError = ({ retry }, { match }) => ( 10 |
11 | 12 |

13 | 17 |

18 |

19 | 20 | 21 | 22 |

23 |
24 | ); 25 | 26 | NetworkError.propTypes = { retry: PropTypes.func.isRequired }; 27 | NetworkError.contextTypes = { 28 | match: matchShape.isRequired, 29 | }; 30 | 31 | export default NetworkError; 32 | -------------------------------------------------------------------------------- /app/component/ParkContainer.js: -------------------------------------------------------------------------------- 1 | import { createFragmentContainer, graphql } from 'react-relay'; 2 | import ParkAndRideContent from './ParkAndRideContent'; 3 | 4 | const containerComponent = createFragmentContainer(ParkAndRideContent, { 5 | vehicleParking: graphql` 6 | fragment ParkContainer_vehicleParking on VehicleParking { 7 | availability { 8 | bicycleSpaces 9 | carSpaces 10 | } 11 | capacity { 12 | carSpaces 13 | } 14 | name 15 | lat 16 | lon 17 | tags 18 | realtime 19 | } 20 | `, 21 | }); 22 | 23 | export { containerComponent as default, ParkAndRideContent as Component }; 24 | -------------------------------------------------------------------------------- /app/component/RentalVehicle.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import Icon from './Icon'; 4 | import { 5 | getRentalNetworkIcon, 6 | getRentalNetworkConfig, 7 | } from '../util/vehicleRentalUtils'; 8 | import { rentalVehicleShape } from '../util/shapes'; 9 | 10 | const RentalVehicle = ({ rentalVehicle }, { config }) => { 11 | const vehicleIcon = getRentalNetworkIcon( 12 | getRentalNetworkConfig(rentalVehicle.rentalNetwork.networkId, config), 13 | ); 14 | return ( 15 |
16 | 17 |
18 | ); 19 | }; 20 | 21 | RentalVehicle.contextTypes = { 22 | config: PropTypes.shape({ 23 | vehicleRental: { networks: PropTypes.arrayOf(PropTypes.string.isRequired) }, 24 | }).isRequired, 25 | }; 26 | RentalVehicle.propTypes = { 27 | rentalVehicle: rentalVehicleShape.isRequired, 28 | }; 29 | export default RentalVehicle; 30 | -------------------------------------------------------------------------------- /app/component/SplitBars.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | const SplitBars = ({ children }) => { 5 | let splits = []; 6 | children.forEach(child => { 7 | splits.push(
{child}
); 8 | splits.push(
); 9 | }); 10 | splits = splits.splice(0, splits.length - 1); 11 | return
{splits}
; 12 | }; 13 | 14 | SplitBars.displayName = 'SplitBars'; 15 | 16 | SplitBars.propTypes = { 17 | children: PropTypes.node.isRequired, 18 | }; 19 | 20 | export default SplitBars; 21 | -------------------------------------------------------------------------------- /app/component/StopCode.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | const StopCode = ({ code }) => 5 | code && {code}; 6 | 7 | StopCode.displayName = 'StopCode'; 8 | StopCode.propTypes = { 9 | code: PropTypes.string.isRequired, 10 | }; 11 | export default StopCode; 12 | -------------------------------------------------------------------------------- /app/component/Title.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { configShape } from '../util/shapes'; 3 | 4 | const TitleComponent = (props, { config: { title } }) => {title}; 5 | 6 | TitleComponent.contextTypes = { config: configShape.isRequired }; 7 | 8 | export default TitleComponent; 9 | -------------------------------------------------------------------------------- /app/component/ToggleMapTracking.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import Icon from './Icon'; 4 | 5 | /* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */ 6 | function ToggleMapTracking(props) { 7 | return ( 8 |
15 | 16 |
17 | ); 18 | } 19 | 20 | ToggleMapTracking.propTypes = { 21 | handleClick: PropTypes.func.isRequired, 22 | className: PropTypes.string.isRequired, 23 | img: PropTypes.string.isRequired, 24 | ariaLabel: PropTypes.string.isRequired, 25 | }; 26 | 27 | export default ToggleMapTracking; 28 | -------------------------------------------------------------------------------- /app/component/app-bar-hsl.scss: -------------------------------------------------------------------------------- 1 | .hslfi-cb__button-primary { 2 | &:hover { 3 | background-color: #0062a1 !important; 4 | color: white !important; 5 | } 6 | } 7 | 8 | .hslfi-cb__button-secondary { 9 | &:hover { 10 | color: #0062a1 !important; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/component/embedded/EmbeddedSearchContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { matchShape } from 'found'; 3 | import LazilyLoad, { importLazy } from '../LazilyLoad'; 4 | 5 | const modules = { 6 | EmbeddedSearch: () => importLazy(import('./EmbeddedSearch')), 7 | }; 8 | 9 | const EmbeddedSearchContainer = props => { 10 | return ( 11 | 12 | {({ EmbeddedSearch }) => } 13 | 14 | ); 15 | }; 16 | 17 | EmbeddedSearchContainer.propTypes = { 18 | match: matchShape.isRequired, 19 | }; 20 | 21 | export default EmbeddedSearchContainer; 22 | -------------------------------------------------------------------------------- /app/component/itinerary/AirplaneLeg.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { FormattedMessage } from 'react-intl'; 4 | import { legShape } from '../../util/shapes'; 5 | 6 | import TransitLeg from './TransitLeg'; 7 | 8 | const AirplaneLeg = ({ leg, focusAction, index }) => ( 9 | 16 | 23 | 24 | ); 25 | 26 | AirplaneLeg.propTypes = { 27 | leg: legShape.isRequired, 28 | index: PropTypes.number.isRequired, 29 | focusAction: PropTypes.func.isRequired, 30 | }; 31 | 32 | export default AirplaneLeg; 33 | -------------------------------------------------------------------------------- /app/component/itinerary/ChangeDepartureTimeLink.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cx from 'classnames'; 3 | import { matchShape } from 'found'; 4 | import { FormattedMessage } from 'react-intl'; 5 | 6 | const ChangeDepartureTimeLink = ({ match }) => ( 7 |
8 | 9 | 10 | 11 |
12 | ); 13 | 14 | ChangeDepartureTimeLink.propTypes = { 15 | match: matchShape.isRequired, 16 | }; 17 | 18 | export default ChangeDepartureTimeLink; 19 | -------------------------------------------------------------------------------- /app/component/itinerary/Duration.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { FormattedMessage } from 'react-intl'; 4 | 5 | function Duration({ duration }) { 6 | const dur = Math.max(duration, 0); 7 | const hours = Math.floor(dur / 3600000); 8 | const mins = Math.floor(dur / 60000 - hours * 60); 9 | if (hours >= 1) { 10 | return ( 11 | 15 | ); 16 | } 17 | return ( 18 | 22 | ); 23 | } 24 | 25 | Duration.propTypes = { duration: PropTypes.number.isRequired }; 26 | 27 | export default Duration; 28 | -------------------------------------------------------------------------------- /app/component/itinerary/FeedbackPrompt.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { FormattedMessage } from 'react-intl'; 3 | import { configShape } from '../../util/shapes'; 4 | 5 | export default function FeedbackPrompt(props, { config }) { 6 | return config.useRoutingFeedbackPrompt ? ( 7 |
8 |
9 | 10 |
11 | 17 | 18 | 19 |
20 | ) : null; 21 | } 22 | 23 | FeedbackPrompt.contextTypes = { 24 | config: configShape, 25 | }; 26 | -------------------------------------------------------------------------------- /app/component/itinerary/ItineraryDistance.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { FormattedMessage } from 'react-intl'; 4 | 5 | const Distance = props => { 6 | let approxDistance; 7 | 8 | if (props.distance > 0) { 9 | approxDistance = Math.round(props.distance / 50) * 50; 10 | 11 | if (approxDistance > 50) { 12 | return ( 13 | 18 | ); 19 | } 20 | } 21 | 22 | return null; 23 | }; 24 | 25 | Distance.propTypes = { 26 | distance: PropTypes.number.isRequired, 27 | }; 28 | 29 | export default Distance; 30 | -------------------------------------------------------------------------------- /app/component/itinerary/ItineraryNotification.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { FormattedMessage } from 'react-intl'; 4 | import Icon from '../Icon'; 5 | 6 | export default function ItineraryNotification({ headerId, bodyId, iconId }) { 7 | return ( 8 |
9 |
{iconId && }
10 |
11 |

{headerId && }

12 |

{bodyId && }

13 |
14 |
15 | ); 16 | } 17 | 18 | ItineraryNotification.propTypes = { 19 | headerId: PropTypes.string, 20 | bodyId: PropTypes.string, 21 | iconId: PropTypes.string, 22 | }; 23 | 24 | ItineraryNotification.defaultProps = { 25 | headerId: undefined, 26 | bodyId: undefined, 27 | iconId: undefined, 28 | }; 29 | -------------------------------------------------------------------------------- /app/component/itinerary/ItineraryPageTitle.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { matchShape } from 'found'; 3 | import { FormattedMessage } from 'react-intl'; 4 | 5 | export default function ItineraryPageTitle(props) { 6 | return ( 7 | 8 | {props.match.params.hash == null ? ( 9 | 13 | ) : ( 14 | 18 | )} 19 | 20 | ); 21 | } 22 | 23 | ItineraryPageTitle.propTypes = { 24 | match: matchShape.isRequired, 25 | }; 26 | -------------------------------------------------------------------------------- /app/component/itinerary/PastLink.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { matchShape } from 'found'; 3 | import { FormattedMessage } from 'react-intl'; 4 | import cx from 'classnames'; 5 | 6 | const PastLink = ({ match }) => ( 7 |
8 | 9 | 10 | 11 |
12 | ); 13 | 14 | PastLink.propTypes = { 15 | match: matchShape.isRequired, 16 | }; 17 | 18 | export default PastLink; 19 | -------------------------------------------------------------------------------- /app/component/itinerary/itinerary-profile.scss: -------------------------------------------------------------------------------- 1 | .itinerary-profile-container { 2 | display: flex; 3 | align-items: center; 4 | justify-content: space-between; 5 | margin-left: 15px; 6 | font-size: 15px; 7 | line-height: 18px; 8 | margin-top: 7px; 9 | margin-bottom: 7px; 10 | 11 | &.small { 12 | font-size: 10pt; 13 | } 14 | 15 | .itinerary-profile-item-title { 16 | @include font-book; 17 | 18 | color: $gray; 19 | display: inline-block; 20 | } 21 | 22 | .itinerary-profile-item-value { 23 | color: $black; 24 | display: inline-block; 25 | margin-left: 0.25rem; 26 | } 27 | 28 | @media print { 29 | margin-bottom: 16px; 30 | } 31 | 32 | button { 33 | display: none; 34 | 35 | @include min-width(tablet) { 36 | display: flex; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/component/itinerary/navigator/hooks/useLogo.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from 'react'; 2 | 3 | const useLogo = logoPath => { 4 | const [logo, setLogo] = useState(null); 5 | const [loading, setLoading] = useState(true); 6 | 7 | const fetchLogo = useCallback(async () => { 8 | setLoading(true); 9 | try { 10 | const importedLogo = await import( 11 | /* webpackChunkName: "main" */ `../../../../configurations/images/${logoPath}` 12 | ); 13 | setLogo(importedLogo.default); 14 | } catch (error) { 15 | // eslint-disable-next-line no-console 16 | console.error('Error loading logo:', error); 17 | } finally { 18 | setLoading(false); 19 | } 20 | }, [logoPath]); 21 | 22 | useEffect(() => { 23 | fetchLogo(); 24 | }, [fetchLogo]); 25 | 26 | return { logo, loading }; 27 | }; 28 | 29 | export { useLogo }; 30 | -------------------------------------------------------------------------------- /app/component/itinerary/navigator/hooks/usePrevious.js: -------------------------------------------------------------------------------- 1 | import { useRef } from 'react'; 2 | 3 | const usePrevious = (value, comparingFunc) => { 4 | const ref = useRef({ 5 | value, 6 | prev: null, 7 | }); 8 | 9 | const current = ref.current.value; 10 | let isEqual = false; 11 | 12 | if ( 13 | comparingFunc 14 | ? !comparingFunc(current, value) 15 | : JSON.stringify(value) !== JSON.stringify(current) 16 | ) { 17 | ref.current = { 18 | value, 19 | prev: current, 20 | }; 21 | isEqual = true; 22 | } 23 | 24 | return { previous: ref.current.prev, isEqual }; 25 | }; 26 | 27 | export default usePrevious; 28 | -------------------------------------------------------------------------------- /app/component/itinerary/navigator/navigatorgeolocation/navigator-geolocation.scss: -------------------------------------------------------------------------------- 1 | .navigator-modal-content { 2 | .geolocation-body { 3 | display: flex; 4 | flex-direction: column; 5 | flex-wrap: wrap; 6 | align-items: stretch; 7 | align-content: center; 8 | gap: var(--space-m); 9 | 10 | &.slide-in { 11 | animation: slideUpFromBottom 0.5s ease-in-out; 12 | } 13 | 14 | h2 { 15 | text-align: center; 16 | margin: unset; 17 | } 18 | 19 | p { 20 | margin: 0 0 var(--space-m) 0; 21 | line-height: 1.3; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/component/itinerary/origin-destination-bar.scss: -------------------------------------------------------------------------------- 1 | .origin-destination-bar { 2 | background-color: #fff; 3 | display: flex; 4 | justify-content: space-around; 5 | align-items: initial; 6 | 7 | &.bp-large { 8 | margin: 0 60px; 9 | } 10 | } 11 | 12 | .mobile { 13 | .origin-destination-bar { 14 | z-index: 999; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/component/itinerary/queries/ItineraryListContainerPlanEdges.js: -------------------------------------------------------------------------------- 1 | import { graphql } from 'react-relay'; 2 | 3 | export const ItineraryListContainerPlanEdges = graphql` 4 | fragment ItineraryListContainerPlanEdges on PlanEdge @relay(plural: true) { 5 | ...ItineraryListPlanEdges 6 | node { 7 | legs { 8 | mode 9 | } 10 | } 11 | } 12 | `; 13 | -------------------------------------------------------------------------------- /app/component/itinerary/queries/ItineraryListPlanEdges.js: -------------------------------------------------------------------------------- 1 | import { graphql } from 'react-relay'; 2 | 3 | export const ItineraryListPlanEdges = graphql` 4 | fragment ItineraryListPlanEdges on PlanEdge @relay(plural: true) { 5 | node { 6 | ...ItineraryFragment 7 | emissionsPerPerson { 8 | co2 9 | } 10 | legs { 11 | transitLeg 12 | mode 13 | route { 14 | mode 15 | type 16 | } 17 | } 18 | } 19 | } 20 | `; 21 | -------------------------------------------------------------------------------- /app/component/itinerary/queries/LegAgencyInfoFragment.js: -------------------------------------------------------------------------------- 1 | import { graphql } from 'react-relay'; 2 | 3 | export const LegAgencyInfoFragment = graphql` 4 | fragment LegAgencyInfoFragment on Leg { 5 | agency { 6 | name 7 | url 8 | fareUrl 9 | } 10 | } 11 | `; 12 | -------------------------------------------------------------------------------- /app/component/map/MapBottomsheetContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | // undefined value used in desktop 4 | export default createContext(undefined); 5 | -------------------------------------------------------------------------------- /app/component/map/tile-layer/ParkAndRideForBikes.js: -------------------------------------------------------------------------------- 1 | import ParkAndRide from './ParkAndRide'; 2 | import { ParkTypes } from '../../../constants'; 3 | 4 | export default class ParkAndRideForBikes extends ParkAndRide { 5 | constructor(tile, config, mapLayers, relayEnvironment, lang) { 6 | super(tile, config, relayEnvironment, lang); 7 | } 8 | 9 | static getName = () => 'parkAndRideForBikes'; 10 | 11 | getPromise(lang) { 12 | return this.fetchAndDrawParks(ParkTypes.Bicycle, lang); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/component/map/tile-layer/ParkAndRideForCars.js: -------------------------------------------------------------------------------- 1 | import ParkAndRide from './ParkAndRide'; 2 | import { ParkTypes } from '../../../constants'; 3 | 4 | export default class ParkAndRideForCars extends ParkAndRide { 5 | constructor(tile, config, mapLayers, relayEnvironment, lang) { 6 | super(tile, config, relayEnvironment, lang); 7 | } 8 | 9 | static getName = () => 'parkAndRide'; 10 | 11 | getPromise(lang) { 12 | return this.fetchAndDrawParks(ParkTypes.Car, lang); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/component/no-favourites-panel.scss: -------------------------------------------------------------------------------- 1 | /* No favourites image */ 2 | 3 | .front-page { 4 | .nofavs-img { 5 | height: 80px; 6 | width: 100%; 7 | max-width: 160px; 8 | margin: 0 auto; 9 | margin-top: 4.5em; 10 | } 11 | 12 | .no-favourites-icon { 13 | fill: transparent; 14 | stroke: $link-color; 15 | stroke-width: 25px; 16 | width: 56px; 17 | height: 56px; 18 | } 19 | 20 | .nofavs-p { 21 | width: 70%; 22 | margin-left: 15%; 23 | margin-right: 15%; 24 | font-size: $font-size-small; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/component/select-maplayers-dialog.scss: -------------------------------------------------------------------------------- 1 | .select-map-layers-dialog-content { 2 | display: flex; 3 | flex-direction: column; 4 | margin-top: 0.25em; 5 | position: relative; 6 | 7 | &.bubble-dialog-content--large { 8 | white-space: nowrap; 9 | } 10 | 11 | .checkbox-grouping + .checkbox-grouping { 12 | margin-top: 2em; 13 | 14 | &::before { 15 | border-top: 1px solid $light-gray; 16 | content: ''; 17 | left: 0; 18 | margin-top: -1.05em; 19 | right: 0; 20 | position: absolute; 21 | } 22 | } 23 | 24 | .option-checkbox-container + .option-checkbox-container { 25 | margin-top: 0.25em; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/component/stop/StopCardHeaderContainer.js: -------------------------------------------------------------------------------- 1 | import connectToStores from 'fluxible-addons-react/connectToStores'; 2 | import { createFragmentContainer, graphql } from 'react-relay'; 3 | 4 | import StopCardHeader from './StopCardHeader'; 5 | 6 | export default createFragmentContainer( 7 | connectToStores(StopCardHeader, ['TimeStore'], context => ({ 8 | currentTime: context.getStore('TimeStore').getCurrentTime(), 9 | })), 10 | { 11 | stop: graphql` 12 | fragment StopCardHeaderContainer_stop on Stop { 13 | gtfsId 14 | name 15 | code 16 | desc 17 | zoneId 18 | alerts { 19 | alertSeverityLevel 20 | effectiveEndDate 21 | effectiveStartDate 22 | } 23 | lat 24 | lon 25 | stops { 26 | name 27 | desc 28 | } 29 | } 30 | `, 31 | }, 32 | ); 33 | -------------------------------------------------------------------------------- /app/component/stop/StopPageHeader.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import mapProps from 'recompose/mapProps'; 3 | import getContext from 'recompose/getContext'; 4 | import compose from 'recompose/compose'; 5 | 6 | import StopCardHeaderContainer from './StopCardHeaderContainer'; 7 | import withBreakpoint from '../../util/withBreakpoint'; 8 | 9 | const StopPageHeader = compose( 10 | withBreakpoint, 11 | getContext({ 12 | executeAction: PropTypes.func.isRequired, 13 | }), 14 | mapProps(props => ({ 15 | stop: props.stop || props.station, 16 | className: 'stop-page header', 17 | headingStyle: 'h3', 18 | icons: [], 19 | breakpoint: props.breakpoint, 20 | isTerminal: props.isTerminal, 21 | })), 22 | )(StopCardHeaderContainer); 23 | 24 | StopPageHeader.displayName = 'StopPageHeader'; 25 | 26 | export default StopPageHeader; 27 | -------------------------------------------------------------------------------- /app/component/stop/StopPageHeaderContainer.js: -------------------------------------------------------------------------------- 1 | import { createFragmentContainer, graphql } from 'react-relay'; 2 | import connectToStores from 'fluxible-addons-react/connectToStores'; 3 | 4 | import StopPageHeader from './StopPageHeader'; 5 | 6 | export default createFragmentContainer( 7 | connectToStores( 8 | StopPageHeader, 9 | ['FavouriteStore'], 10 | ({ getStore }, { match }) => ({ 11 | favourite: getStore('FavouriteStore').isFavourite( 12 | match.params.stopId, 13 | 'stop', 14 | ), 15 | }), 16 | ), 17 | { 18 | stop: graphql` 19 | fragment StopPageHeaderContainer_stop on Stop { 20 | ...StopCardHeaderContainer_stop 21 | } 22 | `, 23 | }, 24 | ); 25 | -------------------------------------------------------------------------------- /app/component/stop/StopTitle.js: -------------------------------------------------------------------------------- 1 | import withProps from 'recompose/withProps'; 2 | import { FormattedMessage } from 'react-intl'; 3 | 4 | export default withProps({ 5 | id: 'stop-page.title-short', 6 | defaultMessage: 'Stop', 7 | })(FormattedMessage); 8 | -------------------------------------------------------------------------------- /app/component/stop/TerminalPageHeaderContainer.js: -------------------------------------------------------------------------------- 1 | import { createFragmentContainer, graphql } from 'react-relay'; 2 | import connectToStores from 'fluxible-addons-react/connectToStores'; 3 | 4 | import StopPageHeader from './StopPageHeader'; 5 | 6 | export default createFragmentContainer( 7 | connectToStores( 8 | StopPageHeader, 9 | ['FavouriteStore'], 10 | ({ getStore }, { match }) => ({ 11 | favourite: getStore('FavouriteStore').isFavourite( 12 | match.params.terminalId, 13 | 'station', 14 | ), 15 | isTerminal: true, 16 | }), 17 | ), 18 | { 19 | station: graphql` 20 | fragment TerminalPageHeaderContainer_station on Stop { 21 | ...StopCardHeaderContainer_stop 22 | } 23 | `, 24 | }, 25 | ); 26 | -------------------------------------------------------------------------------- /app/component/stop/TerminalTitle.js: -------------------------------------------------------------------------------- 1 | import withProps from 'recompose/withProps'; 2 | import { FormattedMessage } from 'react-intl'; 3 | 4 | export default withProps({ 5 | id: 'terminal-page.title-short', 6 | defaultMessage: 'Terminal', 7 | })(FormattedMessage); 8 | -------------------------------------------------------------------------------- /app/component/stop/queries/TimetableFragment.js: -------------------------------------------------------------------------------- 1 | import { graphql } from 'react-relay'; 2 | 3 | export const TimetableFragment = graphql` 4 | fragment TimetableFragment on Stop 5 | @argumentDefinitions(date: { type: "String" }) { 6 | gtfsId 7 | name 8 | url 9 | locationType 10 | stoptimesForServiceDate(date: $date, omitCanceled: false) { 11 | pattern { 12 | headsign 13 | code 14 | route { 15 | id 16 | shortName 17 | longName 18 | type 19 | mode 20 | agency { 21 | id 22 | name 23 | } 24 | } 25 | } 26 | stoptimes { 27 | realtimeState 28 | scheduledDeparture 29 | serviceDay 30 | headsign 31 | pickupType 32 | } 33 | } 34 | } 35 | `; 36 | -------------------------------------------------------------------------------- /app/component/visual/OverlayWithSpinner.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { FormattedMessage } from 'react-intl'; 3 | import Loading from '../Loading'; 4 | 5 | const OverlayWithSpinner = () => ( 6 |
7 |
8 | 9 |
10 | 14 |
15 | ); 16 | 17 | export default OverlayWithSpinner; 18 | -------------------------------------------------------------------------------- /app/component/visual/index.scss: -------------------------------------------------------------------------------- 1 | @import 'overlay-with-spinner'; 2 | -------------------------------------------------------------------------------- /app/component/visual/overlay-with-spinner.scss: -------------------------------------------------------------------------------- 1 | div.overlay-with-spinner { 2 | background-color: rgba(255, 255, 255, 0.6); 3 | z-index: 2001; 4 | width: 100%; 5 | height: 100%; 6 | position: absolute; 7 | top: 0; 8 | right: 0; 9 | justify-content: center; 10 | display: flex; 11 | flex-direction: column; 12 | 13 | div { 14 | display: flex; 15 | height: 68px; 16 | justify-content: center; 17 | margin-bottom: 20px; 18 | } 19 | 20 | span { 21 | text-align: center; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/component/zone-icon.scss: -------------------------------------------------------------------------------- 1 | .zone-icon-container { 2 | .circle { 3 | display: flex; 4 | justify-content: center; 5 | width: 0.875rem; 6 | height: 0.875rem; 7 | border-radius: 50%; 8 | font-size: 12px; 9 | color: #fff; 10 | letter-spacing: 0; 11 | padding: 0 2px 0 2px; 12 | line-height: 1.2; 13 | background: $primary-color; 14 | font-weight: $font-weight-medium; 15 | 16 | &.multi-letter { 17 | border-radius: 10px; 18 | width: max-content; 19 | } 20 | } 21 | 22 | .unknown { 23 | text-align: center; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/configurations/images/default/default-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/default/default-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/default/digitransit-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/default/digitransit-logo.png -------------------------------------------------------------------------------- /app/configurations/images/default/dotted-line-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/default/dotted-line-bg.png -------------------------------------------------------------------------------- /app/configurations/images/default/dotted-line-bg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/default/dotted-line-bg2.png -------------------------------------------------------------------------------- /app/configurations/images/default/dotted-line.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 16 | 17 | -------------------------------------------------------------------------------- /app/configurations/images/hameenlinna/hameenlinna-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/hameenlinna/hameenlinna-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/hameenlinna/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/hameenlinna/logo.png -------------------------------------------------------------------------------- /app/configurations/images/hameenlinna/secondary-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/hameenlinna/secondary-logo.png -------------------------------------------------------------------------------- /app/configurations/images/hsl/hsl-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/hsl/hsl-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/joensuu/joensuu-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/joensuu/joensuu-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/joensuu/jojo-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/joensuu/jojo-logo.png -------------------------------------------------------------------------------- /app/configurations/images/jyvaskyla/jyvaskyla-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/jyvaskyla/jyvaskyla-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/kotka/kotka.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/kotka/kotka.png -------------------------------------------------------------------------------- /app/configurations/images/kouvola/kouvola-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/kouvola/kouvola-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/kouvola/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/kouvola/logo.png -------------------------------------------------------------------------------- /app/configurations/images/kouvola/secondary-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/kouvola/secondary-logo.png -------------------------------------------------------------------------------- /app/configurations/images/kuopio/kuopio-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/kuopio/kuopio-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/kuopio/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/kuopio/logo.png -------------------------------------------------------------------------------- /app/configurations/images/kuopio/secondary-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/kuopio/secondary-logo.png -------------------------------------------------------------------------------- /app/configurations/images/lahti/lahti-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/lahti/lahti-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/lahti/lahti-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/lahti/lahti-logo.png -------------------------------------------------------------------------------- /app/configurations/images/lahti/secondary-lahti-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/lahti/secondary-lahti-logo.png -------------------------------------------------------------------------------- /app/configurations/images/lappeenranta/lappeenranta-favicon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/lappeenranta/lappeenranta-favicon.jpg -------------------------------------------------------------------------------- /app/configurations/images/lappeenranta/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/lappeenranta/logo.png -------------------------------------------------------------------------------- /app/configurations/images/lappeenranta/secondary-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/lappeenranta/secondary-logo.png -------------------------------------------------------------------------------- /app/configurations/images/oulu/oulu-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/oulu/oulu-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/oulu/oulu-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/oulu/oulu-logo.png -------------------------------------------------------------------------------- /app/configurations/images/oulu/secondary-oulu-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/oulu/secondary-oulu-logo.png -------------------------------------------------------------------------------- /app/configurations/images/pori/pori-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/pori/pori-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/raasepori/raasepori-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/raasepori/raasepori-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/raasepori/raasepori_logo_musta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/raasepori/raasepori_logo_musta.png -------------------------------------------------------------------------------- /app/configurations/images/raasepori/raasepori_logo_valkoinen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/raasepori/raasepori_logo_valkoinen.png -------------------------------------------------------------------------------- /app/configurations/images/rovaniemi/rovaniemi-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/rovaniemi/rovaniemi-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/tampere/tampere-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/tampere/tampere-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/tampere/tampere-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/tampere/tampere-logo.png -------------------------------------------------------------------------------- /app/configurations/images/turku/foli-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/turku/foli-logo.png -------------------------------------------------------------------------------- /app/configurations/images/turku/turku-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/turku/turku-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/vaasa/secondary-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/vaasa/secondary-logo.png -------------------------------------------------------------------------------- /app/configurations/images/vaasa/vaasa-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/vaasa/vaasa-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/varely/varely-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/varely/varely-favicon.png -------------------------------------------------------------------------------- /app/configurations/images/walttiOpas/waltti-logo-secondary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/walttiOpas/waltti-logo-secondary.png -------------------------------------------------------------------------------- /app/configurations/images/walttiOpas/waltti-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/walttiOpas/waltti-logo.png -------------------------------------------------------------------------------- /app/configurations/images/walttiOpas/walttiOpas-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/app/configurations/images/walttiOpas/walttiOpas-favicon.png -------------------------------------------------------------------------------- /app/store/CanceledLegsBarStore.js: -------------------------------------------------------------------------------- 1 | import Store from 'fluxible/addons/BaseStore'; 2 | 3 | class CanceledLegsBarStore extends Store { 4 | static storeName = 'CanceledLegsBarStore'; 5 | 6 | showCanceledLegsBanner = false; 7 | 8 | updateShowCanceledLegsBannerState(val) { 9 | this.showCanceledLegsBanner = val; 10 | this.emit('change'); 11 | } 12 | 13 | getShowCanceledLegsBanner() { 14 | return this.showCanceledLegsBanner; 15 | } 16 | 17 | static handlers = { 18 | updateShowCanceledLegsBannerState: 'updateShowCanceledLegsBannerState', 19 | getShowCanceledLegsBanner: 'getShowCanceledLegsBanner', 20 | }; 21 | } 22 | 23 | export default CanceledLegsBarStore; 24 | -------------------------------------------------------------------------------- /app/store/CountryStore.js: -------------------------------------------------------------------------------- 1 | import Store from 'fluxible/addons/BaseStore'; 2 | import { getCountries, setCountries } from './localStorage'; 3 | 4 | class CountryStore extends Store { 5 | static handlers = { 6 | UpdateCountries: 'updateCountries', 7 | }; 8 | 9 | static storeName = 'CountryStore'; 10 | 11 | countries = getCountries(); 12 | 13 | getCountries = () => { 14 | return this.countries; 15 | }; 16 | 17 | updateCountries = countries => { 18 | this.countries = countries; 19 | setCountries(countries); 20 | this.emitChange(); 21 | }; 22 | } 23 | 24 | export default CountryStore; 25 | -------------------------------------------------------------------------------- /app/store/DestinationStore.js: -------------------------------------------------------------------------------- 1 | import Store from 'fluxible/addons/BaseStore'; 2 | 3 | class DestinationStore extends Store { 4 | static storeName = 'DestinationStore'; 5 | 6 | constructor(...args) { 7 | super(...args); 8 | this.destination = {}; 9 | } 10 | 11 | getDestination() { 12 | return this.destination; 13 | } 14 | 15 | setDestination(destination) { 16 | this.destination = destination; 17 | this.emitChange(); 18 | } 19 | 20 | static handlers = { 21 | SetDestination: 'setDestination', 22 | }; 23 | } 24 | 25 | export default DestinationStore; 26 | -------------------------------------------------------------------------------- /app/store/OriginStore.js: -------------------------------------------------------------------------------- 1 | import Store from 'fluxible/addons/BaseStore'; 2 | 3 | class OriginStore extends Store { 4 | static storeName = 'OriginStore'; 5 | 6 | constructor(...args) { 7 | super(...args); 8 | this.origin = {}; 9 | } 10 | 11 | getOrigin() { 12 | return this.origin; 13 | } 14 | 15 | setOrigin(origin) { 16 | this.origin = origin; 17 | this.emitChange(); 18 | } 19 | 20 | static handlers = { 21 | SetOrigin: 'setOrigin', 22 | }; 23 | } 24 | 25 | export default OriginStore; 26 | -------------------------------------------------------------------------------- /app/store/UserStore.js: -------------------------------------------------------------------------------- 1 | import Store from 'fluxible/addons/BaseStore'; 2 | 3 | class UserStore extends Store { 4 | static storeName = 'UserStore'; 5 | 6 | user = {}; 7 | 8 | getUser() { 9 | return this.user; 10 | } 11 | 12 | setUser(user) { 13 | this.user = user; 14 | this.emitChange(); 15 | } 16 | 17 | static handlers = { 18 | setUser: 'setUser', 19 | }; 20 | } 21 | 22 | export default UserStore; 23 | -------------------------------------------------------------------------------- /app/store/ViaPointStore.js: -------------------------------------------------------------------------------- 1 | import Store from 'fluxible/addons/BaseStore'; 2 | 3 | class ViaPointStore extends Store { 4 | static storeName = 'ViaPointStore'; 5 | 6 | viaPoints = []; 7 | 8 | addViaPoint(val) { 9 | this.viaPoints.push(val); 10 | this.emitChange(); 11 | } 12 | 13 | setViaPoints(viaPoints) { 14 | this.viaPoints = [...viaPoints]; 15 | this.emitChange(); 16 | } 17 | 18 | getViaPoints() { 19 | return this.viaPoints; 20 | } 21 | 22 | static handlers = { 23 | addViaPoint: 'addViaPoint', 24 | setViaPoints: 'setViaPoints', 25 | }; 26 | } 27 | 28 | export default ViaPointStore; 29 | -------------------------------------------------------------------------------- /app/util/StoreListeningIntlProvider.js: -------------------------------------------------------------------------------- 1 | import { IntlProvider, addLocaleData } from 'react-intl'; 2 | import connectToStores from 'fluxible-addons-react/connectToStores'; 3 | 4 | export default connectToStores( 5 | IntlProvider, 6 | ['PreferencesStore'], 7 | (context, props) => { 8 | const language = context.getStore('PreferencesStore').getLanguage(); 9 | 10 | // eslint-disable-next-line global-require, import/no-dynamic-require 11 | addLocaleData(require(`react-intl/locale-data/${language}`)); 12 | 13 | return { 14 | locale: language, 15 | messages: props.translations[language], 16 | }; 17 | }, 18 | ); 19 | -------------------------------------------------------------------------------- /app/util/emissions.js: -------------------------------------------------------------------------------- 1 | export default function getCo2Value(itinerary) { 2 | return typeof itinerary.emissionsPerPerson?.co2 === 'number' && 3 | itinerary.emissionsPerPerson?.co2 >= 0 4 | ? Math.round(itinerary.emissionsPerPerson?.co2) 5 | : null; 6 | } 7 | -------------------------------------------------------------------------------- /app/util/envUtils.js: -------------------------------------------------------------------------------- 1 | /** Check if application is running in a dev environment. RUN_ENV is defined in kubernetes-deploy for dev instances. For running dev locally, NODE_ENV is checked * */ 2 | export const isDevelopmentEnvironment = config => { 3 | return ( 4 | config?.RUN_ENV === 'development' || process.env.NODE_ENV === 'development' 5 | ); 6 | }; 7 | -------------------------------------------------------------------------------- /app/util/events.js: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'events'; 2 | 3 | const dtEmitter = new EventEmitter(); 4 | export default dtEmitter; 5 | -------------------------------------------------------------------------------- /app/util/filterUtils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Filters object that contains objects so that only objects that have 3 | * a certain key with the correct value defined are returned. 4 | * 5 | * @param {*} obj object to filter 6 | * @param {String} filter key on object's child objects 7 | * @param {*} filterValue the key's intended value 8 | * @returns filtered object 9 | */ 10 | export const filterObject = (obj, filter, filterValue) => 11 | Object.keys(obj).reduce( 12 | (acc, val) => 13 | obj[val][filter] === filterValue 14 | ? { 15 | ...acc, 16 | [val]: obj[val], 17 | } 18 | : acc, 19 | {}, 20 | ); 21 | -------------------------------------------------------------------------------- /app/util/getIterator.js: -------------------------------------------------------------------------------- 1 | function isObject(it) { 2 | return typeof it === 'object' ? it !== null : typeof it === 'function'; 3 | } 4 | 5 | export default function iter(it) { 6 | const iterFn = it[Symbol.iterator]; 7 | if (typeof iterFn !== 'function') { 8 | throw TypeError(`${it} is not iterable!`); 9 | } 10 | if (!isObject(it)) { 11 | throw TypeError(`${it} is not an object!`); 12 | } 13 | return iterFn.call(it); 14 | } 15 | -------------------------------------------------------------------------------- /app/util/gtfs.js: -------------------------------------------------------------------------------- 1 | export const typeToName = { 2 | 0: 'tram', 3 | 1: 'subway', 4 | 2: 'rail', 5 | 3: 'bus', 6 | 4: 'ferry', 7 | 7: 'funicular', 8 | 109: 'rail', 9 | }; 10 | -------------------------------------------------------------------------------- /app/util/hashUtil.js: -------------------------------------------------------------------------------- 1 | import isString from 'lodash/isString'; 2 | 3 | /** 4 | * A simple Java-like hash function for strings. 5 | * 6 | * see: https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/ 7 | * @param {string} str the string to hash. 8 | */ 9 | const hashCode = str => { 10 | if (!str || str.length === 0 || !isString(str)) { 11 | return 0; 12 | } 13 | 14 | let hash = 0; 15 | for (let i = 0; i < str.length; i++) { 16 | const chr = str.charCodeAt(i); 17 | hash = (hash << 5) - hash + chr; // eslint-disable-line no-bitwise 18 | hash |= 0; // eslint-disable-line no-bitwise 19 | } 20 | return hash; 21 | }; 22 | 23 | export default hashCode; 24 | -------------------------------------------------------------------------------- /app/util/patternUtils.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | /** 3 | Helper for determining is current date in active dates. 4 | Return false if pattern doesn't have active dates information available 5 | or if current day is not found in active days 6 | * */ 7 | export const isActiveDate = pattern => { 8 | if (!pattern || !pattern.activeDates) { 9 | return false; 10 | } 11 | 12 | const activeDates = pattern.activeDates.reduce((dates, activeDate) => { 13 | return dates.concat(activeDate.day); 14 | }, []); 15 | const now = moment().format('YYYYMMDD'); 16 | return activeDates.indexOf(now) > -1; 17 | }; 18 | -------------------------------------------------------------------------------- /app/util/publicPath.js: -------------------------------------------------------------------------------- 1 | if (window.ASSET_URL) { 2 | // eslint-disable-next-line camelcase, no-undef 3 | __webpack_public_path__ = window.ASSET_URL; 4 | } 5 | -------------------------------------------------------------------------------- /app/util/relayUtils.js: -------------------------------------------------------------------------------- 1 | export default function isRelayNetworkError(error) { 2 | return ( 3 | typeof error === 'string' && 4 | (error === 5 | 'Server does not return response for request at index 0.\nResponse should have an array with 1 item(s).' || 6 | error.includes('Reached request timeout')) 7 | ); 8 | } 9 | -------------------------------------------------------------------------------- /app/util/safeJsonParser.js: -------------------------------------------------------------------------------- 1 | export default function safeJsonParse(jsonString) { 2 | try { 3 | return JSON.parse(jsonString); 4 | } catch (e) { 5 | return undefined; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/util/scroll.js: -------------------------------------------------------------------------------- 1 | import { isBrowser } from './browser'; 2 | 3 | export default function scrollTop() { 4 | if (isBrowser) { 5 | window.scrollTo(0, 0); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/util/searchRoutes.js: -------------------------------------------------------------------------------- 1 | import { graphql } from 'react-relay'; 2 | 3 | export default graphql` 4 | query searchRoutesQuery($feeds: [String!]!, $name: String) { 5 | viewer { 6 | routes(feeds: $feeds, name: $name) { 7 | gtfsId 8 | agency { 9 | name 10 | } 11 | shortName 12 | mode 13 | longName 14 | patterns { 15 | code 16 | } 17 | } 18 | } 19 | } 20 | `; 21 | -------------------------------------------------------------------------------- /app/util/urlUtils.js: -------------------------------------------------------------------------------- 1 | export default function localizedUrl(object, lang) { 2 | if (!object) { 3 | return null; 4 | } 5 | return object[lang] || object[Object.keys(object)[0]]; 6 | } 7 | -------------------------------------------------------------------------------- /app/util/zoneIconUtils.js: -------------------------------------------------------------------------------- 1 | export default function getZoneId(config, propertiesZones, dataZones) { 2 | function zoneFilter(zones) { 3 | return Array.isArray(zones) 4 | ? zones.filter( 5 | zone => zone && config.feedIds.includes(zone.split(':')[0]), 6 | ) 7 | : []; 8 | } 9 | 10 | const filteredZones = propertiesZones 11 | ? zoneFilter(propertiesZones) 12 | : zoneFilter(dataZones); 13 | const zone = filteredZones.length > 0 ? filteredZones[0] : undefined; 14 | return zone ? zone.split(':')[1] : undefined; 15 | } 16 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | targets: { 7 | node: 'current', 8 | browsers: [], 9 | }, 10 | }, 11 | ], 12 | '@babel/preset-react', 13 | ], 14 | plugins: [ 15 | 'dynamic-import-node', 16 | 'relay', 17 | '@babel/plugin-syntax-dynamic-import', 18 | '@babel/plugin-transform-class-properties', 19 | '@babel/plugin-transform-json-strings', 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-abtesting/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-abtesting/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This package is used to ab test other components 3 | * Use this by importing specific components by name. 4 | * 5 | * Currently unused 6 | */ 7 | export {}; // eslint-disable-line import/prefer-default-export 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-abtesting/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | // import React from 'react'; 3 | // import Adapter from 'enzyme-adapter-react-16'; 4 | // import { expect } from 'chai'; 5 | // import { describe, it } from 'mocha'; 6 | // import { shallow, configure } from 'enzyme'; 7 | 8 | // configure({ adapter: new Adapter() }); 9 | 10 | // describe('Testing something', () => { 11 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-autosuggest-panel/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-autosuggest-panel/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import React from 'react'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import { expect } from 'chai'; 5 | import { describe, it } from 'mocha'; 6 | import { shallow, configure } from 'enzyme'; 7 | import AutosuggestPanel from './src'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe('Testing @digitransit-component/digitransit-component-autosuggest-panel module', () => { 12 | const wrapper = shallow(); 13 | 14 | it('should render', () => { 15 | expect(wrapper.isEmptyRender()).to.equal(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-autosuggest/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-autosuggest/src/helpers/MobileNoScroll.scss: -------------------------------------------------------------------------------- 1 | @import './MobileSearch'; 2 | 3 | .suggestionsContainerOpen { 4 | -ms-overflow-style: none; /* Internet Explorer 10+ */ 5 | scrollbar-width: none; /* Firefox */ 6 | &::-webkit-scrollbar { 7 | display: none; /* Safari and Chrome */ 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-autosuggest/src/helpers/withScrollLock.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import hooks from '@hsl-fi/hooks'; 3 | 4 | const withScrollLock = Component => { 5 | return props => { 6 | const { lock, unlock } = hooks.useScrollLock(); 7 | 8 | return ; 9 | }; 10 | }; 11 | 12 | export default withScrollLock; 13 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-autosuggest/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import React from 'react'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import { expect } from 'chai'; 5 | import { describe, it } from 'mocha'; 6 | import { shallow, configure } from 'enzyme'; 7 | import Autosuggest from './src'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe('Testing @digitransit-component/digitransit-component-autosuggest module', () => { 12 | const wrapper = shallow(); 13 | 14 | it('should render', () => { 15 | expect(wrapper.isEmptyRender()).to.equal(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-control-panel/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-datetimepicker/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-datetimepicker/src/helpers/dateTimeInputIsSupported.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Detect if input type="date" and type="time" are supported in by the browser 3 | * 4 | * @return {boolean} 5 | */ 6 | function dateTimeInputIsSupported() { 7 | if (typeof window === 'undefined' || window === null) { 8 | return false; 9 | } 10 | const elem = document.createElement('input'); 11 | elem.type = 'date'; 12 | if (elem.type !== 'date') { 13 | return false; 14 | } 15 | elem.type = 'time'; 16 | if (elem.type !== 'time') { 17 | return false; 18 | } 19 | return true; 20 | } 21 | 22 | export default dateTimeInputIsSupported; 23 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-datetimepicker/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import React from 'react'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import { expect } from 'chai'; 5 | import { describe, it } from 'mocha'; 6 | import { shallow, configure } from 'enzyme'; 7 | import Datetimepicker from './src'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe('Testing @digitransit-component/digitransit-component-datetimepicker module', () => { 12 | const wrapper = shallow(); 13 | 14 | it('should render', () => { 15 | expect(wrapper.isEmptyRender()).to.equal(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-dialog-modal/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-dialog-modal/src/helpers/translations.js: -------------------------------------------------------------------------------- 1 | const translations = { 2 | de: { 3 | 'close-modal': 'Schließe den Dialog', 4 | }, 5 | en: { 6 | 'close-modal': 'Close the modal', 7 | }, 8 | fi: { 9 | 'close-modal': 'Sulje modaali', 10 | }, 11 | pl: { 12 | 'close-modal': 'Zamknij modal', 13 | }, 14 | sv: { 15 | 'close-modal': 'Stäng modalen', 16 | }, 17 | }; 18 | 19 | export default translations; 20 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-dialog-modal/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import React from 'react'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import { expect } from 'chai'; 5 | import { describe, it } from 'mocha'; 6 | import { shallow, configure } from 'enzyme'; 7 | import DialogModal from './src'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe('Testing @digitransit-component/digitransit-component-dialog-modal module', () => { 12 | const wrapper = shallow(); 13 | 14 | it('should render', () => { 15 | expect(wrapper.isEmptyRender()).to.equal(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-favourite-bar/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-favourite-bar/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import React from 'react'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import { expect } from 'chai'; 5 | import { describe, it } from 'mocha'; 6 | import { shallow, configure } from 'enzyme'; 7 | import FavouriteBar from './src'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe('Testing @digitransit-component/digitransit-component-favourite-bar module', () => { 12 | const wrapper = shallow(); 13 | 14 | it('should render', () => { 15 | expect(wrapper.isEmptyRender()).to.equal(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-favourite-editing-modal/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-favourite-editing-modal/src/helpers/ModalContent.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/click-events-have-key-events */ 2 | import React from 'react'; 3 | import PropTypes from 'prop-types'; 4 | import styles from './modal-content.scss'; 5 | 6 | const ModalContent = ({ headerText, renderList }) => { 7 | return ( 8 |
9 |
10 |
11 | {headerText} 12 |
13 |
14 | {renderList()} 15 |
16 | ); 17 | }; 18 | 19 | ModalContent.propTypes = { 20 | headerText: PropTypes.string.isRequired, 21 | renderList: PropTypes.func.isRequired, 22 | }; 23 | 24 | export default ModalContent; 25 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-favourite-editing-modal/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import React from 'react'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import { expect } from 'chai'; 5 | import { describe, it } from 'mocha'; 6 | import { shallow, configure } from 'enzyme'; 7 | import FavouriteEditingModal from './src'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe('Testing @digitransit-component/digitransit-component-favourite-editing-modal module', () => { 12 | const wrapper = shallow(); 13 | 14 | it('should render', () => { 15 | expect(wrapper.isEmptyRender()).to.equal(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-favourite-modal/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-favourite-modal/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import React from 'react'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import { expect } from 'chai'; 5 | import { describe, it } from 'mocha'; 6 | import { shallow, configure } from 'enzyme'; 7 | import FavouriteModal from './src'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe('Testing @digitransit-component/digitransit-component-favourite-modal module', () => { 12 | const wrapper = shallow(); 13 | 14 | it('should render', () => { 15 | expect(wrapper.isEmptyRender()).to.equal(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/airplane.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/attention.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/caution_white_exclamation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/dropdown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/ellipsis.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/home.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/locate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/mapmarker-via.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/mapmarker.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/mode_airplane.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/place.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/search-airplane-digitransit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/shopping.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/time.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/src/assets/trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-icon/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import React from 'react'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import { expect } from 'chai'; 5 | import { describe, it } from 'mocha'; 6 | import { shallow, configure } from 'enzyme'; 7 | import Icon from './src'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe('Testing @digitransit-component/digitransit-component-icon module', () => { 12 | const wrapper = shallow(); 13 | 14 | it('should render', () => { 15 | expect(wrapper.isEmptyRender()).to.equal(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-suggestion-item/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-suggestion-item/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import React from 'react'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import { expect } from 'chai'; 5 | import { describe, it } from 'mocha'; 6 | import { shallow, configure } from 'enzyme'; 7 | import SuggestionItem from './src'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe('Testing @digitransit-component/digitransit-component-suggestion-item module', () => { 12 | const item = {}; 13 | const content = ['suggestionType', 'label', 'name']; 14 | const wrapper = shallow(); 15 | 16 | it('should render', () => { 17 | expect(wrapper.isEmptyRender()).to.equal(false); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-traffic-now-link/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | 3 | if (process.env.NODE_ENV === 'development') { 4 | module.exports = require('./lib/index.development.js'); 5 | } else { 6 | module.exports = require('./lib/index.js'); 7 | } 8 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-traffic-now-link/src/helpers/styles.scss: -------------------------------------------------------------------------------- 1 | @import '~@hsl-fi/sass/colors'; 2 | @import '~@hsl-fi/sass/mixins/screen'; 3 | @import '~@hsl-fi/sass/mixins/text'; 4 | 5 | .text { 6 | display: flex; 7 | line-height: 1; 8 | font-size: 18px; 9 | padding-left: 15px; 10 | font-weight: var(--font-weight-medium); 11 | letter-spacing: -0.67px; 12 | color: #333; 13 | margin-left: -1px; 14 | 15 | @include min-width(tablet) { 16 | font-size: 20px; 17 | } 18 | } 19 | 20 | .banner { 21 | font-size: 16px; 22 | cursor: pointer; 23 | display: flex; 24 | margin-top: 0; 25 | 26 | @include min-width(tablet) { 27 | padding: 7px 13px 6px 16px; 28 | } 29 | 30 | padding: 6px 13px 6px 16px; 31 | justify-content: space-between; 32 | } 33 | 34 | .caution { 35 | margin-top: 0; 36 | display: flex; 37 | } 38 | 39 | .container { 40 | margin: 0; 41 | } 42 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-traffic-now-link/src/helpers/translations.js: -------------------------------------------------------------------------------- 1 | const translations = { 2 | de: { 3 | traffic: 'Aktuelle Verbindungen', 4 | }, 5 | en: { 6 | traffic: 'Changes and disruptions', 7 | }, 8 | pl: { 9 | traffic: 'Zmiany i zakłócenia', 10 | }, 11 | sv: { 12 | traffic: 'Störningar och ändringar', 13 | }, 14 | fi: { 15 | traffic: 'Häiriöt ja muutokset', 16 | }, 17 | }; 18 | export default translations; 19 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-traffic-now-link/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import React from 'react'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import { expect } from 'chai'; 5 | import { describe, it } from 'mocha'; 6 | import { shallow, configure } from 'enzyme'; 7 | import TrafficNowLink from './src'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe('Testing @digitransit-component/digitransit-component-traffic-now-link module', () => { 12 | const wrapper = shallow(); 13 | 14 | it('should render', () => { 15 | expect(wrapper.isEmptyRender()).to.equal(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /digitransit-component/packages/digitransit-component-with-breakpoint/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import React from 'react'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import { expect } from 'chai'; 5 | import { describe, it } from 'mocha'; 6 | import { shallow, configure } from 'enzyme'; 7 | import WithBreakpoint from './src'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | describe('Testing @digitransit-component/digitransit-component-with-breakpoint module', () => { 12 | const wrapper = shallow(); 13 | 14 | it('should render', () => { 15 | expect(wrapper.isEmptyRender()).to.equal(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /digitransit-component/scripts/installation.md: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | --- 7 | 8 | This module is part of the Digitransit-ui project. It is maintained in the 9 | [HSLdevcom/digitransit-ui](https://github.com/HSLdevcom/digitransit-ui) repository, where you can create 10 | PRs and issues. 11 | 12 | ### Installation 13 | 14 | Install this module individually: 15 | 16 | ```sh 17 | $ npm install {module} 18 | ``` 19 | 20 | Or install the digitransit-component module that includes it as a class: 21 | 22 | ```sh 23 | $ npm install @digitransit-component/digitransit-component 24 | ``` 25 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-distance/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-distance", 3 | "version": "0.0.8", 4 | "description": "digitransit-search-util distance module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-util", 19 | "distance" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)" 23 | } 24 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-distance/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { expect } from 'chai'; 3 | import { describe, it } from 'mocha'; 4 | import distance from '.'; 5 | 6 | describe('Testing @digitransit-util/digitransit-util-distance module', () => { 7 | it('Checking that distance is calculated', () => { 8 | const latlon1 = { 9 | lat: 3, 10 | lon: 2, 11 | }; 12 | const latlon2 = { 13 | lat: 4, 14 | lon: 1, 15 | }; 16 | 17 | const retValue = distance(latlon1, latlon2); 18 | expect(157105.77709637067).to.be.equal(retValue); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-execute-search-immidiate/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { expect } from 'chai'; 3 | import { describe, it } from 'mocha'; 4 | // import executeSearchImmidiate from '.'; 5 | 6 | describe('Testing @digitransit-search-util/digitransit-search-util-execute-search-immidiate module', () => { 7 | it('Checking that true is true', () => { 8 | // const retValue = executeSearchImmidiate(param1, param2); 9 | expect(true).to.be.equal(true); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-filter-matching-to-input/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-filter-matching-to-input", 3 | "version": "0.0.3", 4 | "description": "digitransit-search-util filter-matching-to-input module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-search-util", 19 | "filter-matching-to-input" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)", 23 | "dependencies": { 24 | "lodash": "4.17.21" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-get-geocoding-results/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-get-geocoding-results", 3 | "version": "0.0.8", 4 | "description": "digitransit-search-util get-geocoding-results module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-search-util", 19 | "get-geocoding-results" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)", 23 | "dependencies": { 24 | "@digitransit-search-util/digitransit-search-util-get-json": "0.0.7" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-get-geocoding-results/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { expect } from 'chai'; 3 | import { describe, it } from 'mocha'; 4 | // import getGeocodingResults from '.'; 5 | 6 | describe('Testing @digitransit-search-util/digitransit-search-util-get-geocoding-results module', () => { 7 | it('Checking that true is true', () => { 8 | // TODO: const retValue = getGeocodingResults(param1, param2); 9 | expect(true).to.be.equal(true); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-get-json/index.js: -------------------------------------------------------------------------------- 1 | import serialize from '@digitransit-search-util/digitransit-search-util-serialize'; 2 | /** 3 | * Return Promise for a url json get request 4 | * 5 | * @name getJson 6 | * @param {String} url 7 | * @param {Array} params 8 | * @returns {Object} response 9 | * @example 10 | * digitransit-search-util.getJson(param1, param2); 11 | * //=response 12 | */ 13 | const axios = require('axios').default; 14 | 15 | export default function getJson(url, params) { 16 | return axios 17 | .get( 18 | encodeURI(url) + 19 | (params 20 | ? (url.search(/\?/) === -1 ? '?' : '&') + serialize(params) 21 | : ''), 22 | { 23 | timeout: 10000, 24 | method: 'GET', 25 | 26 | headers: { 27 | Accept: 'application/json', 28 | }, 29 | }, 30 | ) 31 | .then(res => { 32 | return res.data; 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-get-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-get-json", 3 | "version": "0.0.7", 4 | "description": "digitransit-search-util get-json module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-search-util", 19 | "get-json" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)", 23 | "dependencies": { 24 | "@digitransit-search-util/digitransit-search-util-serialize": "0.0.2", 25 | "axios": "1.9.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-get-json/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { expect } from 'chai'; 3 | import { describe, it } from 'mocha'; 4 | import getJson from '.'; 5 | 6 | describe('Testing @digitransit-search-util/digitransit-search-util-get-json module', () => { 7 | it('Checking that null returns empty ', () => { 8 | const retValue = getJson(null, null); 9 | const test = retValue === {}; 10 | expect(test).to.be.equal(false); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-get-label/index.js: -------------------------------------------------------------------------------- 1 | import { getNameLabel } from '@digitransit-search-util/digitransit-search-util-uniq-by-label'; 2 | /** 3 | * Returns label for properties 4 | * 5 | * @name getLabel 6 | * @param {*} properties object 7 | * @returns {Boolean} true/false 8 | */ 9 | export default function getLabel(properties) { 10 | const parts = getNameLabel(properties, true); 11 | switch (properties.layer) { 12 | case 'selectFromMap': 13 | case 'currentPosition': 14 | case 'ownLocations': 15 | case 'back': 16 | return parts[1] || parts[0]; 17 | case 'favouriteVehicleRentalStation': 18 | case 'favouritePlace': 19 | return parts[0]; 20 | default: 21 | return parts.length > 1 && parts[1] !== '' 22 | ? parts.join(', ') 23 | : parts[1] || parts[0]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-get-label/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-get-label", 3 | "version": "1.0.1", 4 | "description": "digitransit-search-util get-label module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-search-util", 19 | "get-label" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)", 23 | "dependencies": { 24 | "@digitransit-search-util/digitransit-search-util-uniq-by-label": "^2.1.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-get-label/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { expect } from 'chai'; 3 | import { describe, it } from 'mocha'; 4 | // eslint-disable-next-line no-unused-vars 5 | import getLabel from '.'; 6 | 7 | describe('Testing @digitransit-search-util/digitransit-search-util-get-label module', () => { 8 | it('Checking that true is true', () => { 9 | // const retValue = getLabel(param1, param2); 10 | expect(true).to.be.equal(true); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-helpers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-helpers", 3 | "version": "2.0.1", 4 | "description": "digitransit-search-util helpers module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-search-util", 19 | "helpers" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)", 23 | "dependencies": { 24 | "@digitransit-search-util/digitransit-search-util-is-duplicate": "2.1.0", 25 | "lodash": "4.17.21" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-helpers/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { expect } from 'chai'; 3 | import { describe, it } from 'mocha'; 4 | import { sortSearchResults } from './index'; 5 | 6 | describe('Testing @digitransit-search-util/digitransit-search-util-helpers module', () => { 7 | it('Checking that sortSearchresults verifies array', () => { 8 | const retValue = sortSearchResults(null, null); 9 | expect(retValue).to.be.equal(null); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-is-duplicate/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-is-duplicate", 3 | "version": "2.1.0", 4 | "description": "digitransit-search-util is-duplicate module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-util", 19 | "is-duplicate" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)", 23 | "dependencies": { 24 | "@digitransit-search-util/digitransit-search-util-tru-eq": "0.0.2" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-query-utils/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | /* eslint-disable import/no-extraneous-dependencies */ 3 | import { expect } from 'chai'; 4 | import { describe, it } from 'mocha'; 5 | // import searchQueryUtils from '.'; 6 | 7 | // describe('Testing @digitransit-search-util/digitransit-search-util-query-utils module', () => { 8 | // it('Checking that true is true', () => { 9 | // //const retValue = searchQueryUtils(param1, param2); 10 | // expect(true).to.be.equal(true); 11 | // }); 12 | // }); 13 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-route-name-compare/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-route-name-compare", 3 | "version": "0.0.2", 4 | "description": "digitransit-search-util route-name-compare module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-search-util", 19 | "route-name-compare" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)" 23 | } 24 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-serialize/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Serializes objects 3 | * 4 | * @name serialize 5 | * @param {Object} obj Object to be serialized 6 | * @param {Any} prefix 7 | * @returns {String} Serialized object 8 | * @example 9 | * digitransit-search-util.serialize(param1, param2); 10 | * //=true 11 | */ 12 | export default function serialize(obj, prefix) { 13 | if (!obj) { 14 | return ''; 15 | } 16 | return Object.keys(obj) 17 | .map(p => { 18 | const k = prefix || p; 19 | const v = obj[p]; 20 | 21 | return typeof v === 'object' 22 | ? serialize(v, k) 23 | : `${encodeURIComponent(k)}=${encodeURIComponent(v)}`; 24 | }) 25 | .join('&'); 26 | } 27 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-serialize/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-serialize", 3 | "version": "0.0.2", 4 | "description": "digitransit-search-util serialize module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-search-util", 19 | "serialize" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)" 23 | } 24 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-serialize/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { expect } from 'chai'; 3 | import { describe, it } from 'mocha'; 4 | import serialize from '.'; 5 | 6 | describe('Testing @digitransit-search-util/digitransit-search-util-serialize module', () => { 7 | it('Checking that null returns empty', () => { 8 | const retValue = serialize(null, 'hello'); 9 | expect('').to.be.equal(retValue); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-suggestion-to-location/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-suggestion-to-location", 3 | "version": "1.0.1", 4 | "description": "digitransit-search-util suggestion-to-location module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-search-util", 19 | "suggestion-to-location" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)", 23 | "dependencies": { 24 | "@digitransit-search-util/digitransit-search-util-get-label": "1.0.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-suggestion-to-location/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { expect } from 'chai'; 3 | import { describe, it } from 'mocha'; 4 | // eslint-disable-next-line no-unused-vars 5 | import suggestionToLocation from '.'; 6 | 7 | describe('Testing @digitransit-search-util/digitransit-search-util-suggestion-to-location module', () => { 8 | it('Checking that true is true', () => { 9 | // const retValue = suggestionToLocation(param1, param2); 10 | expect(true).to.be.equal(true); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-tru-eq/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * accept equality of non nullish values 3 | * 4 | * @name truEq 5 | * @param {Boolean|Number|BigInt|String|Symbol|Object} val1 First value to be compared 6 | * @param {Boolean|Number|BigInt|String|Symbol|Object} param2 Second value to be compared 7 | * @returns {Boolean} true/false 8 | * @example 9 | * digitransit-util.truEq('2', '2'); 10 | * //=true 11 | */ 12 | export default function truEq(val1, val2) { 13 | return val1 && val2 && val1 === val2; 14 | } 15 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-tru-eq/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-tru-eq", 3 | "version": "0.0.2", 4 | "description": "digitransit-search-util tru-eq module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-util", 19 | "tru-eq" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)" 23 | } 24 | -------------------------------------------------------------------------------- /digitransit-search-util/packages/digitransit-search-util-uniq-by-label/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-search-util/digitransit-search-util-uniq-by-label", 3 | "version": "2.1.0", 4 | "description": "digitransit-search-util uniq-by-label module", 5 | "main": "index.js", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "mocha -r esm test.js", 11 | "docs": "node -r esm ../../scripts/generate-readmes" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 16 | }, 17 | "keywords": [ 18 | "digitransit-search-util", 19 | "uniq-by-label" 20 | ], 21 | "author": "Digitransit Authors", 22 | "license": "(AGPL-3.0 OR EUPL-1.2)", 23 | "dependencies": { 24 | "lodash": "4.17.21", 25 | "lodash-es": "4.17.21" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /digitransit-search-util/scripts/installation.md: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | --- 7 | 8 | This module is part of the Digitransit-ui project. It is maintained in the 9 | [HSLdevcom/digitransit-ui](https://github.com/HSLdevcom/digitransit-ui) repository, where you can create 10 | PRs and issues. 11 | 12 | ### Installation 13 | 14 | Install this module individually: 15 | 16 | ```sh 17 | $ npm install {module} 18 | ``` 19 | 20 | Or install the digitransit-search-util module that includes it as a function: 21 | 22 | ```sh 23 | $ npm install @digitransit-search-util/digitransit-search-util 24 | ``` 25 | -------------------------------------------------------------------------------- /digitransit-store/packages/digitransit-store-common-functions/mock-localstorage.js: -------------------------------------------------------------------------------- 1 | import 'mock-local-storage'; 2 | 3 | global.window = {}; 4 | window.localStorage = global.localStorage; 5 | -------------------------------------------------------------------------------- /digitransit-store/packages/digitransit-store-future-route/mock-localstorage.js: -------------------------------------------------------------------------------- 1 | import 'mock-local-storage'; 2 | 3 | global.window = {}; 4 | window.localStorage = global.localStorage; 5 | -------------------------------------------------------------------------------- /digitransit-store/scripts/installation.md: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | --- 7 | 8 | This module is part of the Digitransit-ui project. It is maintained in the 9 | [HSLdevcom/digitransit-ui](https://github.com/HSLdevcom/digitransit-ui) repository, where you can create 10 | PRs and issues. 11 | 12 | ### Installation 13 | 14 | Install this module individually: 15 | 16 | ```sh 17 | $ npm install {module} 18 | ``` 19 | 20 | Or install the Digitransit-store module that includes it as a function: 21 | 22 | ```sh 23 | $ npm install @digitransit-store/digitransit-store 24 | ``` 25 | -------------------------------------------------------------------------------- /digitransit-util/packages/digitransit-util-day-range-allowed-diff/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | # 1.1.0 (2020-03-06) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * setting initial version 0.0.1 ([8a3d681](https://github.com/HSLdevcom/digitransit-ui/commit/8a3d681c894950dbac949fbb71dd4ff583a05554)) 11 | * typo, added repository and lerna commands ([045d08e](https://github.com/HSLdevcom/digitransit-ui/commit/045d08eeae734da913a81052eee7ebaab4994fbc)) 12 | * version numbers and length of undefenined ([f650d5e](https://github.com/HSLdevcom/digitransit-ui/commit/f650d5e23084622c1042fec9736d24c5c02a9758)) 13 | 14 | 15 | ### Features 16 | 17 | * initial version ([c57ff7c](https://github.com/HSLdevcom/digitransit-ui/commit/c57ff7c469e9618881e281167b06e28f081ed830)) 18 | -------------------------------------------------------------------------------- /digitransit-util/packages/digitransit-util-day-range-allowed-diff/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-util/digitransit-util-day-range-allowed-diff", 3 | "version": "1.0.4", 4 | "description": "digitransit-util digitransit-util-day-range-allowed-diff module", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha -r esm test.js", 8 | "docs": "node -r esm ../../scripts/generate-readmes" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 13 | }, 14 | "keywords": [ 15 | "digitransit-util", 16 | "dayRangeAllowedDiff" 17 | ], 18 | "author": "Digitransit Authors", 19 | "license": "(AGPL-3.0 OR EUPL-1.2)" 20 | } 21 | -------------------------------------------------------------------------------- /digitransit-util/packages/digitransit-util-day-range-pattern/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | # 1.1.0 (2020-03-06) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * setting initial version 0.0.1 ([8a3d681](https://github.com/HSLdevcom/digitransit-ui/commit/8a3d681c894950dbac949fbb71dd4ff583a05554)) 11 | * typo and create-new-module ([ac64af7](https://github.com/HSLdevcom/digitransit-ui/commit/ac64af76d20f99e77aad58c797098c57678b00ea)) 12 | * typo, added repository and lerna commands ([045d08e](https://github.com/HSLdevcom/digitransit-ui/commit/045d08eeae734da913a81052eee7ebaab4994fbc)) 13 | * version numbers and length of undefenined ([f650d5e](https://github.com/HSLdevcom/digitransit-ui/commit/f650d5e23084622c1042fec9736d24c5c02a9758)) 14 | 15 | 16 | ### Features 17 | 18 | * initial version ([c57ff7c](https://github.com/HSLdevcom/digitransit-ui/commit/c57ff7c469e9618881e281167b06e28f081ed830)) 19 | -------------------------------------------------------------------------------- /digitransit-util/packages/digitransit-util-day-range-pattern/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-util/digitransit-util-day-range-pattern", 3 | "version": "1.1.0", 4 | "description": "digitransit-util digitransit-util-day-range-pattern module", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha -r esm test.js", 8 | "docs": "node -r esm ../../scripts/generate-readmes" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 13 | }, 14 | "keywords": [ 15 | "digitransit-util", 16 | "dayRangePattern" 17 | ], 18 | "author": "Digitransit Authors", 19 | "license": "(AGPL-3.0 OR EUPL-1.2)" 20 | } 21 | -------------------------------------------------------------------------------- /digitransit-util/packages/digitransit-util-enrich-patterns/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | # 1.1.0 (2020-03-06) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * setting initial version 0.0.1 ([8a3d681](https://github.com/HSLdevcom/digitransit-ui/commit/8a3d681c894950dbac949fbb71dd4ff583a05554)) 11 | * typo, added repository and lerna commands ([045d08e](https://github.com/HSLdevcom/digitransit-ui/commit/045d08eeae734da913a81052eee7ebaab4994fbc)) 12 | * version numbers and length of undefenined ([f650d5e](https://github.com/HSLdevcom/digitransit-ui/commit/f650d5e23084622c1042fec9736d24c5c02a9758)) 13 | 14 | 15 | ### Features 16 | 17 | * initial version ([c57ff7c](https://github.com/HSLdevcom/digitransit-ui/commit/c57ff7c469e9618881e281167b06e28f081ed830)) 18 | -------------------------------------------------------------------------------- /digitransit-util/packages/digitransit-util-enrich-patterns/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-util/digitransit-util-enrich-patterns", 3 | "version": "1.1.3", 4 | "description": "digitransit-util enrich-patterns module", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha -r esm test.js", 8 | "docs": "node -r esm ../../scripts/generate-readmes" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 13 | }, 14 | "keywords": [ 15 | "digitransit-util", 16 | "enrichPatterns" 17 | ], 18 | "author": "Digitransit Authors", 19 | "license": "(AGPL-3.0 OR EUPL-1.2)", 20 | "dependencies": { 21 | "@digitransit-util/digitransit-util-day-range-allowed-diff": "^1.0.4", 22 | "@digitransit-util/digitransit-util-day-range-pattern": "^1.1.0" 23 | }, 24 | "peerDependencies": { 25 | "lodash": "4.17.21", 26 | "lodash-es": "4.17.21" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /digitransit-util/packages/digitransit-util-route-pattern-option-text/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-util/digitransit-util-route-pattern-option-text", 3 | "version": "1.1.3", 4 | "description": "digitransit-util route-pattern-option-text module", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha -r esm test.js", 8 | "docs": "node -r esm ../../scripts/generate-readmes" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/HSLdevcom/digitransit-ui.git" 13 | }, 14 | "keywords": [ 15 | "digitransit-util", 16 | "routePatternOptionText" 17 | ], 18 | "author": "Digitransit Authors", 19 | "license": "(AGPL-3.0 OR EUPL-1.2)", 20 | "peerDependencies": { 21 | "i18next": "^19.2.0", 22 | "i18next-xhr-backend": "^3.2.2", 23 | "lodash": "4.17.21", 24 | "lodash-es": "4.17.21" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /digitransit-util/packages/digitransit-util/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | # 1.1.0 (2020-03-06) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * missing .name from stop[x] ([47e76bf](https://github.com/HSLdevcom/digitransit-ui/commit/47e76bf87381ef4704518601d396b85abc355c3c)) 11 | * setting initial version 0.0.1 ([8a3d681](https://github.com/HSLdevcom/digitransit-ui/commit/8a3d681c894950dbac949fbb71dd4ff583a05554)) 12 | * typo, added repository and lerna commands ([045d08e](https://github.com/HSLdevcom/digitransit-ui/commit/045d08eeae734da913a81052eee7ebaab4994fbc)) 13 | * version numbers and length of undefenined ([f650d5e](https://github.com/HSLdevcom/digitransit-ui/commit/f650d5e23084622c1042fec9736d24c5c02a9758)) 14 | 15 | 16 | ### Features 17 | 18 | * initial version ([c57ff7c](https://github.com/HSLdevcom/digitransit-ui/commit/c57ff7c469e9618881e281167b06e28f081ed830)) 19 | -------------------------------------------------------------------------------- /digitransit-util/packages/digitransit-util/index.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Digitransit-util is a util library for digitransit-ui written in JavaScript. 3 | * 4 | * @module digitransit-util 5 | * @summary Util library for Digitransit-ui 6 | */ 7 | export { default as dayRangeAllowedDiff } from '@digitransit-util/digitransit-util-day-range-allowed-diff'; 8 | export { default as dayRangePattern } from '@digitransit-util/digitransit-util-day-range-pattern'; 9 | export { default as enrichPatterns } from '@digitransit-util/digitransit-util-enrich-patterns'; 10 | export { default as routePatternOptionText } from '@digitransit-util/digitransit-util-route-pattern-option-text'; 11 | -------------------------------------------------------------------------------- /digitransit-util/packages/digitransit-util/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@digitransit-util/digitransit-util", 3 | "version": "1.0.6", 4 | "description": "a JavaScript library for Digitransit", 5 | "main": "digitransit-util", 6 | "module": "digitransit-util.mjs", 7 | "keywords": [ 8 | "digitransit-util" 9 | ], 10 | "author": "Digitransit Authors", 11 | "license": "(AGPL-3.0 OR EUPL-1.2)", 12 | "scripts": { 13 | "test": "mocha -r esm test.js", 14 | "docs": "node -r esm ../../scripts/generate-readmes" 15 | }, 16 | "dependencies": { 17 | "@digitransit-util/digitransit-util-day-range-allowed-diff": "^1.0.4", 18 | "@digitransit-util/digitransit-util-day-range-pattern": "^1.1.0", 19 | "@digitransit-util/digitransit-util-enrich-patterns": "^1.1.3", 20 | "@digitransit-util/digitransit-util-route-pattern-option-text": "^1.1.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /digitransit-util/scripts/installation.md: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | --- 7 | 8 | This module is part of the Digitransit-ui project. It is maintained in the 9 | [HSLdevcom/digitransit-ui](https://github.com/HSLdevcom/digitransit-ui) repository, where you can create 10 | PRs and issues. 11 | 12 | ### Installation 13 | 14 | Install this module individually: 15 | 16 | ```sh 17 | $ npm install {module} 18 | ``` 19 | 20 | Or install the Digitransit-util module that includes it as a function: 21 | 22 | ```sh 23 | $ npm install @digitransit-util/digitransit-util 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/GraphQL.md: -------------------------------------------------------------------------------- 1 | - If the data schema available from the OTP backend changes 2 | (for example if new query types are added), 3 | you need to regenerate the schema (schema.graphql) by running 4 | `cd build; node generate-schema.js` 5 | 6 | If you need to fetch the schema from some non-default location, `SCHEMA_SRC` changes 7 | the URL or filepath for the schema file in graphls format: 8 | 9 | `cd build; SCHEMA_SRC=where-schema-file-is-located node generate-schema.js` 10 | 11 | When copying from a local OTP clone, usually something like this works: 12 | 13 | `cd build; SCHEMA_SRC=~/OpenTripPlanner/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls node generate-schema.js` 14 | -------------------------------------------------------------------------------- /docs/Location.md: -------------------------------------------------------------------------------- 1 | Location has two functions. Firstly, it marks routing start and stop location and possibly a routing via point. Secondly, from location can be used for nearby stop search. 2 | 3 | ![Location](https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/master/docs/images/location.png) 4 | 5 | |State|Description| 6 | |--------|-------| 7 | |**No location**|We have no location information set| 8 | |**From Location set**|User's from location is set| 9 | |**To Location set**|User's to location is set| 10 | |**Route set**|Both from and to locations are set| 11 | |**Route via point set**|Both from and to locations are set and also a route via point| 12 | -------------------------------------------------------------------------------- /docs/Terms.md: -------------------------------------------------------------------------------- 1 | |Term|Explanation| 2 | |--------|-------| 3 | |**Position**|User's position received through HTML5 geolocation interface| 4 | |**Location**|User's given value for position. Used for finding services near to defined location, e.g. nearest stops or routing. "route start location"| 5 | 6 | -------------------------------------------------------------------------------- /docs/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/docs/images/architecture.png -------------------------------------------------------------------------------- /docs/images/hierarchy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/docs/images/hierarchy.png -------------------------------------------------------------------------------- /docs/images/location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/docs/images/location.png -------------------------------------------------------------------------------- /docs/images/position.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/docs/images/position.png -------------------------------------------------------------------------------- /docs/images/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/docs/images/up.png -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "digitransit-util/packages/*", 4 | "digitransit-search-util/packages/*", 5 | "digitransit-component/packages/*", 6 | "digitransit-store/packages/*" 7 | ], 8 | "version": "independent", 9 | "npmClient": "yarn", 10 | "useWorkspaces": true, 11 | "command": { 12 | "publish": { 13 | "conventionalCommits": false 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ env }) => ({ 2 | plugins: 3 | env === 'production' ? ['postcss-flexbugs-fixes', 'autoprefixer'] : [], 4 | }); 5 | -------------------------------------------------------------------------------- /sass/base/_button.scss: -------------------------------------------------------------------------------- 1 | button { 2 | border: 0; 3 | margin: 0; 4 | padding: 0; 5 | font-size: 100%; 6 | background: none; 7 | border-style: none; 8 | border-width: 0; 9 | cursor: pointer; 10 | font-family: $button-font-family; 11 | position: relative; 12 | background-color: transparent; 13 | transition: none; 14 | display: inline-block; 15 | text-decoration: none; 16 | font-weight: inherit; 17 | appearance: none; 18 | color: inherit; 19 | 20 | &:focus { 21 | background-color: transparent; 22 | color: inherit; 23 | } 24 | 25 | &:active { 26 | background-color: transparent; 27 | color: inherit; 28 | } 29 | 30 | &:hover { 31 | background-color: transparent; 32 | color: inherit; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sass/base/_helper-mixins.scss: -------------------------------------------------------------------------------- 1 | /* Using these avoids making mistakes when some font settings are inherited 2 | from a parent using different font-family. */ 3 | 4 | @mixin font-book { 5 | font-family: $font-family; 6 | font-weight: $font-weight-book; 7 | letter-spacing: $letter-spacing; 8 | } 9 | 10 | @mixin font-medium { 11 | font-family: $font-family; 12 | font-weight: $font-weight-medium; 13 | letter-spacing: $letter-spacing; 14 | } 15 | 16 | @mixin font-map-container { 17 | font-family: $font-family; 18 | font-weight: $font-weight-map-container; 19 | letter-spacing: $letter-spacing; 20 | } 21 | 22 | @mixin font-narrow-book { 23 | font-family: $font-family-narrow; 24 | font-weight: $font-narrow-weight-book; 25 | letter-spacing: $narrow-letter-spacing; 26 | } 27 | 28 | @mixin font-narrow-medium { 29 | font-family: $font-family-narrow; 30 | font-weight: $font-narrow-weight-medium; 31 | letter-spacing: $narrow-letter-spacing; 32 | } 33 | -------------------------------------------------------------------------------- /sass/base/_radius.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --radius-s: 4px; 3 | --radius-m: 8px; 4 | --radius-l: 16px; 5 | --radius-xl: 24px; 6 | --radius-pill: 999px; 7 | } 8 | -------------------------------------------------------------------------------- /sass/base/_waltti.scss: -------------------------------------------------------------------------------- 1 | /* waltti 'virtual' base theme */ 2 | 3 | @import '../themes/default/theme'; 4 | 5 | /* Component palette */ 6 | $standalone-btn-hover-color: $gray; 7 | $standalone-btn-active-color: $gray; 8 | -------------------------------------------------------------------------------- /sass/base/_zindex.scss: -------------------------------------------------------------------------------- 1 | $zindex: base, map-container, map-gradient, map-fullscreen-toggle, map-buttons, 2 | mobile-drawer, mobile-drawer-drag-line, context-panel, search-panel, 3 | search-overlay, stop-route-station-input, destination-input, viapoint-input-5, 4 | viapoint-input-4, viapoint-input-3, viapoint-input-2, viapoint-input-1, 5 | origin-input, search-input-focus, search-input-icon, 6 | autosuggest-suggestion-container, before-scrollable-area, 7 | click-prevent-overlay, front; 8 | $leaflet-overlay: 800; 9 | -------------------------------------------------------------------------------- /sass/themes/default/default-spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/sass/themes/default/default-spinner.png -------------------------------------------------------------------------------- /sass/themes/default/main.scss: -------------------------------------------------------------------------------- 1 | /* Theme */ 2 | @import 'theme'; 3 | @import '../../main'; 4 | -------------------------------------------------------------------------------- /sass/themes/hameenlinna/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: rgb(196, 40, 31); 5 | $secondary-color: darken($primary-color, 20%); 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $primary-color; 12 | 13 | /* Component palette */ 14 | $desktop-title-color: $primary-color; 15 | $desktop-title-arrow-icon-color: $secondary-color; 16 | $link-color: $primary-color; 17 | $top-bar-color: rgb(236, 236, 236); 18 | 19 | /* Navbar dimensions */ 20 | $nav-logo-height: 3em; 21 | -------------------------------------------------------------------------------- /sass/themes/hameenlinna/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/hsl/hsl-spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/sass/themes/hsl/hsl-spinner.png -------------------------------------------------------------------------------- /sass/themes/hsl/main.scss: -------------------------------------------------------------------------------- 1 | /* Theme */ 2 | @import 'theme'; 3 | @import '../../main'; 4 | -------------------------------------------------------------------------------- /sass/themes/joensuu/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/jyvaskyla/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #7dc02d; 5 | $secondary-color: #489227; 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $secondary-color; 12 | $link-color: $primary-color; 13 | 14 | /* Component palette */ 15 | $desktop-title-color: $primary-color; 16 | $desktop-title-arrow-icon-color: $secondary-color; 17 | $top-bar-color: $primary-color; 18 | -------------------------------------------------------------------------------- /sass/themes/jyvaskyla/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/kela/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #003580; 5 | $secondary-color: darken($primary-color, 20%); 6 | $hilight-color: rgb(253, 185, 19); 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $primary-color; 12 | $link-color: $primary-color; 13 | 14 | /* Component palette */ 15 | $desktop-title-color: $primary-color; 16 | $desktop-title-arrow-icon-color: $secondary-color; 17 | $top-bar-color: #003580; 18 | -------------------------------------------------------------------------------- /sass/themes/kela/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/kotka/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #0001ff; 5 | $secondary-color: darken($primary-color, 20%); 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $primary-color; 12 | $link-color: $primary-color; 13 | 14 | /* Component palette */ 15 | $desktop-title-color: $primary-color; 16 | $desktop-title-arrow-icon-color: $secondary-color; 17 | $top-bar-color: rgb(130, 189, 83); 18 | -------------------------------------------------------------------------------- /sass/themes/kotka/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/kouvola/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #000; 5 | $secondary-color: darken($primary-color, 20%); 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $primary-color; 12 | $link-color: $primary-color; 13 | 14 | /* Component palette */ 15 | $desktop-title-color: $primary-color; 16 | $desktop-title-arrow-icon-color: $secondary-color; 17 | $top-bar-color: $primary-color; 18 | -------------------------------------------------------------------------------- /sass/themes/kouvola/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/kuopio/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #0ab1c8; 5 | $secondary-color: #724f9f; 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $secondary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $secondary-color; 11 | $standalone-btn-color: $primary-color; 12 | $link-color: $primary-color; 13 | $rail-color: #0e7f3c; 14 | 15 | /* Component palette */ 16 | $desktop-title-color: $primary-color; 17 | $desktop-title-arrow-icon-color: $secondary-color; 18 | $top-bar-color: $primary-color; 19 | -------------------------------------------------------------------------------- /sass/themes/kuopio/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/lahti/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #0066b3; 5 | $secondary-color: darken($primary-color, 20%); 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $primary-color; 12 | $link-color: $primary-color; 13 | 14 | /* Component palette */ 15 | $desktop-title-color: $primary-color; 16 | $desktop-title-arrow-icon-color: $secondary-color; 17 | $top-bar-color: $primary-color; 18 | -------------------------------------------------------------------------------- /sass/themes/lahti/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/lappeenranta/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #d4007a; 5 | $secondary-color: #3c974c; 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $primary-color; 12 | $standalone-btn-hover-color: $secondary-color; 13 | $standalone-btn-active-color: $secondary-color; 14 | $link-color: $primary-color; 15 | 16 | /* Component palette */ 17 | $desktop-title-color: $primary-color; 18 | $desktop-title-arrow-icon-color: $secondary-color; 19 | $top-bar-color: $primary-color; 20 | 21 | /* Navbar dimensions */ 22 | $nav-logo-height: 4.5em; 23 | -------------------------------------------------------------------------------- /sass/themes/lappeenranta/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/matka/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/mikkeli/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #167cac; 5 | $secondary-color: darken($primary-color, 20%); 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $primary-color; 12 | $link-color: $primary-color; 13 | 14 | /* Component palette */ 15 | $desktop-title-color: $primary-color; 16 | $desktop-title-arrow-icon-color: $secondary-color; 17 | $top-bar-color: $primary-color; 18 | $nav-content-color: #fff; 19 | -------------------------------------------------------------------------------- /sass/themes/mikkeli/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/oulu/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $ouluColor: #e10669; 5 | $primary-color: $ouluColor; 6 | $secondary-color: darken($primary-color, 20%); 7 | $hilight-color: $ouluColor; 8 | $action-color: $ouluColor; 9 | $bus-color: $ouluColor; 10 | $viewpoint-marker-color: $ouluColor; 11 | $current-location-color: $primary-color; 12 | $standalone-btn-color: $primary-color; 13 | $link-color: $primary-color; 14 | $banner-disruption-color: rgb(24, 59, 224); 15 | 16 | /* Component palette */ 17 | $desktop-title-color: $primary-color; 18 | $desktop-title-arrow-icon-color: $secondary-color; 19 | $top-bar-color: $primary-color; 20 | -------------------------------------------------------------------------------- /sass/themes/oulu/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/pori/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $poriColor: #1f1f66; 5 | $primary-color: $poriColor; 6 | $secondary-color: darken($primary-color, 20%); 7 | $hilight-color: $poriColor; 8 | $action-color: $poriColor; 9 | $bus-color: $poriColor; 10 | $viewpoint-marker-color: $poriColor; 11 | $current-location-color: $primary-color; 12 | $standalone-btn-color: $primary-color; 13 | $link-color: $primary-color; 14 | 15 | /* Component palette */ 16 | $desktop-title-color: $primary-color; 17 | $desktop-title-arrow-icon-color: $secondary-color; 18 | $top-bar-color: $primary-color; 19 | -------------------------------------------------------------------------------- /sass/themes/pori/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/raasepori/_theme.scss: -------------------------------------------------------------------------------- 1 | /* Raasepori theme */ 2 | 3 | /* Base theme */ 4 | @import '../../base/waltti'; 5 | 6 | /* Operator palette */ 7 | $raasepori-green: #5b7b32; 8 | 9 | /* Application palette */ 10 | $primary-color: $raasepori-green; 11 | $favourite-color: $raasepori-green; 12 | $current-location-color: $primary-color; 13 | 14 | /* Component palette */ 15 | $viewpoint-marker-color: $raasepori-green; 16 | $link-color: $primary-color; 17 | $desktop-title-color: $primary-color; 18 | $top-bar-color: $primary-color; 19 | $top-navigation-icon-color: white; 20 | 21 | /* Vehicle palette */ 22 | $bus-color: $raasepori-green; 23 | 24 | /* Navbar dimensions */ 25 | $nav-logo-height: 3em; 26 | -------------------------------------------------------------------------------- /sass/themes/raasepori/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/rovaniemi/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #34b233; 5 | $secondary-color: darken($primary-color, 20%); 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $primary-color; 12 | $link-color: $primary-color; 13 | 14 | /* Component palette */ 15 | $desktop-title-color: $primary-color; 16 | $desktop-title-arrow-icon-color: $secondary-color; 17 | $top-bar-color: $primary-color; 18 | -------------------------------------------------------------------------------- /sass/themes/rovaniemi/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/tampere/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #1c57cf; 5 | $secondary-color: darken($primary-color, 20%); 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: #1a4a8f; 9 | $tram-color: #da2128; 10 | $rail-color: #0e7f3c; 11 | $viewpoint-marker-color: $primary-color; 12 | $current-location-color: $primary-color; 13 | $selected-lang-background: #1a4a8f; 14 | 15 | /* Component palette */ 16 | 17 | $standalone-btn-color: $primary-color; 18 | $link-color: $primary-color; 19 | $desktop-title-color: #40ba54; 20 | $desktop-title-arrow-icon-color: $white; 21 | $caution-icon-color: #ec5e47; 22 | $caution-icon-font-color: $white; 23 | $top-bar-color: $primary-color; 24 | 25 | /* Navbar dimensions */ 26 | $nav-logo-height: 2.5em; 27 | -------------------------------------------------------------------------------- /sass/themes/tampere/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/turku/foli-spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/sass/themes/turku/foli-spinner.png -------------------------------------------------------------------------------- /sass/themes/turku/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/vaasa/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #000a8c; 5 | $secondary-color: #0096aa; 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $primary-color; 12 | $link-color: $primary-color; 13 | 14 | /* Component palette */ 15 | $desktop-title-color: $primary-color; 16 | $desktop-title-arrow-icon-color: $secondary-color; 17 | $top-bar-color: $primary-color; 18 | -------------------------------------------------------------------------------- /sass/themes/vaasa/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/varely/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #008161; 5 | $secondary-color: #00bf6f; 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $primary-color; 12 | $link-color: $primary-color; 13 | 14 | /* Component palette */ 15 | $desktop-title-color: $primary-color; 16 | $desktop-title-arrow-icon-color: $white; 17 | $link-color: $primary-color; 18 | $top-bar-color: #008061; 19 | -------------------------------------------------------------------------------- /sass/themes/varely/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /sass/themes/walttiOpas/_theme.scss: -------------------------------------------------------------------------------- 1 | @import '../../base/waltti'; 2 | 3 | /* main theme colors */ 4 | $primary-color: #5959a8; 5 | $secondary-color: #17083b; 6 | $hilight-color: $primary-color; 7 | $action-color: $primary-color; 8 | $bus-color: $primary-color; 9 | $viewpoint-marker-color: $primary-color; 10 | $current-location-color: $primary-color; 11 | $standalone-btn-color: $primary-color; 12 | $link-color: $primary-color; 13 | 14 | /* Component palette */ 15 | $desktop-title-color: $primary-color; 16 | $desktop-title-arrow-icon-color: $secondary-color; 17 | $top-bar-color: $secondary-color; 18 | -------------------------------------------------------------------------------- /sass/themes/walttiOpas/main.scss: -------------------------------------------------------------------------------- 1 | @import 'theme'; 2 | @import '../../main'; 3 | -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | # Using scripts 2 | 3 | See the `themeMap` in `app/configurations/config.default.js` for configuration options. 4 | 5 | ## Before using 6 | ``` 7 | source ui.sh 8 | ``` 9 | ## Usage examples 10 | 11 | Using remote instance of OTP with subscription key: 12 | ``` 13 | SUBSCRIPTION_KEY= ui hsl 14 | ``` 15 | Using local instance of OTP on port `9080`: 16 | ``` 17 | SUBSCRIPTION_KEY= uiotp matka 18 | ``` 19 | In case you do not need features usable with a subscription key when running a local instance of OTP on port `9080`: 20 | ``` 21 | NO_SUBSCRIPTION_KEY=true uiotp matka 22 | ``` 23 | -------------------------------------------------------------------------------- /scripts/ui.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # See the themeMap in app/configurations/config.default.js for configuration options. 4 | 5 | ui () { 6 | if [ "$SUBSCRIPTION_KEY" = "" -a "$NO_SUBSCRIPTION_KEY" != "true" ]; then 7 | echo "In order to use the UI you need to set the SUBSCRIPTION_KEY environment variable." 8 | echo "If you want to run the UI without a subscription key, set NO_SUBSCRIPTION_KEY=true." 9 | return 1 2>/dev/null 10 | fi 11 | CONFIG=$1 API_SUBSCRIPTION_QUERY_PARAMETER_NAME=digitransit-subscription-key API_SUBSCRIPTION_HEADER_NAME=digitransit-subscription-key API_SUBSCRIPTION_TOKEN=$SUBSCRIPTION_KEY yarn run dev 12 | } 13 | 14 | uiotp () { 15 | OTP_URL=http://localhost:9080/otp/ ui $1 16 | } 17 | -------------------------------------------------------------------------------- /server/passport-openid-connect/User.js: -------------------------------------------------------------------------------- 1 | class User { 2 | constructor(data) { 3 | this.data = data; 4 | } 5 | 6 | serialize() { 7 | const x = { 8 | data: this.data, 9 | }; 10 | if (this.token) { 11 | x.token = this.token; 12 | } 13 | if (this.idtoken) { 14 | x.idtoken = this.idtoken; 15 | } 16 | return x; 17 | } 18 | 19 | static unserialize(obj) { 20 | const u = new User(obj.data); 21 | if (obj.token) { 22 | u.token = obj.token; 23 | } 24 | if (obj.idtoken) { 25 | u.idtoken = obj.idtoken; 26 | } 27 | return u; 28 | } 29 | } 30 | 31 | exports.User = User; 32 | -------------------------------------------------------------------------------- /server/proxyTester.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | const express = require('express'); 3 | const proxy = require('express-http-proxy'); 4 | 5 | const app = express(); 6 | 7 | const port = 9000; 8 | 9 | app.use('/proxy', proxy('http://localhost:8080/')); 10 | 11 | const server = app.listen(port, () => 12 | console.log('Digitransit-ui available on port %d', server.address().port), 13 | ); 14 | 15 | /* 16 | This file enables toy to test CDN functionality locally by starting with 17 | node server/proxyTester.js && \ 18 | ASSET_URL="http://localhost:9000/proxy" yarn run start 19 | */ 20 | -------------------------------------------------------------------------------- /server/swInjection.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef, no-restricted-syntax */ 2 | __wpo.assets.main = __wpo.assets.main.map(asset => 3 | __wpo.externals.includes(asset) ? asset : `ASSET_URL${asset}`, 4 | ); 5 | __wpo.assets.additional = __wpo.assets.additional.map(asset => 6 | __wpo.externals.includes(asset) ? asset : `ASSET_URL${asset}`, 7 | ); 8 | __wpo.assets.optional = __wpo.assets.optional.map(asset => 9 | __wpo.externals.includes(asset) ? asset : `ASSET_URL${asset}`, 10 | ); 11 | for (const key in __wpo.hashesMap) { 12 | if (!__wpo.externals.includes(__wpo.hashesMap[key])) { 13 | __wpo.hashesMap[key] = `ASSET_URL${__wpo.hashesMap[key]}`; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /static/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/static/favicon.ico -------------------------------------------------------------------------------- /static/img/default-social-share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/static/img/default-social-share.png -------------------------------------------------------------------------------- /static/img/hsl-social-share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/static/img/hsl-social-share.png -------------------------------------------------------------------------------- /static/img/nearby-stop_animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/static/img/nearby-stop_animation.gif -------------------------------------------------------------------------------- /static/img/nearby-stop_desktop-animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/static/img/nearby-stop_desktop-animation.gif -------------------------------------------------------------------------------- /static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/hsl/front-page-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/hsl/front-page-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/hsl/front-page-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/hsl/front-page-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/hsl/itinerary-details-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/hsl/itinerary-details-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/hsl/itinerary-details-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/hsl/itinerary-details-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/hsl/itinerary-suggestions-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/hsl/itinerary-suggestions-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/hsl/itinerary-suggestions-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/hsl/itinerary-suggestions-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/hsl/route-page-stop-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/hsl/route-page-stop-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/hsl/route-page-stop-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/hsl/route-page-stop-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/hsl/stop-page-departure-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/hsl/stop-page-departure-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/hsl/stop-page-departure-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/hsl/stop-page-departure-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/matka/front-page-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/matka/front-page-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/matka/front-page-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/matka/front-page-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/matka/itinerary-details-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/matka/itinerary-details-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/matka/itinerary-details-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/matka/itinerary-details-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/matka/itinerary-suggestions-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/matka/itinerary-suggestions-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/matka/itinerary-suggestions-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/matka/itinerary-suggestions-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/matka/route-page-stop-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/matka/route-page-stop-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/matka/route-page-stop-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/matka/route-page-stop-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/matka/stop-page-departure-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/matka/stop-page-departure-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/matka/stop-page-departure-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/matka/stop-page-departure-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/tampere/front-page-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/tampere/front-page-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/tampere/front-page-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/tampere/front-page-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/tampere/itinerary-details-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/tampere/itinerary-details-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/tampere/itinerary-details-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/tampere/itinerary-details-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/tampere/itinerary-suggestions-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/tampere/itinerary-suggestions-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/tampere/itinerary-suggestions-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/tampere/itinerary-suggestions-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/tampere/route-page-stop-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/tampere/route-page-stop-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/tampere/route-page-stop-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/tampere/route-page-stop-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/tampere/stop-page-departure-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/tampere/stop-page-departure-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/chromium/tampere/stop-page-departure-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/chromium/tampere/stop-page-departure-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/hsl/front-page-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/hsl/front-page-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/hsl/itinerary-details-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/hsl/itinerary-details-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/hsl/itinerary-suggestions-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/hsl/itinerary-suggestions-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/hsl/route-page-stop-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/hsl/route-page-stop-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/hsl/stop-page-departure-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/hsl/stop-page-departure-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/matka/front-page-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/matka/front-page-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/matka/itinerary-details-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/matka/itinerary-details-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/matka/itinerary-suggestions-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/matka/itinerary-suggestions-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/matka/route-page-stop-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/matka/route-page-stop-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/matka/stop-page-departure-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/matka/stop-page-departure-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/tampere/front-page-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/tampere/front-page-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/tampere/itinerary-details-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/tampere/itinerary-details-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/tampere/itinerary-suggestions-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/tampere/itinerary-suggestions-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/tampere/route-page-stop-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/tampere/route-page-stop-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/firefox/tampere/stop-page-departure-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/firefox/tampere/stop-page-departure-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/hsl/front-page-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/hsl/front-page-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/hsl/front-page-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/hsl/front-page-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/hsl/itinerary-details-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/hsl/itinerary-details-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/hsl/itinerary-details-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/hsl/itinerary-details-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/hsl/itinerary-suggestions-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/hsl/itinerary-suggestions-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/hsl/itinerary-suggestions-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/hsl/itinerary-suggestions-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/hsl/route-page-stop-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/hsl/route-page-stop-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/hsl/route-page-stop-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/hsl/route-page-stop-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/hsl/stop-page-departure-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/hsl/stop-page-departure-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/hsl/stop-page-departure-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/hsl/stop-page-departure-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/matka/front-page-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/matka/front-page-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/matka/front-page-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/matka/front-page-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/matka/itinerary-details-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/matka/itinerary-details-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/matka/itinerary-details-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/matka/itinerary-details-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/matka/itinerary-suggestions-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/matka/itinerary-suggestions-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/matka/itinerary-suggestions-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/matka/itinerary-suggestions-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/matka/route-page-stop-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/matka/route-page-stop-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/matka/route-page-stop-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/matka/route-page-stop-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/matka/stop-page-departure-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/matka/stop-page-departure-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/matka/stop-page-departure-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/matka/stop-page-departure-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/tampere/front-page-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/tampere/front-page-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/tampere/front-page-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/tampere/front-page-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/tampere/itinerary-details-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/tampere/itinerary-details-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/tampere/itinerary-details-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/tampere/itinerary-details-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/tampere/itinerary-suggestions-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/tampere/itinerary-suggestions-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/tampere/itinerary-suggestions-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/tampere/itinerary-suggestions-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/tampere/route-page-stop-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/tampere/route-page-stop-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/tampere/route-page-stop-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/tampere/route-page-stop-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/tampere/stop-page-departure-list-desktop-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/tampere/stop-page-departure-list-desktop-snap.png -------------------------------------------------------------------------------- /test/e2e/__image_snapshots__/webkit/tampere/stop-page-departure-list-mobile-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/e2e/__image_snapshots__/webkit/tampere/stop-page-departure-list-mobile-snap.png -------------------------------------------------------------------------------- /test/e2e/helpers/image-snapshot-config.js: -------------------------------------------------------------------------------- 1 | const getConfig = ( 2 | customSnapshotIdentifier, 3 | customSnapshotsDir, 4 | customDiffDir, 5 | ) => { 6 | return { 7 | diffDirection: 'vertical', 8 | dumpDiffToConsole: false, 9 | comparisonMethod: 'pixelmatch', 10 | failureThreshold: process.env.UPDATE_E2E ? 0 : 0.0125, 11 | failureThresholdType: 'percent', 12 | customSnapshotsDir, 13 | customDiffDir, 14 | customSnapshotIdentifier, 15 | }; 16 | }; 17 | 18 | export default getConfig; 19 | -------------------------------------------------------------------------------- /test/e2e/jest-playwright-desktop.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | serverOptions: { 3 | command: `CONFIG=${ 4 | process.env.CONFIG || 'hsl' 5 | } NODE_OPTS=--max_old_space_size=1000 yarn start-test`, 6 | port: 8080, 7 | protocol: 'http', 8 | launchTimeout: 200000, 9 | debug: true, 10 | usedPortAction: 'ignore', 11 | }, 12 | launchOptions: { 13 | headless: !process.env.DEBUG, 14 | }, 15 | contextOptions: { 16 | viewport: { 17 | width: 1920, 18 | height: 1080, 19 | }, 20 | }, 21 | browsers: ['chromium', 'firefox', 'webkit'], 22 | }; 23 | -------------------------------------------------------------------------------- /test/e2e/jest-playwright-mobile.config.js: -------------------------------------------------------------------------------- 1 | const { devices } = require('playwright'); 2 | 3 | const iPhone12 = devices['iPhone 12']; 4 | 5 | module.exports = { 6 | serverOptions: { 7 | command: `CONFIG=${ 8 | process.env.CONFIG || 'hsl' 9 | } NODE_OPTS=--max_old_space_size=1000 yarn start-test`, 10 | port: 8080, 11 | protocol: 'http', 12 | launchTimeout: 200000, 13 | debug: true, 14 | usedPortAction: 'ignore', 15 | }, 16 | launchOptions: { 17 | headless: !process.env.DEBUG, 18 | }, 19 | contextOptions: { 20 | viewport: iPhone12.viewport, 21 | }, 22 | isMobile: true, 23 | devices: ['iPhone 12'], 24 | browsers: ['chromium'], 25 | }; 26 | -------------------------------------------------------------------------------- /test/e2e/jest.config.js: -------------------------------------------------------------------------------- 1 | process.env.JEST_PLAYWRIGHT_CONFIG = `./test/e2e/jest-playwright-${ 2 | (process.env.MOBILE === 'true' && 'mobile') || 'desktop' 3 | }.config.js`; 4 | 5 | module.exports = { 6 | verbose: true, 7 | rootDir: '../..', 8 | roots: ['./test/e2e'], 9 | testMatch: ['**/?(*.)+(test).js'], 10 | testPathIgnorePatterns: ['/node_modules/', 'app', 'build', '_static'], 11 | testTimeout: 200000, 12 | preset: 'jest-playwright-preset', 13 | setupFilesAfterEnv: ['./test/e2e/jest.image.js'], 14 | reporters: ['default', './test/e2e/helpers/image-reporter.js'], 15 | }; 16 | -------------------------------------------------------------------------------- /test/e2e/jest.image.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import { toMatchImageSnapshot } from 'jest-image-snapshot'; 3 | 4 | expect.extend({ toMatchImageSnapshot }); 5 | -------------------------------------------------------------------------------- /test/install.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | set -e 4 | 5 | yarn setup 6 | yarn lint 7 | yarn build 8 | -------------------------------------------------------------------------------- /test/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: '../../.eslintrc.js', 3 | env: { 4 | mocha: true, 5 | }, 6 | globals: { 7 | expect: true, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /test/unit/CanceledLegsBar.test.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { describe, it } from 'mocha'; 3 | import React from 'react'; 4 | import { shallowWithIntl } from './helpers/mock-intl-enzyme'; 5 | import { mockContext } from './helpers/mock-context'; 6 | 7 | import { component as CanceledLegsBar } from '../../app/component/CanceledLegsBar'; 8 | 9 | describe('', () => { 10 | it('should render the banner if there are canceled legs', () => { 11 | const props = { 12 | showCanceledLegsBanner: true, 13 | }; 14 | const wrapper = shallowWithIntl(, { 15 | context: { ...mockContext }, 16 | }); 17 | expect( 18 | wrapper.find('.canceled-legs-banner').prop('style'), 19 | ).to.have.property('display', 'block'); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/unit/Checkbox.test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HSLdevcom/digitransit-ui/549ae8c9f3eb9fd26c66a372bc188f749575575f/test/unit/Checkbox.test.js -------------------------------------------------------------------------------- /test/unit/component/IconWithIcon.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { shallowWithIntl } from '../helpers/mock-intl-enzyme'; 4 | import Icon from '../../../app/component/Icon'; 5 | import IconWithIcon from '../../../app/component/IconWithIcon'; 6 | 7 | describe('', () => { 8 | it('should apply the given sub icon shape', () => { 9 | const props = { 10 | img: 'img', 11 | subIcon: 'sub-img', 12 | subIconShape: 'circle', 13 | }; 14 | const wrapper = shallowWithIntl(); 15 | expect(wrapper.find(Icon).at(1).prop('backgroundShape')).to.equal('circle'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/unit/component/LangSelect.test.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { describe, it } from 'mocha'; 3 | import React from 'react'; 4 | import moment from 'moment'; 5 | 6 | import { mockContext } from '../helpers/mock-context'; 7 | import { shallowWithIntl } from '../helpers/mock-intl-enzyme'; 8 | import { Component as LangSelect } from '../../../app/component/LangSelect'; 9 | 10 | describe('LangSelect', () => { 11 | after(() => { 12 | moment.locale('en'); 13 | }); 14 | 15 | describe('', () => { 16 | it('should render', () => { 17 | const wrapper = shallowWithIntl(, { 18 | context: { 19 | ...mockContext, 20 | executeAction: () => true, 21 | config: { availableLanguages: ['fi', 'sv', 'en'] }, 22 | }, 23 | }); 24 | expect(wrapper.isEmptyRender()).to.equal(false); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/unit/component/ScheduleTripRow.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { expect } from 'chai'; 3 | import { describe, it } from 'mocha'; 4 | 5 | import { shallowWithIntl } from '../helpers/mock-intl-enzyme'; 6 | import ScheduleTripRow from '../../../app/component/routepage/ScheduleTripRow'; 7 | 8 | describe('', () => { 9 | it('should highlight a canceled departure', () => { 10 | const props = { 11 | isCanceled: true, 12 | departureTime: '10.50', 13 | arrivalTime: '11.55', 14 | }; 15 | const wrapper = shallowWithIntl(); 16 | expect(wrapper.find('.trip-from.canceled')).to.have.lengthOf(1); 17 | expect(wrapper.find('.trip-to.canceled')).to.have.lengthOf(1); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /test/unit/component/StopPageMap.test.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { describe, it } from 'mocha'; 3 | import React from 'react'; 4 | 5 | import { shallowWithIntl } from '../helpers/mock-intl-enzyme'; 6 | import { Component as StopPageMap } from '../../../app/component/map/StopPageMap'; 7 | 8 | describe('', () => { 9 | it('should render empty if stop information is missing', () => { 10 | const props = { 11 | breakpoint: 'large', 12 | params: { 13 | stopId: 'HSL:2211275', 14 | }, 15 | routes: [], 16 | stop: null, 17 | }; 18 | const wrapper = shallowWithIntl(); 19 | expect(wrapper.find('.map').length).to.equal(0); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/unit/component/StopPageTabs.test.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { describe, it } from 'mocha'; 3 | import React from 'react'; 4 | 5 | import { shallowWithIntl } from '../helpers/mock-intl-enzyme'; 6 | import { Component as StopPageTabs } from '../../../app/component/stop/StopPageTabs'; 7 | 8 | const context = { 9 | match: { 10 | location: { 11 | pathname: 'foobar', 12 | }, 13 | params: { 14 | stopId: 'HSL:2211275', 15 | }, 16 | }, 17 | }; 18 | 19 | describe('', () => { 20 | it('should render empty if stop information is missing', () => { 21 | const props = { 22 | breakpoint: 'large', 23 | children:
, 24 | routes: [], 25 | stop: null, 26 | }; 27 | const wrapper = shallowWithIntl(, { 28 | context, 29 | }); 30 | expect(wrapper.isEmptyRender()).to.equal(true); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/unit/component/TripStopsContainer.test.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { describe, it } from 'mocha'; 3 | import React from 'react'; 4 | 5 | import { shallowWithIntl } from '../helpers/mock-intl-enzyme'; 6 | import { Component as TripStopsContainer } from '../../../app/component/routepage/TripStopsContainer'; 7 | import { mockMatch } from '../helpers/mock-router'; 8 | 9 | describe('', () => { 10 | it('should render empty if trip information is missing', () => { 11 | const props = { 12 | breakpoint: 'large', 13 | routes: [], 14 | trip: null, 15 | match: mockMatch, 16 | }; 17 | const wrapper = shallowWithIntl(); 18 | expect(wrapper.isEmptyRender()).to.equal(true); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test/unit/component/map/MarkerPopupBottom.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { expect } from 'chai'; 3 | import { describe, it } from 'mocha'; 4 | 5 | import { mountWithIntl } from '../../helpers/mock-intl-enzyme'; 6 | import { Component as MarkerPopupBottomWithoutLeaflet } from '../../../../app/component/map/MarkerPopupBottom'; 7 | 8 | describe('', () => { 9 | it('should render a viapoint button when asked so', () => { 10 | const props = { 11 | location: {}, 12 | leaflet: { 13 | map: { 14 | closePopup: () => {}, 15 | }, 16 | }, 17 | locationPopup: 'all', 18 | onSelectLocation: () => null, 19 | }; 20 | 21 | const wrapper = mountWithIntl( 22 | , 23 | {}, 24 | ); 25 | 26 | expect(wrapper.find('.route-add-viapoint').length).to.equal(1); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/unit/configurations/config.default.test.js: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'mocha'; 2 | import { expect } from 'chai'; 3 | 4 | import defaultConfig from '../../../app/configurations/config.default'; 5 | 6 | describe('default configuration', () => { 7 | describe('realTime', () => { 8 | it('routeSelector should map the given props to something', () => { 9 | const props = { 10 | route: { 11 | gtfsId: 'HSL:12345', 12 | }, 13 | }; 14 | const result = defaultConfig.realTime.HSL.routeSelector(props); 15 | expect(result).to.equal('12345'); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/unit/configurations/config.hsl.test.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { describe, it } from 'mocha'; 3 | 4 | import config from '../../../app/configurations/config.hsl'; 5 | 6 | describe('HSL Configuration', () => { 7 | describe('fareMapping', () => { 8 | it('should return fare name without feedId', () => { 9 | expect(config.fareMapping('HSL:AB')).to.equal('AB'); 10 | }); 11 | 12 | it('should work with a missing fareId', () => { 13 | expect(config.fareMapping(undefined)).to.equal(''); 14 | expect(config.fareMapping(null)).to.equal(''); 15 | }); 16 | 17 | it('should work with a malformed fareId', () => { 18 | expect(config.fareMapping('HSL:')).to.equal(''); 19 | }); 20 | 21 | it('should work with a non-string fareId', () => { 22 | expect(config.fareMapping({})).to.equal(''); 23 | expect(config.fareMapping(1234)).to.equal(''); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/unit/helpers/babel-register.js: -------------------------------------------------------------------------------- 1 | require('@babel/register')({ 2 | // This will override `node_modules` ignoring - you can alternatively pass 3 | // an array of strings to be explicitly matched or a regex / glob 4 | ignore: [ 5 | /node_modules\/(?!react-leaflet|@babel\/runtime\/helpers\/esm|lodash-es|@digitransit-util|@digitransit-component)/, 6 | ], 7 | }); 8 | -------------------------------------------------------------------------------- /test/unit/helpers/mock-router.js: -------------------------------------------------------------------------------- 1 | const mockMatcher = { 2 | routeConfig: [], 3 | match: () => {}, 4 | getRoutes: () => {}, 5 | isActive: () => {}, 6 | format: () => {}, 7 | }; 8 | 9 | export const mockRouter = { 10 | push: () => {}, 11 | replace: () => {}, 12 | go: () => {}, 13 | createHref: () => {}, 14 | createLocation: () => {}, 15 | addNavigationListener: () => {}, 16 | matcher: mockMatcher, 17 | replaceRouteConfig: () => {}, 18 | isActive: () => {}, 19 | }; 20 | 21 | export const mockMatch = { 22 | location: { 23 | action: '', 24 | pathname: '', 25 | search: '', 26 | hash: '', 27 | index: 0, 28 | delta: 0, 29 | query: {}, 30 | }, 31 | routeIndices: [], 32 | routeParams: {}, 33 | params: {}, 34 | routes: [], 35 | router: mockRouter, 36 | route: { 37 | getComponent: () => {}, 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /test/unit/store/ViaPointsStore.test.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { describe, it } from 'mocha'; 3 | 4 | import ViaPointStore from '../../../app/store/ViaPointStore'; 5 | 6 | describe('ViaPointsStore', () => { 7 | it('Should store via points', () => { 8 | const store = new ViaPointStore(); 9 | store.addViaPoint({ via: 'point' }); 10 | expect(store.getViaPoints()[0].via).to.deep.equal('point'); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /test/unit/util/hashUtil.test.js: -------------------------------------------------------------------------------- 1 | import hashCode from '../../../app/util/hashUtil'; 2 | 3 | describe('hashUtil', () => { 4 | it('should return 0 if the input string is falsy', () => { 5 | expect(hashCode(undefined)).to.equal(0); 6 | }); 7 | 8 | it('should return 0 if the input string has zero length', () => { 9 | expect(hashCode('')).to.equal(0); 10 | }); 11 | 12 | it('should return 0 if the input is not a string', () => { 13 | expect(hashCode(['f', 'o', 'o'])).to.equal(0); 14 | }); 15 | 16 | it('should return a numeric hash value', () => { 17 | expect(hashCode('foo')).to.equal(101574); 18 | expect(hashCode('bar')).to.equal(97299); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /win-launch-scripts/hsl-win-launch-script.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | START "Start node server" CMD /K "CD..&& set NODE_ENV=development&& set CONFIG=hsl&& nodemon -e js,css,scss,html --watch ./app/ server/server.js" 3 | START "Start node hot load server" CMD /K "CD..&& set NODE_ENV=development&& set CONFIG=hsl&& yarn run webpack-dev-server" 4 | -------------------------------------------------------------------------------- /win-launch-scripts/national-win-launch-script.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | START "Start node server" CMD /K "CD..&& set NODE_ENV=development&& nodemon -e js,css,scss,html --watch ./app/ server/server.js" 3 | START "Start node hot load server" CMD /K "CD..&& set NODE_ENV=development&& yarn run webpack-dev-server" 4 | --------------------------------------------------------------------------------