56 Commits

Author SHA1 Message Date
ea2a18f3ad Add: code to fetch disruption data and see if it is relevant 2020-12-08 10:29:03 +01:00
75b4ecc4ed Merge pull request #5 from thefeli73/we-json-examples
Add: json files for scenarios
2020-12-08 09:38:22 +01:00
3080359dcd Merge branch 'main' into we-json-examples 2020-12-08 09:38:11 +01:00
3d7e6cf52f Add: json files for scenarios 2020-12-08 09:36:19 +01:00
34f4b8af18 Merge pull request #4 from thefeli73/we-Disruption-base
We disruption base
2020-12-08 09:18:21 +01:00
7c59fa2825 Merge branch 'main' into we-Disruption-base 2020-12-08 09:18:00 +01:00
31263e919e Minor modifications to Example API components and base classes 2020-12-08 09:13:38 +01:00
d40420ad2b Remove irrelevant button errors in console 2020-12-04 12:02:45 +01:00
4ce76dbe90 Merge branch 'aw-disruption-control' into main 2020-12-04 11:53:37 +01:00
051afedcc5 Add user name to navigation drawer 2020-12-04 11:52:41 +01:00
bff5a73c8c Merge branch 'main' into aw-disruption-control 2020-12-04 11:49:28 +01:00
093199d0e0 Add global data variable 2020-12-04 11:48:56 +01:00
25d66f9195 Updated class changes in TrafficEntry 2020-12-04 11:47:42 +01:00
4e36270130 Format TrafficInfo.js 2020-12-04 11:13:55 +01:00
c36d6afea7 Merge to work on aw branch 2020-12-04 10:51:09 +01:00
ff8a87c961 Hack: Nothing is done just commiting to swap branch 2020-12-04 10:45:22 +01:00
c3edd2d74f Add basic component for calls to traffic disruption API 2020-12-04 10:08:11 +01:00
b324250c79 Merge remote-tracking branch 'origin/aw-client-side-classes' into aw-disruption-control 2020-12-04 09:59:51 +01:00
e35524fa19 Merge pull request #3 from williameriksson126/we-AccessToken-class
Add: AccessToken now updated to seperate class
2020-11-30 10:21:10 +01:00
521d3b2e63 Add: AccessToken now updated to seperate class 2020-11-30 10:18:18 +01:00
3bc1ff9a1a Add and update classes for client-side data management 2020-11-27 17:32:35 +01:00
177bbdf89d Add possibility of closing popups 2020-11-27 17:25:29 +01:00
a1b078f418 Add misc CSS 2020-11-27 17:23:25 +01:00
66dbc66ec4 Add generalized button class 2020-11-27 17:06:14 +01:00
f86b9ee220 Add popup class 2020-11-27 17:04:19 +01:00
daaa9a62f4 Add navigation drawer content and make it expandable 2020-11-27 16:17:56 +01:00
38a6f7c786 Add new color 2020-11-27 16:16:28 +01:00
24dd1361f6 Fix traffic info entries overlapping stop title 2020-11-27 16:16:01 +01:00
e8cfc33991 Add word-break to bottom menu button labels 2020-11-27 16:15:27 +01:00
a1158d4525 Move and rename Disruption 2020-11-27 14:00:05 +01:00
1067277cb8 Allow scroll for entries on traffic info page 2020-11-27 13:58:01 +01:00
a3810491e9 Remove default logo 2020-11-27 13:45:27 +01:00
b8322417a0 Fix some React errors and warnings 2020-11-27 13:43:33 +01:00
fc29d7d327 Non-existing button 2020-11-27 11:41:20 +01:00
87f9661993 Merge pull request #2 from williameriksson126/we-VT-API-Access-Token-tests
We vt api access token tests
2020-11-27 09:43:58 +01:00
bd3e0fb582 Merge branch 'main' into we-VT-API-Access-Token-tests 2020-11-27 09:43:36 +01:00
12b43e3d61 Add Access Token class as template for generating future tokens 2020-11-27 09:27:54 +01:00
771b5a5509 Add content to Traffic Info page 2020-11-26 21:42:30 +01:00
7cde8a62ba Add Stop and Departure classes 2020-11-26 21:41:57 +01:00
9c21062fdc Add color for transport line 2020-11-26 20:40:48 +01:00
f4ee176f67 Prevent side scrolling 2020-11-26 20:07:38 +01:00
025061693c Remove unnecessary parameters 2020-11-26 19:43:10 +01:00
0a99562d83 Add TopMenu component and page specific content 2020-11-26 19:37:44 +01:00
51e91981e6 Add NearbyStation class is a form that given latitude and longitude coordinates gives nearby locations 2020-11-24 11:54:59 +01:00
83cdfb3959 Add traffic info button 2020-11-24 09:47:09 +01:00
3a1d06f53a Add Test file for trying to access the API, Not successful 2020-11-23 16:22:13 +01:00
9a8c9756a2 Remove unnecessary constructor 2020-11-20 18:01:36 +01:00
3d76447d72 Merge branch 'aw-uiBase' into main 2020-11-20 18:00:34 +01:00
a7e177905e Add client-side routing 2020-11-20 17:56:18 +01:00
ae8ef6fc57 Rename PageArea to MainArea 2020-11-20 17:55:22 +01:00
5f12f1ad5a Add react-router-dom 2020-11-20 17:55:22 +01:00
4bcd512374 Add basic VT UI design 2020-11-20 17:55:22 +01:00
f95d78721f Add Roboto Light font 2020-11-20 17:55:22 +01:00
cd467370b9 Add CSS color variables 2020-11-20 17:55:21 +01:00
899086352d Update app settings and parameters 2020-11-20 17:55:12 +01:00
43ecf76337 Merge pull request #1 from williameriksson126/we-basicButtonClass
Add basic button class
2020-11-20 11:54:59 +01:00
74 changed files with 1931 additions and 117 deletions

View File

