@geops/rvf-mobility-web-component 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/.fixpackrc +21 -0
  2. package/.husky/commit-msg +1 -0
  3. package/.husky/post-checkout +1 -0
  4. package/.husky/post-merge +1 -0
  5. package/.husky/post-rebase +1 -0
  6. package/.husky/pre-commit +1 -0
  7. package/.lintstagedrc.js +12 -0
  8. package/.nvmrc +1 -0
  9. package/.prettierrc.js +1 -0
  10. package/CHANGELOG.md +183 -0
  11. package/Logo.svg +10 -0
  12. package/README.md +179 -0
  13. package/__mocks__/dataurl.js +11 -0
  14. package/__mocks__/mapbox-gl.js +19 -0
  15. package/commitlint.config.cjs +1 -0
  16. package/doc/.eslintrc.json +3 -0
  17. package/doc/.fixpackrc +21 -0
  18. package/doc/.prettierrc +1 -0
  19. package/doc/README.md +14 -0
  20. package/doc/declarations.d.ts +6 -0
  21. package/doc/next.config.mjs +4 -0
  22. package/doc/package.json +43 -0
  23. package/doc/postcss.config.mjs +8 -0
  24. package/doc/public/README.md +1 -0
  25. package/doc/src/app/components/GeopsAPIKeyLink.tsx +6 -0
  26. package/doc/src/app/components/GeopsAPIsLink.tsx +6 -0
  27. package/doc/src/app/components/GeopsMapsAPILink.tsx +8 -0
  28. package/doc/src/app/components/GeopsMobility.tsx +9 -0
  29. package/doc/src/app/components/GeopsMobilityDoc.tsx +231 -0
  30. package/doc/src/app/components/GeopsMobilitySearch.tsx +10 -0
  31. package/doc/src/app/components/GeopsMobilitySearchDoc.tsx +129 -0
  32. package/doc/src/app/components/GeopsRealtimeAPILink.tsx +10 -0
  33. package/doc/src/app/components/GeopsStopsAPILink.tsx +8 -0
  34. package/doc/src/app/components/Link.tsx +9 -0
  35. package/doc/src/app/components/WebComponentDoc.tsx +296 -0
  36. package/doc/src/app/favicon.ico +0 -0
  37. package/doc/src/app/geops-mobility/page.tsx +6 -0
  38. package/doc/src/app/geops-mobility-search/page.tsx +7 -0
  39. package/doc/src/app/globals.css +38 -0
  40. package/doc/src/app/hooks/useAttrFromUrlParams.ts +21 -0
  41. package/doc/src/app/hooks/useIsFullScreen.ts +14 -0
  42. package/doc/src/app/hooks/usePublicKey.ts +21 -0
  43. package/doc/src/app/layout.tsx +51 -0
  44. package/doc/src/app/page.tsx +86 -0
  45. package/doc/src/geops-ui.ts +3 -0
  46. package/doc/tailwind.config.ts +20 -0
  47. package/doc/tsconfig.json +40 -0
  48. package/eslint.config.mjs +40 -0
  49. package/favicon.ico +0 -0
  50. package/global.d.ts +4 -0
  51. package/iframe.html +34 -0
  52. package/index.html +276 -0
  53. package/index.js +2162 -0
  54. package/input.css +34 -0
  55. package/jest-setup.js +4 -0
  56. package/jest.config.js +17 -0
  57. package/package.json +80 -0
  58. package/scripts/build.mjs +16 -0
  59. package/scripts/dev.mjs +26 -0
  60. package/search.html +144 -0
  61. package/src/BaseLayer/BaseLayer.tsx +36 -0
  62. package/src/BaseLayer/index.tsx +1 -0
  63. package/src/Copyright/Copyright.tsx +54 -0
  64. package/src/Copyright/index.css +3 -0
  65. package/src/Copyright/index.tsx +1 -0
  66. package/src/DebugDeparture/DebugDeparture.tsx +116 -0
  67. package/src/DebugDeparture/index.tsx +1 -0
  68. package/src/DebugStop/DebugStop.tsx +47 -0
  69. package/src/DebugStop/index.tsx +1 -0
  70. package/src/Departure/Departure.tsx +55 -0
  71. package/src/Departure/index.tsx +1 -0
  72. package/src/GeolocationButton/GeolocationButton.tsx +81 -0
  73. package/src/GeolocationButton/index.tsx +1 -0
  74. package/src/Map/Map.tsx +89 -0
  75. package/src/Map/index.tsx +1 -0
  76. package/src/MobilityMap/MobilityMap.tsx +259 -0
  77. package/src/MobilityMap/index.css +13 -0
  78. package/src/MobilityMap/index.tsx +1 -0
  79. package/src/NotificationLayer/NotificationLayer.tsx +156 -0
  80. package/src/NotificationLayer/index.tsx +1 -0
  81. package/src/NotificationLayer/notificationUtils.ts +191 -0
  82. package/src/Overlay/Overlay.tsx +57 -0
  83. package/src/Overlay/index.tsx +1 -0
  84. package/src/RealtimeLayer/RealtimeLayer.tsx +230 -0
  85. package/src/RealtimeLayer/index.tsx +1 -0
  86. package/src/RouteDestination/RouteDestination.test.tsx +13 -0
  87. package/src/RouteDestination/RouteDestination.tsx +15 -0
  88. package/src/RouteDestination/index.tsx +1 -0
  89. package/src/RouteIcon/RouteIcon.tsx +66 -0
  90. package/src/RouteIcon/index.tsx +1 -0
  91. package/src/RouteIdentifier/RouteIdentifer.tsx +35 -0
  92. package/src/RouteIdentifier/index.tsx +1 -0
  93. package/src/RouteInfos/RouteInfos.tsx +22 -0
  94. package/src/RouteInfos/index.tsx +1 -0
  95. package/src/RouteSchedule/RouteSchedule.tsx +69 -0
  96. package/src/RouteSchedule/firstStation.png +0 -0
  97. package/src/RouteSchedule/index.tsx +1 -0
  98. package/src/RouteSchedule/lastStation.png +0 -0
  99. package/src/RouteSchedule/line.png +0 -0
  100. package/src/RouteSchedule/station.png +0 -0
  101. package/src/RouteScheduleFooter/RouteScheduleFooter.tsx +44 -0
  102. package/src/RouteScheduleFooter/index.tsx +1 -0
  103. package/src/RouteScheduleHeader/RouteScheduleHeader.tsx +58 -0
  104. package/src/RouteScheduleHeader/index.tsx +1 -0
  105. package/src/RouteStop/RouteStop.tsx +121 -0
  106. package/src/RouteStop/index.tsx +1 -0
  107. package/src/RouteStopDelay/RouteStopDelay.tsx +36 -0
  108. package/src/RouteStopDelay/index.tsx +1 -0
  109. package/src/RouteStopName/RouteStopName.tsx +24 -0
  110. package/src/RouteStopName/index.tsx +1 -0
  111. package/src/RouteStopPlatform/RouteStopPlatform.tsx +29 -0
  112. package/src/RouteStopPlatform/index.tsx +1 -0
  113. package/src/RouteStopProgress/RouteStopProgress.tsx +101 -0
  114. package/src/RouteStopProgress/index.tsx +1 -0
  115. package/src/RouteStopServices/RouteStopServices.tsx +26 -0
  116. package/src/RouteStopServices/index.tsx +1 -0
  117. package/src/RouteStopStation/RouteStopStation.tsx +32 -0
  118. package/src/RouteStopStation/index.tsx +1 -0
  119. package/src/RouteStopTime/RouteStopTime.tsx +34 -0
  120. package/src/RouteStopTime/index.tsx +1 -0
  121. package/src/RvfMobilityMap/RvfMobilityMap.tsx +245 -0
  122. package/src/RvfMobilityMap/index.css +13 -0
  123. package/src/RvfMobilityMap/index.tsx +1 -0
  124. package/src/ScaleLine/ScaleLine.tsx +51 -0
  125. package/src/ScaleLine/index.css +6 -0
  126. package/src/ScaleLine/index.tsx +1 -0
  127. package/src/ScrollableHandler/ScrollableHandler.tsx +65 -0
  128. package/src/ScrollableHandler/index.tsx +1 -0
  129. package/src/Search/Search.tsx +18 -0
  130. package/src/Search/index.tsx +1 -0
  131. package/src/SingleClickListener/SingleClickListener.tsx +103 -0
  132. package/src/SingleClickListener/index.tsx +1 -0
  133. package/src/Station/Station.tsx +68 -0
  134. package/src/Station/index.tsx +1 -0
  135. package/src/StationHeader/StationHeader.tsx +32 -0
  136. package/src/StationHeader/index.tsx +1 -0
  137. package/src/StationName/StationName.tsx +21 -0
  138. package/src/StationName/index.tsx +1 -0
  139. package/src/StationServices/StationServices.tsx +80 -0
  140. package/src/StationServices/index.tsx +1 -0
  141. package/src/StationsLayer/StationsLayer.tsx +41 -0
  142. package/src/StationsLayer/index.tsx +1 -0
  143. package/src/StopsSearch/StopsSearch.tsx +254 -0
  144. package/src/StopsSearch/index.tsx +1 -0
  145. package/src/icons/Airport/Airport.tsx +17 -0
  146. package/src/icons/Airport/airport-14-svgrepo-com.svg +41 -0
  147. package/src/icons/Airport/index.tsx +1 -0
  148. package/src/icons/BarAndRestaurants/BarAndRestaurants.tsx +17 -0
  149. package/src/icons/BarAndRestaurants/food-restaurant-svgrepo-com.svg +12 -0
  150. package/src/icons/BarAndRestaurants/index.tsx +1 -0
  151. package/src/icons/Bathroom/Bathroom.tsx +59 -0
  152. package/src/icons/Bathroom/bathroom-restroom-svgrepo-com.svg +38 -0
  153. package/src/icons/Bathroom/index.tsx +1 -0
  154. package/src/icons/BikeStorage/BikeStorage.tsx +17 -0
  155. package/src/icons/BikeStorage/index.tsx +1 -0
  156. package/src/icons/BikeStorage/parking-bicycle-14-svgrepo-com.svg +41 -0
  157. package/src/icons/Elevator/Elevator.tsx +16 -0
  158. package/src/icons/Elevator/elevator-svgrepo-com.svg +2 -0
  159. package/src/icons/Elevator/index.tsx +1 -0
  160. package/src/icons/Police/Police.tsx +20 -0
  161. package/src/icons/Police/index.tsx +1 -0
  162. package/src/icons/Police/polizia.png +0 -0
  163. package/src/icons/README.md +52 -0
  164. package/src/icons/WaitingAreas/WaitingAreas.tsx +16 -0
  165. package/src/icons/WaitingAreas/highway-rest-area-svgrepo-com.svg +5 -0
  166. package/src/icons/WaitingAreas/index.tsx +1 -0
  167. package/src/icons/WaitingAreas/wheelchair-svgrepo-com.svg +2 -0
  168. package/src/icons/WheelChair/WheelChair.tsx +16 -0
  169. package/src/icons/WheelChair/disabili.png +0 -0
  170. package/src/icons/WheelChair/index.tsx +1 -0
  171. package/src/icons/WheelChair/wheelchair-svgrepo-com.svg +2 -0
  172. package/src/index.tsx +50 -0
  173. package/src/utils/MobilityEvent.ts +21 -0
  174. package/src/utils/addSourceAndLayers.ts +62 -0
  175. package/src/utils/centerOnStation.ts +17 -0
  176. package/src/utils/centerOnVehicle.ts +50 -0
  177. package/src/utils/getBgColor.ts +3 -0
  178. package/src/utils/getDelayColor.test.ts +20 -0
  179. package/src/utils/getDelayColor.ts +23 -0
  180. package/src/utils/getDelayColorForVehicle.test.ts +28 -0
  181. package/src/utils/getDelayColorForVehicle.ts +25 -0
  182. package/src/utils/getDelayFontForVehicle.test.ts +7 -0
  183. package/src/utils/getDelayFontForVehicle.tsx +8 -0
  184. package/src/utils/getDelayString.test.ts +22 -0
  185. package/src/utils/getDelayString.ts +28 -0
  186. package/src/utils/getDelayTextForVehicle.test.ts +28 -0
  187. package/src/utils/getDelayTextForVehicle.ts +21 -0
  188. package/src/utils/getFullTrajectoryAndFit.ts +40 -0
  189. package/src/utils/getHoursAndMinutes.test.ts +14 -0
  190. package/src/utils/getHoursAndMinutes.ts +22 -0
  191. package/src/utils/getMainColorForVehicle.test.ts +27 -0
  192. package/src/utils/getMainColorForVehicle.ts +46 -0
  193. package/src/utils/getStopStatus.test.ts +104 -0
  194. package/src/utils/getStopStatus.ts +171 -0
  195. package/src/utils/getTextFontForVehicle.test.ts +7 -0
  196. package/src/utils/getTextFontForVehicle.tsx +9 -0
  197. package/src/utils/getTextForVehicle.test.ts +17 -0
  198. package/src/utils/getTextForVehicle.ts +19 -0
  199. package/src/utils/hooks/useDebug.tsx +11 -0
  200. package/src/utils/hooks/useDeparture.tsx +23 -0
  201. package/src/utils/hooks/useI18n.tsx +20 -0
  202. package/src/utils/hooks/useMapContext.tsx +74 -0
  203. package/src/utils/hooks/useParams.ts +5 -0
  204. package/src/utils/hooks/useRouteStop.tsx +33 -0
  205. package/src/utils/hooks/useStation.tsx +21 -0
  206. package/src/utils/hooks/useUpdatePermalink.tsx +33 -0
  207. package/src/utils/hooks/useZoom.tsx +32 -0
  208. package/src/utils/i18n.ts +16 -0
  209. package/src/utils/translations.ts +31 -0
  210. package/tailwind.config.mjs +56 -0
  211. package/testNotification.json +50653 -0
  212. package/tsconfig.json +12 -0
