structure du projet + docker, back: mise en place BD et apps, front: début de dev pour le header et mise en place du thème et css global (override des variables bootstrap)

This commit is contained in:
2026-06-01 15:21:47 +02:00
parent b3c027794c
commit e8e6122a45
111 changed files with 6778 additions and 1 deletions
+24
View File
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
+68
View File
@@ -0,0 +1,68 @@
server {
listen 80;
listen [::]:80;
server_name _;
location /static/ {
alias /var/www/html/static/;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
location /media/ {
alias /var/www/html/media/;
expires 30d;
add_header Cache-Control "public";
}
location /assets {
root /usr/share/nginx/html;
expires 1y;
add_header Cache-Control "public, immutable";
}
location /api/ {
proxy_pass http://backend:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
location / {
root /usr/share/nginx/html;
index index.html
try_files $uri $uri/ /index.html;
# Cache busting pour index.html
add_header Cache-Control "public, max-age=0, must-revalidate";
}
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss;
gzip_min_length 1000;
error_page 404 /index.html;
error_page 500 502 503 504 /50x.html;
}
+39
View File
@@ -0,0 +1,39 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 20M;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/rss+xml font/truetype font/opentype
application/vnd.ms-fontobject image/svg+xml;
include /etc/nginx/conf.d/*.conf;
}
+21
View File
@@ -0,0 +1,21 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import { defineConfig, globalIgnores } from 'eslint/config'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{js,jsx}'],
extends: [
js.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
globals: globals.browser,
parserOptions: { ecmaFeatures: { jsx: true } },
},
},
])
+17
View File
@@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#5d6367">
<title>Eiro</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
+3241
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
{
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"bootstrap": "^5.3.8",
"react": "^19.2.6",
"react-bootstrap": "^2.10.10",
"react-dom": "^19.2.6",
"react-icons": "^5.6.0",
"sass": "^1.100.0"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1",
"eslint": "^10.3.0",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.6.0",
"vite": "^8.0.12"
}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

+12
View File
@@ -0,0 +1,12 @@
import { useState } from 'react'
import Header from './components/Header/Header'
function App() {
return (
<>
<Header />
</>
)
}
export default App
+182
View File
@@ -0,0 +1,182 @@
:root {
/* ============================
Base
============================ */
--bs-body-bg: #FEF6F4;
--bs-body-color: #34344A;
--bs-light: #FEF6F4;
--bs-light-rgb: 254, 246, 244;
--bs-dark: #34344A;
--bs-dark-rgb: 52, 52, 74;
/* ============================
Semantic colors
============================ */
--bs-primary: #845A6D;
--bs-primary-rgb: 132, 90, 109;
--bs-secondary: #C89B7B;
--bs-secondary-rgb: 200, 155, 123;
--bs-success: #32746D;
--bs-success-rgb: 50, 116, 109;
--bs-info: #9A7284;
--bs-info-rgb: 154, 114, 132;
--bs-warning: #C89B7B;
--bs-warning-rgb: 200, 155, 123;
--bs-danger: #D47386;
--bs-danger-rgb: 212, 115, 134;
/* ============================
Links
============================ */
--bs-link-color: var(--bs-primary);
--bs-link-color-rgb: 132, 90, 109;
/* Hover = primary + dark */
--bs-link-hover-color: color-mix(in srgb, var(--bs-primary) 80%, var(--bs-dark));
--bs-link-hover-color-rgb: 118, 86, 102;
/* ============================
Subtle UI backgrounds
============================ */
--bs-border-color: color-mix(in srgb, var(--bs-dark) 15%, var(--bs-light));
--bs-border-color-rgb: 223, 214, 214;
--bs-primary-bg-subtle: color-mix(in srgb, var(--bs-primary) 12%, var(--bs-light));
--bs-primary-bg-subtle-rgb: 243, 229, 233;
--bs-success-bg-subtle: color-mix(in srgb, var(--bs-success) 12%, var(--bs-light));
--bs-success-bg-subtle-rgb: 229, 238, 237;
--bs-danger-bg-subtle: color-mix(in srgb, var(--bs-danger) 12%, var(--bs-light));
--bs-danger-bg-subtle-rgb: 245, 224, 229;
--bs-secondary-bg: color-mix(in srgb, var(--bs-secondary) 10%, var(--bs-light));
--bs-secondary-bg-rgb: 246, 236, 230;
/* ============================
Focus ring
============================ */
--bs-focus-ring-color: rgba(132, 90, 109, 0.25);
/* ============================
Typography polish
============================ */
--bs-heading-color: var(--bs-dark);
--bs-secondary-color: color-mix(in srgb, var(--bs-dark) 65%, var(--bs-light));
--bs-secondary-color-rgb: 120, 120, 135;
}
/* =========================================
DARK MODE
Trigger: <html data-bs-theme="dark">
========================================= */
[data-bs-theme="dark"] {
/* ============================
Base background + text
============================ */
--bs-body-bg: #1B1B24;
--bs-body-color: #FEF6F4;
--bs-light: #2A2A36;
--bs-light-rgb: 42, 42, 54;
--bs-dark: #FEF6F4;
--bs-dark-rgb: 254, 246, 244;
/* ============================
Semantic colors
============================ */
--bs-primary: #B08A9C;
--bs-primary-rgb: 176, 138, 156;
--bs-secondary: #C89B7B;
--bs-secondary-rgb: 200, 155, 123;
--bs-success: #4AA89E;
--bs-success-rgb: 74, 168, 158;
--bs-info: #9A7284;
--bs-info-rgb: 154, 114, 132;
--bs-warning: #E2B48E;
--bs-warning-rgb: 226, 180, 142;
--bs-danger: #E08A9C;
--bs-danger-rgb: 224, 138, 156;
/* ============================
Links
============================ */
--bs-link-color: rgb(var(--bs-primary-rgb));
--bs-link-hover-color: color-mix(in srgb, var(--bs-primary) 85%, white);
/* ============================
Borders + surfaces
============================ */
--bs-border-color: rgba(255, 255, 255, 0.10);
--bs-secondary-bg: rgba(var(--bs-primary-rgb), 0.08);
--bs-tertiary-bg: rgba(255, 255, 255, 0.04);
--bs-primary-bg-subtle: rgba(var(--bs-primary-rgb), 0.12);
--bs-success-bg-subtle: rgba(var(--bs-success-rgb), 0.12);
--bs-danger-bg-subtle: rgba(var(--bs-danger-rgb), 0.12);
/* ============================
Focus ring
============================ */
--bs-focus-ring-color: rgba(var(--bs-primary-rgb), 0.35);
/* ============================
Typography polish
============================ */
--bs-heading-color: #FEF6F4;
--bs-secondary-color: rgba(254, 246, 244, 0.70);
}
/* =========================================
OTHER VARIABLES
========================================= */
:root {
--bs-border-radius: 0.6rem;
.toast-container>:not(:last-child) {
--bs-toast-spacing: 0.6rem;
}
}
File diff suppressed because one or more lines are too long
+354
View File
@@ -0,0 +1,354 @@
@font-face {
font-family: "Salin";
src: url("../fonts/salin.otf") format("opentype");
font-weight: 400;
font-style: normal;
font-display: swap;
}
* {
margin: 0;
padding: 0;
}
h1,
h2,
h3,
h4,
h5 {
color: var(--bs-heading-color);
letter-spacing: -0.01em;
}
a {
text-decoration-thickness: 1px;
text-underline-offset: 0.15em;
}
a:hover {
text-decoration-thickness: 2px;
}
a {
color: var(--bs-link-color);
}
a:hover {
color: var(--bs-link-hover-color);
}
/* ---------------------------------------
Navbar
---------------------------------------- */
.navbar {
border-bottom: 1px solid rgba(var(--bs-border-color-rgb), 1);
background: color-mix(in srgb, var(--bs-light) 92%, var(--bs-primary));
}
.navbar .navbar-brand {
letter-spacing: 0.03em;
color: var(--bs-dark);
font-family: "Salin";
}
.logo-text {
letter-spacing: 0.03em;
color: var(--bs-dark);
font-family: "Salin";
}
.logo-img {
max-height: 10vh;
}
.navbar .nav-link {
color: rgba(var(--bs-dark-rgb), 0.78);
border-radius: 999px;
padding: 0.4rem 0.75rem;
}
.navbar .nav-link:hover,
.navbar .nav-link:focus {
color: var(--bs-dark);
background: rgba(var(--bs-primary-rgb), 0.08);
}
.navbar .nav-link.active {
color: var(--bs-dark);
background: rgba(var(--bs-primary-rgb), 0.14);
}
/* ---------------------------------------
Buttons
---------------------------------------- */
.btn {
font-weight: 600;
letter-spacing: -0.005em;
box-shadow: 0 1px 0 rgba(var(--bs-dark-rgb), 0.04);
}
.btn-primary {
border-color: rgba(var(--bs-primary-rgb), 0.65);
--bs-btn-bg: var(--bs-primary);
--bs-btn-border-color: var(--bs-primary);
--bs-btn-hover-bg: color-mix(in srgb, var(--bs-primary) 85%, black);
--bs-btn-hover-border-color: color-mix(in srgb, var(--bs-primary) 85%, black);
--bs-btn-active-bg: color-mix(in srgb, var(--bs-primary) 75%, black);
--bs-btn-active-border-color: color-mix(in srgb, var(--bs-primary) 75%, black);
--bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
color: rgb(var(--bs-light-rgb)) !important;
}
.btn-primary:hover,
.btn-primary:focus {
filter: brightness(0.98);
box-shadow:
0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.18),
0 6px 16px rgba(var(--bs-dark-rgb), 0.08);
}
.btn-success {
--bs-btn-bg: var(--bs-success);
--bs-btn-border-color: var(--bs-success);
--bs-btn-focus-shadow-rgb: var(--bs-success-rgb);
}
.btn-success:hover,
.btn-success:focus {
box-shadow:
0 0 0 0.2rem rgba(var(--bs-success-rgb), 0.18),
0 6px 16px rgba(var(--bs-dark-rgb), 0.08);
}
.btn-outline-primary {
--bs-btn-color: var(--bs-primary);
--bs-btn-border-color: rgba(var(--bs-primary-rgb), .45);
--bs-btn-hover-bg: rgba(var(--bs-primary-rgb), .10);
--bs-btn-hover-border-color: rgba(var(--bs-primary-rgb), .45);
--bs-btn-active-bg: rgba(var(--bs-primary-rgb), .16);
--bs-btn-active-border-color: rgba(var(--bs-primary-rgb), .45);
--bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}
.btn-outline-primary:hover,
.btn-outline-primary:focus {
background: rgba(var(--bs-primary-rgb), 0.10);
color: rgb(var(--bs-primary-rgb));
box-shadow:
0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.12);
}
/* Icon buttons */
.btn.btn-icon {
width: 2.5rem;
height: 2.5rem;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 999px;
box-shadow: 0 0 transparent;
}
.btn.btn-icon:hover,
.btn.btn-icon:focus {
color: var(--bs-dark);
background: rgba(var(--bs-primary-rgb), 0.08);
}
/* ---------------------------------------
Dropdowns
---------------------------------------- */
.dropdown-menu .dropdown-item:hover {
background: rgba(var(--bs-primary-rgb), .08);
}
/* ---------------------------------------
Cards / containers
---------------------------------------- */
.card {
border-radius: 1.25rem;
border: 1px solid rgba(var(--bs-border-color-rgb), 1);
background: rgba(var(--bs-light-rgb), 0.85);
box-shadow: 0 2px 10px rgba(var(--bs-dark-rgb), 0.04);
padding: 1rem;
}
.card-header {
border-bottom: 1px solid rgba(var(--bs-border-color-rgb), 1);
background: rgba(var(--bs-light-rgb), 0.94);
}
.card-body {
--bs-card-spacer-y: 0.5rem;
--bs-card-spacer-x: 0.5rem;
}
.card-footer {
/* border-top: 1px solid rgba(var(--bs-border-color-rgb), 1); */
border-top: none;
background: rgba(var(--bs-light-rgb), 0.94);
}
/* ---------------------------------------
Badges
---------------------------------------- */
.badge {
border-radius: 999px;
font-weight: 600;
padding: 0.4em 0.7em;
}
.badge.text-bg-primary {
background: var(--bs-primary) !important;
color: rgb(var(--bs-light-rgb)) !important;
border: 1px solid rgba(var(--bs-primary-rgb), 0.20);
}
.badge.text-bg-success {
background: rgba(var(--bs-success-rgb), 0.14) !important;
color: rgb(var(--bs-success-rgb)) !important;
border: 1px solid rgba(var(--bs-success-rgb), 0.20);
}
.badge.text-bg-danger {
background: rgba(var(--bs-danger-rgb), 0.14) !important;
color: rgb(var(--bs-danger-rgb)) !important;
border: 1px solid rgba(var(--bs-danger-rgb), 0.20);
}
.badge.text-bg-warning {
background: rgba(var(--bs-warning-rgb), 0.18) !important;
color: rgb(var(--bs-dark-rgb)) !important;
border: 1px solid rgba(var(--bs-warning-rgb), 0.22);
}
/* ---------------------------------------
Forms
---------------------------------------- */
.form-control,
.form-select {
border-color: rgba(var(--bs-border-color-rgb), 1);
background: rgba(var(--bs-light-rgb), 0.95);
}
.form-control:focus,
.form-select:focus {
border-color: rgba(var(--bs-primary-rgb), 0.45);
box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.18);
}
/* Checkboxes/switches */
.form-check-input:focus {
box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.18);
}
.form-check-input:checked {
background-color: rgb(var(--bs-primary-rgb));
border-color: rgb(var(--bs-primary-rgb));
}
/* ---------------------------------------
Alerts (soft)
---------------------------------------- */
.alert {
border-radius: 1rem;
border: 1px solid rgba(var(--bs-border-color-rgb), 1);
background: rgba(var(--bs-light-rgb), 0.90);
}
.alert-primary {
--bs-toast-max-width: 33vw;
border-color: rgba(var(--bs-primary-rgb), 0.25);
background: rgba(var(--bs-primary-rgb), 0.20);
color: rgb(var(--bs-dark-rgb));
}
.alert-success {
--bs-toast-max-width: 33vw;
border-color: rgba(var(--bs-success-rgb), 0.25);
background: rgba(var(--bs-success-rgb), 0.20);
color: rgb(var(--bs-dark-rgb));
}
.alert-danger {
--bs-toast-max-width: 33vw;
border-color: rgba(var(--bs-danger-rgb), 0.25);
background: rgba(var(--bs-danger-rgb), 0.30);
color: rgb(var(--bs-dark-rgb));
}
.alert-warning {
--bs-toast-max-width: 33vw;
border-color: rgba(var(--bs-warning-rgb), 0.28);
background: rgba(var(--bs-warning-rgb), 0.2);
color: rgb(var(--bs-dark-rgb));
}
.alert-icon {
font-size: 1rem;
}
/* ---------------------------------------
Tables (soft rows)
---------------------------------------- */
.table {
--bs-table-bg: transparent;
}
.table thead th {
color: rgba(var(--bs-dark-rgb), 0.75);
font-weight: 700;
border-bottom: 1px solid rgba(var(--bs-border-color-rgb), 1);
}
.table tbody tr {
border-bottom: 1px solid rgba(var(--bs-border-color-rgb), 1);
}
.table-hover tbody tr:hover {
background: rgba(var(--bs-primary-rgb), 0.06);
}
/* ---------------------------------------
Toasts / Modals
---------------------------------------- */
.modal-content {
border-radius: 1.25rem;
border: 1px solid rgba(var(--bs-border-color-rgb), 1);
box-shadow: 0 18px 50px rgba(var(--bs-dark-rgb), 0.18);
}
/* ---------------------------------------
Utility: “pill” chips (nice for filters)
---------------------------------------- */
.chip {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.35rem 0.75rem;
border-radius: 999px;
border: 1px solid rgba(var(--bs-border-color-rgb), 1);
background: rgba(var(--bs-light-rgb), 0.85);
color: rgba(var(--bs-dark-rgb), 0.8);
font-weight: 600;
}
.chip:hover {
background: rgba(var(--bs-primary-rgb), 0.08);
color: var(--bs-dark);
}
Binary file not shown.
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="m 8 1 c -1.65625 0 -3 1.34375 -3 3 s 1.34375 3 3 3 s 3 -1.34375 3 -3 s -1.34375 -3 -3 -3 z m -1.5 7 c -2.492188 0 -4.5 2.007812 -4.5 4.5 v 0.5 c 0 1.109375 0.890625 2 2 2 h 8 c 1.109375 0 2 -0.890625 2 -2 v -0.5 c 0 -2.492188 -2.007812 -4.5 -4.5 -4.5 z m 0 0" fill="#2e3436"/>
</svg>

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

