Compare commits

..

100 Commits

Author SHA1 Message Date
André Wahlberg
0d26321055 Update style for snackbar notification 2020-12-15 10:53:19 +01:00
André Wahlberg
c294b60b5a Minor layout adjustments 2020-12-11 19:14:01 +01:00
André Wahlberg
13bf20c2ea Hide snackbar option to view traffic info if already on that page 2020-12-11 19:05:30 +01:00
André Wahlberg
30bcbd0286 Add 'Show less' in detailed traffic info paragraph 2020-12-11 18:23:51 +01:00
André Wahlberg
6fc5fd8ea4 Add snackbar notification for disruptions 2020-12-11 18:19:55 +01:00
André Wahlberg
b07708f3e9 Add border to button for alternative routes 2020-12-11 17:00:36 +01:00
André Wahlberg
84fa5e0597 Change usernames to stop names 2020-12-11 17:00:02 +01:00
williameriksson126
c0a64784ac Change: Disruption json file values 2020-12-11 11:38:42 +01:00
André Wahlberg
98db97627b Layout fixes 2020-12-11 11:01:43 +01:00
William Eriksson
b56e334d00
Merge pull request #14 from thefeli73/we-new-users
Add: new locations
2020-12-11 10:08:31 +01:00
William Eriksson
c1fe945a41
Merge branch 'main' into we-new-users 2020-12-11 10:08:22 +01:00
williameriksson126
919fd4b438 Add: new locations 2020-12-11 10:06:24 +01:00
André Wahlberg
be292c8aa3 Change of track and fix minor design flaws 2020-12-10 13:55:34 +01:00
williameriksson126
f7cbe39b0d Merge conflicts and small fixes 2020-12-10 13:21:09 +01:00
williameriksson126
078393335a Add: Update user disruption status when user is not selected 2020-12-10 13:19:07 +01:00
André Wahlberg
5cafe99946 Present correct information about track in traffic info 2020-12-10 12:48:36 +01:00
André Wahlberg
28d549de28 Minor design and typo fixes 2020-12-10 12:47:20 +01:00
williameriksson126
cd2a61947f Add: DateTime handling when displaying delay 2020-12-10 12:32:40 +01:00
williameriksson126
cf977ccb1f Almost done, final touches needed 2020-12-10 11:47:46 +01:00
André Wahlberg
1b3f5abd25 Fix nonexisting info being displayed oddly 2020-12-10 11:17:10 +01:00
André Wahlberg
9e185ef941 Fix wrong function name 2020-12-10 11:16:18 +01:00
williameriksson126
031829d4f9 Add: Traffic info now shows disruption data as well. Format of new time needs to be rewritten 2020-12-10 11:15:17 +01:00
williameriksson126
2b8c08e082 Change: departureuser4 to work correctly and updated UI for disruptions 2020-12-10 11:01:43 +01:00
William Eriksson
19282607ba
Merge pull request #13 from thefeli73/we-out-of-creativity-for-names
Add: Progress
2020-12-10 10:46:10 +01:00
William Eriksson
308bd7b99f
Merge branch 'main' into we-out-of-creativity-for-names 2020-12-10 10:45:54 +01:00
André Wahlberg
8e21856eb2 Update page when changing user 2020-12-10 10:43:43 +01:00
williameriksson126
df3e181e2e Add: Progress 2020-12-10 10:43:43 +01:00
André Wahlberg
211257ac67 Fix traffic info crash 2020-12-10 10:24:02 +01:00
William Eriksson
3b6aed2e41
Merge pull request #12 from thefeli73/we-departureboard-example
Add: json files for departure board for all users
2020-12-10 10:15:45 +01:00
williameriksson126
2c5567cb62 Add: json files for departure board for all users 2020-12-10 10:15:00 +01:00
William Eriksson
6d6356d576
Merge pull request #11 from thefeli73/we-location-select
Add: More progress regarding findstops button
2020-12-10 09:57:02 +01:00
williameriksson126
5c59866dc4 Add: More progress regarding findstops button 2020-12-10 09:56:24 +01:00
William Eriksson
9ccd2f01c0
Merge pull request #10 from thefeli73/we-location-select
Add: Json files for nearby busstops and a component for accessing sai…
2020-12-09 17:55:12 +01:00
williameriksson126
d304b250a2 Add: Json files for nearby busstops and a component for accessing said json files 2020-12-09 17:54:28 +01:00
André Wahlberg
68b6e4e836 Polish and button functionality for traffic info page 2020-12-08 12:28:33 +01:00
André Wahlberg
3accd7806a Add help message for button errors 2020-12-08 12:28:32 +01:00
William Eriksson
b207b464bd
Merge pull request #9 from thefeli73/we-select-user
Add: Multiple disruptions
2020-12-08 12:10:51 +01:00
williameriksson126
2d2ec96533 Add: Multiple disruptions 2020-12-08 12:10:08 +01:00
William Eriksson
359c0a8192
Merge pull request #8 from thefeli73/we-select-user
Add: Select user buttons
2020-12-08 11:55:46 +01:00
williameriksson126
3c0fc6fe1f Add: Select user buttons 2020-12-08 11:54:34 +01:00
William Eriksson
c7517f185c
Merge pull request #7 from thefeli73/we-fix-broken-git
We fix broken git
2020-12-08 10:43:20 +01:00
williameriksson126
d39f114d5c Fix 2of2 2020-12-08 10:42:50 +01:00
williameriksson126
a0ff50ab23 Fix 1of2 2020-12-08 10:41:31 +01:00
William Eriksson
ca1ca3884d
Merge pull request #6 from thefeli73/we-demo-disruption-first
Add: code to fetch disruption data and see if it is relevant
2020-12-08 10:30:41 +01:00
williameriksson126
ea2a18f3ad Add: code to fetch disruption data and see if it is relevant 2020-12-08 10:29:03 +01:00
William Eriksson
75b4ecc4ed
Merge pull request #5 from thefeli73/we-json-examples
Add: json files for scenarios
2020-12-08 09:38:22 +01:00
William Eriksson
3080359dcd
Merge branch 'main' into we-json-examples 2020-12-08 09:38:11 +01:00
williameriksson126
3d7e6cf52f Add: json files for scenarios 2020-12-08 09:36:19 +01:00
William Eriksson
34f4b8af18
Merge pull request #4 from thefeli73/we-Disruption-base
We disruption base
2020-12-08 09:18:21 +01:00
William Eriksson
7c59fa2825
Merge branch 'main' into we-Disruption-base 2020-12-08 09:18:00 +01:00
williameriksson126
31263e919e Minor modifications to Example API components and base classes 2020-12-08 09:13:38 +01:00
André Wahlberg
d40420ad2b Remove irrelevant button errors in console 2020-12-04 12:02:45 +01:00
André Wahlberg
4ce76dbe90 Merge branch 'aw-disruption-control' into main 2020-12-04 11:53:37 +01:00
André Wahlberg
051afedcc5 Add user name to navigation drawer 2020-12-04 11:52:41 +01:00
André Wahlberg
bff5a73c8c Merge branch 'main' into aw-disruption-control 2020-12-04 11:49:28 +01:00
André Wahlberg
093199d0e0 Add global data variable 2020-12-04 11:48:56 +01:00
André Wahlberg
25d66f9195 Updated class changes in TrafficEntry 2020-12-04 11:47:42 +01:00
André Wahlberg
4e36270130 Format TrafficInfo.js 2020-12-04 11:13:55 +01:00
williameriksson126
c36d6afea7 Merge to work on aw branch 2020-12-04 10:51:09 +01:00
williameriksson126
ff8a87c961 Hack: Nothing is done just commiting to swap branch 2020-12-04 10:45:22 +01:00
williameriksson126
c3edd2d74f Add basic component for calls to traffic disruption API 2020-12-04 10:08:11 +01:00
André Wahlberg
b324250c79 Merge remote-tracking branch 'origin/aw-client-side-classes' into aw-disruption-control 2020-12-04 09:59:51 +01:00
William Eriksson
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
williameriksson126
521d3b2e63 Add: AccessToken now updated to seperate class 2020-11-30 10:18:18 +01:00
André Wahlberg
3bc1ff9a1a Add and update classes for client-side data management 2020-11-27 17:32:35 +01:00
André Wahlberg
177bbdf89d Add possibility of closing popups 2020-11-27 17:25:29 +01:00
André Wahlberg
a1b078f418 Add misc CSS 2020-11-27 17:23:25 +01:00
André Wahlberg
66dbc66ec4 Add generalized button class 2020-11-27 17:06:14 +01:00
André Wahlberg
f86b9ee220 Add popup class 2020-11-27 17:04:19 +01:00
André Wahlberg
daaa9a62f4 Add navigation drawer content and make it expandable 2020-11-27 16:17:56 +01:00
André Wahlberg
38a6f7c786 Add new color 2020-11-27 16:16:28 +01:00
André Wahlberg
24dd1361f6 Fix traffic info entries overlapping stop title 2020-11-27 16:16:01 +01:00
André Wahlberg
e8cfc33991 Add word-break to bottom menu button labels 2020-11-27 16:15:27 +01:00
André Wahlberg
a1158d4525 Move and rename Disruption 2020-11-27 14:00:05 +01:00
André Wahlberg
1067277cb8 Allow scroll for entries on traffic info page 2020-11-27 13:58:01 +01:00
André Wahlberg
a3810491e9 Remove default logo 2020-11-27 13:45:27 +01:00
André Wahlberg
b8322417a0 Fix some React errors and warnings 2020-11-27 13:43:33 +01:00
Daniel Nguyen
fc29d7d327 Non-existing button 2020-11-27 11:41:20 +01:00
William Eriksson
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
William Eriksson
bd3e0fb582
Merge branch 'main' into we-VT-API-Access-Token-tests 2020-11-27 09:43:36 +01:00
williameriksson126
12b43e3d61 Add Access Token class as template for generating future tokens 2020-11-27 09:27:54 +01:00
André Wahlberg
771b5a5509 Add content to Traffic Info page 2020-11-26 21:42:30 +01:00
André Wahlberg
7cde8a62ba Add Stop and Departure classes 2020-11-26 21:41:57 +01:00
André Wahlberg
9c21062fdc Add color for transport line 2020-11-26 20:40:48 +01:00
André Wahlberg
f4ee176f67 Prevent side scrolling 2020-11-26 20:07:38 +01:00
André Wahlberg
025061693c Remove unnecessary parameters 2020-11-26 19:43:10 +01:00
André Wahlberg
0a99562d83 Add TopMenu component and page specific content 2020-11-26 19:37:44 +01:00
williameriksson126
51e91981e6 Add NearbyStation class is a form that given latitude and longitude coordinates gives nearby locations 2020-11-24 11:54:59 +01:00
André Wahlberg
83cdfb3959 Add traffic info button 2020-11-24 09:47:09 +01:00
williameriksson126
3a1d06f53a Add Test file for trying to access the API, Not successful 2020-11-23 16:22:13 +01:00
André Wahlberg
9a8c9756a2 Remove unnecessary constructor 2020-11-20 18:01:36 +01:00
André Wahlberg
3d76447d72 Merge branch 'aw-uiBase' into main 2020-11-20 18:00:34 +01:00
André Wahlberg
a7e177905e Add client-side routing 2020-11-20 17:56:18 +01:00
André Wahlberg
ae8ef6fc57 Rename PageArea to MainArea 2020-11-20 17:55:22 +01:00
André Wahlberg
5f12f1ad5a Add react-router-dom 2020-11-20 17:55:22 +01:00
André Wahlberg
4bcd512374 Add basic VT UI design 2020-11-20 17:55:22 +01:00
André Wahlberg
f95d78721f Add Roboto Light font 2020-11-20 17:55:22 +01:00
André Wahlberg
cd467370b9 Add CSS color variables 2020-11-20 17:55:21 +01:00
André Wahlberg
899086352d Update app settings and parameters 2020-11-20 17:55:12 +01:00
William Eriksson
43ecf76337
Merge pull request #1 from williameriksson126/we-basicButtonClass
Add basic button class
2020-11-20 11:54:59 +01:00
88 changed files with 2824 additions and 118 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. * ``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``. * Ursprungspunkten för React är ``src/index.js``.
<!--
## Upplägg ## Upplägg
``` mermaid ```mermaid
classDiagram classDiagram
class User
User : String deviceId
User : Coordinates location
User : nearbyStops()
class User class Coordinates
User : Subscription[] subs Coordinates : Float lon
User : Location loc Coordinates : Float lat
class Line class Stop
Stop : String name
Stop : Track[] locations
Stop : Departure[] departures
class Subscription class Departure
Subscription : Line line 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
``` ```
-->

