@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.
- package/.fixpackrc +21 -0
- package/.husky/commit-msg +1 -0
- package/.husky/post-checkout +1 -0
- package/.husky/post-merge +1 -0
- package/.husky/post-rebase +1 -0
- package/.husky/pre-commit +1 -0
- package/.lintstagedrc.js +12 -0
- package/.nvmrc +1 -0
- package/.prettierrc.js +1 -0
- package/CHANGELOG.md +183 -0
- package/Logo.svg +10 -0
- package/README.md +179 -0
- package/__mocks__/dataurl.js +11 -0
- package/__mocks__/mapbox-gl.js +19 -0
- package/commitlint.config.cjs +1 -0
- package/doc/.eslintrc.json +3 -0
- package/doc/.fixpackrc +21 -0
- package/doc/.prettierrc +1 -0
- package/doc/README.md +14 -0
- package/doc/declarations.d.ts +6 -0
- package/doc/next.config.mjs +4 -0
- package/doc/package.json +43 -0
- package/doc/postcss.config.mjs +8 -0
- package/doc/public/README.md +1 -0
- package/doc/src/app/components/GeopsAPIKeyLink.tsx +6 -0
- package/doc/src/app/components/GeopsAPIsLink.tsx +6 -0
- package/doc/src/app/components/GeopsMapsAPILink.tsx +8 -0
- package/doc/src/app/components/GeopsMobility.tsx +9 -0
- package/doc/src/app/components/GeopsMobilityDoc.tsx +231 -0
- package/doc/src/app/components/GeopsMobilitySearch.tsx +10 -0
- package/doc/src/app/components/GeopsMobilitySearchDoc.tsx +129 -0
- package/doc/src/app/components/GeopsRealtimeAPILink.tsx +10 -0
- package/doc/src/app/components/GeopsStopsAPILink.tsx +8 -0
- package/doc/src/app/components/Link.tsx +9 -0
- package/doc/src/app/components/WebComponentDoc.tsx +296 -0
- package/doc/src/app/favicon.ico +0 -0
- package/doc/src/app/geops-mobility/page.tsx +6 -0
- package/doc/src/app/geops-mobility-search/page.tsx +7 -0
- package/doc/src/app/globals.css +38 -0
- package/doc/src/app/hooks/useAttrFromUrlParams.ts +21 -0
- package/doc/src/app/hooks/useIsFullScreen.ts +14 -0
- package/doc/src/app/hooks/usePublicKey.ts +21 -0
- package/doc/src/app/layout.tsx +51 -0
- package/doc/src/app/page.tsx +86 -0
- package/doc/src/geops-ui.ts +3 -0
- package/doc/tailwind.config.ts +20 -0
- package/doc/tsconfig.json +40 -0
- package/eslint.config.mjs +40 -0
- package/favicon.ico +0 -0
- package/global.d.ts +4 -0
- package/iframe.html +34 -0
- package/index.html +276 -0
- package/index.js +2162 -0
- package/input.css +34 -0
- package/jest-setup.js +4 -0
- package/jest.config.js +17 -0
- package/package.json +80 -0
- package/scripts/build.mjs +16 -0
- package/scripts/dev.mjs +26 -0
- package/search.html +144 -0
- package/src/BaseLayer/BaseLayer.tsx +36 -0
- package/src/BaseLayer/index.tsx +1 -0
- package/src/Copyright/Copyright.tsx +54 -0
- package/src/Copyright/index.css +3 -0
- package/src/Copyright/index.tsx +1 -0
- package/src/DebugDeparture/DebugDeparture.tsx +116 -0
- package/src/DebugDeparture/index.tsx +1 -0
- package/src/DebugStop/DebugStop.tsx +47 -0
- package/src/DebugStop/index.tsx +1 -0
- package/src/Departure/Departure.tsx +55 -0
- package/src/Departure/index.tsx +1 -0
- package/src/GeolocationButton/GeolocationButton.tsx +81 -0
- package/src/GeolocationButton/index.tsx +1 -0
- package/src/Map/Map.tsx +89 -0
- package/src/Map/index.tsx +1 -0
- package/src/MobilityMap/MobilityMap.tsx +259 -0
- package/src/MobilityMap/index.css +13 -0
- package/src/MobilityMap/index.tsx +1 -0
- package/src/NotificationLayer/NotificationLayer.tsx +156 -0
- package/src/NotificationLayer/index.tsx +1 -0
- package/src/NotificationLayer/notificationUtils.ts +191 -0
- package/src/Overlay/Overlay.tsx +57 -0
- package/src/Overlay/index.tsx +1 -0
- package/src/RealtimeLayer/RealtimeLayer.tsx +230 -0
- package/src/RealtimeLayer/index.tsx +1 -0
- package/src/RouteDestination/RouteDestination.test.tsx +13 -0
- package/src/RouteDestination/RouteDestination.tsx +15 -0
- package/src/RouteDestination/index.tsx +1 -0
- package/src/RouteIcon/RouteIcon.tsx +66 -0
- package/src/RouteIcon/index.tsx +1 -0
- package/src/RouteIdentifier/RouteIdentifer.tsx +35 -0
- package/src/RouteIdentifier/index.tsx +1 -0
- package/src/RouteInfos/RouteInfos.tsx +22 -0
- package/src/RouteInfos/index.tsx +1 -0
- package/src/RouteSchedule/RouteSchedule.tsx +69 -0
- package/src/RouteSchedule/firstStation.png +0 -0
- package/src/RouteSchedule/index.tsx +1 -0
- package/src/RouteSchedule/lastStation.png +0 -0
- package/src/RouteSchedule/line.png +0 -0
- package/src/RouteSchedule/station.png +0 -0
- package/src/RouteScheduleFooter/RouteScheduleFooter.tsx +44 -0
- package/src/RouteScheduleFooter/index.tsx +1 -0
- package/src/RouteScheduleHeader/RouteScheduleHeader.tsx +58 -0
- package/src/RouteScheduleHeader/index.tsx +1 -0
- package/src/RouteStop/RouteStop.tsx +121 -0
- package/src/RouteStop/index.tsx +1 -0
- package/src/RouteStopDelay/RouteStopDelay.tsx +36 -0
- package/src/RouteStopDelay/index.tsx +1 -0
- package/src/RouteStopName/RouteStopName.tsx +24 -0
- package/src/RouteStopName/index.tsx +1 -0
- package/src/RouteStopPlatform/RouteStopPlatform.tsx +29 -0
- package/src/RouteStopPlatform/index.tsx +1 -0
- package/src/RouteStopProgress/RouteStopProgress.tsx +101 -0
- package/src/RouteStopProgress/index.tsx +1 -0
- package/src/RouteStopServices/RouteStopServices.tsx +26 -0
- package/src/RouteStopServices/index.tsx +1 -0
- package/src/RouteStopStation/RouteStopStation.tsx +32 -0
- package/src/RouteStopStation/index.tsx +1 -0
- package/src/RouteStopTime/RouteStopTime.tsx +34 -0
- package/src/RouteStopTime/index.tsx +1 -0
- package/src/RvfMobilityMap/RvfMobilityMap.tsx +245 -0
- package/src/RvfMobilityMap/index.css +13 -0
- package/src/RvfMobilityMap/index.tsx +1 -0
- package/src/ScaleLine/ScaleLine.tsx +51 -0
- package/src/ScaleLine/index.css +6 -0
- package/src/ScaleLine/index.tsx +1 -0
- package/src/ScrollableHandler/ScrollableHandler.tsx +65 -0
- package/src/ScrollableHandler/index.tsx +1 -0
- package/src/Search/Search.tsx +18 -0
- package/src/Search/index.tsx +1 -0
- package/src/SingleClickListener/SingleClickListener.tsx +103 -0
- package/src/SingleClickListener/index.tsx +1 -0
- package/src/Station/Station.tsx +68 -0
- package/src/Station/index.tsx +1 -0
- package/src/StationHeader/StationHeader.tsx +32 -0
- package/src/StationHeader/index.tsx +1 -0
- package/src/StationName/StationName.tsx +21 -0
- package/src/StationName/index.tsx +1 -0
- package/src/StationServices/StationServices.tsx +80 -0
- package/src/StationServices/index.tsx +1 -0
- package/src/StationsLayer/StationsLayer.tsx +41 -0
- package/src/StationsLayer/index.tsx +1 -0
- package/src/StopsSearch/StopsSearch.tsx +254 -0
- package/src/StopsSearch/index.tsx +1 -0
- package/src/icons/Airport/Airport.tsx +17 -0
- package/src/icons/Airport/airport-14-svgrepo-com.svg +41 -0
- package/src/icons/Airport/index.tsx +1 -0
- package/src/icons/BarAndRestaurants/BarAndRestaurants.tsx +17 -0
- package/src/icons/BarAndRestaurants/food-restaurant-svgrepo-com.svg +12 -0
- package/src/icons/BarAndRestaurants/index.tsx +1 -0
- package/src/icons/Bathroom/Bathroom.tsx +59 -0
- package/src/icons/Bathroom/bathroom-restroom-svgrepo-com.svg +38 -0
- package/src/icons/Bathroom/index.tsx +1 -0
- package/src/icons/BikeStorage/BikeStorage.tsx +17 -0
- package/src/icons/BikeStorage/index.tsx +1 -0
- package/src/icons/BikeStorage/parking-bicycle-14-svgrepo-com.svg +41 -0
- package/src/icons/Elevator/Elevator.tsx +16 -0
- package/src/icons/Elevator/elevator-svgrepo-com.svg +2 -0
- package/src/icons/Elevator/index.tsx +1 -0
- package/src/icons/Police/Police.tsx +20 -0
- package/src/icons/Police/index.tsx +1 -0
- package/src/icons/Police/polizia.png +0 -0
- package/src/icons/README.md +52 -0
- package/src/icons/WaitingAreas/WaitingAreas.tsx +16 -0
- package/src/icons/WaitingAreas/highway-rest-area-svgrepo-com.svg +5 -0
- package/src/icons/WaitingAreas/index.tsx +1 -0
- package/src/icons/WaitingAreas/wheelchair-svgrepo-com.svg +2 -0
- package/src/icons/WheelChair/WheelChair.tsx +16 -0
- package/src/icons/WheelChair/disabili.png +0 -0
- package/src/icons/WheelChair/index.tsx +1 -0
- package/src/icons/WheelChair/wheelchair-svgrepo-com.svg +2 -0
- package/src/index.tsx +50 -0
- package/src/utils/MobilityEvent.ts +21 -0
- package/src/utils/addSourceAndLayers.ts +62 -0
- package/src/utils/centerOnStation.ts +17 -0
- package/src/utils/centerOnVehicle.ts +50 -0
- package/src/utils/getBgColor.ts +3 -0
- package/src/utils/getDelayColor.test.ts +20 -0
- package/src/utils/getDelayColor.ts +23 -0
- package/src/utils/getDelayColorForVehicle.test.ts +28 -0
- package/src/utils/getDelayColorForVehicle.ts +25 -0
- package/src/utils/getDelayFontForVehicle.test.ts +7 -0
- package/src/utils/getDelayFontForVehicle.tsx +8 -0
- package/src/utils/getDelayString.test.ts +22 -0
- package/src/utils/getDelayString.ts +28 -0
- package/src/utils/getDelayTextForVehicle.test.ts +28 -0
- package/src/utils/getDelayTextForVehicle.ts +21 -0
- package/src/utils/getFullTrajectoryAndFit.ts +40 -0
- package/src/utils/getHoursAndMinutes.test.ts +14 -0
- package/src/utils/getHoursAndMinutes.ts +22 -0
- package/src/utils/getMainColorForVehicle.test.ts +27 -0
- package/src/utils/getMainColorForVehicle.ts +46 -0
- package/src/utils/getStopStatus.test.ts +104 -0
- package/src/utils/getStopStatus.ts +171 -0
- package/src/utils/getTextFontForVehicle.test.ts +7 -0
- package/src/utils/getTextFontForVehicle.tsx +9 -0
- package/src/utils/getTextForVehicle.test.ts +17 -0
- package/src/utils/getTextForVehicle.ts +19 -0
- package/src/utils/hooks/useDebug.tsx +11 -0
- package/src/utils/hooks/useDeparture.tsx +23 -0
- package/src/utils/hooks/useI18n.tsx +20 -0
- package/src/utils/hooks/useMapContext.tsx +74 -0
- package/src/utils/hooks/useParams.ts +5 -0
- package/src/utils/hooks/useRouteStop.tsx +33 -0
- package/src/utils/hooks/useStation.tsx +21 -0
- package/src/utils/hooks/useUpdatePermalink.tsx +33 -0
- package/src/utils/hooks/useZoom.tsx +32 -0
- package/src/utils/i18n.ts +16 -0
- package/src/utils/translations.ts +31 -0
- package/tailwind.config.mjs +56 -0
- package/testNotification.json +50653 -0
- 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
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
|
+
});
|
package/scripts/dev.mjs
ADDED
|
@@ -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
|
+
<script
|
|
54
|
+
type="module"
|
|
55
|
+
src="https://www.unpkg.com/@geops/mobility-web-component">
|
|
56
|
+
</script>
|
|
57
|
+
<geops-mobility-search
|
|
58
|
+
apikey="YOUR_GEOPS_API_KEY"
|
|
59
|
+
limit="5"
|
|
60
|
+
mots="rail,bus"
|
|
61
|
+
style="display: block;width: 800px;height: 800px;">
|
|
62
|
+
</geops-mobility></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
|
+
>>> 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 @@
|
|
|
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";
|