@ -25,20 +25,37 @@ Tutorials för React går att hitta [här](https://www.youtube.com/playlist?list
* ``public/index.html`` är den enda HTML-fil vi kommer ha i appen, detta eftersom vi bygger en s.k. SPA (Single Page Application). Man ändrar oftast inget i denna fil utöver möjligtvis innehållet i ``<head>``, detta eftersom React hanterar hela vårt UI.
* Ursprungspunkten för React är ``src/index.js``.
<!--
## Upplägg
``` mermaid
```mermaid
classDiagram
class User
User : String deviceId
User : Coordinates location
User : nearbyStops()
class User
User : Subscription[] subs
User : Location loc
class Coordinates
Coordinates : Float lon
Coordinates : Float lat
class Line
class Stop
Stop : String name
Stop : Track[] locations
Stop : Departure[] departures
class Subscription
Subscription : Line line
class Departure
Departure : String lineName
Departure : Stop finalStop
Departure : String time
Departure : String trafficInfo
```
-->
class Track
Track : String name
User <.. Coordinates
User <.. Stop
Stop <.. Departure
Departure <.. Stop
Stop <.. Track
```

152
package-lock.json generated
View File

@ -3030,6 +3030,14 @@
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.0.2.tgz",
"integrity": "sha512-arU1h31OGFu+LPrOLGZ7nB45v940NMDMEJeNmbutu57P+UFDVnkZg3e+J1I2HJRZ9hT7gO8J91dn/PMrAiKakA=="
},
"axios": {
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz",
"integrity": "sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@ -3438,6 +3446,15 @@
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
"optional": true
},
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"optional": true,
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@ -6335,6 +6352,12 @@
}
}
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"optional": true
},
"filesize": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@ -6969,6 +6992,19 @@
"resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
"integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
},
"history": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
"integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
"requires": {
"@babel/runtime": "^7.1.2",
"loose-envify": "^1.2.0",
"resolve-pathname": "^3.0.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0",
"value-equal": "^1.0.1"
}
},
"hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@ -6979,6 +7015,14 @@
"minimalistic-crypto-utils": "^1.0.1"
}
},
"hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"requires": {
"react-is": "^16.7.0"
}
},
"hoopy": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
@ -9909,6 +9953,15 @@
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="
},
"mini-create-react-context": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz",
"integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==",
"requires": {
"@babel/runtime": "^7.12.1",
"tiny-warning": "^1.0.3"
}
},
"mini-css-extract-plugin": {
"version": "0.11.3",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.3.tgz",
@ -10095,6 +10148,12 @@
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
},
"nan": {
"version": "2.14.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
"optional": true
},
"nanoid": {
"version": "3.1.16",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.16.tgz",
@ -12217,6 +12276,11 @@
"whatwg-fetch": "^3.4.1"
}
},
"react-axios": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/react-axios/-/react-axios-2.0.3.tgz",
"integrity": "sha512-63kY2iupdRgbvPq9G8xmM0NWUnt2Q5YmpotMoLQsxKOzKXKZg2Lo6CzF/bcZvtmv3WnfjBU6Bg8nZQO28eIAZw=="
},
"react-dev-utils": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.0.tgz",
@ -12322,11 +12386,67 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-native-push-notification": {
"version": "6.1.3",
"resolved": "https://registry.npmjs.org/react-native-push-notification/-/react-native-push-notification-6.1.3.tgz",
"integrity": "sha512-qNbFCkObCXwSFQbK6hJyx1Bym1D7V4XM8iN2L6eL3GAdNLmeBTdLdx3mPbKJtuaDJ1+deniFTQ2rz6hU4ELOXA=="
},
"react-push-notification": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/react-push-notification/-/react-push-notification-1.3.0.tgz",
"integrity": "sha512-hyYKZqwtNOgRP74fAafVIivEr99vUtH0nDgcWkPKd302BhMuUMr5wuuEX236bSbCoM4nxlOge1m0CKIEtWBqLA=="
},
"react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg=="
},
"react-router": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz",
"integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==",
"requires": {
"@babel/runtime": "^7.1.2",
"history": "^4.9.0",
"hoist-non-react-statics": "^3.1.0",
"loose-envify": "^1.3.1",
"mini-create-react-context": "^0.4.0",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.6.2",
"react-is": "^16.6.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"path-to-regexp": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
"requires": {
"isarray": "0.0.1"
}
}
}
},
"react-router-dom": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz",
"integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==",
"requires": {
"@babel/runtime": "^7.1.2",
"history": "^4.9.0",
"loose-envify": "^1.3.1",
"prop-types": "^15.6.2",
"react-router": "5.2.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0"
}
},
"react-scripts": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.0.tgz",
@ -12782,6 +12902,11 @@
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
},
"resolve-pathname": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
},
"resolve-url": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
@ -14518,6 +14643,16 @@
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
},
"tiny-invariant": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz",
"integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw=="
},
"tiny-warning": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@ -14976,6 +15111,11 @@
"spdx-expression-parse": "^3.0.0"
}
},
"value-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
"integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@ -15148,7 +15288,11 @@
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"optional": true
"optional": true,
"requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
}
},
"glob-parent": {
"version": "3.1.0",
@ -15734,7 +15878,11 @@
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"optional": true
"optional": true,
"requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
}
},
"glob-parent": {
"version": "3.1.0",

View File

@ -6,8 +6,13 @@
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.1.2",
"@testing-library/user-event": "^12.2.2",
"axios": "^0.21.0",
"react": "^17.0.1",
"react-axios": "^2.0.3",
"react-dom": "^17.0.1",
"react-native-push-notification": "^6.1.3",
"react-push-notification": "^1.3.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.0",
"web-vitals": "^0.2.4"
},

View File

@ -3,17 +3,13 @@
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<meta name="theme-color" content="#01aaeb" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="description" content="Störningar i kollektivtrafiken" />
<meta name='viewport' content='minimal-ui, width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=0' >
<meta name=apple-mobile-web-app-capable content=yes>
<meta name=apple-mobile-web-app-status-bar-style content=black>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
@ -29,15 +25,5 @@
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -1,25 +1,20 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"short_name": "Västtrafik",
"name": "Störningar i kollektivtrafiken",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"src": "logo.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
"sizes": "135x135"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
"display": "fullscreen",
"theme_color": "#01aaeb",
"background_color": "#f0f8fa"
}

View File

@ -0,0 +1,15 @@
{
"situationNumber": "RT1",
"severity":"normal",
"title":"Stannar inte på dessa hållplatser",
"affectedStopPoints":[
{
"gid": "9022014014020001",
"name": "Ekelöv västra, Kungälv"
},
{
"gid": "9022014014751001",
"name": "Guddeby, Kungälv"
}
]
}

View File

@ -0,0 +1,11 @@
{
"situationNumber": "RT2",
"severity":"normal",
"title":"Försening",
"affectedStopPoints":[
{
"gid": "9021014014225000",
"name": "Skrämmenborg, Kungälv"
}
]
}

View File

@ -0,0 +1,5 @@
{
"name":"1",
"deviceId":"1",
"location":"9022014014754001"
}

View File

@ -0,0 +1,5 @@
{
"name":"2",
"deviceId":"2",
"location":"9022014014020001"
}

View File

@ -0,0 +1,5 @@
{
"name":"3",
"deviceId":"3",
"location":"9022014014751001"
}

View File

@ -0,0 +1,5 @@
{
"name":"4",
"deviceId":"4",
"location":"9021014014225000"
}

View File

@ -3,6 +3,7 @@
text-align: center;
display: flex;
flex-direction: column;
background: var(--colorBg);
}
.App-logo {

View File

@ -1,27 +1,37 @@
import './App.css';
import React, { Component } from 'react';
import NavigationDrawer from './components/NavigationDrawer.js'
import Header from './components/Header.js'
import PageArea from './components/PageArea.js'
import BottomMenu from './components/BottomMenu.js'
import "./variables.css";
import "./App.css";
import React, { Component } from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import BottomMenu from "./components/BottomMenu.js";
import NearbyStation from "./components/NearbyStation.js";
import Disruption from "./components/Disruption.js";
import StationDisruption from "./components/StationDisruption.js";
import Tickets from "./components/pages/Tickets.js";
import TicketsBuy from "./components/pages/TicketsBuy.js";
import Travel from "./components/pages/Travel.js";
import TrafficInfo from "./components/pages/TrafficInfo.js";
import "./variables.css";
class App extends Component {
render() {
return (
<div className="App">
{/*
<Button
title = "placeholderTitle"
destination = "placeholderDestination"
/>
*/}
<NavigationDrawer />
<Header />
<PageArea />
<BottomMenu />
</div>
);
}
render() {
return (
<Router>
<div className="App">
<Route path="/" exact component={TicketsBuy} />
<Route path="/tickets" exact component={Tickets} />
<Route path="/ticketsBuy" exact component={TicketsBuy} />
<Route path="/travel" exact component={Travel} />
<Route path="/traffic" exact component={TrafficInfo} />
<BottomMenu />
</div>
</Router>
);
}
}
export default App;

16
src/GlobalData.js Normal file
View File

@ -0,0 +1,16 @@
import User from './classes/User.js';
import Disruption from './classes/Disruption.js'
import Coordinates from "./classes/Coordinates.js";
let globalData = {
user: new User(
"test",
"123",
new Coordinates(),
"9022014014020001"
),
disruption: new Disruption(
)
};
export default globalData;

View File

@ -0,0 +1,21 @@
import axios from 'axios';
class AccessToken {
credentials = 'NXR5N2d4bUFmUWxVSERIZG03a2dhcVh3SzVJYTp3cElPVVJuSkpjVHRPNnJPUlltWVlQcTR3WGth'
device = '123'
constructor() {
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + this.credentials
};
axios.post('https://api.vasttrafik.se/token','grant_type=client_credentials&scope=device_'+this.device, {headers} )
.then(response => {
console.log(response);
this.token = response.data.access_token
});
}
}
export default AccessToken

View File

@ -0,0 +1,15 @@
/*
Denna klass är en modell för platskoordinater.
lon : Float (Longitud)
lat : Float (Latitud)
*/
class Coordinates {
constructor(lon, lat) {
this.lon = lon;
this.lat = lat;
}
}
export default Coordinates;

19
src/classes/Departure.js Normal file
View File