157
package-lock.json generated
View File

@ -3030,6 +3030,14 @@
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.0.2.tgz", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.0.2.tgz",
"integrity": "sha512-arU1h31OGFu+LPrOLGZ7nB45v940NMDMEJeNmbutu57P+UFDVnkZg3e+J1I2HJRZ9hT7gO8J91dn/PMrAiKakA==" "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": { "axobject-query": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@ -3438,6 +3446,15 @@
"integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
"optional": true "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": { "bluebird": {
"version": "3.7.2", "version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "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": { "filesize": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz", "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", "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
"integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" "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": { "hmac-drbg": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
@ -6979,6 +7015,14 @@
"minimalistic-crypto-utils": "^1.0.1" "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": { "hoopy": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", "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", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" "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": { "mini-css-extract-plugin": {
"version": "0.11.3", "version": "0.11.3",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.3.tgz", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.3.tgz",
@ -10058,6 +10111,11 @@
"minimist": "^1.2.5" "minimist": "^1.2.5"
} }
}, },
"moment": {
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
},
"move-concurrently": { "move-concurrently": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@ -10095,6 +10153,12 @@
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" "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": { "nanoid": {
"version": "3.1.16", "version": "3.1.16",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.16.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.16.tgz",
@ -12217,6 +12281,11 @@
"whatwg-fetch": "^3.4.1" "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": { "react-dev-utils": {
"version": "11.0.0", "version": "11.0.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.0.tgz", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.0.tgz",
@ -12322,11 +12391,67 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" "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": { "react-refresh": {
"version": "0.8.3", "version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==" "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": { "react-scripts": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.0.tgz", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.0.tgz",
@ -12782,6 +12907,11 @@
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" "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": { "resolve-url": {
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
@ -14518,6 +14648,16 @@
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" "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": { "tmp": {
"version": "0.0.33", "version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@ -14976,6 +15116,11 @@
"spdx-expression-parse": "^3.0.0" "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": { "vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@ -15148,7 +15293,11 @@
"version": "1.2.13", "version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"optional": true "optional": true,
"requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
}
}, },
"glob-parent": { "glob-parent": {
"version": "3.1.0", "version": "3.1.0",
@ -15734,7 +15883,11 @@
"version": "1.2.13", "version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"optional": true "optional": true,
"requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
}
}, },
"glob-parent": { "glob-parent": {
"version": "3.1.0", "version": "3.1.0",

View File

@ -6,8 +6,14 @@
"@testing-library/jest-dom": "^5.11.6", "@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.1.2", "@testing-library/react": "^11.1.2",
"@testing-library/user-event": "^12.2.2", "@testing-library/user-event": "^12.2.2",
"axios": "^0.21.0",
"moment": "^2.29.1",
"react": "^17.0.1", "react": "^17.0.1",
"react-axios": "^2.0.3",
"react-dom": "^17.0.1", "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", "react-scripts": "4.0.0",
"web-vitals": "^0.2.4" "web-vitals": "^0.2.4"
}, },

View File

@ -3,17 +3,13 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#01aaeb" />
<meta name="theme-color" content="#000000" /> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta <meta name="description" content="Störningar i kollektivtrafiken" />
name="description" <meta name='viewport' content='minimal-ui, width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=0' >
content="Web site created using create-react-app" <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%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.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/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
@ -29,15 +25,5 @@
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <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> </body>
</html> </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,6 +1,6 @@
{ {
"short_name": "React App", "short_name": "Västtrafik",
"name": "Create React App Sample", "name": "Störningar i kollektivtrafiken",
"icons": [ "icons": [
{ {
"src": "favicon.ico", "src": "favicon.ico",
@ -8,18 +8,13 @@
"type": "image/x-icon" "type": "image/x-icon"
}, },
{ {
"src": "logo192.png", "src": "logo.png",
"type": "image/png", "type": "image/png",
"sizes": "192x192" "sizes": "135x135"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
} }
], ],
"start_url": ".", "start_url": ".",
"display": "standalone", "display": "fullscreen",
"theme_color": "#000000", "theme_color": "#01aaeb",
"background_color": "#ffffff" "background_color": "#f0f8fa"
} }

View File

@ -0,0 +1,53 @@
{
"DepartureBoard": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestDepartureBoard.xsd",
"servertime": "09:38",
"serverdate": "2020-12-11",
"Departures": [
{
"name": "Buss MEXP",
"sname": "MEXP",
"journeyNumber": "22",
"type": "BUS",
"stopid": "9022014014751002",
"stop": "Guddeby",
"time": "09:40",
"date": "2020-12-11",
"journeyid": "9015014621000022",
"direction": "Marstrand",
"track": "B",
"rtTime": "09:44",
"rtDate": "2020-12-11",
"fgColor": "#006C93",
"bgColor": "#FFFFFF",
"stroke": "Solid",
"accessibility": "wheelChair",
"JourneyDetailRef": {
"ref": "https://api.vasttrafik.se/bin/rest.exe/v2/journeyDetail?ref=715722%2F247121%2F629948%2F76401%2F80%3Fdate%3D2020-12-11%26station_evaId%3D14751002%26station_type%3Ddep%26format%3Djson%26"
}
},
{
"name": "Buss 927",
"sname": "927",
"journeyNumber": "2",
"type": "BUS",
"stopid": "9022014014751002",
"stop": "Guddeby",
"time": "12:29",
"date": "2020-12-11",
"journeyid": "9015014692700002",
"direction": "Tjuvkil",
"track": "B",
"rtTime": "12:30",
"rtDate": "2020-12-11",
"fgColor": "#006C93",
"bgColor": "#FFFFFF",
"stroke": "Solid",
"accessibility": "wheelChair",
"JourneyDetailRef": {
"ref": "https://api.vasttrafik.se/bin/rest.exe/v2/journeyDetail?ref=286581%2F125303%2F109682%2F40686%2F80%3Fdate%3D2020-12-11%26station_evaId%3D14751002%26station_type%3Ddep%26format%3Djson%26"
}
}
]
}
}

View File

@ -0,0 +1,53 @@
{
"DepartureBoard": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestDepartureBoard.xsd",
"servertime": "09:41",
"serverdate": "2020-12-11",
"Departures": [
{
"name": "Buss MEXP",
"sname": "MEXP",
"journeyNumber": "22",
"type": "BUS",
"stopid": "9022014014010002",
"stop": "Hålta kyrka",
"time": "09:47",
"date": "2020-12-11",
"journeyid": "9015014621000022",
"direction": "Marstrand",
"track": "B",
"rtTime": "09:50",
"rtDate": "2020-12-11",
"fgColor": "#006C93",
"bgColor": "#FFFFFF",
"stroke": "Solid",
"accessibility": "wheelChair",
"JourneyDetailRef": {
"ref": "https://api.vasttrafik.se/bin/rest.exe/v2/journeyDetail?ref=514476%2F180039%2F54148%2F144419%2F80%3Fdate%3D2020-12-11%26station_evaId%3D14010002%26station_type%3Ddep%26format%3Djson%26"
}
},
{
"name": "Buss 927",
"sname": "927",
"journeyNumber": "2",
"type": "BUS",
"stopid": "9022014014010002",
"stop": "Hålta kyrka",
"time": "12:38",
"date": "2020-12-11",
"journeyid": "9015014692700002",
"direction": "Tjuvkil",
"track": "B",
"rtTime": "12:38",
"rtDate": "2020-12-11",
"fgColor": "#006C93",
"bgColor": "#FFFFFF",
"stroke": "Solid",
"accessibility": "wheelChair",
"JourneyDetailRef": {
"ref": "https://api.vasttrafik.se/bin/rest.exe/v2/journeyDetail?ref=667647%2F252325%2F917844%2F236373%2F80%3Fdate%3D2020-12-11%26station_evaId%3D14010002%26station_type%3Ddep%26format%3Djson%26"
}
}
]
}
}

View File

@ -0,0 +1,53 @@
{
"DepartureBoard": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestDepartureBoard.xsd",
"servertime": "09:44",
"serverdate": "2020-12-11",
"Departures": [
{
"name": "Buss MEXP",
"sname": "MEXP",
"journeyNumber": "22",
"type": "BUS",
"stopid": "9022014014614002",
"stop": "Stenskärsvägen",
"time": "09:52",
"date": "2020-12-11",
"journeyid": "9015014621000022",
"direction": "Marstrand",
"track": "B",
"rtTime": "09:57",
"rtDate": "2020-12-11",
"fgColor": "#006C93",
"bgColor": "#FFFFFF",
"stroke": "Solid",
"accessibility": "wheelChair",
"JourneyDetailRef": {
"ref": "https://api.vasttrafik.se/bin/rest.exe/v2/journeyDetail?ref=341064%2F122235%2F154456%2F36461%2F80%3Fdate%3D2020-12-11%26station_evaId%3D14614002%26station_type%3Ddep%26format%3Djson%26"
}
},
{
"name": "Buss 320",
"sname": "320",
"journeyNumber": "10",
"type": "BUS",
"stopid": "9022014014614002",
"stop": "Stenskärsvägen",
"time": "10:44",
"date": "2020-12-11",
"journeyid": "9015014632000010",
"direction": "Tjuvkil",
"track": "B",
"rtTime": "10:44",
"rtDate": "2020-12-11",
"fgColor": "#006C93",
"bgColor": "#FFFFFF",
"stroke": "Solid",
"accessibility": "wheelChair",
"JourneyDetailRef": {
"ref": "https://api.vasttrafik.se/bin/rest.exe/v2/journeyDetail?ref=931884%2F318653%2F795430%2F87087%2F80%3Fdate%3D2020-12-11%26station_evaId%3D14614002%26station_type%3Ddep%26format%3Djson%26"
}
}
]
}
}

View File

@ -0,0 +1,29 @@
{
"DepartureBoard": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestDepartureBoard.xsd",
"servertime": "09:45",
"serverdate": "2020-12-11",
"Departures": [{
"name": "Buss 928",
"sname": "928",
"journeyNumber": "10",
"type": "BUS",
"stopid": "9022014014225001",
"stop": "Skrämmenborg",
"time": "15:19",
"date": "2020-12-11",
"journeyid": "9015014692800010",
"direction": "Kärna",
"track": "A",
"rtTime": "15:19",
"rtDate": "2020-12-11",
"fgColor": "#006C93",
"bgColor": "#FFFFFF",
"stroke": "Solid",
"accessibility": "wheelChair",
"JourneyDetailRef": {
"ref": "https://api.vasttrafik.se/bin/rest.exe/v2/journeyDetail?ref=110424%2F37130%2F997492%2F461938%2F80%3Fdate%3D2020-12-11%26station_evaId%3D14225001%26station_type%3Ddep%26format%3Djson%26"
}
}]
}
}

