first push
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<base href="/" />
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="app.css" />
|
||||
<link rel="stylesheet" href="MovieActorLookup.styles.css" />
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<HeadOutlet />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<Routes />
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<div class="page">
|
||||
<div class="sidebar">
|
||||
<NavMenu />
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<div class="top-row px-4">
|
||||
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
|
||||
</div>
|
||||
|
||||
<article class="content px-4">
|
||||
@Body
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
@@ -0,0 +1,96 @@
|
||||
.page {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #d6d5d5;
|
||||
justify-content: flex-end;
|
||||
height: 3.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||
white-space: nowrap;
|
||||
margin-left: 1.5rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.top-row ::deep a:first-child {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@media (max-width: 640.98px) {
|
||||
.top-row {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.page {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
height: 100vh;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.top-row {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.top-row.auth ::deep a:first-child {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.top-row, article {
|
||||
padding-left: 2rem !important;
|
||||
padding-right: 1.5rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
background: lightyellow;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||
display: none;
|
||||
left: 0;
|
||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#blazor-error-ui .dismiss {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 0.5rem;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<div class="top-row ps-3 navbar navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="">I Know Them!</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="checkbox" title="Navigation menu" class="navbar-toggler" />
|
||||
|
||||
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
|
||||
<nav class="flex-column">
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
||||
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="searchmovies">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-camera-reels" viewBox="0 0 16 16">
|
||||
<path d="M6 3a3 3 0 1 1-6 0 3 3 0 0 1 6 0M1 3a2 2 0 1 0 4 0 2 2 0 0 0-4 0" />
|
||||
<path d="M9 6h.5a2 2 0 0 1 1.983 1.738l3.11-1.382A1 1 0 0 1 16 7.269v7.462a1 1 0 0 1-1.406.913l-3.111-1.382A2 2 0 0 1 9.5 16H2a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2zm6 8.73V7.27l-3.5 1.555v4.35zM1 8v6a1 1 0 0 0 1 1h7.5a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1" />
|
||||
<path d="M9 6a3 3 0 1 0 0-6 3 3 0 0 0 0 6M7 3a2 2 0 1 1 4 0 2 2 0 0 1-4 0" />
|
||||
</svg> Search Movies
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="searchshows">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-tv" viewBox="0 0 16 16">
|
||||
<path d="M2.5 13.5A.5.5 0 0 1 3 13h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5M13.991 3l.024.001a1.5 1.5 0 0 1 .538.143.76.76 0 0 1 .302.254c.067.1.145.277.145.602v5.991l-.001.024a1.5 1.5 0 0 1-.143.538.76.76 0 0 1-.254.302c-.1.067-.277.145-.602.145H2.009l-.024-.001a1.5 1.5 0 0 1-.538-.143.76.76 0 0 1-.302-.254C1.078 10.502 1 10.325 1 10V4.009l.001-.024a1.5 1.5 0 0 1 .143-.538.76.76 0 0 1 .254-.302C1.498 3.078 1.675 3 2 3zM14 2H2C0 2 0 4 0 4v6c0 2 2 2 2 2h12c2 0 2-2 2-2V4c0-2-2-2-2-2" />
|
||||
</svg> TV Show Search
|
||||
</NavLink>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
.navbar-toggler {
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
width: 3.5rem;
|
||||
height: 2.5rem;
|
||||
color: white;
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 1rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.navbar-toggler:checked {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
height: 3.5rem;
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.bi {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
margin-right: 0.75rem;
|
||||
top: -1px;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bi-house-door-fill-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-plus-square-fill-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-list-nested-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item ::deep .nav-link {
|
||||
color: #d7d7d7;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-item ::deep a.active {
|
||||
background-color: rgba(255,255,255,0.37);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-item ::deep .nav-link:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-toggler:checked ~ .nav-scrollable {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.navbar-toggler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
/* Never collapse the sidebar for wide screens */
|
||||
display: block;
|
||||
|
||||
/* Allow sidebar to scroll for tall menus */
|
||||
height: calc(100vh - 3.5rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
@page "/counter"
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>Counter</PageTitle>
|
||||
|
||||
<h1>Counter</h1>
|
||||
|
||||
<p role="status">Current count: @currentCount</p>
|
||||
|
||||
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
|
||||
|
||||
@code {
|
||||
private int currentCount = 0;
|
||||
|
||||
private void IncrementCount()
|
||||
{
|
||||
currentCount++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
@page "/Error"
|
||||
@using System.Diagnostics
|
||||
|
||||
<PageTitle>Error</PageTitle>
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
||||
|
||||
@code{
|
||||
[CascadingParameter]
|
||||
private HttpContext? HttpContext { get; set; }
|
||||
|
||||
private string? RequestId { get; set; }
|
||||
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
protected override void OnInitialized() =>
|
||||
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
@page "/"
|
||||
|
||||
<PageTitle>Home</PageTitle>
|
||||
|
||||
<h1>Hello, world!</h1>
|
||||
|
||||
Welcome to your new app.
|
||||
@@ -0,0 +1,156 @@
|
||||
@page "/searchmovies"
|
||||
@using MovieActorLookup.Models
|
||||
@using MovieActorLookup.Models.Movies
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@inject MovieService MovieService
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<h3>Search for Actor by Movie and Character Name</h3>
|
||||
|
||||
<div class="mb-3">
|
||||
<input type="text" class="form-control" @bind="_movieTitle" placeholder="Enter movie title..." />
|
||||
<input type="text" class="form-control" @bind="_characterName" placeholder="Enter character name..." />
|
||||
<button class="btn btn-primary mt-2" @onclick="SearchForActorAndCharacters">Search</button>
|
||||
</div>
|
||||
|
||||
@if (_isSearching)
|
||||
{
|
||||
<p>Searching...</p>
|
||||
}
|
||||
|
||||
else if (_actor != null)
|
||||
{
|
||||
<h4>Actor: @_actor.Name</h4>
|
||||
|
||||
@if (_matchedMovie != null)
|
||||
{
|
||||
<div class="card m-2" style="width: 18rem;">
|
||||
<img class="card-img-top" src="@($"https://image.tmdb.org/t/p/w500{_matchedMovie.MoviePosterPath}")" alt="Movie Poster">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">@_matchedMovie.MovieTitle</h5>
|
||||
<h10 class="card-text">@_matchedMovie.CharacterName</h10>
|
||||
<br />
|
||||
<small class="card-text">@_matchedMovie.Franchise</small>
|
||||
<small class="text-muted">Release Date: @_matchedMovie.ReleaseDate</small>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@foreach (var franchiseGroup in _actor.MovieCharacters
|
||||
.GroupBy(mc => mc.Franchise)
|
||||
.OrderBy(g => g.Key == "Standalone")
|
||||
.ThenBy(g => g.Key))
|
||||
{
|
||||
<h5 class="mt-4">@franchiseGroup.Key</h5>
|
||||
<div class="d-flex flex-wrap">
|
||||
@foreach (var movieCharacter in (franchiseGroup.Key == "Standalone"
|
||||
? franchiseGroup.OrderByDescending(mc =>
|
||||
DateTime.TryParse(mc.ReleaseDate, out var d) ? d : DateTime.MinValue)
|
||||
: franchiseGroup.OrderBy(mc =>
|
||||
DateTime.TryParse(mc.ReleaseDate, out var d) ? d : DateTime.MaxValue)))
|
||||
{
|
||||
<div class="card m-2" style="width: 18rem;">
|
||||
<img class="card-img-top" src="@($"https://image.tmdb.org/t/p/w500{movieCharacter.MoviePosterPath}")" alt="Movie Poster">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">@movieCharacter.MovieTitle</h5>
|
||||
<h10 class="card-text">@movieCharacter.CharacterName</h10>
|
||||
<p class="text-muted">@movieCharacter.Overview</p>
|
||||
<small class="text-muted">Release Date: @movieCharacter.ReleaseDate</small>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>Enter a movie title and character name to begin your search.</p>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _movieTitle;
|
||||
private string _characterName;
|
||||
private Actor _actor;
|
||||
private MovieCharacter _matchedMovie;
|
||||
private bool _isSearching = false;
|
||||
|
||||
private async Task SearchForActorAndCharacters()
|
||||
{
|
||||
_isSearching = true;
|
||||
_actor = null;
|
||||
_matchedMovie = null; // reset matched movie
|
||||
StateHasChanged();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_movieTitle) && !string.IsNullOrWhiteSpace(_characterName))
|
||||
{
|
||||
var movies = await MovieService.GetMoviesByTitle(_movieTitle);
|
||||
foreach (var movie in movies)
|
||||
{
|
||||
var credits = await MovieService.GetMovieCreditsByMovieId(movie.Id);
|
||||
foreach (var castMember in credits.Cast)
|
||||
{
|
||||
if (castMember.Character.ToLower().Contains(_characterName.ToLower()))
|
||||
{
|
||||
if (_actor == null)
|
||||
{
|
||||
_actor = new Actor(castMember.Name);
|
||||
int personId = castMember.Id;
|
||||
|
||||
var filmography = await MovieService.GetActorMovieCreditsById(personId);
|
||||
if (filmography?.Cast != null)
|
||||
{
|
||||
foreach (var role in filmography.Cast)
|
||||
{
|
||||
var fullMovie = await MovieService.GetMovieDetailsById(role.Id);
|
||||
|
||||
var movieCharacter = new MovieCharacter
|
||||
{
|
||||
MovieTitle = role.Title,
|
||||
CharacterName = role.Character,
|
||||
MoviePosterPath = role.PosterPath,
|
||||
ReleaseDate = DateTime.TryParse(fullMovie?.ReleaseDate, out var parsedDate)
|
||||
? parsedDate.ToString("MM/dd/yyyy")
|
||||
: "N/A",
|
||||
Overview = fullMovie?.Overview ?? "",
|
||||
Franchise = fullMovie?.BelongsToCollection?.Name ?? "Standalone"
|
||||
};
|
||||
|
||||
_actor.MovieCharacters.Add(movieCharacter);
|
||||
|
||||
if (_matchedMovie == null)
|
||||
{
|
||||
if (role.Title == movie.Title && role.Character == castMember.Character)
|
||||
{
|
||||
_matchedMovie = movieCharacter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_isSearching = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
private async Task<Movie> GetProperMovieBasedOffOfActorInvolvement(string movieActorTitle, CastMember actor)
|
||||
{
|
||||
List<Credits> overallCredits = new();
|
||||
|
||||
List<Movie> actorMovies = await MovieService.GetMoviesByTitle(movieActorTitle);
|
||||
|
||||
foreach (Movie movie in actorMovies)
|
||||
{
|
||||
overallCredits.Add(await MovieService.GetMovieCreditsByMovieId(movie.Id));
|
||||
}
|
||||
|
||||
Credits actorMovieCredits = overallCredits.FirstOrDefault(x => x.Cast.Any(c => c.Id == actor.Id));
|
||||
Movie movie1 = actorMovies.Where(x => x.Id == actorMovieCredits.Id).FirstOrDefault();
|
||||
|
||||
return movie1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
@page "/searchshows"
|
||||
@using MovieActorLookup.Models
|
||||
@inject ShowService ShowService
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<h3>Search for Actor by TV Show and Character Name</h3>
|
||||
|
||||
<div class="mb-3">
|
||||
<input type="text" class="form-control" @bind="_tvTitle" placeholder="Enter show title..." />
|
||||
<input type="text" class="form-control" @bind="_characterName" placeholder="Enter character name..." />
|
||||
<button class="btn btn-primary mt-2" @onclick="SearchForActorAndCharacters">Search</button>
|
||||
</div>
|
||||
|
||||
@if (_isSearching)
|
||||
{
|
||||
<p>Searching...</p>
|
||||
}
|
||||
else if (_actor != null)
|
||||
{
|
||||
<h4>Actor: @_actor.Name</h4>
|
||||
|
||||
@if (_matchedShow != null)
|
||||
{
|
||||
<div class="card m-2" style="width: 18rem;">
|
||||
<img class="card-img-top" src="@($"https://image.tmdb.org/t/p/w500{_matchedShow.ShowPosterPath}")" alt="Show Poster">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">@_matchedShow.ShowTitle</h5>
|
||||
<h10 class="card-text">@_matchedShow.CharacterName</h10>
|
||||
<br />
|
||||
<small class="text-muted">First Air Date: @_matchedShow.FirstAirDate</small>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@foreach (var group in _actor.TvCharacters
|
||||
.GroupBy(tc => tc.Franchise)
|
||||
.OrderBy(g => g.Key == "Standalone")
|
||||
.ThenBy(g => g.Key))
|
||||
{
|
||||
<div class="d-flex flex-wrap">
|
||||
@foreach (var show in (group.Key == "Standalone"
|
||||
? group.OrderByDescending(tc => DateTime.TryParse(tc.FirstAirDate, out var d) ? d : DateTime.MinValue)
|
||||
: group.OrderBy(tc => DateTime.TryParse(tc.FirstAirDate, out var d) ? d : DateTime.MaxValue)))
|
||||
{
|
||||
<div class="card m-2" style="width: 18rem;">
|
||||
<img class="card-img-top" src="@($"https://image.tmdb.org/t/p/w500{show.ShowPosterPath}")" alt="Poster">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">@show.ShowTitle</h5>
|
||||
<h10 class="card-text">@show.CharacterName</h10>
|
||||
<p class="text-muted">@show.Overview</p>
|
||||
<small class="text-muted">First Air Date: @show.FirstAirDate</small>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>Enter a TV show title and character name to begin your search.</p>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _tvTitle;
|
||||
private string _characterName;
|
||||
private Actor _actor;
|
||||
private TvCharacter _matchedShow;
|
||||
private bool _isSearching = false;
|
||||
|
||||
private async Task SearchForActorAndCharacters()
|
||||
{
|
||||
_isSearching = true;
|
||||
_actor = null;
|
||||
_matchedShow = null;
|
||||
StateHasChanged();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_tvTitle) && !string.IsNullOrWhiteSpace(_characterName))
|
||||
{
|
||||
var shows = await ShowService.GetShowsByTitle(_tvTitle);
|
||||
foreach (var show in shows)
|
||||
{
|
||||
var credits = await ShowService.GetShowCreditsById(show.Id);
|
||||
foreach (var cast in credits.Cast)
|
||||
{
|
||||
if (cast.Character.ToLower().Contains(_characterName.ToLower()))
|
||||
{
|
||||
if (_actor == null)
|
||||
{
|
||||
_actor = new Actor(cast.Name);
|
||||
int personId = cast.Id;
|
||||
|
||||
var filmography = await ShowService.GetActorTvCreditsById(personId);
|
||||
if (filmography?.Cast != null)
|
||||
{
|
||||
foreach (var role in filmography.Cast)
|
||||
{
|
||||
var fullShow = await ShowService.GetShowDetailsById(role.Id);
|
||||
|
||||
var tvCharacter = new TvCharacter
|
||||
{
|
||||
ShowTitle = role.ShowTitle,
|
||||
CharacterName = role.Character,
|
||||
ShowPosterPath = role.PosterPath,
|
||||
FirstAirDate = DateTime.TryParse(fullShow?.FirstAirDate, out var parsedDate)
|
||||
? parsedDate.ToString("MM/dd/yyyy")
|
||||
: "N/A",
|
||||
Overview = fullShow?.Overview ?? "",
|
||||
Franchise = fullShow?.BelongsToCollection?.Name ?? "Standalone"
|
||||
};
|
||||
|
||||
_actor.TvCharacters.Add(tvCharacter);
|
||||
|
||||
if (_matchedShow == null &&
|
||||
role.ShowTitle == show.Name &&
|
||||
role.Character == cast.Character)
|
||||
{
|
||||
_matchedShow = tvCharacter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_isSearching = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
@page "/weather"
|
||||
@attribute [StreamRendering]
|
||||
|
||||
<PageTitle>Weather</PageTitle>
|
||||
|
||||
<h1>Weather</h1>
|
||||
|
||||
<p>This component demonstrates showing data.</p>
|
||||
|
||||
@if (forecasts == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var forecast in forecasts)
|
||||
{
|
||||
<tr>
|
||||
<td>@forecast.Date.ToShortDateString()</td>
|
||||
<td>@forecast.TemperatureC</td>
|
||||
<td>@forecast.TemperatureF</td>
|
||||
<td>@forecast.Summary</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
@code {
|
||||
private WeatherForecast[]? forecasts;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// Simulate asynchronous loading to demonstrate streaming rendering
|
||||
await Task.Delay(500);
|
||||
|
||||
var startDate = DateOnly.FromDateTime(DateTime.Now);
|
||||
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
|
||||
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = startDate.AddDays(index),
|
||||
TemperatureC = Random.Shared.Next(-20, 55),
|
||||
Summary = summaries[Random.Shared.Next(summaries.Length)]
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
private class WeatherForecast
|
||||
{
|
||||
public DateOnly Date { get; set; }
|
||||
public int TemperatureC { get; set; }
|
||||
public string? Summary { get; set; }
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<Router AppAssembly="typeof(Program).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
|
||||
<FocusOnNavigate RouteData="routeData" Selector="h1" />
|
||||
</Found>
|
||||
</Router>
|
||||
@@ -0,0 +1,10 @@
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using MovieActorLookup
|
||||
@using MovieActorLookup.Components
|
||||
@@ -0,0 +1,56 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MovieActorLookup.Models
|
||||
{
|
||||
public class Actor(string name)
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = name;
|
||||
|
||||
[JsonPropertyName("movie_cast")]
|
||||
public List<MovieCharacter> MovieCharacters { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("tv_cast")]
|
||||
public List<TvCharacter> TvCharacters { get; set; } = new();
|
||||
}
|
||||
|
||||
public class MovieCharacter
|
||||
{
|
||||
[JsonPropertyName("title")]
|
||||
public string MovieTitle { get; set; }
|
||||
|
||||
[JsonPropertyName("character")]
|
||||
public string CharacterName { get; set; }
|
||||
|
||||
[JsonPropertyName("poster_path")]
|
||||
public string MoviePosterPath { get; set; }
|
||||
|
||||
[JsonPropertyName("overview")]
|
||||
public string Overview { get; set; }
|
||||
|
||||
[JsonPropertyName("release_date")]
|
||||
public string ReleaseDate { get; set; }
|
||||
|
||||
public string Franchise { get; set; }
|
||||
}
|
||||
|
||||
public class TvCharacter
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string ShowTitle { get; set; }
|
||||
|
||||
[JsonPropertyName("character")]
|
||||
public string CharacterName { get; set; }
|
||||
|
||||
[JsonPropertyName("poster_path")]
|
||||
public string ShowPosterPath { get; set; }
|
||||
|
||||
[JsonPropertyName("overview")]
|
||||
public string Overview { get; set; }
|
||||
|
||||
[JsonPropertyName("first_air_date")]
|
||||
public string FirstAirDate { get; set; }
|
||||
|
||||
public string Franchise { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace MovieActorLookup.Models
|
||||
{
|
||||
public class ActorViewModel
|
||||
{
|
||||
public string ActorName { get; set; }
|
||||
public string ActorProfilePath { get; set; }
|
||||
public List<MovieCharacterInfo> MovieCharacterInfos { get; set; } = new List<MovieCharacterInfo>();
|
||||
}
|
||||
|
||||
public class MovieCharacterInfo
|
||||
{
|
||||
public string MovieTitle { get; set; }
|
||||
public string CharacterName { get; set; }
|
||||
public string MoviePosterPath { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MovieActorLookup.Models
|
||||
{
|
||||
public class Credits
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonPropertyName("cast")]
|
||||
public List<CastMember> Cast { get; set; }
|
||||
|
||||
public Credits() { }
|
||||
|
||||
public Credits(int id, List<CastMember> cast)
|
||||
{
|
||||
Id = id;
|
||||
Cast = cast;
|
||||
}
|
||||
}
|
||||
|
||||
public class CastMember
|
||||
{
|
||||
[JsonPropertyName("adult")]
|
||||
public bool Adult { get; set; }
|
||||
|
||||
[JsonPropertyName("gender")]
|
||||
public int Gender { get; set; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonPropertyName("known_for_department")]
|
||||
public string KnownForDepartment { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("original_name")]
|
||||
public string OriginalName { get; set; }
|
||||
|
||||
[JsonPropertyName("popularity")]
|
||||
public double Popularity { get; set; }
|
||||
|
||||
[JsonPropertyName("profile_path")]
|
||||
public string ProfilePath { get; set; }
|
||||
|
||||
[JsonPropertyName("cast_id")]
|
||||
public int CastId { get; set; }
|
||||
|
||||
[JsonPropertyName("character")]
|
||||
public string Character { get; set; }
|
||||
|
||||
[JsonPropertyName("credit_id")]
|
||||
public string CreditId { get; set; }
|
||||
|
||||
[JsonPropertyName("order")]
|
||||
public int Order { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MovieActorLookup.Models.Movie.Movie
|
||||
{
|
||||
public class ActorMovieFilmography
|
||||
{
|
||||
[JsonPropertyName("cast")]
|
||||
public List<MovieRole> Cast { get; set; }
|
||||
}
|
||||
|
||||
public class MovieRole
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonPropertyName("character")]
|
||||
public string Character { get; set; }
|
||||
|
||||
[JsonPropertyName("poster_path")]
|
||||
public string PosterPath { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MovieActorLookup.Models.Movies
|
||||
{
|
||||
public class Movie
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string? Title { get; set; }
|
||||
|
||||
[JsonPropertyName("original_title")]
|
||||
public string? OriginalTitle { get; set; }
|
||||
|
||||
[JsonPropertyName("overview")]
|
||||
public string? Overview { get; set; }
|
||||
|
||||
[JsonPropertyName("adult")]
|
||||
public bool Adult { get; set; }
|
||||
|
||||
[JsonPropertyName("backdrop_path")]
|
||||
public string? BackdropPath { get; set; }
|
||||
|
||||
[JsonPropertyName("genre_ids")]
|
||||
public List<int> GenreIds { get; set; } = new List<int>();
|
||||
|
||||
[JsonPropertyName("original_language")]
|
||||
public string? OriginalLanguage { get; set; }
|
||||
|
||||
[JsonPropertyName("popularity")]
|
||||
public double Popularity { get; set; }
|
||||
|
||||
[JsonPropertyName("poster_path")]
|
||||
public string? PosterPath { get; set; }
|
||||
|
||||
[JsonPropertyName("release_date")]
|
||||
public string? ReleaseDate { get; set; }
|
||||
|
||||
[JsonPropertyName("video")]
|
||||
public bool Video { get; set; }
|
||||
|
||||
[JsonPropertyName("vote_average")]
|
||||
public double VoteAverage { get; set; }
|
||||
|
||||
[JsonPropertyName("vote_count")]
|
||||
public int VoteCount { get; set; }
|
||||
|
||||
[JsonPropertyName("belongs_to_collection")]
|
||||
public CollectionInfo BelongsToCollection { get; set; }
|
||||
|
||||
// Constructor
|
||||
public Movie()
|
||||
{
|
||||
GenreIds = new List<int>();
|
||||
}
|
||||
}
|
||||
|
||||
public class CollectionInfo
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("poster_path")]
|
||||
public string PosterPath { get; set; }
|
||||
|
||||
[JsonPropertyName("backdrop_path")]
|
||||
public string BackdropPath { get; set; }
|
||||
}
|
||||
|
||||
public class MovieResponse
|
||||
{
|
||||
[JsonPropertyName("page")]
|
||||
public int Page { get; set; }
|
||||
|
||||
[JsonPropertyName("results")]
|
||||
public List<Movie> Results { get; set; } = new List<Movie>();
|
||||
|
||||
[JsonPropertyName("total_pages")]
|
||||
public int TotalPages { get; set; }
|
||||
|
||||
[JsonPropertyName("total_results")]
|
||||
public int TotalResults { get; set; }
|
||||
public MovieResponse()
|
||||
{
|
||||
Results = new List<Movie>();
|
||||
}
|
||||
}
|
||||
|
||||
public class Genre
|
||||
{
|
||||
public int? Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace MovieActorLookup.Models.Movie
|
||||
{
|
||||
public class MovieResult
|
||||
{
|
||||
public MovieResult() { }
|
||||
public int Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public string PosterPath { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MovieActorLookup.Models.TvShow.TvShow
|
||||
{
|
||||
public class ActorTvFilmography
|
||||
{
|
||||
[JsonPropertyName("cast")]
|
||||
public List<TvRole> Cast { get; set; }
|
||||
}
|
||||
|
||||
public class TvRole
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string ShowTitle { get; set; }
|
||||
|
||||
[JsonPropertyName("character")]
|
||||
public string Character { get; set; }
|
||||
|
||||
[JsonPropertyName("poster_path")]
|
||||
public string PosterPath { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using MovieActorLookup.Models.Movie;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MovieActorLookup.Models.TvShows
|
||||
{
|
||||
public class TvShow
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("overview")]
|
||||
public string Overview { get; set; }
|
||||
|
||||
[JsonPropertyName("poster_path")]
|
||||
public string PosterPath { get; set; }
|
||||
|
||||
[JsonPropertyName("backdrop_path")]
|
||||
public string BackdropPath { get; set; }
|
||||
|
||||
[JsonPropertyName("first_air_date")]
|
||||
public string FirstAirDate { get; set; }
|
||||
|
||||
[JsonPropertyName("popularity")]
|
||||
public double Popularity { get; set; }
|
||||
|
||||
[JsonPropertyName("vote_average")]
|
||||
public double VoteAverage { get; set; }
|
||||
|
||||
[JsonPropertyName("genre_ids")]
|
||||
public List<int> GenreIds { get; set; } = new List<int>();
|
||||
|
||||
[JsonPropertyName("belongs_to_collection")]
|
||||
public CollectionInfo BelongsToCollection { get; set; }
|
||||
}
|
||||
|
||||
public class CollectionInfo
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("poster_path")]
|
||||
public string PosterPath { get; set; }
|
||||
|
||||
[JsonPropertyName("backdrop_path")]
|
||||
public string BackdropPath { get; set; }
|
||||
}
|
||||
|
||||
public class TvResponse
|
||||
{
|
||||
[JsonPropertyName("page")]
|
||||
public int Page { get; set; }
|
||||
|
||||
[JsonPropertyName("results")]
|
||||
public List<TvShow> Results { get; set; } = new List<TvShow>();
|
||||
|
||||
[JsonPropertyName("total_pages")]
|
||||
public int TotalPages { get; set; }
|
||||
|
||||
[JsonPropertyName("total_results")]
|
||||
public int TotalResults { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.8.34525.116
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MovieActorLookup", "MovieActorLookup\MovieActorLookup.csproj", "{0718836B-99B5-43F4-B64B-053E5438A9C8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0718836B-99B5-43F4-B64B-053E5438A9C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0718836B-99B5-43F4-B64B-053E5438A9C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0718836B-99B5-43F4-B64B-053E5438A9C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0718836B-99B5-43F4-B64B-053E5438A9C8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5D64DDBA-ECAC-4E5B-838A-F4A4A3ECD730}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,33 @@
|
||||
using MovieActorLookup.Components;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
builder.Services.AddSingleton(new MovieService("https://api.themoviedb.org/3", "45986ef3bc3be0f98701339092f28ce3", "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI0NTk4NmVmM2JjM2JlMGY5ODcwMTMzOTA5MmYyOGNlMyIsInN1YiI6IjY1YzU3MGVhNTM0NjYxMDE2MjhhY2VlZCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.UK_3zXedq_xs_ma1zCbh6-s0bEKdlUH8XWkpAWpDLZ0"));
|
||||
builder.Services.AddSingleton(new ShowService(
|
||||
"https://api.themoviedb.org/3",
|
||||
"45986ef3bc3be0f98701339092f28ce3",
|
||||
"eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI0NTk4NmVmM2JjM2JlMGY5ODcwMTMzOTA5MmYyOGNlMyIsInN1YiI6IjY1YzU3MGVhNTM0NjYxMDE2MjhhY2VlZCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.UK_3zXedq_xs_ma1zCbh6-s0bEKdlUH8XWkpAWpDLZ0"
|
||||
));
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseAntiforgery();
|
||||
|
||||
app.MapRazorComponents<App>()
|
||||
.AddInteractiveServerRenderMode();
|
||||
|
||||
app.Run();
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"metadata": {
|
||||
"_dependencyType": "compute.appService.windows"
|
||||
},
|
||||
"parameters": {
|
||||
"resourceGroupName": {
|
||||
"type": "string",
|
||||
"defaultValue": "MovieActorLookup_group",
|
||||
"metadata": {
|
||||
"description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking."
|
||||
}
|
||||
},
|
||||
"resourceGroupLocation": {
|
||||
"type": "string",
|
||||
"defaultValue": "eastus",
|
||||
"metadata": {
|
||||
"description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support."
|
||||
}
|
||||
},
|
||||
"resourceName": {
|
||||
"type": "string",
|
||||
"defaultValue": "MovieActorLookup",
|
||||
"metadata": {
|
||||
"description": "Name of the main resource to be created by this template."
|
||||
}
|
||||
},
|
||||
"resourceLocation": {
|
||||
"type": "string",
|
||||
"defaultValue": "[parameters('resourceGroupLocation')]",
|
||||
"metadata": {
|
||||
"description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there."
|
||||
}
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
|
||||
"appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.Resources/resourceGroups",
|
||||
"name": "[parameters('resourceGroupName')]",
|
||||
"location": "[parameters('resourceGroupLocation')]",
|
||||
"apiVersion": "2019-10-01"
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Resources/deployments",
|
||||
"name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]",
|
||||
"resourceGroup": "[parameters('resourceGroupName')]",
|
||||
"apiVersion": "2019-10-01",
|
||||
"dependsOn": [
|
||||
"[parameters('resourceGroupName')]"
|
||||
],
|
||||
"properties": {
|
||||
"mode": "Incremental",
|
||||
"template": {
|
||||
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"resources": [
|
||||
{
|
||||
"location": "[parameters('resourceLocation')]",
|
||||
"name": "[parameters('resourceName')]",
|
||||
"type": "Microsoft.Web/sites",
|
||||
"apiVersion": "2015-08-01",
|
||||
"tags": {
|
||||
"[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[variables('appServicePlan_ResourceId')]"
|
||||
],
|
||||
"kind": "app",
|
||||
"properties": {
|
||||
"name": "[parameters('resourceName')]",
|
||||
"kind": "app",
|
||||
"httpsOnly": true,
|
||||
"reserved": false,
|
||||
"serverFarmId": "[variables('appServicePlan_ResourceId')]",
|
||||
"siteConfig": {
|
||||
"metadata": [
|
||||
{
|
||||
"name": "CURRENT_STACK",
|
||||
"value": "dotnetcore"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"identity": {
|
||||
"type": "SystemAssigned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"location": "[parameters('resourceLocation')]",
|
||||
"name": "[variables('appServicePlan_name')]",
|
||||
"type": "Microsoft.Web/serverFarms",
|
||||
"apiVersion": "2015-08-01",
|
||||
"sku": {
|
||||
"name": "S1",
|
||||
"tier": "Standard",
|
||||
"family": "S",
|
||||
"size": "S1"
|
||||
},
|
||||
"properties": {
|
||||
"name": "[variables('appServicePlan_name')]"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:13916",
|
||||
"sslPort": 44304
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:5279",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:7185;http://localhost:5279",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
using MovieActorLookup.Models;
|
||||
using MovieActorLookup.Models.Movies;
|
||||
using MovieActorLookup.Models.Movie.Movie;
|
||||
using RestSharp;
|
||||
using System.Text.Json;
|
||||
|
||||
public class MovieService
|
||||
{
|
||||
private readonly string _baseUrl;
|
||||
private readonly string _apiKey;
|
||||
private readonly string _bearerToken;
|
||||
|
||||
public MovieService(string baseUrl, string apiKey, string bearerToken)
|
||||
{
|
||||
_baseUrl = baseUrl;
|
||||
_apiKey = apiKey;
|
||||
_bearerToken = bearerToken;
|
||||
}
|
||||
|
||||
public async Task<List<Movie>> GetMoviesByTitle(string title)
|
||||
{
|
||||
var client = new RestClient("https://api.themoviedb.org/3/");
|
||||
|
||||
var request = new RestRequest("search/movie")
|
||||
.AddQueryParameter("query", title)
|
||||
.AddQueryParameter("include_adult", "false")
|
||||
.AddQueryParameter("language", "en-US")
|
||||
.AddQueryParameter("page", "1");
|
||||
|
||||
request.AddHeader("accept", "application/json");
|
||||
request.AddHeader("Authorization", $"Bearer {_bearerToken}");
|
||||
|
||||
var response = await client.GetAsync(request);
|
||||
|
||||
var movies = new List<Movie>();
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
var movieResponse = JsonSerializer.Deserialize<MovieResponse>(response.Content);
|
||||
if (movieResponse != null && movieResponse.Results.Any())
|
||||
{
|
||||
foreach (var apiMovie in movieResponse.Results)
|
||||
{
|
||||
var movie = new Movie
|
||||
{
|
||||
Id = apiMovie.Id,
|
||||
Title = apiMovie.Title,
|
||||
OriginalTitle = apiMovie.OriginalTitle,
|
||||
Overview = apiMovie.Overview,
|
||||
Adult = apiMovie.Adult,
|
||||
BackdropPath = apiMovie.BackdropPath != null ? $"https://image.tmdb.org/t/p/w500{apiMovie.BackdropPath}" : null,
|
||||
GenreIds = apiMovie.GenreIds,
|
||||
OriginalLanguage = apiMovie.OriginalLanguage,
|
||||
Popularity = apiMovie.Popularity,
|
||||
PosterPath = apiMovie.PosterPath != null ? $"https://image.tmdb.org/t/p/w500{apiMovie.PosterPath}" : null,
|
||||
ReleaseDate = apiMovie.ReleaseDate,
|
||||
Video = apiMovie.Video,
|
||||
VoteAverage = apiMovie.VoteAverage,
|
||||
VoteCount = apiMovie.VoteCount
|
||||
};
|
||||
movies.Add(movie);
|
||||
}
|
||||
}
|
||||
}
|
||||
return movies;
|
||||
}
|
||||
|
||||
public async Task<Credits> GetMovieCreditsByMovieId(int movieId)
|
||||
{
|
||||
var client = new RestClient(_baseUrl);
|
||||
|
||||
var request = new RestRequest($"movie/{movieId}/credits")
|
||||
.AddQueryParameter("language", "en-US");
|
||||
|
||||
request.AddHeader("accept", "application/json");
|
||||
request.AddHeader("Authorization", $"Bearer {_bearerToken}");
|
||||
|
||||
var response = await client.GetAsync(request);
|
||||
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
var credits = JsonSerializer.Deserialize<Credits>(response.Content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
return credits;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Error retrieving movie credits: " + response.ErrorMessage);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ActorMovieFilmography> GetActorMovieCreditsById(int personId)
|
||||
{
|
||||
var client = new RestClient(_baseUrl);
|
||||
var request = new RestRequest($"person/{personId}/movie_credits")
|
||||
.AddQueryParameter("language", "en-US");
|
||||
|
||||
request.AddHeader("accept", "application/json");
|
||||
request.AddHeader("Authorization", $"Bearer {_bearerToken}");
|
||||
|
||||
var response = await client.GetAsync(request);
|
||||
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
// Deserialize the response into the ActorFilmography class
|
||||
var actorFilmography = JsonSerializer.Deserialize<ActorMovieFilmography>(response.Content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
return actorFilmography;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Error retrieving actor's movie credits: " + response.ErrorMessage);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Movie> GetMovieDetailsById(int movieId)
|
||||
{
|
||||
var client = new RestClient(_baseUrl);
|
||||
|
||||
var request = new RestRequest($"movie/{movieId}")
|
||||
.AddQueryParameter("language", "en-US");
|
||||
|
||||
request.AddHeader("accept", "application/json");
|
||||
request.AddHeader("Authorization", $"Bearer {_bearerToken}");
|
||||
|
||||
var response = await client.GetAsync(request);
|
||||
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
var movie = JsonSerializer.Deserialize<Movie>(response.Content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
return movie;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Error retrieving movie details: " + response.ErrorMessage);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using MovieActorLookup.Models;
|
||||
using MovieActorLookup.Models.TvShows;
|
||||
using RestSharp;
|
||||
using System.Text.Json;
|
||||
|
||||
public class ShowService
|
||||
{
|
||||
private readonly string _baseUrl;
|
||||
private readonly string _apiKey;
|
||||
private readonly string _bearerToken;
|
||||
|
||||
public ShowService(string baseUrl, string apiKey, string bearerToken)
|
||||
{
|
||||
_baseUrl = baseUrl;
|
||||
_apiKey = apiKey;
|
||||
_bearerToken = bearerToken;
|
||||
}
|
||||
|
||||
public async Task<List<TvShow>> GetShowsByTitle(string title)
|
||||
{
|
||||
var client = new RestClient("https://api.themoviedb.org/3/");
|
||||
var request = new RestRequest("search/tv")
|
||||
.AddQueryParameter("query", title)
|
||||
.AddQueryParameter("include_adult", "false")
|
||||
.AddQueryParameter("language", "en-US")
|
||||
.AddQueryParameter("page", "1");
|
||||
|
||||
request.AddHeader("accept", "application/json");
|
||||
request.AddHeader("Authorization", $"Bearer {_bearerToken}");
|
||||
|
||||
var response = await client.GetAsync(request);
|
||||
var shows = new List<TvShow>();
|
||||
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
var showResponse = JsonSerializer.Deserialize<TvResponse>(response.Content);
|
||||
if (showResponse != null && showResponse.Results.Any())
|
||||
{
|
||||
foreach (var show in showResponse.Results)
|
||||
{
|
||||
shows.Add(new TvShow
|
||||
{
|
||||
Id = show.Id,
|
||||
Name = show.Name,
|
||||
Overview = show.Overview,
|
||||
PosterPath = show.PosterPath != null ? $"https://image.tmdb.org/t/p/w500{show.PosterPath}" : null,
|
||||
BackdropPath = show.BackdropPath != null ? $"https://image.tmdb.org/t/p/w500{show.BackdropPath}" : null,
|
||||
FirstAirDate = show.FirstAirDate,
|
||||
Popularity = show.Popularity,
|
||||
VoteAverage = show.VoteAverage
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shows;
|
||||
}
|
||||
|
||||
public async Task<Credits> GetShowCreditsById(int showId)
|
||||
{
|
||||
var client = new RestClient(_baseUrl);
|
||||
var request = new RestRequest($"tv/{showId}/credits")
|
||||
.AddQueryParameter("language", "en-US");
|
||||
|
||||
request.AddHeader("accept", "application/json");
|
||||
request.AddHeader("Authorization", $"Bearer {_bearerToken}");
|
||||
|
||||
var response = await client.GetAsync(request);
|
||||
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
return JsonSerializer.Deserialize<Credits>(response.Content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<MovieActorLookup.Models.TvShow.TvShow.ActorTvFilmography> GetActorTvCreditsById(int personId)
|
||||
{
|
||||
var client = new RestClient(_baseUrl);
|
||||
var request = new RestRequest($"person/{personId}/tv_credits")
|
||||
.AddQueryParameter("language", "en-US");
|
||||
|
||||
request.AddHeader("accept", "application/json");
|
||||
request.AddHeader("Authorization", $"Bearer {_bearerToken}");
|
||||
|
||||
var response = await client.GetAsync(request);
|
||||
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
return JsonSerializer.Deserialize<MovieActorLookup.Models.TvShow.TvShow.ActorTvFilmography>(response.Content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<TvShow> GetShowDetailsById(int showId)
|
||||
{
|
||||
var client = new RestClient(_baseUrl);
|
||||
var request = new RestRequest($"tv/{showId}")
|
||||
.AddQueryParameter("language", "en-US");
|
||||
|
||||
request.AddHeader("accept", "application/json");
|
||||
request.AddHeader("Authorization", $"Bearer {_bearerToken}");
|
||||
|
||||
var response = await client.GetAsync(request);
|
||||
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
return JsonSerializer.Deserialize<TvShow>(response.Content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"MovieApi": {
|
||||
"BaseUrl": "https://api.themoviedb.org/3",
|
||||
"ApiKey": "45986ef3bc3be0f98701339092f28ce3",
|
||||
"BearerToken": "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI0NTk4NmVmM2JjM2JlMGY5ODcwMTMzOTA5MmYyOGNlMyIsInN1YiI6IjY1YzU3MGVhNTM0NjYxMDE2MjhhY2VlZCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.UK_3zXedq_xs_ma1zCbh6-s0bEKdlUH8XWkpAWpDLZ0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
@import url('https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css');
|
||||
|
||||
html, body {
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
a, .btn-link {
|
||||
color: #006bb7;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
|
||||
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1.1rem;
|
||||
}
|
||||
|
||||
h1:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.valid.modified:not([type=checkbox]) {
|
||||
outline: 1px solid #26b050;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
outline: 1px solid #e50000;
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
color: #e50000;
|
||||
}
|
||||
|
||||
.blazor-error-boundary {
|
||||
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
|
||||
padding: 1rem 1rem 1rem 3.7rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.blazor-error-boundary::after {
|
||||
content: "An error has occurred."
|
||||
}
|
||||
|
||||
.darker-border-checkbox.form-check-input {
|
||||
border-color: #929292;
|
||||
}
|
||||
|
||||
/*movie card styling*/
|
||||
|
||||
.movie-poster {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.movie-card{
|
||||
padding: 10px;
|
||||
height:auto;
|
||||
}
|
||||
|
||||
.movie-card-text{
|
||||
text-align:center;
|
||||
font-size:22px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.movie-card-body{
|
||||
text-align:center;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
.movie-card-footer{
|
||||
text-align: center;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Reference in New Issue
Block a user