components organized

This commit is contained in:
2024-10-19 21:14:38 +02:00
Unverified
parent 28dcc102e6
commit 25fccff60d
76 changed files with 456 additions and 297 deletions

View File

@@ -9,11 +9,11 @@
<link rel="icon" type="image/png" href="favicon.png"/> <link rel="icon" type="image/png" href="favicon.png"/>
<!-- CSS --> <!-- CSS -->
<link rel="stylesheet" href="css/general.css?version=0.3.0.2"/> <link rel="stylesheet" href="css/general.css?version=0.3.0.4"/>
<link rel="stylesheet" href="css/panel.css?version=0.3.0.2"/> <link rel="stylesheet" href="css/panel.css?version=0.3.0.3"/>
<link rel="stylesheet" href="css/main_button.css?version=0.3.0.0"/> <link rel="stylesheet" href="css/main_button.css?version=0.3.0.0"/>
<link rel="stylesheet" href="css/gaps.css?version=0.3.0.0"/> <link rel="stylesheet" href="css/gaps.css?version=0.3.0.1"/>
<link rel="stylesheet" href="WatchIt.Website.styles.css?version=0.2.0.12"/> <link rel="stylesheet" href="WatchIt.Website.styles.css?version=0.2.0.13"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- BOOTSTRAP --> <!-- BOOTSTRAP -->

View File

@@ -0,0 +1,16 @@
<div class="panel">
<div class="vstack">
<div class="d-flex justify-content-center">
<div class="text-danger icon-size">⚠&#xFE0E;</div>
</div>
<div class="d-flex justify-content-center">
<h3 class="text-danger">An error occured while loading a page</h3>
</div>
@if (!string.IsNullOrWhiteSpace(ErrorMessage))
{
<div class="d-flex justify-content-center">
<p>@ErrorMessage</p>
</div>
}
</div>
</div>

View File