View File

@ -0,0 +1,12 @@
{
"situationNumber": "RT1",
"severity":"normal",
"title":"Nabbensbergsvägen närmast Edsvägen helt avstängd och trafiken hänvisas istället via Korsebergsvägen. Samtidigt tas den tillfälliga förbifarten bort på Edsvägen och trafiken kommer att ledas förbi den nya cirkulationsplatsen i de två västra körfälten tills arbetet på Nabbensbergsvägen är klart Hastighet: 50km/h",
"time":"00:07",
"affectedStopPoints":[
{
"gid": "9022014014614001",
"name": "Stenskärsvägen"
}
]
}

View File

@ -0,0 +1,20 @@
{
"situationNumber": "RT2",
"severity":"normal",
"title":"På grund av renovation av Nordreälvsbron i Kungälv från 10 november, 2019 till sommaren 2022 är det risk för förseningar på vissa Västtrafik bussar.",
"time":"00:09",
"affectedStopPoints":[
{
"gid": "9022014014751001",
"name": "Guddeby"
},
{
"gid": "9022014014010001",
"name": "Hålta kyrka"
},
{
"gid": "9022014014614001",
"name": "Stenskärsvägen"
}
]
}

View File

@ -0,0 +1,36 @@
{
"LocationList": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestLocation.xsd",
"servertime": "09:34",
"serverdate": "2020-12-11",
"StopLocation": [
{
"name": "Guddeby",
"id": "9022014014751001",
"lat": "57.874665",
"lon": "11.903884",
"track": "A"
},
{
"name": "Guddeby",
"id": "9021014014751000",
"lat": "57.874710",
"lon": "11.903929"
},
{
"name": "Guddeby",
"id": "9022014014751002",
"lat": "57.874746",
"lon": "11.903965",
"track": "B"
},
{
"name": "Stället",
"id": "9022014014744001",
"lat": "57.869784",
"lon": "11.904172",
"track": "A"
}
]
}
}

