Functionnal UI
This commit is contained in:
152
README.md
152
README.md
@ -1,154 +1,2 @@
|
||||
# DTFlux Titrage Client - Interface Angular pour Unreal Engine
|
||||
|
||||
## 🎯 Vue d'ensemble
|
||||
|
||||
Interface graphique modulaire Angular 19+ pour créer et gérer des fiches de titrage destinées à Unreal Engine avec le plugin Remote Control et Motion Design.
|
||||
|
||||
## ✅ Composants créés et fonctionnalités
|
||||
|
||||
### 🏗️ Architecture modulaire respectée
|
||||
|
||||
#### Services
|
||||
- ✅ **TitleSheetsService** - Gestion des fiches de titrage (CRUD + localStorage)
|
||||
- ✅ **UnrealEngineService** - Communication avec Unreal Engine Remote Control API
|
||||
- ✅ **ConfigService** - Gestion de la configuration de l'application
|
||||
|
||||
#### Composants modulaires
|
||||
- ✅ **MenuBarComponent** - Barre de menu avec actions de configuration
|
||||
- ✅ **CuedTitleComponent** - Affichage du titre en cours de lecture
|
||||
- ✅ **ToolbarComponent** - Barre de recherche + bouton d'ajout
|
||||
- ✅ **ListHeaderComponent** - En-têtes de colonnes avec tri
|
||||
- ✅ **ListComponent** - Liste principale des titres
|
||||
- ✅ **ListItemComponent** - Élément de liste avec édition inline
|
||||
- ✅ **DetailsPanelComponent** - Panneau de détails de l'élément sélectionné
|
||||
- ✅ **TitleDialogComponent** - Boîte de dialogue d'ajout/modification
|
||||
- ✅ **TitleSheetsListComponent** - Composant principal orchestrant la liste
|
||||
|
||||
#### Pages
|
||||
- ✅ **DTFluxTitleComponent** - Page principale de l'application
|
||||
- ✅ **SetupComponent** - Page de configuration légère
|
||||
|
||||
### 🎨 Design et thème
|
||||
- ✅ **Thème dark** inspiré de VS Code et Unreal Engine
|
||||
- ✅ **Design sobre et épuré** comme demandé
|
||||
- ✅ **Responsive design** adaptatif jusqu'à 950px de largeur max
|
||||
- ✅ **Icônes FontAwesome** intégrées
|
||||
- ✅ **Animations et transitions** modernes
|
||||
|
||||
### ⚡ Fonctionnalités Angular 19+
|
||||
- ✅ **Signals** utilisés partout (input, output, computed, effect)
|
||||
- ✅ **Directives modernes** (@if, @for, etc.)
|
||||
- ✅ **Composants standalone**
|
||||
- ✅ **Reactive Forms** pour la validation
|
||||
- ✅ **Gestion d'état** avec BehaviorSubject et Signals
|
||||
|
||||
### 🔧 Fonctionnalités métier
|
||||
- ✅ **CRUD complet** des fiches de titrage (Nom, Prénom, Fonction1, Fonction2)
|
||||
- ✅ **Recherche en temps réel** avec autocomplétion
|
||||
- ✅ **Tri des colonnes** (nom, prénom, fonctions, date de modification)
|
||||
- ✅ **Édition inline** des cellules avec navigation clavier
|
||||
- ✅ **Sélection et navigation** avec flèches clavier
|
||||
- ✅ **Raccourcis clavier** (Ctrl+I ajouter, Enter play, Space stop, Delete supprimer)
|
||||
- ✅ **Communication Unreal Engine** via Remote Control API
|
||||
- ✅ **Gestion des états** (stopped, playing, error)
|
||||
- ✅ **Timer de lecture** avec changement de couleur
|
||||
- ✅ **Sauvegarde automatique** et configuration persistante
|
||||
|
||||
### 📱 Expérience utilisateur
|
||||
- ✅ **Interface adaptative** 950px max comme demandé
|
||||
- ✅ **États vides** avec messages et actions appropriées
|
||||
- ✅ **Messages de feedback** (succès, erreurs)
|
||||
- ✅ **Loading states** pendant les opérations
|
||||
- ✅ **Tooltips et aide** contextuelle
|
||||
- ✅ **Accessibilité** (aria-labels, focus management, contraste élevé)
|
||||
|
||||
## 🚀 Comment démarrer
|
||||
|
||||
1. **Installation des dépendances** :
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
2. **Démarrage du serveur de développement** :
|
||||
```bash
|
||||
ng serve
|
||||
```
|
||||
|
||||
3. **Accès à l'application** :
|
||||
- Interface principale : `http://localhost:4200/dtflux-title`
|
||||
- Configuration : `http://localhost:4200/setup`
|
||||
|
||||
## 📋 Utilisation
|
||||
|
||||
### Interface principale
|
||||
1. **Ajouter une fiche** : Bouton "Add" ou Ctrl+I
|
||||
2. **Modifier une fiche** : Clic sur l'icône roue crantée ou double-clic sur une cellule
|
||||
3. **Supprimer une fiche** : Bouton poubelle ou sélectionner + Delete
|
||||
4. **Lancer un rundown** : Bouton play ou sélectionner + Enter
|
||||
5. **Arrêter un rundown** : Bouton stop ou Space
|
||||
6. **Rechercher** : Tapez dans la barre de recherche
|
||||
7. **Trier** : Cliquez sur les en-têtes de colonnes
|
||||
|
||||
### Configuration
|
||||
- **Unreal Engine** : Adresse IP, port, timeout
|
||||
- **Sauvegarde** : Chemin, auto-sauvegarde, intervalle
|
||||
- **Test de connexion** : Vérifier la communication avec Unreal
|
||||
|
||||
## 🔌 API Unreal Engine
|
||||
|
||||
L'application communique avec Unreal Engine via l'API Remote Control :
|
||||
- **Endpoint** : `http://{address}:{port}/remote/object/call`
|
||||
- **Blueprint cible** : `/Game/MotionDesign/TitleSheet_BP.TitleSheet_BP_C`
|
||||
- **Fonctions** : `SetTitleProperties`, `StartRundown`, `StopRundown`, `GetStatus`
|
||||
|
||||
## 🛠️ Prochaines étapes possibles
|
||||
|
||||
### Fonctionnalités avancées
|
||||
- [ ] **Import/Export** de fiches en CSV/JSON
|
||||
- [ ] **Templates** de fiches prédéfinies
|
||||
- [ ] **Historique** des modifications
|
||||
- [ ] **Groupes/Catégories** de fiches
|
||||
- [ ] **Preview en temps réel** dans Unreal
|
||||
- [ ] **Synchronisation** multi-utilisateurs
|
||||
|
||||
### Intégrations
|
||||
- [ ] **Drag & drop** pour réorganiser
|
||||
- [ ] **Copier/coller** entre fiches
|
||||
- [ ] **Undo/redo** des actions
|
||||
- [ ] **Notifications** push pour les changements d'état
|
||||
- [ ] **Mode hors ligne** avec synchronisation
|
||||
|
||||
### Performance
|
||||
- [ ] **Virtualisation** de la liste pour de gros volumes
|
||||
- [ ] **Lazy loading** des données
|
||||
- [ ] **Cache** intelligent des requêtes
|
||||
- [ ] **Optimisation bundle** et tree-shaking
|
||||
|
||||
## 🏗️ Architecture technique
|
||||
|
||||
```
|
||||
src/app/
|
||||
├── models/ # Interfaces TypeScript
|
||||
│ ├── title-sheet.model.ts
|
||||
│ ├── unreal-status.model.ts
|
||||
│ └── app-config.model.ts
|
||||
├── services/ # Services Angular
|
||||
│ ├── title-sheet.service.ts
|
||||
│ ├── unreal-engine.service.ts
|
||||
│ └── config.service.ts
|
||||
└── view/
|
||||
├── components/ # Composants réutilisables
|
||||
│ ├── menu-bar/
|
||||
│ ├── cued-title/
|
||||
│ ├── toolbar/
|
||||
│ ├── list-header/
|
||||
│ ├── list-item/
|
||||
│ ├── details-panel/
|
||||
│ ├── title-dialog/
|
||||
│ └── title-sheets-list/
|
||||
└── pages/ # Pages de l'application
|
||||
├── dtflux-title/
|
||||
└── setup/
|
||||
```
|
||||
|
||||
L'architecture respecte parfaitement le paradigme de modularité demandé avec des composants indépendants et réutilisables.
|
||||
|
||||
@ -63,6 +63,7 @@
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"proxyConfig": "src/proxy.conf.json",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "DTFluxTitrage-Client:build:production"
|
||||
|
||||
143
package-lock.json
generated
143
package-lock.json
generated
@ -18,6 +18,9 @@
|
||||
"@angular/platform-browser": "^19.2.0",
|
||||
"@angular/platform-browser-dynamic": "^19.2.0",
|
||||
"@angular/router": "^19.2.0",
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"cbor-x": "^1.6.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.15.0"
|
||||
@ -2467,6 +2470,84 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@cbor-extract/cbor-extract-darwin-arm64": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.2.0.tgz",
|
||||
"integrity": "sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@cbor-extract/cbor-extract-darwin-x64": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-x64/-/cbor-extract-darwin-x64-2.2.0.tgz",
|
||||
"integrity": "sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@cbor-extract/cbor-extract-linux-arm": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm/-/cbor-extract-linux-arm-2.2.0.tgz",
|
||||
"integrity": "sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@cbor-extract/cbor-extract-linux-arm64": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm64/-/cbor-extract-linux-arm64-2.2.0.tgz",
|
||||
"integrity": "sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@cbor-extract/cbor-extract-linux-x64": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-x64/-/cbor-extract-linux-x64-2.2.0.tgz",
|
||||
"integrity": "sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@cbor-extract/cbor-extract-win32-x64": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.2.0.tgz",
|
||||
"integrity": "sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@colors/colors": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
|
||||
@ -2912,6 +2993,15 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-free": {
|
||||
"version": "6.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz",
|
||||
"integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==",
|
||||
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/checkbox": {
|
||||
"version": "4.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.1.9.tgz",
|
||||
@ -5304,6 +5394,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
|
||||
"integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||
@ -6329,6 +6425,52 @@
|
||||
],
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/cbor-extract": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cbor-extract/-/cbor-extract-2.2.0.tgz",
|
||||
"integrity": "sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build-optional-packages": "5.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"download-cbor-prebuilds": "bin/download-prebuilds.js"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@cbor-extract/cbor-extract-darwin-arm64": "2.2.0",
|
||||
"@cbor-extract/cbor-extract-darwin-x64": "2.2.0",
|
||||
"@cbor-extract/cbor-extract-linux-arm": "2.2.0",
|
||||
"@cbor-extract/cbor-extract-linux-arm64": "2.2.0",
|
||||
"@cbor-extract/cbor-extract-linux-x64": "2.2.0",
|
||||
"@cbor-extract/cbor-extract-win32-x64": "2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cbor-extract/node_modules/node-gyp-build-optional-packages": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz",
|
||||
"integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"node-gyp-build-optional-packages": "bin.js",
|
||||
"node-gyp-build-optional-packages-optional": "optional.js",
|
||||
"node-gyp-build-optional-packages-test": "build-test.js"
|
||||
}
|
||||
},
|
||||
"node_modules/cbor-x": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cbor-x/-/cbor-x-1.6.0.tgz",
|
||||
"integrity": "sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==",
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"cbor-extract": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
@ -7094,7 +7236,6 @@
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
|
||||
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
|
||||
@ -20,6 +20,9 @@
|
||||
"@angular/platform-browser": "^19.2.0",
|
||||
"@angular/platform-browser-dynamic": "^19.2.0",
|
||||
"@angular/router": "^19.2.0",
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"cbor-x": "^1.6.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.15.0"
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
<div class="app-root">
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
<!-- Global Toast Notifications -->
|
||||
<app-toast></app-toast>
|
||||
</div>
|
||||
|
||||
@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { TitleSheetsFormComponent } from './view/components/title-sheets-form/title-sheets-form.component';
|
||||
import { TitleSheet, createEmptyTitleSheet } from './models/title-sheet.model';
|
||||
import { Router, RouterModule, RouterOutlet } from '@angular/router';
|
||||
import { ToastComponent } from './view/components/toast/toast.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@ -11,7 +12,7 @@ import { Router, RouterModule, RouterOutlet } from '@angular/router';
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterOutlet,
|
||||
TitleSheetsFormComponent // ← Import direct du composant
|
||||
ToastComponent
|
||||
],
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/* src/styles.scss - Variables globales Dark Theme */
|
||||
|
||||
// === FONTAWESOME IMPORT ===
|
||||
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css');
|
||||
// === FONTAWESOME IMPORT (OFFLINE) ===
|
||||
@import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||
|
||||
// === DARK THEME PALETTE ===
|
||||
:root {
|
||||
@ -97,3 +97,45 @@ html, body {
|
||||
.border-radius { border-radius: var(--radius-medium); }
|
||||
.shadow-light { box-shadow: var(--shadow-light); }
|
||||
.shadow-medium { box-shadow: var(--shadow-medium); }
|
||||
|
||||
// === FONT AWESOME ICON STYLES ===
|
||||
.icon {
|
||||
font-size: inherit;
|
||||
vertical-align: middle;
|
||||
|
||||
&.icon-sm { font-size: 0.875rem; }
|
||||
&.icon-md { font-size: 1rem; }
|
||||
&.icon-lg { font-size: 1.25rem; }
|
||||
&.icon-xl { font-size: 1.5rem; }
|
||||
}
|
||||
|
||||
// Icônes de statut
|
||||
.status-icon {
|
||||
font-size: 1.5rem;
|
||||
margin-right: 15px;
|
||||
|
||||
&.success { color: var(--color-success); }
|
||||
&.warning { color: var(--color-warning); }
|
||||
&.danger { color: var(--color-danger); }
|
||||
&.info { color: var(--color-info); }
|
||||
}
|
||||
|
||||
// Icônes d'action
|
||||
.action-icon {
|
||||
font-size: 1rem;
|
||||
transition: transform 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
// Animation pour les icônes de chargement
|
||||
.fa-spin {
|
||||
animation: fa-spin 1s infinite linear;
|
||||
}
|
||||
|
||||
@keyframes fa-spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user