@@ -1,8 +1,8 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
namespace WatchIt.Website.Components; namespace WatchIt.Website.Components.Common.Panels;
public partial class ErrorComponent : ComponentBase public partial class ErrorPanelComponent : ComponentBase
{ {
#region PARAMETERS #region PARAMETERS

View File

@@ -1,4 +1,4 @@
<div class="rounded-3 panel panel-regular p-3 @(Class)"> <div class="panel @(Class)">
@if (_loaded) @if (_loaded)
{ {
<div class="vstack gap-3"> <div class="vstack gap-3">
@@ -51,7 +51,7 @@
else else
{ {
<div class="d-flex align-items-center justify-content-center h-100 content-width"> <div class="d-flex align-items-center justify-content-center h-100 content-width">
<LoadingComponent Color="white"/> <LoadingComponent Color="@(LoadingComponent.LoadingComponentColors.Light)"/>
</div> </div>
} }
</div> </div>

View File

@@ -2,15 +2,15 @@ using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms; using Microsoft.AspNetCore.Components.Forms;
using WatchIt.Common.Model; using WatchIt.Common.Model;
namespace WatchIt.Website.Components; namespace WatchIt.Website.Components.Common.Panels;
public partial class PictureEditorComponent : ComponentBase public partial class PictureEditorPanelComponent : ComponentBase
{ {
#region PARAMETERS #region PARAMETERS
[Parameter] public long? Id { get; set; } [Parameter] public long? Id { get; set; }
[Parameter] public int ContentWidth { get; set; } = 300; [Parameter] public int ContentWidth { get; set; } = 300;
[Parameter] public string PicturePlaceholder { get; set; } = "assets/poster.png"; [Parameter] public required string PicturePlaceholder { get; set; }
[Parameter] public string Class { get; set; } = string.Empty; [Parameter] public string Class { get; set; } = string.Empty;
[Parameter] public required Func<long, Action<Picture>, Task> PictureGetTask { get; set; } [Parameter] public required Func<long, Action<Picture>, Task> PictureGetTask { get; set; }
[Parameter] public required Func<long, Picture, Action<Picture>, Task> PicturePutTask { get; set; } [Parameter] public required Func<long, Picture, Action<Picture>, Task> PicturePutTask { get; set; }

View File

@@ -1,7 +1,7 @@
<div class="container-grid"> <div class="container-grid">
<div class="row"> <div class="row">
<div class="col-auto"> <div class="col-auto">
<img id="picture" class="rounded-2 shadow object-fit-cover picture-aspect-ratio" src="@(_picture is not null ? _picture.ToString() : "assets/poster.png")" alt="picture" height="@(PictureHeight)"/> <img id="picture" class="rounded-2 shadow object-fit-cover picture-aspect-ratio" src="@(_picture is not null ? _picture.ToString() : "assets/media_poster.png")" alt="picture" height="@(PictureHeight)"/>
</div> </div>
<div class="col"> <div class="col">
<div class="d-flex align-items-start flex-column h-100"> <div class="d-flex align-items-start flex-column h-100">

View File

@@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Components;
using WatchIt.Common.Model; using WatchIt.Common.Model;
using WatchIt.Common.Model.Rating; using WatchIt.Common.Model.Rating;
namespace WatchIt.Website.Components; namespace WatchIt.Website.Components.Common.Subcomponents;
public partial class ListItemComponent : ComponentBase public partial class ListItemComponent : ComponentBase
{ {

View File

@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
namespace WatchIt.Website.Components; namespace WatchIt.Website.Components.Common.Subcomponents;
public partial class LoadingButtonContentComponent : ComponentBase public partial class LoadingButtonContentComponent : ComponentBase
{ {

View File

@@ -1,8 +1,8 @@
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<div id="spinner" class="spinner-border text-@(Color)"></div> <div id="spinner" class="spinner-border text-@(GetColor())"></div>
</div> </div>
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<p id="text" class="text-@(Color)" m-0>Loading...</p> <p id="text" class="text-@(GetColor())" m-0>Loading...</p>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,47 @@
using System.ComponentModel;
using System.Reflection;
using Microsoft.AspNetCore.Components;
namespace WatchIt.Website.Components.Common.Subcomponents;
public partial class LoadingComponent : ComponentBase
{
#region PARAMETERS
[Parameter] public LoadingComponentColors Color { get; set; } = LoadingComponentColors.Dark;
#endregion
#region PRIVATE METHODS
private string GetColor()
{
DescriptionAttribute? attribute = Color.GetType()
.GetTypeInfo()
.GetMember(Color.ToString())
.FirstOrDefault(member => member.MemberType == MemberTypes.Field)!
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.SingleOrDefault()
as DescriptionAttribute;
return attribute!.Description;
}
#endregion
#region ENUMS
public enum LoadingComponentColors
{
[Description("dark")]
Dark,
[Description("light")]
Light,
}
#endregion
}

View File

@@ -0,0 +1,7 @@
<img id="imgObject" class="rounded-2 shadow object-fit-cover @(Class)" src="@(Picture is not null ? Picture.ToString() : Placeholder)" alt="@(AlternativeText)"/>
<style>
#imgObject {
aspect-ratio: @(AspectRatio.ToString());
}
</style>

View File

@@ -0,0 +1,57 @@
using Microsoft.AspNetCore.Components;
using WatchIt.Common.Model;
namespace WatchIt.Website.Components.Common.Subcomponents;
public partial class PictureComponent : ComponentBase
{
#region PARAMETERS
[Parameter] public Picture? Picture { get; set; }
[Parameter] public required string Placeholder { get; set; }
[Parameter] public PictureComponentAspectRatio AspectRatio { get; set; } = PictureComponentAspectRatio.Default;
[Parameter] public string AlternativeText { get; set; } = "picture";
[Parameter] public string Class { get; set; } = string.Empty;
#endregion
#region STRUCTS
public struct PictureComponentAspectRatio
{
#region Properties
public int Vertical { get; set; }
public int Horizontal { get; set; }
#endregion
#region Constructors
public PictureComponentAspectRatio() : this(3, 5) {}
public PictureComponentAspectRatio(int horizontal, int vertical)
{
Horizontal = horizontal;
Vertical = vertical;
}
public static PictureComponentAspectRatio Default = new PictureComponentAspectRatio();
#endregion
#region Public methods
public override string ToString() => $"{Horizontal}/{Vertical}";
#endregion
}
#endregion
}

View File

@@ -1,28 +0,0 @@
<div class="rounded-3 panel panel-regular p-4">
<div class="container-grid">
<div class="row">
<div class="col">
<div class="d-flex justify-content-center">
<div class="text-danger icon-size">⚠&#xFE0E;</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="d-flex justify-content-center">
<h3 class="text-danger">An error occured while loading a page</h3>
</div>
</div>
</div>
@if (!string.IsNullOrWhiteSpace(ErrorMessage))
{
<div class="row">
<div class="col">
<div class="d-flex justify-content-center">
<p>@ErrorMessage</p>
</div>
</div>
</div>
}
</div>
</div>

View File

@@ -1,12 +0,0 @@
using Microsoft.AspNetCore.Components;
namespace WatchIt.Website.Components;
public partial class LoadingComponent : ComponentBase
{
#region PARAMETERS
[Parameter] public string Color { get; set; } = "dark";
#endregion
}

View File

@@ -77,7 +77,7 @@
} }
else else
{ {
<ErrorComponent ErrorMessage="@_error"/> <ErrorPanelComponent ErrorMessage="@_error"/>
} }
} }
else else

View File

@@ -4,7 +4,7 @@ using WatchIt.Common.Model.Movies;
using WatchIt.Common.Model.Rating; using WatchIt.Common.Model.Rating;
using WatchIt.Common.Query; using WatchIt.Common.Query;
namespace WatchIt.Website.Components.DatabasePage; namespace WatchIt.Website.Components.Pages.DatabasePage;
public partial class DatabasePageComponent<TItem, TQuery> : ComponentBase where TItem : IQueryOrderable<TItem> where TQuery : QueryParameters<TItem> public partial class DatabasePageComponent<TItem, TQuery> : ComponentBase where TItem : IQueryOrderable<TItem> where TQuery : QueryParameters<TItem>
{ {

View File

@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using WatchIt.Common.Query; using WatchIt.Common.Query;
namespace WatchIt.Website.Components.DatabasePage; namespace WatchIt.Website.Components.Pages.DatabasePage.Subcomponents;
public abstract class FilterFormComponent<TItem, TQuery> : ComponentBase where TItem : IQueryOrderable<TItem> where TQuery : QueryParameters<TItem> public abstract class FilterFormComponent<TItem, TQuery> : ComponentBase where TItem : IQueryOrderable<TItem> where TQuery : QueryParameters<TItem>
{ {

View File

@@ -0,0 +1,37 @@
@using WatchIt.Website.Components.Pages.HomePage.Subcomponents
@typeparam TItem
<div class="panel">
<div class="vstack gap-3">
<span class="panel-text-title">Top @(Count) @(Name) this week by popularity</span>
@if (_loaded)
{
<div class="container-grid">
<div class="row">
@for (int i = 0; i < Count; i++)
{
<div class="col">
@if (_items.Count() > i)
{
<a class="text-reset text-decoration-none" href="@(string.Format(ItemUrlFormatString, IdSource(_items.ElementAt(i))))">
@{int iCopy = i;}
<ViewRankItemComponent Place="@(i + 1)"
Name="@(NameSource(_items.ElementAt(iCopy)))"
PosterPlaceholder="@(PosterPlaceholder)"
GetPosterAction="@(action => GetPictureAction(IdSource(_items.ElementAt(iCopy)), action))"/>
</a>
}
</div>
}
</div>
</div>
}
else
{
<LoadingComponent Color="@(LoadingComponent.LoadingComponentColors.Light)"/>
}
</div>
</div>

View File

@@ -0,0 +1,58 @@
using Blazorise.Components.Autocomplete;
using Microsoft.AspNetCore.Components;
using WatchIt.Common.Model;
using WatchIt.Common.Query;
namespace WatchIt.Website.Components.Pages.HomePage.Panels;
public partial class ViewRankPanelComponent<TItem> : ComponentBase
{
#region PARAMETERS
[Parameter] public int Count { get; set; } = 5;
[Parameter] public required string Name {get; set; }
[Parameter] public required Func<int, Action<IEnumerable<TItem>>, Task> GetViewRankAction { get; set; }
[Parameter] public required string ItemUrlFormatString { get; set; }
[Parameter] public required Func<TItem, long> IdSource { get; set; }
[Parameter] public required Func<TItem, string> NameSource { get; set; }
[Parameter] public required string PosterPlaceholder {get; set; }
[Parameter] public required Func<long, Action<Picture>, Task> GetPictureAction { get; set; }
#endregion
#region FIELDS
private bool _loaded;
private IEnumerable<TItem> _items = default!;
#endregion
#region PRIVATE METHODS
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
List<Task> endTasks = new List<Task>();
// STEP 0
endTasks.AddRange(
[
GetViewRankAction(Count, data => _items = data)
]);
// END
await Task.WhenAll(endTasks);
_loaded = true;
StateHasChanged();
}
}
#endregion
}

View File

@@ -0,0 +1,13 @@
<div class="d-flex flex-column align-items-center gap-2 h-100">
<PictureComponent Class="w-100" Picture="@(_poster)" Placeholder="@(PosterPlaceholder)" AlternativeText="poster"/>
<div class="container-grid">
<div class="row">
<div class="col-auto">
<div class="text-center border border-2 border-light rounded-circle place-circle fw-bold">@(Place)</div>
</div>
<div class="col">
<div class="text-end ms-auto pt-05">@(Name)</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,49 @@
using Microsoft.AspNetCore.Components;
using WatchIt.Common.Model;
namespace WatchIt.Website.Components.Pages.HomePage.Subcomponents;
public partial class ViewRankItemComponent : ComponentBase
{
#region PARAMETERS
[Parameter] public required int Place { get; set; }
[Parameter] public required string Name { get; set; }
[Parameter] public required string PosterPlaceholder { get; set; }
[Parameter] public required Func<Action<Picture>, Task> GetPosterAction { get; set; }
#endregion
#region FIELDS
private Picture? _poster;
#endregion
#region PRIVATE METHODS
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
List<Task> endTasks = new List<Task>();
// STEP 0
endTasks.AddRange(
[
GetPosterAction(data => _poster = data),
]);
// END
await Task.WhenAll(endTasks);
StateHasChanged();
}
}
#endregion
}

View File

@@ -0,0 +1,12 @@
/* CLASSES */
.border-2 {
border-width: 2px;
}
.place-circle {
width: 30px;
height: 30px;
vertical-align: middle;
line-height: 25px;
}

View File

@@ -5,7 +5,7 @@
<div class="rounded-3 panel panel-regular p-3 @(Class)"> <div class="panel @(Class)">
@if (_loaded) @if (_loaded)
{ {
<div class="vstack gap-3"> <div class="vstack gap-3">
@@ -151,6 +151,6 @@
} }
else else
{ {
<LoadingComponent Color="white"/> <LoadingComponent Color="@(LoadingComponent.LoadingComponentColors.Light)"/>
} }
</div> </div>

View File

@@ -6,9 +6,9 @@ using WatchIt.Website.Services.WebAPI.Media;
using WatchIt.Website.Services.WebAPI.Persons; using WatchIt.Website.Services.WebAPI.Persons;
using WatchIt.Website.Services.WebAPI.Roles; using WatchIt.Website.Services.WebAPI.Roles;
namespace WatchIt.Website.Components.MediaEditPage; namespace WatchIt.Website.Components.Pages.MediaEditPage.Panels;
public partial class MediaRolesEditActorComponent : ComponentBase public partial class MediaActorRolesEditPanelComponent : ComponentBase
{ {
#region SERVICES #region SERVICES

View File

@@ -3,7 +3,7 @@
@using WatchIt.Common.Model.Persons @using WatchIt.Common.Model.Persons
<div class="rounded-3 panel panel-regular p-3 @(Class)"> <div class="panel @(Class)">
@if (_loaded) @if (_loaded)
{ {
<div class="vstack gap-3"> <div class="vstack gap-3">
@@ -137,6 +137,6 @@
} }
else else
{ {
<LoadingComponent Color="white"/> <LoadingComponent Color="@(LoadingComponent.LoadingComponentColors.Light)"/>
} }
</div> </div>

View File

@@ -6,9 +6,9 @@ using WatchIt.Website.Services.WebAPI.Media;
using WatchIt.Website.Services.WebAPI.Persons; using WatchIt.Website.Services.WebAPI.Persons;
using WatchIt.Website.Services.WebAPI.Roles; using WatchIt.Website.Services.WebAPI.Roles;
namespace WatchIt.Website.Components.MediaEditPage; namespace WatchIt.Website.Components.Pages.MediaEditPage.Panels;
public partial class MediaRolesEditCreatorComponent : ComponentBase public partial class MediaCreatorRolesEditPanelComponent : ComponentBase
{ {
#region SERVICES #region SERVICES

View File

@@ -1,3 +1,7 @@
@using WatchIt.Website.Components.Pages.MediaPage.Subcomponents
<div class="panel panel-padding-regular panel-radius-regular panel-background-regular @(Class)"> <div class="panel panel-padding-regular panel-radius-regular panel-background-regular @(Class)">
<div class="vstack gap-3"> <div class="vstack gap-3">
<span class="panel-text-title">Actors</span> <span class="panel-text-title">Actors</span>

View File

@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using WatchIt.Website.Services.WebAPI.Media; using WatchIt.Website.Services.WebAPI.Media;
namespace WatchIt.Website.Components.MediaPage; namespace WatchIt.Website.Components.Pages.MediaPage.Panels;
public partial class ActorRolesPanelComponent : ComponentBase public partial class ActorRolesPanelComponent : ComponentBase
{ {

View File

@@ -1,4 +1,5 @@
@using WatchIt.Common.Model.Roles @using WatchIt.Common.Model.Roles
@using WatchIt.Website.Components.Pages.MediaPage.Subcomponents
@@ -25,6 +26,6 @@
} }
else else
{ {
<LoadingComponent Color="white"/> <LoadingComponent Color="@(LoadingComponent.LoadingComponentColors.Light)"/>
} }
</div> </div>

View File

@@ -1,9 +1,10 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using WatchIt.Common.Model.Roles; using WatchIt.Common.Model.Roles;
using WatchIt.Website.Components.Pages.MediaPage.Subcomponents;
using WatchIt.Website.Services.WebAPI.Media; using WatchIt.Website.Services.WebAPI.Media;
using WatchIt.Website.Services.WebAPI.Roles; using WatchIt.Website.Services.WebAPI.Roles;
namespace WatchIt.Website.Components.MediaPage; namespace WatchIt.Website.Components.Pages.MediaPage.Panels;
public partial class CreatorRolesPanelComponent : ComponentBase public partial class CreatorRolesPanelComponent : ComponentBase
{ {

View File

@@ -4,7 +4,7 @@ using WatchIt.Common.Model.Persons;
using WatchIt.Common.Model.Roles; using WatchIt.Common.Model.Roles;
using WatchIt.Website.Services.WebAPI.Persons; using WatchIt.Website.Services.WebAPI.Persons;
namespace WatchIt.Website.Components.MediaPage; namespace WatchIt.Website.Components.Pages.MediaPage.Subcomponents;
public partial class RoleComponent<TRole> : ComponentBase where TRole : IRoleResponse public partial class RoleComponent<TRole> : ComponentBase where TRole : IRoleResponse
{ {

View File

@@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Components;
using WatchIt.Common.Model.Roles; using WatchIt.Common.Model.Roles;
using WatchIt.Common.Query; using WatchIt.Common.Query;
namespace WatchIt.Website.Components.MediaPage; namespace WatchIt.Website.Components.Pages.MediaPage.Subcomponents;
public partial class RoleListComponent<TRole, TQuery> : ComponentBase where TRole : IRoleResponse, IQueryOrderable<TRole> where TQuery : QueryParameters<TRole> public partial class RoleListComponent<TRole, TQuery> : ComponentBase where TRole : IRoleResponse, IQueryOrderable<TRole> where TQuery : QueryParameters<TRole>
{ {

View File

@@ -4,7 +4,7 @@
<div class="rounded-3 panel panel-regular p-3 @(Class)"> <div class="panel @(Class)">
@if (_loaded) @if (_loaded)
{ {
<div class="vstack gap-3"> <div class="vstack gap-3">
@@ -156,6 +156,6 @@
} }
else else
{ {
<LoadingComponent Color="white"/> <LoadingComponent Color="@(LoadingComponent.LoadingComponentColors.Light)"/>
} }
</div> </div>

View File

@@ -5,9 +5,9 @@ using WatchIt.Website.Services.WebAPI.Media;
using WatchIt.Website.Services.WebAPI.Persons; using WatchIt.Website.Services.WebAPI.Persons;
using WatchIt.Website.Services.WebAPI.Roles; using WatchIt.Website.Services.WebAPI.Roles;
namespace WatchIt.Website.Components.PersonEditPage; namespace WatchIt.Website.Components.Pages.PersonEditPage.Panels;
public partial class PersonRolesEditActorComponent : ComponentBase public partial class PersonActorRolesEditPanelComponent : ComponentBase
{ {
#region SERVICES #region SERVICES

View File

@@ -3,7 +3,7 @@
<div class="rounded-3 panel panel-regular p-3 @(Class)"> <div class="panel @(Class)">
@if (_loaded) @if (_loaded)
{ {
<div class="vstack gap-3"> <div class="vstack gap-3">
@@ -143,6 +143,6 @@
} }
else else
{ {
<LoadingComponent Color="white"/> <LoadingComponent Color="@(LoadingComponent.LoadingComponentColors.Light)"/>
} }
</div> </div>

View File

@@ -5,9 +5,9 @@ using WatchIt.Website.Services.WebAPI.Media;
using WatchIt.Website.Services.WebAPI.Persons; using WatchIt.Website.Services.WebAPI.Persons;
using WatchIt.Website.Services.WebAPI.Roles; using WatchIt.Website.Services.WebAPI.Roles;
namespace WatchIt.Website.Components.PersonEditPage; namespace WatchIt.Website.Components.Pages.PersonEditPage.Panels;
public partial class PersonRolesEditCreatorComponent : ComponentBase public partial class PersonCreatorRolesEditPanelComponent : ComponentBase
{ {
#region SERVICES #region SERVICES

View File

@@ -1,5 +1,8 @@
@using WatchIt.Common.Model.Genders @using WatchIt.Common.Model.Genders
<div class="rounded-3 panel panel-regular p-3 @(Class)">
<div class="panel @(Class)">
@if (_loaded) @if (_loaded)
{ {
<EditForm Model="_person"> <EditForm Model="_person">
@@ -71,6 +74,6 @@
} }
else else
{ {
<LoadingComponent Color="white"/> <LoadingComponent Color="@(LoadingComponent.LoadingComponentColors.Light)"/>
} }
</div> </div>

View File

@@ -4,9 +4,9 @@ using WatchIt.Common.Model.Persons;
using WatchIt.Website.Services.WebAPI.Genders; using WatchIt.Website.Services.WebAPI.Genders;
using WatchIt.Website.Services.WebAPI.Persons; using WatchIt.Website.Services.WebAPI.Persons;
namespace WatchIt.Website.Components.PersonEditPage; namespace WatchIt.Website.Components.Pages.PersonEditPage.Panels;
public partial class PersonEditFormComponent : ComponentBase public partial class PersonEditFormPanelComponent : ComponentBase
{ {
#region SERVICES #region SERVICES

View File

@@ -5,7 +5,7 @@
<div class="rounded-3 panel panel-regular p-4"> <div class="panel">
<div class="container-grid"> <div class="container-grid">
<div class="row mb-4"> <div class="row mb-4">
<div class="col"> <div class="col">
@@ -74,7 +74,7 @@
{ {
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<LoadingComponent Color="light"/> <LoadingComponent Color="@(LoadingComponent.LoadingComponentColors.Light)"/>
</div> </div>
</div> </div>
} }

View File

@@ -3,9 +3,9 @@ using WatchIt.Common.Model;
using WatchIt.Common.Model.Rating; using WatchIt.Common.Model.Rating;
using WatchIt.Common.Query; using WatchIt.Common.Query;
namespace WatchIt.Website.Components.SearchPage; namespace WatchIt.Website.Components.Pages.SearchPage.Panels;
public partial class SearchResultComponent<TItem, TQuery> : ComponentBase where TQuery : QueryParameters public partial class SearchResultPanelComponent<TItem, TQuery> : ComponentBase where TQuery : QueryParameters
{ {
#region PARAMETERS #region PARAMETERS

View File

@@ -28,7 +28,7 @@
{ {
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<ErrorComponent ErrorMessage="You do not have permission to view this site"/> <ErrorPanelComponent ErrorMessage="You do not have permission to view this site"/>
</div> </div>
</div> </div>
} }

View File

@@ -1,6 +1,7 @@
@using WatchIt.Common.Model.Movies @using WatchIt.Common.Model.Movies
@using WatchIt.Common.Model.Series @using WatchIt.Common.Model.Series
@using WatchIt.Website.Components.DatabasePage @using WatchIt.Website.Components.Pages.DatabasePage
@using WatchIt.Website.Components.Pages.DatabasePage.Subcomponents
@page "/database/{type?}" @page "/database/{type?}"

View File

@@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using WatchIt.Website.Components.DatabasePage;
using WatchIt.Website.Services.WebAPI.Media; using WatchIt.Website.Services.WebAPI.Media;
using WatchIt.Website.Services.WebAPI.Movies; using WatchIt.Website.Services.WebAPI.Movies;
using WatchIt.Website.Services.WebAPI.Series; using WatchIt.Website.Services.WebAPI.Series;

View File

@@ -1,106 +1,37 @@
@page "/" @using WatchIt.Common.Model.Movies
@using WatchIt.Common.Model.Persons
@using WatchIt.Common.Model.Series
@using WatchIt.Website.Components.Pages.HomePage.Panels
@page "/"
<PageTitle>WatchIt</PageTitle> <PageTitle>WatchIt</PageTitle>
<div class="container-grid">
@if (_loaded)
{ <div class="vstack gap-default">
if (string.IsNullOrWhiteSpace(_error)) <ViewRankPanelComponent TItem="MovieResponse"
{ Name="movies"
<div class="row"> GetViewRankAction="@((count, action) => MoviesWebAPIService.GetMoviesViewRank(count, successAction: action))"
<div class="col"> ItemUrlFormatString="/media/{0}"
<div class="rounded-3 panel panel-regular p-4"> IdSource="@(item => item.Id)"
<div class="container-grid"> NameSource="@(item => item.ReleaseDate.HasValue ? $"{item.Title} ({item.ReleaseDate.Value.Year})" : item.Title)"
<div class="row"> PosterPlaceholder="/assets/media_poster.png"
<div class="col"> GetPictureAction="@((id, action) => MediaWebAPIService.GetMediaPoster(id, action))"/>
<h4><strong>Top 5 movies this week by popularity</strong></h4> <ViewRankPanelComponent TItem="SeriesResponse"
</div> Name="TV series"
</div> GetViewRankAction="@((count, action) => SeriesWebAPIService.GetSeriesViewRank(count, successAction: action))"
<div class="row mt-3"> ItemUrlFormatString="/media/{0}"
@for (int i = 0; i < 5; i++) IdSource="@(item => item.Id)"
{ NameSource="@(item => item.ReleaseDate.HasValue ? $"{item.Title} ({item.ReleaseDate.Value.Year})" : item.Title)"
<div class="col"> PosterPlaceholder="/assets/media_poster.png"
@if (_topMovies.Count > i) GetPictureAction="@((id, action) => MediaWebAPIService.GetMediaPoster(id, action))"/>
{ <ViewRankPanelComponent TItem="PersonResponse"
<a class="text-reset text-decoration-none" href="/media/@_topMovies.ToArray()[i].Key.Id"> Name="people"
<div class="d-flex flex-column align-items-center gap-2 h-100"> GetViewRankAction="@((count, action) => PersonsWebAPIService.GetPersonsViewRank(count, successAction: action))"
<img class="rounded-2 shadow object-fit-cover poster-aspect-ratio" src="@(_topMovies.ToArray()[i].Value is not null ? _topMovies.ToArray()[i].Value.ToString() : "assets/poster.png")" alt="poster" width="100%"/> ItemUrlFormatString="/person/{0}"
<div class="container-grid"> IdSource="@(item => item.Id)"
<div class="row"> NameSource="@(item => item.Name)"
<div class="col-auto"> PosterPlaceholder="/assets/person_poster.png"
<div class="text-center border border-2 border-light rounded-circle place-circle"><strong>@(i + 1)</strong></div> GetPictureAction="@((id, action) => PersonsWebAPIService.GetPersonPhoto(id, action))"/>
</div>
<div class="col">
<div class="text-end ms-auto">@_topMovies.ToArray()[i].Key.Title@(_topMovies.ToArray()[i].Key.ReleaseDate.HasValue ? $" ({_topMovies.ToArray()[i].Key.ReleaseDate.Value.Year})" : string.Empty)</div>
</div>
</div>
</div>
</div>
</a>
}
</div>
}
</div>
</div>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col">
<div class="rounded-3 panel panel-regular p-4">
<div class="container-grid">
<div class="row">
<div class="col">
<h4><strong>Top 5 TV series this week by popularity</strong></h4>
</div>
</div>
<div class="row mt-3">
@for (int i = 0; i < 5; i++)
{
<div class="col">
@if (_topSeries.Count > i)
{
<a class="text-reset text-decoration-none" href="/media/@_topSeries.ToArray()[i].Key.Id">
<div class="d-flex flex-column align-items-center gap-2 h-100">
<img class="rounded-2 shadow object-fit-cover poster-aspect-ratio" src="@(_topSeries.ToArray()[i].Value is not null ? _topSeries.ToArray()[i].Value.ToString() : "assets/poster.png")" alt="poster" width="100%"/>
<div class="container-grid">
<div class="row">
<div class="col-auto">
<div class="text-center border border-2 border-light rounded-circle place-circle"><strong>@(i + 1)</strong></div>
</div>
<div class="col">
<div class="text-end ms-auto">@_topSeries.ToArray()[i].Key.Title@(_topSeries.ToArray()[i].Key.ReleaseDate.HasValue ? $" ({_topSeries.ToArray()[i].Key.ReleaseDate.Value.Year})" : string.Empty)</div>
</div>
</div>
</div>
</div>
</a>
}
</div>
}
</div>
</div>
</div>
</div>
</div>
}
else
{
<div class="row">
<div class="col">
<ErrorComponent ErrorMessage="@_error"/>
</div>
</div>
}
}
else
{
<div class="row">
<div class="col">
<div class="m-5">
<LoadingComponent/>
</div>
</div>
</div>
}
</div> </div>

View File

@@ -5,6 +5,7 @@ using WatchIt.Common.Model.Series;
using WatchIt.Website.Layout; using WatchIt.Website.Layout;
using WatchIt.Website.Services.WebAPI.Media; using WatchIt.Website.Services.WebAPI.Media;
using WatchIt.Website.Services.WebAPI.Movies; using WatchIt.Website.Services.WebAPI.Movies;
using WatchIt.Website.Services.WebAPI.Persons;
using WatchIt.Website.Services.WebAPI.Series; using WatchIt.Website.Services.WebAPI.Series;
namespace WatchIt.Website.Pages; namespace WatchIt.Website.Pages;
@@ -17,6 +18,7 @@ public partial class HomePage
[Inject] public IMediaWebAPIService MediaWebAPIService { get; set; } = default!; [Inject] public IMediaWebAPIService MediaWebAPIService { get; set; } = default!;
[Inject] public IMoviesWebAPIService MoviesWebAPIService { get; set; } = default!; [Inject] public IMoviesWebAPIService MoviesWebAPIService { get; set; } = default!;
[Inject] public ISeriesWebAPIService SeriesWebAPIService { get; set; } = default!; [Inject] public ISeriesWebAPIService SeriesWebAPIService { get; set; } = default!;
[Inject] public IPersonsWebAPIService PersonsWebAPIService { get; set; } = default!;
#endregion #endregion
@@ -24,19 +26,7 @@ public partial class HomePage
#region PARAMETERS #region PARAMETERS
[CascadingParameter] public MainLayout Layout { get; set; } [CascadingParameter] public MainLayout Layout { get; set; } = default!;
#endregion
#region FIELDS
private bool _loaded;
private string? _error;
private IDictionary<MovieResponse, MediaPosterResponse?> _topMovies = new Dictionary<MovieResponse, MediaPosterResponse?>();
private IDictionary<SeriesResponse, MediaPosterResponse?> _topSeries = new Dictionary<SeriesResponse, MediaPosterResponse?>();
#endregion #endregion
@@ -44,34 +34,12 @@ public partial class HomePage
#region PRIVATE METHODS #region PRIVATE METHODS
protected override async Task OnAfterRenderAsync(bool firstRender) protected override void OnAfterRender(bool firstRender)
{ {
if (firstRender) if (firstRender)
{ {
Layout.BackgroundPhoto = null; Layout.BackgroundPhoto = null;
List<Task> step1Tasks = new List<Task>();
List<Task> endTasks = new List<Task>();
// STEP 0
step1Tasks.AddRange(
[
MoviesWebAPIService.GetMoviesViewRank(successAction: data => _topMovies = data.ToDictionary(x => x, _ => default(MediaPosterResponse?))),
SeriesWebAPIService.GetSeriesViewRank(successAction: data => _topSeries = data.ToDictionary(x => x, _ => default(MediaPosterResponse?))),
]);
// STEP 1
await Task.WhenAll(step1Tasks);
endTasks.AddRange(
[
Parallel.ForEachAsync(_topMovies, async (x, _) => await MediaWebAPIService.GetMediaPoster(x.Key.Id, y => _topMovies[x.Key] = y)),
Parallel.ForEachAsync(_topSeries, async (x, _) => await MediaWebAPIService.GetMediaPoster(x.Key.Id, y => _topSeries[x.Key] = y))
]);
// END
await Task.WhenAll(endTasks);
_loaded = true;
StateHasChanged(); StateHasChanged();
} }
} }

View File

@@ -1,16 +0,0 @@
/* CLASSES */
.poster-aspect-ratio {
aspect-ratio: 3/5;
}
.border-2 {
border-width: 2px;
}
.place-circle {
width: 30px;
height: 30px;
vertical-align: middle;
line-height: 25px;
}

View File

@@ -2,6 +2,7 @@
@using WatchIt.Common.Model.Movies @using WatchIt.Common.Model.Movies
@using WatchIt.Common.Model.Photos @using WatchIt.Common.Model.Photos
@using WatchIt.Common.Model.Series @using WatchIt.Common.Model.Series
@using WatchIt.Website.Components.Pages.MediaEditPage.Panels
@page "/media/{id:long}/edit" @page "/media/{id:long}/edit"
@page "/media/new/{type?}" @page "/media/new/{type?}"
@@ -60,7 +61,7 @@
<div class="container-grid"> <div class="container-grid">
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<img class="rounded-2 shadow object-fit-cover" src="@(_mediaPosterRequest is not null ? _mediaPosterRequest.ToString() : "assets/poster.png")" alt="poster" width="300" height="500"/> <img class="rounded-2 shadow object-fit-cover" src="@(_mediaPosterRequest is not null ? _mediaPosterRequest.ToString() : "assets/media_poster.png")" alt="poster" width="300" height="500"/>
</div> </div>
</div> </div>
<div class="row mt-4"> <div class="row mt-4">
@@ -201,14 +202,14 @@
</div> </div>
<div class="row mt-3"> <div class="row mt-3">
<div class="col"> <div class="col">
<MediaRolesEditActorComponent Id="@(Id)" <MediaActorRolesEditPanelComponent Id="@(Id)"
Persons="@(_persons)"/> Persons="@(_persons)"/>
</div> </div>
</div> </div>
<div class="row mt-3"> <div class="row mt-3">
<div class="col"> <div class="col">
<MediaRolesEditCreatorComponent Id="@(Id)" <MediaCreatorRolesEditPanelComponent Id="@(Id)"
Persons="@(_persons)"/> Persons="@(_persons)"/>
</div> </div>
</div> </div>
<div class="row mt-3"> <div class="row mt-3">
@@ -376,7 +377,7 @@
{ {
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<ErrorComponent ErrorMessage="You do not have permission to view this site"/> <ErrorPanelComponent ErrorMessage="You do not have permission to view this site"/>
</div> </div>
</div> </div>
} }
@@ -385,7 +386,7 @@
{ {
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<ErrorComponent ErrorMessage="@_error"/> <ErrorPanelComponent ErrorMessage="@_error"/>
</div> </div>
</div> </div>
} }

View File

@@ -1,6 +1,7 @@
@using System.Text @using System.Text
@using Microsoft.IdentityModel.Tokens @using Microsoft.IdentityModel.Tokens
@using WatchIt.Common.Model.Genres @using WatchIt.Common.Model.Genres
@using WatchIt.Website.Components.Pages.MediaPage.Panels
@page "/media/{id:long}" @page "/media/{id:long}"
@@ -31,7 +32,7 @@ else
{ {
<div class="row mt-9"> <div class="row mt-9">
<div class="col-auto"> <div class="col-auto">
<img class="rounded-2 shadow object-fit-cover" src="@(_poster is not null ? _poster.ToString() : "assets/poster.png")" alt="poster" width="200" height="333"/> <img class="rounded-2 shadow object-fit-cover" src="@(_poster is not null ? _poster.ToString() : "assets/media_poster.png")" alt="poster" width="200" height="333"/>
</div> </div>
<div class="col"> <div class="col">
<div class="d-flex h-100"> <div class="d-flex h-100">
@@ -220,7 +221,7 @@ else
{ {
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<ErrorComponent ErrorMessage="@_error"/> <ErrorPanelComponent ErrorMessage="@_error"/>
</div> </div>
</div> </div>
} }

View File

@@ -1,4 +1,5 @@
@using WatchIt.Common.Model.Persons @using WatchIt.Common.Model.Persons
@using WatchIt.Website.Components.Pages.PersonEditPage.Panels
@page "/person/{id:long}/edit" @page "/person/{id:long}/edit"
@page "/person/new" @page "/person/new"
@@ -47,35 +48,35 @@
</div> </div>
<div class="row mt-3 gx-3"> <div class="row mt-3 gx-3">
<div class="col-auto"> <div class="col-auto">
<PictureEditorComponent Id="@(Id)" <PictureEditorPanelComponent Id="@(Id)"
PictureGetTask="@(async (id, action) => await PersonsWebAPIService.GetPersonPhoto(id, action))" PictureGetTask="@(async (id, action) => await PersonsWebAPIService.GetPersonPhoto(id, action))"
PicturePutTask="@(async (id, data, action) => await PersonsWebAPIService.PutPersonPhoto(id, new PersonPhotoRequest(data), action))" PicturePutTask="@(async (id, data, action) => await PersonsWebAPIService.PutPersonPhoto(id, new PersonPhotoRequest(data), action))"
PictureDeleteTask="@(async (id, action) => await PersonsWebAPIService.DeletePersonPhoto(id, action))" PictureDeleteTask="@(async (id, action) => await PersonsWebAPIService.DeletePersonPhoto(id, action))"
PicturePlaceholder="/assets/person_picture.png" PicturePlaceholder="/assets/person_picture.png"
Class="h-100"/> Class="h-100"/>
</div> </div>
<div class="col"> <div class="col">
<PersonEditFormComponent Id="@(Id)" <PersonEditFormPanelComponent Id="@(Id)"
Class="h-100"/> Class="h-100"/>
</div> </div>
</div> </div>
<div class="row mt-3"> <div class="row mt-3">
<div class="col"> <div class="col">
<PersonRolesEditActorComponent Id="@(Id)" <PersonActorRolesEditPanelComponent Id="@(Id)"
Media="@(_media)"/> Media="@(_media)"/>
</div> </div>
</div> </div>
<div class="row mt-3"> <div class="row mt-3">
<div class="col"> <div class="col">
<PersonRolesEditCreatorComponent Id="@(Id)" <PersonCreatorRolesEditPanelComponent Id="@(Id)"
Media="@(_media)"/> Media="@(_media)"/>
</div> </div>
</div> </div>
</div> </div>
} }
else else
{ {
<ErrorComponent ErrorMessage="You do not have permission to view this site"/> <ErrorPanelComponent ErrorMessage="You do not have permission to view this site"/>
} }
} }
else else

View File

@@ -1,7 +1,7 @@
@using WatchIt.Common.Model.Movies @using WatchIt.Common.Model.Movies
@using WatchIt.Common.Model.Series @using WatchIt.Common.Model.Series
@using WatchIt.Common.Query @using WatchIt.Common.Query
@using WatchIt.Website.Components.SearchPage @using WatchIt.Website.Components.Pages.SearchPage.Panels
@using WatchIt.Website.Services.WebAPI.Movies @using WatchIt.Website.Services.WebAPI.Movies
@layout MainLayout @layout MainLayout
@@ -30,32 +30,32 @@
</div> </div>
<div class="row mt-3"> <div class="row mt-3">
<div class="col"> <div class="col">
<SearchResultComponent TItem="MovieResponse" <SearchResultPanelComponent TItem="MovieResponse"
TQuery="MovieQueryParameters" TQuery="MovieQueryParameters"
Title="Movies" Title="Movies"
UrlIdTemplate="/media/{0}" UrlIdTemplate="/media/{0}"
IdSource="@(item => item.Id)" IdSource="@(item => item.Id)"
NameSource="@(item => item.Title)" NameSource="@(item => item.Title)"
AdditionalNameInfoSource="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)" AdditionalNameInfoSource="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
RatingSource="@(item => item.Rating)" RatingSource="@(item => item.Rating)"
Query="@(new MovieQueryParameters { Title = DecodedQuery, OrderBy = "rating.count" })" Query="@(new MovieQueryParameters { Title = DecodedQuery, OrderBy = "rating.count" })"
ItemDownloadingTask="@(MoviesWebAPIService.GetAllMovies)" ItemDownloadingTask="@(MoviesWebAPIService.GetAllMovies)"
PictureDownloadingTask="@((id, action) => MediaWebAPIService.GetMediaPoster(id, action))"/> PictureDownloadingTask="@((id, action) => MediaWebAPIService.GetMediaPoster(id, action))"/>
</div> </div>
</div> </div>
<div class="row mt-3"> <div class="row mt-3">
<div class="col"> <div class="col">
<SearchResultComponent TItem="SeriesResponse" <SearchResultPanelComponent TItem="SeriesResponse"
TQuery="SeriesQueryParameters" TQuery="SeriesQueryParameters"
Title="TV series" Title="TV series"
UrlIdTemplate="/media/{0}" UrlIdTemplate="/media/{0}"
IdSource="@(item => item.Id)" IdSource="@(item => item.Id)"
NameSource="@(item => item.Title)" NameSource="@(item => item.Title)"
AdditionalNameInfoSource="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)" AdditionalNameInfoSource="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
RatingSource="@(item => item.Rating)" RatingSource="@(item => item.Rating)"
Query="@(new SeriesQueryParameters { Title = DecodedQuery, OrderBy = "rating.count" })" Query="@(new SeriesQueryParameters { Title = DecodedQuery, OrderBy = "rating.count" })"
ItemDownloadingTask="@(SeriesWebAPIService.GetAllSeries)" ItemDownloadingTask="@(SeriesWebAPIService.GetAllSeries)"
PictureDownloadingTask="@((id, action) => MediaWebAPIService.GetMediaPoster(id, action))"/> PictureDownloadingTask="@((id, action) => MediaWebAPIService.GetMediaPoster(id, action))"/>
</div> </div>
</div> </div>
} }
@@ -63,7 +63,7 @@
{ {
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<ErrorComponent ErrorMessage="@(_error)"/> <ErrorPanelComponent ErrorMessage="@(_error)"/>
</div> </div>
</div> </div>
} }

View File

@@ -51,4 +51,8 @@
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="1.6.1" /> <PackageReference Include="Blazorise.Icons.FontAwesome" Version="1.6.1" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Components\DatabasePage\" />
</ItemGroup>
</Project> </Project>

View File

@@ -8,10 +8,8 @@
@using Microsoft.JSInterop @using Microsoft.JSInterop
@using WatchIt.Website @using WatchIt.Website
@using WatchIt.Website.Layout @using WatchIt.Website.Layout
@using WatchIt.Website.Components @using WatchIt.Website.Components.Common.Subcomponents
@using WatchIt.Website.Components.PersonEditPage @using WatchIt.Website.Components.Common.Panels
@using WatchIt.Website.Components.MediaEditPage
@using WatchIt.Website.Components.MediaPage
@using WatchIt.Common.Model.Accounts @using WatchIt.Common.Model.Accounts
@using WatchIt.Common.Model.Media @using WatchIt.Common.Model.Media
@using WatchIt.Website.Services.Utility.Tokens @using WatchIt.Website.Services.Utility.Tokens

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 KiB

View File

@@ -8,6 +8,10 @@
--bs-gutter-x: 1rem !important; --bs-gutter-x: 1rem !important;
} }
.gap-default {
gap: 1rem;
}
/* OTHERS */ /* OTHERS */

View File

@@ -82,7 +82,9 @@ body, html {
background-color: rgba(255, 184, 58, 0.6) !important; background-color: rgba(255, 184, 58, 0.6) !important;
} }
.pt-05 {
padding-top: 0.125rem !important;
}