View File

@ -0,0 +1,36 @@
{
"LocationList": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestLocation.xsd",
"servertime": "09:35",
"serverdate": "2020-12-11",
"StopLocation": [
{
"name": "Hålta kyrka",
"id": "9022014014010001",
"lat": "57.895125",
"lon": "11.827854",
"track": "A"
},
{
"name": "Hålta kyrka",
"id": "9021014014010000",
"lat": "57.895206",
"lon": "11.827647"
},
{
"name": "Hålta kyrka",
"id": "9022014014010002",
"lat": "57.895278",
"lon": "11.827440",
"track": "B"
},
{
"name": "Hålta skola",
"id": "9022014014015001",
"lat": "57.896015",
"lon": "11.824555",
"track": "A"
}
]
}
}

View File

@ -0,0 +1,36 @@
{
"LocationList": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestLocation.xsd",
"servertime": "09:36",
"serverdate": "2020-12-11",
"StopLocation": [
{
"name": "Stenskärsvägen",
"id": "9022014014614001",
"lat": "57.894594",
"lon": "11.740128",
"track": "A"
},
{
"name": "Stenskärsvägen",
"id": "9022014014614002",
"lat": "57.894729",
"lon": "11.739984",
"track": "B"
},
{
"name": "Stenskärsvägen",
"id": "9021014014614000",
"lat": "57.894738",
"lon": "11.739858"
},
{
"name": "Tjuvkilsboden",
"id": "9022014014615002",
"lat": "57.892743",
"lon": "11.743490",
"track": "B"
}
]
}
}

View File

@ -0,0 +1,35 @@
{
"LocationList": {
"noNamespaceSchemaLocation": "http://api.vasttrafik.se/v1/hafasRestLocation.xsd",
"servertime": "09:37",
"serverdate": "2020-12-11",
"StopLocation": [
{
"name": "Kuröd",
"id": "9022014014762001",
"lat": "57.856687",
"lon": "11.864727",
"track": "A"
},
{
"name": "Kuröd",
"id": "9021014014762000",
"lat": "57.856831",
"lon": "11.864260"
},
{
"name": "Kuröd",
"id": "9022014014762002",
"lat": "57.856966",
"lon": "11.863774",
"track": "B"
},
{
"name": "Skrämmenborg",
"id": "9021014014225000",
"lat": "57.863528",
"lon": "11.867406"
}
]
}
}

View File

@ -0,0 +1,5 @@
{
"name": "Användare 1",
"deviceId": "1",
"stoppointgid": "9022014014751001"
}

View File

@ -0,0 +1,5 @@
{
"name": "Användare 2",
"deviceId": "2",
"stoppointgid": "9022014014010001"
}

View File

@ -0,0 +1,5 @@
{
"name": "Användare 3",
"deviceId": "3",
"stoppointgid": "9022014014614001"
}

