feat: download data preview modal

This commit is contained in:
2025-08-02 22:46:21 -05:00
parent 0430dba6a9
commit 2becc98d61
19 changed files with 2058 additions and 9 deletions

4
assets/bootstrap.js vendored
View File

@@ -1,5 +1,7 @@
import PreviewContentDialog from "./components/preview-content-dialog.js";
import EpisodeContainer from './components/episode-container.js';
import DownloadOptionTr from './components/download-option-tr.js';
import DownloadListRow from './components/download-list-row.js';
import MovieContainer from "./components/movie-container.js";
import { startStimulusApp } from '@symfony/stimulus-bundle';
@@ -14,6 +16,8 @@ app.register('popover', Popover);
app.register('dialog', Dialog);
app.register('dropdown', Dropdown);
customElements.define('preview-content-dialog', PreviewContentDialog, {extends: 'dialog'});
customElements.define('episode-container', EpisodeContainer);
customElements.define('movie-container', MovieContainer);
customElements.define('dl-tr', DownloadOptionTr, {extends: 'tr'});
customElements.define('download-list-row', DownloadListRow, {extends: 'tr'});

View File

@@ -0,0 +1,110 @@
export default class DownloadListRow extends HTMLTableRowElement {
constructor() {
super();
this.downloadId = this.getAttribute('download-id');
this.imdbId = this.getAttribute('imdb-id');
this.mediaTitle = this.getAttribute('media-title');
this.url = this.getAttribute('url');
this.filename = this.getAttribute('filename');
this.status = this.getAttribute('status');
this.progress = this.getAttribute('progress');
this.mediaType = this.getAttribute('media-type');
this.episodeId = this.getAttribute('episode-id');
this.createdAt = this.getAttribute('created-at');
this.updatedAt = this.getAttribute('updated-at');
// this.previewContent = this.previewContent.bind(this);
}
static get observedAttributes() {
return ['download-id', 'imdb-id', 'media-title', 'url', 'filename', 'status', 'progress', 'media-type', 'episode-id', 'created-at', 'updated-at'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue) {
this[name] = newValue;
this.setAttribute(name, newValue);
}
}
previewContent() {
return `
<table class="table-auto flex flex-row">
<thead>
<tr class="flex flex-col">
<th class="px-4 py-2">
<div class="text-right whitespace-nowrap ">ID</div>
</th>
<th class="px-4 py-2">
<div class="text-right whitespace-nowrap ">IMDB ID</div>
</th>
<th class="px-4 py-2">
<div class="text-right whitespace-nowrap ">Title</div>
</th>
<th class="px-4 py-2">
<div class="text-right whitespace-nowrap ">URL</div>
</th>
<th class="px-4 py-2">
<div class="text-right whitespace-nowrap ">Filename</div>
</th>
<th class="px-4 py-2">
<div class="text-right whitespace-nowrap ">Status</div>
</th>
<th class="px-4 py-2">
<div class="text-right whitespace-nowrap ">Progress</div>
</th>
<th class="px-4 py-2">
<div class="text-right whitespace-nowrap ">Media Type</div>
</th>
<th class="px-4 py-2">
<div class="text-right whitespace-nowrap ">Episode ID</div>
</th>
<th class="px-4 py-2">
<div class="text-right whitespace-nowrap ">Created At</div>
</th>
<th class="px-4 py-2">
<div class="text-right whitespace-nowrap ">Updated At</div>
</th>
</tr>
</thead>
<tbody>
<tr class="flex flex-col">
<th class="px-4 py-2">
<div class="text-left whitespace-nowrap font-normal">${this.getAttribute('download-id') ?? "-"}</div>
</th>
<th class="px-4 py-2">
<div class="text-left whitespace-nowrap font-normal">${this.getAttribute('imdb-id') ?? "-"}</div>
</th>
<th class="px-4 py-2">
<div class="text-left whitespace-nowrap font-normal">${this.getAttribute('media-title') ?? "-"}</div>
</th>
<th class="px-4 py-2">
<div class="text-left whitespace-nowrap font-normal">${this.getAttribute('url') ?? "-"}</div>
</th>
<th class="px-4 py-2">
<div class="text-left whitespace-nowrap font-normal">${this.getAttribute('filename') ?? "-"}</div>
</th>
<th class="px-4 py-2">
<div class="text-left whitespace-nowrap font-normal">${this.getAttribute('status') ?? "-"}</div>
</th>
<th class="px-4 py-2">
<div class="text-left whitespace-nowrap font-normal">${this.getAttribute('progress') ?? "-"}</div>
</th>
<th class="px-4 py-2">
<div class="text-left whitespace-nowrap font-normal">${this.getAttribute('media-type') ?? "-"}</div>
</th>
<th class="px-4 py-2">
<div class="text-left whitespace-nowrap font-normal">${this.getAttribute('episode-id') ?? "-"}</div>
</th>
<th class="px-4 py-2">
<div class="text-left whitespace-nowrap font-normal">${this.getAttribute('created-at') ?? "-"}</div>
</th>
<th class="px-4 py-2">
<div class="text-left whitespace-nowrap font-normal">${this.getAttribute('updated-at') ?? "-"}</div>
</th>
</tr>
</tbody>
</table>
`;
}
}

