wip: working episode-container
This commit is contained in:
4
assets/bootstrap.js
vendored
4
assets/bootstrap.js
vendored
@@ -3,7 +3,7 @@ import Popover from '@stimulus-components/popover';
|
||||
import Dialog from '@stimulus-components/dialog';
|
||||
import Dropdown from '@stimulus-components/dropdown';
|
||||
import 'animate.css';
|
||||
import Brock from './components/brock.js';
|
||||
import EpisodeContainer from './components/episode-container.js';
|
||||
|
||||
const app = startStimulusApp();
|
||||
// register any custom, 3rd party controllers here
|
||||
@@ -11,4 +11,4 @@ app.register('popover', Popover);
|
||||
app.register('dialog', Dialog);
|
||||
app.register('dropdown', Dropdown);
|
||||
|
||||
customElements.define('brock-app', Brock);
|
||||
customElements.define('episode-container', EpisodeContainer);
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
export default class Brock extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
connectedCallback() {
|
||||
this.render();
|
||||
}
|
||||
|
||||
render() {
|
||||
this.innerHTML = `
|
||||
Yo, yo, yo! Waddup ${this.name}, doe, it's Brocky fresh!
|
||||
`;
|
||||
}
|
||||
|
||||
// attribute change
|
||||
attributeChangedCallback(property, oldValue, newValue) {
|
||||
if (oldValue === newValue) return;
|
||||
this[ property ] = newValue;
|
||||
this.render();
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ['name'];
|
||||
}
|
||||
}
|
||||
34
assets/components/episode-container.js
Normal file
34
assets/components/episode-container.js
Normal file
@@ -0,0 +1,34 @@
|
||||
export default class EpisodeContainer extends HTMLElement {
|
||||
#resultsToggleBtnEl;
|
||||
#resultsTableEl;
|
||||
#resultsCountBadgeEl;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.#resultsToggleBtnEl = this.querySelector('.dropdown-button');
|
||||
this.#resultsCountBadgeEl = this.querySelector('.results-count-badge');
|
||||
this.#resultsTableEl = this.querySelector('.results-container');
|
||||
|
||||
this.#resultsToggleBtnEl.addEventListener('click', () => this.toggleResults());
|
||||
this.#resultsCountBadgeEl.addEventListener('click', () => this.toggleResults());
|
||||
}
|
||||
connectedCallback() {
|
||||
|
||||
}
|
||||
|
||||
// attribute change
|
||||
attributeChangedCallback(property, oldValue, newValue) {
|
||||
if (oldValue === newValue) return;
|
||||
this[ property ] = newValue;
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ['name'];
|
||||
}
|
||||
|
||||
toggleResults() {
|
||||
this.#resultsToggleBtnEl.classList.toggle('rotate-90');
|
||||
this.#resultsToggleBtnEl.classList.toggle('-rotate-90');
|
||||
this.#resultsTableEl.classList.toggle('hidden');
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,10 @@ export default class extends Controller {
|
||||
});
|
||||
if (window.location.hash) {
|
||||
let targetElement = document.querySelector(window.location.hash);
|
||||
targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
targetElement.classList.add('animate__animated', 'animate__pulse', 'animate__faster');
|
||||
if (targetElement) {
|
||||
targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
targetElement.classList.add('animate__animated', 'animate__pulse', 'animate__faster');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,13 +71,6 @@ export default class extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
toggleList() {
|
||||
this.listTarget.classList.toggle('options-table');
|
||||
this.listTarget.classList.toggle('hidden');
|
||||
this.toggleButtonTarget.classList.toggle('rotate-90');
|
||||
this.toggleButtonTarget.classList.toggle('-rotate-90');
|
||||
}
|
||||
|
||||
download() {
|
||||
this.options.forEach(option => {
|
||||
const optionSelector = option.querySelector('input[type="checkbox"]');
|
||||
|
||||
@@ -130,3 +130,21 @@ dialog[data-dialog-target="dialog"][closing] {
|
||||
background: unset;
|
||||
@apply bg-orange-500/80 text-black font-bold rounded-md
|
||||
}
|
||||
|
||||
.progress {
|
||||
display: grid;
|
||||
grid-template: 1fr / 1fr;
|
||||
place-items: center;
|
||||
}
|
||||
.progress > * {
|
||||
grid-column: 1 / 1;
|
||||
grid-row: 1 / 1;
|
||||
}
|
||||
.progress .background {
|
||||
z-index: 1;
|
||||
place-self: start;
|
||||
}
|
||||
.progress .number {
|
||||
z-index: 2;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ module.exports = {
|
||||
"bg-rose-600",
|
||||
"alert-success",
|
||||
"alert-warning",
|
||||
"font-bold",
|
||||
"min-w-64",
|
||||
"rotate-180",
|
||||
"-rotate-180",
|
||||
|
||||
@@ -14,14 +14,11 @@
|
||||
{% if entity.status != "Complete" %}
|
||||
<turbo-stream action="update" target="download_progress_{{ id }}">
|
||||
<template>
|
||||
<div class="text-black text-center rounded-sm text-bold bg-green-300 h-5 relative z-10"
|
||||
style="width:{{ entity.progress }}%">
|
||||
</div>
|
||||
<div class="absolute text-black text-center"
|
||||
style="z-index: 400;margin-top: -1.25rem; margin-left: 1.2rem">
|
||||
{{ entity.progress }}%
|
||||
</div>
|
||||
<div class="background text-black text-center rounded-sm text-bold bg-green-300 h-5 relative z-10"
|
||||
style="width: {{ entity.progress }}%">
|
||||
</div>
|
||||
<div class="number text-black font-bold text-center z-40"
|
||||
>{{ entity.progress }}%</div>
|
||||
</template>
|
||||
</turbo-stream>
|
||||
<turbo-stream action="update" target="action_buttons_{{ id }}">
|
||||
|
||||
@@ -29,12 +29,13 @@
|
||||
<td class="whitespace-nowrap gap-2 text-sm align-middle text-gray-800 dark:text-gray-50">
|
||||
{% if download.progress < 100 %}
|
||||
<div class="flex flex-row items-center justify-center">
|
||||
<div id="download_progress_{{ download.id }}" class="border-2 border-green-600 rounded-md text-center w-16 h-6 align-middle overflow-hidden">
|
||||
<div class="text-black text-center rounded-sm text-bold bg-green-300 h-5 relative z-10"
|
||||
style="width:{{ download.progress }}%">
|
||||
<div id="download_progress_{{ download.id }}" class="progress border-2 border-green-600 rounded-md text-center w-16 h-6 align-middle overflow-hidden">
|
||||
<div class="background text-black text-center rounded-sm text-bold bg-green-300 h-5 relative z-10"
|
||||
style="width: {{ download.progress }}%">
|
||||
</div>
|
||||
<div class="number text-black font-bold text-center z-40"
|
||||
>{{ download.progress }}%</div>
|
||||
</div>
|
||||
<div class="text-black font-bold text-center z-40 ml-[-42px]">{{ download.progress }}%</div>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
|
||||
{% if results.media.mediaType == "tvshows" %}
|
||||
<div class="flex flex-row gap-2 justify-end px-8">
|
||||
<twig:Modal heading="Back up a sec!" button_text="Download Season" submit_action="{{ stimulus_action('result_filter', 'downloadSeason', 'click')|stimulus_action('dialog', 'close') }}" button_class="px-1.5 py-1 bg-green-600 rounded-ms text-sm font-semibold" show_cancel show_submit>
|
||||
<twig:Modal heading="Back up a sec!" button_text="Download Season" submit_action="{{ stimulus_action('result_filter', 'downloadSeason', 'click')|stimulus_action('dialog', 'close') }}" button_class="px-1.5 py-1 border border-green-500 bg-green-800/60 rounded-ms text-sm font-semibold" show_cancel show_submit>
|
||||
Downloading an entire season this way will use the filter from your
|
||||
<a href="{{ path('app_user_preferences') }}" class="text-underline">preferences</a> to choose
|
||||
the appropriate file(s).
|
||||
@@ -99,7 +99,7 @@
|
||||
Do you wish to download <strong>season <span id="downloadSeasonModal">{{ results.season }}</span></strong> of "<strong>{{ results.media.title }}</strong>"?
|
||||
</twig:Modal>
|
||||
|
||||
<button class="px-1.5 py-1 bg-green-600 hover:bg-green-700 rounded-ms text-sm font-semibold"
|
||||
<button class="px-1.5 py-1 bg-green-800/60 hover:bg-green-700/60 border border-green-500 rounded-ms text-sm font-semibold"
|
||||
{{ stimulus_target('result_filter', 'downloadSelected') }}
|
||||
{{ stimulus_action('result_filter', 'downloadSelectedEpisodes', 'click') }}
|
||||
>Download Selected</button>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
>
|
||||
<div data-live-id="{{ uniqid() }}" class="episode-container flex flex-col gap-4">
|
||||
{% for episode in this.getEpisodes().items %}
|
||||
<div id="{{ episode_anchor(episode['season_number'], episode['episode_number']) }}" class="results"
|
||||
<episode-container id="{{ episode_anchor(episode['season_number'], episode['episode_number']) }}" class="results"
|
||||
data-tv-results-loading-icon-outlet=".loading-icon"
|
||||
data-download-button-outlet=".download-btn"
|
||||
{{ stimulus_controller('tv_results', {
|
||||
@@ -15,77 +15,73 @@
|
||||
active: 'true',
|
||||
}) }}
|
||||
>
|
||||
<div class="p-4 md:p-6 flex flex-col gap-6 bg-orange-500 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60 rounded-md">
|
||||
<div class="flex flex-col md:flex-row gap-4">
|
||||
{% if episode['poster'] != null %}
|
||||
<img class="w-full md:w-64 rounded-lg" src="{{ episode['poster'] }}" />
|
||||
{% else %}
|
||||
<div class="w-full md:w-64 min-w-64 sticky h-[144px] rounded-lg bg-gray-700 flex items-center justify-center">
|
||||
<twig:ux:icon width="32" name="hugeicons:loading-01" />
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex flex-col gap-4 grow">
|
||||
<h4 class="text-md font-bold">
|
||||
{{ episode['episode_number'] }}. {{ episode['name'] }}
|
||||
</h4>
|
||||
<p>{{ episode['overview']|truncate }}</p>
|
||||
<div>
|
||||
<button class="py-1 px-1.5 mr-1 grow-0 font-bold text-xs bg-green-600 rounded-lg hover:cursor-pointer hover:bg-green-700 text-white"
|
||||
{{ stimulus_action('tv-results', 'toggleList', 'click') }}
|
||||
>
|
||||
<span {{ stimulus_target('tv-results', 'count') }}>-</span> results
|
||||
</button>
|
||||
<div class="p-4 md:p-6 flex flex-col gap-6 bg-orange-500 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60 rounded-md">
|
||||
<div class="flex flex-col md:flex-row gap-4">
|
||||
{% if episode['poster'] != null %}
|
||||
<img class="w-full md:w-64 rounded-lg" src="{{ episode['poster'] }}" />
|
||||
{% else %}
|
||||
<div class="w-full md:w-64 min-w-64 sticky h-[144px] rounded-lg bg-gray-700 flex items-center justify-center">
|
||||
<twig:ux:icon width="32" name="hugeicons:loading-01" />
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex flex-col gap-4 grow">
|
||||
<h4 class="text-md font-bold">
|
||||
{{ episode['episode_number'] }}. {{ episode['name'] }}
|
||||
</h4>
|
||||
<p>{{ episode['overview']|truncate }}</p>
|
||||
<div>
|
||||
<button class="results-count-badge py-1 px-1.5 mr-1 grow-0 font-bold text-xs bg-green-600 rounded-lg hover:cursor-pointer hover:bg-green-700 text-white" title="Click to expand the results table for season {{ episode['season_number'] }} episode {{ episode['episode_number'] }}.">
|
||||
<span {{ stimulus_target('tv-results', 'count') }}>-</span> results
|
||||
</button>
|
||||
|
||||
<small class="py-1 px-1.5 mr-1 grow-0 font-bold bg-gray-700 rounded-lg font-normal text-white" title="Air date {{ episode['name'] }}">
|
||||
{{ episode['air_date']|date(null, 'UTC') }}
|
||||
</small>
|
||||
<small class="py-1 px-1.5 mr-1 grow-0 font-bold bg-gray-700 rounded-lg font-normal text-white" title='"{{ episode['name'] }}" aired on {{ episode['air_date']|date(null, 'UTC') }}.'>
|
||||
{{ episode['air_date']|date(null, 'UTC') }}
|
||||
</small>
|
||||
|
||||
<twig:Turbo:Frame id="meb_{{ this.imdbId }}_{{ episode_id(episode['season_number'], episode['episode_number']) }}" src="{{ path('api.library.search', {
|
||||
<twig:Turbo:Frame id="meb_{{ this.imdbId }}_{{ episode_id(episode['season_number'], episode['episode_number']) }}" src="{{ path('api.library.search', {
|
||||
title: this.title,
|
||||
season: episode['season_number'],
|
||||
episode: episode['episode_number'],
|
||||
block: 'media_exists_badge',
|
||||
target: "meb_" ~ this.imdbId ~"_" ~ episode_id(episode['season_number'], episode['episode_number'])
|
||||
}) }}">
|
||||
<small class="py-1 px-1.5 mr-1 grow-0 font-bold bg-rose-600 rounded-lg text-white" title="Episode has not been downloaded yet.">
|
||||
missing
|
||||
</small>
|
||||
</twig:Turbo:Frame>
|
||||
}) }}">
|
||||
<small class="py-1 px-1.5 mr-1 grow-0 font-bold bg-rose-600 rounded-lg text-white" title="Episode has not been downloaded yet.">
|
||||
missing
|
||||
</small>
|
||||
</twig:Turbo:Frame>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4 justify-between">
|
||||
<div class="flex flex-col items-center">
|
||||
<input type="checkbox"
|
||||
{{ stimulus_target('tv-results', 'episodeSelector') }}
|
||||
/>
|
||||
</div>
|
||||
<button class="dropdown-button flex flex-col items-end transition-transform duration-300 ease-in-out rotate-90" title="Click to expand the results table for season {{ episode['season_number'] }} episode {{ episode['episode_number'] }}.">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32">
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M20 6L10 16l10 10" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4 justify-between">
|
||||
<div class="flex flex-col items-center">
|
||||
<input type="checkbox"
|
||||
{{ stimulus_target('tv-results', 'episodeSelector') }}
|
||||
/>
|
||||
</div>
|
||||
<button class="flex flex-col items-end transition-transform duration-300 ease-in-out rotate-90"
|
||||
{{ stimulus_target('tv-results', 'toggleButton') }}
|
||||
{{ stimulus_action('tv-results', 'toggleList', 'click') }}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32">
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M20 6L10 16l10 10" />
|
||||
</svg>
|
||||
</button>
|
||||
<div class="results-container inline-block overflow-hidden rounded-lg hidden">
|
||||
<twig:Turbo:Frame id="results_{{ episode_id(episode['season_number'], episode['episode_number']) }}" src="{{ path('app_torrentio_tvshows', {
|
||||
tmdbId: this.tmdbId,
|
||||
imdbId: this.imdbId,
|
||||
season: episode['season_number'],
|
||||
episode: episode['episode_number'],
|
||||
target: 'results_' ~ episode_id(episode['season_number'], episode['episode_number']),
|
||||
block: 'tvshow_results'
|
||||
}) }}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-block overflow-hidden rounded-lg">
|
||||
<twig:Turbo:Frame id="results_{{ episode_id(episode['season_number'], episode['episode_number']) }}" src="{{ path('app_torrentio_tvshows', {
|
||||
tmdbId: this.tmdbId,
|
||||
imdbId: this.imdbId,
|
||||
season: episode['season_number'],
|
||||
episode: episode['episode_number'],
|
||||
target: 'results_' ~ episode_id(episode['season_number'], episode['episode_number']),
|
||||
block: 'tvshow_results'
|
||||
}) }}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</episode-container>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% set paginator = this.episodes %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<table class="w-full max-w-[75vw] text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400 flex-row flex-no-wrap {{ results.media.mediaType == "tvshows" ? "hidden" : "options-table" }}"
|
||||
<table class="w-full max-w-[75vw] text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400 flex-row flex-no-wrap options-table"
|
||||
{{ stimulus_target(controller, "list") }}
|
||||
>
|
||||
<thead class="text-xs text-gray-700 uppercase dark:text-gray-400">
|
||||
|
||||
Reference in New Issue
Block a user