Merge pull request 'Ajout du moteur de recherche' (#77) from j1/feat/recherche into dev
Reviewed-on: http://10.4.0.131/DI1-P4-E1/Webzine/pulls/77 Reviewed-by: j.vetu <josephine.vetu@diiage.org>
This commit is contained in:
@@ -10,20 +10,20 @@ namespace Webzine.Repository.Contracts
|
||||
|
||||
// void Delete(Titre titre);
|
||||
|
||||
// Titre Find(int idTitre);
|
||||
Titre? Find(int idTitre);
|
||||
|
||||
// IEnumerable<Titre> FindTitres(int offset, int limit);
|
||||
|
||||
// IEnumerable<Titre> FindAll();
|
||||
IEnumerable<Titre> FindAll();
|
||||
|
||||
// void IncrementNbLectures(Titre titre);
|
||||
|
||||
// void IncrementNbLikes(Titre titre);
|
||||
|
||||
// IEnumerable<Titre> Search(string mot);
|
||||
IEnumerable<Titre> Search(string mot);
|
||||
|
||||
// IEnumerable<Titre> SearchByStyle(string libelle);
|
||||
IEnumerable<Titre> SearchByStyle(string libelle);
|
||||
|
||||
// void Update(Titre titre);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,71 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Webzine.Entity;
|
||||
using Webzine.Entity.Fixtures;
|
||||
using Webzine.Repository.Contracts;
|
||||
|
||||
namespace Webzine.Repository;
|
||||
|
||||
public class LocalEntityRepository
|
||||
/// <summary>
|
||||
/// Classe qui permet d'initialiser un jeu de données
|
||||
/// pour tester l'application
|
||||
/// </summary>
|
||||
public class LocalEntityRepository : ITitreRepository
|
||||
{
|
||||
private readonly ILogger<LocalEntityRepository> _logger;
|
||||
private readonly List<Titre> _titres;
|
||||
|
||||
/// <summary>
|
||||
/// Initialise une nouvelle instance du <see cref="LocalEntityRepository"/> avec un service de journalisation injecté.
|
||||
/// Initialise une nouvelle instance du <see cref="LocalEntityRepository"/> avec un service de journalisation injecte.
|
||||
/// </summary>
|
||||
/// <param name="logger">Service de journalisation injecté pour suivre les opérations du repository.</param>
|
||||
/// <param name="logger">Service de journalisation injecte pour suivre les operations du repository.</param>
|
||||
public LocalEntityRepository(ILogger<LocalEntityRepository> logger)
|
||||
{
|
||||
this._logger = logger;
|
||||
this._logger.LogDebug(1, "NLog injected into LocalEntityRepository");
|
||||
_logger = logger;
|
||||
_logger.LogDebug(1, "NLog injected into LocalEntityRepository");
|
||||
|
||||
var factory = new DataFactory();
|
||||
var artistes = factory.GenerateArtists(10);
|
||||
var styles = factory.GenerateStyles(10);
|
||||
|
||||
_titres = factory.GenerateTitres(30, artistes, styles);
|
||||
factory.GenerateCommentaires(50, _titres);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Titre> Search(string mot)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(mot))
|
||||
{
|
||||
return Enumerable.Empty<Titre>();
|
||||
}
|
||||
|
||||
return _titres
|
||||
.Where(t => !string.IsNullOrWhiteSpace(t.Libelle)
|
||||
&& t.Libelle.Contains(mot, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(t => t.Libelle)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public Titre? Find(int idTitre)
|
||||
{
|
||||
return _titres.FirstOrDefault(t => t.IdTitre == idTitre);
|
||||
}
|
||||
|
||||
public IEnumerable<Titre> FindAll()
|
||||
{
|
||||
return _titres;
|
||||
}
|
||||
|
||||
public IEnumerable<Titre> SearchByStyle(string libelle)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(libelle))
|
||||
{
|
||||
return Enumerable.Empty<Titre>();
|
||||
}
|
||||
|
||||
return _titres
|
||||
.Where(t => t.Styles.Any(s => !string.IsNullOrWhiteSpace(s.Libelle)
|
||||
&& s.Libelle.Contains(libelle, StringComparison.OrdinalIgnoreCase)))
|
||||
.OrderBy(t => t.Libelle)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Webzine.Entity\Webzine.Entity.csproj" />
|
||||
<ProjectReference Include="..\Webzine.Repository.Contracts\Webzine.Repository.Contracts.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
63
Webzine.WebApplication/Controllers/RechercheController.cs
Normal file
63
Webzine.WebApplication/Controllers/RechercheController.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Webzine.Repository.Contracts;
|
||||
using Webzine.WebApplication.ViewModels.Recherche;
|
||||
using Webzine.WebApplication.ViewModels.Titre;
|
||||
|
||||
namespace Webzine.WebApplication.Controllers;
|
||||
|
||||
[Route("recherche")]
|
||||
public class RechercheController : Controller
|
||||
{
|
||||
private readonly ILogger<RechercheController> _logger;
|
||||
private readonly ITitreRepository _titreRepository;
|
||||
|
||||
public RechercheController(ILogger<RechercheController> logger, ITitreRepository titreRepository)
|
||||
{
|
||||
_logger = logger;
|
||||
_titreRepository = titreRepository;
|
||||
}
|
||||
|
||||
[HttpPost("")]
|
||||
public IActionResult Index(string mot)
|
||||
{
|
||||
_logger.LogInformation("Recherche artistes/titres pour le mot : {Mot}.", mot);
|
||||
|
||||
var titres = _titreRepository.Search(mot)
|
||||
.Concat(_titreRepository.SearchByStyle(mot))
|
||||
.DistinctBy(t => t.IdTitre)
|
||||
.OrderBy(t => t.Libelle)
|
||||
.Select(t => new TitreStyleItem
|
||||
{
|
||||
IdTitre = t.IdTitre,
|
||||
Libelle = t.Libelle,
|
||||
ArtisteNom = t.Artiste?.Nom,
|
||||
UrlJaquette = t.UrlJaquette,
|
||||
Duree = t.Duree
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var artistes = _titreRepository.FindAll()
|
||||
.Select(t => t.Artiste)
|
||||
.Where(a => a != null
|
||||
&& !string.IsNullOrWhiteSpace(a.Nom)
|
||||
&& !string.IsNullOrWhiteSpace(mot)
|
||||
&& a.Nom.Contains(mot, StringComparison.OrdinalIgnoreCase))
|
||||
.DistinctBy(a => a!.IdArtiste)
|
||||
.OrderBy(a => a!.Nom)
|
||||
.Select(a => new RechercheArtisteItem
|
||||
{
|
||||
Nom = a!.Nom,
|
||||
NombreDeTitres = a.Titres?.Count ?? 0
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var vm = new RechercheIndexViewModel
|
||||
{
|
||||
Mot = mot,
|
||||
Artistes = artistes,
|
||||
Titres = titres
|
||||
};
|
||||
|
||||
return View(vm);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,45 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Webzine.Entity;
|
||||
using Webzine.Entity.Fixtures;
|
||||
using Webzine.Repository.Contracts;
|
||||
using Webzine.WebApplication.ViewModels.Titre;
|
||||
|
||||
namespace Webzine.WebApplication.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Contrôleur responsable de la gestion des titres musicaux :
|
||||
/// affichage des détails, filtrage par style,
|
||||
/// ajout de likes et commentaires.
|
||||
/// Controleur responsable de la gestion des titres musicaux :
|
||||
/// affichage des details, filtrage par style,
|
||||
/// ajout de likes, commentaires et recherche.
|
||||
/// </summary>
|
||||
[Route("titre")]
|
||||
public class TitreController : Controller
|
||||
{
|
||||
private readonly ILogger<TitreController> _logger;
|
||||
private readonly List<Titre> _titres;
|
||||
private readonly List<Style> _styles;
|
||||
private readonly List<Artiste> _artistes;
|
||||
private readonly ITitreRepository _titreRepository;
|
||||
|
||||
/// <summary>
|
||||
/// Initialise une nouvelle instance du <see cref="TitreController"/>.
|
||||
/// Les données sont générées dynamiquement via <see cref="DataFactory"/>.
|
||||
/// </summary>
|
||||
/// <param name="logger">Service de journalisation injecté.</param>
|
||||
public TitreController(ILogger<TitreController> logger)
|
||||
/// <param name="logger">Service de journalisation injecte.</param>
|
||||
/// <param name="titreRepository">Repository des titres injecte.</param>
|
||||
public TitreController(ILogger<TitreController> logger, ITitreRepository titreRepository)
|
||||
{
|
||||
_logger = logger;
|
||||
_titreRepository = titreRepository;
|
||||
|
||||
_logger.LogInformation("Initialisation du contrôleur TitreController.");
|
||||
|
||||
var factory = new DataFactory();
|
||||
|
||||
_artistes = factory.GenerateArtists(10);
|
||||
_styles = factory.GenerateStyles(10);
|
||||
_titres = factory.GenerateTitres(30, _artistes, _styles);
|
||||
|
||||
factory.GenerateCommentaires(50, _titres);
|
||||
|
||||
_logger.LogInformation("Données fictives générées avec succès.");
|
||||
_logger.LogInformation("Initialisation du controleur TitreController.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Affiche le détail d'un titre spécifique.
|
||||
/// Affiche le detail d'un titre specifique.
|
||||
/// </summary>
|
||||
/// <param name="id">Identifiant du titre.</param>
|
||||
/// <returns>Vue des détails ou 404 si introuvable.</returns>
|
||||
/// <returns>Vue des details ou 404 si introuvable.</returns>
|
||||
[HttpGet("{id}")]
|
||||
public IActionResult Details(int id)
|
||||
{
|
||||
_logger.LogInformation("Demande d'affichage du détail pour le titre ID {Id}.", id);
|
||||
_logger.LogInformation("Demande d'affichage du detail pour le titre ID {Id}.", id);
|
||||
|
||||
var titre = _titres.FirstOrDefault(t => t.IdTitre == id);
|
||||
var titre = FindById(id);
|
||||
|
||||
if (titre == null)
|
||||
{
|
||||
@@ -83,53 +72,37 @@ public class TitreController : Controller
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Affiche les titres correspondant à un style musical donné.
|
||||
/// Affiche les titres correspondant a un style musical donne.
|
||||
/// </summary>
|
||||
/// <param name="style">Nom du style musical.</param>
|
||||
/// <returns>Vue contenant la liste filtrée.</returns>
|
||||
/// <returns>Vue contenant la liste filtree.</returns>
|
||||
[HttpGet("style/{style}")]
|
||||
public IActionResult Style(string style)
|
||||
{
|
||||
_logger.LogInformation("Recherche des titres pour le style : {Style}.", style);
|
||||
|
||||
var titresFiltres = _titres
|
||||
.Where(t => t.Styles.Any(s => s.Libelle.Equals(style)))
|
||||
.OrderBy(t => t.Libelle)
|
||||
.ToList();
|
||||
|
||||
if (!titresFiltres.Any())
|
||||
{
|
||||
_logger.LogWarning("Aucun titre trouvé pour le style : {Style}.", style);
|
||||
return NotFound();
|
||||
}
|
||||
var titresFiltres = _titreRepository.SearchByStyle(style).ToList();
|
||||
|
||||
var vm = new TitreStyle
|
||||
{
|
||||
StyleName = style,
|
||||
Titres = titresFiltres.Select(t => new TitreStyleItem
|
||||
{
|
||||
IdTitre = t.IdTitre,
|
||||
Libelle = t.Libelle,
|
||||
ArtisteNom = t.Artiste?.Nom,
|
||||
UrlJaquette = t.UrlJaquette,
|
||||
Duree = t.Duree
|
||||
}).ToList()
|
||||
Titres = titresFiltres.Select(MapTitreItem).ToList()
|
||||
};
|
||||
|
||||
return View(vm);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ajoute un like à un titre.
|
||||
/// Ajoute un like a un titre.
|
||||
/// </summary>
|
||||
/// <param name="model">Modèle contenant l'identifiant du titre.</param>
|
||||
/// <returns>Redirection vers la page détail.</returns>
|
||||
/// <param name="model">Modele contenant l'identifiant du titre.</param>
|
||||
/// <returns>Redirection vers la page detail.</returns>
|
||||
[HttpPost("like")]
|
||||
public IActionResult Like(TitreLike model)
|
||||
{
|
||||
_logger.LogInformation("Ajout d'un like pour le titre ID {Id}.", model.IdTitre);
|
||||
|
||||
var titre = _titres.FirstOrDefault(t => t.IdTitre == model.IdTitre);
|
||||
var titre = FindById(model.IdTitre);
|
||||
|
||||
if (titre == null)
|
||||
{
|
||||
@@ -143,20 +116,20 @@ public class TitreController : Controller
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ajoute un commentaire à un titre.
|
||||
/// Ajoute un commentaire a un titre.
|
||||
/// </summary>
|
||||
/// <param name="model">Données du commentaire.</param>
|
||||
/// <returns>Redirection vers la page détail.</returns>
|
||||
/// <param name="model">Donnees du commentaire.</param>
|
||||
/// <returns>Redirection vers la page detail.</returns>
|
||||
[HttpPost("comment")]
|
||||
public IActionResult Comment(TitreComment model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
_logger.LogWarning("Échec de validation du modèle de commentaire pour le titre ID {Id}.", model.IdTitre);
|
||||
_logger.LogWarning("Echec de validation du modele de commentaire pour le titre ID {Id}.", model.IdTitre);
|
||||
return RedirectToAction("Details", new { id = model.IdTitre });
|
||||
}
|
||||
|
||||
var titre = _titres.FirstOrDefault(t => t.IdTitre == model.IdTitre);
|
||||
var titre = FindById(model.IdTitre);
|
||||
|
||||
if (titre == null)
|
||||
{
|
||||
@@ -174,8 +147,25 @@ public class TitreController : Controller
|
||||
|
||||
titre.Commentaires.Add(commentaire);
|
||||
|
||||
_logger.LogInformation("Commentaire ajouté avec succès au titre ID {Id}.", model.IdTitre);
|
||||
_logger.LogInformation("Commentaire ajoute avec succes au titre ID {Id}.", model.IdTitre);
|
||||
|
||||
return RedirectToAction("Details", new { id = model.IdTitre });
|
||||
}
|
||||
}
|
||||
|
||||
private Titre? FindById(int id)
|
||||
{
|
||||
return _titreRepository.Find(id);
|
||||
}
|
||||
|
||||
private static TitreStyleItem MapTitreItem(Titre titre)
|
||||
{
|
||||
return new TitreStyleItem
|
||||
{
|
||||
IdTitre = titre.IdTitre,
|
||||
Libelle = titre.Libelle,
|
||||
ArtisteNom = titre.Artiste?.Nom,
|
||||
UrlJaquette = titre.UrlJaquette,
|
||||
Duree = titre.Duree
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using NLog;
|
||||
using NLog.Web;
|
||||
using Webzine.Repository;
|
||||
using Webzine.Repository.Contracts;
|
||||
|
||||
// Initiation du logger NLog pour la classe courante afin de pouvoir l'utiliser pour logger des messages d'information, d'erreur, etc avant la construction de l'application.
|
||||
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
||||
@@ -9,28 +11,29 @@ try
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Ajoute les services nécessaires pour permettre l'utilisation des
|
||||
// Ajoute les services necessaires pour permettre l'utilisation des
|
||||
// controllers avec des vues.
|
||||
builder.Services.AddControllersWithViews()
|
||||
// Ajoute la compilation des vues lors de l'exécution de l'application.
|
||||
// Cela nous évite de recompiler l'application à chaque modification de vue.
|
||||
// Nécessite le package Nuget Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.
|
||||
// Ajoute la compilation des vues lors de l'execution de l'application.
|
||||
// Cela nous evite de recompiler l'application a chaque modification de vue.
|
||||
// Necessite le package Nuget Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.
|
||||
.AddRazorRuntimeCompilation();
|
||||
|
||||
builder.Services.AddSingleton<ITitreRepository, LocalEntityRepository>();
|
||||
|
||||
// NLog: Setup NLog for Dependency injection
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Host.UseNLog();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Active la possibilité de servir des fichiers statiques présents dans
|
||||
// Active la possibilite de servir des fichiers statiques presents dans
|
||||
// le dossier wwwroot.
|
||||
app.UseStaticFiles();
|
||||
|
||||
// Active le middleware permettant le routage des requétes entrantes.
|
||||
// Active le middleware permettant le routage des requetes entrantes.
|
||||
app.UseRouting();
|
||||
|
||||
|
||||
// Ajoute une route pour les zones (Areas) comme Admin
|
||||
app.MapControllerRoute(
|
||||
name: "areas",
|
||||
@@ -46,7 +49,7 @@ try
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// NLog: attrape les exceptions non gérées et les logge.
|
||||
// NLog: attrape les exceptions non gerees et les logge.
|
||||
logger.Error(exception, "Stopped program because of exception");
|
||||
throw;
|
||||
}
|
||||
@@ -54,4 +57,4 @@ finally
|
||||
{
|
||||
// Assure que NLog flush tous les messages de log avant de fermer l'application.
|
||||
NLog.LogManager.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Webzine.WebApplication.ViewModels.Recherche;
|
||||
|
||||
/// <summary>
|
||||
/// ViewModel pour afficher un artiste dans les resultats de recherche.
|
||||
/// </summary>
|
||||
public class RechercheArtisteItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Nom de l'artiste.
|
||||
/// </summary>
|
||||
public string? Nom { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Nombre de titres associes a l'artiste.
|
||||
/// </summary>
|
||||
public int NombreDeTitres { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Webzine.WebApplication.ViewModels.Titre;
|
||||
|
||||
namespace Webzine.WebApplication.ViewModels.Recherche;
|
||||
|
||||
/// <summary>
|
||||
/// ViewModel pour afficher les resultats de recherche d'artistes et de titres.
|
||||
/// </summary>
|
||||
public class RechercheIndexViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Mot saisi dans le formulaire.
|
||||
/// </summary>
|
||||
public string? Mot { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Artistes trouves.
|
||||
/// </summary>
|
||||
public List<RechercheArtisteItem> Artistes { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Titres trouves.
|
||||
/// </summary>
|
||||
public List<TitreStyleItem> Titres { get; set; } = new();
|
||||
}
|
||||
@@ -82,14 +82,11 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row justify-content-end">
|
||||
<button class="btn btn-secondary col-auto mt-3">Titres plus anciens >></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-end">
|
||||
<button class="btn btn-secondary col-auto mt-3">Titres plus anciens >></button>
|
||||
</div>
|
||||
|
||||
<h1 class="mt-5">Titres les plus populaires</h1>
|
||||
|
||||
@* TEMPLATE *@
|
||||
@* <div class="container">
|
||||
<div class="row">
|
||||
@@ -105,10 +102,11 @@
|
||||
</div>
|
||||
</div> *@
|
||||
<div class="container">
|
||||
<h1 class="mt-5">Titres les plus populaires</h1>
|
||||
<div class="row">
|
||||
@foreach (var titre in Model.TopTitres)
|
||||
{
|
||||
<div class="card col-4 m-1" style="width: 18rem;">
|
||||
<div class="card col m-1" style="width: auto;">
|
||||
<img class="card-img-top"
|
||||
src="@titre.UrlJaquette" />
|
||||
|
||||
|
||||
85
Webzine.WebApplication/Views/Recherche/Index.cshtml
Normal file
85
Webzine.WebApplication/Views/Recherche/Index.cshtml
Normal file
@@ -0,0 +1,85 @@
|
||||
@model Webzine.WebApplication.ViewModels.Recherche.RechercheIndexViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Recherche";
|
||||
Layout = "_Layout";
|
||||
}
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h1 class="mb-4">Resultats pour "@Model.Mot"</h1>
|
||||
|
||||
<hr />
|
||||
|
||||
@if (string.IsNullOrWhiteSpace(Model.Mot))
|
||||
{
|
||||
<div class="alert alert-info">
|
||||
Saisissez un mot-cle pour lancer une recherche.
|
||||
</div>
|
||||
}
|
||||
else if (!Model.Artistes.Any() && !Model.Titres.Any())
|
||||
{
|
||||
<div class="alert alert-info">
|
||||
Aucun artiste ni titre ne correspond a votre recherche.
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (Model.Artistes.Any())
|
||||
{
|
||||
<h2 class="h4 mt-4">Artistes</h2>
|
||||
|
||||
@foreach (var artiste in Model.Artistes)
|
||||
{
|
||||
<div class="my-3">
|
||||
<a asp-controller="Artiste"
|
||||
asp-action="Index"
|
||||
asp-route-nom="@artiste.Nom">
|
||||
@artiste.Nom
|
||||
</a>
|
||||
<span class="text-muted">(@artiste.NombreDeTitres titre(s))</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@if (Model.Titres.Any())
|
||||
{
|
||||
<h2 class="h4 mt-4">Titres</h2>
|
||||
|
||||
@foreach (var titre in Model.Titres)
|
||||
{
|
||||
<div class="d-flex align-items-start my-3">
|
||||
<a asp-controller="Titre"
|
||||
asp-action="Details"
|
||||
asp-route-id="@titre.IdTitre"
|
||||
class="me-3 text-black">
|
||||
<img src="@titre.UrlJaquette" alt="@titre.Libelle" width="70" height="70" class="object-fit-cover" />
|
||||
</a>
|
||||
|
||||
<div class="justify-content-center d-flex flex-column">
|
||||
<div>
|
||||
<a asp-controller="Artiste"
|
||||
asp-action="Index"
|
||||
asp-route-nom="@titre.ArtisteNom">
|
||||
@titre.ArtisteNom
|
||||
</a>
|
||||
-
|
||||
<a asp-controller="Titre"
|
||||
asp-action="Details"
|
||||
asp-route-id="@titre.IdTitre">
|
||||
@titre.Libelle
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Duree : @TimeSpan.FromSeconds(titre.Duree).ToString(@"mm\:ss")
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -3,11 +3,11 @@
|
||||
*@
|
||||
@{
|
||||
}
|
||||
<div class="container text-bg-light my-2 pb-0">
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4">
|
||||
<div class="site-footer text-bg-light mt-auto">
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3">
|
||||
<div class="col-md-4 d-flex align-items-center">
|
||||
|
||||
<span class="mb-3 mb-md-0 ms-5 text-body-secondary">© ASP .NET Core - DIIAGE 2025 - 2026</span>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -62,10 +62,13 @@
|
||||
</ul>
|
||||
|
||||
<!-- Barre de recherche -->
|
||||
<form class="d-flex">
|
||||
<form class="d-flex" asp-controller="Recherche" asp-action="Index" method="post">
|
||||
<div class="input-group">
|
||||
<div class="form-outline">
|
||||
<input class="form-control me-2" type="search" placeholder="Trouver un artiste / titre">
|
||||
<input class="form-control me-2"
|
||||
type="search"
|
||||
name="mot"
|
||||
placeholder="Trouver un artiste, un titre ou un style">
|
||||
</div>
|
||||
<button class="btn btn-primary" type="submit">
|
||||
<i class="fa-solid fa-magnifying-glass"></i>
|
||||
@@ -75,4 +78,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
</header>
|
||||
|
||||
@@ -15,18 +15,20 @@
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container pb-0 mb-0">
|
||||
<div class="site-shell">
|
||||
<partial name="_Header"/>
|
||||
<div class="row mt-5">
|
||||
<main class="col">
|
||||
@RenderBody()
|
||||
</main>
|
||||
@if(ViewContext.RouteData.Values["area"]?.ToString() != "Administration")
|
||||
{
|
||||
<partial name="_Sidebar" />
|
||||
}
|
||||
<div class="container-fluid flex-grow-1 py-4">
|
||||
<div class="row g-0">
|
||||
<main class="col mx-3">
|
||||
@RenderBody()
|
||||
</main>
|
||||
@if(ViewContext.RouteData.Values["area"]?.ToString() != "Administration")
|
||||
{
|
||||
<partial name="_Sidebar" />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<partial name="_Footer" />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user