View File

@ -0,0 +1,5 @@
{
"name": "Användare 4",
"deviceId": "4",
"stoppointgid": "9022014014762001"
}

View File

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

View File

@ -1,25 +1,73 @@
import './App.css'; import "./variables.css";
import React, { Component } from 'react'; import "./App.css";
import NavigationDrawer from './components/NavigationDrawer.js'
import Header from './components/Header.js' import React, { Component } from "react";
import PageArea from './components/PageArea.js' import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import BottomMenu from './components/BottomMenu.js' import Snackbar from "@material-ui/core/Snackbar";
import IconButton from "@material-ui/core/IconButton";
import globalData from './GlobalData.js';
import BottomMenu from "./components/BottomMenu.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";
import warningIcon from './img/warning.svg';
import closeIcon from './img/close.svg';
class App extends Component { class App extends Component {
currentPageName = () => {
if (globalData.currentPage.constructor !== undefined)
return globalData.currentPage.constructor.name;
else
return "";
};
render() { render() {
globalData.root = this;
return ( return (
<Router>
<div className="App"> <div className="App">
{/* <Route path="/" exact component={TicketsBuy} />
<Button <Route path="/tickets" exact component={Tickets} />
title = "placeholderTitle" <Route path="/ticketsBuy" exact component={TicketsBuy} />
destination = "placeholderDestination" <Route path="/travel" exact component={Travel} />
/> <Route path="/traffic" exact component={TrafficInfo} />
*/}
<NavigationDrawer />
<Header />
<PageArea />
<BottomMenu /> <BottomMenu />
<Snackbar
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
open={globalData.snackbarVisible}
autoHideDuration={3000}
onClose={() => globalData.snackbarVisible = false}
message={
<div id="snackDisruptInfo">
<img src={warningIcon} alt="" />
<span id="message-id">Trafikstörning upptäckt</span>
</div> </div>
}
action={[
<IconButton
key="close"
aria-label="Close"
color="inherit"
onClick={() => { globalData.snackbarVisible = false; globalData.root.forceUpdate() }}
>
{this.currentPageName() !== "TrafficInfo" &&
<Link to="/traffic">Visa trafikinfo</Link>
}
<img src={closeIcon} alt="" />
</IconButton>,
]}
/>
</div>
</Router>
); );
} }
} }

21
src/GlobalData.js Normal file
View File

@ -0,0 +1,21 @@
import User from './classes/User.js';
import Disruption from './classes/Disruption.js'
import Coordinates from './classes/Coordinates.js';
import Stop from './classes/Stop.js'
let globalData = {
users : [],
user: new User(
"Exempelanvändare",
"123",
new Coordinates(),
"123"
),
disruption: new Disruption(
),
stop: new Stop(
),
currentPage: ""
};
export default globalData;

View File

