From 2b659920c2b471c4ab80a8e616f16512bf97a203 Mon Sep 17 00:00:00 2001 From: Gilles Soulier Date: Thu, 22 Jan 2026 06:18:04 +0100 Subject: [PATCH] update frontend ui, i18n, filters, and deps --- .env.example | 2 + .gitignore | 6 + backend/internal/handlers/categories.go | 3 + backend/internal/handlers/config.go | 109 + backend/internal/handlers/debug.go | 52 + backend/internal/handlers/emplacements.go | 3 + backend/internal/handlers/router.go | 3 + doc_dev/22_etape15_settings_debug.md | 16 + doc_dev/23_etape16_frontend_api.md | 12 + doc_dev/24_etape17_frontend_detail.md | 11 + doc_dev/25_etape18_objet_detail_pj_champs.md | 9 + .../26_etape19_objet_liens_upload_champs.md | 9 + doc_dev/27_etape20_fileuploader_robuste.md | 10 + doc_dev/28_etape21_fileuploader_ui_pj.md | 9 + doc_dev/29_etape22_ui_crud_errors.md | 10 + doc_dev/30_etape23_tree_confirm_polish.md | 11 + doc_dev/31_etape24_components_tree.md | 9 + doc_dev/32_etape25_emplacement_picker_i18n.md | 8 + doc_dev/33_etape26_i18n_layout.md | 9 + doc_dev/34_etape27_i18n_components.md | 9 + doc_dev/35_etape28_i18n_full.md | 11 + doc_dev/36_etape29_i18n_filtres_pagination.md | 10 + doc_dev/37_etape30_i18n_rest_filters.md | 9 + doc_dev/38_etape31_pagination_filtres_ce.md | 9 + doc_dev/39_etape32_backend_filter_tests.md | 8 + doc_dev/40_etape33_npm_warnings.md | 13 + docker-compose.yml | 2 + frontend/assets/css/main.css | 99 +- frontend/components/CategorieForm.vue | 61 + frontend/components/ConfirmDialog.vue | 27 + frontend/components/EmplacementForm.vue | 63 + frontend/components/EmplacementPicker.vue | 58 + frontend/components/FileUploader.vue | 94 + frontend/components/I18nStub.vue | 10 + frontend/components/ObjetForm.vue | 66 + frontend/components/TreeList.vue | 94 + frontend/composables/useApi.ts | 13 + frontend/i18n.config.ts | 7 + frontend/layouts/default.vue | 30 + frontend/locales/fr.json | 144 + frontend/nuxt.config.ts | 12 + frontend/package-lock.json | 11543 ++++++++++++++++ frontend/package.json | 10 +- frontend/pages/categories/index.vue | 212 + frontend/pages/debug.vue | 64 + frontend/pages/emplacements/index.vue | 214 +- frontend/pages/index.vue | 15 +- frontend/pages/objets/[id].vue | 369 +- frontend/pages/objets/index.vue | 210 +- frontend/pages/settings.vue | 80 + frontend/tests/useApi.test.ts | 12 + frontend/vitest.config.ts | 8 + 52 files changed, 13874 insertions(+), 13 deletions(-) create mode 100644 backend/internal/handlers/config.go create mode 100644 backend/internal/handlers/debug.go create mode 100644 doc_dev/22_etape15_settings_debug.md create mode 100644 doc_dev/23_etape16_frontend_api.md create mode 100644 doc_dev/24_etape17_frontend_detail.md create mode 100644 doc_dev/25_etape18_objet_detail_pj_champs.md create mode 100644 doc_dev/26_etape19_objet_liens_upload_champs.md create mode 100644 doc_dev/27_etape20_fileuploader_robuste.md create mode 100644 doc_dev/28_etape21_fileuploader_ui_pj.md create mode 100644 doc_dev/29_etape22_ui_crud_errors.md create mode 100644 doc_dev/30_etape23_tree_confirm_polish.md create mode 100644 doc_dev/31_etape24_components_tree.md create mode 100644 doc_dev/32_etape25_emplacement_picker_i18n.md create mode 100644 doc_dev/33_etape26_i18n_layout.md create mode 100644 doc_dev/34_etape27_i18n_components.md create mode 100644 doc_dev/35_etape28_i18n_full.md create mode 100644 doc_dev/36_etape29_i18n_filtres_pagination.md create mode 100644 doc_dev/37_etape30_i18n_rest_filters.md create mode 100644 doc_dev/38_etape31_pagination_filtres_ce.md create mode 100644 doc_dev/39_etape32_backend_filter_tests.md create mode 100644 doc_dev/40_etape33_npm_warnings.md create mode 100644 frontend/components/CategorieForm.vue create mode 100644 frontend/components/ConfirmDialog.vue create mode 100644 frontend/components/EmplacementForm.vue create mode 100644 frontend/components/EmplacementPicker.vue create mode 100644 frontend/components/FileUploader.vue create mode 100644 frontend/components/I18nStub.vue create mode 100644 frontend/components/ObjetForm.vue create mode 100644 frontend/components/TreeList.vue create mode 100644 frontend/composables/useApi.ts create mode 100644 frontend/i18n.config.ts create mode 100644 frontend/layouts/default.vue create mode 100644 frontend/locales/fr.json create mode 100644 frontend/package-lock.json create mode 100644 frontend/pages/categories/index.vue create mode 100644 frontend/pages/debug.vue create mode 100644 frontend/pages/settings.vue create mode 100644 frontend/tests/useApi.test.ts create mode 100644 frontend/vitest.config.ts diff --git a/.env.example b/.env.example index ad03ea4..a65370c 100644 --- a/.env.example +++ b/.env.example @@ -5,6 +5,8 @@ DATABASE_URL=file:./data/matosbox.db?_fk=1 ATTACHMENTS_DIR=./data/pieces_jointes BACKUP_DIR=./data/backups MAX_UPLOAD_MB=50 +CONFIG_PATH=./data/config.json +DEBUG_LOG_PATH=./data/logs/backend.log # App TIMEZONE=Europe/Paris diff --git a/.gitignore b/.gitignore index ca4a4e9..c805628 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,9 @@ /bin/ *.exe *.out + +# Frontend +/frontend/node_modules/ +/frontend/.nuxt/ +/frontend/.output/ +/frontend/dist/ diff --git a/backend/internal/handlers/categories.go b/backend/internal/handlers/categories.go index d23a4c6..4d712ef 100644 --- a/backend/internal/handlers/categories.go +++ b/backend/internal/handlers/categories.go @@ -27,6 +27,9 @@ type categorieRequest struct { func (h *Handler) ListCategories(c *gin.Context) { limit, offset, page := parsePagination(c.Query("page"), c.Query("limit")) query := h.client.Categorie.Query() + if nom := c.Query("nom"); nom != "" { + query = query.Where(categorie.NomContainsFold(nom)) + } total, err := query.Count(c.Request.Context()) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de compter les categories"}) diff --git a/backend/internal/handlers/config.go b/backend/internal/handlers/config.go new file mode 100644 index 0000000..0bb96e8 --- /dev/null +++ b/backend/internal/handlers/config.go @@ -0,0 +1,109 @@ +package handlers + +import ( + "encoding/json" + "net/http" + "os" + "path/filepath" + + "github.com/gin-gonic/gin" +) + +type configPayload struct { + Backend map[string]any `json:"backend"` + Frontend map[string]any `json:"frontend"` + Timezone string `json:"timezone"` +} + +// @Summary Lire la configuration +// @Tags Config +// @Produce json +// @Success 200 {object} configPayload +// @Failure 500 {object} map[string]string +// @Router /config [get] +func (h *Handler) GetConfig(c *gin.Context) { + config, err := readConfig() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de lire la configuration"}) + return + } + c.JSON(http.StatusOK, config) +} + +// @Summary Mettre a jour la configuration +// @Tags Config +// @Accept json +// @Produce json +// @Param body body configPayload true "Configuration" +// @Success 200 {object} configPayload +// @Failure 400 {object} map[string]string +// @Failure 500 {object} map[string]string +// @Router /config [put] +func (h *Handler) UpdateConfig(c *gin.Context) { + var payload configPayload + if err := c.ShouldBindJSON(&payload); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"erreur": "donnees invalides"}) + return + } + if payload.Timezone == "" { + payload.Timezone = "Europe/Paris" + } + + if err := writeConfig(payload); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de sauvegarder la configuration"}) + return + } + c.JSON(http.StatusOK, payload) +} + +func configPath() string { + value := os.Getenv("CONFIG_PATH") + if value == "" { + return "./data/config.json" + } + return value +} + +func defaultConfig() configPayload { + return configPayload{ + Backend: map[string]any{}, + Frontend: map[string]any{}, + Timezone: "Europe/Paris", + } +} + +func readConfig() (configPayload, error) { + path := configPath() + data, err := os.ReadFile(path) + if err != nil { + if os.IsNotExist(err) { + cfg := defaultConfig() + if err := writeConfig(cfg); err != nil { + return configPayload{}, err + } + return cfg, nil + } + return configPayload{}, err + } + + var cfg configPayload + if err := json.Unmarshal(data, &cfg); err != nil { + return configPayload{}, err + } + if cfg.Timezone == "" { + cfg.Timezone = "Europe/Paris" + } + return cfg, nil +} + +func writeConfig(cfg configPayload) error { + path := configPath() + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + return err + } + data, err := json.MarshalIndent(cfg, "", " ") + if err != nil { + return err + } + return os.WriteFile(path, data, 0o644) +} diff --git a/backend/internal/handlers/debug.go b/backend/internal/handlers/debug.go new file mode 100644 index 0000000..c592ce5 --- /dev/null +++ b/backend/internal/handlers/debug.go @@ -0,0 +1,52 @@ +package handlers + +import ( + "net/http" + "os" + + "github.com/gin-gonic/gin" +) + +type debugLogsResponse struct { + Logs string `json:"logs"` +} + +// @Summary Lire les logs backend +// @Tags Debug +// @Produce json +// @Success 200 {object} debugLogsResponse +// @Failure 500 {object} map[string]string +// @Router /debug/logs [get] +func (h *Handler) GetDebugLogs(c *gin.Context) { + logs, err := readLogTail() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de lire les logs"}) + return + } + c.JSON(http.StatusOK, debugLogsResponse{Logs: logs}) +} + +func debugLogPath() string { + value := os.Getenv("DEBUG_LOG_PATH") + if value == "" { + return "./data/logs/backend.log" + } + return value +} + +func readLogTail() (string, error) { + path := debugLogPath() + data, err := os.ReadFile(path) + if err != nil { + if os.IsNotExist(err) { + return "", nil + } + return "", err + } + + const maxBytes = 20000 + if len(data) > maxBytes { + data = data[len(data)-maxBytes:] + } + return string(data), nil +} diff --git a/backend/internal/handlers/emplacements.go b/backend/internal/handlers/emplacements.go index b9c18aa..a1b05b9 100644 --- a/backend/internal/handlers/emplacements.go +++ b/backend/internal/handlers/emplacements.go @@ -30,6 +30,9 @@ type emplacementRequest struct { func (h *Handler) ListEmplacements(c *gin.Context) { limit, offset, page := parsePagination(c.Query("page"), c.Query("limit")) query := h.client.Emplacement.Query() + if nom := c.Query("nom"); nom != "" { + query = query.Where(emplacement.NomContainsFold(nom)) + } total, err := query.Count(c.Request.Context()) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"erreur": "impossible de compter les emplacements"}) diff --git a/backend/internal/handlers/router.go b/backend/internal/handlers/router.go index 3439545..12b46ab 100644 --- a/backend/internal/handlers/router.go +++ b/backend/internal/handlers/router.go @@ -28,6 +28,9 @@ func RegisterRoutes(r *gin.Engine, client *ent.Client) { v1.POST("/objets/:id/liens_emplacements", h.CreateLienEmplacement) v1.PUT("/liens_emplacements/:id", h.UpdateLienEmplacement) v1.DELETE("/liens_emplacements/:id", h.DeleteLienEmplacement) + v1.GET("/config", h.GetConfig) + v1.PUT("/config", h.UpdateConfig) + v1.GET("/debug/logs", h.GetDebugLogs) v1.GET("/categories", h.ListCategories) v1.POST("/categories", h.CreateCategorie) diff --git a/doc_dev/22_etape15_settings_debug.md b/doc_dev/22_etape15_settings_debug.md new file mode 100644 index 0000000..7e47daa --- /dev/null +++ b/doc_dev/22_etape15_settings_debug.md @@ -0,0 +1,16 @@ +# Etape 15 - Settings + Debug + +## Backend +- Endpoint config : + - `GET /v1/config` + - `PUT /v1/config` +- Endpoint debug logs : + - `GET /v1/debug/logs` + +## Frontend +- Page `/settings` pour edition du `config.json`. +- Page `/debug` pour affichage logs backend. + +## Variables +- `CONFIG_PATH` : chemin config (defaut `./data/config.json`). +- `DEBUG_LOG_PATH` : chemin logs (defaut `./data/logs/backend.log`). diff --git a/doc_dev/23_etape16_frontend_api.md b/doc_dev/23_etape16_frontend_api.md new file mode 100644 index 0000000..0febc36 --- /dev/null +++ b/doc_dev/23_etape16_frontend_api.md @@ -0,0 +1,12 @@ +# Etape 16 - Frontend API (listes) + +## Objectif +Brancher le frontend sur l'API pour les listes. + +## Pages +- `frontend/pages/objets/index.vue` : GET `/v1/objets?limit=50`. +- `frontend/pages/emplacements/index.vue` : GET `/v1/emplacements?limit=50`. + +## Notes +- Gestion du chargement et des erreurs. +- Affichage simple sous forme de cartes. diff --git a/doc_dev/24_etape17_frontend_detail.md b/doc_dev/24_etape17_frontend_detail.md new file mode 100644 index 0000000..ff78de6 --- /dev/null +++ b/doc_dev/24_etape17_frontend_detail.md @@ -0,0 +1,11 @@ +# Etape 17 - Frontend detail objet + +## Objectif +Connecter la fiche objet a l'API. + +## Page +- `frontend/pages/objets/[id].vue` : GET `/v1/objets/:id`. + +## Notes +- Gestion du chargement et des erreurs. +- Affichage minimal (nom, description, quantite, statut). diff --git a/doc_dev/25_etape18_objet_detail_pj_champs.md b/doc_dev/25_etape18_objet_detail_pj_champs.md new file mode 100644 index 0000000..8b34398 --- /dev/null +++ b/doc_dev/25_etape18_objet_detail_pj_champs.md @@ -0,0 +1,9 @@ +# Etape 18 - Detail objet (pieces jointes + champs) + +## Objectif +Afficher les pieces jointes et champs personnalises sur la fiche objet. + +## Page +- `frontend/pages/objets/[id].vue` + - GET `/v1/objets/:id/pieces_jointes` + - GET `/v1/objets/:id/champs_personnalises` diff --git a/doc_dev/26_etape19_objet_liens_upload_champs.md b/doc_dev/26_etape19_objet_liens_upload_champs.md new file mode 100644 index 0000000..0b34bac --- /dev/null +++ b/doc_dev/26_etape19_objet_liens_upload_champs.md @@ -0,0 +1,9 @@ +# Etape 19 - Fiche objet (liens, upload, edition champs) + +## Ajouts +- Liste et creation des liens emplacements. +- Upload multiple de pieces jointes. +- Creation, edition et suppression des champs personnalises. + +## Page +- `frontend/pages/objets/[id].vue` diff --git a/doc_dev/27_etape20_fileuploader_robuste.md b/doc_dev/27_etape20_fileuploader_robuste.md new file mode 100644 index 0000000..b537ad7 --- /dev/null +++ b/doc_dev/27_etape20_fileuploader_robuste.md @@ -0,0 +1,10 @@ +# Etape 20 - FileUploader + robustesse + +## Ajouts +- Composant `FileUploader` reutilisable. +- Blocage pendant upload et messages d'etat. +- Messages d'erreur/succes pour champs et liens. + +## Fichiers +- `frontend/components/FileUploader.vue` +- `frontend/pages/objets/[id].vue` diff --git a/doc_dev/28_etape21_fileuploader_ui_pj.md b/doc_dev/28_etape21_fileuploader_ui_pj.md new file mode 100644 index 0000000..2462bdd --- /dev/null +++ b/doc_dev/28_etape21_fileuploader_ui_pj.md @@ -0,0 +1,9 @@ +# Etape 21 - FileUploader + UI pieces jointes + +## FileUploader +- Drag & drop + preview images. +- Etat bloque si upload en cours. + +## Pieces jointes +- Actions UI : definir principale, supprimer. +- Indicateur "Principale" sur la fiche objet. diff --git a/doc_dev/29_etape22_ui_crud_errors.md b/doc_dev/29_etape22_ui_crud_errors.md new file mode 100644 index 0000000..c1f173c --- /dev/null +++ b/doc_dev/29_etape22_ui_crud_errors.md @@ -0,0 +1,10 @@ +# Etape 22 - UI CRUD + erreurs + +## Frontend +- CRUD objets, categories, emplacements avec formulaires simples. +- Fiche objet : erreurs detaillees (API). +- Settings : champ timezone + injection dans config JSON. +- Debug : auto-refresh + copie des logs. + +## Composables +- `frontend/composables/useApi.ts` pour base API + messages d'erreur. diff --git a/doc_dev/30_etape23_tree_confirm_polish.md b/doc_dev/30_etape23_tree_confirm_polish.md new file mode 100644 index 0000000..cf90e15 --- /dev/null +++ b/doc_dev/30_etape23_tree_confirm_polish.md @@ -0,0 +1,11 @@ +# Etape 23 - Arborescences, confirmations, polish + +## Arborescences +- Vue en liste indentee pour categories et emplacements. + +## Confirmations +- Boite de confirmation avant suppression (objets, categories, emplacements, champs, pieces jointes). + +## Polish UI +- Amelioration styles : cartes, boutons, inputs, modal. +- Ajout composant `ConfirmDialog`. diff --git a/doc_dev/31_etape24_components_tree.md b/doc_dev/31_etape24_components_tree.md new file mode 100644 index 0000000..814b088 --- /dev/null +++ b/doc_dev/31_etape24_components_tree.md @@ -0,0 +1,9 @@ +# Etape 24 - Composants + tree + +## Composants +- `ObjetForm` pour le formulaire objet. +- `TreeList` pour arborescences collapsibles. + +## Pages +- `objets/index.vue` utilise `ObjetForm`. +- `categories/index.vue` et `emplacements/index.vue` utilisent `TreeList`. diff --git a/doc_dev/32_etape25_emplacement_picker_i18n.md b/doc_dev/32_etape25_emplacement_picker_i18n.md new file mode 100644 index 0000000..7903d7b --- /dev/null +++ b/doc_dev/32_etape25_emplacement_picker_i18n.md @@ -0,0 +1,8 @@ +# Etape 25 - Emplacement picker + i18n stub + +## Emplacement picker +- Composant `EmplacementPicker` pour choisir un emplacement par nom. +- Utilise la liste des emplacements et affiche une indentation par niveau. + +## I18n +- Ajout d'un bloc d'information dans Settings (integration Weblate a venir). diff --git a/doc_dev/33_etape26_i18n_layout.md b/doc_dev/33_etape26_i18n_layout.md new file mode 100644 index 0000000..dab83d1 --- /dev/null +++ b/doc_dev/33_etape26_i18n_layout.md @@ -0,0 +1,9 @@ +# Etape 26 - i18n + layout + +## i18n +- Ajout du module `@nuxtjs/i18n`. +- Config FR par defaut + fichier `locales/fr.json`. + +## Layout +- Ajout d'un layout global avec header nav et footer. +- Styles header/nav/footer dans `assets/css/main.css`. diff --git a/doc_dev/34_etape27_i18n_components.md b/doc_dev/34_etape27_i18n_components.md new file mode 100644 index 0000000..81a9cd9 --- /dev/null +++ b/doc_dev/34_etape27_i18n_components.md @@ -0,0 +1,9 @@ +# Etape 27 - i18n + composants + +## Composants +- `CategorieForm` et `EmplacementForm` pour factoriser les formulaires CRUD. +- `TreeList` conserve l'arborescence collapsible. + +## i18n +- Texte UI principal remplace par des cles i18n. +- Fichier `locales/fr.json` enrichi. diff --git a/doc_dev/35_etape28_i18n_full.md b/doc_dev/35_etape28_i18n_full.md new file mode 100644 index 0000000..f29306e --- /dev/null +++ b/doc_dev/35_etape28_i18n_full.md @@ -0,0 +1,11 @@ +# Etape 28 - i18n complet + +## Actions +- Traduction des boutons et messages dans les pages CRUD. +- i18n pour FileUploader et ConfirmDialog. + +## Fichiers +- `frontend/locales/fr.json` +- pages CRUD + fiche objet +- `frontend/components/FileUploader.vue` +- `frontend/components/ConfirmDialog.vue` diff --git a/doc_dev/36_etape29_i18n_filtres_pagination.md b/doc_dev/36_etape29_i18n_filtres_pagination.md new file mode 100644 index 0000000..f612021 --- /dev/null +++ b/doc_dev/36_etape29_i18n_filtres_pagination.md @@ -0,0 +1,10 @@ +# Etape 29 - i18n complet + filtres objets + +## i18n +- Remplacement des textes restants par des cles i18n. +- Ajouts dans `locales/fr.json`. +- Composants CRUD et pages detail traduits. + +## Objets +- Filtres nom/statut + limite. +- Pagination avec total (meta) et navigation. diff --git a/doc_dev/37_etape30_i18n_rest_filters.md b/doc_dev/37_etape30_i18n_rest_filters.md new file mode 100644 index 0000000..0de879f --- /dev/null +++ b/doc_dev/37_etape30_i18n_rest_filters.md @@ -0,0 +1,9 @@ +# Etape 30 - i18n fin + filtres/pagination objets + +## i18n +- Traduction des textes restants (pages liste/detail, formulaires, confirmations). +- Cles supplementaires dans `locales/fr.json`. + +## Objets +- Filtres nom/statut + limite. +- Pagination avec meta (page/total). diff --git a/doc_dev/38_etape31_pagination_filtres_ce.md b/doc_dev/38_etape31_pagination_filtres_ce.md new file mode 100644 index 0000000..0ee8eb0 --- /dev/null +++ b/doc_dev/38_etape31_pagination_filtres_ce.md @@ -0,0 +1,9 @@ +# Etape 31 - Filtres + pagination categories/emplacements + +## Categories +- Filtres nom + limite. +- Pagination avec meta. + +## Emplacements +- Filtres nom + limite. +- Pagination avec meta. diff --git a/doc_dev/39_etape32_backend_filter_tests.md b/doc_dev/39_etape32_backend_filter_tests.md new file mode 100644 index 0000000..4056428 --- /dev/null +++ b/doc_dev/39_etape32_backend_filter_tests.md @@ -0,0 +1,8 @@ +# Etape 32 - Filtres backend + tests front + +## Backend +- Filtre `nom` sur `GET /v1/categories` et `GET /v1/emplacements`. + +## Frontend +- Ajout de Vitest config + test basique `useApi`. +- Script `pnpm test` via `npm run test`. diff --git a/doc_dev/40_etape33_npm_warnings.md b/doc_dev/40_etape33_npm_warnings.md new file mode 100644 index 0000000..a0bddd5 --- /dev/null +++ b/doc_dev/40_etape33_npm_warnings.md @@ -0,0 +1,13 @@ +# Etape 33 - Warnings npm + +## Contexte +Lors de `npm install` dans `frontend/`, npm a remonte des warnings de dependances. + +## Warnings observes +- `whatwg-encoding@3.1.1` deprecate (suggestion: @exodus/bytes). +- `vue-i18n@9.14.5` deprecie (v9/v10 non supportees, migration vers v11 conseillee). +- `tar@6.2.1` deprecie (vulnerabilites connues, mise a jour recommandee). + +## Vulnerabilites npm audit +- 13 vulnerabilites (2 low, 4 moderate, 5 high, 2 critical). +- Npm a suggere: `npm audit fix --force` (a evaluer avant execution). diff --git a/docker-compose.yml b/docker-compose.yml index 501dae2..7eec1de 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,8 @@ services: ATTACHMENTS_DIR: ./data/pieces_jointes BACKUP_DIR: ./data/backups MAX_UPLOAD_MB: 50 + CONFIG_PATH: ./data/config.json + DEBUG_LOG_PATH: ./data/logs/backend.log volumes: - ./:/app - ./data:/app/data diff --git a/frontend/assets/css/main.css b/frontend/assets/css/main.css index 01ba84a..127140b 100644 --- a/frontend/assets/css/main.css +++ b/frontend/assets/css/main.css @@ -11,7 +11,7 @@ body { margin: 0; font-family: "Space Grotesk", system-ui, sans-serif; - background: var(--bg); + background: linear-gradient(135deg, #f5f1e8 0%, #efe6d6 100%); color: var(--text); } @@ -26,6 +26,45 @@ a { padding: 24px; } +.app-header { + position: sticky; + top: 0; + z-index: 20; + background: rgba(245, 241, 232, 0.9); + backdrop-filter: blur(6px); + border-bottom: 1px solid #e3d8c5; +} + +.header-content { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; +} + +.brand { + font-weight: 700; + font-size: 20px; + color: #3a2a1a; +} + +.nav-links { + display: flex; + gap: 12px; + flex-wrap: wrap; +} + +.nav-links a { + padding: 6px 10px; + border-radius: 10px; + border: 1px solid transparent; +} + +.nav-links a.router-link-active { + border-color: #c46b2d; + background: #fffaf2; +} + .hero { display: grid; gap: 12px; @@ -42,4 +81,62 @@ a { border-radius: 16px; padding: 16px; background: #fffaf2; + box-shadow: 0 8px 20px rgba(60, 40, 20, 0.08); +} + +.app-footer { + margin-top: 40px; + border-top: 1px solid #e3d8c5; + padding: 16px 0; +} + +button.card { + cursor: pointer; + transition: transform 0.15s ease, box-shadow 0.15s ease; +} + +button.card:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +button.card:hover:not(:disabled) { + transform: translateY(-2px); + box-shadow: 0 10px 24px rgba(60, 40, 20, 0.12); +} + +input, +textarea, +select { + padding: 10px 12px; + border-radius: 10px; + border: 1px solid #d9c9b2; + font: inherit; + background: #fffaf2; +} + +.modal-overlay { + position: fixed; + inset: 0; + background: rgba(20, 15, 10, 0.45); + display: flex; + align-items: center; + justify-content: center; + z-index: 50; +} + +.modal-card { + background: #fffaf2; + border-radius: 16px; + padding: 20px; + border: 1px solid #e3d8c5; + max-width: 420px; + width: 90%; +} + +.modal-actions { + display: flex; + gap: 8px; + justify-content: flex-end; + margin-top: 16px; } diff --git a/frontend/components/CategorieForm.vue b/frontend/components/CategorieForm.vue new file mode 100644 index 0000000..05646a7 --- /dev/null +++ b/frontend/components/CategorieForm.vue @@ -0,0 +1,61 @@ + + + diff --git a/frontend/components/ConfirmDialog.vue b/frontend/components/ConfirmDialog.vue new file mode 100644 index 0000000..dbe3f57 --- /dev/null +++ b/frontend/components/ConfirmDialog.vue @@ -0,0 +1,27 @@ + + + diff --git a/frontend/components/EmplacementForm.vue b/frontend/components/EmplacementForm.vue new file mode 100644 index 0000000..183b7b8 --- /dev/null +++ b/frontend/components/EmplacementForm.vue @@ -0,0 +1,63 @@ + + + diff --git a/frontend/components/EmplacementPicker.vue b/frontend/components/EmplacementPicker.vue new file mode 100644 index 0000000..fdc9f1d --- /dev/null +++ b/frontend/components/EmplacementPicker.vue @@ -0,0 +1,58 @@ + + + diff --git a/frontend/components/FileUploader.vue b/frontend/components/FileUploader.vue new file mode 100644 index 0000000..ad2b523 --- /dev/null +++ b/frontend/components/FileUploader.vue @@ -0,0 +1,94 @@ + + + diff --git a/frontend/components/I18nStub.vue b/frontend/components/I18nStub.vue new file mode 100644 index 0000000..ccc01d7 --- /dev/null +++ b/frontend/components/I18nStub.vue @@ -0,0 +1,10 @@ + + + diff --git a/frontend/components/ObjetForm.vue b/frontend/components/ObjetForm.vue new file mode 100644 index 0000000..c4b381a --- /dev/null +++ b/frontend/components/ObjetForm.vue @@ -0,0 +1,66 @@ +