@ -0,0 +1,19 @@
/*
Denna klass är en modell för avgångar.
lineName : String (Linjenamnet)
finalStop : Stop (Ändhållplats)
time : String (Avgångstid)
trafficInfo : String (Trafikinformation)
*/
class Departure {
constructor(lineName, finalStop, time, trafficInfo) {
this.lineName = lineName;
this.finalStop = finalStop;
this.time = time;
this.trafficInfo = trafficInfo;
}
}
export default Departure;

24
src/classes/Disruption.js Normal file
View File

@ -0,0 +1,24 @@
/*
Denna klass är en modell för störningar.
*/
class Disruption {
constructor(startTime, locations, departures) {
this.startTime = startTime;
this.affectedLines = affectedLines;
this.departures = departures;
}
}
/*
Från västtrafiks api ett element i listan av hållplatser ser ut som följande
"id": "string",
"lon": "string",
"idx": "string",
"weight": "string",
"name": "string",
"track": "string",
"lat": "string"
*/
export default Disruption;

28
src/classes/Stop.js Normal file
View File

@ -0,0 +1,28 @@
/*
Denna klass är en modell för hållplatser.
name : String (Hållplatsens namn)
locations : Track[] (Möjliga lägen)
departures : Departure[] (Avgångar från hållplatsen)
*/
class Stop {
constructor(name, locations, departures) {
this.name = name;
this.locations = locations;
this.departures = departures;
}
}
/*
Från västtrafiks api ett element i listan av hållplatser ser ut som följande
"id": "string",
"lon": "string",
"idx": "string",
"weight": "string",
"name": "string",
"track": "string",
"lat": "string"
*/
export default Stop;

13
src/classes/Track.js Normal file
View File

@ -0,0 +1,13 @@
/*
Denna klass är en modell för hållplatslägen, ex. "Läge A" eller "Spår 3".
name : String (Lägets namn)
*/
class Track {
constructor(name) {
this.name = name;
}
}
export default Track;

18
src/classes/User.js Normal file
View File

@ -0,0 +1,18 @@
/*
Denna klass är en modell för användare.
name : String (Användarnamn)
deviceId : Int (Enhetens ID)
location : Coordinates (Användarens koordinater)
*/
class User {
constructor(name, deviceId, location, stoppointgid) {
this.name = name;
this.deviceId = deviceId;
this.location = location;
this.stoppointgid = stoppointgid;
}
}
export default User;

11
src/classes/disruption.js Normal file
View File

@ -0,0 +1,11 @@
class Disruption {
constructor(situationNumber, severity, title, affectedStopPoints) {
this.situationNumber = situationNumber;
this.severity = severity;
this.title = title;
this.affectedStopPoints = affectedStopPoints;
}
}
export default Disruption;

View File