@@ -0,0 +1,3 @@
.pointer-icon {
cursor: pointer;
}
+38
View File
@@ -0,0 +1,38 @@
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import NavDropdown from 'react-bootstrap/NavDropdown';
import Button from "react-bootstrap/Button"
import { useThemeContext } from '../../context/ThemeContext'
import { useTheme } from '../../hooks/useTheme'
import './Header.css'
import appIcon from "../../assets/images/icon/icon-removebg.png"
import { BsFillSunFill, BsFillMoonFill } from 'react-icons/bs'
export default function Header(props) {
const { theme, toggleTheme } = useTheme()
return (
<Navbar expand="lg" className="align-middle px-3 py-2">
<Container fluid className="g-3">
<Navbar.Brand href="#home">
<img
alt="Icon"
src={appIcon}
width="30"
height="30"
className="d-inline-block"
/>{' '}
{import.meta.env.VITE_APP_NAME}
</Navbar.Brand>
</Container>
{theme === 'dark' ?
<BsFillSunFill className="pointer-icon" onClick={toggleTheme} /> :
<BsFillMoonFill className="pointer-icon" onClick={toggleTheme} />
}
</Navbar>
)
}
+19
View File
@@ -0,0 +1,19 @@
import { createContext, useContext } from 'react'
import { useTheme } from '../hooks/useTheme'
const ThemeContext = createContext(null)
export function ThemeProvider({ children }) {
const theme = useTheme()
return (
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
)
}
export function useThemeContext() {
const ctx = useContext(ThemeContext)
if (!ctx) throw new Error('useThemeContext must be used within ThemeProvider')
return ctx
}
+18
View File
@@ -0,0 +1,18 @@
import { useState, useEffect } from 'react'
export function useTheme() {
const [theme, setTheme] = useState(() => {
const saved = localStorage.getItem('theme')
if (saved) return saved
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
})
useEffect(() => {
document.documentElement.setAttribute('data-bs-theme', theme)
localStorage.setItem('theme', theme)
}, [theme])
const toggleTheme = () => setTheme(t => t === 'dark' ? 'light' : 'dark')
return { theme, setTheme, toggleTheme }
}
+17
View File
@@ -0,0 +1,17 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
// import 'bootstrap/dist/css/bootstrap.css'
import './assets/css/bootstrap.min.css'
import './assets/css/bootstrap-override.css'
import './assets/css/theme.css'
import { ThemeProvider } from './context/ThemeContext.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<ThemeProvider>
<App />
</ThemeProvider>
</StrictMode>,
)
+12
View File
@@ -0,0 +1,12 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
envDir: "../",
server: {
port: 3000,
'/api': "http://localhost:8000/api/v1"
}
})