Changes to styling and font
This commit is contained in:
@@ -12,5 +12,5 @@ a {
|
||||
}
|
||||
|
||||
.selectable {
|
||||
@apply focus-within:outline outline-2 outline-lighten outline-offset-2;
|
||||
@apply focus-within:outline outline-2 outline-[#FDEA8A88] outline-offset-2;
|
||||
}
|
||||
|
||||
17
src/app.html
17
src/app.html
@@ -6,16 +6,23 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&family=Inter:wght@100;200;300;400;500;600;700;800;900&family=Nunito+Sans:wght@200;300;400;500;600;700;800;900;1000&display=swap" rel="stylesheet">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&family=Inter:wght@100;200;300;400;500;600;700;800;900&family=Nunito+Sans:wght@200;300;400;500;600;700;800;900;1000&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&family=Inter:wght@100;200;300;400;500;600;700;800;900&family=Montserrat:wght@100;200;300;400;500;600;700;800;900&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover" class="bg-stone-900 min-h-screen text-white">
|
||||
<body data-sveltekit-preload-data="hover" class="bg-stone-950 min-h-screen text-white">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -5,24 +5,39 @@
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let size: 'md' | 'sm' | 'lg' = 'md';
|
||||
export let type: 'primary' | 'secondary' | 'tertiary' = 'primary';
|
||||
export let type: 'primary' | 'secondary' | 'tertiary' = 'secondary';
|
||||
export let disabled = false;
|
||||
|
||||
export let href: string | undefined = undefined;
|
||||
export let target: string | undefined = undefined;
|
||||
|
||||
let buttonStyle: string;
|
||||
// $: buttonStyle = classNames(
|
||||
// 'border-2 border-white transition-all uppercase tracking-widest text-xs whitespace-nowrap',
|
||||
// {
|
||||
// 'bg-white text-zinc-900 font-extrabold': type === 'primary',
|
||||
// 'hover:bg-amber-400 hover:border-amber-400': type === 'primary' && !disabled,
|
||||
// 'font-semibold': type === 'secondary',
|
||||
// 'hover:bg-white hover:text-black': type === 'secondary' && !disabled,
|
||||
// 'px-8 py-3.5': size === 'lg',
|
||||
// 'px-6 py-2.5': size === 'md',
|
||||
// 'px-5 py-2': size === 'sm',
|
||||
// 'opacity-70': disabled,
|
||||
// 'cursor-pointer': !disabled
|
||||
// }
|
||||
// );
|
||||
$: buttonStyle = classNames(
|
||||
'border-2 border-white transition-all uppercase tracking-widest text-xs whitespace-nowrap',
|
||||
'flex items-center gap-1 py-3 px-6 rounded-xl font-medium select-none cursor-pointer selectable transition-all backdrop-blur-lg',
|
||||
{
|
||||
'bg-white text-zinc-900 font-extrabold': type === 'primary',
|
||||
'hover:bg-amber-400 hover:border-amber-400': type === 'primary' && !disabled,
|
||||
'font-semibold': type === 'secondary',
|
||||
'hover:bg-white hover:text-black': type === 'secondary' && !disabled,
|
||||
'px-8 py-3.5': size === 'lg',
|
||||
'px-6 py-2.5': size === 'md',
|
||||
'text-zinc-200 bg-stone-800 bg-opacity-30': type === 'secondary',
|
||||
'focus-visible:bg-zinc-200 focus-visible:text-zinc-800 hover:bg-zinc-200 hover:text-zinc-800':
|
||||
type === 'secondary' && !disabled,
|
||||
'py-3 px-6': size === 'lg',
|
||||
// 'py-3 px-6': size === 'md',
|
||||
'px-5 py-2': size === 'sm',
|
||||
'opacity-70': disabled,
|
||||
'opacity-50': disabled,
|
||||
'cursor-pointer': !disabled
|
||||
}
|
||||
);
|
||||
@@ -37,7 +52,14 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<button class={buttonStyle} on:click={handleClick} on:mouseover on:mouseleave {disabled}>
|
||||
<button
|
||||
class={buttonStyle}
|
||||
on:click={handleClick}
|
||||
on:focus
|
||||
on:mouseover
|
||||
on:mouseleave
|
||||
on:blur
|
||||
{disabled}
|
||||
>
|
||||
<slot />
|
||||
</button>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<a
|
||||
href={`/discover/network/${network.name}`}
|
||||
class="border rounded-xl h-52 w-96 bg-stone-800 border-stone-700 cursor-pointer p-12 text-zinc-300 hover:text-amber-200 transition-all relative group selectable"
|
||||
class="block border rounded-xl h-52 w-96 bg-stone-900 border-stone-700 cursor-pointer p-12 text-zinc-300 hover:text-amber-200 transition-all relative group selectable flex-shrink-0"
|
||||
>
|
||||
<div
|
||||
class="absolute inset-10 bg-zinc-300 hover:bg-amber-200 group-hover:scale-105 transition-all"
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
<script lang="ts">
|
||||
import { getJellyfinEpisodes } from '$lib/apis/jellyfin/jellyfinApi';
|
||||
import { getTmdbSeriesSeasons, type CastMember, type Video } from '$lib/apis/tmdb/tmdbApi';
|
||||
import type { CastMember, Video } from '$lib/apis/tmdb/tmdbApi';
|
||||
import Button from '$lib/components/Button.svelte';
|
||||
import { TMDB_IMAGES_ORIGINAL } from '$lib/constants';
|
||||
import { library } from '$lib/stores/library.store';
|
||||
import { settings } from '$lib/stores/settings.store';
|
||||
import { formatMinutesToTime } from '$lib/utils';
|
||||
import classNames from 'classnames';
|
||||
import { ChevronDown, Clock } from 'radix-icons-svelte';
|
||||
import { ChevronDown, ChevronRight, Clock } from 'radix-icons-svelte';
|
||||
import type { ComponentProps } from 'svelte';
|
||||
import { fade, fly } from 'svelte/transition';
|
||||
import EpisodeCard from '../EpisodeCard/EpisodeCard.svelte';
|
||||
import HeightHider from '../HeightHider.svelte';
|
||||
import { playerState } from '../VideoPlayer/VideoPlayer';
|
||||
import LibraryDetails from './LibraryDetails.svelte';
|
||||
import SeasonsDetails from './SeasonsDetails.svelte';
|
||||
import type { ComponentProps } from 'svelte';
|
||||
|
||||
export let tmdbId: number;
|
||||
export let type: 'movie' | 'tv';
|
||||
@@ -99,229 +98,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// async function fetchPlayDetails(tmdbId: number, numberOfSeasons?: number) {
|
||||
// const libraryData = await $library;
|
||||
// const jellyfinItem = libraryData.items[tmdbId]?.jellyfinItem;
|
||||
|
||||
// const movieData = type === 'movie' ? await fetchMovieData() : undefined;
|
||||
// const showData =
|
||||
// type === 'tv' && numberOfSeasons ? await fetchShowData(tmdbId, numberOfSeasons) : undefined;
|
||||
|
||||
// return {
|
||||
// jellyfinItem,
|
||||
// ...movieData,
|
||||
// ...showData
|
||||
// };
|
||||
// }
|
||||
|
||||
// async function fetchMovieData() {
|
||||
// const radarrMoviePromise = getRadarrMovieByTmdbId(String(tmdbId));
|
||||
// const radarrMovieQueuedPromise = radarrMoviePromise.then((movie) =>
|
||||
// movie?.id ? getRadarrDownloadsById(movie.id) : undefined
|
||||
// );
|
||||
|
||||
// const libraryData = await $library;
|
||||
|
||||
// return {
|
||||
// playableMovie: libraryData.getMovie(tmdbId),
|
||||
// radarrMovie: await radarrMoviePromise,
|
||||
// radarrDownloads: await radarrMovieQueuedPromise
|
||||
// };
|
||||
// }
|
||||
|
||||
// async function fetchShowData(tmdbId: number, numberOfSeasons: number) {
|
||||
// const tmdbSeasonsPromises = getTmdbSeriesSeasons(tmdbId, numberOfSeasons);
|
||||
|
||||
// const libraryData = await $library;
|
||||
// const librarySeries = libraryData.getSeries(tmdbId);
|
||||
|
||||
// const sonarrSeriesPromise = librarySeries?.tmdbId
|
||||
// ? getSonarrSeriesByTvdbId(librarySeries.tmdbId)
|
||||
// : undefined;
|
||||
// const sonarrDownloadsPromise = sonarrSeriesPromise?.then((series) =>
|
||||
// series?.id ? getSonarrDownloadsById(series.id) : undefined
|
||||
// );
|
||||
// const sonarrEpisodePromises = sonarrSeriesPromise?.then((series) =>
|
||||
// series ? getSonarrEpisodes(series.id) : undefined
|
||||
// );
|
||||
|
||||
// const jellyfinEpisodesPromise = librarySeries?.jellyfinId
|
||||
// ? getJellyfinEpisodes(librarySeries.jellyfinId)
|
||||
// : undefined;
|
||||
|
||||
// return {
|
||||
// playableSeries: librarySeries,
|
||||
// tmdbSeasons: await tmdbSeasonsPromises,
|
||||
// sonarrSeries: await sonarrSeriesPromise,
|
||||
// sonarrDownloads: await sonarrDownloadsPromise,
|
||||
// sonarrEpisodes: await sonarrEpisodePromises,
|
||||
// jellyfinEpisodes: await jellyfinEpisodesPromise
|
||||
// };
|
||||
// }
|
||||
|
||||
// async function fetchLibraryData(): Promise<{ isAdded: boolean }> {
|
||||
// if (type === 'movie') {
|
||||
// const jellyfinItemPromise = getJellyfinItemByTmdbId(String(tmdbId));
|
||||
// const radarrMoviePromise = getRadarrMovieByTmdbId(String(tmdbId));
|
||||
// const radarrMovieQueuedPromise = radarrMoviePromise.then((movie) =>
|
||||
// movie?.id ? getRadarrDownloadsById(movie.id) : undefined
|
||||
// );
|
||||
|
||||
// const radarrMovie = await radarrMoviePromise;
|
||||
// const radarrDownloads = await radarrMovieQueuedPromise;
|
||||
// const jellyfinItem = await jellyfinItemPromise;
|
||||
|
||||
// servarrId = radarrMovie?.id;
|
||||
|
||||
// if (radarrDownloads) {
|
||||
// downloadProps = radarrDownloads.map((download) => ({
|
||||
// status: 'downloading',
|
||||
// resolution: download.quality?.quality?.resolution || 0,
|
||||
// sizeOnDisk: download.size || 0,
|
||||
// qualityType: download.quality?.quality?.source || 'Unknown',
|
||||
// videoCodec: 'Unknown',
|
||||
// downloadEta: new Date(download.estimatedCompletionTime || Date.now()),
|
||||
// cancelDownload: () => {
|
||||
// if (download.id && !cancelDownloadFetching) cancelDownload(download.id);
|
||||
// }
|
||||
// }));
|
||||
// }
|
||||
|
||||
// if (radarrMovie?.movieFile) {
|
||||
// movieFileProps = [
|
||||
// {
|
||||
// status: 'ready',
|
||||
// resolution: radarrMovie.movieFile.quality?.quality?.resolution || 0,
|
||||
// sizeOnDisk: radarrMovie.movieFile.size || 0,
|
||||
// qualityType: radarrMovie.movieFile.quality?.quality?.source || 'Unknown',
|
||||
// videoCodec: radarrMovie.movieFile.mediaInfo?.videoCodec || 'Unknown',
|
||||
// downloadEta: undefined,
|
||||
// deleteFile: () => {
|
||||
// if (radarrMovie?.movieFile?.id && !deleteMovieFetching)
|
||||
// deleteFile(radarrMovie.movieFile.id);
|
||||
// },
|
||||
// jellyfinStreamDisabled: !jellyfinItem,
|
||||
// openJellyfinStream: () => {
|
||||
// if (jellyfinItem?.Id) streamJellyfinId(jellyfinItem.Id);
|
||||
// }
|
||||
// }
|
||||
// ];
|
||||
// }
|
||||
|
||||
// return {
|
||||
// isAdded: !!radarrMovie
|
||||
// };
|
||||
// } else {
|
||||
// const tvdbId = await getTmdbSeries(tmdbId).then((series) => series?.external_ids?.tvdb_id);
|
||||
// if (!tvdbId) throw new Error("Couldn't find tvdb id");
|
||||
|
||||
// const jellyfinItemPromise = getJellyfinItemByTmdbId(String(tmdbId));
|
||||
// const sonarrSeriesPromise = getSonarrSeriesByTvdbId(tvdbId);
|
||||
// const sonarrDownloadsPromise = sonarrSeriesPromise.then((series) =>
|
||||
// series?.id ? getSonarrDownloadsById(series.id) : undefined
|
||||
// );
|
||||
// const sonarrEpisodePromises = sonarrSeriesPromise.then((series) =>
|
||||
// series ? getSonarrEpisodes(series.id) : undefined
|
||||
// );
|
||||
|
||||
// const sonarrSeries = await sonarrSeriesPromise;
|
||||
// const sonarrDownloads = await sonarrDownloadsPromise;
|
||||
// const jellyfinItem = await jellyfinItemPromise;
|
||||
// const sonarrEpisodes = await sonarrEpisodePromises.then((episodes) =>
|
||||
// episodes?.filter((episode) => episode.episode.absoluteEpisodeNumber !== undefined)
|
||||
// );
|
||||
|
||||
// sonarrEpisodes?.sort((a, b) => {
|
||||
// if (!a.episode.absoluteEpisodeNumber || !b.episode.absoluteEpisodeNumber) return -1;
|
||||
// return a.episode.absoluteEpisodeNumber - b.episode.absoluteEpisodeNumber;
|
||||
// });
|
||||
|
||||
// if (sonarrDownloads) {
|
||||
// }
|
||||
|
||||
// if (sonarrEpisodes) {
|
||||
// seasonFileProps = [];
|
||||
// for (const episode of sonarrEpisodes) {
|
||||
// if (episode.episodeFile) {
|
||||
// seasonFileProps[(episode.episode.seasonNumber || 1) - 1] = [
|
||||
// ...(seasonFileProps[(episode.episode.seasonNumber || 1) - 1] || []),
|
||||
// {
|
||||
// episodeNumber: episode.episode.episodeNumber,
|
||||
// status: 'ready',
|
||||
// resolution: episode.episodeFile.quality?.quality?.resolution || 0,
|
||||
// sizeOnDisk: episode.episodeFile.size || 0,
|
||||
// qualityType: episode.episodeFile.quality?.quality?.source || 'Unknown',
|
||||
// videoCodec: episode.episodeFile.mediaInfo?.videoCodec || 'Unknown',
|
||||
// downloadEta: undefined,
|
||||
// deleteFile: () => {
|
||||
// if (episode?.episodeFile?.id && !deleteMovieFetching)
|
||||
// deleteFile(episode.episodeFile.id);
|
||||
// },
|
||||
// jellyfinStreamDisabled: !jellyfinItem,
|
||||
// openJellyfinStream: () => {
|
||||
// if (jellyfinItem?.Id) streamJellyfinId(jellyfinItem.Id);
|
||||
// }
|
||||
// }
|
||||
// ];
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// servarrId = sonarrSeries?.id;
|
||||
|
||||
// return {
|
||||
// isAdded: !!sonarrSeries
|
||||
// };
|
||||
// }
|
||||
|
||||
// async function fetchSeasonDetails() {
|
||||
// if (seasons > 0 && type === 'tv') {
|
||||
// const tmdbSeasonsPromises = getTmdbSeriesSeasons(tmdbId, seasons);
|
||||
|
||||
// const libraryData = await $library;
|
||||
// const jellyfinSeriesId = libraryData.getSeries(tmdbId)?.jellyfinId;
|
||||
// const jellyfinEpisodesPromise = jellyfinSeriesId
|
||||
// ? getJellyfinEpisodes(jellyfinSeriesId)
|
||||
// : undefined;
|
||||
|
||||
// const tmdbSeasons = await tmdbSeasonsPromises;
|
||||
// const jellyfinEpisodes = await jellyfinEpisodesPromise;
|
||||
|
||||
// jellyfinEpisodes?.sort((a, b) => (a.IndexNumber || 99) - (b.IndexNumber || 99));
|
||||
// const nextJellyfinEpisode = jellyfinEpisodes?.find((e) => e?.UserData?.Played === false);
|
||||
|
||||
// const nextEpisode = {
|
||||
// jellyfinEpisode: nextJellyfinEpisode,
|
||||
// tmdbEpisode: nextJellyfinEpisode
|
||||
// ? tmdbSeasons
|
||||
// .flatMap((s) => s?.episodes)
|
||||
// .find(
|
||||
// (e) =>
|
||||
// e?.episode_number === nextJellyfinEpisode.IndexNumber &&
|
||||
// e?.season_number === nextJellyfinEpisode.ParentIndexNumber
|
||||
// )
|
||||
// : undefined
|
||||
// };
|
||||
|
||||
// return {
|
||||
// currentSeason: nextEpisode?.tmdbEpisode?.season_number || 1,
|
||||
// nextEpisode,
|
||||
// tmdbSeasons,
|
||||
// jellyfinEpisodes
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
||||
async function fetchSeriesData() {
|
||||
const tmdbSeasonsPromise = getTmdbSeriesSeasons(tmdbId, seasons);
|
||||
const jellyfinEpisodesPromise = jellyfinId ? getJellyfinEpisodes(jellyfinId) : undefined;
|
||||
|
||||
return {
|
||||
tmdbSeasons: await tmdbSeasonsPromise,
|
||||
jellyfinEpisodes: await jellyfinEpisodesPromise
|
||||
};
|
||||
}
|
||||
|
||||
let localDetails: HTMLDivElement;
|
||||
</script>
|
||||
|
||||
@@ -351,6 +127,7 @@
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
tabindex="-1"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -395,11 +172,11 @@
|
||||
{/if}
|
||||
</h2>
|
||||
<h2
|
||||
class="tracking-wider font-display font-extrabold text-amber-300 absolute opacity-10 text-8xl -ml-6 mt-8"
|
||||
class="tracking-wider font-display font-bold text-amber-300 absolute opacity-10 text-8xl -ml-6 mt-16"
|
||||
>
|
||||
<slot name="reason">{reason}</slot>
|
||||
</h2>
|
||||
<h1 class="uppercase text-8xl font-bold font-display z-[1] relative">
|
||||
<h1 class="uppercase text-9xl font-semibold font-display z-[1] relative">
|
||||
{title}
|
||||
</h1>
|
||||
</div>
|
||||
@@ -408,15 +185,63 @@
|
||||
style={opacityStyle}
|
||||
in:fly={{ x: -20, duration, delay: 600 }}
|
||||
>
|
||||
<div class="text-xl font-semibold tracking-wider">{tagline}</div>
|
||||
<div class="text-lg font-semibold tracking-wider">{tagline}</div>
|
||||
<div
|
||||
class="tracking-wider text-zinc-200 font-light leading-6 pl-4 border-l-2 border-zinc-300"
|
||||
class="tracking-wider text-sm text-zinc-200 font-light leading-6 pl-4 border-l-2 border-zinc-300"
|
||||
>
|
||||
{overview}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-6 mt-10" in:fly={{ x: -20, duration, delay: 600 }}>
|
||||
<div class="flex gap-1">
|
||||
<!-- <button
|
||||
class={classNames(
|
||||
'flex items-center gap-1 py-3 px-6 rounded-xl font-medium select-none cursor-pointer selectable transition-all backdrop-blur-lg',
|
||||
'text-zinc-200 bg-stone-800 bg-opacity-30 focus-visible:bg-zinc-200 focus-visible:text-zinc-800 hover:bg-zinc-200 hover:text-zinc-800'
|
||||
)}
|
||||
>
|
||||
<span>Details</span><ChevronRight size={20} />
|
||||
</button>
|
||||
<button
|
||||
class={classNames(
|
||||
'flex items-center gap-1 py-3 px-6 rounded-xl font-medium select-none cursor-pointer selectable transition-all backdrop-blur-lg',
|
||||
'text-zinc-200 bg-stone-800 bg-opacity-30 focus-visible:bg-zinc-200 focus-visible:text-zinc-800 hover:bg-zinc-200 hover:text-zinc-800'
|
||||
)}
|
||||
>
|
||||
<span>Watch Trailer</span><ChevronRight size={20} />
|
||||
</button> -->
|
||||
<!-- <button
|
||||
class={classNames(
|
||||
'flex items-center gap-1 py-2 px-6 rounded-full font-medium select-none cursor-pointer selectable transition-all',
|
||||
'text-zinc-200 hover:text-zinc-900 border border-zinc-200 border-opacity-50'
|
||||
)}
|
||||
>
|
||||
<span>Details</span><ChevronRight size={20} />
|
||||
</button>
|
||||
<button
|
||||
class={classNames(
|
||||
'flex items-center gap-1 py-2 px-6 rounded-full font-medium select-none cursor-pointer selectable transition-all',
|
||||
'text-zinc-200 hover:text-zinc-900 border border-zinc-200 border-opacity-50'
|
||||
)}
|
||||
>
|
||||
<span>Watch Trailer</span><ChevronRight size={20} />
|
||||
</button> -->
|
||||
<!-- <button
|
||||
class={classNames(
|
||||
'flex items-center gap-1 backdrop-blur-xl py-2.5 px-6 rounded-xl font-medium select-none cursor-pointer selectable transition-all',
|
||||
'text-zinc-200 bg-stone-700 bg-opacity-50 hover:bg-amber-300 hover:text-zinc-900 hover:bg-opacity-70'
|
||||
)}
|
||||
>
|
||||
<span>Details</span><ChevronRight size={20} />
|
||||
</button>
|
||||
<button
|
||||
class={classNames(
|
||||
'flex items-center gap-1 backdrop-blur-xl py-2.5 px-6 rounded-xl font-medium select-none cursor-pointer selectable transition-all',
|
||||
'text-zinc-200 bg-stone-700 bg-opacity-50 hover:bg-amber-300 hover:text-zinc-900 hover:bg-opacity-70'
|
||||
)}
|
||||
>
|
||||
<span>Watch Trailer</span><ChevronRight size={20} />
|
||||
</button> -->
|
||||
<!-- <div class="flex gap-1">
|
||||
<div style={opacityStyle}>
|
||||
<Button
|
||||
disabled={streamButtonDisabled}
|
||||
@@ -447,7 +272,41 @@
|
||||
on:mouseover={() => (focusTrailer = autoplayTrailer)}
|
||||
on:mouseleave={() => (focusTrailer = false)}
|
||||
on:click={openTrailer}>Watch Trailer</Button
|
||||
> -->
|
||||
<!-- <div style={opacityStyle}>
|
||||
<Button
|
||||
disabled={streamButtonDisabled}
|
||||
size="lg"
|
||||
on:click={() => jellyfinId && playerState.streamJellyfinId(jellyfinId)}
|
||||
>
|
||||
<span>Stream</span><ChevronRight size={20} />
|
||||
</Button>
|
||||
</div> -->
|
||||
<div style={opacityStyle} class:hidden={showDetails}>
|
||||
<Button
|
||||
size="lg"
|
||||
type="secondary"
|
||||
on:click={() => {
|
||||
detailsVisible = true;
|
||||
localDetails?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}}
|
||||
>
|
||||
<span>Details</span>
|
||||
<ChevronRight size={20} />
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
size="lg"
|
||||
type="secondary"
|
||||
on:mouseover={() => (focusTrailer = autoplayTrailer)}
|
||||
on:focus={() => (focusTrailer = autoplayTrailer)}
|
||||
on:mouseleave={() => (focusTrailer = false)}
|
||||
on:blur={() => (focusTrailer = false)}
|
||||
on:click={openTrailer}
|
||||
>
|
||||
<span>Watch Trailer</span>
|
||||
<ChevronRight size={20} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -483,17 +342,6 @@
|
||||
>
|
||||
<b>{tmdbRating.toFixed(1)}</b> TMDB
|
||||
</a>
|
||||
<div class="flex mt-4" in:fade={getFade()}>
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="text-white w-4"
|
||||
><g
|
||||
><path d="M0 0h24v24H0z" fill="none" /><path
|
||||
d="M11.29 3.814l2.02 5.707.395 1.116.007-4.81.01-4.818h4.27L18 11.871c.003 5.98-.003 10.89-.015 10.9-.012.009-.209 0-.436-.027-.989-.118-2.29-.236-3.34-.282a14.57 14.57 0 0 1-.636-.038c-.003-.004-.273-.762-.776-2.184v-.004l-2.144-6.061-.34-.954-.008 4.586c-.006 4.365-.01 4.61-.057 4.61-.163 0-1.57.09-2.04.136-.308.027-.926.09-1.37.145-.446.051-.816.085-.823.078C6.006 22.77 6 17.867 6 11.883V1.002h.005V1h4.288l.028.08c.007.016.065.176.157.437l.641 1.778.173.496-.001.023z"
|
||||
fill-rule="evenodd"
|
||||
fill="currentColor"
|
||||
/></g
|
||||
></svg
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{#if starring?.length > 0}
|
||||
<h3 class="text-xs tracking-wide uppercase" in:fade={getFade()}>Starring</h3>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
{#await $library then libraryData}
|
||||
{#if libraryData.itemsArray.filter((item) => item.continueWatching).length}
|
||||
{@const continueWatching = libraryData.continueWatching}
|
||||
<div class="p-8 flex flex-col gap-6 backdrop-blur-xl bg-stone-900">
|
||||
<div class="p-8 flex flex-col gap-6 backdrop-blur-xl">
|
||||
<h1 class="uppercase tracking-widest font-bold">Continue Watching</h1>
|
||||
<div class="flex gap-4 overflow-x-scroll">
|
||||
{#each continueWatching.slice(0, 5) as item (item.tmdbId)}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import RadarrStats from '$lib/components/SourceStats/RadarrStats.svelte';
|
||||
import SonarrStats from '$lib/components/SourceStats/SonarrStats.svelte';
|
||||
import { library, type PlayableItem } from '$lib/stores/library.store';
|
||||
import classNames from 'classnames';
|
||||
import { ChevronDown, MagnifyingGlass, TextAlignBottom, Trash } from 'radix-icons-svelte';
|
||||
import type { ComponentProps } from 'svelte';
|
||||
|
||||
@@ -90,7 +91,7 @@
|
||||
props = {
|
||||
size: 'dynamic',
|
||||
type: 'series',
|
||||
tmdbId: String(item.tmdbId),
|
||||
tmdbId: item.tmdbId,
|
||||
title: series.title || '',
|
||||
genres: series.genres || [],
|
||||
backdropUri: item.cardBackdropUrl,
|
||||
@@ -101,7 +102,7 @@
|
||||
props = {
|
||||
size: 'dynamic',
|
||||
type: 'movie',
|
||||
tmdbId: String(item.tmdbId),
|
||||
tmdbId: item.tmdbId,
|
||||
title: movie.title || '',
|
||||
genres: movie.genres || [],
|
||||
backdropUri: item.cardBackdropUrl,
|
||||
@@ -163,19 +164,27 @@
|
||||
<div class="py-4 px-2 md:px-8">
|
||||
<div class="max-w-screen-2xl m-auto backdrop-blur-2xl flex flex-col gap-4">
|
||||
<div class="flex justify-between gap-2 sm:flex-row flex-col">
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="flex gap-2 items-center bg-stone-950 rounded-2xl p-3 px-4 shadow-xl focus-within:outline outline-2 outline-stone-400"
|
||||
class={classNames(
|
||||
'flex gap-2 items-center p-3 px-4 shadow-xl selectable rounded-xl',
|
||||
'text-zinc-200 bg-zinc-700 bg-opacity-40 cursor-text focus-within:bg-opacity-60'
|
||||
)}
|
||||
on:click={() => document.activeElement !== searchInput && searchInput?.focus()}
|
||||
>
|
||||
<MagnifyingGlass size={24} class="text-zinc-200" />
|
||||
<MagnifyingGlass size={24} />
|
||||
<input
|
||||
type="text"
|
||||
class="bg-transparent outline-none text-zinc-300"
|
||||
class="bg-transparent outline-none placeholder:text-zinc-400 font-medium"
|
||||
placeholder="Search from library"
|
||||
bind:this={searchInput}
|
||||
bind:value={searchInputValue}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 bg-stone-950 rounded-2xl p-3 px-5 shadow-lg">
|
||||
<div
|
||||
class="flex items-center gap-2 p-3 px-5 shadow-xl rounded-xl text-zinc-200 bg-zinc-700 bg-opacity-40"
|
||||
>
|
||||
<IconButton>
|
||||
<TextAlignBottom size={20} />
|
||||
</IconButton>
|
||||
|
||||
@@ -4,8 +4,8 @@ export default {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'sans-serif'],
|
||||
display: ['Inter', 'system', 'sans-serif']
|
||||
sans: ['Montserrat', 'sans-serif'],
|
||||
display: ['Montserrat', 'system', 'sans-serif']
|
||||
},
|
||||
colors: {
|
||||
darken: '#07050199',
|
||||
|
||||
Reference in New Issue
Block a user