@ -1,13 +1,33 @@
import './css/BottomMenu.css';
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import MenuButton from './MenuButton';
import './css/BottomMenu.css';
import ticketsIcon from '../img/tickets.svg';
import ticketsBuyIcon from '../img/tickets+.svg';
import travelIcon from '../img/tram.svg';
import trafficIcon from '../img/traffic.svg';
class BottomMenu extends Component {
render() {
return (
<div id="bottomMenu">
<button>Biljetter</button>
<button>Köp biljett</button>
<button>Reseplanering</button>
<Link to="/tickets">
<MenuButton label="Biljetter" icon={ticketsIcon}/>
</Link>
<Link to="/ticketsBuy">
<MenuButton label="Köp biljett" icon={ticketsBuyIcon}/>
</Link>
<Link to="/travel">
<MenuButton label="Reseplanering" icon={travelIcon}/>
</Link>
<Link to="/traffic">
<MenuButton label="Trafikinfo" icon={trafficIcon}/>
</Link>
</div>
);
}

View File

@ -1,14 +1,30 @@
import React, {Component} from 'react'
import React, { Component } from 'react';
import './css/Button.css';
class Button extends Component {
render() {
// Multiple onClick functions
onClick = () => {
if (this.props.onClick !== null
&& this.props.onClick !== undefined) {
if (Array.isArray(this.props.onClick)) {
this.props.onClick.forEach(func => {
func();
});
} else {
console.log("Error when parsing Button onClick functions.");
}
}
}
render() {
return (
<a href={this.props.destination}>
{this.props.title}
</a>
<button className={this.props.className} onClick={this.onClick}>
{this.props.children}
</button>
);
}
}
// TODO Add css
export default Button
export default Button;

View File

@ -0,0 +1,60 @@
import React from 'react';
import axios from 'axios';
import AccessToken from '../classes/AccessToken'
class Diruption extends React.Component {
state = {
gid: '9022014005700002',
disruptions: [],
token: undefined,
tokenClass: new AccessToken()
}
handleChangeGid = event => {
this.setState({ lat: event.target.value});
}
handleSubmit = event => {
event.preventDefault();
const headers = {
'Authorization': 'Bearer ' + this.state.tokenClass.token
};
console.log('Attempted connection')
axios.get('https://api.vasttrafik.se/ts/v1/traffic-situations/stoppoint/'+this.state.gid, { headers })
//axios.get('https://api.vasttrafik.se/ts/v1/traffic-situations/stoppoint/9022014005700002', { headers })
.then(response => {
console.log(response)
this.setState({
disruptions: response.data
})
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Stoppoint Gid:
<input type="text" name="gid" onChange={this.handleChangeGid} />
</label>
<button type="submit">Find traffic disruptions</button>
</form>
<h1>
{this.state.gid}
</h1>
{this.state.disruptions.map((item) =>
<div>
<h1>
{item.description}
</h1>
</div>
)}
</div>
)
}
}
export default Diruption

View File

@ -0,0 +1,51 @@
import addNotification from "react-push-notification";
import globData from '../GlobalData.js';
import ex1 from '../APIexamples/disruption1.json'
import ex2 from '../APIexamples/disruption1.json'
import Button from './Button.js';
import disruptIcon from '../img/flash.svg';
class DisruptionButton extends Button {
state = {
jsonLocation: this.props.path,
user: globData.user,
disruption: ""
}
genDisrupt = () => {
console.log(globData.disruption)
for (let stopPoint of ex1.affectedStopPoints) {
if(stopPoint.gid === this.state.user.stoppointgid){
this.state.disruption = ex1
}
}
globData.disruption = this.state.disruption
console.log(globData.disruption)
addNotification({
title: "Warning",
subtitle: "This is a subtitle",
message: "This is a very long message",
theme: "blue",
native: true, // when using native, your OS will handle theming.
});
}
render() {
return (
<Button onClick={this.props.onClick.concat([this.genDisrupt])} className="disruptBtn">
<img src={disruptIcon} alt="" />
<span>Generera Störning</span>
</Button>
);
}
}
export default DisruptionButton;

View File

@ -1,12 +1,31 @@
import './css/Header.css';
import React, { Component } from 'react';
import NavigationDrawer from './NavigationDrawer.js';
import './css/Header.css';
import navIcon from '../img/menu.svg'
class Header extends Component {
constructor(props) {
super(props);
this.navDrawerElem = React.createRef();
}
handleClick = () => {
this.navDrawerElem.current.toggle();
};
render() {
return (
<header>
<button id="navDrawBtn"></button>
</header>
<>
<NavigationDrawer ref={this.navDrawerElem} />
<header>
<button id="navBtn"><img src={navIcon} alt="" onClick={this.handleClick} /></button>
<h1 id="pageTitle">{this.props.title}</h1>
</header>
</>
);
}
}

View File

@ -0,0 +1,15 @@
import React, { Component } from 'react';
import './css/MainArea.css';
class MainArea extends Component {
render() {
return (
<main>
{this.props.children}
</main>
);
}
}
export default MainArea;

View File

@ -0,0 +1,24 @@
import Button from './Button.js';
class MenuButton extends Button {
render() {
if (this.props.childOrderReverse) {
return (
<Button>
<span>{this.props.label}</span>
<img src={this.props.icon} alt="" />
</Button>
);
} else {
return (
<Button>
<img src={this.props.icon} alt="" />
<span>{this.props.label}</span>
</Button>
);
}
}
}
export default MenuButton;

View File

@ -1,10 +1,75 @@
import './css/NavigationDrawer.css';
import React, { Component } from 'react';
import globalData from '../GlobalData.js';
import DisruptionButton from "./DisruptionButton.js";
import Popup from './Popup.js';
import Button from './Button.js';
import './css/NavigationDrawer.css';
import userIcon from '../img/user.svg';
class NavigationDrawer extends Component {
constructor(props) {
super(props);
this.popupElem = React.createRef();
}
state = {
open: false
};
toggle = () => {
if (this.state.open)
this.close();
else
this.open();
};
open = () => {
this.setState({
open: true
});
};
close = () => {
this.setState({
open: false
});
};
showPopup = () => {
this.popupElem.current.show();
};
render() {
return (
<div id="navDrawer"></div>
<>
<Popup ref={this.popupElem}>
<h3>Välj hållplats:</h3>
<ul>
<li><Button>Hållplats 1</Button></li>
<li><Button>Hållplats 2</Button></li>
<li><Button>Hållplats 3</Button></li>
<li><Button>Hållplats 4</Button></li>
</ul>
</Popup>
<div id="navDrawer" className={`${this.state.open ? "open" : ""}`}>
<header>
<img src={userIcon} alt="" />
<span>{globalData.user.name}</span>
<span>example@gmail.com</span>
</header>
<div id="navList">
<DisruptionButton path={"ex1"} onClick={[this.showPopup, this.close]} />
</div>
<hr />
<span id="version">Projektgrupp 3 - Utmaning 7</span>
</div>
<div id="clickArea" className={`${this.state.open ? "" : "hidden"}`} onClick={this.close} />
</>
);
}
}

View File

@ -0,0 +1,70 @@
import React from 'react';
import axios from 'axios';
import AccessToken from '../classes/AccessToken';
import StopComponent from './StopComponent';
import Stop from '../classes/Stop';
class NearbyStation extends React.Component {
state = {
lat: '57.7',
long: '12.0',
stops: [],
token: undefined,
tokenClass: new AccessToken()
}
handleChangeLat = event => {
this.setState({ lat: event.target.value});
}
handleChangeLong = event => {
this.setState({ long: event.target.value});
}
handleSubmit = event => {
event.preventDefault();
const headers = {
'Authorization': 'Bearer ' + this.state.tokenClass.token
};
console.log('Attempted connection')
axios.get('https://api.vasttrafik.se/bin/rest.exe/v2/location.nearbystops?originCoordLat='+this.state.lat+'&originCoordLong='+this.state.long+'&maxNo=5&format=json', { headers })
.then(response => {
console.log(response.data.LocationList.StopLocation)
this.setState({
stops: response.data.LocationList.StopLocation,
})
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Lattitude coord:
<input type="text" name="lat" onChange={this.handleChangeLat} />
</label>
<label>
Longitude coord:
<input type="text" name="long" onChange={this.handleChangeLong} />
</label>
<button type="submit">Stops</button>
</form>
<h1>
{this.state.lat}
</h1>
<h1>
{this.state.long}
</h1>
{this.state.stops.map((item) =>
<StopComponent stop={item} />
)}
</div>
)
}
}
export default NearbyStation

View File

@ -1,12 +0,0 @@
import './css/PageArea.css';
import React, { Component } from 'react';
class PageArea extends Component {
render() {
return (
<div id="pageArea"></div>
);
}
}
export default PageArea;

36
src/components/Popup.js Normal file
View File

@ -0,0 +1,36 @@
import React, { Component } from 'react';
import './css/Popup.css';
class Popup extends Component {
state = {
visible: false
};
show = () => {
this.setState({
visible: true
});
};
hide = () => {
this.setState({
visible: false
});
};
render() {
return (
<>
<div className={`${this.state.visible ? "" : "hidden"}` + " popupClose"} onClick={this.hide} />
<div className={`${this.state.visible ? "visible" : ""}` + " popup " + this.props.className}>
{this.props.children}
</div>
</>
);
}
}
export default Popup;

View File

@ -0,0 +1,64 @@
import React from 'react';
import axios from 'axios';
import AccessToken from '../classes/AccessToken'
class StationDisruption extends React.Component {
state = {
gid: '9022014005700002',
lat: '57.7',
long: '12.0',
disruptions: [],
token: undefined,
tokenClass: new AccessToken()
}
handleChangeGid = event => {
this.setState({ lat: event.target.value});
}
handleSubmit = event => {
event.preventDefault();
const headers = {
'Authorization': 'Bearer ' + this.state.tokenClass.token
};
console.log('Attempted connection')
axios.get('https://api.vasttrafik.se/bin/rest.exe/v2/location.nearbystops?originCoordLat='+this.state.lat+'&originCoordLong='+this.state.long+'&maxNo=5&format=json', { headers })
.then(response => {
console.log(response.data.LocationList.StopLocation)
})
axios.get('https://api.vasttrafik.se/ts/v1/traffic-situations/stoppoint/'+this.state.gid, { headers })
.then(response => {
console.log(response)
this.setState({
disruptions: response.data
})
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Stoppoint Gid:
<input type="text" name="gid" onChange={this.handleChangeGid} />
</label>
<button type="submit">Find traffic disruptions</button>
</form>
<h1>
{this.state.gid}
</h1>
{this.state.disruptions.map((item) =>
<div>
<h1>
{item.description}
</h1>
</div>
)}
</div>
)
}
}
export default StationDisruption

View File

@ -0,0 +1,19 @@
import React, {Component} from 'react';
class StopComponent extends Component {
render() {
return (
<div>
<h1>
{this.props.stop.name},
{this.props.stop.id},
{this.props.stop.lat},
{this.props.stop.lon},
{this.props.stop.track}
</h1>
</div>
);
}
}
// TODO Add css
export default StopComponent

View File

@ -0,0 +1,19 @@
import React, { Component } from 'react';
import './css/StopTitle.css';
class StopTitle extends Component {
render() {
return (
<div id="stopTitle">
<h1>{this.props.stop.name}</h1>
<div>
<h3>{this.props.stop.locations[0]}</h3>
<button>Byt Läge</button>
</div>
</div>
);
}
}
export default StopTitle;

15
src/components/TopMenu.js Normal file
View File

@ -0,0 +1,15 @@
import React, { Component } from 'react';
import './css/TopMenu.css';
class TopMenu extends Component {
render() {
return (
<div id="topMenu">
{this.props.children}
</div>
);
}
}
export default TopMenu;

View File

@ -0,0 +1,42 @@
import React, { Component } from 'react';
import './css/TrafficInfo.css';
import busIcon from '../img/bus.svg';
import warningIcon from '../img/warning.svg';
class TrafficEntry extends Component {
render() {
let trafficInfo = this.props.departure.trafficInfo;
let lineInterference = trafficInfo !== "" && trafficInfo !== null && trafficInfo !== undefined;
return (
<div className="trafficEntry">
<div>
<div className="timeColumn">
<span>{this.props.departure.time}</span>
{lineInterference &&
<img src={warningIcon} alt=""></img>
}
</div>
<div className="lineColumn">
<div>
<span className="lineName">{this.props.departure.lineName}</span>
<img src={busIcon} alt=""></img>
<span className="destination">{this.props.departure.finalStop}</span>
</div>
{lineInterference &&
<p>{trafficInfo} <u>Visa mer</u></p>
}
</div>
</div>
{lineInterference &&
<button>Hitta annan resväg</button>
}
</div>
);
}
}
export default TrafficEntry;

View File

@ -0,0 +1,36 @@
import React, { Component } from 'react';
import TrafficEntry from './TrafficEntry.js';
import './css/TrafficInfo.css';
class TrafficList extends Component {
render() {
let entries = [];
let i = 0; // React requires elems in array to have associated unique key
this.props.departures.forEach(departure => {
entries.push(
<TrafficEntry key={i++} departure={departure} />
);
});
// Add separator between every element
const intersperse = (arr, sep) => arr.reduce((a,v)=>[...a,v,sep],[]).slice(0,-1);
entries = intersperse(entries, (<hr key={i++} />));
// Add separator after the last element
entries.push(<hr key={i++} />);
return (
<div id="trafficList">
{entries.map(element => {
return element
})}
</div>
);
}
}
export default TrafficList;

View File

@ -0,0 +1,17 @@
import React, { Component } from 'react';
class TripSelector extends Component {
render() {
return (
<form>
<label>Från:</label>
<input type="text" placeholder="Hållplats/Adress/Plats" />
<hr/>
<label>Till:</label>
<input type="text" placeholder="Hållplats/Adress/Plats" />
</form>
);
}
}
export default TripSelector;

View File

@ -1,18 +1,38 @@
#bottomMenu {
width: 100%;
height: 8vh;
background: lightcoral;
height: 9vh;
min-height: 60px;
background: white;
display: flex;
justify-content: space-evenly;
border-top: 2px solid rgba(0, 0, 0, 0.05);
}
#bottomMenu a {
display: contents;
text-decoration: none;
}
#bottomMenu button {
background: none;
border: none;
font-size: 0.9em;
margin-bottom: 5px;
flex-basis: calc(100%/3);
display: flex;
align-items: flex-end;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
word-break: break-word;
}
#bottomMenu button:active {
background: rgba(0, 0, 0, 0.1);
}
#bottomMenu button span {
color: black;
}
#bottomMenu button img {
width: 25px;
}