View File

@@ -0,0 +1,35 @@
export default class PreviewContentDialog extends HTMLDialogElement {
#headingEl;
#contentEl;
#closeBtnEl;
constructor() {
super();
this.#headingEl = this.querySelector('.modal-heading');
this.#contentEl = this.querySelector('.modal-content');
this.#closeBtnEl = this.querySelector('.modal-close');
this.setHeading = this.setHeading.bind(this);
this.setContent = this.setContent.bind(this);
document.addEventListener('showPreviewContentModal', (event) => {
this.display(event.detail);
});
document.addEventListener('hidePreviewContentModal', (e) => this.close());
this.#closeBtnEl.addEventListener('click', () => this.close());
}
setHeading(heading) {
this.#headingEl.innerHTML = heading;
}
setContent(content) {
this.#contentEl.innerHTML = content;
}
display({ heading, content }) {
this.setHeading(heading);
this.setContent(content);
this.showModal();
}
}

View File

@@ -20,13 +20,46 @@ export default class extends Controller {
// Here you can add event listeners on the element or target elements,
// add or remove classes, attributes, dispatch custom events, etc.
// this.fooTarget.addEventListener('click', this._fooBar)
// this.element.addEventListener('click', (event) => {
// let previewContentModal = document.querySelector('#previewContentModal');
// // previewContentModal.setHeading(event.target.dataset['title']);
// // previewContentModal.setContent('<p>Testing this here thingy-ma-bob!</p>');
// // previewContentModal.showModal();
// let content, heading = ""
// if (event.target.tagName !== "TR") {
// content = event.target.parentElement.previewContent();
// heading = event.target.parentElement.mediaTitle;
// } else {
// content = event.target.previewContent();
// heading = event.target.mediaTitle;
// }
//
// document.dispatchEvent(new CustomEvent('showPreviewContentModal', {detail: {heading: heading, content: content}}))
// })
}
downloadTargetConnected(target) {
let downloads = this.element.querySelectorAll('tbody tr');
if (downloads.length > 5) {
target.classList.add('hidden');
}
console.log(target)
downloads.forEach(download => {
console.log(download)
download.mediaTitle = download.getAttribute('media-title');
download.addEventListener('click', (event) => {
// let previewContentModal = document.querySelector('#previewContentModal');
let content, heading = ""
if (event.target.tagName !== "TR") {
content = event.target.parentElement.previewContent();
heading = event.target.parentElement.mediaTitle;
} else {
content = event.target.previewContent();
heading = event.target.mediaTitle;
}
document.dispatchEvent(new CustomEvent('showPreviewContentModal', {detail: {heading: heading, content: content}}))
})
})
}
pauseDownload(data) {