├── .env
├── .eslintrc.js
├── .fixpackrc
├── .github
├── CODEOWNERS
└── workflows
│ ├── conventional-pr-title.yml
│ ├── cypress-chrome.yml
│ ├── cypress-edge.yml
│ ├── cypress-firefox.yml
│ └── test.yml
├── .gitignore
├── .husky
├── commit-msg
├── post-checkout
├── post-merge
├── post-rebase
└── pre-commit
├── .imgbotconfig
├── .lintstagedrc.js
├── .nvmrc
├── .prettierrc.js
├── .stylelintrc.js
├── CHANGELOG.md
├── LICENSE
├── README.md
├── babel.config.json
├── commitlint.config.js
├── cypress.config.js
├── cypress
├── e2e
│ ├── Barrierfree.cy.js
│ ├── DataLink.cy.js
│ ├── FloorSwitcher.cy.js
│ ├── Header.cy.js
│ ├── MapControls.cy.js
│ ├── Search.cy.js
│ ├── ch.sbb.funkmesswagen.cy.js
│ ├── ch.sbb.geltungsbereiche-iframe.cy.js
│ ├── ch.sbb.handicap.cy.js
│ ├── ch.sbb.infrastruktur.cy.js
│ ├── ch.sbb.netzkarte.cy.js
│ ├── ch.sbb.tarifverbundkarte.public.cy.js
│ ├── consent.cy.js
│ ├── metadata.cy.js
│ └── permalink.cy.js
├── fixtures
│ ├── busAtZoom14.png
│ ├── example.json
│ ├── fullTrajectory.png
│ └── noBusAtZoom9.png
├── plugins
│ └── index.js
└── support
│ ├── commands.js
│ └── e2e.js
├── dependabot.yml
├── package.json
├── packages
├── es
│ ├── .babelrc
│ └── index.js
└── wc
│ └── config-overrides.js
├── public
├── README.md
├── data
│ ├── pois.geojson
│ └── tours.json
├── embed.html
├── favicon.png
├── iframe.html
├── index.html
└── manifest.json
├── pull_request_template.md
├── scripts
├── build-es.sh
├── prepare-package.js
├── process_contentful.py
├── read-pkg-json.js
└── requirements.txt
├── src
├── WebComponent.js
├── WebComponent.scss
├── __mocks__
│ ├── @jonkoops
│ │ └── matomo-tracker-react.js
│ ├── mapbox-gl.js
│ ├── maplibre-gl.js
│ └── resize-observer-polyfill.js
├── components
│ ├── Autocomplete
│ │ ├── Autocomplete.js
│ │ ├── Autocomplete.md.scss
│ │ ├── Autocomplete.scss
│ │ ├── Autocomplete.test.js
│ │ ├── __snapshots__
│ │ │ └── Autocomplete.test.js.snap
│ │ └── index.js
│ ├── Button
│ │ ├── Button.js
│ │ ├── Button.md.scss
│ │ ├── Button.scss
│ │ ├── Button.test.js
│ │ ├── __snapshots__
│ │ │ └── Button.test.js.snap
│ │ └── index.js
│ ├── CloseButton
│ │ ├── CloseButton.js
│ │ └── index.js
│ ├── Collapsible
│ │ ├── Collapsible.js
│ │ ├── Collapsible.scss
│ │ └── index.js
│ ├── Copyright
│ │ ├── Copyright.js
│ │ └── index.js
│ ├── DataLink
│ │ ├── DataLink.js
│ │ ├── DataLink.test.js
│ │ └── index.js
│ ├── Dialog
│ │ ├── Dialog.js
│ │ ├── Dialog.test.js
│ │ ├── __snapshots__
│ │ │ └── Dialog.test.js.snap
│ │ └── index.js
│ ├── Draw
│ │ ├── Draw.js
│ │ ├── Draw.test.js
│ │ └── index.js
│ ├── DrawButton
│ │ ├── DrawButton.js
│ │ ├── DrawButton.test.js
│ │ └── index.js
│ ├── DrawEditLinkInput
│ │ ├── DrawEditLinkInput.js
│ │ ├── DrawEditLinkInput.test.js
│ │ └── index.js
│ ├── DrawLayerMenu
│ │ ├── DrawLayerMenu.js
│ │ ├── DrawLayerMenu.scss
│ │ ├── DrawLayerMenu.test.js
│ │ ├── __snapshots__
│ │ │ └── DrawLayerMenu.test.js.snap
│ │ └── index.js
│ ├── DrawPermalinkButton
│ │ ├── DrawPermalinkButton.js
│ │ ├── DrawPermalinkButton.test.js
│ │ └── index.js
│ ├── DrawRemoveDialog
│ │ ├── DrawRemoveDialog.js
│ │ ├── DrawRemoveDialog.test.js
│ │ ├── __snapshots__
│ │ │ └── DrawRemoveDialog.test.js.snap
│ │ └── index.js
│ ├── ExportButton
│ │ ├── ExportButton.js
│ │ ├── ExportButton.test.js
│ │ ├── index.js
│ │ ├── loader.svg
│ │ └── northArrowCircle.png
│ ├── FadeShadow
│ │ ├── FadeShadow.js
│ │ └── index.js
│ ├── FeatureInformation
│ │ ├── FeatureInformation.js
│ │ ├── FeatureInformation.scss
│ │ ├── FeatureInformation.test.js
│ │ ├── FeaturePagination.scss
│ │ ├── __snapshots__
│ │ │ └── FeatureInformation.test.js.snap
│ │ └── index.js
│ ├── FeatureMenu
│ │ ├── FeatureMenu.js
│ │ └── index.js
│ ├── FloorSwitcher
│ │ ├── FloorSwitcher.js
│ │ └── index.js
│ ├── Footer
│ │ ├── Footer.js
│ │ ├── Footer.scss
│ │ ├── Footer.test.js
│ │ └── index.js
│ ├── Head
│ │ ├── Head.js
│ │ ├── Head.test.js
│ │ └── index.js
│ ├── Header
│ │ ├── Header.js
│ │ ├── Header.scss
│ │ ├── Header.test.js
│ │ ├── __snapshots__
│ │ │ └── Header.test.js.snap
│ │ └── index.js
│ ├── IconList
│ │ ├── IconList.js
│ │ ├── IconList.scss
│ │ └── index.js
│ ├── InfosButton
│ │ ├── InfosButton.js
│ │ ├── InfosButton.test.js
│ │ └── index.js
│ ├── InputIcon
│ │ ├── InputIcon.js
│ │ ├── InputIcon.test.js
│ │ ├── __snapshots__
│ │ │ └── InputIcon.test.js.snap
│ │ └── index.js
│ ├── LanguageSelect
│ │ ├── LanguageSelect.js
│ │ ├── LanguageSelect.test.js
│ │ └── index.js
│ ├── LayerInfosDialog
│ │ ├── LayerInfosDialog.js
│ │ ├── LayerInfosDialog.test.js
│ │ ├── __snapshots__
│ │ │ └── LayerInfosDialog.test.js.snap
│ │ └── index.js
│ ├── LegalLines
│ │ ├── Contact
│ │ │ ├── Contact.js
│ │ │ └── index.js
│ │ ├── Imprint
│ │ │ ├── Imprint.js
│ │ │ └── index.js
│ │ ├── Legal
│ │ │ ├── Legal.js
│ │ │ └── index.js
│ │ ├── LegalLines.js
│ │ ├── LegalLines.test.js
│ │ ├── __snapshots__
│ │ │ └── LegalLines.test.js.snap
│ │ └── index.js
│ ├── LegendCircle
│ │ └── LegendCircle.js
│ ├── Link
│ │ ├── Link.js
│ │ ├── Link.svg
│ │ ├── Link.test.js
│ │ ├── __snapshots__
│ │ │ └── Link.test.js.snap
│ │ └── index.js
│ ├── List
│ │ ├── List.js
│ │ ├── List.scss
│ │ ├── List.test.js
│ │ ├── __snapshots__
│ │ │ └── List.test.js.snap
│ │ └── index.js
│ ├── ListItem
│ │ ├── ListItem.js
│ │ ├── ListItem.test.js
│ │ ├── __snapshots__
│ │ │ └── ListItem.test.js.snap
│ │ └── index.js
│ ├── Login
│ │ ├── Login.js
│ │ ├── Login.scss
│ │ ├── Login.test.js
│ │ ├── __snapshots__
│ │ │ └── Login.test.js.snap
│ │ └── index.js
│ ├── MainDialog
│ │ ├── MainDialog.js
│ │ └── index.js
│ ├── Map
│ │ ├── Map.js
│ │ └── index.js
│ ├── MapAccessibility
│ │ ├── MapAccessibility.js
│ │ ├── MapAccessibility.test.js
│ │ ├── __snapshots__
│ │ │ └── MapAccessibility.test.js.snap
│ │ └── index.js
│ ├── MapButton
│ │ ├── MapButton.js
│ │ └── index.js
│ ├── MapControls
│ │ ├── FitExtent
│ │ │ ├── FitExtent.js
│ │ │ └── index.js
│ │ ├── Geolocation
│ │ │ ├── Geolocation.js
│ │ │ └── index.js
│ │ ├── MapControls.js
│ │ ├── MapControls.test.js
│ │ ├── MenuToggler
│ │ │ ├── MenuToggler.js
│ │ │ └── index.js
│ │ └── index.js
│ ├── MatomoTracker
│ │ ├── MatomoTracker.js
│ │ ├── MatomoTracker.test.js
│ │ └── index.js
│ ├── Menu
│ │ ├── Menu.js
│ │ ├── Menu.scss
│ │ ├── MenuItem.js
│ │ ├── MenuItem.scss
│ │ ├── MenuItemHeader.js
│ │ ├── MenuItemHeader.scss
│ │ └── index.js
│ ├── MessageListener
│ │ ├── MessageListener.js
│ │ └── index.js
│ ├── NoDragPanWarning
│ │ ├── NoDragPanWarning.js
│ │ ├── NoDragPanWarning.test.js
│ │ └── index.js
│ ├── NoMouseWheelWarning
│ │ ├── NoMouseWheelWarning.js
│ │ ├── NoMouseWheelWarning.test.js
│ │ └── index.js
│ ├── Overlay
│ │ ├── Overlay.js
│ │ └── index.js
│ ├── Permalink
│ │ ├── Permalink.js
│ │ ├── Permalink.test.js
│ │ └── index.js
│ ├── PermalinkButton
│ │ ├── PermalinkButton.js
│ │ ├── PermalinkButton.test.js
│ │ ├── __snapshots__
│ │ │ └── PermalinkButton.test.js.snap
│ │ └── index.js
│ ├── PermalinkInput
│ │ ├── PermalinkInput.js
│ │ ├── PermalinkInput.test.js
│ │ ├── __snapshots__
│ │ │ └── PermalinkInput.test.js.snap
│ │ └── index.js
│ ├── PermalinkInputCore
│ │ ├── PermalinkInput.js
│ │ ├── PermalinkInput.test.js
│ │ ├── __snapshots__
│ │ │ └── PermalinkInput.test.js.snap
│ │ └── index.js
│ ├── PersonCard
│ │ ├── PersonCard.js
│ │ └── index.js
│ ├── PhotoCarusel
│ │ ├── PhotoCarusel.js
│ │ ├── PhotoCarusel.test.js
│ │ └── index.js
│ ├── Popup
│ │ ├── Popup.js
│ │ └── index.js
│ ├── ProjectionSelect
│ │ ├── ProjectionSelect.js
│ │ └── index.js
│ ├── ResizeHandler
│ │ ├── ResizeHandler.js
│ │ ├── ResizeHandler.test.js
│ │ └── index.js
│ ├── SBBSwitch
│ │ ├── SBBSwitch.js
│ │ └── index.js
│ ├── Search
│ │ ├── Search.js
│ │ ├── Search.scss
│ │ ├── Search.svg
│ │ ├── Search.test.js
│ │ ├── SearchInfo.js
│ │ ├── SearchInput.js
│ │ ├── SearchInput.scss
│ │ ├── SearchService.js
│ │ ├── SearchToggle.js
│ │ ├── SearchToggle.scss
│ │ └── index.js
│ ├── SearchInput
│ │ ├── SearchInput.js
│ │ ├── SearchInput.md.scss
│ │ ├── SearchInput.scss
│ │ ├── SearchInput.test.js
│ │ ├── __snapshots__
│ │ │ └── SearchInput.test.js.snap
│ │ └── index.js
│ ├── Select
│ │ ├── Select.js
│ │ └── index.js
│ ├── Share
│ │ ├── Share.js
│ │ ├── Share.scss
│ │ ├── Share.test.js
│ │ └── index.js
│ ├── SharePermalinkButton
│ │ ├── SharePermalinkButton.js
│ │ ├── SharePermalinkButton.test.js
│ │ └── index.js
│ ├── StopSearchResult
│ │ ├── StopSearchResult.js
│ │ ├── StopSearchResult.test.js
│ │ └── index.js
│ ├── TarifverbundPartner
│ │ ├── TarifverbundPartner.js
│ │ └── index.js
│ ├── TopicElements
│ │ ├── TopicElements.js
│ │ ├── TopicElements.test.js
│ │ └── index.js
│ ├── TopicInfosButton
│ │ ├── TopicInfosButton.js
│ │ ├── TopicInfosButton.test.js
│ │ └── index.js
│ ├── TopicLoader
│ │ ├── TopicLoader.js
│ │ ├── TopicLoader.test.js
│ │ └── index.js
│ ├── TopicMenu
│ │ ├── TopicMenu.js
│ │ ├── TopicMenu.scss
│ │ ├── TopicMenu.test.js
│ │ └── index.js
│ ├── TopicTelephoneInfos
│ │ ├── TopicTelephoneInfos.js
│ │ └── index.js
│ ├── TopicsMenu
│ │ ├── TopicsMenu.js
│ │ ├── TopicsMenu.scss
│ │ ├── TopicsMenu.test.js
│ │ └── index.js
│ ├── TopicsMenuHeader
│ │ ├── TopicsMenuHeader.js
│ │ ├── TopicsMenuHeader.scss
│ │ ├── TopicsMenuHeader.test.js
│ │ └── index.js
│ ├── TrafimageMaps
│ │ ├── TrafimageMaps.js
│ │ ├── TrafimageMaps.scss
│ │ ├── TrafimageMaps.test.js
│ │ └── index.js
│ └── withResizing
│ │ ├── index.js
│ │ └── withResizing.js
├── config
│ ├── ch.railplus.mitglieder
│ │ ├── RailplusExportButton.js
│ │ └── index.js
│ ├── ch.sbb.beleuchtungsstaerken
│ │ └── index.js
│ ├── ch.sbb.casa
│ │ └── index.js
│ ├── ch.sbb.construction
│ │ └── index.js
│ ├── ch.sbb.direktverbindungen
│ │ ├── DvFeatureInfo
│ │ │ ├── DvFeatureInfo.js
│ │ │ └── index.js
│ │ ├── DvFeatureInfoTitle
│ │ │ ├── DvFeatureInfoTitle.js
│ │ │ └── index.js
│ │ ├── DvLegendLine
│ │ │ ├── DvLegendLine.js
│ │ │ └── index.js
│ │ ├── DvLineInfo
│ │ │ ├── DvLineInfo.js
│ │ │ └── index.js
│ │ ├── DvLineTitle
│ │ │ ├── DvLineTitle.js
│ │ │ └── index.js
│ │ ├── DvListButton
│ │ │ ├── DvListButton.js
│ │ │ ├── DvListButton.test.js
│ │ │ ├── __snapshots__
│ │ │ │ └── DvListButton.test.js.snap
│ │ │ └── index.js
│ │ ├── dvParseFeatures.js
│ │ └── index.js
│ ├── ch.sbb.energie
│ │ └── index.js
│ ├── ch.sbb.funkmesswagen
│ │ ├── MesswagenFollowButton
│ │ │ ├── MesswagenFollowButton.js
│ │ │ └── index.js
│ │ └── index.js
│ ├── ch.sbb.geltungsbereiche.iframe
│ │ └── index.js
│ ├── ch.sbb.geltungsbereiche.mvp
│ │ └── index.js
│ ├── ch.sbb.handicap
│ │ ├── index.js
│ │ └── index.test.js
│ ├── ch.sbb.immobilien
│ │ └── index.js
│ ├── ch.sbb.infrastruktur
│ │ └── index.js
│ ├── ch.sbb.isb
│ │ ├── index.js
│ │ └── index.test.js
│ ├── ch.sbb.netzkarte.sandbox
│ │ └── index.js
│ ├── ch.sbb.netzkarte
│ │ └── index.js
│ ├── ch.sbb.regionenkarte.public
│ │ └── index.js
│ ├── ch.sbb.sts
│ │ ├── StsMenuToggler
│ │ │ ├── StsMenuToggler.js
│ │ │ └── index.js
│ │ └── index.js
│ ├── ch.sbb.tarifverbundkarte.public
│ │ └── index.js
│ ├── ch.sbb.zweitausbildung
│ │ └── index.js
│ ├── doc-config.json
│ ├── proj4.js
│ ├── searches.js
│ └── topics.js
├── examples
│ ├── Angular
│ │ └── README.md
│ ├── Betriebsregionen
│ │ └── README.md
│ ├── Construction
│ │ └── README.md
│ ├── CustomTopic
│ │ ├── ExampleCode.txt
│ │ └── README.md
│ ├── DirektVerbindung
│ │ └── README.md
│ ├── DocForm.js
│ ├── ExternalUpdate
│ │ └── README.md
│ ├── Geltungsbereiche
│ │ └── README.md
│ ├── OverrideTopic
│ │ ├── ExampleCode.txt
│ │ └── README.md
│ ├── Punctuality
│ │ ├── ExampleCode.txt
│ │ └── README.md
│ ├── Schulzug
│ │ ├── ExampleCode.txt
│ │ ├── README.md
│ │ └── marker.png
│ ├── WebComponent
│ │ ├── README.md
│ │ ├── getWcAttributesFromUrl.js
│ │ ├── getWcCodeFromUrl.js
│ │ └── webComponentAttributes.js
│ ├── getCodeWithApiKey.js
│ ├── getHtmlPageCode.js
│ └── iframe
│ │ ├── Geltungsbereiche
│ │ └── README.md
│ │ ├── README.md
│ │ ├── Railplus
│ │ └── README.md
│ │ ├── getHtmlPageCode.js
│ │ ├── getIframeCodeFromUrl.js
│ │ └── iframeSearchParams.js
├── filters
│ ├── AusbauFilters
│ │ ├── AusbauFilters.js
│ │ ├── AusbauFilters.test.js
│ │ ├── __snapshots__
│ │ │ └── AusbauFilters.test.js.snap
│ │ └── index.js
│ └── index.js
├── globals.scss
├── i18n.js
├── img
│ ├── Geolocate
│ │ ├── Geolocate.js
│ │ └── index.js
│ ├── arrow.png
│ ├── arrow.svg
│ ├── bahnhofplanLayerIcon.png
│ ├── chevronLeft.svg
│ ├── circleQuestionMark.svg
│ ├── clock_10_large.svg
│ ├── energie_legend_pub.url.svg
│ ├── favicon.png
│ ├── finish_flag.png
│ ├── finish_flag.svg
│ ├── geltungsbereicheLegends
│ │ ├── ga_legend_a3_de.svg
│ │ ├── ga_legend_a3_en.svg
│ │ ├── ga_legend_a3_fr.svg
│ │ ├── ga_legend_a3_it.svg
│ │ ├── ga_legend_a4_de.svg
│ │ ├── ga_legend_a4_en.svg
│ │ ├── ga_legend_a4_fr.svg
│ │ ├── ga_legend_a4_it.svg
│ │ ├── hta_legend_a3_de.svg
│ │ ├── hta_legend_a3_en.svg
│ │ ├── hta_legend_a3_fr.svg
│ │ ├── hta_legend_a3_it.svg
│ │ ├── hta_legend_a4_de.svg
│ │ ├── hta_legend_a4_en.svg
│ │ ├── hta_legend_a4_fr.svg
│ │ ├── hta_legend_a4_it.svg
│ │ ├── index.js
│ │ ├── index.test.js
│ │ ├── tk_legend_a3_de.svg
│ │ ├── tk_legend_a3_en.svg
│ │ ├── tk_legend_a3_fr.svg
│ │ ├── tk_legend_a3_it.svg
│ │ ├── tk_legend_a4_de.svg
│ │ ├── tk_legend_a4_en.svg
│ │ ├── tk_legend_a4_fr.svg
│ │ └── tk_legend_a4_it.svg
│ ├── geolocate_marker.svg
│ ├── geolocate_marker_direction.svg
│ ├── layers
│ │ ├── BahnhofplanLayer
│ │ │ ├── interactiveStationplans.png
│ │ │ └── printproducts.png
│ │ ├── Betriebsregionen
│ │ │ ├── mitte.png
│ │ │ ├── ost.png
│ │ │ ├── other.png
│ │ │ ├── sud.png
│ │ │ └── west.png
│ │ ├── NetzkartePointLayer
│ │ │ ├── layer.png
│ │ │ └── stations.png
│ │ ├── PassagierfrequenzenLayer
│ │ │ └── layer.png
│ │ ├── RouteLayer
│ │ │ └── layer.png
│ │ └── ZoneLayer
│ │ │ └── layer.png
│ ├── list-icon-sbb.svg
│ ├── loader.svg
│ ├── mail.svg
│ ├── menu.png
│ ├── menu_closed.png
│ ├── menu_open.png
│ ├── minus.svg
│ ├── northArrowCircle.png
│ ├── pencil.svg
│ ├── pencil_add.svg
│ ├── person.svg
│ ├── phone.svg
│ ├── plus.svg
│ ├── popups
│ │ └── NetzentwicklungPopup
│ │ │ ├── mail.svg
│ │ │ ├── person.svg
│ │ │ └── phone.svg
│ ├── railplus_legend.svg
│ ├── sbb-logo.svg
│ ├── sbb
│ │ ├── 040_hamburgermenu_102_36.svg
│ │ ├── 040_schliessen_104_36.svg
│ │ ├── globe_210_large.svg
│ │ ├── gps-large.svg
│ │ ├── gps-medium.svg
│ │ ├── gps-small.svg
│ │ ├── location-pin-a-medium.svg
│ │ ├── location-pin-m-medium-bg-red.url.svg
│ │ ├── two-finger-tap-large.svg
│ │ └── user_92_large.svg
│ ├── search.svg
│ ├── swissbounds.svg
│ ├── tarifverbund_legend.url.svg
│ ├── train-day.svg
│ └── train-night.svg
├── index.js
├── lang
│ ├── de.json
│ ├── en.json
│ ├── fr.json
│ └── it.json
├── layerInfos
│ ├── BeleuchtungLayerInfo
│ │ ├── BeleuchtungLayerInfo.js
│ │ ├── index.js
│ │ └── lightingMapping.js
│ ├── BeleuchtungTopicInfo
│ │ ├── BeleuchtungLegende.js
│ │ ├── BeleuchtungTopicInfo.js
│ │ └── index.js
│ ├── BetriebsRegionenLayerInfo
│ │ ├── BetriebsRegionenLayerInfo.js
│ │ ├── BetriebsRegionenLayerInfo.scss
│ │ └── index.js
│ ├── BuslinesLayerInfo
│ │ ├── BuslinesLayerInfo.js
│ │ └── index.js
│ ├── ConstructionFertigstellungLayerInfo
│ │ ├── ConstructionFertigstellungLayerInfo.js
│ │ └── index.js
│ ├── ConstructionLayerInfo
│ │ ├── ConstructionLayerInfo.js
│ │ ├── ConstructionLayerInfo.scss
│ │ └── index.js
│ ├── ConstructionTopicInfo
│ │ ├── ConstructionTopicInfo.js
│ │ ├── ConstructionTopicInfo.test.js
│ │ └── index.js
│ ├── DrawLayerInfo
│ │ ├── DrawLayerInfo.js
│ │ └── index.js
│ ├── DvLayerInfo
│ │ ├── DvLayerInfo.js
│ │ └── index.js
│ ├── DvTopicInfo
│ │ ├── DvTopicInfo.js
│ │ └── index.js
│ ├── EnergieLayerInfo
│ │ ├── EnergieLayerInfo.js
│ │ └── index.js
│ ├── EnergiePublicTopicInfo
│ │ ├── EnergiePublicTopicInfo.js
│ │ └── index.js
│ ├── EnergieTopicInfo
│ │ ├── EnergieTopicInfo.js
│ │ └── index.js
│ ├── GeltungsbereicheLayerInfo
│ │ ├── GeltungsbereicheLayerInfo.js
│ │ └── index.js
│ ├── GeltungsbereicheTopicInfo
│ │ ├── GeltungsbereicheTopicInfo.js
│ │ └── index.js
│ ├── HandicapLayerInfo
│ │ ├── HandicapLayerInfo.js
│ │ └── index.js
│ ├── HandicapTopicInfo
│ │ ├── HandicapTopicInfo.js
│ │ └── index.js
│ ├── InfoFPWTopicInfo
│ │ └── InfoFPWTopicInfo.js
│ ├── InfrastrukturTopicInfo
│ │ ├── InfrastrukturTopicInfo.js
│ │ └── index.js
│ ├── IsbNormalspurLayerInfo
│ │ ├── IsbNormalspurLayerInfo.js
│ │ ├── IsbNormalspurLayerInfo.test.js
│ │ └── index.js
│ ├── IsbOtherLayerInfo
│ │ ├── IsbOtherLayerInfo.js
│ │ ├── IsbOtherLayerInfo.test.js
│ │ └── index.js
│ ├── IsbSchmalspurLayerInfo
│ │ ├── IsbSchmalspurLayerInfo.js
│ │ ├── IsbSchmalspurLayerInfo.test.js
│ │ └── index.js
│ ├── IsbTVSLayerInfo
│ │ ├── IsbTVSLayerInfo.js
│ │ ├── IsbTVSLayerInfo.test.js
│ │ ├── OperatorLegend.js
│ │ ├── OperatorShortAndLongName.js
│ │ └── index.js
│ ├── IsbTopicInfo
│ │ ├── IsbTopicInfo.js
│ │ └── index.js
│ ├── MapsGeoAdminLayerInfo
│ │ ├── MapsGeoAdminLayerInfo.js
│ │ ├── MapsGeoAdminLayerInfo.scss
│ │ └── index.js
│ ├── MesswagenPhotosLayerInfo
│ │ ├── MesswagenPhotosLayerInfo.js
│ │ └── index.js
│ ├── MesswagenTopicInfo
│ │ ├── MesswagenTopicInfo.js
│ │ └── index.js
│ ├── MobzTopicInfo
│ │ └── MobzTopicInfo.js
│ ├── NetzkarteTopicInfo
│ │ ├── NetzkarteTopicInfo.js
│ │ └── index.js
│ ├── PassagierFrequenzenLayerInfo
│ │ ├── PassagierFrequenzenLayerInfo.js
│ │ ├── PassagierFrequenzenLayerInfo.test.js
│ │ └── index.js
│ ├── PunctualityLayerInfo
│ │ ├── PunctualityLayerInfo.js
│ │ └── index.js
│ ├── RegionenkartePublicLayerInfo
│ │ ├── RegionenkarteLegend.js
│ │ ├── RegionenkarteLegend.test.js
│ │ ├── RegionenkartePublicLayerInfo.js
│ │ ├── boundary.png
│ │ ├── gelb.png
│ │ ├── grun.png
│ │ ├── index.js
│ │ ├── lila.png
│ │ └── rot.png
│ ├── RegionenkartePublicTopicInfo
│ │ ├── RegionenkartePublicTopicInfo.js
│ │ └── index.js
│ ├── SandboxTopicInfo
│ │ ├── SandboxTopicInfo.js
│ │ └── index.js
│ ├── TarifverbundkarteTopicInfo
│ │ ├── TarifVerbundLegend.js
│ │ ├── TarifverbundLegend.test.js
│ │ ├── TarifverbundkarteTopicInfo.js
│ │ └── index.js
│ ├── ZweitausbildungLayerInfo
│ │ ├── ZweitausbildungLayerInfo.js
│ │ └── index.js
│ ├── ZweitausbildungRoutesSubLayerInfo
│ │ ├── ZweitausbildungRoutesSubLayerInfo.js
│ │ └── index.js
│ ├── ZweitausbildungSubLayerInfo
│ │ ├── ZweitausbildungSubLayerInfo.js
│ │ └── index.js
│ ├── ZweitausbildungTopicInfo
│ │ ├── ZweitausbildungTopicInfo.js
│ │ └── index.js
│ └── index.js
├── layers
│ ├── AusbauLayer
│ │ ├── AusbauLayer.js
│ │ ├── AusbauLayer.test.js
│ │ └── index.js
│ ├── BeleuchtungsLayer
│ │ ├── BeleuchtungsLayer.js
│ │ └── index.js
│ ├── DirektverbindungenLayer
│ │ ├── DirektverbindungenLayer.js
│ │ ├── DirektverbindungenLayer.test.js
│ │ └── index.js
│ ├── DrawLayer
│ │ ├── DrawLayer.js
│ │ └── index.js
│ ├── GeltungsbereicheLayer
│ │ ├── GeltungsbereicheLayer.js
│ │ ├── GeltungsbereicheLayer.test.js
│ │ └── index.js
│ ├── HandicapLayer
│ │ ├── HandicapLayer.js
│ │ └── index.js
│ ├── KilometrageLayer
│ │ ├── KilometrageLayer.js
│ │ └── index.js
│ ├── LevelLayer
│ │ ├── LevelLayer.js
│ │ └── index.js
│ ├── MapboxStyleLayer
│ │ ├── MapboxStyleLayer.js
│ │ ├── MapboxStyleLayer.test.js
│ │ └── index.js
│ ├── MapsGeoAdminLayer
│ │ ├── MapsGeoAdminLayer.js
│ │ └── index.js
│ ├── MesswagenLayer
│ │ ├── MesswagenLayer.js
│ │ ├── MesswagenLayer.test.js
│ │ └── index.js
│ ├── PlatformsLayer
│ │ ├── PlatformsLayer.js
│ │ ├── PlatformsLayer.test.js
│ │ └── index.js
│ ├── RailplusLayer
│ │ ├── RailplusLayer.js
│ │ ├── RailplusLayer.test.js
│ │ └── index.js
│ ├── RegionenkarteLayer
│ │ ├── RegionenkarteLayer.js
│ │ ├── RegionenkarteLayer.test.js
│ │ └── index.js
│ ├── SchmalspurLayer
│ │ ├── SchmalspurLayer.js
│ │ ├── SchmalspurLayer.test.js
│ │ └── index.js
│ ├── StationsLayer
│ │ ├── StationsLayer.js
│ │ └── index.js
│ ├── StsHighlightRoutesLayer
│ │ ├── StsHighlightRoutesLayer.js
│ │ └── index.js
│ ├── StsPoisLayer
│ │ ├── StsPoisLayer.js
│ │ ├── StsPoisLayer.test.js
│ │ ├── img
│ │ │ ├── poi.png
│ │ │ └── poi_hl.png
│ │ └── index.js
│ ├── TarifverbundkarteLayer
│ │ ├── TarifverbundkarteLayer.js
│ │ └── index.js
│ ├── TrafimageMapboxLayer
│ │ ├── TrafimageMapboxLayer.js
│ │ └── index.js
│ ├── TralisLayer
│ │ ├── TralisLayer.js
│ │ └── index.js
│ ├── ZweitausbildungAbroadLayer
│ │ ├── FeatureCollection.json
│ │ ├── ZweitausbildungAbroadLayer.js
│ │ └── index.js
│ ├── ZweitausbildungPoisLayer
│ │ ├── ZweitausbildungPoisLayer.js
│ │ └── index.js
│ ├── ZweitausbildungRoutesHighlightLayer
│ │ ├── ZweitausbildungRoutesHighlightLayer.js
│ │ └── index.js
│ ├── ZweitausbildungRoutesLayer
│ │ ├── GS100_Gotthard_Panorama_Expresses_shiplines.json
│ │ ├── GS150_Gotthard_Panorama_Expresses_shiplines.json
│ │ ├── ZweitausbildungRoutesLayer.js
│ │ ├── getStyleLayers.js
│ │ ├── index.js
│ │ ├── lines.js
│ │ └── lines.test.js
│ └── index.js
├── menus
│ ├── DirektverbindungenMenu
│ │ ├── DvLayerSwitcher.js
│ │ ├── DvMenu.js
│ │ ├── DvMenu.test.js
│ │ └── index.js
│ ├── DrawMenu
│ │ ├── DrawMenu.js
│ │ ├── DrawMenu.test.js
│ │ └── index.js
│ ├── ExportMenu
│ │ ├── ExportMenu.js
│ │ ├── ExportResolutionSelect.js
│ │ └── index.js
│ ├── GaExportMenu
│ │ ├── GaExportMapButton.js
│ │ ├── GaExportMenu.js
│ │ └── index.js
│ ├── GeltungsbereicheTopicMenu
│ │ ├── GeltungsbereicheTopicMenu.js
│ │ ├── GeltungsbereicheTopicMenu.test.js
│ │ └── index.js
│ ├── IframeMenu
│ │ ├── IframeMenu.js
│ │ └── index.js
│ ├── RailplusMenu
│ │ ├── RailplusMenu.js
│ │ └── index.js
│ ├── ShareMenu
│ │ ├── ShareMenu.js
│ │ └── index.js
│ ├── StsMenu
│ │ ├── StsMenu.js
│ │ ├── StsMenu.test.js
│ │ ├── StsValidityFeatureInfo.js
│ │ ├── StsValidityLayerSwitcher.js
│ │ ├── index.js
│ │ └── stsParseFeatureInfo.js
│ └── TrackerMenu
│ │ ├── TrackerMenu.js
│ │ ├── TrackerMenu.scss
│ │ └── index.js
├── model
│ ├── app
│ │ ├── actions.js
│ │ ├── actions.test.js
│ │ ├── reducers.js
│ │ └── reducers.test.js
│ ├── map
│ │ ├── actions.js
│ │ └── reducers.js
│ └── store.js
├── ol
│ └── interaction
│ │ ├── DblClickDragZoom.js
│ │ └── DblPointerClickZoomOut.js
├── popups
│ ├── BahnhofplanPopup
│ │ ├── BahnhofplanPopup.js
│ │ ├── BahnhofplanPopup.scss
│ │ └── index.js
│ ├── BeleuchtungsPopup
│ │ ├── BeleuchtungsPopup.js
│ │ └── index.js
│ ├── BetriebsRegionenPopup
│ │ ├── BetriebsRegionenPopup.js
│ │ └── index.js
│ ├── BusLinePopup
│ │ ├── BusLinePopup.js
│ │ ├── BusLinePopup.scss
│ │ └── index.js
│ ├── CasaRoutePopup
│ │ ├── CasaRoutePopup.js
│ │ ├── CasaRoutePopup.scss
│ │ └── index.js
│ ├── ConstructionPopup
│ │ ├── ConstructionPopup.js
│ │ ├── ConstructionPopup.scss
│ │ └── index.js
│ ├── DeparturePopup
│ │ ├── DeparturePopup.js
│ │ ├── DeparturePopupContent.js
│ │ ├── DeparturePopupContent.scss
│ │ ├── DestinationInput.js
│ │ ├── DestinationInput.scss
│ │ └── index.js
│ ├── DirektverbindungenPopup
│ │ ├── DvPopup.js
│ │ └── index.js
│ ├── DrawPopup
│ │ ├── DrawPopup.js
│ │ └── index.js
│ ├── EnergiePopup
│ │ ├── EnergiePopup.js
│ │ └── index.js
│ ├── GeltungsbereicheGaPopup
│ │ ├── GeltungsbereicheGaPopup.js
│ │ ├── GeltungsbereicheLegend.js
│ │ ├── GeltungsbereicheLegend.test.js
│ │ └── index.js
│ ├── HandicapPopup
│ │ ├── HandicapPopup.js
│ │ ├── HandicapPopup.scss
│ │ ├── HandicapPopupElement.js
│ │ ├── HandicapPopupElement.test.js
│ │ ├── README.md
│ │ ├── __snapshots__
│ │ │ └── HandicapPopupElement.test.js.snap
│ │ └── index.js
│ ├── IsbPopup
│ │ ├── IsbPopup.js
│ │ └── index.js
│ ├── KilometragePopup
│ │ ├── KilometragePopup.js
│ │ └── index.js
│ ├── MapsGeoAdminPopup
│ │ ├── MapsGeoAdminPopup.js
│ │ ├── MapsGeoAdminPopup.scss
│ │ └── index.js
│ ├── MesswagenPhotosPopup
│ │ ├── MesswagenPhotosPopup.js
│ │ └── index.js
│ ├── MesswagenPopup
│ │ ├── MesswagenPopup.js
│ │ └── index.js
│ ├── NetzkartePopup
│ │ ├── NetzkartePopup.js
│ │ ├── NetzkartePopup.scss
│ │ ├── NetzkartePopup.test.js
│ │ └── index.js
│ ├── PassagierFrequenzenPopup
│ │ ├── PassagierFrequenzenPopup.js
│ │ └── index.js
│ ├── PunctualityPopup
│ │ ├── PunctualityPopup.js
│ │ └── index.js
│ ├── RailplusPopup
│ │ ├── RailplusPopup.js
│ │ ├── RailplusPopup.test.js
│ │ └── index.js
│ ├── RegionenkarteIntersectionPopup
│ │ ├── RegionenkarteIntersectionPopup.js
│ │ └── index.js
│ ├── RegionenkarteSegmentPopup
│ │ ├── Av.js
│ │ ├── Line.js
│ │ ├── LineData.js
│ │ ├── Nl.js
│ │ ├── Person.js
│ │ ├── Region.js
│ │ ├── RegionenkarteSegmentPopup.js
│ │ └── index.js
│ ├── SchmalspurPopup
│ │ ├── SchmalspurPopup.js
│ │ ├── SchmalspurPopup.test.js
│ │ └── index.js
│ ├── StationPopup
│ │ ├── StationPopup.js
│ │ └── index.js
│ ├── StopPlacePopup
│ │ ├── StopPlacePopup.js
│ │ ├── StopPlacePopup.test.js
│ │ └── index.js
│ ├── TarifverbundkartePopup
│ │ ├── TarifverbundkartePopup.js
│ │ └── index.js
│ ├── ZweitausbildungAbroadPopup
│ │ ├── ZweitausbildungAbroadPopup.js
│ │ └── index.js
│ ├── ZweitausbildungPoisPopup
│ │ ├── ZweitausbildungPoisPopup.js
│ │ ├── ZweitausbildungPoisPopup.scss
│ │ └── index.js
│ ├── ZweitausbildungRoutesPopup
│ │ ├── ZweitausbildungRoutesPopup.js
│ │ ├── ZweitausbildungRoutesPopup.scss
│ │ └── index.js
│ └── index.js
├── searches
│ ├── Betriebspunkte
│ │ ├── Betriebspunkte.js
│ │ └── index.js
│ ├── HandicapStopFinder
│ │ ├── HandicapStopFinder.js
│ │ └── index.js
│ ├── Lines
│ │ ├── Lines.js
│ │ ├── Lines.test.js
│ │ └── index.js
│ ├── Locations
│ │ ├── Locations.js
│ │ └── index.js
│ ├── Municipalities
│ │ ├── Municipalities.js
│ │ └── index.js
│ ├── Search.js
│ ├── Search.test.js
│ ├── StopFinder
│ │ ├── StopFinder.js
│ │ ├── StopFinder.test.js
│ │ └── index.js
│ └── index.js
├── setupTests.js
├── styleguidist
│ ├── ComponentsList.js
│ ├── StyleGuide.js
│ └── styleguidist.css
├── themes
│ ├── default.js
│ └── react-ui
│ │ ├── components.scss
│ │ ├── index.scss
│ │ ├── mixins.scss
│ │ └── variables.scss
└── utils
│ ├── LayerService.js
│ ├── LayerService.test.js
│ ├── applyPermalinkVisibility.js
│ ├── applyPermalinkVisibility.test.js
│ ├── capitalizeFirstLetter.js
│ ├── constants.js
│ ├── coordinateHelper.js
│ ├── coordinateHelper.test.js
│ ├── exportUtils.js
│ ├── exportUtils.test.js
│ ├── fontUtils.js
│ ├── fonts
│ ├── SBBWeb-Bold.eot
│ ├── SBBWeb-Bold.ttf
│ ├── SBBWeb-Bold.woff
│ ├── SBBWeb-Bold.woff2
│ ├── SBBWeb-Italic.eot
│ ├── SBBWeb-Italic.ttf
│ ├── SBBWeb-Italic.woff
│ ├── SBBWeb-Italic.woff2
│ ├── SBBWeb-Light.eot
│ ├── SBBWeb-Light.ttf
│ ├── SBBWeb-Light.woff
│ ├── SBBWeb-Light.woff2
│ ├── SBBWeb-Roman.eot
│ ├── SBBWeb-Roman.ttf
│ ├── SBBWeb-Roman.woff
│ ├── SBBWeb-Roman.woff2
│ ├── SBBWeb-Thin.eot
│ ├── SBBWeb-Thin.ttf
│ ├── SBBWeb-Thin.woff
│ ├── SBBWeb-Thin.woff2
│ ├── SBBWeb-UltraLight.eot
│ ├── SBBWeb-UltraLight.ttf
│ ├── SBBWeb-UltraLight.woff
│ └── SBBWeb-UltraLight.woff2
│ ├── formatPhone.js
│ ├── getDelayString.js
│ ├── getDelayString.test.js
│ ├── getFeatureInfoAtCoordinate.js
│ ├── getGreaterNumber.js
│ ├── getGreaterNumber.test.js
│ ├── getIsMobileDevice.js
│ ├── getLayersAsFlatArray.js
│ ├── getPopupComponent.js
│ ├── getQueryableLayers.js
│ ├── getTrafimageFilter.js
│ ├── highlightPointFeatures.js
│ ├── highlightPointStyle.js
│ ├── highlightPointStyle.test.js
│ ├── isoToIntlVehicleCode.js
│ ├── isoToIntlVehicleCode.test.js
│ ├── panCenterFeature.js
│ ├── redirectHelper.js
│ ├── redirectHelper.test.js
│ ├── removeDuplicateFeatures.js
│ ├── toBase64.js
│ ├── trackingUtils.js
│ ├── useDisableIosElasticScrollEffect.js
│ ├── useExportPrintOptions.js
│ ├── useFetch.js
│ ├── useHasScreenSize.js
│ ├── useHighlightLayer.js
│ ├── useHighlightSomeFeatures.js
│ ├── useHighlightSomeFeatures.test.js
│ ├── useIndexedFeatureInfo.js
│ ├── useMaxCanvasSize.js
│ ├── useOverlayWidth.js
│ ├── usePanCenterFeature.js
│ ├── usePrevious.js
│ ├── useUpdateFeatureInfoOnLayerToggle.js
│ └── useUpdateFeatureInfoOnLayerToggle.test.js
├── styleguide.config.js
└── yarn.lock
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | const eslintConfig = {
2 | env: {
3 | node: true,
4 | browser: true,
5 | es6: true,
6 | jest: true,
7 | "cypress/globals": true,
8 | },
9 | parserOptions: {
10 | ecmaVersion: "latest",
11 | jsx: true,
12 | impliedStrict: true,
13 | },
14 | extends: ["airbnb", "airbnb/hooks", "prettier"],
15 | plugins: ["cypress", "prettier"],
16 | rules: {
17 | "linebreak-style": 0,
18 | "arrow-body-style": 0,
19 | "default-param-last": 0,
20 | "no-restricted-exports": 0,
21 | "react/jsx-filename-extension": [
22 | 1,
23 | {
24 | extensions: [".js", ".jsx"],
25 | },
26 | ],
27 | "react/forbid-prop-types": "Off",
28 | "react/jsx-props-no-spreading": "Off",
29 | "react/require-default-props": "Off",
30 | "prettier/prettier": "error",
31 | },
32 | settings: {
33 | react: {
34 | version: "detect",
35 | },
36 | },
37 | };
38 |
39 | module.exports = eslintConfig;
40 |
--------------------------------------------------------------------------------
/.fixpackrc:
--------------------------------------------------------------------------------
1 | {
2 | "sortToTop": [
3 | "name",
4 | "license",
5 | "description",
6 | "version",
7 | "author",
8 | "homepage",
9 | "private",
10 | "main",
11 | "module",
12 | "files",
13 | "exports",
14 | "proxy",
15 | "dependencies",
16 | "peerDependencies",
17 | "devDependencies",
18 | "resolutions",
19 | "scripts"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/.github/workflows/conventional-pr-title.yml:
--------------------------------------------------------------------------------
1 | name: Check PR title
2 | on:
3 | pull_request:
4 | types:
5 | - opened
6 | - reopened
7 | - edited
8 | - synchronize
9 |
10 | # permissions for dependabot PRs
11 | permissions:
12 | actions: read
13 | checks: read
14 | contents: read
15 | deployments: read
16 | id-token: write
17 | issues: read
18 | discussions: read
19 | packages: read
20 | pages: read
21 | pull-requests: read
22 | repository-projects: read
23 | security-events: read
24 | statuses: write
25 |
26 | jobs:
27 | lint:
28 | runs-on: ubuntu-latest
29 | steps:
30 | - uses: aslafy-z/conventional-pr-title-action@v3
31 | with:
32 | success-state: Title follows the specification.
33 | failure-state: Title does not follow the specification.
34 | context-name: conventional-pr-title
35 | env:
36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37 |
--------------------------------------------------------------------------------
/.github/workflows/cypress-chrome.yml:
--------------------------------------------------------------------------------
1 | name: Cypress Chrome
2 |
3 | on: [push]
4 |
5 | jobs:
6 | run:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - name: Checkout
10 | uses: actions/checkout@v3
11 |
12 | - name: Setup node
13 | uses: actions/setup-node@v3
14 | with:
15 | node-version-file: '.nvmrc'
16 |
17 | - name: Cypress install
18 | uses: cypress-io/github-action@v5
19 | with:
20 | runTests: false
21 | # report machine parameters
22 | - run: yarn cypress info
23 | - run: node --version
24 | - run: node -p 'os.cpus()'
25 | - run: yarn cy:test:chrome
26 |
--------------------------------------------------------------------------------
/.github/workflows/cypress-edge.yml:
--------------------------------------------------------------------------------
1 | name: Cypress Edge
2 |
3 | on: [push]
4 |
5 | jobs:
6 | run:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - name: Checkout
10 | uses: actions/checkout@v3
11 |
12 | - name: Setup node
13 | uses: actions/setup-node@v3
14 | with:
15 | node-version-file: '.nvmrc'
16 |
17 | - name: Cypress install
18 | uses: cypress-io/github-action@v5
19 | with:
20 | runTests: false
21 | # report machine parameters
22 | - run: yarn cypress info
23 | - run: node --version
24 | - run: node -p 'os.cpus()'
25 | - run: yarn cy:test:edge
26 |
--------------------------------------------------------------------------------
/.github/workflows/cypress-firefox.yml:
--------------------------------------------------------------------------------
1 | name: Cypress Firefox
2 |
3 | on: [push]
4 |
5 | jobs:
6 | run:
7 | runs-on: ubuntu-latest
8 | container:
9 | # See images at https://github.com/cypress-io/cypress-docker-images/tree/master/browsers
10 | image: cypress/browsers:latest
11 | options: --user 1001
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v3
15 |
16 | - name: Setup node
17 | uses: actions/setup-node@v3
18 | with:
19 | node-version-file: '.nvmrc'
20 |
21 | - name: Cypress install
22 | uses: cypress-io/github-action@v5
23 | with:
24 | runTests: false
25 | # report machine parameters
26 | - run: yarn cypress info
27 | - run: node --version
28 | - run: node -p 'os.cpus()'
29 | - run: yarn cy:test:firefox
30 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Lint / Test
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - uses: actions/checkout@v3
11 | - uses: actions/setup-node@v3
12 | with:
13 | node-version-file: '.nvmrc'
14 | - run: npm install -g yarn
15 | - run: yarn install --frozen-lockfile
16 | - run: yarn lint
17 | - run: yarn test
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # others
7 | /doc
8 | /docjs
9 |
10 | # testing
11 | /coverage
12 |
13 | # production
14 | /build
15 |
16 | #scripts
17 | /scripts/venv
18 |
19 | # misc
20 | .vscode
21 | .DS_Store
22 | .env.local
23 | .env.development.local
24 | .env.test.local
25 | .env.production.local
26 |
27 | npm-debug.log*
28 | yarn-debug.log*
29 | yarn-error.log*
30 |
31 | *.swp
32 | *.swo
33 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | yarn commitlint --edit $1
2 |
--------------------------------------------------------------------------------
/.husky/post-checkout:
--------------------------------------------------------------------------------
1 | yarn install --frozen-lockfile
2 |
--------------------------------------------------------------------------------
/.husky/post-merge:
--------------------------------------------------------------------------------
1 | yarn install --frozen-lockfile
2 |
--------------------------------------------------------------------------------
/.husky/post-rebase:
--------------------------------------------------------------------------------
1 | yarn install --frozen-lockfile
2 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | CI=true npx lint-staged
2 |
--------------------------------------------------------------------------------
/.imgbotconfig:
--------------------------------------------------------------------------------
1 | {
2 | "ignoredFiles": ["cypress/*"],
3 | "aggressiveCompression": "false"
4 | }
5 |
--------------------------------------------------------------------------------
/.lintstagedrc.js:
--------------------------------------------------------------------------------
1 | const lintStaged = {
2 | "*.md": ["prettier --write"],
3 | "src/lang/*.json": ["yarn sort", "git add"],
4 | "(src|__mocks__)/**/*.js": [
5 | "eslint --fix",
6 | "prettier --write",
7 | "git add",
8 | "yarn test --bail --findRelatedTests",
9 | ],
10 | "src/**/*.scss": ["stylelint --fix", "git add"],
11 | "package.json": ["yarn fixpack", "git add"],
12 | };
13 | module.exports = lintStaged;
14 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 20
2 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/.stylelintrc.js:
--------------------------------------------------------------------------------
1 | const stylelint = {
2 | plugins: ["stylelint-scss"],
3 | extends: ["stylelint-config-standard", "stylelint-config-recommended-scss"],
4 | rules: {
5 | "import-notation": "string",
6 | "scss/at-import-partial-extension": "always",
7 | "scss/load-partial-extension": null,
8 | "selector-pseudo-class-no-unknown": [
9 | true,
10 | {
11 | ignorePseudoClasses: ["export"],
12 | },
13 | ],
14 | "property-no-unknown": [
15 | true,
16 | {
17 | ignoreProperties: ["/transitiondelay/"],
18 | },
19 | ],
20 | },
21 | };
22 |
23 | module.exports = stylelint;
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 geOps
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/babel.config.json:
--------------------------------------------------------------------------------
1 | // This babel config is used by babel-eslint (using yarn lint and yarn build)
2 | {
3 | "presets": ["@babel/preset-env", "@babel/preset-react"]
4 | }
5 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = { extends: ["@commitlint/config-conventional"] };
2 |
--------------------------------------------------------------------------------
/cypress.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies */
2 | const { defineConfig } = require("cypress");
3 |
4 | module.exports = defineConfig({
5 | requestTimeout: 20000,
6 | defaultCommandTimeout: 20000,
7 | retries: {
8 | // Configure retry attempts for `cypress run`
9 | // Default is 0
10 | runMode: 3,
11 | // Configure retry attempts for `cypress open`
12 | // Default is 0
13 | openMode: 0,
14 | },
15 | e2e: {
16 | baseUrl: "http://localhost:3000",
17 | numTestsKeptInMemory: 0,
18 | chromeWebSecurity: false,
19 | video: false,
20 |
21 | // We've imported your old cypress plugins here.
22 | // You may want to clean this up later by importing these.
23 | setupNodeEvents(on, config) {
24 | // eslint-disable-next-line global-require, import/extensions
25 | return require("./cypress/plugins/index.js")(on, config);
26 | },
27 | },
28 | });
29 |
--------------------------------------------------------------------------------
/cypress/e2e/ch.sbb.geltungsbereiche-iframe.cy.js:
--------------------------------------------------------------------------------
1 | describe("Geltungsbereiche iframe topic", () => {
2 | beforeEach(() => {
3 | cy.consent();
4 | cy.visit("/ch.sbb.geltungsbereiche-iframe");
5 | });
6 |
7 | it("should show/hide some elements", () => {
8 | cy.viewport(1440, 900);
9 | cy.get(".tm-trafimage-maps").should("exist");
10 |
11 | // header + telephoneinfos
12 | cy.get(".wkp-header").should("not.exist");
13 | // search
14 | cy.get(".wkp-search").should("not.exist");
15 | // telephoneInfos
16 | cy.get('[data-testid="wkp-tel-infos"]').should("not.exist");
17 | // menu
18 | cy.get(".wkp-topics-menu").should("not.exist");
19 | // baseLayerSwitcher
20 | cy.get(".rs-base-layer-switcher").should("not.exist");
21 | // mapControls
22 | cy.get(".wkp-map-controls").should("exist");
23 | // geolocationButton
24 | cy.get(".wkp-fit-extent").should("exist");
25 | // fitExtent
26 | cy.get(".wkp-geolocation").should("not.exist");
27 | // footer
28 | cy.get(".wkp-footer").should("not.exist");
29 |
30 | // topicMenu
31 | cy.get(".wkp-gb-topic-menu").should("exist");
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/cypress/e2e/ch.sbb.handicap.cy.js:
--------------------------------------------------------------------------------
1 | import lang from "../../src/lang/de.json";
2 |
3 | describe("Handicap Topic", () => {
4 | beforeEach(() => {
5 | cy.consent();
6 | cy.visit("/ch.sbb.handicap");
7 | cy.get(".wkp-menu-header ").click();
8 | });
9 |
10 | it("should open a popup on station search.", () => {
11 | cy.viewport(1440, 900);
12 | cy.get(".wkp-feature-information").should("not.exist");
13 |
14 | // In handicap topic
15 | cy.get(".wkp-menu-header .wkp-menu-title", { timeout: 10000 }).contains(
16 | lang["ch.sbb.handicap"],
17 | );
18 |
19 | cy.get(".wkp-search-input input")
20 | .focus()
21 | .type("B")
22 | .type("e")
23 | .type("r")
24 | .type("n");
25 |
26 | cy.wait(1000);
27 |
28 | cy.get("#react-autowhatever-1-section-0-item-0", { timeout: 10000 }).click({
29 | force: true,
30 | });
31 |
32 | // Popup is opened.
33 | cy.get(".wkp-feature-information", { timeout: 20000 }).should("be.visible");
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/cypress/e2e/ch.sbb.infrastruktur.cy.js:
--------------------------------------------------------------------------------
1 | describe("Infrastruktur topic", () => {
2 | beforeEach(() => {
3 | cy.consent();
4 | });
5 |
6 | [
7 | "/ch.sbb.infrastruktur",
8 | "/ch.sbb.infrastruktur?layers=", // TRAFKLEIN-726
9 | ].forEach((url) => {
10 | describe(`when loading directly the topic witht url ${url}`, () => {
11 | beforeEach(() => {
12 | cy.visit(url);
13 | });
14 |
15 | it("should display the baselayer", () => {
16 | cy.viewport(1440, 900);
17 | cy.get(".maplibregl-map").should("exist");
18 | });
19 | });
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/cypress/e2e/ch.sbb.tarifverbundkarte.public.cy.js:
--------------------------------------------------------------------------------
1 | describe("Tarifverbundkarte topic", () => {
2 | beforeEach(() => {
3 | cy.consent();
4 | });
5 |
6 | [
7 | "/ch.sbb.tarifverbundkarte.public",
8 | "/ch.sbb.tarifverbundkarte.public?layers=", // TRAFKLEIN-726
9 | ].forEach((url) => {
10 | describe(`when loading directly the topic witht url ${url}`, () => {
11 | beforeEach(() => {
12 | cy.visit(url);
13 | });
14 |
15 | it("should display the baselayer", () => {
16 | cy.viewport(1440, 900);
17 | cy.get(".maplibregl-map").should("exist");
18 | });
19 |
20 | it("should open a popup on click", () => {
21 | cy.viewport(1440, 900);
22 | cy.get(".maplibregl-map canvas").then(() => {
23 | cy.wait(5000);
24 | cy.get(".rs-map").click("center");
25 | cy.get(".wkp-feature-information").should("be.visible");
26 | });
27 | });
28 | });
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/cypress/e2e/consent.cy.js:
--------------------------------------------------------------------------------
1 | describe("consent", () => {
2 | it(`opens consent banner`, () => {
3 | cy.visit("");
4 | cy.get("#onetrust-accept-btn-handler", { timeout: 10000 }).click();
5 | });
6 | });
7 |
--------------------------------------------------------------------------------
/cypress/fixtures/busAtZoom14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/cypress/fixtures/busAtZoom14.png
--------------------------------------------------------------------------------
/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io",
4 | "body": "Fixtures are a great way to mock data for responses to routes"
5 | }
--------------------------------------------------------------------------------
/cypress/fixtures/fullTrajectory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/cypress/fixtures/fullTrajectory.png
--------------------------------------------------------------------------------
/cypress/fixtures/noBusAtZoom9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/cypress/fixtures/noBusAtZoom9.png
--------------------------------------------------------------------------------
/cypress/plugins/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies */
2 | ///
3 | ///
4 | // @ts-check
5 | const resemble = require("resemblejs");
6 |
7 | /**
8 | * @type {Cypress.PluginConfig}
9 | */
10 | module.exports = (on) => {
11 | on("task", {
12 | log(message) {
13 | // eslint-disable-next-line no-console
14 | console.log(message);
15 | return Promise.resolve(null);
16 | },
17 | comparePng({ current, fixture }) {
18 | const diff = resemble(fixture).compareTo(current);
19 | // eslint-disable-next-line no-promise-executor-return
20 | return new Promise((resolve) => diff.onComplete(resolve));
21 | },
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/cypress/support/commands.js:
--------------------------------------------------------------------------------
1 | // ***********************************************
2 | // This example commands.js shows you how to
3 | // create various custom commands and overwrite
4 | // existing commands.
5 | //
6 | // For more comprehensive examples of custom
7 | // commands please read more here:
8 | // https://on.cypress.io/custom-commands
9 | // ***********************************************
10 | //
11 | //
12 | // -- This is a parent command --
13 | // Cypress.Commands.add("login", (email, password) => { ... })
14 | //
15 | //
16 | // -- This is a child command --
17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
18 | //
19 | //
20 | // -- This is a dual command --
21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
22 | //
23 | //
24 | // -- This will overwrite an existing command --
25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
26 |
--------------------------------------------------------------------------------
/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Cnfiguration file that:
2 | # - Enables security updates
3 | # - Disables version-updates
4 |
5 | version: 2
6 | updates:
7 | - package-ecosystem: 'npm'
8 | directory: '/'
9 | schedule:
10 | interval: 'daily'
11 | # Disable version updates for npm dependencies
12 | open-pull-requests-limit: 0
13 |
--------------------------------------------------------------------------------
/packages/es/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["@babel/preset-env", { "modules": false }],
4 | "@babel/preset-react"
5 | ],
6 | "ignore": ["**/*.test.js"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/es/index.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/no-unresolved
2 | import TrafimageMaps from './components/TrafimageMaps';
3 |
4 | export default TrafimageMaps;
5 |
--------------------------------------------------------------------------------
/public/embed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 | Trafimage Webkarten
10 |
11 |
18 |
19 |
20 |
21 |
Test web component in custom page
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/public/favicon.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Geops Starter",
3 | "name": "geops-react-spatial-starter",
4 | "icons": [
5 | {
6 | "src": "favicon.png",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # How to
2 |
3 |
4 |
5 | # Others
6 |
7 |
8 |
9 | - [ ] It's not a hack or at least an unauthorized hack :).
10 | - [ ] The images added are optimized.
11 | - [ ] Everything in ticket description has been fixed.
12 | - [ ] The author of the MR has made its own review before assigning the reviewer.
13 | - [ ] The title means something for a human being and follows the [conventional commits](https://www.conventionalcommits.org/) specification.
14 | - [ ] The title contains [WIP] if it's necessary.
15 | - [ ] Labels applied. if it's a release? a hotfix?
16 | - [ ] Check the preview app on iOS before merge: Is everything working? SVGs visible?
17 | - [ ] Tests added.
18 |
--------------------------------------------------------------------------------
/scripts/build-es.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ###
4 | # This script build a folder you can use via import es6 module.
5 | ###
6 |
7 | # Remove the old files.
8 | if rm -rf build/es; then
9 | echo "Build folder emptied."
10 | else
11 | echo "Empty build/es folder failed."
12 | exit 1
13 | fi
14 |
15 | # Transform all es6 files to es5.
16 | # Transform jsx to js.
17 | # Transform .scss import to .css import.
18 | # Creates also js sourcemaps.
19 | if NODE_ENV=production ./node_modules/.bin/babel src --config-file './packages/es/.babelrc' --out-dir build/es --source-maps --copy-files; then
20 | # if NODE_ENV=production yarn esbuild; then
21 | echo "Transformation suceeds."
22 | else
23 | echo "Compile the 'src' directory failed."
24 | exit 1
25 | fi
26 |
27 | # Remove all tests files.
28 | if find build/es -regextype posix-extended -regex '.*(test).*js.?(map|snap)?$' -type f | xargs rm -f; then
29 | echo "All test files removed."
30 | else
31 | echo "Remove tests files failed."
32 | exit 1
33 | fi
34 |
35 | # Move the index.js file to build/es
36 | cp -f packages/es/index.js build/es
37 |
--------------------------------------------------------------------------------
/scripts/prepare-package.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const path = require("path");
3 | const pkg = require("../package.json");
4 |
5 | const buildDir = path.resolve(__dirname, "../build/");
6 |
7 | // Write out simplified package.json to be able to publish only the build
8 | // folder content.
9 | delete pkg.scripts;
10 | delete pkg.devDependencies;
11 | delete pkg.style;
12 | delete pkg.eslintConfig;
13 | delete pkg.private;
14 | delete pkg.dependencies["react-styleguidist"];
15 |
16 | // Write the good index file import for es6 module loading.
17 | pkg.main = "bundle.js";
18 | fs.writeFileSync(
19 | path.join(buildDir, "package.json"),
20 | JSON.stringify(pkg, null, 2),
21 | "utf-8",
22 | );
23 |
--------------------------------------------------------------------------------
/scripts/read-pkg-json.js:
--------------------------------------------------------------------------------
1 | const pjson = require("../package.json");
2 |
3 | const { peerDependencies } = pjson;
4 |
5 | const packageKeys = Object.keys(peerDependencies || {});
6 |
7 | const arg = process.argv[2];
8 |
9 | if (arg === "add" && packageKeys.length > 0) {
10 | console.log(
11 | `yarn add ${packageKeys
12 | .map((p) => `${p}@${peerDependencies[p]}`)
13 | .join(" ")}`,
14 | );
15 | } else if (arg === "remove" && packageKeys.length > 0) {
16 | console.log(
17 | `rm -rf ${packageKeys.map((p) => `node_modules/${p}`).join(" ")}`,
18 | );
19 | } else {
20 | console.log('echo "wrong argument."');
21 | }
22 |
--------------------------------------------------------------------------------
/scripts/requirements.txt:
--------------------------------------------------------------------------------
1 | certifi==2022.12.7
2 | charset-normalizer==2.0.7
3 | geojson==2.5.0
4 | idna==3.3
5 | psycopg2-binary==2.9.1
6 | requests==2.26.0
7 | urllib3==1.26.7
8 |
--------------------------------------------------------------------------------
/src/__mocks__/@jonkoops/matomo-tracker-react.js:
--------------------------------------------------------------------------------
1 | const {
2 | MatomoProvider: MP,
3 | MatomoContext: MC,
4 | useMatomo: uM,
5 | createInstance: cI,
6 | } = require("@jonkoops/matomo-tracker-react");
7 |
8 | const createInstanceTmp = jest.fn((params) => {
9 | const inst = cI(params);
10 | inst.pushInstruction = jest.fn();
11 |
12 | // Store the lastinstance for testing
13 | createInstanceTmp.lastInstance = inst;
14 | return inst;
15 | });
16 |
17 | export const createInstance = createInstanceTmp;
18 | export const useMatomo = uM;
19 | export const MatomoContext = MC;
20 | export const MatomoProvider = MP;
21 |
--------------------------------------------------------------------------------
/src/__mocks__/mapbox-gl.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable class-methods-use-this */
2 | class Map {
3 | isStyleLoaded() {}
4 |
5 | loaded() {}
6 |
7 | getCanvas() {}
8 |
9 | on() {}
10 |
11 | off() {}
12 |
13 | once() {}
14 |
15 | getLayer() {}
16 | }
17 | module.exports = {
18 | Map,
19 | };
20 |
--------------------------------------------------------------------------------
/src/__mocks__/maplibre-gl.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable class-methods-use-this */
2 | class Map {
3 | isStyleLoaded() {}
4 |
5 | loaded() {}
6 |
7 | getCanvas() {}
8 |
9 | on() {}
10 |
11 | off() {}
12 |
13 | once() {}
14 |
15 | getLayer() {}
16 | }
17 | module.exports = {
18 | Map,
19 | };
20 |
--------------------------------------------------------------------------------
/src/__mocks__/resize-observer-polyfill.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export default class ResizeObserver {
3 | constructor(onResize) {
4 | ResizeObserver.onResize = onResize;
5 | }
6 | observe() {}
7 | unobserve() {}
8 | disconnect() {}
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/Autocomplete/Autocomplete.md.scss:
--------------------------------------------------------------------------------
1 | .tm-autocomplete-example {
2 | position: relative;
3 | width: 420px;
4 | height: 44px;
5 |
6 | .tm-button {
7 | padding: 0 $padding-base;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/Autocomplete/Autocomplete.scss:
--------------------------------------------------------------------------------
1 | .tm-autocomplete {
2 | .tm-search {
3 | color: $gray-dark;
4 | }
5 |
6 | .tm-autocomplete-results,
7 | .tm-search-input {
8 | border: 2px solid $gray-lighter;
9 | }
10 |
11 | .tm-bt-clear {
12 | color: black;
13 | }
14 |
15 | .tm-autocomplete-results {
16 | position: absolute;
17 | margin: auto;
18 | border-top: none;
19 | top: calc(100% - 1px);
20 | left: 0;
21 | right: 0;
22 | background-color: white;
23 | overflow: auto;
24 | max-height: 400px;
25 | z-index: $zindex-higher;
26 |
27 | p {
28 | font-size: 0.9em;
29 | font-weight: bold;
30 | color: $gray-light;
31 | padding: 5px 15px 2px;
32 | margin: 0;
33 | }
34 |
35 | ul:first-child {
36 | margin-top: 8px;
37 | }
38 |
39 | li {
40 | &:hover,
41 | &:focus {
42 | color: $btn-primary-color;
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/components/Autocomplete/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Autocomplete";
2 |
--------------------------------------------------------------------------------
/src/components/Button/Button.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 |
4 | const propTypes = {
5 | children: PropTypes.node.isRequired,
6 | onClick: PropTypes.func.isRequired,
7 | disabled: PropTypes.bool,
8 | };
9 |
10 | /**
11 | * This component displays a simple button.
12 | * @ignore
13 | */
14 | function Button({ children, disabled = false, onClick, ...props }) {
15 | return (
16 | {
21 | if (disabled) {
22 | return;
23 | }
24 | onClick(e);
25 | }}
26 | onKeyPress={(e) => e.which === 13 && onClick(e)}
27 | >
28 | {children}
29 |
30 | );
31 | }
32 |
33 | Button.propTypes = propTypes;
34 |
35 | export default Button;
36 |
--------------------------------------------------------------------------------
/src/components/Button/Button.md.scss:
--------------------------------------------------------------------------------
1 | .tm-button-example {
2 | cursor: pointer;
3 | color: $btn-primary-color;
4 | border-radius: 15px;
5 | width: 100px;
6 | text-align: center;
7 | border: 3px solid $btn-primary-color;
8 | padding: 10px;
9 | transition: background-color 0.1s ease;
10 |
11 | &:hover {
12 | background-color: $gray-lighter;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/Button/Button.scss:
--------------------------------------------------------------------------------
1 | .tm-button {
2 | cursor: pointer;
3 | height: $btn-size-base;
4 | width: $btn-size-base;
5 | display: flex;
6 | justify-content: center;
7 | align-items: center;
8 | transition: background-color 0.5s ease, color 0.5s ease;
9 | }
10 |
11 | .tm-round-blue {
12 | background: $btn-secondary-color;
13 | border-radius: 50%;
14 | color: white;
15 | }
16 |
17 | .tm-square-white {
18 | border: 1px solid #aaa;
19 | background: white;
20 | color: #aaa;
21 |
22 | &.tm-active {
23 | background-color: $btn-secondary-color-active;
24 | }
25 | }
26 |
27 | .tm-round-grey-hover-primary {
28 | background-color: $gray-light;
29 | border-radius: 50%;
30 | color: white;
31 |
32 | &:hover {
33 | background-color: $btn-primary-color-hover;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/Button/Button.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { fireEvent, render } from "@testing-library/react";
3 | import Button from "./Button";
4 |
5 | const funcs = {
6 | onClick: () => {},
7 | };
8 |
9 | test("Button should match snapshot.", () => {
10 | const { container } = render(
11 | ,
18 | );
19 | expect(container.innerHTML).toMatchSnapshot();
20 | });
21 |
22 | test("Button should update.", () => {
23 | const spy = jest.spyOn(funcs, "onClick");
24 | const { container } = render(
25 | ,
28 | );
29 |
30 | fireEvent.click(container.querySelector(".tm-class"));
31 | fireEvent.keyPress(container.querySelector(".tm-class"), {
32 | key: "Enter",
33 | code: "Enter",
34 | charCode: 13,
35 | which: 13,
36 | });
37 |
38 | expect(spy).toHaveBeenCalledTimes(2);
39 | });
40 |
--------------------------------------------------------------------------------
/src/components/Button/__snapshots__/Button.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Button should match snapshot. 1`] = `
4 |
9 | +
10 |
11 | `;
12 |
--------------------------------------------------------------------------------
/src/components/Button/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Button";
2 |
--------------------------------------------------------------------------------
/src/components/CloseButton/CloseButton.js:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types";
2 | import { IconButton } from "@mui/material";
3 | import React from "react";
4 | import { MdClose } from "react-icons/md";
5 | import { useTranslation } from "react-i18next";
6 |
7 | function CloseButton({ children, ...props }) {
8 | const { t } = useTranslation();
9 | return (
10 |
20 | {children || }
21 |
22 | );
23 | }
24 |
25 | CloseButton.propTypes = {
26 | children: PropTypes.node,
27 | };
28 |
29 | export default CloseButton;
30 |
--------------------------------------------------------------------------------
/src/components/CloseButton/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./CloseButton";
2 |
--------------------------------------------------------------------------------
/src/components/Collapsible/Collapsible.scss:
--------------------------------------------------------------------------------
1 | .wkp-collapsible-vertical {
2 | overflow: hidden auto;
3 | transition: max-height 0.3s ease;
4 | }
5 |
6 | .wkp-collapsible-hide-scrollbar::-webkit-scrollbar {
7 | display: none;
8 | }
9 |
10 | .wkp-collapsible-horizontal {
11 | overflow: hidden;
12 | transition: max-width 0.3s ease;
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/Collapsible/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Collapsible";
2 |
--------------------------------------------------------------------------------
/src/components/Copyright/Copyright.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useTranslation } from "react-i18next";
3 | import { useSelector } from "react-redux";
4 | import RsCopyright from "react-spatial/components/Copyright";
5 | import { makeStyles } from "@mui/styles";
6 |
7 | const useStyles = makeStyles(() => ({
8 | wrapper: {
9 | position: "absolute",
10 | right: 5,
11 | paddingLeft: 5,
12 | fontSize: 12,
13 | bottom: ({ footer }) => (footer ? 42 : 2),
14 | "& a:not(.MuiIconButton-root)": {
15 | whiteSpace: "nowrap",
16 | textDecoration: "none !important",
17 | },
18 | },
19 | }));
20 |
21 | function Copyright() {
22 | const { t } = useTranslation();
23 | const topic = useSelector((state) => state.app.activeTopic);
24 | const map = useSelector((state) => state.app.map);
25 | const classes = useStyles({ footer: topic.elements.footer });
26 |
27 | return (
28 |
29 | `${t("Geodaten")} ${f.join(", ")}`}
32 | />
33 |
34 | );
35 | }
36 |
37 | export default Copyright;
38 |
--------------------------------------------------------------------------------
/src/components/Copyright/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Copyright";
2 |
--------------------------------------------------------------------------------
/src/components/DataLink/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DataLink";
2 |
--------------------------------------------------------------------------------
/src/components/Dialog/Dialog.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Provider } from "react-redux";
4 |
5 | import { Map, View } from "ol";
6 | import { render } from "@testing-library/react";
7 | import { ThemeProvider } from "@mui/material";
8 | import theme from "../../themes/default";
9 | import Dialog from "./Dialog";
10 |
11 | describe("Dialog", () => {
12 | let store;
13 | let map;
14 |
15 | beforeEach(() => {
16 | store = global.mockStore({
17 | map: {},
18 | app: {},
19 | });
20 | map = new Map({ view: new View({}) });
21 | });
22 |
23 | test("should match snapshot.", () => {
24 | const component = render(
25 |
26 |
27 |
28 |
29 | ,
30 | );
31 | expect(component.container.innerHTML).toMatchSnapshot();
32 | });
33 |
34 | // TODO: test focus document.activeElement on popup close
35 | });
36 |
--------------------------------------------------------------------------------
/src/components/Dialog/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Dialog";
2 |
--------------------------------------------------------------------------------
/src/components/Draw/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Draw";
2 |
--------------------------------------------------------------------------------
/src/components/DrawButton/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DrawButton";
2 |
--------------------------------------------------------------------------------
/src/components/DrawEditLinkInput/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DrawEditLinkInput";
2 |
--------------------------------------------------------------------------------
/src/components/DrawLayerMenu/DrawLayerMenu.scss:
--------------------------------------------------------------------------------
1 | .wkp-draw-layer-menu {
2 | .wkp-layer-tree,
3 | .wkp-layer-tree .rs-layer-tree-item {
4 | margin: 0;
5 |
6 | .rs-layer-tree-toggle {
7 | max-width: none;
8 | }
9 |
10 | .rs-checkbox {
11 | margin-right: 7px;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/DrawLayerMenu/__snapshots__/DrawLayerMenu.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`DrawLayerMenu should match snapshot. should return null 1`] = `""`;
4 |
5 | exports[`DrawLayerMenu should match snapshot. using the layerService property 1`] = `
6 |
12 | `;
13 |
--------------------------------------------------------------------------------
/src/components/DrawLayerMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DrawLayerMenu";
2 |
--------------------------------------------------------------------------------
/src/components/DrawPermalinkButton/DrawPermalinkButton.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Provider } from "react-redux";
3 |
4 | import { ThemeProvider } from "@mui/material";
5 | import { render } from "@testing-library/react";
6 | import theme from "../../themes/default";
7 | import DrawPermalinkButton from ".";
8 |
9 | describe("DrawPermalinkButton", () => {
10 | let store;
11 | test("should match snapshot.", () => {
12 | store = global.mockStore({
13 | map: {},
14 | app: { drawIds: {} },
15 | });
16 |
17 | const component = render(
18 |
19 |
20 |
21 |
22 | ,
23 | );
24 | expect(
25 | component.container.querySelectorAll(".wkp-permalink-bt").length,
26 | ).toBe(1);
27 | expect(component.container.querySelectorAll("button").length).toBe(1);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/DrawPermalinkButton/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DrawPermalinkButton";
2 |
--------------------------------------------------------------------------------
/src/components/DrawRemoveDialog/index.js:
--------------------------------------------------------------------------------
1 | export { default, NAME } from "./DrawRemoveDialog";
2 |
--------------------------------------------------------------------------------
/src/components/ExportButton/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ExportButton";
2 |
--------------------------------------------------------------------------------
/src/components/ExportButton/northArrowCircle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/components/ExportButton/northArrowCircle.png
--------------------------------------------------------------------------------
/src/components/FadeShadow/FadeShadow.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { makeStyles } from "@mui/styles";
3 |
4 | const useStyles = makeStyles(() => {
5 | return {
6 | topShadow: {
7 | position: "absolute",
8 | overflow: "hidden",
9 | width: "100%",
10 | height: 80,
11 | pointerEvents: "none",
12 | "&::after": {
13 | content: '""',
14 | position: "absolute",
15 | left: 0,
16 | right: 0,
17 | top: -20,
18 | bottom: 0,
19 | zIndex: 1,
20 | height: 20,
21 | background: "#18191B",
22 | opacity: 0.2,
23 | borderRadius: "600px / 50px",
24 | filter: "blur(15px)",
25 | },
26 | },
27 | };
28 | });
29 |
30 | // Unused component for now (does not work on iOS), but we keep it for now in case it becomes iOS compatible
31 | function FadeShadow() {
32 | const classes = useStyles();
33 | return ;
34 | }
35 |
36 | export default FadeShadow;
37 |
--------------------------------------------------------------------------------
/src/components/FadeShadow/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./FadeShadow";
2 |
--------------------------------------------------------------------------------
/src/components/FeatureInformation/FeatureInformation.scss:
--------------------------------------------------------------------------------
1 | .wkp-feature-information {
2 | .wkp-feature-information-header {
3 | display: flex;
4 | align-items: center;
5 | justify-content: space-between;
6 | background-color: #f5f5f5;
7 | font-family: SBBWeb-Bold, Arial, sans-serif;
8 | min-height: 40px;
9 | max-height: 60px;
10 |
11 | > span {
12 | display: flex;
13 | align-items: center;
14 | padding: 10px 0 10px 10px;
15 | height: 100%;
16 | overflow: hidden;
17 | }
18 | }
19 |
20 | .wkp-feature-information-body {
21 | > div:first-child {
22 | padding: 10px;
23 | min-width: 220px;
24 | overflow: auto;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/FeatureInformation/FeaturePagination.scss:
--------------------------------------------------------------------------------
1 | .wkp-pagination-wrapper {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 | height: 35px;
6 |
7 | .wkp-pagination-button-wrapper {
8 | padding: 0 10px;
9 | height: 25px;
10 | width: 25px;
11 |
12 | .wkp-pagination-button {
13 | height: 25px;
14 | width: 25px;
15 | cursor: pointer;
16 |
17 | svg {
18 | height: 25px;
19 | width: 25px;
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/FeatureInformation/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./FeatureInformation";
2 |
--------------------------------------------------------------------------------
/src/components/FeatureMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./FeatureMenu";
2 |
--------------------------------------------------------------------------------
/src/components/FloorSwitcher/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./FloorSwitcher";
2 |
--------------------------------------------------------------------------------
/src/components/Footer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Footer";
2 |
--------------------------------------------------------------------------------
/src/components/Head/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Head";
2 |
--------------------------------------------------------------------------------
/src/components/Header/Header.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import Login from "../Login";
4 | import { ReactComponent as SBBLogo } from "../../img/sbb-logo.svg";
5 | import LanguageSelect from "../LanguageSelect";
6 |
7 | import "./Header.scss";
8 |
9 | const propTypes = {
10 | loginUrl: PropTypes.string,
11 | };
12 |
13 | function Header({ loginUrl }) {
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | );
25 | }
26 |
27 | Header.propTypes = propTypes;
28 |
29 | export default React.memo(Header);
30 |
--------------------------------------------------------------------------------
/src/components/Header/Header.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Provider } from "react-redux";
4 |
5 | import { render } from "@testing-library/react";
6 | import { ThemeProvider } from "@mui/material";
7 | import theme from "../../themes/default";
8 | import Header from "./Header";
9 |
10 | describe("Header", () => {
11 | test("match snapshots", () => {
12 | const store = global.mockStore({
13 | map: {},
14 | app: { language: "fr" },
15 | });
16 | const { container } = render(
17 |
18 |
19 |
20 |
21 | ,
22 | );
23 | expect(container.innerHTML).toMatchSnapshot();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/components/Header/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Header";
2 |
--------------------------------------------------------------------------------
/src/components/IconList/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./IconList";
2 |
--------------------------------------------------------------------------------
/src/components/InfosButton/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./InfosButton";
2 |
--------------------------------------------------------------------------------
/src/components/InputIcon/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./InputIcon";
2 |
--------------------------------------------------------------------------------
/src/components/LanguageSelect/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./LanguageSelect";
2 |
--------------------------------------------------------------------------------
/src/components/LayerInfosDialog/index.js:
--------------------------------------------------------------------------------
1 | export { default, NAME } from "./LayerInfosDialog";
2 |
--------------------------------------------------------------------------------
/src/components/LegalLines/Contact/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Contact";
2 |
--------------------------------------------------------------------------------
/src/components/LegalLines/Imprint/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Imprint";
2 |
--------------------------------------------------------------------------------
/src/components/LegalLines/Legal/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Legal";
2 |
--------------------------------------------------------------------------------
/src/components/LegalLines/LegalLines.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import Contact from "./Contact";
4 | import Legal from "./Legal";
5 | import Imprint from "./Imprint";
6 |
7 | const kontakt = Contact;
8 | const rechtliches = Legal;
9 | const impressum = Imprint;
10 |
11 | const docs = {
12 | kontakt,
13 | rechtliches,
14 | impressum,
15 | };
16 |
17 | const propTypes = {
18 | language: PropTypes.string,
19 | doc: PropTypes.oneOf(Object.keys(docs)),
20 | };
21 |
22 | function LegalLines({ language = "de", doc = Object.keys(docs)[0] }) {
23 | const Comp = docs[doc];
24 | return ;
25 | }
26 |
27 | LegalLines.propTypes = propTypes;
28 |
29 | export default LegalLines;
30 |
--------------------------------------------------------------------------------
/src/components/LegalLines/LegalLines.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "@testing-library/react";
3 | import LegalLines from "./LegalLines";
4 |
5 | describe("LegalLines", () => {
6 | test("uses default properties", () => {
7 | window.console.error = jest.fn().mockImplementation(() => {});
8 | const component = render();
9 | expect(component.container.innerHTML).toMatchSnapshot();
10 | });
11 |
12 | ["rechtliches", "impressum", "kontakt"].forEach((doc) => {
13 | ["de", "fr", "en", "it"].forEach((lng) => {
14 | test(`should match snapshot with doc=${doc} and language=${lng}`, () => {
15 | const component = render();
16 | expect(component.container.innerHTML).toMatchSnapshot();
17 | });
18 | });
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/src/components/LegalLines/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./LegalLines";
2 |
--------------------------------------------------------------------------------
/src/components/Link/Link.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import { Link as MuiLink } from "@mui/material";
4 | import { ReactComponent as LinkIcon } from "./Link.svg";
5 |
6 | const propTypes = {
7 | href: PropTypes.string.isRequired,
8 | children: PropTypes.node.isRequired,
9 | className: PropTypes.string,
10 | };
11 |
12 | function Link({ href, children, className = "" }) {
13 | return (
14 |
32 | {children}
33 |
34 |
35 | );
36 | }
37 |
38 | Link.propTypes = propTypes;
39 |
40 | export default Link;
41 |
--------------------------------------------------------------------------------
/src/components/Link/Link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Link/Link.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "@testing-library/react";
3 | import Link from ".";
4 |
5 | describe("Link", () => {
6 | test("should match snapshot.", () => {
7 | const component = render(geOps);
8 | expect(component.container.innerHTML).toMatchSnapshot();
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/src/components/Link/__snapshots__/Link.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Link should match snapshot. 1`] = `
4 |
9 |
10 | geOps
11 |
12 |
15 |
16 | `;
17 |
--------------------------------------------------------------------------------
/src/components/Link/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Link";
2 |
--------------------------------------------------------------------------------
/src/components/List/List.scss:
--------------------------------------------------------------------------------
1 | .tm-list {
2 | list-style-type: none;
3 | padding: 0;
4 | margin: 0;
5 |
6 | li {
7 | line-height: 25px;
8 | padding: 4px 15px;
9 | cursor: pointer;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/components/List/__snapshots__/List.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`List when no properties are set matches snapshot 1`] = `""`;
4 |
5 | exports[`List when properties are set matches snapshot with defaultItems 1`] = `""`;
6 |
7 | exports[`List when properties are set matches snapshot with items 1`] = `
8 |
11 | -
15 | qux
16 |
17 | -
21 | quux
22 |
23 | -
27 | corge
28 |
29 |
30 | `;
31 |
--------------------------------------------------------------------------------
/src/components/List/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./List";
2 |
--------------------------------------------------------------------------------
/src/components/ListItem/__snapshots__/ListItem.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`ListItem when no properties are set matches snapshot 1`] = `
4 |
8 |
9 | `;
10 |
11 | exports[`ListItem when properties are set matches snapshot 1`] = `
12 |
16 |
17 | bar
18 |
19 |
20 | `;
21 |
--------------------------------------------------------------------------------
/src/components/ListItem/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ListItem";
2 |
--------------------------------------------------------------------------------
/src/components/Login/Login.scss:
--------------------------------------------------------------------------------
1 | @import '../../globals.scss';
2 |
3 | .wkp-login {
4 | margin-right: 6px;
5 | padding-top: 2px;
6 | color: $brand-grey;
7 | display: flex;
8 | align-items: center;
9 |
10 | .wkp-login-icon {
11 | float: left;
12 | margin-bottom: 2px;
13 | height: 28px;
14 | width: 28px;
15 |
16 | path {
17 | stroke: $brand-grey;
18 | }
19 | }
20 |
21 | &:hover {
22 | color: $brand-primary-hover;
23 |
24 | svg {
25 | path {
26 | stroke: $brand-primary-hover;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/Login/Login.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "@testing-library/react";
3 | import { Provider } from "react-redux";
4 | import Login from ".";
5 |
6 | describe("Login", () => {
7 | describe("matches snapshot", () => {
8 | test("displaying default text", () => {
9 | const store = global.global.mockStore({
10 | app: { appBaseUrl: "http://foo.de" },
11 | });
12 | const component = render(
13 |
14 |
15 | ,
16 | );
17 | expect(component.container.innerHTML).toMatchSnapshot();
18 | });
19 |
20 | test("displaying user name", () => {
21 | const store = global.global.mockStore({
22 | app: { permissionInfos: { user: "bar" }, appBaseUrl: "http://foo.de" },
23 | });
24 | const component = render(
25 |
26 |
27 | ,
28 | );
29 | expect(component.container.innerHTML).toMatchSnapshot();
30 | });
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/src/components/Login/__snapshots__/Login.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Login matches snapshot displaying default text 1`] = `
4 |
8 |
13 |
14 | Anmelden
15 |
16 |
17 | `;
18 |
19 | exports[`Login matches snapshot displaying user name 1`] = `
20 |
25 |
30 |
31 | bar
32 |
33 |
34 | `;
35 |
--------------------------------------------------------------------------------
/src/components/Login/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Login";
2 |
--------------------------------------------------------------------------------
/src/components/MainDialog/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MainDialog";
2 |
--------------------------------------------------------------------------------
/src/components/Map/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Map";
2 |
--------------------------------------------------------------------------------
/src/components/MapAccessibility/__snapshots__/MapAccessibility.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`MapAccessibility should return null 1`] = `""`;
4 |
--------------------------------------------------------------------------------
/src/components/MapAccessibility/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MapAccessibility";
2 |
--------------------------------------------------------------------------------
/src/components/MapButton/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MapButton";
2 |
--------------------------------------------------------------------------------
/src/components/MapControls/FitExtent/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./FitExtent";
2 |
--------------------------------------------------------------------------------
/src/components/MapControls/Geolocation/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Geolocation";
2 |
--------------------------------------------------------------------------------
/src/components/MapControls/MenuToggler/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MenuToggler";
2 |
--------------------------------------------------------------------------------
/src/components/MapControls/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MapControls";
2 |
--------------------------------------------------------------------------------
/src/components/MatomoTracker/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MatomoTracker";
2 |
--------------------------------------------------------------------------------
/src/components/Menu/Menu.js:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from "react";
2 | import PropTypes from "prop-types";
3 | import { useSelector } from "react-redux";
4 |
5 | import "./Menu.scss";
6 |
7 | const propTypes = {
8 | children: PropTypes.node.isRequired,
9 | };
10 |
11 | function Menu({ children }) {
12 | const menuOpen = useSelector((state) => state.app.menuOpen);
13 | const className = useMemo(() => {
14 | return `wkp-menu-wrapper${menuOpen ? " wkp-menu-wrapper-open" : ""}`;
15 | }, [menuOpen]);
16 |
17 | return {children}
;
18 | }
19 |
20 | Menu.propTypes = propTypes;
21 |
22 | export default React.memo(Menu);
23 |
--------------------------------------------------------------------------------
/src/components/Menu/Menu.scss:
--------------------------------------------------------------------------------
1 | .wkp-menu-wrapper {
2 | position: absolute;
3 | top: 12px;
4 | left: 10px;
5 | max-width: 371px;
6 | z-index: 1;
7 | right: 10px;
8 | }
9 |
10 | .map-controls .wkp-menu-wrapper {
11 | right: 75px; // map-controls + margin*2
12 | }
13 |
14 | // Specific zu geltungsbereiche iframe topic
15 | .tm-trafimage-maps.ch-sbb-geltungsbereiche-iframe .wkp-menu-wrapper {
16 | max-width: 406px;
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/Menu/MenuItem.scss:
--------------------------------------------------------------------------------
1 | .wkp-topic-menu-item {
2 | position: relative;
3 |
4 | .wkp-menu-title {
5 | display: flex;
6 | justify-content: space-between;
7 | padding: 15px 10px 15px 15px;
8 | align-items: center;
9 |
10 | .wkp-menu-title-left {
11 | display: flex;
12 | align-items: center;
13 | }
14 | }
15 | }
16 |
17 | .wkp-menu-item {
18 | border: 2px solid #666;
19 | background: white;
20 | margin-top: 5px;
21 |
22 | .wkp-menu-item {
23 | border: none;
24 | }
25 |
26 | .wkp-menu-item-body {
27 | min-width: 250px;
28 | max-height: 1000px;
29 | overflow-y: auto;
30 | padding: 5px 0 0;
31 | }
32 |
33 | &.closed {
34 | border-width: 0;
35 | }
36 |
37 | .wkp-collapsible-vertical {
38 | overflow: hidden auto;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/components/Menu/MenuItemHeader.scss:
--------------------------------------------------------------------------------
1 | .wkp-menu-item-header {
2 | height: 15px;
3 | border: none;
4 | display: flex;
5 | align-items: center;
6 | padding: 15px 10px 15px 15px;
7 |
8 | &.open {
9 | border-bottom: 1px solid #eee;
10 | }
11 |
12 | .wkp-menu-item-header-icon {
13 | margin-right: 10px;
14 | width: 15px;
15 | height: 15px;
16 | }
17 |
18 | .wkp-menu-item-header-toggler {
19 | width: 15px;
20 | height: 15px;
21 | }
22 |
23 | .wkp-menu-item-header-icon,
24 | .wkp-menu-item-header-toggler {
25 | svg {
26 | width: 100%;
27 | height: 100%;
28 | }
29 | }
30 |
31 | .wkp-menu-item-header-title {
32 | flex-grow: 2;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/Menu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Menu";
2 |
--------------------------------------------------------------------------------
/src/components/MessageListener/MessageListener.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import { useSelector } from "react-redux";
3 |
4 | function MessageListener() {
5 | const messageEvents = useSelector(
6 | (state) => state.app.activeTopic?.messageEvents,
7 | );
8 |
9 | useEffect(() => {
10 | const unlistens = [];
11 | (messageEvents || []).forEach((messageEvent) => {
12 | const callback = (evt) => {
13 | if (
14 | evt.type === messageEvent.eventType ||
15 | evt.data === messageEvent.eventType
16 | ) {
17 | messageEvent.callback(evt);
18 | }
19 | };
20 | window.addEventListener("message", callback);
21 | unlistens.push(() => {
22 | window.removeEventListener("message", callback);
23 | });
24 | });
25 |
26 | return () => {
27 | unlistens.forEach((unlisten) => {
28 | unlisten();
29 | });
30 | };
31 | }, [messageEvents]);
32 |
33 | return null;
34 | }
35 |
36 | export default React.memo(MessageListener);
37 |
--------------------------------------------------------------------------------
/src/components/MessageListener/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MessageListener";
2 |
--------------------------------------------------------------------------------
/src/components/NoDragPanWarning/NoDragPanWarning.test.js:
--------------------------------------------------------------------------------
1 | // import NoDragPanWarning from '.';
2 |
3 | describe("NoDragPanWarning", () => {
4 | test("display warning message", () => {
5 | expect(true).toBe(true);
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/src/components/NoDragPanWarning/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./NoDragPanWarning";
2 |
--------------------------------------------------------------------------------
/src/components/NoMouseWheelWarning/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./NoMouseWheelWarning";
2 |
--------------------------------------------------------------------------------
/src/components/Overlay/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Overlay";
2 |
--------------------------------------------------------------------------------
/src/components/Permalink/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Permalink";
2 |
--------------------------------------------------------------------------------
/src/components/PermalinkButton/PermalinkButton.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Provider } from "react-redux";
3 |
4 | import { render } from "@testing-library/react";
5 | import PermalinkButton from ".";
6 |
7 | describe("PermalinkButton", () => {
8 | let store;
9 | test("should match snapshot.", () => {
10 | store = global.mockStore({
11 | map: {},
12 | app: { drawIds: {} },
13 | });
14 |
15 | const component = render(
16 |
17 |
18 | {() => {
19 | return ;
20 | }}
21 |
22 | ,
23 | );
24 | expect(component.container.innerHTML).toMatchSnapshot();
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/src/components/PermalinkButton/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./PermalinkButton";
2 |
--------------------------------------------------------------------------------
/src/components/PermalinkInput/PermalinkInput.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "@testing-library/react";
3 | import PermalinkInput from ".";
4 |
5 | describe("PermalinkInput", () => {
6 | test("should match snapshot.", () => {
7 | const component = render();
8 | expect(component.container.innerHTML).toMatchSnapshot();
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/src/components/PermalinkInput/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./PermalinkInput";
2 |
--------------------------------------------------------------------------------
/src/components/PermalinkInputCore/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./PermalinkInput";
2 |
--------------------------------------------------------------------------------
/src/components/PersonCard/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./PersonCard";
2 |
--------------------------------------------------------------------------------
/src/components/PhotoCarusel/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./PhotoCarusel";
2 |
--------------------------------------------------------------------------------
/src/components/Popup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Popup";
2 |
--------------------------------------------------------------------------------
/src/components/ProjectionSelect/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ProjectionSelect";
2 |
--------------------------------------------------------------------------------
/src/components/ResizeHandler/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ResizeHandler";
2 |
--------------------------------------------------------------------------------
/src/components/SBBSwitch/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./SBBSwitch";
2 |
--------------------------------------------------------------------------------
/src/components/Search/Search.js:
--------------------------------------------------------------------------------
1 | import React, { useRef } from "react";
2 | import SearchInput from "./SearchInput";
3 | import SearchToggle from "./SearchToggle";
4 |
5 | import "./Search.scss";
6 |
7 | function Search() {
8 | const searchContainerRef = useRef();
9 |
10 | return (
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | export default React.memo(Search);
20 |
--------------------------------------------------------------------------------
/src/components/Search/Search.scss:
--------------------------------------------------------------------------------
1 | /* stylelint-disable selector-class-pattern */
2 | @import "../../globals.scss";
3 |
4 | .wkp-search {
5 | position: absolute;
6 | top: 25px;
7 | z-index: 2; /* To be above header div, in order to be clickable. */
8 | right: 480px;
9 | left: 400px;
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/Search/Search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Search/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Search";
2 |
--------------------------------------------------------------------------------
/src/components/SearchInput/SearchInput.md.scss:
--------------------------------------------------------------------------------
1 | .tm-search-input-example {
2 | .tm-search-input {
3 | position: relative;
4 | width: 300px;
5 | height: 40px;
6 | transition: width 0.3s ease;
7 |
8 | &.tm-focus {
9 | width: 600px;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/SearchInput/SearchInput.scss:
--------------------------------------------------------------------------------
1 | .tm-search-input {
2 | display: flex;
3 | justify-content: flex-end;
4 | width: calc(100% - 4px);
5 | height: calc(100% - 4px);
6 | position: absolute;
7 | top: 0;
8 | bottom: 0;
9 | margin: auto;
10 | border: 1px solid $gray;
11 | background-color: white;
12 |
13 | input,
14 | button,
15 | svg {
16 | border: none;
17 | }
18 |
19 | input {
20 | padding: 0 0 0 15px;
21 | flex-grow: 2;
22 | text-overflow: ellipsis;
23 | min-width: 0;
24 |
25 | &::-ms-clear {
26 | display: none;
27 | }
28 | }
29 |
30 | div[role='button'] {
31 | width: $btn-size-base;
32 | height: 100%;
33 | flex-shrink: 0;
34 | }
35 |
36 | div[role='button']:last-child {
37 | background-color: $btn-primary-color;
38 | color: white;
39 |
40 | &:hover {
41 | background-color: $btn-primary-color-hover;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/SearchInput/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./SearchInput";
2 |
--------------------------------------------------------------------------------
/src/components/Select/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Select";
2 |
--------------------------------------------------------------------------------
/src/components/Share/Share.scss:
--------------------------------------------------------------------------------
1 | .wkp-share {
2 | display: flex;
3 | flex-wrap: wrap;
4 | gap: 5px;
5 | padding: 10px 16px;
6 |
7 | > div, > button, > a {
8 | min-width: 55px;
9 | height: 30px;
10 | padding-top: 0;
11 | padding-bottom: 0;
12 | margin: 0;
13 | display: flex;
14 | align-items: center;
15 | justify-content: center;
16 | }
17 |
18 | // .ta-facebook-icon {
19 | // padding: 0 5px;
20 | // }
21 |
22 | .rs-canvas-save-button {
23 | padding-top: 2px;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/Share/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Share";
2 |
--------------------------------------------------------------------------------
/src/components/SharePermalinkButton/SharePermalinkButton.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Provider } from "react-redux";
3 |
4 | import { render } from "@testing-library/react";
5 | import { ThemeProvider } from "@mui/material";
6 | import theme from "../../themes/default";
7 | import SharePermalinkButton from ".";
8 |
9 | describe("SharePermalinkButton", () => {
10 | let store;
11 | test("should match snapshot.", () => {
12 | store = global.mockStore({
13 | map: {},
14 | app: { drawIds: {} },
15 | });
16 |
17 | const component = render(
18 |
19 |
20 |
21 |
22 | ,
23 | );
24 | expect(
25 | component.container.querySelectorAll(".wkp-permalink-bt").length,
26 | ).toBe(1);
27 | expect(component.container.querySelectorAll("button").length).toBe(1);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/SharePermalinkButton/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./SharePermalinkButton";
2 |
--------------------------------------------------------------------------------
/src/components/StopSearchResult/StopSearchResult.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "@testing-library/react";
3 |
4 | import StopSearchResult from "./StopSearchResult";
5 |
6 | describe("StopSearchResult", () => {
7 | test("returns null when no properties defined", () => {
8 | const { queryByTestId } = render();
9 | expect(queryByTestId("stopfinder-search-result")).toBeNull();
10 | });
11 |
12 | test("returns null when no property title defined", () => {
13 | const { queryByTestId } = render(
14 | ,
15 | );
16 | expect(queryByTestId("stopfinder-search-result")).toBeNull();
17 | });
18 |
19 | test("returns component with name when property title defined", () => {
20 | const { queryByTestId } = render(
21 | ,
22 | );
23 | expect(queryByTestId("stopfinder-search-result")).toBeDefined();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/components/StopSearchResult/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./StopSearchResult";
2 |
--------------------------------------------------------------------------------
/src/components/TarifverbundPartner/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TarifverbundPartner";
2 |
--------------------------------------------------------------------------------
/src/components/TopicElements/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TopicElements";
2 |
--------------------------------------------------------------------------------
/src/components/TopicInfosButton/TopicInfosButton.js:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from "react";
2 | import { useSelector } from "react-redux";
3 | import PropTypes from "prop-types";
4 | import InfosButton from "../InfosButton";
5 |
6 | function TopicInfosButton({ topic }) {
7 | const activeTopic = useSelector((state) => state.app.activeTopic);
8 |
9 | const className = useMemo(() => {
10 | const classes = ["wkp-info-bt"];
11 |
12 | if (activeTopic?.key === topic.key) {
13 | classes.push("wkp-active");
14 | }
15 | return classes.join(" ");
16 | }, [activeTopic.key, topic]);
17 |
18 | if (!topic) {
19 | return null;
20 | }
21 |
22 | return ;
23 | }
24 |
25 | TopicInfosButton.propTypes = {
26 | topic: PropTypes.object.isRequired,
27 | };
28 |
29 | export default React.memo(TopicInfosButton);
30 |
--------------------------------------------------------------------------------
/src/components/TopicInfosButton/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TopicInfosButton";
2 |
--------------------------------------------------------------------------------
/src/components/TopicLoader/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TopicLoader";
2 |
--------------------------------------------------------------------------------
/src/components/TopicMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TopicMenu";
2 |
--------------------------------------------------------------------------------
/src/components/TopicTelephoneInfos/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TopicTelephoneInfos";
2 |
--------------------------------------------------------------------------------
/src/components/TopicsMenu/TopicsMenu.scss:
--------------------------------------------------------------------------------
1 | .wkp-topics-menu {
2 | border: 2px solid #666;
3 | max-height: 1500px;
4 |
5 | .wkp-menu-item {
6 | border: none;
7 | margin-top: 0;
8 | }
9 |
10 | .wkp-menu-item-header {
11 | border-top: 1px solid #eee;
12 | }
13 |
14 | .wkp-topics-menu-title {
15 | display: flex;
16 | align-items: center;
17 | }
18 |
19 | .wkp-topics-menu-body {
20 | min-width: 250px;
21 | max-height: 2000px;
22 | overflow-y: auto;
23 | background: white;
24 | padding: 10px 15px;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/TopicsMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TopicsMenu";
2 |
--------------------------------------------------------------------------------
/src/components/TopicsMenuHeader/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TopicsMenuHeader";
2 |
--------------------------------------------------------------------------------
/src/components/TrafimageMaps/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TrafimageMaps";
2 |
--------------------------------------------------------------------------------
/src/components/withResizing/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./withResizing";
2 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.direktverbindungen/DvFeatureInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DvFeatureInfo";
2 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.direktverbindungen/DvFeatureInfoTitle/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DvFeatureInfoTitle";
2 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.direktverbindungen/DvLegendLine/DvLegendLine.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 |
4 | function DvLegendLine({ color, width = 50 }) {
5 | return ;
6 | }
7 |
8 | DvLegendLine.propTypes = {
9 | color: PropTypes.string.isRequired,
10 | width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
11 | };
12 |
13 | export default DvLegendLine;
14 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.direktverbindungen/DvLegendLine/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DvLegendLine";
2 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.direktverbindungen/DvLineInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DvLineInfo";
2 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.direktverbindungen/DvLineTitle/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DvLineTitle";
2 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.direktverbindungen/DvListButton/__snapshots__/DvListButton.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`DvListButton should match snapshot and be disabled on load. 1`] = `","`;
4 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.direktverbindungen/DvListButton/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DvListButton";
2 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.direktverbindungen/dvParseFeatures.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Convert Direktverbindungen features for popup
3 | */
4 | const parseDvFeatures = (featuresArray) => {
5 | return featuresArray.map((feature) => {
6 | const { vias } = feature.getProperties();
7 | const parsedVias = Array.isArray(vias) ? vias : JSON.parse(vias);
8 |
9 | const switchVias = vias
10 | ? parsedVias.filter(
11 | (via) => via.via_type === "switch" || via.via_type === "visible",
12 | )
13 | : [];
14 | feature.set("vias", [
15 | parsedVias[0],
16 | ...switchVias,
17 | parsedVias[parsedVias.length - 1],
18 | ]);
19 | return feature;
20 | });
21 | };
22 |
23 | export default parseDvFeatures;
24 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.funkmesswagen/MesswagenFollowButton/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MesswagenFollowButton";
2 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.geltungsbereiche.iframe/index.js:
--------------------------------------------------------------------------------
1 | import layers from "../ch.sbb.geltungsbereiche.mvp";
2 |
3 | export default layers;
4 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.handicap/index.test.js:
--------------------------------------------------------------------------------
1 | import { getLayersAsFlatArray } from "mobility-toolbox-js/common";
2 | import layers from "./index";
3 |
4 | describe("ch.sbb.handicap", () => {
5 | it("should always have the same layers key for layers available via permalink", () => {
6 | expect(true).toBe(true);
7 | const permalinkKeys = getLayersAsFlatArray(layers)
8 | .filter((l) => {
9 | return !l.get("hideInLegend") && !l.get("isBaseLayer");
10 | })
11 | .map((l) => l.key)
12 | .join(",");
13 | expect(permalinkKeys).toBe(
14 | "ch.sbb.bahnhofplaene,ch.sbb.bahnhofplaene.interaktiv,ch.sbb.bahnhofplaene.printprodukte,ch.sbb.status_unbekannt,ch.sbb.nichtbarrierfreierbahnhoefe,ch.sbb.teilbarrierefreiebahnhoefe,ch.sbb.barrierfreierbahnhoefe",
15 | );
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.immobilien/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/config/ch.sbb.immobilien/index.js
--------------------------------------------------------------------------------
/src/config/ch.sbb.isb/index.test.js:
--------------------------------------------------------------------------------
1 | import { isbOther, isbTVS } from "./index";
2 |
3 | describe("ch.sbb.isb", () => {
4 | describe("isbOther", () => {
5 | test("has a shortToLongName property set and only unique keys, it's important for the layer infos", () => {
6 | expect(isbOther.get("shortToLongName")).toBeDefined();
7 | expect(isbOther.get("defaultColor")).toBeDefined();
8 | });
9 | });
10 | describe("isbTVS", () => {
11 | test("has a shortToLongName property set and only unique keys, it's important for the layer infos", () => {
12 | expect(isbTVS.get("shortToLongName")).toBeDefined();
13 | expect(isbTVS.get("colors")).toBeDefined();
14 | expect(isbTVS.get("defaultColor")).toBeDefined();
15 | });
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.sts/StsMenuToggler/StsMenuToggler.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useTranslation } from "react-i18next";
3 | import { useSelector } from "react-redux";
4 | import MenuToggler from "../../../components/MapControls/MenuToggler";
5 | import useHasScreenSize from "../../../utils/useHasScreenSize";
6 | import { ReactComponent as MenuOpen } from "../../../img/sbb/040_hamburgermenu_102_36.svg";
7 | import { ReactComponent as SearchIcon } from "../../../components/Search/Search.svg";
8 |
9 | function StsMenuToggler() {
10 | const { t } = useTranslation();
11 | const isMobile = useHasScreenSize(["xs"]);
12 | const displayMenu = useSelector((state) => state.app.displayMenu);
13 |
14 | return (
15 | : ,
19 | title: !displayMenu ? t("Menü") : t("Suchen"),
20 | style: { padding: 8 },
21 | }
22 | : {})}
23 | />
24 | );
25 | }
26 |
27 | export default StsMenuToggler;
28 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.sts/StsMenuToggler/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./StsMenuToggler";
2 |
--------------------------------------------------------------------------------
/src/config/ch.sbb.tarifverbundkarte.public/index.js:
--------------------------------------------------------------------------------
1 | import TrafimageMapboxLayer from "../../layers/TrafimageMapboxLayer";
2 | import TarifverbundkarteLayer from "../../layers/TarifverbundkarteLayer";
3 |
4 | export const tarifverbundkarteDataLayer = new TrafimageMapboxLayer({
5 | name: "ch.sbb.tarifverbundkarte.data",
6 | visible: true,
7 | zIndex: -1, // Add zIndex as the MapboxLayer would block tiled layers (buslines)
8 | style: "ch.sbb.tarifverbund",
9 | properties: {
10 | hideInLegend: true,
11 | isBaseLayer: true,
12 | },
13 | mapOptions: {
14 | preserveDrawingBuffer: true,
15 | },
16 | });
17 |
18 | export const tarifverbundkarteLayer = new TarifverbundkarteLayer({
19 | mapboxLayer: tarifverbundkarteDataLayer,
20 | visible: true,
21 | properties: {
22 | isQueryable: true,
23 | hideInLegend: true,
24 | useOverlay: true,
25 | popupComponent: "TarifverbundkartePopup",
26 | },
27 | });
28 | export default [tarifverbundkarteDataLayer, tarifverbundkarteLayer];
29 |
--------------------------------------------------------------------------------
/src/config/doc-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appName": "Trafimage-maps",
3 | "githubRepo": "https://github.com/geops/trafimage-maps"
4 | }
5 |
--------------------------------------------------------------------------------
/src/config/proj4.js:
--------------------------------------------------------------------------------
1 | import proj4 from "proj4";
2 | import { register } from "ol/proj/proj4";
3 |
4 | proj4.defs(
5 | "EPSG:21781",
6 | "+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 " +
7 | "+x_0=600000 +y_0=200000 +ellps=bessel " +
8 | "+towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs",
9 | );
10 |
11 | proj4.defs(
12 | "EPSG:2056",
13 | "+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 " +
14 | "+x_0=2600000 +y_0=1200000 +ellps=bessel " +
15 | "+towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs",
16 | );
17 |
18 | register(proj4);
19 |
--------------------------------------------------------------------------------
/src/config/searches.js:
--------------------------------------------------------------------------------
1 | import Betriebspunkte from "../searches/Betriebspunkte";
2 | import Lines from "../searches/Lines";
3 | import Locations from "../searches/Locations";
4 | import Municipalities from "../searches/Municipalities";
5 | import StopFinder from "../searches/StopFinder";
6 | import HandicapStopFinder from "../searches/HandicapStopFinder";
7 |
8 | export const betriebspunkte = new Betriebspunkte();
9 |
10 | export const lines = new Lines();
11 |
12 | export const locations = new Locations();
13 |
14 | export const municipalities = new Municipalities();
15 |
16 | export const stopFinder = new StopFinder();
17 |
18 | export const handicapStopFinder = new HandicapStopFinder();
19 |
20 | export default {
21 | Stationen: stopFinder,
22 | Gemeinden: municipalities,
23 | Orte: locations,
24 | Betriebspunkte: betriebspunkte,
25 | Linien: lines,
26 | };
27 |
--------------------------------------------------------------------------------
/src/examples/Angular/README.md:
--------------------------------------------------------------------------------
1 | For Angular, we provide this [CodeSandBox example](https://codesandbox.io/p/devbox/angular-trafimage-maps-4jkf9x) to demonstrate the usage of _trafimage-maps_ web component in an Angular app.
2 |
3 |
9 |
--------------------------------------------------------------------------------
/src/examples/Betriebsregionen/README.md:
--------------------------------------------------------------------------------
1 | Example for the _Operating regions_ topic.
2 |
3 | ```js
4 | import "trafimage-maps";
5 | import Editor from "react-styleguidist/lib/client/rsg-components/Editor";
6 | import getHtmlPageCode from "../getHtmlPageCode";
7 |
8 | const App = () => {
9 | return (
10 | <>
11 |
12 |
18 |
19 |
20 | \n `,
23 | )}
24 | onChange={(code) => null} //setCode(code)}
25 | />
26 | >
27 | );
28 | };
29 | ;
30 | ```
31 |
--------------------------------------------------------------------------------
/src/examples/Construction/README.md:
--------------------------------------------------------------------------------
1 | Example how to load _trafimage-maps_ with a specific topic without using React.
2 |
3 | ```js
4 | import "trafimage-maps";
5 | import Editor from "react-styleguidist/lib/client/rsg-components/Editor";
6 | import getHtmlPageCode from "../getHtmlPageCode";
7 |
8 | const App = () => {
9 | return (
10 | <>
11 |
12 |
18 |
19 |
20 | \n `,
23 | )}
24 | onChange={(code) => null} //setCode(code)}
25 | />
26 | >
27 | );
28 | };
29 | ;
30 | ```
31 |
--------------------------------------------------------------------------------
/src/examples/CustomTopic/ExampleCode.txt:
--------------------------------------------------------------------------------
1 | import 'trafimage-maps';
2 | import React, { useRef, useEffect } from 'react';
3 | import TrafimageMapboxLayer from 'trafimage-maps/es/layers/TrafimageMapboxLayer';
4 |
5 | const topic = {
6 | name: 'Default',
7 | key: 'default',
8 | elements: {
9 | menu: false,
10 | header: true,
11 | footer: true,
12 | permalink: false,
13 | },
14 | layers: [
15 | new TrafimageMapboxLayer({
16 | name: 'Netzkarte',
17 | visible: true,
18 | style: 'base_bright_v2',
19 | }),
20 | ],
21 | };
22 |
23 | const App = () => {
24 | const ref = useRef();
25 |
26 | useEffect(() => {
27 | const map = ref.current;
28 | map.topics = [topic];
29 |
30 | return () => {
31 | map.topics = null;
32 | };
33 | }, []);
34 |
35 | return (
36 |
37 |
38 |
42 | />
43 |
44 | );
45 | };
46 |
47 | ;
--------------------------------------------------------------------------------
/src/examples/OverrideTopic/ExampleCode.txt:
--------------------------------------------------------------------------------
1 | import 'trafimage-maps';
2 | import React, { useRef, useEffect } from 'react';
3 | import { netzkarte } from 'trafimage-maps/es/config/topics';
4 |
5 | const topic = {
6 | ...netzkarte,
7 | elements: {
8 | ...netzkarte.elements,
9 | popup: false,
10 | },
11 | };
12 |
13 | const App = () => {
14 | const ref = useRef();
15 |
16 | useEffect(() => {
17 | const map = ref.current;
18 | map.topics = [topic];
19 |
20 | return () => {
21 | map.topics = null;
22 | };
23 | }, []);
24 |
25 | return (
26 |
27 |
28 |
32 | />
33 |
34 | );
35 | };
36 |
37 | ;
38 |
--------------------------------------------------------------------------------
/src/examples/Schulzug/marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/examples/Schulzug/marker.png
--------------------------------------------------------------------------------
/src/examples/getCodeWithApiKey.js:
--------------------------------------------------------------------------------
1 | const getCodeWithApiKey = async (pathToFile, apiKey) => {
2 | const text = await fetch(pathToFile).then((res) => res.text());
3 | return text.replace("", `"${apiKey}"`);
4 | };
5 |
6 | export default getCodeWithApiKey;
7 |
--------------------------------------------------------------------------------
/src/examples/getHtmlPageCode.js:
--------------------------------------------------------------------------------
1 | const getHtmlPageCode = (wcCode, scriptCode) => {
2 | if (!wcCode) {
3 | return null;
4 | }
5 | return `
6 |
7 |
8 | ${
9 | scriptCode ? `\n ${scriptCode}` : ""
10 | }
11 |
12 |
13 |
14 | ${wcCode}
15 |
16 |
17 |
18 | `;
19 | };
20 |
21 | export default getHtmlPageCode;
22 |
--------------------------------------------------------------------------------
/src/examples/iframe/getHtmlPageCode.js:
--------------------------------------------------------------------------------
1 | const getHtmlPageCode = (iframeCode, extraCode = "") => {
2 | if (!iframeCode) {
3 | return null;
4 | }
5 | return `
6 |
7 |
8 |
9 |
10 | ${iframeCode}
11 |
${extraCode}
12 |
13 |
14 | `;
15 | };
16 |
17 | export default getHtmlPageCode;
18 |
--------------------------------------------------------------------------------
/src/examples/iframe/getIframeCodeFromUrl.js:
--------------------------------------------------------------------------------
1 | const getIframeCodeFromUrl = (url) => {
2 | if (!url) {
3 | return null;
4 | }
5 | return ``;
6 | };
7 |
8 | export default getIframeCodeFromUrl;
9 |
--------------------------------------------------------------------------------
/src/filters/AusbauFilters/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./AusbauFilters";
2 |
--------------------------------------------------------------------------------
/src/filters/index.js:
--------------------------------------------------------------------------------
1 | import AusbauFilters from "./AusbauFilters";
2 |
3 | export { default as AusbauFilters } from "./AusbauFilters";
4 |
5 | export default { AusbauFilters };
6 |
--------------------------------------------------------------------------------
/src/img/Geolocate/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Geolocate";
2 |
--------------------------------------------------------------------------------
/src/img/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/arrow.png
--------------------------------------------------------------------------------
/src/img/arrow.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/bahnhofplanLayerIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/bahnhofplanLayerIcon.png
--------------------------------------------------------------------------------
/src/img/chevronLeft.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/clock_10_large.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/favicon.png
--------------------------------------------------------------------------------
/src/img/finish_flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/finish_flag.png
--------------------------------------------------------------------------------
/src/img/finish_flag.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/geltungsbereicheLegends/index.test.js:
--------------------------------------------------------------------------------
1 | import geltungsbereicheLegendConfigs from ".";
2 |
3 | const fs = require("fs");
4 | const path = require("path");
5 |
6 | describe("Geltungsbereiche legends: ", () => {
7 | geltungsbereicheLegendConfigs.forEach((item) => {
8 | it(`${item.legend} should contain a scaleline tag for dynamic scaleline placement`, () => {
9 | const svgPath = path.join(__dirname, "./", item.legend);
10 | const fdr = fs.readFileSync(svgPath, "utf8", (err, data) => {
11 | return data;
12 | });
13 | expect(fdr).toContain(`id="scaleline"`);
14 | });
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/img/layers/BahnhofplanLayer/interactiveStationplans.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/BahnhofplanLayer/interactiveStationplans.png
--------------------------------------------------------------------------------
/src/img/layers/BahnhofplanLayer/printproducts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/BahnhofplanLayer/printproducts.png
--------------------------------------------------------------------------------
/src/img/layers/Betriebsregionen/mitte.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/Betriebsregionen/mitte.png
--------------------------------------------------------------------------------
/src/img/layers/Betriebsregionen/ost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/Betriebsregionen/ost.png
--------------------------------------------------------------------------------
/src/img/layers/Betriebsregionen/other.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/Betriebsregionen/other.png
--------------------------------------------------------------------------------
/src/img/layers/Betriebsregionen/sud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/Betriebsregionen/sud.png
--------------------------------------------------------------------------------
/src/img/layers/Betriebsregionen/west.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/Betriebsregionen/west.png
--------------------------------------------------------------------------------
/src/img/layers/NetzkartePointLayer/layer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/NetzkartePointLayer/layer.png
--------------------------------------------------------------------------------
/src/img/layers/NetzkartePointLayer/stations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/NetzkartePointLayer/stations.png
--------------------------------------------------------------------------------
/src/img/layers/PassagierfrequenzenLayer/layer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/PassagierfrequenzenLayer/layer.png
--------------------------------------------------------------------------------
/src/img/layers/RouteLayer/layer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/RouteLayer/layer.png
--------------------------------------------------------------------------------
/src/img/layers/ZoneLayer/layer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/layers/ZoneLayer/layer.png
--------------------------------------------------------------------------------
/src/img/list-icon-sbb.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/mail.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/menu.png
--------------------------------------------------------------------------------
/src/img/menu_closed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/menu_closed.png
--------------------------------------------------------------------------------
/src/img/menu_open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/menu_open.png
--------------------------------------------------------------------------------
/src/img/minus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/northArrowCircle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/img/northArrowCircle.png
--------------------------------------------------------------------------------
/src/img/pencil.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/pencil_add.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/person.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/phone.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/plus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/popups/NetzentwicklungPopup/mail.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/popups/NetzentwicklungPopup/person.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/popups/NetzentwicklungPopup/phone.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/sbb/040_hamburgermenu_102_36.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/img/sbb/040_schliessen_104_36.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/img/sbb/globe_210_large.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/sbb/gps-large.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/img/sbb/gps-medium.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/img/sbb/gps-small.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/img/sbb/location-pin-a-medium.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/sbb/location-pin-m-medium-bg-red.url.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/sbb/two-finger-tap-large.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/img/sbb/user_92_large.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/swissbounds.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/train-day.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/img/train-night.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import "react-app-polyfill/stable";
2 | // import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only';
3 |
4 | // Import web-components polyfills for ie 11, see https://github.com/webcomponents/polyfills.
5 | // If you need to test the component with { shadow: true }, you have to add:
6 | // import '@webcomponents/shadydom'
7 | // import '@webcomponents/shadycss'
8 | // import '@webcomponents/webcomponents-platform';
9 | // import '@webcomponents/custom-elements';
10 | // import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter';
11 | // import 'proxy-polyfill';
12 | import ReactWebComponent from "@geops/create-react-web-component";
13 | import WebComponent from "./WebComponent";
14 |
15 | ReactWebComponent.setAttributes(WebComponent.attributes);
16 | ReactWebComponent.setProperties(WebComponent.defaultProps);
17 | ReactWebComponent.render(WebComponent, "trafimage-maps", { shadow: false });
18 |
--------------------------------------------------------------------------------
/src/layerInfos/BeleuchtungLayerInfo/BeleuchtungLayerInfo.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { PropTypes } from "prop-types";
3 | import { BeleuchtungLegendeRow } from "../BeleuchtungTopicInfo/BeleuchtungLegende";
4 |
5 | function BeleuchtungLayerInfo({ properties }) {
6 | const lightClass = properties.name.split("beleuchtungsstaerken")[1];
7 | return ;
8 | }
9 |
10 | BeleuchtungLayerInfo.propTypes = {
11 | properties: PropTypes.shape({
12 | name: PropTypes.string,
13 | }).isRequired,
14 | };
15 |
16 | export default BeleuchtungLayerInfo;
17 |
--------------------------------------------------------------------------------
/src/layerInfos/BeleuchtungLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./BeleuchtungLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/BeleuchtungLayerInfo/lightingMapping.js:
--------------------------------------------------------------------------------
1 | export const lightingMapping = {
2 | 1: {
3 | color: "#fdd815",
4 | info: [">= 20000", "Hohes Personenaufkommen"],
5 | },
6 | "2a": {
7 | color: "#e8a60a",
8 | info: ["10000 - 19999", "Mittleres Personenaufkommen"],
9 | },
10 | "2b": {
11 | color: "#9c7c2e",
12 | info: ["1500 - 9999", "Mittleres Personenaufkommen"],
13 | },
14 | 3: {
15 | color: "#674512",
16 | info: ["50 - 1499", "Geringes Personenaufkommen"],
17 | },
18 | 4: {
19 | color: "#000000",
20 | info: ["< 50", "Sehr geringes Personenaufkommen"],
21 | },
22 | };
23 |
24 | export default lightingMapping;
25 |
--------------------------------------------------------------------------------
/src/layerInfos/BeleuchtungTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./BeleuchtungTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/BetriebsRegionenLayerInfo/BetriebsRegionenLayerInfo.scss:
--------------------------------------------------------------------------------
1 | .wkp-betriebsregionen {
2 | padding-top: 5px;
3 |
4 | .wkp-betriebsregion {
5 | display: flex;
6 | padding: 5px 0;
7 | align-items: center;
8 |
9 | img {
10 | padding-right: 7px;
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/layerInfos/BetriebsRegionenLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./BetriebsRegionenLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/BuslinesLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./BuslinesLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/ConstructionFertigstellungLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ConstructionFertigstellungLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/ConstructionLayerInfo/ConstructionLayerInfo.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import { withTranslation } from "react-i18next";
4 |
5 | import "./ConstructionLayerInfo.scss";
6 |
7 | const propTypes = {
8 | t: PropTypes.func.isRequired,
9 | properties: PropTypes.object.isRequired,
10 | staticFilesUrl: PropTypes.string.isRequired,
11 | };
12 |
13 | function ConstructionLayerInfo({ t, properties, staticFilesUrl }) {
14 | const config = properties.get("construction");
15 | const filename = `${config.art}_${config.ort}`.replace(
16 | /[^A-Z,^0-9,-_]/gi,
17 | "",
18 | );
19 |
20 | return (
21 |
22 |

27 | {t(`${properties.key}-desc`)}
28 |
29 | );
30 | }
31 |
32 | ConstructionLayerInfo.propTypes = propTypes;
33 |
34 | export default withTranslation()(ConstructionLayerInfo);
35 |
--------------------------------------------------------------------------------
/src/layerInfos/ConstructionLayerInfo/ConstructionLayerInfo.scss:
--------------------------------------------------------------------------------
1 | .wkp-construction-layer-info {
2 | img {
3 | float: left;
4 | padding-right: 10px;
5 | padding-bottom: 10px;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/layerInfos/ConstructionLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ConstructionLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/ConstructionTopicInfo/ConstructionTopicInfo.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "@testing-library/react";
3 | import ConstructionTopicInfo from ".";
4 |
5 | describe("ConstructionTopicInfo", () => {
6 | test("should display link to data", () => {
7 | const { container } = render();
8 | const link = container.querySelector("a.wkp-link");
9 | expect(link.href).toBe(
10 | "https://data.sbb.ch/explore/dataset/construction-projects/information/",
11 | );
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/src/layerInfos/ConstructionTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ConstructionTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/DrawLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DrawLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/DvLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DvLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/DvTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DvTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/EnergieLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./EnergieLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/EnergiePublicTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./EnergiePublicTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/EnergieTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./EnergieTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/GeltungsbereicheLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./GeltungsbereicheLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/GeltungsbereicheTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./GeltungsbereicheTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/HandicapLayerInfo/HandicapLayerInfo.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import { Typography } from "@mui/material";
4 | import { makeStyles } from "@mui/styles";
5 | import { useTranslation } from "react-i18next";
6 | import HandicapLayer from "../../layers/HandicapLayer";
7 |
8 | const propTypes = {
9 | properties: PropTypes.instanceOf(HandicapLayer).isRequired,
10 | };
11 |
12 | const useStyles = makeStyles({
13 | grid: {
14 | display: "flex",
15 | gap: 10,
16 | },
17 | circle: {
18 | height: 15,
19 | minWidth: 15,
20 | borderRadius: "50%",
21 | },
22 | });
23 |
24 | function HandicapLayerInfo({ properties: layer }) {
25 | const { t } = useTranslation();
26 | const classes = useStyles();
27 |
28 | return (
29 |
30 |
34 |
{t(`${layer.key}.layerinfo`)}
35 |
36 | );
37 | }
38 |
39 | HandicapLayerInfo.propTypes = propTypes;
40 |
41 | export default HandicapLayerInfo;
42 |
--------------------------------------------------------------------------------
/src/layerInfos/HandicapLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./HandicapLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/HandicapTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./HandicapTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/InfrastrukturTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./InfrastrukturTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/IsbNormalspurLayerInfo/IsbNormalspurLayerInfo.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "@testing-library/react";
3 | import { Layer } from "mobility-toolbox-js/ol";
4 | import IsbNormalspurLayerInfo from ".";
5 |
6 | describe("IsbNormalspurLayerInfo", () => {
7 | test("render opertaors in alphabetical order", () => {
8 | const { container } = render(
9 | ,
22 | );
23 | // Test important operator
24 | expect(container.textContent.includes("aSm aSmASM ASMzB zB")).toBe(true);
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/src/layerInfos/IsbNormalspurLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./IsbNormalspurLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/IsbOtherLayerInfo/IsbOtherLayerInfo.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render, screen } from "@testing-library/react";
3 | import { isbOther } from "../../config/ch.sbb.isb";
4 | import IsbOtherLayerInfo from ".";
5 |
6 | describe("IsbOtherLayerInfo", () => {
7 | test("render something", () => {
8 | render();
9 | // Test important operator
10 | expect(screen.getByText(/DB, /)).toBeInTheDocument();
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/src/layerInfos/IsbOtherLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./IsbOtherLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/IsbSchmalspurLayerInfo/IsbSchmalspurLayerInfo.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "@testing-library/react";
3 | import { Layer } from "mobility-toolbox-js/ol";
4 | import IsbSchmalspurLayerInfo from ".";
5 |
6 | describe("IsbSchmalspurLayerInfo", () => {
7 | test("render something", () => {
8 | const { container } = render(
9 | ,
22 | );
23 | // Test important operator
24 | expect(container.textContent.includes("aSm aSmASM ASMzB zB")).toBe(true);
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/src/layerInfos/IsbSchmalspurLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./IsbSchmalspurLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/IsbTVSLayerInfo/IsbTVSLayerInfo.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render, screen } from "@testing-library/react";
3 | import { isbTVS } from "../../config/ch.sbb.isb";
4 | import IsbTVSLayerInfo from ".";
5 |
6 | describe("IsbTVSLayerInfo", () => {
7 | test("render something", () => {
8 | render( a} language="de" properties={isbTVS} />);
9 | // Test important operator
10 | expect(screen.getByText("SBB")).toBeInTheDocument();
11 | expect(screen.getByText("SBB Infrastruktur")).toBeInTheDocument();
12 | // Test one of the other operators
13 | expect(screen.getByText(/TMR, /)).toBeInTheDocument();
14 | expect(screen.getByText("www.tvs.ch")).toBeInTheDocument();
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/layerInfos/IsbTVSLayerInfo/OperatorShortAndLongName.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useTranslation } from "react-i18next";
3 | import { makeStyles } from "@mui/styles";
4 | import PropTypes from "prop-types";
5 |
6 | const useStyles = makeStyles({
7 | root: {
8 | display: "flex",
9 | alignItems: "center",
10 | fontSize: "0.8em",
11 | margin: "3px 0",
12 | },
13 | shortName: {
14 | display: "inline-block",
15 | flex: "0 0 40px",
16 | minWidth: "40px",
17 | marginRight: 5,
18 | },
19 | });
20 |
21 | const propTypes = {
22 | shortName: PropTypes.string.isRequired,
23 | longName: PropTypes.string.isRequired,
24 | };
25 |
26 | function OperatorShortAndLongName({ shortName, longName }) {
27 | const { t } = useTranslation();
28 | const classes = useStyles();
29 | return (
30 |
31 | {shortName}
32 | {t(longName)}
33 |
34 | );
35 | }
36 |
37 | OperatorShortAndLongName.propTypes = propTypes;
38 |
39 | export default React.memo(OperatorShortAndLongName);
40 |
--------------------------------------------------------------------------------
/src/layerInfos/IsbTVSLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./IsbTVSLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/IsbTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./IsbTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/MapsGeoAdminLayerInfo/MapsGeoAdminLayerInfo.scss:
--------------------------------------------------------------------------------
1 | .wkp-maps-geo-admin-layer-info {
2 | max-height: 50vh;
3 |
4 | .bod-title {
5 | font-family: SBBWeb-Bold, Arial, sans-serif;
6 | }
7 |
8 | .legend-footer {
9 | display: none;
10 | }
11 |
12 | .wkp-maps-geo-admin-layer-info-footer {
13 | margin: 10px 0;
14 | padding-bottom: 20px;
15 |
16 | img {
17 | margin: 10px 0;
18 | }
19 |
20 | span {
21 | display: flex;
22 | align-items: baseline;
23 | white-space: pre;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/layerInfos/MapsGeoAdminLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MapsGeoAdminLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/MesswagenPhotosLayerInfo/MesswagenPhotosLayerInfo.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Typography } from "@mui/material";
3 | import { makeStyles } from "@mui/styles";
4 | import { useTranslation } from "react-i18next";
5 | import LegendCircle from "../../components/LegendCircle/LegendCircle";
6 |
7 | const useStyles = makeStyles((theme) => ({
8 | grid: {
9 | display: "grid",
10 | gridTemplateColumns: "1fr 8fr",
11 | gridGap: theme.spacing(1),
12 | },
13 | }));
14 |
15 | function MesswagenPhotosLayerInfo() {
16 | const classes = useStyles();
17 | const { t } = useTranslation();
18 | return (
19 |
20 |
21 | {t("SBB-Funkmesswagen")}
22 |
23 | {t("Verschiedenes")}
24 |
25 | );
26 | }
27 |
28 | export default MesswagenPhotosLayerInfo;
29 |
--------------------------------------------------------------------------------
/src/layerInfos/MesswagenPhotosLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MesswagenPhotosLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/MesswagenTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MesswagenTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/NetzkarteTopicInfo/NetzkarteTopicInfo.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import { withTranslation } from "react-i18next";
4 |
5 | const propTypes = {
6 | t: PropTypes.func.isRequired,
7 | };
8 |
9 | function NetzkarteTopicInfo({ t }) {
10 | return (
11 |
12 |
{`${t("ch.sbb.netzkarte-desc")} ${t(
13 | "ch.sbb.netzkarte-desc-topic-info",
14 | )}`}
15 |
16 | {t("Verantwortlich")}:
17 |
18 | {t("SBB AG, Product Owner Trafimage")},
19 |
20 | Daniel Hofstetter,
21 | {t("trafimage@sbb.ch")}.
22 |
23 |
24 | );
25 | }
26 |
27 | NetzkarteTopicInfo.propTypes = propTypes;
28 |
29 | export default withTranslation()(NetzkarteTopicInfo);
30 |
--------------------------------------------------------------------------------
/src/layerInfos/NetzkarteTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./NetzkarteTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/PassagierFrequenzenLayerInfo/PassagierFrequenzenLayerInfo.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "@testing-library/react";
3 | import { passagierfrequenzen } from "../../config/ch.sbb.netzkarte";
4 | import PassagierFrequenzenLayerInfo from ".";
5 |
6 | describe("PassagierFrequenzenLayerInfo", () => {
7 | test("should display link to data", () => {
8 | const { container } = render(
9 | ,
10 | );
11 | const link = container.querySelector("a.wkp-link");
12 | expect(link.href).toBe(
13 | "https://reporting.sbb.ch/verkehr?highlighted=row-243",
14 | );
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/layerInfos/PassagierFrequenzenLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./PassagierFrequenzenLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/PunctualityLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./PunctualityLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/RegionenkartePublicLayerInfo/RegionenkarteLegend.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ThemeProvider } from "@mui/material";
3 | import { render } from "@testing-library/react";
4 | import theme from "../../themes/default";
5 | import RegionenkarteLegend from "./RegionenkarteLegend";
6 |
7 | const mapping = {
8 | ost: "grun",
9 | sud: "rot",
10 | mitte: "lila",
11 | west: "gelb",
12 | };
13 |
14 | describe("RegionenkarteLegend", () => {
15 | test("should display all regions with correct colors", async () => {
16 | const { queryByTestId } = render(
17 |
18 |
19 | ,
20 | );
21 | Object.keys(mapping).forEach((region) => {
22 | const imgElement = queryByTestId(`regionenkartelegend-${region}`);
23 | expect(imgElement).toBeInTheDocument();
24 | expect(imgElement).toHaveAttribute("src", `${mapping[region]}.png`);
25 | });
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/src/layerInfos/RegionenkartePublicLayerInfo/boundary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/layerInfos/RegionenkartePublicLayerInfo/boundary.png
--------------------------------------------------------------------------------
/src/layerInfos/RegionenkartePublicLayerInfo/gelb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/layerInfos/RegionenkartePublicLayerInfo/gelb.png
--------------------------------------------------------------------------------
/src/layerInfos/RegionenkartePublicLayerInfo/grun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/layerInfos/RegionenkartePublicLayerInfo/grun.png
--------------------------------------------------------------------------------
/src/layerInfos/RegionenkartePublicLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./RegionenkartePublicLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/RegionenkartePublicLayerInfo/lila.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/layerInfos/RegionenkartePublicLayerInfo/lila.png
--------------------------------------------------------------------------------
/src/layerInfos/RegionenkartePublicLayerInfo/rot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/layerInfos/RegionenkartePublicLayerInfo/rot.png
--------------------------------------------------------------------------------
/src/layerInfos/RegionenkartePublicTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./RegionenkartePublicTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/SandboxTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./SandboxTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/TarifverbundkarteTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TarifverbundkarteTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/ZweitausbildungLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ZweitausbildungLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/ZweitausbildungRoutesSubLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ZweitausbildungRoutesSubLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/ZweitausbildungSubLayerInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ZweitausbildungSubLayerInfo";
2 |
--------------------------------------------------------------------------------
/src/layerInfos/ZweitausbildungTopicInfo/ZweitausbildungTopicInfo.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useTranslation } from "react-i18next";
3 |
4 | function ZweitausbildungTopicInfo() {
5 | const { t } = useTranslation();
6 | return (
7 |
8 |
{t("ch.sbb.zweitausbildung-desc")}
9 |
10 | {t("Datenstand")}: {t("ch.sbb.zweitausbildung-datastatus")}
11 |
12 |
13 | {t("Verantwortlich")}:
14 |
15 | HR-POK-SKK-PM
16 |
17 | pm.skk.kbc@sbb.ch.
18 |
19 |
20 | );
21 | }
22 |
23 | export default ZweitausbildungTopicInfo;
24 |
--------------------------------------------------------------------------------
/src/layerInfos/ZweitausbildungTopicInfo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ZweitausbildungTopicInfo";
2 |
--------------------------------------------------------------------------------
/src/layers/AusbauLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./AusbauLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/BeleuchtungsLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./BeleuchtungsLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/DirektverbindungenLayer/DirektverbindungenLayer.test.js:
--------------------------------------------------------------------------------
1 | import { Layer } from "mobility-toolbox-js/ol";
2 | import OLMap from "ol/Map";
3 | import DirektverbindungenLayer from "./DirektverbindungenLayer";
4 |
5 | describe("DirektverbindungenLayer", () => {
6 | test("should become visible when night or day layer are hidden then day layer becomes visible", () => {
7 | const map = new OLMap({});
8 | const layer = new DirektverbindungenLayer({
9 | visible: false,
10 | properties: {
11 | dayLayer: new Layer({ visible: false }),
12 | nightLayer: new Layer({ visible: false }),
13 | },
14 | });
15 |
16 | // Listen day/night layer events
17 | layer.attachToMap(map);
18 |
19 | expect(layer.visible).toBe(false);
20 | layer.get("dayLayer").visible = true;
21 | expect(layer.visible).toBe(true);
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/src/layers/DirektverbindungenLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DirektverbindungenLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/DrawLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DrawLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/GeltungsbereicheLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./GeltungsbereicheLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/HandicapLayer/HandicapLayer.js:
--------------------------------------------------------------------------------
1 | import MapboxStyleLayer from "../MapboxStyleLayer";
2 |
3 | /**
4 | * Layer for Handicap
5 | * Extends {@link https://mobility-toolbox-js.geops.io/doc/class/build/ol/layers/MapboxStyleLayer%20js~MapboxStyleLayer%20html-offset-anchor}
6 | * @private
7 | * @class
8 | * @param {Object} [options] Layer options.
9 | */
10 | class HandicapLayer extends MapboxStyleLayer {
11 | getFeatureInfoAtCoordinate(coordinate) {
12 | return super.getFeatureInfoAtCoordinate(coordinate).then((data) => {
13 | // Remove duplicate features.
14 | return {
15 | ...data,
16 | features: data.features.reduce((acc, feature) => {
17 | return acc.find((f) => f.get("uic") === feature.get("uic"))
18 | ? acc
19 | : [...acc, feature];
20 | }, []),
21 | };
22 | });
23 | }
24 | }
25 |
26 | export default HandicapLayer;
27 |
--------------------------------------------------------------------------------
/src/layers/HandicapLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./HandicapLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/KilometrageLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./KilometrageLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/LevelLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./LevelLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/MapboxStyleLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MapboxStyleLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/MapsGeoAdminLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MapsGeoAdminLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/MesswagenLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MesswagenLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/PlatformsLayer/PlatformsLayer.test.js:
--------------------------------------------------------------------------------
1 | import MapboxStyleLayer from "../MapboxStyleLayer";
2 | import PlatformsLayer from "./PlatformsLayer";
3 |
4 | describe("PlatformsLayer", () => {
5 | test("return only one featureInfo to avoid duplicate data in der Popup [TRAFDATA-334]", (done) => {
6 | const feat1 = { id: "feat1" };
7 | const feat2 = { id: "feat2" };
8 | MapboxStyleLayer.prototype.getFeatureInfoAtCoordinate = jest.fn(() =>
9 | Promise.resolve({
10 | features: [feat1, feat2],
11 | }),
12 | );
13 | const layer = new PlatformsLayer();
14 | layer.getFeatureInfoAtCoordinate().then((featureInfo) => {
15 | expect(featureInfo.features.length).toBe(1);
16 | expect(featureInfo.features[0]).toBe(feat1);
17 | done();
18 | });
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/src/layers/PlatformsLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./PlatformsLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/RailplusLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./RailplusLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/RegionenkarteLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./RegionenkarteLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/SchmalspurLayer/SchmalspurLayer.js:
--------------------------------------------------------------------------------
1 | import MapboxStyleLayer from "../MapboxStyleLayer";
2 |
3 | /**
4 | * Layer for SchmalspurLayer
5 | * Extends {@link https://mobility-toolbox-js.geops.io/doc/class/build/ol/layers/MapboxStyleLayer%20js~MapboxStyleLayer%20html-offset-anchor}
6 | * @private
7 | * @class
8 | * @param {Object} [options] Layer options.
9 | */
10 | class SchmalspurLayer extends MapboxStyleLayer {
11 | onLoad() {
12 | super.onLoad();
13 | this.fetchSource();
14 | }
15 |
16 | fetchSource() {
17 | const { url } =
18 | this.mapboxLayer?.mbMap?.getSource("ch.sbb.isb.schmalspur") || {};
19 | fetch(url)
20 | .then((res) => res.json())
21 | .then((data) => {
22 | this.tuInfos = data["geops.isb.schmalspur.tu_info"];
23 | })
24 | // eslint-disable-next-line no-console
25 | .catch((err) => console.error(err));
26 | }
27 | }
28 |
29 | export default SchmalspurLayer;
30 |
--------------------------------------------------------------------------------
/src/layers/SchmalspurLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./SchmalspurLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/StationsLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./StationsLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/StsHighlightRoutesLayer/StsHighlightRoutesLayer.js:
--------------------------------------------------------------------------------
1 | import MapboxStyleLayer from "../MapboxStyleLayer";
2 |
3 | const lineWidth = 15;
4 |
5 | class HighlightRoutesLayer extends MapboxStyleLayer {
6 | highlightRoutes(names = [], property = "route_names_premium") {
7 | const { mbMap, loaded } = this.mapboxLayer || {};
8 | if (loaded && mbMap && mbMap.getStyle()) {
9 | let lineWidthProp = 0;
10 | if (names.length) {
11 | const any = ["any"];
12 | names.forEach((name) => {
13 | any.push(["in", name, ["get", property]]);
14 | });
15 | lineWidthProp = ["case", any, lineWidth, 0];
16 | }
17 | mbMap
18 | .getStyle()
19 | .layers.filter(this.styleLayersFilter)
20 | .forEach((layer) => {
21 | mbMap.setPaintProperty(layer.id, "line-opacity", 0.8);
22 | mbMap.setPaintProperty(layer.id, "line-width", lineWidthProp);
23 | });
24 | }
25 | }
26 | }
27 |
28 | export default HighlightRoutesLayer;
29 |
--------------------------------------------------------------------------------
/src/layers/StsHighlightRoutesLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./StsHighlightRoutesLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/StsPoisLayer/StsPoisLayer.test.js:
--------------------------------------------------------------------------------
1 | import StsPoisLayer from "./StsPoisLayer";
2 |
3 | describe("StsPoisLayer", () => {
4 | test("sets up a correct ol layer", () => {
5 | const layer = new StsPoisLayer();
6 | expect(layer.olLayer.getSource().getUrl()).toBe(
7 | "https://maps.trafimage.ch/sts-static/pois.geojson",
8 | );
9 | expect(layer.olLayer.getSource().getFormat().dataProjection.getCode()).toBe(
10 | "EPSG:4326",
11 | );
12 | expect(
13 | layer.olLayer.getSource().getFormat().defaultFeatureProjection.getCode(),
14 | ).toBe("EPSG:3857");
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/layers/StsPoisLayer/img/poi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/layers/StsPoisLayer/img/poi.png
--------------------------------------------------------------------------------
/src/layers/StsPoisLayer/img/poi_hl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/layers/StsPoisLayer/img/poi_hl.png
--------------------------------------------------------------------------------
/src/layers/StsPoisLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./StsPoisLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/TarifverbundkarteLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TarifverbundkarteLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/TrafimageMapboxLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TrafimageMapboxLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/TralisLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TralisLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/ZweitausbildungAbroadLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ZweitausbildungAbroadLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/ZweitausbildungPoisLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ZweitausbildungPoisLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/ZweitausbildungRoutesHighlightLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ZweitausbildungRoutesHighlightLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/ZweitausbildungRoutesLayer/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ZweitausbildungRoutesLayer";
2 |
--------------------------------------------------------------------------------
/src/layers/ZweitausbildungRoutesLayer/lines.test.js:
--------------------------------------------------------------------------------
1 | import lines from "./lines";
2 |
3 | describe("lines", () => {
4 | test("must no have a string as key that is included in another key (that means style is probably broken)", () => {
5 | let hasWrongKey = false;
6 | Object.keys(lines).forEach((key) => {
7 | Object.keys(lines).forEach((key2) => {
8 | if (key !== key2 && key2.includes(key)) {
9 | // eslint-disable-next-line no-console
10 | console.log("Bad key key1:", key, "key2:", key2);
11 | hasWrongKey = true;
12 | }
13 | });
14 | });
15 |
16 | expect(hasWrongKey).toBe(false);
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/src/menus/DirektverbindungenMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DvMenu";
2 |
--------------------------------------------------------------------------------
/src/menus/DrawMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DrawMenu";
2 |
--------------------------------------------------------------------------------
/src/menus/ExportMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ExportMenu";
2 |
--------------------------------------------------------------------------------
/src/menus/GaExportMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./GaExportMenu";
2 |
--------------------------------------------------------------------------------
/src/menus/GeltungsbereicheTopicMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./GeltungsbereicheTopicMenu";
2 |
--------------------------------------------------------------------------------
/src/menus/IframeMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./IframeMenu";
2 |
--------------------------------------------------------------------------------
/src/menus/RailplusMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./RailplusMenu";
2 |
--------------------------------------------------------------------------------
/src/menus/ShareMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ShareMenu";
2 |
--------------------------------------------------------------------------------
/src/menus/StsMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./StsMenu";
2 |
--------------------------------------------------------------------------------
/src/menus/TrackerMenu/TrackerMenu.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useTranslation } from "react-i18next";
3 | import { TiVideo } from "react-icons/ti";
4 | import FeatureMenu from "../../components/FeatureMenu";
5 |
6 | /**
7 | * Menu use to display feature info from punctuality layers.
8 | */
9 | function TrackerMenu(props) {
10 | const { t } = useTranslation();
11 |
12 | return (
13 | ,
20 | }}
21 | />
22 | );
23 | }
24 |
25 | export default React.memo(TrackerMenu);
26 |
--------------------------------------------------------------------------------
/src/menus/TrackerMenu/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TrackerMenu";
2 |
--------------------------------------------------------------------------------
/src/model/map/actions.js:
--------------------------------------------------------------------------------
1 | export const SET_LAYERS = "SET_LAYERS";
2 | export const SET_LAYER_SERVICE = "SET_LAYER_SERVICE";
3 | export const SET_CENTER = "SET_CENTER";
4 | export const SET_RESOLUTION = "SET_RESOLUTION";
5 | export const SET_ZOOM = "SET_ZOOM";
6 | export const SET_MAX_EXTENT = "SET_MAX_EXTENT";
7 | export const SET_MAX_ZOOM = "SET_MAX_ZOOM";
8 | export const SET_MIN_ZOOM = "SET_MIN_ZOOM";
9 | export const SET_ZOOM_TYPE = "SET_ZOOM_TYPE";
10 |
11 | export const setLayers = (data) => ({ type: SET_LAYERS, data });
12 |
13 | export const setCenter = (data) => ({ type: SET_CENTER, data });
14 |
15 | export const setResolution = (data) => ({ type: SET_RESOLUTION, data });
16 |
17 | export const setZoom = (data) => ({ type: SET_ZOOM, data });
18 |
19 | export const setMaxExtent = (data) => ({ type: SET_MAX_EXTENT, data });
20 |
21 | export const setMaxZoom = (data) => ({ type: SET_MAX_ZOOM, data });
22 |
23 | export const setMinZoom = (data) => ({ type: SET_MIN_ZOOM, data });
24 |
25 | export const setZoomType = (data) => ({ type: SET_ZOOM_TYPE, data });
26 |
--------------------------------------------------------------------------------
/src/model/store.js:
--------------------------------------------------------------------------------
1 | import {
2 | legacy_createStore as createStore,
3 | applyMiddleware,
4 | compose,
5 | combineReducers,
6 | } from "redux";
7 | import { thunk } from "redux-thunk";
8 | import createDebounce from "redux-debounced";
9 | import map from "./map/reducers";
10 | import app from "./app/reducers";
11 |
12 | // reduxjstoolkit:
13 |
14 | // const store = configureStore({
15 | // // Automatically calls `combineReducers`
16 | // reducer: {
17 | // app,
18 | // map,
19 | // },
20 | // middleware: (getDefaultMiddleware) => {
21 | // return getDefaultMiddleware().concat(createDebounce());
22 | // },
23 | // });
24 | /* eslint-disable */
25 | const getStore = () => {
26 | const store = createStore(
27 | combineReducers({
28 | app,
29 | map,
30 | }),
31 | compose(applyMiddleware(createDebounce(), thunk)),
32 | );
33 |
34 | return store;
35 | };
36 |
37 | export default getStore;
38 |
--------------------------------------------------------------------------------
/src/popups/BahnhofplanPopup/BahnhofplanPopup.scss:
--------------------------------------------------------------------------------
1 | .wkp-bahnhofplan-popup {
2 | svg {
3 | margin-left: 5px;
4 | }
5 |
6 | .wkp-bahnhofplan-popup-title {
7 | font-weight: bold;
8 | }
9 |
10 | a {
11 | text-decoration: none !important;
12 | }
13 |
14 | div {
15 | padding: 3px 0;
16 | border-width: 0 0 1px;
17 | border-style: solid;
18 | border-color: #eee;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/popups/BahnhofplanPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./BahnhofplanPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/BeleuchtungsPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./BeleuchtungsPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/BetriebsRegionenPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./BetriebsRegionenPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/BusLinePopup/BusLinePopup.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import Feature from "ol/Feature";
4 |
5 | const propTypes = {
6 | feature: PropTypes.instanceOf(Feature).isRequired,
7 | };
8 |
9 | function BusLinePopup({ feature }) {
10 | const props = feature.getProperties();
11 | return (
12 |
13 | {Object.entries(props).map(([key, value]) => {
14 | if (!/^lines /.test(key)) {
15 | return null;
16 | }
17 | return (
18 |
19 |
{key.replace("lines ", "")}
20 |
{value}
21 |
22 | );
23 | })}
24 |
25 | );
26 | }
27 |
28 | BusLinePopup.propTypes = propTypes;
29 |
30 | export default React.memo(BusLinePopup);
31 |
--------------------------------------------------------------------------------
/src/popups/BusLinePopup/BusLinePopup.scss:
--------------------------------------------------------------------------------
1 | .wkp-bus-line-popup {
2 | > div {
3 | display: flex;
4 | align-content: center;
5 | margin: 10px 0;
6 |
7 | > div:first-child {
8 | font-weight: bold;
9 | width: 100px;
10 | margin-right: 10px;
11 | }
12 |
13 | > div:last-child {
14 | width: 200px;
15 | max-height: 100px;
16 | overflow-y: auto;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/popups/BusLinePopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./BusLinePopup";
2 |
--------------------------------------------------------------------------------
/src/popups/CasaRoutePopup/CasaRoutePopup.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import Feature from "ol/Feature";
4 |
5 | const propTypes = {
6 | feature: PropTypes.instanceOf(Feature).isRequired,
7 | };
8 |
9 | function CasaRoutePopup({ feature }) {
10 | const route = feature.get("route");
11 |
12 | return (
13 |
14 | {route.popupContent.map((item) => (
15 |
18 | ))}
19 |
20 | );
21 | }
22 |
23 | CasaRoutePopup.propTypes = propTypes;
24 |
25 | CasaRoutePopup.hideHeader = (feature) => {
26 | const route = feature.get("route");
27 | return !route.popupTitle;
28 | };
29 |
30 | CasaRoutePopup.renderTitle = (feature) => {
31 | const route = feature.get("route");
32 | return route.popupTitle;
33 | };
34 |
35 | export default CasaRoutePopup;
36 |
--------------------------------------------------------------------------------
/src/popups/CasaRoutePopup/CasaRoutePopup.scss:
--------------------------------------------------------------------------------
1 | .wkp-casa-route-popup {
2 | .wkp-casa-route-popup-row {
3 | padding: 3px;
4 |
5 | pre {
6 | font-size: inherit;
7 | color: inherit;
8 | margin: inherit;
9 | font-family: inherit;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/popups/CasaRoutePopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./CasaRoutePopup";
2 |
--------------------------------------------------------------------------------
/src/popups/ConstructionPopup/ConstructionPopup.scss:
--------------------------------------------------------------------------------
1 | .wkp-construction-popup {
2 | .wkp-construction-popup-subtitle {
3 | font-style: italic;
4 | padding-bottom: 7px;
5 | }
6 |
7 | .wkp-construction-popup-desc {
8 | padding-bottom: 4px;
9 | }
10 |
11 | .wkp-construction-popup-link {
12 | padding: 3px 0;
13 | border-width: 1px 0 0;
14 | border-style: solid;
15 | border-color: #eee;
16 |
17 | &:last-child {
18 | border-bottom-width: 1px;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/popups/ConstructionPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ConstructionPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/DeparturePopup/DeparturePopup.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import Feature from "ol/Feature";
4 | import { withTranslation } from "react-i18next";
5 | import DeparturePopupContent from "./DeparturePopupContent";
6 |
7 | function DeparturePopup({ feature, children }) {
8 | const platform = feature.get("platform");
9 | const uic = parseFloat(feature.get("sbb_id"));
10 |
11 | return (
12 |
13 | {children}
14 |
15 | );
16 | }
17 |
18 | DeparturePopup.propTypes = {
19 | feature: PropTypes.instanceOf(Feature).isRequired,
20 | children: PropTypes.node,
21 | };
22 | DeparturePopup.defaultProps = { children: undefined };
23 |
24 | const composed = withTranslation()(DeparturePopup);
25 | composed.renderTitle = (feat, layer, t) => {
26 | const platform = feat.get("platform");
27 | if (platform) {
28 | return `${feat.get("name")} (${t("abfahrtszeiten_kante")} ${platform})`;
29 | }
30 | return feat.get("name");
31 | };
32 |
33 | export default composed;
34 |
--------------------------------------------------------------------------------
/src/popups/DeparturePopup/DestinationInput.scss:
--------------------------------------------------------------------------------
1 | .tm-departure-input {
2 | position: relative;
3 |
4 | .tm-search-input {
5 | input {
6 | padding: 0 7px;
7 | }
8 |
9 | .tm-bt-search {
10 | display: none;
11 | }
12 | }
13 |
14 | .tm-autocomplete .tm-autocomplete-results {
15 | max-height: 140px;
16 | }
17 |
18 | .tm-list li {
19 | line-height: 20px;
20 | padding: 4px 7px;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/popups/DeparturePopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DeparturePopup";
2 |
--------------------------------------------------------------------------------
/src/popups/DirektverbindungenPopup/DvPopup.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { makeStyles } from "@mui/styles";
3 | import DvFeatureInfo from "../../config/ch.sbb.direktverbindungen/DvFeatureInfo";
4 | import { DvFeatureInfoTitleString } from "../../config/ch.sbb.direktverbindungen/DvFeatureInfoTitle/DvFeatureInfoTitle";
5 |
6 | const useStyles = makeStyles({
7 | container: {
8 | padding: "0 !important",
9 | },
10 | });
11 |
12 | function DvPopup() {
13 | const classes = useStyles();
14 |
15 | return (
16 |
17 |
18 |
19 | );
20 | }
21 |
22 | const memoized = React.memo(DvPopup);
23 | memoized.renderTitle = () => (
24 |
25 |
26 |
27 | );
28 | memoized.hidePagination = true;
29 |
30 | export default memoized;
31 |
--------------------------------------------------------------------------------
/src/popups/DirektverbindungenPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DvPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/DrawPopup/DrawPopup.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import Feature from "ol/Feature";
4 |
5 | function DrawPopup({ feature }) {
6 | const descr = feature.get("description");
7 | if (!descr) {
8 | return null;
9 | }
10 |
11 | return (
12 |
16 | );
17 | }
18 |
19 | DrawPopup.propTypes = {
20 | feature: PropTypes.instanceOf(Feature).isRequired,
21 | };
22 |
23 | const composed = React.memo(DrawPopup);
24 |
25 | composed.renderTitle = (feature) => feature.get("name");
26 | export default composed;
27 |
--------------------------------------------------------------------------------
/src/popups/DrawPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./DrawPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/EnergiePopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./EnergiePopup";
2 |
--------------------------------------------------------------------------------
/src/popups/GeltungsbereicheGaPopup/GeltungsbereicheLegend.test.js:
--------------------------------------------------------------------------------
1 | import { getLegends } from "./GeltungsbereicheLegend";
2 |
3 | describe("GeltungsbereicheLegend", () => {
4 | test("exports legends that have the good mots order", () => {
5 | expect(
6 | Object.values(getLegends()).map(({ mots }) => mots && mots[0]),
7 | ).toEqual(["rail", "bus", "gondola", "ferry", null]);
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/src/popups/GeltungsbereicheGaPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./GeltungsbereicheGaPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/HandicapPopup/HandicapPopup.scss:
--------------------------------------------------------------------------------
1 | .wkp-handicap-popup {
2 | p {
3 | margin-block: 0;
4 | }
5 |
6 | .wkp-handicap-popup-body {
7 | .wkp-handicap-popup-title {
8 | font-weight: bold;
9 | margin-bottom: 10px;
10 | }
11 |
12 | .wkp-handicap-popup-element {
13 | padding-bottom: 10px;
14 | flex-direction: column;
15 | display: flex;
16 |
17 | a {
18 | white-space: nowrap;
19 | }
20 |
21 | &:last-child {
22 | padding: 0;
23 | }
24 |
25 | .wkp-handicap-popup-field-title {
26 | font-weight: bold;
27 | vertical-align: top;
28 | padding-right: 20px;
29 | }
30 |
31 | .wkp-handicap-popup-field-body {
32 | word-break: break-word;
33 | }
34 | }
35 |
36 | .wkp-handicap-popup-bottom {
37 | display: flex;
38 | justify-content: space-between;
39 | flex-wrap: wrap;
40 |
41 | .wkp-handicap-popup-element {
42 | min-width: 180px;
43 | width: 50%;
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/popups/HandicapPopup/README.md:
--------------------------------------------------------------------------------
1 | #
2 |
3 | Example of the Handicap topic together with its menu component.
4 |
5 | ```jsx
6 | import React from 'react';
7 | import { handicap } from '../../config/topics';
8 | import { HandicapMenu } from '../../config/menu';
9 |
10 | import TrafimageMaps from '../../components/TrafimageMaps';
11 |
12 | // The `apiKey` used here is for demonstration purposes only.
13 | // Please get your own api key at https://developer.geops.io/.
14 | const apiKey = window.apiKey;
15 |
16 |
17 |
38 |
;
39 | ```
40 |
--------------------------------------------------------------------------------
/src/popups/HandicapPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./HandicapPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/IsbPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./IsbPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/KilometragePopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./KilometragePopup";
2 |
--------------------------------------------------------------------------------
/src/popups/MapsGeoAdminPopup/MapsGeoAdminPopup.scss:
--------------------------------------------------------------------------------
1 | .wkp-maps-geo-admin-popup {
2 | .wkp-maps-geo-admin-popup-body {
3 | max-height: 200px;
4 | min-width: 300px;
5 | }
6 |
7 | .htmlpopup-header {
8 | font-family: SBBWeb-Bold, Arial, sans-serif;
9 | }
10 |
11 | .htmlpopup-content {
12 | table {
13 | border-spacing: 0 4px;
14 | padding: 10px 0;
15 | }
16 |
17 | .cell-left {
18 | vertical-align: top;
19 | min-width: 150px;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/popups/MapsGeoAdminPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MapsGeoAdminPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/MesswagenPhotosPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MesswagenPhotosPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/MesswagenPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./MesswagenPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/NetzkartePopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./NetzkartePopup";
2 |
--------------------------------------------------------------------------------
/src/popups/PassagierFrequenzenPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./PassagierFrequenzenPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/PunctualityPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./PunctualityPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/RailplusPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./RailplusPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/RegionenkarteIntersectionPopup/RegionenkarteIntersectionPopup.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import Feature from "ol/Feature";
4 | import { makeStyles } from "@mui/styles";
5 |
6 | const useStyles = makeStyles(() => ({
7 | root: {
8 | flex: 1,
9 | display: "flex",
10 | alignItems: "center",
11 | justifyContent: "center",
12 | minWidth: "100px !important",
13 | },
14 | }));
15 |
16 | function RegionenkarteIntersectionPopup({ feature }) {
17 | const classes = useStyles();
18 | return {feature.get("label")}
;
19 | }
20 |
21 | RegionenkarteIntersectionPopup.propTypes = {
22 | feature: PropTypes.instanceOf(Feature).isRequired,
23 | };
24 |
25 | RegionenkarteIntersectionPopup.hideHeader = () => true;
26 |
27 | export default RegionenkarteIntersectionPopup;
28 |
--------------------------------------------------------------------------------
/src/popups/RegionenkarteIntersectionPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./RegionenkarteIntersectionPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/RegionenkarteSegmentPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./RegionenkarteSegmentPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/SchmalspurPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./SchmalspurPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/StationPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./StationPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/StopPlacePopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./StopPlacePopup";
2 |
--------------------------------------------------------------------------------
/src/popups/TarifverbundkartePopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TarifverbundkartePopup";
2 |
--------------------------------------------------------------------------------
/src/popups/ZweitausbildungAbroadPopup/ZweitausbildungAbroadPopup.js:
--------------------------------------------------------------------------------
1 | import { PureComponent } from "react";
2 | import PropTypes from "prop-types";
3 | import Feature from "ol/Feature";
4 | import { connect } from "react-redux";
5 | import { compose } from "redux";
6 | import { setFeatureInfo } from "../../model/app/actions";
7 |
8 | const propTypes = {
9 | feature: PropTypes.instanceOf(Feature).isRequired,
10 |
11 | // mapDispatchToProps
12 | dispatchSetFeatureInfo: PropTypes.func.isRequired,
13 | };
14 |
15 | class ZweitausbildungAbroadPopup extends PureComponent {
16 | componentDidMount() {
17 | const { feature, dispatchSetFeatureInfo } = this.props;
18 | window.open(feature.get("url"), "_blank");
19 | dispatchSetFeatureInfo();
20 | }
21 |
22 | render() {
23 | return null;
24 | }
25 | }
26 |
27 | ZweitausbildungAbroadPopup.propTypes = propTypes;
28 |
29 | const mapDispatchToProps = {
30 | dispatchSetFeatureInfo: setFeatureInfo,
31 | };
32 |
33 | export default compose(connect(null, mapDispatchToProps))(
34 | ZweitausbildungAbroadPopup,
35 | );
36 |
--------------------------------------------------------------------------------
/src/popups/ZweitausbildungAbroadPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ZweitausbildungAbroadPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/ZweitausbildungPoisPopup/ZweitausbildungPoisPopup.scss:
--------------------------------------------------------------------------------
1 | .wkp-zweitausbildung-pois-popup {
2 | overflow-y: auto;
3 |
4 | .wkp-zweitausbildung-pois-popup-row {
5 | border-bottom: dashed 1px #bebebe;
6 | padding-top: 5px;
7 |
8 | &:hover {
9 | background-color: #eaeaea;
10 | }
11 | }
12 |
13 | .wkp-zweitausbildung-pois-popup-railaway {
14 | font-style: italic;
15 | }
16 |
17 | .wkp-zweitausbildung-pois-popup-image {
18 | padding: 6px;
19 |
20 | img {
21 | max-width: 100%;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/popups/ZweitausbildungPoisPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ZweitausbildungPoisPopup";
2 |
--------------------------------------------------------------------------------
/src/popups/ZweitausbildungRoutesPopup/ZweitausbildungRoutesPopup.scss:
--------------------------------------------------------------------------------
1 | .wkp-zweitausbildung-routes-popup {
2 | overflow-y: auto;
3 |
4 | .wkp-zweitausbildung-routes-popup-row {
5 | min-height: 50px;
6 | border-bottom: dashed 1px #bebebe;
7 | padding-top: 5px;
8 |
9 | &.highlight {
10 | background-color: #eaeaea;
11 | }
12 | }
13 |
14 | .wkp-zweitausbildung-routes-popup-image > img {
15 | vertical-align: middle;
16 | padding: 3px 5px 3px 0;
17 | }
18 |
19 | .wkp-zweitausbildung-routes-popup-desc {
20 | padding-top: 5px;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/popups/ZweitausbildungRoutesPopup/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ZweitausbildungRoutesPopup";
2 |
--------------------------------------------------------------------------------
/src/searches/Betriebspunkte/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Betriebspunkte";
2 |
--------------------------------------------------------------------------------
/src/searches/HandicapStopFinder/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./HandicapStopFinder";
2 |
--------------------------------------------------------------------------------
/src/searches/Lines/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Lines";
2 |
--------------------------------------------------------------------------------
/src/searches/Locations/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Locations";
2 |
--------------------------------------------------------------------------------
/src/searches/Municipalities/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Municipalities";
2 |
--------------------------------------------------------------------------------
/src/searches/Search.test.js:
--------------------------------------------------------------------------------
1 | import { Style } from "ol/style";
2 | import Search from "./Search";
3 |
4 | describe("Search", () => {
5 | describe("#getFeatures()", () => {
6 | test("applies the highlightStyle on each feature", () => {
7 | const search = new Search();
8 | search.highlightStyle = new Style({});
9 | const feat = search.getFeature({
10 | type: "Feature",
11 | geometry: {
12 | type: "Point",
13 | coordinates: [0, 0],
14 | },
15 | properties: {},
16 | });
17 |
18 | expect(feat.getStyle()).toBe(search.highlightStyle);
19 | });
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/src/searches/StopFinder/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./StopFinder";
2 |
--------------------------------------------------------------------------------
/src/searches/index.js:
--------------------------------------------------------------------------------
1 | import Betriebspunkte from "./Betriebspunkte";
2 | import HandicapStopFinder from "./HandicapStopFinder";
3 | import Lines from "./Lines";
4 | import Locations from "./Locations";
5 | import Municipalities from "./Municipalities";
6 | import StopFinder from "./StopFinder";
7 | import Search from "./Search";
8 |
9 | export { default as Betriebspunkte } from "./Betriebspunkte";
10 | export { default as HandicapStopFinder } from "./HandicapStopFinder";
11 | export { default as Lines } from "./Lines";
12 | export { default as Locations } from "./Locations";
13 | export { default as Municipalities } from "./Municipalities";
14 | export { default as StopFinder } from "./StopFinder";
15 | export { default as Search } from "./Search";
16 |
17 | export default {
18 | Betriebspunkte,
19 | HandicapStopFinder,
20 | Lines,
21 | Locations,
22 | Municipalities,
23 | StopFinder,
24 | Search,
25 | };
26 |
--------------------------------------------------------------------------------
/src/themes/react-ui/components.scss:
--------------------------------------------------------------------------------
1 | /* stylelint-disable import-notation */
2 | /* stylelint-disable scss/at-import-partial-extension */
3 |
4 | /**
5 | * This file load the css of components.
6 | */
7 | @import '../../components/Autocomplete/Autocomplete.scss';
8 | @import '../../components/Button/Button.scss';
9 | @import '../../components/Checkbox/Checkbox.scss';
10 | @import '../../components/Dialog/Dialog.scss';
11 | @import '../../components/Footer/Footer.scss';
12 | @import '../../components/Header/Header.scss';
13 | @import '../../components/List/List.scss';
14 | @import '../../components/Menu/Menu.scss';
15 | @import '../../components/MenuItem/MenuItem.scss';
16 | @import '../../components/Overlay/Overlay.scss';
17 | @import '../../components/PermalinkInput/PermalinkInput.scss';
18 | @import '../../components/SearchInput/SearchInput.scss';
19 | @import '../../components/Sidebar/Sidebar.scss';
20 | @import '../../components/SidebarMenuItem/SidebarMenuItem.scss';
21 | @import '../../components/Tabs/Tabs.scss';
22 | @import '../../components/Tab/Tab.scss';
23 |
--------------------------------------------------------------------------------
/src/themes/react-ui/index.scss:
--------------------------------------------------------------------------------
1 | /* stylelint-disable scss/at-import-partial-extension */
2 | /* stylelint-disable import-notation */
3 |
4 | /**
5 | * This file load the default theme, for all the components.
6 | */
7 | @import './variables.scss';
8 | @import './mixins.scss';
9 | @import './components.scss';
10 |
11 | [role='button']:not([disable]),
12 | button:not([disable]),
13 | a:not([disable]) {
14 | cursor: pointer;
15 | }
16 |
--------------------------------------------------------------------------------
/src/utils/capitalizeFirstLetter.js:
--------------------------------------------------------------------------------
1 | const capitalizeFirstLetter = (string) => {
2 | return string.charAt(0).toUpperCase() + string.slice(1);
3 | };
4 |
5 | export default capitalizeFirstLetter;
6 |
--------------------------------------------------------------------------------
/src/utils/coordinateHelper.js:
--------------------------------------------------------------------------------
1 | function meterFormat(coords) {
2 | return coords.map((num) =>
3 | Math.round(num)
4 | .toString()
5 | .replace(/\B(?=(\d{3})+(?!\d))/g, "'"),
6 | );
7 | }
8 |
9 | function wgs84Format(coords, decimalSep = ".") {
10 | return coords.map((num) => num.toFixed(5).replace(".", decimalSep));
11 | }
12 |
13 | export default { meterFormat, wgs84Format };
14 |
--------------------------------------------------------------------------------
/src/utils/coordinateHelper.test.js:
--------------------------------------------------------------------------------
1 | import coordinateHelper from "./coordinateHelper";
2 |
3 | describe("coordinateHelper", () => {
4 | test("should format coordinates correcly.", () => {
5 | expect(
6 | coordinateHelper.wgs84Format([8.298163986976597, 47.041177354357444]),
7 | ).toEqual(["8.29816", "47.04118"]);
8 | expect(
9 | coordinateHelper.wgs84Format(
10 | [8.298163986976597, 47.041177354357444],
11 | ",",
12 | ),
13 | ).toEqual(["8,29816", "47,04118"]);
14 | expect(
15 | coordinateHelper.meterFormat([929977.0073545576, 5948635.427925528]),
16 | ).toEqual(["929'977", "5'948'635"]);
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Bold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Bold.eot
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Bold.ttf
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Bold.woff
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Bold.woff2
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Italic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Italic.eot
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Italic.ttf
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Italic.woff
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Italic.woff2
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Light.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Light.eot
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Light.ttf
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Light.woff
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Light.woff2
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Roman.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Roman.eot
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Roman.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Roman.ttf
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Roman.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Roman.woff
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Roman.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Roman.woff2
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Thin.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Thin.eot
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Thin.ttf
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Thin.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Thin.woff
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-Thin.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-Thin.woff2
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-UltraLight.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-UltraLight.eot
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-UltraLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-UltraLight.ttf
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-UltraLight.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-UltraLight.woff
--------------------------------------------------------------------------------
/src/utils/fonts/SBBWeb-UltraLight.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geops/trafimage-maps/d9e73607456380022fdc688a0cee789b53624cba/src/utils/fonts/SBBWeb-UltraLight.woff2
--------------------------------------------------------------------------------
/src/utils/formatPhone.js:
--------------------------------------------------------------------------------
1 | const formatPhone = (phone) => {
2 | try {
3 | return phone
4 | .split(/(\+41)(\d{2})(\d{3})(\d{2})(\d{2})/g)
5 | .join(" ")
6 | .trim();
7 | } catch (e) {
8 | return phone;
9 | }
10 | };
11 |
12 | export default formatPhone;
13 |
--------------------------------------------------------------------------------
/src/utils/getDelayString.js:
--------------------------------------------------------------------------------
1 | // We round the minutes down for departure times and up for arrival times.
2 | export const getDelaySecure = (milliseconds, isArrival) => {
3 | let timeInMs = milliseconds;
4 | if (timeInMs < 0) {
5 | timeInMs = 0;
6 | }
7 | const h = Math.floor(timeInMs / 3600000);
8 | const m = (isArrival ? Math.ceil : Math.floor)((timeInMs % 3600000) / 60000);
9 |
10 | return h * 3600000 + m * 60000;
11 | };
12 |
13 | // We round the minutes down for departure times and up for arrival times.
14 | const getDelayString = (milliseconds, isArrival) => {
15 | let timeInMs = milliseconds;
16 | if (timeInMs < 0) {
17 | timeInMs = 0;
18 | }
19 | timeInMs = getDelaySecure(timeInMs, isArrival);
20 | const h = Math.floor(timeInMs / 3600000);
21 | const m = (timeInMs % 3600000) / 60000;
22 |
23 | if (h === 0 && m === 0) {
24 | return "+0m";
25 | }
26 | if (h === 0) {
27 | return `+${m}m`;
28 | }
29 |
30 | let str = `+`;
31 | if (h > 0) {
32 | str += `${h}h`;
33 | }
34 |
35 | if (m > 0) {
36 | str += `${m}m`;
37 | }
38 | return str;
39 | };
40 |
41 | export default getDelayString;
42 |
--------------------------------------------------------------------------------
/src/utils/getDelayString.test.js:
--------------------------------------------------------------------------------
1 | import getDelayString from "./getDelayString";
2 |
3 | describe("getDelayString", () => {
4 | it('should return "+0m" when delay <= 0', () => {
5 | expect(getDelayString(0)).toBe("+0m");
6 | expect(getDelayString(-1)).toBe("+0m");
7 | });
8 |
9 | it('should return "+Xm" when delay is between hours and 0', () => {
10 | expect(getDelayString(69000)).toBe("+1m");
11 | expect(getDelayString(129000)).toBe("+2m");
12 | });
13 |
14 | it('should return "+XhXm" when delay is more than 1 hour', () => {
15 | expect(getDelayString(3659000)).toBe("+1h");
16 | expect(getDelayString(3661000)).toBe("+1h1m");
17 | expect(getDelayString(36610000)).toBe("+10h10m");
18 | });
19 |
20 | it("should ceil the result if it is an arrival time", () => {
21 | expect(getDelayString(3659000, true)).toBe("+1h1m");
22 | expect(getDelayString(3659000)).toBe("+1h");
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/src/utils/getFeatureInfoAtCoordinate.js:
--------------------------------------------------------------------------------
1 | const getFeatureInfoAtCoordinate = (coordinate, layers, eventType) => {
2 | const promises = layers.map((layer) => {
3 | return layer
4 | .getFeatureInfoAtCoordinate(coordinate, eventType)
5 | .then((featureInfo) => {
6 | return featureInfo;
7 | });
8 | });
9 | return Promise.all(promises);
10 | };
11 |
12 | export default getFeatureInfoAtCoordinate;
13 |
--------------------------------------------------------------------------------
/src/utils/getGreaterNumber.js:
--------------------------------------------------------------------------------
1 | // Get the first number that is higher or equal than the given number.
2 | function getGreaterNumber(number, numbers) {
3 | const sorted = [...numbers].sort((a, b) => a - b);
4 | return (
5 | sorted.find((nb) => {
6 | return number <= nb;
7 | }) || sorted.pop()
8 | );
9 | }
10 |
11 | export default getGreaterNumber;
12 |
--------------------------------------------------------------------------------
/src/utils/getGreaterNumber.test.js:
--------------------------------------------------------------------------------
1 | import getGreaterNumber from "./getGreaterNumber";
2 |
3 | test(`#getGreaterNumber()`, () => {
4 | let gen = getGreaterNumber(20.01, [200, 50, 100, 20, 10, 5]);
5 | expect(gen).toBe(50);
6 | gen = getGreaterNumber(50, [200, 50, 100, 20, 10, 5]);
7 | expect(gen).toBe(50);
8 | gen = getGreaterNumber(300, [200, 50, 100, 20, 10, 5]);
9 | expect(gen).toBe(200);
10 | gen = getGreaterNumber(0, [200, 50, 100, 20, 10, 5]);
11 | expect(gen).toBe(5);
12 | });
13 |
--------------------------------------------------------------------------------
/src/utils/getIsMobileDevice.js:
--------------------------------------------------------------------------------
1 | const getIsMobileDevice = () => {
2 | return !!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
3 | navigator.userAgent,
4 | );
5 | };
6 |
7 | export default getIsMobileDevice;
8 |
--------------------------------------------------------------------------------
/src/utils/getLayersAsFlatArray.js:
--------------------------------------------------------------------------------
1 | const getLayersAsFlatArray = (optLayers = []) => {
2 | let layers = [];
3 | optLayers.forEach((l) => {
4 | layers.push(l);
5 | const { children } = l;
6 | layers = layers.concat(getLayersAsFlatArray(children));
7 | });
8 | return layers;
9 | };
10 |
11 | export default getLayersAsFlatArray;
12 |
--------------------------------------------------------------------------------
/src/utils/getPopupComponent.js:
--------------------------------------------------------------------------------
1 | import popups from "../popups";
2 |
3 | const getPopupComponent = ({ popupComponent, layer }) => {
4 | const comp = popupComponent || layer.get("popupComponent");
5 | return typeof comp === "string" ? popups[comp] : comp;
6 | };
7 |
8 | export default getPopupComponent;
9 |
--------------------------------------------------------------------------------
/src/utils/getQueryableLayers.js:
--------------------------------------------------------------------------------
1 | import getLayersAsFlatArray from "./getLayersAsFlatArray";
2 |
3 | const getQueryableLayers = (featureInfoEventType, layers, map) => {
4 | return getLayersAsFlatArray(layers).filter((layer) => {
5 | let isQueryable =
6 | layer.visible &&
7 | layer.get("isQueryable") &&
8 | (
9 | layer.get("featureInfoEventTypes") || ["pointermove", "singleclick"]
10 | ).includes(featureInfoEventType);
11 |
12 | if (typeof layer.get("isQueryable") === "function") {
13 | isQueryable = layer.get("isQueryable")(map);
14 | }
15 | return isQueryable;
16 | });
17 | };
18 |
19 | export default getQueryableLayers;
20 |
--------------------------------------------------------------------------------
/src/utils/getTrafimageFilter.js:
--------------------------------------------------------------------------------
1 | const getTrafimageFilter = (
2 | stylelayer,
3 | filterAttribute = "trafimage.filter",
4 | ) => {
5 | return stylelayer?.metadata && stylelayer.metadata[filterAttribute];
6 | };
7 |
8 | export default getTrafimageFilter;
9 |
--------------------------------------------------------------------------------
/src/utils/highlightPointStyle.test.js:
--------------------------------------------------------------------------------
1 | import highlightPointStyle from "./highlightPointStyle";
2 |
3 | let context = null;
4 |
5 | describe("higlightPointStyle", () => {
6 | beforeEach(() => {
7 | context = {
8 | createRadialGradient: jest.fn(() => ({
9 | addColorStop: jest.fn(),
10 | })),
11 | beginPath: jest.fn(),
12 | fill: jest.fn(),
13 | stroke: jest.fn(),
14 | arc: jest.fn(),
15 | };
16 | });
17 |
18 | test("draw a gradient if the geometry is a point", () => {
19 | highlightPointStyle.getRenderer()([0, 0], { context });
20 | expect(context.createRadialGradient).toHaveBeenCalled();
21 | });
22 |
23 | test("does not crash if the geometry is not a point", () => {
24 | highlightPointStyle.getRenderer()([[0, 0], 0], { context });
25 | highlightPointStyle.getRenderer()([0, 0, 0], { context });
26 | expect(context.createRadialGradient).not.toHaveBeenCalled();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/src/utils/isoToIntlVehicleCode.test.js:
--------------------------------------------------------------------------------
1 | import isoToIntlVehicleCode from "./isoToIntlVehicleCode";
2 |
3 | describe("isoToIntlVehicleCode", () => {
4 | test("returns the international vehicle registration code from an ISO country code", () => {
5 | expect(isoToIntlVehicleCode("DE")).toBe("D");
6 | expect(isoToIntlVehicleCode("FR")).toBe("F");
7 | expect(isoToIntlVehicleCode("IT")).toBe("I");
8 | expect(isoToIntlVehicleCode("CH")).toBe("CH");
9 | expect(isoToIntlVehicleCode("ZW")).toBe("ZW");
10 | });
11 | test("returns the ISO country code if the vehicle code is not found", () => {
12 | expect(isoToIntlVehicleCode("balbnlba")).toBe("balbnlba");
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/src/utils/removeDuplicateFeatures.js:
--------------------------------------------------------------------------------
1 | export const getId = (feat) => feat?.getId() || feat?.get("id");
2 |
3 | export const removeDuplicateFeatures = (featureArray = []) => {
4 | return featureArray.reduce((final, feat) => {
5 | return final.find((f) => getId(f) === getId(feat))
6 | ? final
7 | : [...final, feat];
8 | }, []);
9 | };
10 |
11 | export default removeDuplicateFeatures;
12 |
--------------------------------------------------------------------------------
/src/utils/toBase64.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Encodes a file to base64 string
3 | * @param {*} file
4 | * @returns promise
5 | */
6 | const toBase64 = (file) =>
7 | new Promise((resolve, reject) => {
8 | const reader = new FileReader();
9 | reader.readAsDataURL(file);
10 | reader.onload = () => resolve(reader.result);
11 | reader.onerror = reject;
12 | });
13 |
14 | export default toBase64;
15 |
--------------------------------------------------------------------------------
/src/utils/useHasScreenSize.js:
--------------------------------------------------------------------------------
1 | import { useMemo } from "react";
2 | import { useSelector } from "react-redux";
3 |
4 | const useHasScreenSize = (screenSizes = ["xs"]) => {
5 | const screenWidth = useSelector((state) => state.app.screenWidth);
6 | const isMobile = useMemo(() => {
7 | return screenSizes.includes(screenWidth);
8 | }, [screenWidth, screenSizes]);
9 | return isMobile;
10 | };
11 |
12 | export default useHasScreenSize;
13 |
--------------------------------------------------------------------------------
/src/utils/useHighlightSomeFeatures.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { useSelector } from "react-redux";
3 |
4 | /**
5 | * This hook will only highlight specific set of features that are part
6 | * of the current feature infos. See iSB popup for exmaple of use.
7 | *
8 | * Works only with MapboxStyleLayer.
9 | */
10 | const useHighlightSomeFeatures = (features, layer) => {
11 | const featureInfo = useSelector((state) => state.app.featureInfo);
12 | // Highlight only one feature at a time.
13 | useEffect(() => {
14 | if (!layer || !features?.length) {
15 | return () => {};
16 | }
17 |
18 | featureInfo?.forEach(({ layer: l }) => {
19 | if (l !== layer) {
20 | l?.highlight?.();
21 | }
22 | });
23 | layer?.highlight(features);
24 | return () => {
25 | layer?.highlight();
26 | };
27 | }, [layer, features, featureInfo]);
28 | };
29 |
30 | export default useHighlightSomeFeatures;
31 |
--------------------------------------------------------------------------------
/src/utils/useOverlayWidth.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { useSelector } from "react-redux";
3 |
4 | const useOverlayWidth = () => {
5 | const overlayElement = useSelector((state) => state.app.overlayElement);
6 | const [width, setWidth] = useState(0);
7 | useEffect(() => {
8 | const resizeObserver = new ResizeObserver((entries) => {
9 | setWidth(entries[0].contentRect.width);
10 | });
11 | if (!overlayElement) {
12 | setWidth(0);
13 | return () => resizeObserver.disconnect();
14 | }
15 | resizeObserver.observe(overlayElement);
16 | return () => resizeObserver.disconnect();
17 | }, [overlayElement]);
18 | return width;
19 | };
20 |
21 | export default useOverlayWidth;
22 |
--------------------------------------------------------------------------------
/src/utils/usePrevious.js:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from "react";
2 |
3 | const usePrevious = (value) => {
4 | const ref = useRef();
5 | useEffect(() => {
6 | ref.current = value;
7 | }, [value]);
8 | return ref.current;
9 | };
10 |
11 | export default usePrevious;
12 |
--------------------------------------------------------------------------------
/src/utils/useUpdateFeatureInfoOnLayerToggle.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { useDispatch, useSelector } from "react-redux";
3 | import { unByKey } from "ol/Observable";
4 |
5 | import { setFeatureInfo } from "../model/app/actions";
6 |
7 | const useUpdateFeatureInfoOnLayerToggle = (layers) => {
8 | const featureInfo = useSelector((state) => state.app.featureInfo);
9 | const dispatch = useDispatch();
10 | useEffect(() => {
11 | const listeners = layers.map((l) => {
12 | return l?.on("change:visible", (evt) => {
13 | const layer = evt.target;
14 | if (!layer.visible) {
15 | dispatch(
16 | setFeatureInfo(featureInfo.filter((info) => info.layer !== layer)),
17 | );
18 | }
19 | });
20 | });
21 | return () => {
22 | unByKey(listeners);
23 | };
24 | }, [layers, featureInfo, dispatch]);
25 | };
26 |
27 | export default useUpdateFeatureInfoOnLayerToggle;
28 |
--------------------------------------------------------------------------------