View File

@ -0,0 +1,3 @@
button:active {
background: rgba(0, 0, 0, 0.1);
}

View File

@ -1,5 +1,21 @@
header {
width: 100vw;
height: 15vh;
background: burlywood;
display: flex;
flex-direction: row;
align-items: center;
padding: 15px 15px 15vh 15px;
top: 0;
background: linear-gradient(90deg, var(--colorVT1), var(--colorVT2));
}
#navBtn img {
height: 1.4em;
}
#pageTitle {
font-size: 1.2em;
letter-spacing: 0.3px;
color: white;
font-family: 'Roboto Light', sans-serif;
padding: 0 0 0 25px;
}

View File

@ -0,0 +1,8 @@
main {
width: 100vw;
flex: 1 1 auto;
display: flex;
flex-flow: column;
justify-content: space-evenly;
overflow: hidden scroll;
}

View File

@ -0,0 +1,83 @@
#navDrawer {
width: 70vw;
height: 100%;
position: fixed;
top: 0;
left: -70vw;
background: white;
overflow: hidden;
z-index: 10;
transition: .35s;
display: flex;
flex-flow: column;
}
.open {
left: 0 !important;
}
#navDrawer header {
width: 100%;
padding: 4vh 0;
color: white;
font-size: 16px;
flex-basis: 15vh;
flex-direction: column;
justify-content: space-evenly;
}
#navDrawer header img {
width: 35px;
}
#navList {
flex-basis: 70vh;
display: flex;
flex-flow: column;
align-items: flex-start;
}
.disruptBtn {
height: 50px;
width: 100%;
padding: 0 0 0 5vw;
display: flex;
align-items: center;
align-self: flex-start;
font-size: 14px;
}
.disruptBtn:active {
background: rgba(0, 0, 0, 0.1);
}
.disruptBtn img {
height: 55%;
margin-right: 10px;
}
#clickArea {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.75);
position: fixed;
z-index: 5;
transition: .15s;
}
#navDrawer hr {
width: 90%;
margin: 0 10px 5px 0;
align-self: flex-end;
opacity: 0.5;
flex-basis: auto;
}
#version {
align-self: flex-end;
margin-right: 10px;
font-size: 14px;
color: var(--colorDiscrete);
min-height: 50px;
}

View File

@ -1,4 +0,0 @@
#pageArea {
width: 100vw;
flex: 1 1 auto;
}

View File

@ -0,0 +1,44 @@
.popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
transform-origin: center;
background: white;
width: 55vw;
height: 39vh;
padding: 3vh 5vw;
box-shadow: var(--boxShadow);
border-radius: var(--borderRadius);
transition: .35s;
z-index: 11;
}
.visible {
pointer-events: all;
transform: translate(-50%, -50%) scale(1);
}
.popup h3 {
margin-bottom: 20px;
}
.popup ul {
list-style: none;
}
.popup li button {
width: 100%;
padding: 8% 0;
font-size: 16px;
}
.popupClose {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.75);
z-index: 11;
}

View File

@ -0,0 +1,40 @@
#stopTitle {
text-align: left;
background: white;
border-radius: var(--borderRadius);
box-shadow: var(--boxShadow);
display: flex;
flex-direction: column;
justify-content: space-evenly;
padding: 0 5vw;
z-index: 4;
}
#stopTitle h1, #stopTitle h3 {
font-weight: 100;
}
#stopTitle div {
display: flex;
flex-direction: row;
}
#stopTitle h3 {
color: var(--colorDiscrete);
}
#stopTitle button {
width: auto;
height: 100%;
box-shadow: none;
background: rgba(0, 0, 0, 0.2);
display: block;
flex-flow: row;
margin-left: 10px;
padding: 0 2.5vw;
border-radius: calc(var(--topMenuHeight) / 15);
}
#stopTitle button:active {
background: rgba(0, 0, 0, 0.3);
}

View File

@ -0,0 +1,32 @@
#topMenu {
width: 100vw;
height: var(--topMenuHeight);
margin-top: calc(var(--topMenuHeight) / -2);
display: inline-flex;
justify-content: space-evenly;
}
#topMenu button {
width: var(--topMenuHeight);
height: calc(var(--topMenuHeight) / 1.3);
display: flex;
flex-flow: column;
justify-content: space-evenly;
background: white;
border-radius: calc(var(--topMenuHeight) / 15);
box-shadow: var(--boxShadow);
}
#topMenu button:active {
background: rgb(235, 235, 235);
}
#topMenu img {
width: 100%;
height: 40%;
}
#topMenu button span {
width: 100%;
font-size: calc(var(--topMenuHeight) / 7);
}

View File

@ -0,0 +1,84 @@
#trafficList {
height: 100%;
margin-top: 40px;
background: white;
}
.trafficEntry {
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
width: 100vw;
padding: 6vw 0;
background: white;
}
.trafficEntry div {
width: 90%;
display: flex;
flex-direction: row;
justify-content: space-evenly;
margin-bottom: 8px;
}
.trafficEntry div p {
text-align: left;
font-size: 3.5vw;
padding: 3vw 0;
}
.trafficEntry div div {
display: flex;
flex-direction: column;
}
.timeColumn {
flex-basis: 15%;
justify-content: flex-start;
align-items: center;
}
.timeColumn img {
width: 20px;
}
.lineColumn {
flex-basis: 75%;
}
.lineColumn img {
width: 30px;
margin-right: 10px;
}
.trafficEntry div div div {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: flex-end;
}
.lineName {
background: var(--colorLine);
color: white;
font-size: 6vw;
font-weight: 100;
margin-right: 10px;
padding: 1vw 4vw;
}
.destination {
font-size: 100%;
text-align: left;
}
.trafficEntry button {
width: 90%;
font-size: 4vw;
font-weight: bold;
color: var(--colorVT1);
padding: 4vw 0;
border-radius: var(--borderRadius);
box-shadow: var(--boxShadow);
}

View File

@ -0,0 +1,32 @@
form {
width: 65vw;
height: calc(var(--topMenuHeight));
background: white;
display: flex;
flex-flow: row wrap;
justify-content: space-evenly;
align-items: center;
font-size: 15px;
padding: 1vw 2vw;
border-radius: var(--borderRadius);
box-shadow: var(--boxShadow);
}
label {
flex-basis: 20%;
height: 15px;
}
input {
flex-basis: 70%;
height: 15px;
border: none;
}
hr {
--width: 90%;
flex-basis: var(--width);
margin: 0 calc((100% - var(--width)) / 2);
opacity: 0.5;
}

View File

@ -0,0 +1,19 @@
import React, { Component } from 'react';
import Header from '../Header.js';
import MainArea from '../MainArea.js';
class Tickets extends Component {
render() {
return (
<>
<Header title="Biljetter" />
<MainArea>
<p>Du har inga biljetter</p>
</MainArea>
</>
);
}
}
export default Tickets;