package/input.css ADDED
@@ -0,0 +1,34 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ ::-webkit-scrollbar {
6
+ height: 3px;
7
+ width: 3px;
8
+ }
9
+
10
+ ::-webkit-scrollbar-thumb {
11
+ background: gray;
12
+ }
13
+
14
+ html {
15
+ @apply text-base;
16
+ }
17
+
18
+ @layer base {
19
+ h1 {
20
+ @apply text-3xl font-bold;
21
+ }
22
+
23
+ h2 {
24
+ @apply text-2xl;
25
+ }
26
+
27
+ h3 {
28
+ @apply text-xl;
29
+ }
30
+
31
+ h4 {
32
+ @apply text-lg;
33
+ }
34
+ }
package/jest-setup.js ADDED
@@ -0,0 +1,4 @@
1
+ /* eslint-disable import/no-extraneous-dependencies */
2
+ import "jest-canvas-mock";
3
+
4
+ global.URL.createObjectURL = jest.fn(() => "fooblob");
package/jest.config.js ADDED
@@ -0,0 +1,17 @@
1
+ /** @type {import('ts-jest').JestConfigWithTsJest} */
2
+ const config = {
3
+ moduleNameMapper: {
4
+ "@geoblocks/ol-maplibre-layer":
5
+ "<rootDir>/node_modules/@geoblocks/ol-maplibre-layer/lib/index.js",
6
+ "\\.(css|less)$": "identity-obj-proxy",
7
+ },
8
+ preset: "jest-preset-preact",
9
+ setupFiles: ["./jest-setup.js"],
10
+ testEnvironment: "jsdom",
11
+ transform: {
12
+ "\\.(jpg|ico|jpeg|png|gif|webp)$": "<rootDir>/__mocks__/dataurl.js",
13
+ "\\.[t]sx?$": "ts-jest",
14
+ },
15
+ transformIgnorePatterns: [],
16
+ };
17
+ export default config;
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@geops/rvf-mobility-web-component",
3
+ "license": "UNLICENSED",
4
+ "description": "Web components for rvf in the domains of mobility and logistics.",
5
+ "version": "0.1.8",
6
+ "homepage": "https://rvf-mobility-web-component-geops.vercel.app/",
7
+ "type": "module",
8
+ "main": "index.js",
9
+ "dependencies": {
10
+ "maplibre-gl": "^4.7.1",
11
+ "mobility-toolbox-js": "3.0.0-beta.38",
12
+ "ol": "^10.3.0",
13
+ "preact": "^10.25.1",
14
+ "preact-custom-element": "^4.3.0",
15
+ "react": "npm:@preact/compat@^18.3.1",
16
+ "react-dom": "npm:@preact/compat@^18.3.1",
17
+ "react-icons": "^5.3.0",
18
+ "rosetta": "^1.1.0"
19
+ },
20
+ "devDependencies": {
21
+ "@commitlint/cli": "^19.6.0",
22
+ "@commitlint/config-conventional": "^19.6.0",
23
+ "@eslint/js": "^9.16.0",
24
+ "@tailwindcss/container-queries": "^0.1.1",
25
+ "@testing-library/preact": "^3.2.4",
26
+ "@types/geojson": "^7946.0.14",
27
+ "@types/jest": "^29.5.14",
28
+ "@types/preact-custom-element": "^4.0.4",
29
+ "concurrently": "^9.1.0",
30
+ "esbuild": "^0.24.0",
31
+ "esbuild-sass-plugin": "^3.3.1",
32
+ "eslint": "^9.16.0",
33
+ "eslint-config-prettier": "9.1.0",
34
+ "eslint-plugin-jsx-a11y": "^6.10.2",
35
+ "eslint-plugin-perfectionist": "^4.1.2",
36
+ "eslint-plugin-prettier": "^5.2.1",
37
+ "eslint-plugin-react": "^7.37.2",
38
+ "eslint-plugin-react-hooks": "^5.1.0-rc.0",
39
+ "eslint-plugin-tailwindcss": "^3.17.5",
40
+ "fixpack": "^4.0.0",
41
+ "generact": "^0.4.0",
42
+ "husky": "^9.1.7",
43
+ "jest": "^29.7.0",
44
+ "jest-canvas-mock": "^2.5.2",
45
+ "jest-environment-jsdom": "^29.7.0",
46
+ "jest-preset-preact": "^4.1.1",
47
+ "next": "15.0.3",
48
+ "preact-render-to-string": "^6.5.11",
49
+ "prettier": "^3.4.1",
50
+ "standard-version": "^9.5.0",
51
+ "tailwindcss": "^3.4.15",
52
+ "ts-jest": "^29.2.5",
53
+ "typescript": "^5.7.2",
54
+ "typescript-eslint": "^8.17.0"
55
+ },
56
+ "scripts": {
57
+ "build": "yarn build:css && yarn build:js",
58
+ "build:css": "yarn tailwind:component && yarn tailwind:website",
59
+ "build:js": "node scripts/build.mjs",
60
+ "cp": "generact --root src",
61
+ "dev": "node scripts/dev.mjs",
62
+ "doc": "yarn build && cp index.js doc/public/index.js && cd doc && yarn build",
63
+ "doc:dev": "yarn build && cp index.js doc/public/index.js && cp index.js.map doc/public/index.js.map && cd doc && yarn dev",
64
+ "format": "prettier --write 'src/**/*.(tsx|ts)' && eslint src/**/*.tsx src/**/*.ts --fix ",
65
+ "lint": "eslint src/**/*.tsx",
66
+ "prepare": "husky",
67
+ "publish:beta": "HUSKY=0 yarn release -- --prerelease beta --skip.changelog && yarn run build && HUSKY=0 yarn publish --access public --tag beta && git push origin HEAD && git push --tags ",
68
+ "publish:beta:dryrun": "yarn release -- --prerelease beta --dry-run --skip.changelog",
69
+ "publish:public": "yarn release && yarn run build && HUSKY=0 yarn publish --access public && git push origin HEAD && git push --tags ",
70
+ "publish:public:dryrun": "yarn release --dry-run",
71
+ "release": "standard-version",
72
+ "start": "concurrently \"yarn tailwind:component --watch\" \"yarn tailwind:website --watch\" \"yarn dev\"",
73
+ "tailwind:component": "tailwindcss --output=src/style.css --content=src/**/*.tsx",
74
+ "tailwind:website": "tailwindcss --input=./input.css --output=output.css --content=*.html --minify",
75
+ "test": "TZ=UTC jest",
76
+ "up": "yarn upgrade-interactive --latest",
77
+ "upstream": "git fetch upstream && git merge upstream/main"
78
+ },
79
+ "packageManager": "yarn@1.22.22+sha256.c17d3797fb9a9115bf375e31bfd30058cac6bc9c3b8807a3d8cb2094794b51ca"
80
+ }
@@ -0,0 +1,16 @@
1
+ /* eslint-disable import/no-extraneous-dependencies */
2
+ import * as esbuild from "esbuild";
3
+ import { sassPlugin } from "esbuild-sass-plugin";
4
+
5
+ await esbuild.build({
6
+ entryPoints: ["./src/index.js"],
7
+ bundle: true,
8
+ minify: true,
9
+ external: ["mapbox-gl"],
10
+ loader: {
11
+ ".png": "dataurl",
12
+ },
13
+ outfile: "index.js",
14
+ plugins: [sassPlugin({ type: "css-text" })],
15
+ sourcemap: false,
16
+ });
@@ -0,0 +1,26 @@
1
+ /* eslint-disable import/no-extraneous-dependencies */
2
+ import * as esbuild from "esbuild";
3
+ import { sassPlugin } from "esbuild-sass-plugin";
4
+
5
+ const ctx = await esbuild.context({
6
+ entryPoints: ["./src/index.js"],
7
+ bundle: true,
8
+ external: ["mapbox-gl"],
9
+ loader: {
10
+ ".png": "dataurl",
11
+ },
12
+ outfile: "index.js",
13
+ plugins: [sassPlugin({ type: "css-text" })],
14
+ sourcemap: true,
15
+ });
16
+
17
+ const { host, port } = await ctx.serve({
18
+ servedir: ".",
19
+ });
20
+
21
+ await ctx.watch();
22
+ console.log(
23
+ `watching... and running at ${
24
+ host === "0.0.0.0" ? "http://localhost" : host
25
+ }:${port}`,
26
+ );
package/search.html ADDED
@@ -0,0 +1,144 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Mobility Web Component</title>
6
+ <link rel="icon" type="image/x-icon" href="favicon.ico" />
7
+ <meta
8
+ name="viewport"
9
+ content="initial-scale=1,maximum-scale=1,user-scalable=no"
10
+ />
11
+ <script type="text/javascript">
12
+ if (/localhost/.test(window.location.hostname)) {
13
+ new EventSource("/esbuild").addEventListener("change", () => {
14
+ location.reload();
15
+ });
16
+ }
17
+ </script>
18
+ <script type="module" src="./index.js"></script>
19
+ <link rel="stylesheet" type="text/css" href="./output.css" />
20
+ <style>
21
+ ::-webkit-scrollbar {
22
+ width: 10px;
23
+ }
24
+ a {
25
+ text-decoration: underline;
26
+ }
27
+ </style>
28
+ </head>
29
+ <body class="p-8">
30
+ <div
31
+ id="doc"
32
+ style="display: none"
33
+ class="mx-auto h-96 max-w-3xl space-y-4"
34
+ >
35
+ <h1 class="text-3xl font-bold">Mobility Search Web Component</h1>
36
+ <p>This is a demo of the geOps Mobility Search Web Component.</p>
37
+ <p>This web component launches a search on the <b>geOps Stops API</b></p>
38
+ <p>Every parameters of the <b>geOps Stops API</b>:</p>
39
+ <ul class="pl-8">
40
+ <li class="list-disc">can be passed as a string attribute of the web component.</li>
41
+ <li class="list-disc">
42
+ can be passed as an URL parameter of this page, they will be
43
+ automatically apply to the web component.
44
+ </li>
45
+ </ul>
46
+ <p>
47
+ The list of parameters of the <b>geOps Stops API</b> can be found
48
+ <a href="https://developer.geops.io/apis/stops#parameters" target="_blank">here</a>.
49
+ </p>
50
+
51
+ <h2 class="text-xl font-bold">Usage example</h2>
52
+ <pre class="bg-slate-800 text-slate-200 p-4 rounded">
53
+ &lt;script
54
+ type=&quot;module&quot;
55
+ src=&quot;https://www.unpkg.com/@geops/mobility-web-component&quot;&gt;
56
+ &lt;/script&gt;
57
+ &lt;geops-mobility-search
58
+ apikey=&quot;YOUR_GEOPS_API_KEY&quot;
59
+ limit=&quot;5&quot;
60
+ mots=&quot;rail,bus&quot;
61
+ style=&quot;display: block;width: 800px;height: 800px;&quot;&gt;
62
+ &lt;/geops-mobility&gt;</pre
63
+ >
64
+
65
+ <!-- Default -->
66
+ <geops-mobility-search
67
+ class="max-w-3xl block border"
68
+ limit="5"
69
+ mots="rail,bus"
70
+ ></geops-mobility-search>
71
+
72
+ <pre id="textarea" class="w-full h-96 p-2"></pre>
73
+
74
+ <br />
75
+ <br />
76
+ <h1 class="text-xl font-bold">More mobility web components</h1>
77
+ <p>
78
+ <a href="index.html" target="_blank"
79
+ >&gt;&gt; Usage example Map Component</a
80
+ >
81
+ </p>
82
+ </div>
83
+ <script type="text/javascript">
84
+ let params = new URLSearchParams(window.location.search);
85
+ const searchElement = document.querySelector("geops-mobility-search");
86
+ const eventLog = document.querySelector("#textarea");
87
+
88
+
89
+ // Listen window event
90
+ window.addEventListener("message", (event) => {
91
+ const { type } = event.data || {};
92
+ console.log("message event: " + type, event.data);
93
+ });
94
+ </script>
95
+
96
+ <script type="text/javascript">
97
+ params = new URLSearchParams(window.location.search);
98
+
99
+ // There should be only one webcompoennt on the html page at this point
100
+ const doc = document.querySelectorAll("#doc");
101
+ const wc = document.querySelector("geops-mobility-search");
102
+ if (params.get("fullscreen") === "true") {
103
+ wc.parentElement.removeChild(wc);
104
+ wc.className = "absolute w-full h-full inset-0";
105
+ document.body.appendChild(wc);
106
+ document.body.style = "padding:0;";
107
+ } else {
108
+ doc.forEach((d) => (d.style.display = "block"));
109
+ }
110
+ params.delete("fullscreen");
111
+
112
+ // Apply all url parameters as attribute of the web component
113
+ params.forEach((value, key) => {
114
+ wc.setAttribute(key, value);
115
+ });
116
+
117
+ if (!wc.getAttribute("apikey")) {
118
+ fetch("https://backend.developer.geops.io/publickey")
119
+ .then((response) => response.json())
120
+ .then((data) => {
121
+ if (data && data.success) {
122
+ wc.setAttribute("apikey", data.key);
123
+ }
124
+ });
125
+ }
126
+
127
+
128
+ // Listen to element event
129
+ searchElement.addEventListener("mwc:stopssearchselect", (event) => {
130
+ const data = event.data;
131
+ if (!data) {
132
+ eventLog.innerText = "";
133
+ } else {
134
+ eventLog.innerText =
135
+ "Event " +
136
+ event.type +
137
+ " received :\n " +
138
+ JSON.stringify(data, undefined, " ");
139
+ window.top.postMessage(data, "*");
140
+ }
141
+ });
142
+ </script>
143
+ </body>
144
+ </html>
@@ -0,0 +1,36 @@
1
+ import { MaplibreLayer } from "mobility-toolbox-js/ol";
2
+ import { MaplibreLayerOptions } from "mobility-toolbox-js/ol/layers/MaplibreLayer";
3
+ import { Layer } from "ol/layer";
4
+ import { memo } from "preact/compat";
5
+ import { useEffect } from "preact/hooks";
6
+
7
+ import useMapContext from "../utils/hooks/useMapContext";
8
+
9
+ function BaseLayer(props: MaplibreLayerOptions) {
10
+ const { apikey, baselayer, map, mapsurl, setBaseLayer } = useMapContext();
11
+ useEffect(() => {
12
+ if (!map || !baselayer || !apikey) {
13
+ return;
14
+ }
15
+ const layer = new MaplibreLayer({
16
+ apiKey: apikey,
17
+ style: baselayer,
18
+ url: mapsurl,
19
+ ...(props || {}),
20
+ });
21
+ const baseLayer = layer as unknown as Layer;
22
+
23
+ // TODO: find why the setZIndex is not found
24
+ baseLayer.setZIndex(0);
25
+ map.addLayer(baseLayer);
26
+ setBaseLayer(layer);
27
+
28
+ return () => {
29
+ map?.removeLayer(baseLayer);
30
+ };
31
+ }, [map, baselayer, apikey, setBaseLayer, props, mapsurl]);
32
+
33
+ return null;
34
+ }
35
+
36
+ export default memo(BaseLayer);
@@ -0,0 +1 @@
1
+ export { default } from "./BaseLayer";
@@ -0,0 +1,54 @@
1
+ import { CopyrightControl } from "mobility-toolbox-js/ol";
2
+ import { CopyrightControlOptions } from "mobility-toolbox-js/ol/controls/CopyrightControl";
3
+ import { JSX, PreactDOMAttributes } from "preact";
4
+ import { useEffect, useMemo, useState } from "preact/hooks";
5
+
6
+ import useMapContext from "../utils/hooks/useMapContext";
7
+ // @ts-expect-error bad type definition
8
+ import style from "./index.css";
9
+
10
+ export type CopyrightProps = {
11
+ options?: CopyrightControlOptions;
12
+ } & JSX.HTMLAttributes<HTMLDivElement> &
13
+ PreactDOMAttributes;
14
+
15
+ function Copyright({ options, ...props }: CopyrightProps) {
16
+ const { map } = useMapContext();
17
+ const [target, setTarget] = useState<HTMLElement>();
18
+ const control = useMemo(() => {
19
+ if (!target) {
20
+ return null;
21
+ }
22
+ const div = document.createElement("div");
23
+ div.className = "flex flex-wrap-reverse justify-end";
24
+
25
+ return new CopyrightControl({
26
+ element: div,
27
+ target,
28
+ ...options,
29
+ });
30
+ }, [options, target]);
31
+
32
+ useEffect(() => {
33
+ if (!map || !control) {
34
+ return;
35
+ }
36
+ map.addControl(control);
37
+ return () => {
38
+ map?.removeControl(control);
39
+ };
40
+ }, [map, control]);
41
+
42
+ return (
43
+ <div
44
+ ref={(node) => {
45
+ setTarget(node);
46
+ }}
47
+ {...props}
48
+ >
49
+ <style>{style}</style>
50
+ </div>
51
+ );
52
+ }
53
+
54
+ export default Copyright;
@@ -0,0 +1,3 @@
1
+ a {
2
+ white-space: pre;
3
+ }
@@ -0,0 +1 @@
1
+ export { default } from "./Copyright";
@@ -0,0 +1,116 @@
1
+ import { JSX, PreactDOMAttributes } from "preact";
2
+
3
+ import useDebug from "../utils/hooks/useDebug";
4
+ import useDeparture from "../utils/hooks/useDeparture";
5
+
6
+ export type DebugDepartureProps = JSX.HTMLAttributes<HTMLDivElement> &
7
+ PreactDOMAttributes;
8
+
9
+ /**
10
+ * Polyfill for String.prototype.padStart()
11
+ */
12
+ const pad = (n: number) => {
13
+ return `0${n}`.slice(-2);
14
+ };
15
+
16
+ const formatDebugTime = (time, excludeSeconds = false) => {
17
+ const d = new Date(time);
18
+
19
+ return !time || Number.isNaN(d)
20
+ ? "unknown"
21
+ : [
22
+ pad(d.getHours()),
23
+ pad(d.getMinutes()),
24
+ excludeSeconds ? null : pad(d.getSeconds()),
25
+ ]
26
+ .filter((t) => {
27
+ return t;
28
+ })
29
+ .join(":");
30
+ };
31
+
32
+ function DebugDeparture(props: DebugDepartureProps) {
33
+ const debug = useDebug();
34
+ const { departure } = useDeparture();
35
+
36
+ if (!debug) {
37
+ return null;
38
+ }
39
+ const {
40
+ // @ts-expect-error bad type definition
41
+ arrivalTime,
42
+ at_station_ds100: atStationDs100,
43
+ // @ts-expect-error bad type definition
44
+ departureTime,
45
+ fzo_estimated_time: fzoEstimatedTime,
46
+ has_fzo: hasFzo,
47
+ // @ts-expect-error bad type definition
48
+ last_boarding_time: lastBoardingTime,
49
+ min_arrival_time: minArrivalTime,
50
+ ris_aimed_time: risAimedTime,
51
+ ris_estimated_time: risEstimatedTime,
52
+ state,
53
+ // @ts-expect-error bad type definition
54
+ station,
55
+ // @ts-expect-error bad type definition
56
+ stations_in_between: stationsInBetween,
57
+ time,
58
+ train_number: trainNumber,
59
+ } = departure;
60
+
61
+ const risTime = new Date(risAimedTime);
62
+ const urlDate = Number.isNaN(risTime)
63
+ ? ""
64
+ : [
65
+ (risTime as Date).getFullYear(),
66
+ pad((risTime as Date).getMonth() + 1),
67
+ pad((risTime as Date).getDate()),
68
+ ].join("-");
69
+
70
+ const risLink = [
71
+ "https://ris-info.bahn.de/rishttp/risinfo.xml?",
72
+ `action=zuglauf&evanr=${station?.get("uic")}&`,
73
+ `zugnummer=${trainNumber}&`,
74
+ `ankunft=${urlDate}T${formatDebugTime(risTime, true)}`,
75
+ ].join("");
76
+
77
+ return (
78
+ <div className="border-b p-4 text-left text-xs" {...props}>
79
+ Zugnummer:
80
+ <a href={risLink} rel="noopener noreferrer" target="_blank">
81
+ {trainNumber}
82
+ </a>
83
+ <div>
84
+ {` State: `}
85
+ <b>{state}</b>
86
+ <br />
87
+ {`Has fzo: ${hasFzo};`}
88
+ <br />
89
+ {/* @ts-expect-error bad type definition */}
90
+ {`Has realtime: ${departure.has_realtime_journey};`}
91
+ <br />
92
+ {`Time: ${formatDebugTime(time)};`}
93
+ <br />
94
+ {`Arrival time: ${formatDebugTime(arrivalTime)};`}
95
+ <br />
96
+ {`Departure time: ${formatDebugTime(departureTime)};`}
97
+ <br />
98
+ {`FzO-Estimated: ${formatDebugTime(fzoEstimatedTime)};`}
99
+ <br />
100
+ {`RIS-Aimed: ${formatDebugTime(risAimedTime)};`}
101
+ <br />
102
+ {`RIS-Estimated: ${formatDebugTime(risEstimatedTime)};`}
103
+ <br />
104
+ {`Ref-Location: ${atStationDs100};`}
105
+ <br />
106
+ {`Normalized Distance: ${formatDebugTime(minArrivalTime)};`}
107
+ <br />
108
+ {`Last Boarding: ${formatDebugTime(lastBoardingTime)};`}
109
+ <br />
110
+ {`Stationen until arrival: ${stationsInBetween};`}
111
+ </div>
112
+ </div>
113
+ );
114
+ }
115
+
116
+ export default DebugDeparture;
@@ -0,0 +1 @@
1
+ export { default } from "./DebugDeparture";
@@ -0,0 +1,47 @@
1
+ import { JSX, PreactDOMAttributes } from "preact";
2
+
3
+ import useDebug from "../utils/hooks/useDebug";
4
+ import useRouteStop from "../utils/hooks/useRouteStop";
5
+
6
+ export type DebugStopProps = JSX.HTMLAttributes<HTMLDivElement> &
7
+ PreactDOMAttributes;
8
+
9
+ function DebugStop(props: DebugStopProps) {
10
+ const { status, stop } = useRouteStop();
11
+ const debug = useDebug();
12
+
13
+ if (!debug) {
14
+ return null;
15
+ }
16
+
17
+ return (
18
+ <div className="p-4 text-left text-xs" {...props}>
19
+ <div>
20
+ State: <b>{stop.state}</b> (isPassed: {`${status.isPassed}`})
21
+ (cancelled: {`${stop.cancelled}`})
22
+ </div>
23
+ <div>
24
+ Arrival time: {stop.arrivalTime} (delay: <b>{`${stop.arrivalDelay}`}</b>
25
+ ) (aimed: {stop.aimedArrivalTime})
26
+ </div>
27
+ <div>
28
+ Departure time: {stop.arrivalTime} (delay:{" "}
29
+ <b>{`${stop.departureDelay}`}</b>) (aimed: {stop.aimedArrivalTime})
30
+ </div>
31
+ <div>
32
+ {Object.entries(status).map(([key, value]) => {
33
+ if (value === false) {
34
+ return null;
35
+ }
36
+ return (
37
+ <div key={key}>
38
+ {key}: {`${value}`}
39
+ </div>
40
+ );
41
+ })}
42
+ </div>
43
+ </div>
44
+ );
45
+ }
46
+
47
+ export default DebugStop;
@@ -0,0 +1 @@
1
+ export { default } from "./DebugStop";
@@ -0,0 +1,55 @@
1
+ import type { RealtimeDeparture } from "mobility-toolbox-js/types";
2
+
3
+ import { memo, useMemo } from "preact/compat";
4
+
5
+ import DebugDeparture from "../DebugDeparture";
6
+ import RouteIcon from "../RouteIcon";
7
+ import getHoursAndMinutes from "../utils/getHoursAndMinutes";
8
+ import { DepartureContext } from "../utils/hooks/useDeparture";
9
+ import useMapContext from "../utils/hooks/useMapContext";
10
+
11
+ export interface DepartureProps {
12
+ departure: RealtimeDeparture;
13
+ index: number;
14
+ }
15
+
16
+ function Departure({ departure, index, ...props }: DepartureProps) {
17
+ const { setStationId, setTrainId } = useMapContext();
18
+
19
+ const departureState = useMemo(() => {
20
+ return { departure, index };
21
+ }, [departure, index]);
22
+
23
+ return (
24
+ <DepartureContext.Provider value={departureState}>
25
+ <button
26
+ className="w-full border-b"
27
+ onClick={() => {
28
+ setTrainId(departure.train_id);
29
+ setStationId();
30
+ }}
31
+ type="button"
32
+ {...props}
33
+ >
34
+ <div
35
+ className="gap-4 py-4"
36
+ style={{
37
+ alignItems: "center",
38
+ display: "flex",
39
+ overflow: "hidden",
40
+ }}
41
+ >
42
+ <div className="pl-4">
43
+ <RouteIcon departure={departure} />
44
+ </div>
45
+ <div className="grow text-left">
46
+ {[...new Set(departure.to)].join("/")}
47
+ </div>
48
+ <div className="pr-4">{getHoursAndMinutes(departure.time)}</div>
49
+ </div>
50
+ </button>
51
+ <DebugDeparture />
52
+ </DepartureContext.Provider>
53
+ );
54
+ }
55
+ export default memo(Departure);
@@ -0,0 +1 @@
1
+ export { default } from "./Departure";