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 Dialog from '@stimulus-components/dialog';
|
||||||
import Dropdown from '@stimulus-components/dropdown';
|
import Dropdown from '@stimulus-components/dropdown';
|
||||||
import 'animate.css';
|
import 'animate.css';
|
||||||
import Brock from './components/brock.js';
|
import EpisodeContainer from './components/episode-container.js';
|
||||||
|
|
||||||
const app = startStimulusApp();
|
const app = startStimulusApp();
|
||||||
// register any custom, 3rd party controllers here
|
// register any custom, 3rd party controllers here
|
||||||
@@ -11,4 +11,4 @@ app.register('popover', Popover);
|
|||||||
app.register('dialog', Dialog);
|
app.register('dialog', Dialog);
|
||||||
app.register('dropdown', Dropdown);
|
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) {
|
if (window.location.hash) {
|
||||||
let targetElement = document.querySelector(window.location.hash);
|
let targetElement = document.querySelector(window.location.hash);
|
||||||
targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
if (targetElement) {
|
||||||
targetElement.classList.add('animate__animated', 'animate__pulse', 'animate__faster');
|
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() {
|
download() {
|
||||||
this.options.forEach(option => {
|
this.options.forEach(option => {
|
||||||
const optionSelector = option.querySelector('input[type="checkbox"]');
|
const optionSelector = option.querySelector('input[type="checkbox"]');
|
||||||
|
|||||||
@@ -130,3 +130,21 @@ dialog[data-dialog-target="dialog"][closing] {
|
|||||||
background: unset;
|
background: unset;
|
||||||
@apply bg-orange-500/80 text-black font-bold rounded-md
|
@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",
|
"bg-rose-600",
|
||||||
"alert-success",
|
"alert-success",
|
||||||
"alert-warning",
|
"alert-warning",
|
||||||
|
"font-bold",
|
||||||
"min-w-64",
|
"min-w-64",
|
||||||
"rotate-180",
|
"rotate-180",
|
||||||
"-rotate-180",
|
"-rotate-180",
|
||||||
|
|||||||
@@ -14,14 +14,11 @@
|
|||||||
{% if entity.status != "Complete" %}
|
{% if entity.status != "Complete" %}
|
||||||
<turbo-stream action="update" target="download_progress_{{ id }}">
|
<turbo-stream action="update" target="download_progress_{{ id }}">
|
||||||
<template>
|
<template>
|
||||||
<div class="text-black text-center rounded-sm text-bold bg-green-300 h-5 relative z-10"
|
<div class="background text-black text-center rounded-sm text-bold bg-green-300 h-5 relative z-10"
|
||||||
style="width:{{ entity.progress }}%">
|
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>
|
</div>
|
||||||
|
<div class="number text-black font-bold text-center z-40"
|
||||||
|
>{{ entity.progress }}%</div>
|
||||||
</template>
|
</template>
|
||||||
</turbo-stream>
|
</turbo-stream>
|
||||||
<turbo-stream action="update" target="action_buttons_{{ id }}">
|
<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">
|
<td class="whitespace-nowrap gap-2 text-sm align-middle text-gray-800 dark:text-gray-50">
|
||||||
{% if download.progress < 100 %}
|
{% if download.progress < 100 %}
|
||||||
<div class="flex flex-row items-center justify-center">
|
<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 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="text-black text-center rounded-sm text-bold bg-green-300 h-5 relative z-10"
|
<div class="background text-black text-center rounded-sm text-bold bg-green-300 h-5 relative z-10"
|
||||||
style="width:{{ download.progress }}%">
|
style="width: {{ download.progress }}%">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="number text-black font-bold text-center z-40"
|
||||||
|
>{{ download.progress }}%</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-black font-bold text-center z-40 ml-[-42px]">{{ download.progress }}%</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@
|
|||||||
|
|
||||||
{% if results.media.mediaType == "tvshows" %}
|
{% if results.media.mediaType == "tvshows" %}
|
||||||
<div class="flex flex-row gap-2 justify-end px-8">
|
<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
|
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
|
<a href="{{ path('app_user_preferences') }}" class="text-underline">preferences</a> to choose
|
||||||
the appropriate file(s).
|
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>"?
|
Do you wish to download <strong>season <span id="downloadSeasonModal">{{ results.season }}</span></strong> of "<strong>{{ results.media.title }}</strong>"?
|
||||||
</twig:Modal>
|
</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_target('result_filter', 'downloadSelected') }}
|
||||||
{{ stimulus_action('result_filter', 'downloadSelectedEpisodes', 'click') }}
|
{{ stimulus_action('result_filter', 'downloadSelectedEpisodes', 'click') }}
|
||||||
>Download Selected</button>
|
>Download Selected</button>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
>
|
>
|
||||||
<div data-live-id="{{ uniqid() }}" class="episode-container flex flex-col gap-4">
|
<div data-live-id="{{ uniqid() }}" class="episode-container flex flex-col gap-4">
|
||||||
{% for episode in this.getEpisodes().items %}
|
{% 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-tv-results-loading-icon-outlet=".loading-icon"
|
||||||
data-download-button-outlet=".download-btn"
|
data-download-button-outlet=".download-btn"
|
||||||
{{ stimulus_controller('tv_results', {
|
{{ stimulus_controller('tv_results', {
|
||||||
@@ -15,77 +15,73 @@
|
|||||||
active: 'true',
|
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="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">
|
<div class="flex flex-col md:flex-row gap-4">
|
||||||
{% if episode['poster'] != null %}
|
{% if episode['poster'] != null %}
|
||||||
<img class="w-full md:w-64 rounded-lg" src="{{ episode['poster'] }}" />
|
<img class="w-full md:w-64 rounded-lg" src="{{ episode['poster'] }}" />
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="w-full md:w-64 min-w-64 sticky h-[144px] rounded-lg bg-gray-700 flex items-center justify-center">
|
<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" />
|
<twig:ux:icon width="32" name="hugeicons:loading-01" />
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="flex flex-col gap-4 grow">
|
<div class="flex flex-col gap-4 grow">
|
||||||
<h4 class="text-md font-bold">
|
<h4 class="text-md font-bold">
|
||||||
{{ episode['episode_number'] }}. {{ episode['name'] }}
|
{{ episode['episode_number'] }}. {{ episode['name'] }}
|
||||||
</h4>
|
</h4>
|
||||||
<p>{{ episode['overview']|truncate }}</p>
|
<p>{{ episode['overview']|truncate }}</p>
|
||||||
<div>
|
<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"
|
<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'] }}.">
|
||||||
{{ stimulus_action('tv-results', 'toggleList', 'click') }}
|
<span {{ stimulus_target('tv-results', 'count') }}>-</span> results
|
||||||
>
|
</button>
|
||||||
<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'] }}">
|
<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') }}
|
{{ episode['air_date']|date(null, 'UTC') }}
|
||||||
</small>
|
</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,
|
title: this.title,
|
||||||
season: episode['season_number'],
|
season: episode['season_number'],
|
||||||
episode: episode['episode_number'],
|
episode: episode['episode_number'],
|
||||||
block: 'media_exists_badge',
|
block: 'media_exists_badge',
|
||||||
target: "meb_" ~ this.imdbId ~"_" ~ episode_id(episode['season_number'], episode['episode_number'])
|
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.">
|
<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
|
missing
|
||||||
</small>
|
</small>
|
||||||
</twig:Turbo:Frame>
|
</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>
|
</div>
|
||||||
<div class="flex flex-col gap-4 justify-between">
|
<div class="results-container inline-block overflow-hidden rounded-lg hidden">
|
||||||
<div class="flex flex-col items-center">
|
<twig:Turbo:Frame id="results_{{ episode_id(episode['season_number'], episode['episode_number']) }}" src="{{ path('app_torrentio_tvshows', {
|
||||||
<input type="checkbox"
|
tmdbId: this.tmdbId,
|
||||||
{{ stimulus_target('tv-results', 'episodeSelector') }}
|
imdbId: this.imdbId,
|
||||||
/>
|
season: episode['season_number'],
|
||||||
</div>
|
episode: episode['episode_number'],
|
||||||
<button class="flex flex-col items-end transition-transform duration-300 ease-in-out rotate-90"
|
target: 'results_' ~ episode_id(episode['season_number'], episode['episode_number']),
|
||||||
{{ stimulus_target('tv-results', 'toggleButton') }}
|
block: 'tvshow_results'
|
||||||
{{ 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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="inline-block overflow-hidden rounded-lg">
|
</episode-container>
|
||||||
<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>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% set paginator = this.episodes %}
|
{% 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") }}
|
{{ stimulus_target(controller, "list") }}
|
||||||
>
|
>
|
||||||
<thead class="text-xs text-gray-700 uppercase dark:text-gray-400">
|
<thead class="text-xs text-gray-700 uppercase dark:text-gray-400">
|
||||||
|
|||||||
Reference in New Issue
Block a user