View File

@ -0,0 +1,30 @@
import React, { Component } from 'react';
import Header from '../Header.js';
import TopMenu from '../TopMenu.js';
import MenuButton from '../MenuButton.js';
import MainArea from '../MainArea.js';
import clockIcon from '../../img/clock.svg';
import calendarIcon from '../../img/calendar.svg';
import recurringIcon from '../../img/redo.svg';
class TicketsBuy extends Component {
render() {
return (
<>
<Header title="Köp biljett" />
<TopMenu>
<MenuButton label="Enkelbiljett" icon={clockIcon} />
<MenuButton label="Periodbiljett" icon={calendarIcon} />
<MenuButton label="Dygnsbiljett" icon={recurringIcon} />
</TopMenu>
<MainArea>
<p>Du har inga tidigare köp</p>
</MainArea>
</>
);
}
}
export default TicketsBuy;

View File

@ -0,0 +1,43 @@
import React, { Component } from "react";
import Header from "../Header.js";
import TopMenu from "../TopMenu.js";
import MainArea from "../MainArea.js";
import StopTitle from "../StopTitle.js";
import TrafficList from "../TrafficList.js";
import Stop from "../../classes/Stop.js";
import Departure from "../../classes/Departure.js";
class TrafficInfo extends Component {
render() {
let testStop = new Stop(
"Lemmingsgatan",
["Läge A", "Läge B", "Läge C"],
[
new Departure(
"519",
"Mot Heden",
"11:59",
"Trafikolycka vid Partille Centrum."
),
new Departure("58", "Mot Västra Eriksberg", "12:07"),
]
);
return (
<>
<Header title="Trafikinfo" />
<TopMenu>
<StopTitle stop={testStop} />
</TopMenu>
<MainArea>
<TrafficList departures={testStop.departures} />
</MainArea>
</>
);
}
}
export default TrafficInfo;

View File

@ -0,0 +1,25 @@
import React, { Component } from 'react';
import Header from '../Header.js';
import TopMenu from '../TopMenu.js';
import MainArea from '../MainArea.js';
import TripSelector from '../TripSelector.js';
import '../css/TripSelector.css';
class Travel extends Component {
render() {
return (
<>
<Header title="Reseplanering" />
<TopMenu>
<TripSelector />
</TopMenu>
<MainArea>
</MainArea>
</>
);
}
}
export default Travel;

BIN
src/fonts/roboto-light.ttf Normal file

Binary file not shown.

71
src/img/bus.svg Normal file
View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M53.333,234.667v-64C59.221,170.667,64,165.888,64,160s-4.779-10.667-10.667-10.667C23.915,149.333,0,173.269,0,202.667
V224c0,17.643,14.357,32,32,32h21.333C59.221,256,64,251.221,64,245.333S59.221,234.667,53.333,234.667z"/>
</g>
</g>
<g>
<g>
<path d="M458.667,149.333c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667v64
c-5.888,0-10.667,4.779-10.667,10.667S452.779,256,458.667,256H480c17.643,0,32-14.357,32-32v-21.333
C512,173.269,488.085,149.333,458.667,149.333z"/>
</g>
</g>
<g>
<g>
<path d="M181.333,448c-5.888,0-10.667,4.779-10.667,10.667h-64c0-5.888-4.779-10.667-10.667-10.667s-10.667,4.779-10.667,10.667
V480c0,17.643,14.357,32,32,32H160c17.643,0,32-14.357,32-32v-21.333C192,452.779,187.221,448,181.333,448z"/>
</g>
</g>
<g>
<g>
<path d="M416,448c-5.888,0-10.667,4.779-10.667,10.667h-64c0-5.888-4.779-10.667-10.667-10.667S320,452.779,320,458.667V480
c0,17.643,14.357,32,32,32h42.667c17.643,0,32-14.357,32-32v-21.333C426.667,452.779,421.888,448,416,448z"/>
</g>
</g>
<g>
<g>
<path d="M416,0H96C66.581,0,42.667,23.936,42.667,53.333V416c0,29.397,23.915,53.333,53.333,53.333h320
c29.419,0,53.333-23.936,53.333-53.333V53.333C469.333,23.936,445.419,0,416,0z M138.667,42.667h234.667c17.643,0,32,14.357,32,32
c0,17.643-14.357,32-32,32H138.667c-17.643,0-32-14.357-32-32C106.667,57.024,121.024,42.667,138.667,42.667z M138.667,405.333
c-17.643,0-32-14.357-32-32c0-17.643,14.357-32,32-32c17.643,0,32,14.357,32,32C170.667,390.976,156.309,405.333,138.667,405.333z
M373.333,405.333c-17.643,0-32-14.357-32-32c0-17.643,14.357-32,32-32c17.643,0,32,14.357,32,32
C405.333,390.976,390.976,405.333,373.333,405.333z M426.667,266.667c0,17.643-14.357,32-32,32H117.333c-17.643,0-32-14.357-32-32
V160c0-17.643,14.357-32,32-32h277.333c17.643,0,32,14.357,32,32V266.667z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

59
src/img/calendar.svg Normal file
View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<g>
<circle cx="386" cy="210" r="20"/>
<path d="M432,40h-26V20c0-11.046-8.954-20-20-20c-11.046,0-20,8.954-20,20v20h-91V20c0-11.046-8.954-20-20-20
c-11.046,0-20,8.954-20,20v20h-90V20c0-11.046-8.954-20-20-20s-20,8.954-20,20v20H80C35.888,40,0,75.888,0,120v312
c0,44.112,35.888,80,80,80h153c11.046,0,20-8.954,20-20c0-11.046-8.954-20-20-20H80c-22.056,0-40-17.944-40-40V120
c0-22.056,17.944-40,40-40h25v20c0,11.046,8.954,20,20,20s20-8.954,20-20V80h90v20c0,11.046,8.954,20,20,20s20-8.954,20-20V80h91
v20c0,11.046,8.954,20,20,20c11.046,0,20-8.954,20-20V80h26c22.056,0,40,17.944,40,40v114c0,11.046,8.954,20,20,20
c11.046,0,20-8.954,20-20V120C512,75.888,476.112,40,432,40z"/>
<path d="M391,270c-66.72,0-121,54.28-121,121s54.28,121,121,121s121-54.28,121-121S457.72,270,391,270z M391,472
c-44.663,0-81-36.336-81-81s36.337-81,81-81c44.663,0,81,36.336,81,81S435.663,472,391,472z"/>
<path d="M420,371h-9v-21c0-11.046-8.954-20-20-20c-11.046,0-20,8.954-20,20v41c0,11.046,8.954,20,20,20h29
c11.046,0,20-8.954,20-20C440,379.954,431.046,371,420,371z"/>
<circle cx="299" cy="210" r="20"/>
<circle cx="212" cy="297" r="20"/>
<circle cx="125" cy="210" r="20"/>
<circle cx="125" cy="297" r="20"/>
<circle cx="125" cy="384" r="20"/>
<circle cx="212" cy="384" r="20"/>
<circle cx="212" cy="210" r="20"/>
</g>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

1
src/img/clock.svg Normal file
View File

@ -0,0 +1 @@
<svg height="384pt" viewBox="0 0 384 384" width="384pt" xmlns="http://www.w3.org/2000/svg"><path d="m343.59375 101.039062c-7.953125 3.847657-11.28125 13.417969-7.433594 21.367188 10.511719 21.714844 15.839844 45.121094 15.839844 69.59375 0 88.222656-71.777344 160-160 160s-160-71.777344-160-160 71.777344-160 160-160c36.558594 0 70.902344 11.9375 99.328125 34.519531 6.894531 5.503907 16.976563 4.351563 22.480469-2.566406 5.503906-6.914063 4.351562-16.984375-2.570313-22.480469-33.652343-26.746094-76-41.472656-119.238281-41.472656-105.863281 0-192 86.136719-192 192s86.136719 192 192 192 192-86.136719 192-192c0-29.335938-6.40625-57.449219-19.039062-83.527344-3.839844-7.96875-13.441407-11.289062-21.367188-7.433594zm0 0"/><path d="m192 64c-8.832031 0-16 7.167969-16 16v112c0 8.832031 7.167969 16 16 16h80c8.832031 0 16-7.167969 16-16s-7.167969-16-16-16h-64v-96c0-8.832031-7.167969-16-16-16zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 906 B

