diff options
Diffstat (limited to 'frontend')
| -rw-r--r-- | frontend/.dockerignore | 10 | ||||
| -rw-r--r-- | frontend/.env.docker (renamed from frontend/.env) | 0 | ||||
| -rw-r--r-- | frontend/Dockerfile | 28 | ||||
| -rw-r--r-- | frontend/eslint.config.ts (renamed from frontend/eslint.config.js) | 0 | ||||
| -rw-r--r-- | frontend/nginx.conf | 27 | ||||
| -rw-r--r-- | frontend/src/components/ErrorBanner.tsx | 5 | ||||
| -rw-r--r-- | frontend/src/components/Sidebar.tsx | 8 | ||||
| -rw-r--r-- | frontend/src/pages/Login.tsx | 13 | ||||
| -rw-r--r-- | frontend/src/styles/login.css | 1 |
9 files changed, 81 insertions, 11 deletions
diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..9f8fe0e --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,10 @@ +**/.env +**/.git +**/.gitignore +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/build +**/dist +LICENSE +README.md
\ No newline at end of file diff --git a/frontend/.env b/frontend/.env.docker index cd41370..cd41370 100644 --- a/frontend/.env +++ b/frontend/.env.docker diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..791cd87 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,28 @@ +# syntax=docker/dockerfile:1 + +# BUILD STAGE +FROM node:22-alpine AS builder + +WORKDIR /app + +COPY package*.json ./ + +RUN npm ci + +# Copy .env.docker as .env for Vite +COPY .env.docker .env + +COPY . . + +# Compile TypeScript & create optimized production build +RUN npm run build + +# PRODUCTION STAGE +FROM nginx:alpine AS production + +# Copy production build files to nginx +COPY --from=builder /app/dist /usr/share/nginx/html + +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80
\ No newline at end of file diff --git a/frontend/eslint.config.js b/frontend/eslint.config.ts index 6343bef..6343bef 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.ts diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 0000000..151afe8 --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,27 @@ +# For Docker Compose +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + # Enable gzip compression + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + # SPA routing - send all requests to index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; +}
\ No newline at end of file diff --git a/frontend/src/components/ErrorBanner.tsx b/frontend/src/components/ErrorBanner.tsx new file mode 100644 index 0000000..fdb3bf1 --- /dev/null +++ b/frontend/src/components/ErrorBanner.tsx @@ -0,0 +1,5 @@ +function ErrorBanner({ message }: { message: string }) { + return <div className="error-message">{message}</div>; +} + +export default ErrorBanner; diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 3760d4e..bdfadad 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -4,6 +4,7 @@ import "../styles/button.css"; import "../styles/sidebar.css"; import type { Robot } from "../types/robot"; import AddRobotForm from "./AddRobotForm"; +import ErrorBanner from "./ErrorBanner"; import RobotList from "./RobotList"; import SimulationActions from "./SimulationActions"; @@ -58,10 +59,8 @@ function Sidebar({ /> )} - {errorMessage && ( - <div className="error-message">{errorMessage}</div> - )} - + {errorMessage && <ErrorBanner message={errorMessage} />} + <SimulationActions activeSimulation={activeSimulation} apiUrl={API_URL} @@ -81,4 +80,3 @@ function Sidebar({ } export default Sidebar; - diff --git a/frontend/src/pages/Login.tsx b/frontend/src/pages/Login.tsx index 11b7c11..463af8e 100644 --- a/frontend/src/pages/Login.tsx +++ b/frontend/src/pages/Login.tsx @@ -1,6 +1,8 @@ import { useEffect, useState, type ChangeEvent, type FormEvent } from "react"; import { useNavigate } from "react-router-dom"; import { FadeLoader } from "react-spinners"; +import mapBackground from "../assets/map-blurred.png"; +import ErrorBanner from "../components/ErrorBanner"; import Logo from "../components/Logo"; import API_URL from "../config"; import "../styles/button.css"; @@ -84,7 +86,10 @@ function Login() { }, []); return ( - <div className="login-page"> + <div + className="login-page" + style={{ backgroundImage: `url(${mapBackground})` }} + > <div className="login-card"> <Logo /> <p className="subtitle">🤖 Please log in to use the app 🤖</p> @@ -119,10 +124,8 @@ function Login() { /> </div> - {errorMessage && ( - <div className="error-message">{errorMessage}</div> - )} - + {errorMessage && <ErrorBanner message={errorMessage} />} + <button className="btn btn-start" disabled={isLoading} diff --git a/frontend/src/styles/login.css b/frontend/src/styles/login.css index 4592016..1da01ea 100644 --- a/frontend/src/styles/login.css +++ b/frontend/src/styles/login.css @@ -1,5 +1,4 @@ .login-page { - background-image: url("../src/assets/map-blurred.png"); background-position: center; background-repeat: no-repeat; background-size: cover; |
