Skip to content

Commit a94cc0e

Browse files
authored
Merge pull request #33 from ssciwr/advanced_view_mode
Improved design: mainly, convert grid data to fine country boundries and has make interactive parts stand out
2 parents 25cbfd0 + e33b0f9 commit a94cc0e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+8765
-1073
lines changed

Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ RUN pnpm build
2121
FROM nginx:alpine
2222

2323
COPY --from=build app/dist /usr/share/nginx/html
24-
COPY nginx/conf/nginx.conf /etc/nginx/conf.d/default.conf
2524

2625
# Expose port 80 for the Nginx server
2726
EXPOSE 80

docker-compose.yml

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
services:
22
frontend:
3-
image: ghcr.io/jmsssc/mock-mapping-frontend:${ONEHEALTH_FRONTEND_DOCKER_IMAGE_TAG:-latest}
3+
image: ghcr.io/ssciwr/onehealth-map-frontend:main
44
build:
55
context: ./frontend
66
ports:
77
- "80:80"
88
- "443:443"
99
volumes:
10-
- ${ONEHEALTH_SSL_CERT:-./cert.pem}:/onehealth_ssl_cert.pem
11-
- ${ONEHEALTH_SSL_KEY:-./key.pem}:/onehealth_ssl_key.pem
12-
# to allow certbot to renew SSL certificates:
13-
- /var/www/certbot:/var/www/certbot:ro
10+
- ./nginx/conf/nginx.conf:/etc/nginx/conf.d/default.conf
11+
- ./nginx/keys:/etc/nginx/ssl:ro # Mount the certificate directory as read-only
1412
logging:
1513
driver: "local"
1614
options:
1715
max-size: 20m
1816
max-file: 25
19-
20-
# WIP in progress based on similar repo (Mondey) GHCR not set up yet/CI not set up yet.

frontend/README.md

Lines changed: 16 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,22 @@
1-
# React + TypeScript + Vite
1+
# Frontend
22

3-
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
3+
The frontend uses React.js and Leaflet to render a map.
44

5-
Currently, two official plugins are available:
5+
There are two main parts:
6+
1) The data-fetching, Model list and rendering that data on the Map
7+
2) The inputs that change state which updates the Map (timeline date selector, etc)
68

7-
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
8-
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
99

10-
## Expanding the ESLint configuration
10+
## Design
11+
The map design is different on mobile and desktop. To support mobile, a Control Bar UI, a more formal inspiration of
12+
TikToks right bar is used. Color balances are really important in this application, because of the map colors.
13+
It also matters because the gradient has to be quite specific to work. Just two colors makes it hard to see the small
14+
differences on the map when you zoom in. Three, such as Red-Yellow-Blue, works much better, and a rainbow also works.
15+
Though a Rainbow might get too complicated because not everybody knows the order intuitively and it has other symbolism.
1116

12-
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
17+
## Design rules
18+
The design of this map attempts to stick to the guidelines set out here which align with my experience making a video
19+
game with a map interface: https://proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_137.pdf
1320

14-
```js
15-
export default tseslint.config({
16-
extends: [
17-
// Remove ...tseslint.configs.recommended and replace with this
18-
...tseslint.configs.recommendedTypeChecked,
19-
// Alternatively, use this for stricter rules
20-
...tseslint.configs.strictTypeChecked,
21-
// Optionally, add this for stylistic rules
22-
...tseslint.configs.stylisticTypeChecked,
23-
],
24-
languageOptions: {
25-
// other options...
26-
parserOptions: {
27-
project: ['./tsconfig.node.json', './tsconfig.app.json'],
28-
tsconfigRootDir: import.meta.dirname,
29-
},
30-
},
31-
})
32-
```
33-
34-
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
35-
36-
```js
37-
// eslint.config.js
38-
import reactX from 'eslint-plugin-react-x'
39-
import reactDom from 'eslint-plugin-react-dom'
40-
41-
export default tseslint.config({
42-
plugins: {
43-
// Add the react-x and react-dom plugins
44-
'react-x': reactX,
45-
'react-dom': reactDom,
46-
},
47-
rules: {
48-
// other rules...
49-
// Enable its recommended typescript rules
50-
...reactX.configs['recommended-typescript'].rules,
51-
...reactDom.configs.recommended.rules,
52-
},
53-
})
54-
```
21+
The main parts being not overwhelming the user, not filling the page with logos or text, and keeping good balance
22+
design wise.