44
src/img/flash.svg Normal file
View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M400.268,175.599c-1.399-3.004-4.412-4.932-7.731-4.932h-101.12l99.797-157.568c1.664-2.628,1.766-5.956,0.265-8.678
C389.977,1.69,387.109,0,384.003,0H247.47c-3.234,0-6.187,1.826-7.637,4.719l-128,256c-1.323,2.637-1.178,5.777,0.375,8.294
c1.562,2.517,4.301,4.053,7.262,4.053h87.748l-95.616,227.089c-1.63,3.883-0.179,8.388,3.413,10.59
c1.382,0.845,2.918,1.254,4.446,1.254c2.449,0,4.864-1.05,6.537-3.029l273.067-324.267
C401.206,182.161,401.667,178.611,400.268,175.599z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1005 B

23
src/img/menu.svg Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 341.3 341.3" style="enable-background:new 0 0 341.3 341.3;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<g>
<rect y="277.3" class="st0" width="341.3" height="42.7"/>
</g>
</g>
<g>
<g>
<rect y="149.3" class="st0" width="341.3" height="42.7"/>
</g>
</g>
<g>
<g>
<rect y="21.3" class="st0" width="341.3" height="42.7"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 656 B

1
src/img/redo.svg Normal file
View File

@ -0,0 +1 @@
<svg height="512pt" viewBox="0 0 512 512" width="512pt" xmlns="http://www.w3.org/2000/svg"><path d="m502.121094 1.214844c-5.972656-2.453125-12.863282-1.109375-17.429688 3.476562l-57.597656 57.601563c-47.488281-39.210938-108.417969-62.292969-171.09375-62.292969-141.164062 0-256 114.835938-256 256s114.835938 256 256 256c68.332031 0 132.609375-26.644531 180.96875-75.03125 8.34375-8.339844 8.34375-21.820312 0-30.164062-8.339844-8.339844-21.820312-8.339844-30.164062 0-40.296876 40.320312-93.867188 62.527343-150.804688 62.527343-117.632812 0-213.332031-95.699219-213.332031-213.332031s95.699219-213.332031 213.332031-213.332031c51.414062 0 101.332031 18.496093 140.777344 49.917969l-50.75 50.773437c-4.585938 4.585937-5.929688 11.457031-3.476563 17.429687 2.472657 5.972657 8.296875 9.878907 14.78125 9.878907h138.667969c8.832031 0 16-7.167969 16-16v-138.667969c0-6.484375-3.902344-12.308594-9.878906-14.785156zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 924 B

56
src/img/tickets+.svg Normal file
View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{clip-path:url(#SVGID_2_);}
.st1{display:none;}
.st2{display:inline;fill:#FF0000;}
</style>
<g id="Capa_1">
</g>
<g id="Layer_4">
<g>
<defs>
<polygon id="SVGID_1_" points="0,0 0,512 299,512 299,393.4 184.1,393.4 184.1,327.8 299,327.8 298.9,234.3 364.5,234.3
364.5,327.8 479.4,327.8 479.4,393.4 364.5,393.4 362.9,512 512,512 512,0 "/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
</clipPath>
<g class="st0">
<g>
<path d="M448.7,128.2l-10.6,10.6c-8.7,8.7-20.2,13.4-32.4,13.4s-23.8-4.8-32.4-13.4c-8.7-8.7-13.4-20.2-13.4-32.4
s4.8-23.8,13.4-32.4l10.6-10.6L320.5,0L0,320.5l63.3,63.3l10.6-10.6c8.7-8.7,20.2-13.4,32.4-13.4s23.8,4.8,32.4,13.4
c8.7,8.7,13.4,20.2,13.4,32.4s-4.8,23.8-13.4,32.4l-10.6,10.6l63.3,63.3L512,191.5L448.7,128.2z M169.6,447.6
c8.2-12.3,12.7-26.8,12.7-42c0-20.3-7.9-39.3-22.2-53.7c-14.3-14.3-33.4-22.2-53.7-22.2c-15.2,0-29.7,4.4-42,12.7l-21.9-21.9
l278-278l21.9,21.9c-8.2,12.3-12.7,26.8-12.7,42c0,20.3,7.9,39.3,22.2,53.7c14.3,14.3,33.4,22.2,53.7,22.2
c15.2,0,29.7-4.4,42-12.7l21.9,21.9l-278,278L169.6,447.6z"/>
</g>
</g>
<g class="st0">
<g>
<rect x="284" y="197.9" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -63.0406 273.8113)" width="30" height="30.1"/>
</g>
</g>
<g class="st0">
<g>
<rect x="241.4" y="155.3" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -45.3836 231.2101)" width="30" height="30.1"/>
</g>
</g>
<g class="st0">
<g>
<rect x="326.6" y="240.5" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -80.6853 316.4155)" width="30" height="30.1"/>
</g>
</g>
</g>
</g>
<g id="Layer_3" class="st1">
<polygon class="st2" points="298.9,234.3 364.5,234.3 364.5,327.8 479.4,327.8 479.4,393.4 364.5,393.4 364.5,486.9 298.9,486.9
299,393.4 184.1,393.4 184.1,327.8 299,327.8 "/>
</g>
<g id="Layer_2">
<rect x="312.4" y="273.8" transform="matrix(-1.836970e-16 1 -1 -1.836970e-16 692.3611 28.913)" width="38.6" height="173.7"/>
<rect x="312.4" y="273.8" transform="matrix(-1 -1.224647e-16 1.224647e-16 -1 663.4481 721.2742)" width="38.6" height="173.7"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

65
src/img/tickets.svg Normal file
View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M448.678,128.219l-10.607,10.608c-8.667,8.667-20.191,13.44-32.449,13.44c-12.258,0-23.78-4.773-32.448-13.44
c-8.667-8.667-13.44-20.191-13.44-32.448s4.773-23.781,13.44-32.449l10.608-10.608L320.459,0L0,320.459l63.322,63.322
l10.608-10.608c8.667-8.667,20.191-13.44,32.449-13.44c12.258,0,23.78,4.773,32.448,13.44c8.667,8.667,13.44,20.191,13.44,32.448
s-4.773,23.781-13.44,32.449l-10.608,10.608L191.541,512L512,191.541L448.678,128.219z M169.61,447.636
c8.237-12.343,12.662-26.839,12.662-42.015c0-20.272-7.894-39.33-22.229-53.664c-14.334-14.335-33.393-22.229-53.664-22.229
c-15.176,0-29.672,4.425-42.015,12.662l-21.932-21.931L320.459,42.432l21.931,21.932c-8.237,12.343-12.662,26.839-12.662,42.015
c0,20.272,7.894,39.33,22.229,53.664c14.334,14.335,33.393,22.229,53.664,22.229c15.176,0,29.672-4.425,42.015-12.662
l21.932,21.931L191.541,469.568L169.61,447.636z"/>
</g>
</g>
<g>
<g>
<rect x="284.001" y="197.94" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -63.0395 273.8137)" width="30.004" height="30.124"/>
</g>
</g>
<g>
<g>
<rect x="241.404" y="155.325" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -45.3819 231.2119)" width="30.004" height="30.124"/>
</g>
</g>
<g>
<g>
<rect x="326.607" y="240.541" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -80.684 316.4184)" width="30.004" height="30.124"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