@ -0,0 +1,20 @@
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 => {
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;

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

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

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;

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

@ -0,0 +1,31 @@
/*
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, id, lat, lon, locations, departures) {
this.name = name;
this.id = id;
this.lat = lat;
this.lon = lon;
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;

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

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

View File

@ -1,13 +1,33 @@
import './css/BottomMenu.css';
import React, { Component } from 'react'; 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 { class BottomMenu extends Component {
render() { render() {
return ( return (
<div id="bottomMenu"> <div id="bottomMenu">
<button>Biljetter</button> <Link to="/tickets">
<button>Köp biljett</button> <MenuButton label="Biljetter" icon={ticketsIcon}/>
<button>Reseplanering</button> </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> </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 { 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. Make sure the functions are passed as an array.");
}
}
}
render() {
return ( return (
<a href={this.props.destination}> <button className={this.props.className} onClick={this.onClick}>
{this.props.title} {this.props.children}
</a> </button>
); );
} }
} }
// TODO Add css
export default Button export default Button;

View File

@ -0,0 +1,57 @@
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
};
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 => {
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,127 @@
import moment from "moment";
import globalData from '../GlobalData.js';
import Button from './Button.js';
import user1 from '../APIexamples/user1.json'
import user2 from '../APIexamples/user2.json'
import user3 from '../APIexamples/user3.json'
import user4 from '../APIexamples/user4.json'
import locationuser1 from '../APIexamples/locationuser1.json'
import locationuser2 from '../APIexamples/locationuser2.json'
import locationuser3 from '../APIexamples/locationuser3.json'
import locationuser4 from '../APIexamples/locationuser4.json'
import departureuser1 from '../APIexamples/departureuser1.json'
import departureuser2 from '../APIexamples/departureuser2.json'
import departureuser3 from '../APIexamples/departureuser3.json'
import departureuser4 from '../APIexamples/departureuser4.json'
import ex1 from '../APIexamples/disruption1.json'
import ex2 from '../APIexamples/disruption2.json'
class DisruptionButton extends Button {
constructor(props) {
super(props);
this.state = {
jsonLocation: this.props.path,
disruption: "",
u1: user1,
u2: user2,
u3: user3,
u4: user4,
};
}
updatePage = () => {
globalData.currentPage.forceUpdate();
}
showMomentTime = (time) => {
return (time.format("HH:mm"))
}
genUsers = () => {
if (globalData.users.length < 2) {
this.state.first = true;
this.state.u1.stop = locationuser1.LocationList.StopLocation[0];
this.state.u1.stop.departures = departureuser1.DepartureBoard.Departures;
this.state.u2.stop = locationuser2.LocationList.StopLocation[0];
this.state.u2.stop.departures = departureuser2.DepartureBoard.Departures;
this.state.u3.stop = locationuser3.LocationList.StopLocation[0];
this.state.u3.stop.departures = departureuser3.DepartureBoard.Departures;
this.state.u4.stop = locationuser4.LocationList.StopLocation[0];
this.state.u4.stop.departures = departureuser4.DepartureBoard.Departures;
globalData.users = [
this.state.u1,
this.state.u2,
this.state.u3,
this.state.u4
]
}
}
genDisrupt = () => {
this.genUsers()
this.state.disruption = undefined
if (this.state.jsonLocation === "ex1") {
for (let stopPoint of ex1.affectedStopPoints) {
for (let user of globalData.users) {
if (stopPoint.gid === user.stoppointgid) {
this.state.disruption = ex1;
var old1t = moment(user.stop.departures[0].time, "HH:mm");
old1t.add(ex1.time, "HH:mm");
user.stop.departures[0].newTime = this.showMomentTime(old1t);
user.stop.departures[0].trafficInfo = ex1.title;
}
}
if (stopPoint.gid === globalData.user.stoppointgid) {
this.state.disruption = ex1;
var old2t = moment(globalData.stop.departures[0].time, "HH:mm");
old2t.add(ex1.time, "HH:mm");
globalData.stop.departures[0].newTime = this.showMomentTime(old2t);
globalData.stop.departures[0].trafficInfo = ex1.title;
globalData.snackbarVisible = true; globalData.root.forceUpdate();
}
}
} else if (this.state.jsonLocation === "ex2") {
for (let stopPoint of ex2.affectedStopPoints) {
for (let user of globalData.users) {
if (stopPoint.gid === user.stoppointgid) {
this.state.disruption = ex2;
var old3t = moment(user.stop.departures[0].time, "HH:mm");
old3t.add(ex2.time, "HH:mm");
user.stop.departures[0].newTime = this.showMomentTime(old3t);
user.stop.departures[0].trafficInfo = ex2.title;
}
}
if (stopPoint.gid === globalData.user.stoppointgid) {
this.state.disruption = ex2;
var old4t = moment(globalData.stop.departures[0].time, "HH:mm");
old4t.add(ex2.time, "HH:mm");
globalData.stop.departures[0].newTime = this.showMomentTime(old4t);
globalData.stop.departures[0].trafficInfo = ex2.title;
globalData.snackbarVisible = true; globalData.root.forceUpdate();
}
}
}
globalData.disruption = this.state.disruption
}
render() {
return (
<div>
<Button onClick={this.props.onClick.concat([this.genDisrupt, this.updatePage])} className="disruptBtn">
{this.props.children}
</Button>
</div>
);
}
}
export default DisruptionButton;

View File

@ -0,0 +1,45 @@
import globalData from '../GlobalData.js';
import locationuser1 from '../APIexamples/locationuser1.json'
import locationuser2 from '../APIexamples/locationuser2.json'
import locationuser3 from '../APIexamples/locationuser3.json'
import locationuser4 from '../APIexamples/locationuser4.json'
import StopSelectButton from './StopSelectButton.js';
import Button from './Button.js';
import disruptIcon from '../img/flash.svg';
class FindStops extends Button {
state = {
locations : []
}
findStops = () => {
if(globalData.user.deviceId === "1"){
this.state.locations = locationuser1.LocationList.StopLocation
}else if (globalData.user.deviceId === "2"){
this.state.locations = locationuser2.LocationList.StopLocation
}else if (globalData.user.deviceId === "3"){
this.state.locations = locationuser3.LocationList.StopLocation
}else if (globalData.user.deviceId === "4"){
this.state.locations = locationuser4.LocationList.StopLocation
}
}
render() {
return (
<>
<Button onClick={[this.findStops]} className="disruptBtn">
<img src={disruptIcon} alt="" />
<span>Select nearby stops</span>
</Button>
{this.state.locations.map((item) =>
<StopSelectButton stop={item}/>
)}
</>
);
}
}
export default FindStops;

View File

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

View File

@ -0,0 +1,15 @@
import React, { Component } from 'react';
import './css/MainArea.css';
class MainArea extends Component {
render() {
return (
<main style={this.props.style}>
{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 className="menuButton">
<span>{this.props.label}</span>
<img src={this.props.icon} alt="" />
</Button>
);
} else {
return (
<Button className="menuButton">
<img src={this.props.icon} alt="" />
<span>{this.props.label}</span>
</Button>
);
}
}
}
export default MenuButton;

View File

@ -1,10 +1,87 @@
import './css/NavigationDrawer.css';
import React, { Component } from 'react'; import React, { Component } from 'react';
import globalData from '../GlobalData.js';
import DisruptionButton from "./DisruptionButton.js";
import SelectUserButton from "./SelectUserButton.js"
import Popup from './Popup.js';
import Button from './Button.js';
import './css/NavigationDrawer.css';
import userIcon from '../img/user.svg';
import disruptIcon from '../img/flash.svg';
class NavigationDrawer extends Component { 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();
};
hidePopup = () => {
this.popupElem.current.hide();
};
updatePage = () => {
globalData.currentPage.render();
}
render() { render() {
return ( return (
<div id="navDrawer"></div> <>
<Popup ref={this.popupElem}>
<h3>Välj scenario:</h3>
<ul>
<li><DisruptionButton path={"ex1"} onClick={[this.hidePopup]}>Störningsscenario 1</DisruptionButton></li>
<li><DisruptionButton path={"ex2"} onClick={[this.hidePopup]}>Störningsscenario 2</DisruptionButton></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">
<SelectUserButton path={"user1"} username="Guddeby"/>
<SelectUserButton path={"user2"} username="Hålta kyrka"/>
<SelectUserButton path={"user3"} username="Stenskärsvägen"/>
<SelectUserButton path={"user4"} username="Kuröd"/>
<Button onClick={[this.showPopup, this.close]} className="disruptBtn"><img src={disruptIcon} alt="" />Generera Störning</Button>
</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,67 @@
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
};
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 => {
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,90 @@
import globalData from '../GlobalData.js';
import user1 from '../APIexamples/user1.json'
import user2 from '../APIexamples/user2.json'
import user3 from '../APIexamples/user3.json'
import user4 from '../APIexamples/user4.json'
import locationuser1 from '../APIexamples/locationuser1.json'
import locationuser2 from '../APIexamples/locationuser2.json'
import locationuser3 from '../APIexamples/locationuser3.json'
import locationuser4 from '../APIexamples/locationuser4.json'
import departureuser1 from '../APIexamples/departureuser1.json'
import departureuser2 from '../APIexamples/departureuser2.json'
import departureuser3 from '../APIexamples/departureuser3.json'
import departureuser4 from '../APIexamples/departureuser4.json'
import Button from './Button.js';
import userIcon from '../img/userDark.svg';
class SelectUserButton extends Button {
state = {
first: false,
u1: user1,
u2: user2,
u3: user3,
u4: user4,
}
genUsers = () => {
if (globalData.users.length < 2) {
this.state.first = true;
this.state.u1.stop = locationuser1.LocationList.StopLocation[0];
this.state.u1.stop.departures = departureuser1.DepartureBoard.Departures;
this.state.u2.stop = locationuser2.LocationList.StopLocation[0];
this.state.u2.stop.departures = departureuser2.DepartureBoard.Departures;
this.state.u3.stop = locationuser3.LocationList.StopLocation[0];
this.state.u3.stop.departures = departureuser3.DepartureBoard.Departures;
this.state.u4.stop = locationuser4.LocationList.StopLocation[0];
this.state.u4.stop.departures = departureuser4.DepartureBoard.Departures;
globalData.users = [
this.state.u1,
this.state.u2,
this.state.u3,
this.state.u4
]
}
}
selectUser = () => {
this.genUsers()
if(this.props.path === "user1"){
globalData.user = user1
globalData.user.track = locationuser1.LocationList.StopLocation[0].track
globalData.stop = locationuser1.LocationList.StopLocation[0]
globalData.stop.departures = departureuser1.DepartureBoard.Departures
}else if (this.props.path === "user2"){
globalData.user = user2
globalData.user.track = locationuser2.LocationList.StopLocation[0].track
globalData.stop = locationuser2.LocationList.StopLocation[0]
globalData.stop.departures = departureuser2.DepartureBoard.Departures
}else if (this.props.path === "user3"){
globalData.user = user3
globalData.user.track = locationuser3.LocationList.StopLocation[0].track
globalData.stop = locationuser3.LocationList.StopLocation[0]
globalData.stop.departures = departureuser3.DepartureBoard.Departures
}else if (this.props.path === "user4"){
globalData.user = user4
globalData.user.track = locationuser4.LocationList.StopLocation[0].track
globalData.stop = locationuser4.LocationList.StopLocation[0]
globalData.stop.departures = departureuser4.DepartureBoard.Departures
}
}
updatePage = () => {
globalData.currentPage.forceUpdate();
}
render() {
return (
<Button onClick={[this.selectUser, this.updatePage]} className="disruptBtn">
<img src={userIcon} alt="" />
{this.props.username}
</Button>
);
}
}
export default SelectUserButton;

View File

@ -0,0 +1,61 @@
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
};
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 => {
})
axios.get('https://api.vasttrafik.se/ts/v1/traffic-situations/stoppoint/'+this.state.gid, { headers })
.then(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,22 @@
import React, {Component} from 'react';
import globalData from '../GlobalData';
import Button from './Button.js';
class StopSelectButton extends Component {
selectStop = () => {
globalData.stop = this.props.stop
}
render() {
return (
<>
<Button onClick={[this.selectStop]}>
<span>{this.props.stop.name}</span>
</Button>
</>
);
}
}
// TODO Add css
export default StopSelectButton

View File

View File

@ -0,0 +1,72 @@
import React, { Component } from 'react';
import Button from './Button.js';
import Popup from './Popup.js';
import globalData from '../GlobalData.js';
import './css/StopTitle.css';
class StopTitle extends Component {
constructor(props) {
super(props);
this.popupElem = React.createRef();
}
showPopup = () => {
this.popupElem.current.show();
};
hidePopup = () => {
this.popupElem.current.hide();
};
setTrackA = () => {
globalData.user.track = "A";
};
setTrackB = () => {
globalData.user.track = "B";
};
updatePage = () => {
globalData.currentPage.forceUpdate();
}
render() {
return (
<div id="stopTitle">
<Popup ref={this.popupElem} className="">
<h3>Välj läge:</h3>
<ul>
<>
<li><Button onClick={[this.setTrackA, this.updatePage, this.hidePopup]}>{"Läge A"}</Button></li>
<li><Button onClick={[this.setTrackB, this.updatePage, this.hidePopup]}>{"Läge B"}</Button></li>
</>
</ul>
</Popup>
<h1>{this.props.stop.name !== undefined ?
this.props.stop.name
: "Hållplats saknas"
}</h1>
{this.props.stop.name !== undefined && this.props.stop.track !== undefined ?
<div>
<h3>
<span>{"Läge " + globalData.user.track}</span>
</h3>
<Button className="changeTrackBtn" onClick={[this.showPopup]}>Byt Läge</Button>
</div>
:
(this.props.stop.name !== undefined ?
<></>
: <h3>Vänligen aktivera platsåtkomst</h3>
)
}
</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,84 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import './css/TrafficInfo.css';
import busIcon from '../img/bus.svg';
import warningIcon from '../img/warning.svg';
class TrafficEntry extends Component {
state = {
expanded: false
};
toggle = () => {
if (this.state.expanded)
this.collapse();
else
this.expand();
};
expand = () => {
this.setState({
expanded: true
});
};
collapse = () => {
this.setState({
expanded: false
});
};
render() {
let trafficInfo = this.props.departure.trafficInfo;
let lineInterference = trafficInfo !== "" && trafficInfo !== null && trafficInfo !== undefined;
return (
<div className="trafficEntry">
<div>
<div className="timeColumn">
{!lineInterference &&
<span>{this.props.departure.time}</span>
}
{lineInterference &&
<>
<div style={{display: "flex", flexDirection: "column"}}>
<span style={{color: "red", fontWeight: "bold"}}>{this.props.departure.newTime}</span>
<span style={{textDecoration: "line-through"}}>{this.props.departure.time}</span>
</div>
<img src={warningIcon} alt=""></img>
</>
}
</div>
<div className="lineColumn">
<div>
<span className="lineName">{this.props.departure.sname}</span>
<img src={busIcon} alt=""></img>
<span className="destination">{"Mot " + this.props.departure.direction}</span>
</div>
{lineInterference &&
<div className="infoWrapper" onClick={this.toggle}>
<p className={`${this.state.expanded ? "expanded" : ""}`}>
{trafficInfo}
<span style={{display: (this.state.expanded ? "inline" : "none"), marginLeft: "5px" }}><u>Visa mindre</u></span>
</p>
<span style={{display: (this.state.expanded ? "none" : "block") }}><u>Visa mer</u></span>
</div>
}
</div>
</div>
{lineInterference &&
<Link to={
{ pathname: "/travel"
, to: this.props.departure.direction
}
}>Hitta annan resväg</Link>
}
</div>
);
}
}
export default TrafficEntry;

View File

@ -0,0 +1,38 @@
import React, { Component } from 'react';
import TrafficEntry from './TrafficEntry.js';
import './css/TrafficInfo.css';
class TrafficList extends Component {
render() {
let entries = [];
if (this.props.departures) {
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" defaultValue={this.props.from}/>
<hr/>
<label>Till:</label>
<input type="text" placeholder="Hållplats/Adress/Plats" defaultValue={this.props.to} />
</form>
);
}
}
export default TripSelector;

View File

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

View File

@ -1,5 +1,21 @@
header { header {
width: 100vw; width: 100vw;
height: 15vh; display: flex;
background: burlywood; flex-direction: row;
align-items: center;
padding: 15px 15px 12vh 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: flex-start;
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,56 @@
.popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
transform-origin: center;
background: white;
display: flex !important;
flex-direction: column !important;
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;
display: block;
font-size: 1.17em;
font-weight: bold !important;
text-align: center;
color: black !important;
}
.popup ul {
list-style: none;
width: 100%;
}
.popup li button {
width: 100% !important;
height: 50px;
padding: 8% 0 !important;
font-size: 16px !important;
display: flex;
align-items: center;
justify-content: center;
}
.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,58 @@
#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;
max-width: 80vw;
}
#stopTitle h1, #stopTitle h3 {
font-weight: 100;
}
#stopTitle h1 {
font-size: 3.5vh;
}
#stopTitle h3 {
font-size: 5vw;
color: var(--colorDiscrete);
}
@media screen and (min-width: 400px) {
#stopTitle h1 {
font-size: 4vh;
}
#stopTitle h3 {
font-size: 20px;
color: var(--colorDiscrete);
}
}
#stopTitle div {
display: flex;
flex-direction: row;
align-items: center;
}
.changeTrackBtn {
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);
}
.changeTrackBtn: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 .menuButton {
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 .menuButton: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,139 @@
#trafficList {
height: 100%;
margin-top: 40px;
padding-bottom: 40px;
background: white;
}
.trafficEntry {
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
width: 100vw;
padding: 8vw 0;
background: white;
font-size: 3.5vw;
}
.trafficEntry div {
width: 90%;
display: flex;
flex-direction: row;
justify-content: flex-start;
margin-bottom: 2vh;
}
.trafficEntry div:only-child {
margin-bottom: 0;
}
.trafficEntry div:only-child > .timeColumn,
.trafficEntry div:only-child > .lineColumn {
margin-bottom: 0;
}
.trafficEntry div:only-child > .timeColumn {
justify-content: center !important;
}
.trafficEntry div p {
text-align: left;
padding: 2vh 0 0 0;
}
.trafficEntry div div {
display: flex;
flex-direction: column;
}
.trafficEntry div div div {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: flex-end;
}
.timeColumn div:first-child, .lineColumn div:first-child {
height: 5.5vh;
}
.timeColumn {
flex-basis: 20%;
justify-content: flex-start !important;
align-items: center;
}
.timeColumn div {
align-items: center !important;
}
.timeColumn img {
width: 3.5vw;
}
.lineColumn {
flex-basis: 75%;
max-width: 75%;
}
.lineColumn div {
margin-bottom: 0px;
}
.lineColumn img {
flex-basis: 25%;
height: 9vw;
}
.infoWrapper p {
text-overflow: ellipsis;
overflow: hidden;
flex-basis: 75%;
flex-grow: 1;
display: block;
white-space: nowrap;
max-height: 4.5vw;
}
.infoWrapper span {
flex-basis: 25%;
}
.expanded {
white-space: normal !important;
max-height: none !important;
}
.lineName {
background: var(--colorLine);
color: white;
font-size: 6vw;
font-weight: 100;
padding: 1vw 2.5vw;
border-radius: var(--borderRadius);
font-family: 'Roboto Light';
height: 7vw;
flex-basis: 35%;
}
.destination {
flex-basis: 40%;
height: 9vw;
font-size: 4vw;
text-align: left;
display: flex;
align-items: flex-end;
}
.trafficEntry a {
width: 90%;
font-size: 4vw;
font-weight: bold;
color: var(--colorVT1);
padding: 4vw 0;
border-radius: var(--borderRadius);
box-shadow: var(--boxShadow);
text-decoration: none;
border: 1px solid rgba(0, 0, 0, 0.2);
}

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,22 @@
import React, { Component } from 'react';
import Header from '../Header.js';
import MainArea from '../MainArea.js';
import globalData from '../../GlobalData.js';
class Tickets extends Component {
render() {
globalData.currentPage = this;
return (
<>
<Header title="Biljetter" />
<MainArea style={{justifyContent: "space-evenly"}}>
<p>Du har inga biljetter</p>
</MainArea>
</>
);
}
}
export default Tickets;

View File

@ -0,0 +1,34 @@
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';
import globalData from '../../GlobalData.js';
class TicketsBuy extends Component {
render() {
globalData.currentPage = this;
return (
<>
<Header title="Köp biljett" />
<TopMenu>
<MenuButton label="Enkelbiljett" icon={clockIcon} />
<MenuButton label="Periodbiljett" icon={calendarIcon} />
<MenuButton label="Dygnsbiljett" icon={recurringIcon} />
</TopMenu>
<MainArea style={{justifyContent: "space-evenly"}}>
<p>Du har inga tidigare köp</p>
</MainArea>
</>
);
}
}
export default TicketsBuy;

View File

@ -0,0 +1,30 @@
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 globalData from '../../GlobalData.js';
class TrafficInfo extends Component {
render() {
globalData.currentPage = this;
return (
<>
<Header title="Trafikinfo" />
<TopMenu>
<StopTitle stop={globalData.stop} />
</TopMenu>
<MainArea>
<TrafficList departures={globalData.stop.departures} />
</MainArea>
</>
);
}
}
export default TrafficInfo;

View File

@ -0,0 +1,32 @@
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';
import globalData from '../../GlobalData.js';
class Travel extends Component {
render() {
globalData.currentPage = this;
return (
<>
<Header title="Reseplanering" />
<TopMenu>
<TripSelector
from={this.props.location.from}
to={this.props.location.to}
/>
</TopMenu>
<MainArea style={{justifyContent: "space-evenly"}}>
</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

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

@ -0,0 +1,8 @@
<?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 329 329" style="enable-background:new 0 0 329 329;" xml:space="preserve">
<path d="M194.6,164.8L322.7,36.7c8.3-8.3,8.3-21.8,0-30.1s-21.8-8.3-30.1,0l-128.1,128L36.4,6.5c-8.3-8.3-21.8-8.3-30.1,0
s-8.3,21.8,0,30.1l128.1,128.1L6.3,292.9c-8.3,8.3-8.3,21.8,0,30.1c4.2,4.2,9.6,6.2,15.1,6.2s10.9-2.1,15.1-6.2l128.1-128.1
l128,128.1c4.2,4.2,9.6,6.2,15.1,6.2s10.9-2.1,15.1-6.2c8.3-8.3,8.3-21.8,0-30.1L194.6,164.8z"/>
</svg>

After

Width:  |  Height:  |  Size: 691 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

19
src/img/userDark.svg Normal file
View File

@ -0,0 +1,19 @@
<?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 460.8 460.8" style="enable-background:new 0 0 460.8 460.8;" xml:space="preserve">
<g>
<g>
<path d="M230.4,0c-65.8,0-119.6,53.8-119.6,119.6s53.8,119.6,119.6,119.6S350,185.4,350,119.6S296.3,0,230.4,0z"/>
</g>
</g>
<g>
<g>
<path 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.0 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 */ 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; margin: 0;
padding: 0; padding: 0;
@ -14,3 +19,90 @@ html, body, #root, #app {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
#root {
overflow: hidden;
}
button {
background: none;
border: none;
}
.hidden {
opacity: 0;
pointer-events: none;
}
.MuiSnackbar-root {
width: 90%;
left: 50% !important;
bottom: 90px !important;
transform: translateX(-50%);
}
.MuiSnackbarContent-root {
background: white !important;
color: black !important;
justify-content: space-between;
padding: 3.5vw 4vw !important;
border: 1px solid rgba(0, 0, 0, 0.2);
}
.MuiSnackbarContent-action {
flex-basis: 38%;
justify-content: flex-end;
margin-left: 0 !important;
margin-right: 0 !important;
padding-left: 0 !important;
height: 7.5vw;
align-items: center;
}
.MuiButtonBase-root{
width: 100%;
padding: 0 !important;
justify-content: space-between;
}
.MuiButtonBase-root:active {
background: none;
}
.MuiTouchRipple-root {
display: none;
}
.MuiSnackbarContent-message {
flex-basis: 60%;
padding: 0 !important;
}
.MuiIconButton-label {
justify-content: flex-end !important;
}
.MuiIconButton-label a {
align-items: center;
font-size: 3.5vw;
color: black;
text-decoration: none;
margin-right: 5vw;
}
.MuiIconButton-label img {
height: 3.5vw;
}
#snackDisruptInfo {
display: flex;
height: 7.5vw;
align-items: center;
font-size: 3.5vw;
font-weight: bold;
}
#snackDisruptInfo img {
height: 100%;
margin-right: 15px;
}

View File

@ -5,9 +5,7 @@ import App from './App';
import reportWebVitals from './reportWebVitals'; import reportWebVitals from './reportWebVitals';
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <App />,
<App />
</React.StrictMode>,
document.getElementById('root') document.getElementById('root')
); );

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);
}