frontend/index.html

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,147 @@
44
<meta charset="UTF-8" />
55
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<title>Vite + React + TS</title>
7+
<title>One Health Platform</title>
8+
<style>
9+
/* Loading Screen Styles */
10+
#loading-screen {
11+
position: fixed;
12+
top: 0;
13+
left: 0;
14+
width: 100vw;
15+
height: 100vh;
16+
background: #2b4172;
17+
display: flex;
18+
align-items: center;
19+
justify-content: center;
20+
z-index: 9999;
21+
transition: opacity 0.15s ease-out, transform 0.15s ease-out;
22+
}
23+
24+
#loading-screen.fade-out {
25+
opacity: 0;
26+
transform: scale(0.9);
27+
pointer-events: none;
28+
}
29+
30+
.loading-logo-container {
31+
background: white;
32+
padding: 40px;
33+
border-radius: 24px;
34+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);
35+
display: flex;
36+
align-items: center;
37+
justify-content: center;
38+
animation: logoGrow 0.55s ease-out forwards;
39+
}
40+
41+
.loading-logo {
42+
max-width: 80px;
43+
max-height: 80px;
44+
opacity: 0;
45+
animation: logoFadeIn 0.3s ease-out 0.1s forwards,
46+
logoScale 0.55s ease-out forwards;
47+
}
48+
49+
@keyframes logoGrow {
50+
0% {
51+
transform: scale(0.5);
52+
opacity: 0;
53+
}
54+
50% {
55+
opacity: 1;
56+
}
57+
100% {
58+
transform: scale(1);
59+
opacity: 1;
60+
}
61+
}
62+
63+
@keyframes logoFadeIn {
64+
0% {
65+
opacity: 0;
66+
transform: scale(0.8);
67+
}
68+
100% {
69+
opacity: 1;
70+
transform: scale(1);
71+
}
72+
}
73+
74+
@keyframes logoScale {
75+
0% {
76+
transform: scale(0.8);
77+
}
78+
60% {
79+
transform: scale(1.1);
80+
}
81+
100% {
82+
transform: scale(1);
83+
}
84+
}
85+
86+
/* Hide the main app initially */
87+
#root {
88+
opacity: 0;
89+
transition: opacity 0.15s ease-in;
90+
}
91+
92+
#root.loaded {
93+
opacity: 1;
94+
}
95+
96+
/* Responsive adjustments */
97+
@media (max-width: 768px) {
98+
.loading-logo-container {
99+
padding: 30px;
100+
border-radius: 20px;
101+
}
102+
103+
.loading-logo {
104+
max-width: 60px;
105+
max-height: 60px;
106+
}
107+
}
108+
</style>
8109
</head>
9110
<body>
111+
<!-- Loading Screen -->
112+
<div id="loading-screen">
113+
<div class="loading-logo-container">
114+
<img
115+
src="/images/oneHealthLogoOnlySymbols.png"
116+
alt="One Health Platform"
117+
class="loading-logo"
118+
/>
119+
</div>
120+
</div>
121+
10122
<div id="root"></div>
11123
<script type="module" src="/src/main.tsx"></script>
124+
125+
<script>
126+
// Remove loading screen when React app is ready
127+
document.addEventListener('DOMContentLoaded', function() {
128+
// Wait for a minimum of 0.75 seconds to show the animation
129+
setTimeout(function() {
130+
const loadingScreen = document.getElementById('loading-screen');
131+
const root = document.getElementById('root');
132+
133+
// Start fade out animation
134+
loadingScreen.classList.add('fade-out');
135+
136+
// Show the React app
137+
setTimeout(function() {
138+
root.classList.add('loaded');
139+
// Remove loading screen from DOM after animation
140+
setTimeout(function() {
141+
if (loadingScreen) {
142+
loadingScreen.remove();
143+
}
144+
}, 250);
145+
}, 100);
146+
}, 750);
147+
});
148+
</script>
12149
</body>
13150
</html>

frontend/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
},
1414
"dependencies": {
1515
"@ant-design/icons": "^6.0.0",
16+
"@reactour/tour": "^3.8.0",
17+
"@turf/boolean-point-in-polygon": "^7.2.0",
1618
"@turf/turf": "^7.2.0",
1719
"antd": "^5.20.0",
1820
"axios": "^1.9.0",
@@ -29,6 +31,7 @@
2931
"react-leaflet-cluster": "^2.1.0",
3032
"react-leaflet-heatmap-layer-v3": "3.0.3-beta-1",
3133
"react-router-dom": "^7.5.3",
34+
"react-top-loading-bar": "^3.0.2",
3235
"topojson-client": "^3.1.0"
3336
},
3437
"devDependencies": {
@@ -47,6 +50,7 @@
4750
"eslint-plugin-react-hooks": "^5.2.0",
4851
"eslint-plugin-react-refresh": "^0.4.19",
4952
"globals": "^16.0.0",
53+
"js-yaml": "^4.1.0",
5054
"typescript": "~5.7.2",
5155
"typescript-eslint": "^8.26.1",
5256
"vite": "^6.3.1"

0 commit comments

Comments
 (0)