2
src/img/traffic.svg Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><g><path d="M256,184a56,56,0,1,0,56,56A56.063,56.063,0,0,0,256,184Zm0,96a40,40,0,1,1,40-40A40.045,40.045,0,0,1,256,280Z"/><path d="M256,56a56,56,0,1,0,56,56A56.063,56.063,0,0,0,256,56Zm0,96a40,40,0,1,1,40-40A40.045,40.045,0,0,1,256,152Z"/><path d="M256,312a56,56,0,1,0,56,56A56.063,56.063,0,0,0,256,312Zm0,96a40,40,0,1,1,40-40A40.045,40.045,0,0,1,256,408Z"/><path d="M368,304a8,8,0,0,0,7.89-6.68l16-96A8.007,8.007,0,0,0,384,192H352V168h16a8,8,0,0,0,7.89-6.68l16-96A8.007,8.007,0,0,0,384,56H352V40a8,8,0,0,0-8-8H319.71A28.043,28.043,0,0,0,292,8H220a28.043,28.043,0,0,0-27.71,24H168a8,8,0,0,0-8,8V56H128a8.007,8.007,0,0,0-7.89,9.32l16,96A8,8,0,0,0,144,168h16v24H128a8.007,8.007,0,0,0-7.89,9.32l16,96A8,8,0,0,0,144,304h16v16H128a8.007,8.007,0,0,0-7.89,9.32l16,96A8,8,0,0,0,144,432h16v8a8,8,0,0,0,8,8h48v48a8,8,0,0,0,8,8h64a8,8,0,0,0,8-8V448h48a8,8,0,0,0,8-8v-8h16a8,8,0,0,0,7.89-6.68l16-96A8.007,8.007,0,0,0,384,320H352V304ZM352,72h22.56l-13.34,80H352Zm0,136h22.56l-13.34,80H352ZM160,416h-9.22l-13.34-80H160Zm0-128h-9.22l-13.34-80H160Zm0-136h-9.22L137.44,72H160ZM220,24h72a12.014,12.014,0,0,1,11.31,8H208.69A12.014,12.014,0,0,1,220,24Zm60,464H232V448h48Zm56-56H176V48H336Zm38.56-96-13.34,80H352V336Z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

8
src/img/tram.svg Normal file
View File

@ -0,0 +1,8 @@
<?xml version='1.0' encoding='iso-8859-1'?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 470 470" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 470 470">
<g>
<path d="m386.032,146.681h-9.045v-23.144c0-25.859-21.038-46.898-46.898-46.898h-70.411l26.433-61.639h25.056c4.143,0 7.5-3.358 7.5-7.5s-3.357-7.5-7.5-7.5h-29.929c-0.023,0-0.045,0-0.068,0h-90.215c-0.023,0-0.047,0-0.07,0h-29.929c-4.143,0-7.5,3.358-7.5,7.5s3.357,7.5 7.5,7.5h25.056l26.433,61.639h-72.533c-25.86,0-46.898,21.039-46.898,46.898v23.144h-9.045c-11.304,0-20.5,9.196-20.5,20.5v50.88c0,4.142 3.357,7.5 7.5,7.5s7.5-3.358 7.5-7.5v-50.88c0-3.033 2.468-5.5 5.5-5.5h9.045v240.819c0,4.142 3.357,7.5 7.5,7.5h41.893l-47.197,47.197c-2.145,2.145-2.786,5.371-1.625,8.173 1.16,2.803 3.896,4.63 6.929,4.63h268.975c3.033,0 5.769-1.827 6.929-4.63 1.161-2.803 0.52-6.028-1.625-8.173l-30-29.999c-0.003-0.002-17.199-17.198-17.199-17.198h41.893c4.143,0 7.5-3.358 7.5-7.5v-240.819h9.045c3.032,0 5.5,2.467 5.5,5.5v50.88c0,4.142 3.357,7.5 7.5,7.5s7.5-3.358 7.5-7.5v-50.88c0-11.304-9.196-20.5-20.5-20.5zm-183.7-131.681h67.459l-26.433,61.639h-14.593l-26.433-61.639zm-94.319,108.537c0-17.588 14.31-31.898 31.898-31.898h83.86c0.018,0 0.036,0.004 0.054,0.004 0.026,0 0.052-0.004 0.078-0.004h24.365c0.049,0 81.82,0 81.82,0 17.589,0 31.898,14.31 31.898,31.898v23.144h-253.973v-23.144zm79.487,178.247v-140.103h95v140.104h-95zm-68.881,153.215l15-15h202.761l15,15h-232.761zm202.761-30h-172.761l15-15h142.76l15.001,15zm40.607-30h-253.974v-233.319h64.487v140.104h-41.987c-4.143,0-7.5,3.358-7.5,7.5s3.357,7.5 7.5,7.5h208.975c4.143,0 7.5-3.358 7.5-7.5s-3.357-7.5-7.5-7.5h-41.988v-140.104h64.487v233.319z"/>
<path d="M290,126.66c4.143,0,7.5-3.358,7.5-7.5s-3.357-7.5-7.5-7.5H180c-4.143,0-7.5,3.358-7.5,7.5s3.357,7.5,7.5,7.5H290z"/>
<path d="m235,333.392c-12.406,0-22.5,10.093-22.5,22.5s10.094,22.5 22.5,22.5 22.5-10.093 22.5-22.5-10.094-22.5-22.5-22.5zm0,30c-4.136,0-7.5-3.364-7.5-7.5s3.364-7.5 7.5-7.5 7.5,3.364 7.5,7.5-3.364,7.5-7.5,7.5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

22
src/img/user.svg Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 460.8 460.8" style="enable-background:new 0 0 460.8 460.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<g>
<path class="st0" d="M230.4,0c-65.8,0-119.6,53.8-119.6,119.6s53.8,119.6,119.6,119.6s119.6-53.8,119.6-119.6S296.3,0,230.4,0z"/>
</g>
</g>
<g>
<g>
<path class="st0" d="M435.8,334.9c-3.1-7.8-7.3-15.2-12-21.9c-24-35.5-61.1-59-102.9-64.8c-5.2-0.5-11,0.5-15.2,3.7
c-21.9,16.2-48.1,24.6-75.2,24.6s-53.3-8.4-75.2-24.6c-4.2-3.1-9.9-4.7-15.2-3.7c-41.8,5.7-79.4,29.3-102.9,64.8
c-4.7,6.8-8.9,14.6-12,21.9c-1.6,3.1-1,6.8,0.5,9.9c4.2,7.3,9.4,14.6,14.1,20.9c7.3,9.9,15.2,18.8,24,27.2
c7.3,7.3,15.7,14.1,24,20.9c41.3,30.8,90.9,47,142.1,47s100.8-16.2,142.1-47c8.4-6.3,16.7-13.6,24-20.9c8.4-8.4,16.7-17.2,24-27.2
c5.2-6.8,9.9-13.6,14.1-20.9C436.8,341.7,437.3,338,435.8,334.9z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

15
src/img/warning.svg Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill:#ED556C;}
</style>
<g>
<g>
<path class="st0" d="M501.4,384L320.5,51.5c-29.1-48.9-99.9-49-129,0L10.6,384c-29.7,50,6.3,113.3,64.5,113.3h361.7
C495,497.2,531.1,434,501.4,384z M256,437.2c-16.5,0-30-13.5-30-30s13.5-30,30-30s30,13.5,30,30S272.5,437.2,256,437.2z
M286,317.2c0,16.5-13.5,30-30,30s-30-13.5-30-30v-150c0-16.5,13.5-30,30-30s30,13.5,30,30V317.2z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 765 B

View File

@ -3,6 +3,11 @@
src: url('fonts/roboto-regular.ttf') format('truetype'); /* Safari, Android, iOS */
}
@font-face {
font-family: 'Roboto Light';
src: url('fonts/roboto-light.ttf') format('truetype'); /* Safari, Android, iOS */
}
* {
margin: 0;
padding: 0;
@ -13,4 +18,18 @@
html, body, #root, #app {
width: 100%;
height: 100%;
}
#root {
overflow: hidden;
}
button {
background: none;
border: none;
}
.hidden {
opacity: 0;
pointer-events: none;
}

View File

@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

11
src/variables.css Normal file
View File

@ -0,0 +1,11 @@
:root {
--colorVT1: rgb(1, 170, 235);
--colorVT2: rgb(25, 212, 245);
--colorBg: rgb(240, 248, 250);
--colorLine: rgb(0, 108, 144);
--colorDiscrete: rgba(0, 0, 0, 0.4);
--topMenuHeight: 15vh;
--borderRadius: calc(var(--topMenuHeight) / 15);
--boxShadow: 0px 1px 5px -1px rgba(0, 0, 0, 0.3);
}