2025-08-12 21:43:26 -08:00

155 lines
5.3 KiB
Handlebars

{{#> main}}
<!-- Header -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/video.js@8.22.0/dist/video-js.min.css">
<header class="container">
{{> navbar}}
</header>
<!-- ./ Header -->
<style>
.handle {
cursor: grab;
}
</style>
<main class="container">
<section>
<h1>Upload {{upload.id}}</h1>
<h2>Stream Date</h2>
<p>{{upload.streamDate}}</p>
{{#if upload.notes}}
<h2>Notes</h2>
<p class="breaklines">{{upload.notes}}</p>
{{/if}}
<h2>Vtubers</h2>
<ul>
{{#each upload.vtubers}}
<li>{{this.displayName}}</li>
{{/each}}
</ul>
<h2>Files</h2>
<p>File segments listed here will be concatenated together in the top-down order listed.</p>
<p><i>Drag &amp; drop to reorder</i></p>
<div id="segmentKeys">
{{#each upload.segmentKeys}}
<div data-key="{{this.key}}" data-name="{{this.name}}">
<svg class="handle" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M4 15v-2h16v2zm0-4V9h16v2z" />
</svg><a href="{{getCdnUrl this.key}}" target="_blank">{{this.name}}</a>
</div>
{{/each}}
</div>
<h2>Status</h2>
{{upload.status}}
<h3></h3>
<form method="PATCH" hx-patch="/uploads/{{upload.id}}" hx-params="*" hx-target="body">
{{#if (isModerator user)}}
<fieldset>
<label for="radio-pending">
<input type="radio" id="radio-pending" name="status" value="pending" {{#if (isEqual upload.status 'pending')}}
checked {{/if}}>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
<path fill="currentColor"
d="M7 13.5q.625 0 1.063-.437T8.5 12t-.437-1.062T7 10.5t-1.062.438T5.5 12t.438 1.063T7 13.5m5 0q.625 0 1.063-.437T13.5 12t-.437-1.062T12 10.5t-1.062.438T10.5 12t.438 1.063T12 13.5m5 0q.625 0 1.063-.437T18.5 12t-.437-1.062T17 10.5t-1.062.438T15.5 12t.438 1.063T17 13.5M12 22q-2.075 0-3.9-.788t-3.175-2.137T2.788 15.9T2 12t.788-3.9t2.137-3.175T8.1 2.788T12 2t3.9.788t3.175 2.137T21.213 8.1T22 12t-.788 3.9t-2.137 3.175t-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4T6.325 6.325T4 12t2.325 5.675T12 20m0-8" />
</svg> pending
</label>
<label for="radio-approved">
<input type="radio" id="radio-approved" name="status" value="approved"
{{#if (isEqual upload.status 'approved')}} checked {{/if}}>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<path fill="currentColor" d="m14 21.414l-5-5.001L10.413 15L14 18.586L21.585 11L23 12.415z" />
<path fill="currentColor"
d="M16 2a14 14 0 1 0 14 14A14 14 0 0 0 16 2m0 26a12 12 0 1 1 12-12a12 12 0 0 1-12 12" />
</svg> approved
</label>
<label for="radio-rejected">
<input type="radio" id="radio-rejected" name="status" value="rejected"
{{#if (isEqual upload.status 'rejected')}} checked {{/if}}>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<path fill="currentColor"
d="M17.414 16L26 7.414L24.586 6L16 14.586L7.414 6L6 7.414L14.586 16L6 24.586L7.414 26L16 17.414L24.586 26L26 24.586z" />
</svg> rejected
</label>
</fieldset>
{{else}}
{{!-- When the user saves, we go to pending state where a moderator is summoned. --}}
<input type="hidden" name="status" value="pending">
{{/if}}
<input type="hidden" name="segmentKeys" value="{{json upload.segmentKeys}}">
<h3></h3>
{{!-- {{#if (isEqual upload.status "pending")}} --}}
<button name="save">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 1536 1536">
<path fill="currentColor"
d="M384 1408h768v-384H384zm896 0h128V512q0-14-10-38.5t-20-34.5l-281-281q-10-10-34-20t-39-10v416q0 40-28 68t-68 28H352q-40 0-68-28t-28-68V128H128v1280h128V992q0-40 28-68t68-28h832q40 0 68 28t28 68zM896 480V160q0-13-9.5-22.5T864 128H672q-13 0-22.5 9.5T640 160v320q0 13 9.5 22.5T672 512h192q13 0 22.5-9.5T896 480m640 32v928q0 40-28 68t-68 28H96q-40 0-68-28t-28-68V96q0-40 28-68T96 0h928q40 0 88 20t76 48l280 280q28 28 48 76t20 88" />
</svg>
Save
</button>
{{!-- {{/if}} --}}
</form>
<div id="save-status">
{{message}}
</div>
</section>
</main>
<script src="https://cdn.jsdelivr.net/npm/video.js@8.22.0/dist/video.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.15.6/Sortable.min.js"
integrity="sha512-csIng5zcB+XpulRUa+ev1zKo7zRNGpEaVfNB9On1no9KYTEY/rLGAEEpvgdw6nim1WdTuihZY1eqZ31K7/fZjw=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
function setupSortable() {
const input = document.querySelector('input[name="segmentKeys"]');
const container = document.getElementById('segmentKeys');
if (!input || !container) return;
new Sortable(container, {
handle: '.handle',
animation: 150,
onSort: (evt) => {
const data = Array.from(evt.to.children).map(el => ({ key: el.dataset.key, name: el.dataset.name }));
input.value = JSON.stringify(data);
}
});
}
// Initial load
setupSortable();
</script>
{{/main}}