mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Completes end-to-end multi-webseed support: the editor can now see, add, and remove every web seed a video carries. - magnetShared: promote normalizeWebSeedList to a shared export (videoNotePayload now imports it) and add setMagnetWebSeeds(), which replaces a magnet's COMPLETE ws= set with exactly the requested list. ensureWebSeeds is append-only, so without set-semantics a webseed a user deleted would linger in the magnet; setMagnetWebSeeds strips the existing ws= params first, making removal stick. - edit-video-modal.html: the single "Web seed (ws=)" input becomes a "Web seeds (one per line)" textarea with backup-origin help text. - EditModal: open() populates the field from extractAllWebSeeds() (every seed, not just the first). On save, when the field was manually edited the magnet's ws set is rebuilt from the field via setMagnetWebSeeds (true add/remove); otherwise existing seeds are preserved untouched. The content `ws` field still stores the primary (first) seed while the magnet carries the full set. Mutation-verified (no-strip and no-add both fail the removal/add tests); build, relevant lints (inline-styles, tokens, innerHTML), and full unit suite green. Co-Authored-By: Claude Opus 4.8 <[email protected]>
968 lines
39 KiB
HTML
968 lines
39 KiB
HTML
<!-- components/edit-video-modal.html -->
|
|
<div
|
|
id="editVideoModal"
|
|
class="bv-modal hidden items-start md:items-center"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
tabindex="-1"
|
|
data-ds="new"
|
|
>
|
|
<div id="editVideoModalOverlay" class="bv-modal-backdrop"></div>
|
|
|
|
<div class="bv-modal__panel modal-sheet max-h-modal-shell overflow-y-auto" tabindex="-1">
|
|
<div class="modal-header">
|
|
<h2 class="text-xl font-bold text-text">Edit Video Note</h2>
|
|
<button id="closeEditVideoModal" class="modal-close">
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="h-6 w-6"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M6 18L18 6M6 6l12 12"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="modal-body space-y-6">
|
|
<p class="text-sm text-muted">
|
|
Fields that already have values are locked. Click <strong>Edit field</strong> to make changes.
|
|
</p>
|
|
|
|
<form id="editVideoForm" class="space-y-5">
|
|
<div class="space-y-1">
|
|
<label for="editVideoTitle" class="block text-sm font-medium text-text">
|
|
Title
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<input
|
|
type="text"
|
|
id="editVideoTitle"
|
|
class="flex-1 input"
|
|
placeholder="Video title"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoTitle"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- NOTE: Keep this NIP-71 markup in sync with the upload and revert modals. -->
|
|
<div
|
|
class="space-y-4 rounded-lg border border-border/70 bg-overlay-black/30 p-4"
|
|
id="editNip71EventDetails"
|
|
data-nip71-section="event-details"
|
|
>
|
|
<fieldset
|
|
id="editNip71KindFieldset"
|
|
class="space-y-2"
|
|
data-nip71-fieldset="kind"
|
|
>
|
|
<legend class="text-sm font-semibold text-text">
|
|
NIP-71 event type
|
|
</legend>
|
|
<p class="text-xs text-muted">
|
|
Choose the video format. <span class="font-medium text-muted-strong">Kind 21</span> is a full video, while
|
|
<span class="font-medium text-muted-strong">Kind 22</span> is a short.
|
|
</p>
|
|
<div
|
|
class="form-control"
|
|
role="radiogroup"
|
|
aria-labelledby="editNip71KindFieldset"
|
|
>
|
|
<div class="menu sm:flex-row sm:flex-wrap sm:py-0" role="presentation">
|
|
<label class="menu__item gap-3 px-0 py-0" for="editNip71KindLong">
|
|
<input
|
|
type="radio"
|
|
name="editNip71Kind"
|
|
id="editNip71KindLong"
|
|
value="21"
|
|
checked
|
|
data-nip71-input="kind"
|
|
class="h-4 w-4 border-border bg-panel text-info focus:ring-info"
|
|
/>
|
|
<span class="text-sm text-text">Normal video (kind 21)</span>
|
|
</label>
|
|
<label class="menu__item gap-3 px-0 py-0" for="editNip71KindShort">
|
|
<input
|
|
type="radio"
|
|
name="editNip71Kind"
|
|
id="editNip71KindShort"
|
|
value="22"
|
|
data-nip71-input="kind"
|
|
class="h-4 w-4 border-border bg-panel text-info focus:ring-info"
|
|
/>
|
|
<span class="text-sm text-text">Short video (kind 22)</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<div class="grid gap-4 md:grid-cols-2" data-nip71-grid="metadata">
|
|
<div class="space-y-2">
|
|
<label for="editNip71PublishedAt" class="block text-sm font-medium text-text">
|
|
Published at
|
|
</label>
|
|
<input
|
|
type="datetime-local"
|
|
id="editNip71PublishedAt"
|
|
data-nip71-input="published_at"
|
|
class="input"
|
|
/>
|
|
<p class="text-xs text-muted">
|
|
Set the canonical publish time for cross-client ordering.
|
|
</p>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label for="editNip71AltText" class="block text-sm font-medium text-text">
|
|
Alt text
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="editNip71AltText"
|
|
data-nip71-input="alt"
|
|
placeholder="Describe the visuals for screen readers"
|
|
class="input"
|
|
/>
|
|
<p class="text-xs text-muted">
|
|
Plain-language fallback shown when the media cannot load.
|
|
</p>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label for="editNip71Duration" class="block text-sm font-medium text-text">
|
|
Duration (seconds)
|
|
</label>
|
|
<input
|
|
type="number"
|
|
id="editNip71Duration"
|
|
min="0"
|
|
step="0.001"
|
|
data-nip71-input="duration"
|
|
class="input"
|
|
/>
|
|
<p class="text-xs text-muted">
|
|
Optional legacy fallback in seconds (fractions allowed) for clients that expect a top-level duration.
|
|
</p>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label for="editNip71ContentWarning" class="block text-sm font-medium text-text">
|
|
Content warning
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="editNip71ContentWarning"
|
|
data-nip71-input="content-warning"
|
|
placeholder="e.g., Flashing lights"
|
|
class="input"
|
|
/>
|
|
<p class="text-xs text-muted">
|
|
Leave blank if the video is safe for all audiences.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<label for="editNip71Summary" class="block text-sm font-medium text-text">
|
|
Summary
|
|
</label>
|
|
<textarea
|
|
id="editNip71Summary"
|
|
rows="3"
|
|
data-nip71-input="summary"
|
|
class="textarea"
|
|
placeholder="Short synopsis used as the Nostr content field"
|
|
></textarea>
|
|
<p class="text-xs text-muted">
|
|
This becomes the event content. Keep it concise for Nostr readers.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<fieldset
|
|
id="editNip71TagsFieldset"
|
|
class="space-y-6 rounded-lg border border-border/70 bg-overlay-black/30 p-4"
|
|
data-nip71-section="tags"
|
|
>
|
|
<legend class="relative text-sm font-semibold text-text">
|
|
<span class="inline-block -ml-2 rounded px-2 bg-overlay-black/30">NIP-71 tags</span>
|
|
</legend>
|
|
<p class="text-xs text-muted">
|
|
Use the controls below to describe media variants, captions, chapters, participants, and references.
|
|
</p>
|
|
|
|
<section class="space-y-4" aria-labelledby="editNip71ImetaLabel" data-nip71-repeater="imeta">
|
|
<div class="flex items-center justify-between">
|
|
<h3 id="editNip71ImetaLabel" class="text-sm font-medium text-text">Image metadata (imeta)</h3>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-xs font-semibold"
|
|
data-nip71-add="imeta"
|
|
aria-describedby="editNip71ImetaHelp"
|
|
>
|
|
Add variant
|
|
</button>
|
|
</div>
|
|
<p id="editNip71ImetaHelp" class="text-xs text-muted">
|
|
Provide dimensions, MIME type, and resource links for each variant. Nested repeaters let you attach multiple
|
|
<code>image</code>, <code>fallback</code>, or <code>service</code> values.
|
|
</p>
|
|
<div id="editNip71ImetaList" class="space-y-4" data-nip71-list="imeta"></div>
|
|
<template id="editNip71ImetaTemplate" data-nip71-template="imeta">
|
|
<article class="card space-y-3 bg-surface/60 p-4" data-nip71-entry="imeta">
|
|
<div class="grid gap-3 md:grid-cols-2">
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">
|
|
MIME type (<code>m</code>)
|
|
</label>
|
|
<input
|
|
type="text"
|
|
data-nip71-field="m"
|
|
placeholder="video/mp4"
|
|
class="input"
|
|
/>
|
|
<p class="text-3xs text-muted">RFC 2046 media type for this encoding.</p>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">
|
|
Pixel dimensions (<code>dim</code>)
|
|
</label>
|
|
<input
|
|
type="text"
|
|
data-nip71-field="dim"
|
|
placeholder="1920x1080"
|
|
class="input"
|
|
/>
|
|
<p class="text-3xs text-muted">Formatted as widthxheight.</p>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">
|
|
Streaming URL (<code>url</code>)
|
|
</label>
|
|
<input
|
|
type="url"
|
|
data-nip71-field="url"
|
|
placeholder="https://cdn.example.com/variant.m3u8"
|
|
class="input"
|
|
/>
|
|
<p class="text-3xs text-muted">HTTPS variant URL shared across clients.</p>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">
|
|
Magnet (<code>x</code>)
|
|
</label>
|
|
<input
|
|
type="text"
|
|
data-nip71-field="x"
|
|
placeholder="magnet:?xt=urn:btih:..."
|
|
class="input"
|
|
/>
|
|
<p class="text-3xs text-muted">Optional magnet pointer if the variant is seeded via P2P.</p>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">
|
|
Duration seconds (<code>duration</code>)
|
|
</label>
|
|
<input
|
|
type="number"
|
|
data-nip71-field="duration"
|
|
min="0"
|
|
step="0.001"
|
|
placeholder="29.97"
|
|
class="input"
|
|
/>
|
|
<p class="text-3xs text-muted">Fractional seconds supported; clients use this for precise timelines.</p>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">
|
|
Bitrate bps (<code>bitrate</code>)
|
|
</label>
|
|
<input
|
|
type="number"
|
|
data-nip71-field="bitrate"
|
|
min="0"
|
|
step="1"
|
|
placeholder="3500000"
|
|
class="input"
|
|
/>
|
|
<p class="text-3xs text-muted">Average bits per second for this variant.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-3" data-nip71-nested="image">
|
|
<div class="flex items-center justify-between">
|
|
<h4 class="text-xs font-semibold uppercase tracking-wide text-muted">Image values</h4>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-nested-add="image"
|
|
>
|
|
Add image URL
|
|
</button>
|
|
</div>
|
|
<div class="space-y-2" data-nip71-nested-list="image"></div>
|
|
<template data-nip71-nested-template="image">
|
|
<div class="flex items-center gap-2" data-nip71-nested-entry="image">
|
|
<input
|
|
type="url"
|
|
placeholder="https://cdn.example.com/poster.jpg"
|
|
data-nip71-nested-field="image"
|
|
class="flex-1 input"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-remove="nested"
|
|
aria-label="Remove image URL"
|
|
>
|
|
Remove
|
|
</button>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
|
|
<div class="space-y-3" data-nip71-nested="fallback">
|
|
<div class="flex items-center justify-between">
|
|
<h4 class="text-xs font-semibold uppercase tracking-wide text-muted">Fallback URLs</h4>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-nested-add="fallback"
|
|
>
|
|
Add fallback
|
|
</button>
|
|
</div>
|
|
<div class="space-y-2" data-nip71-nested-list="fallback"></div>
|
|
<template data-nip71-nested-template="fallback">
|
|
<div class="flex items-center gap-2" data-nip71-nested-entry="fallback">
|
|
<input
|
|
type="url"
|
|
placeholder="https://cdn.backup.net/video.mp4"
|
|
data-nip71-nested-field="fallback"
|
|
class="flex-1 input"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-remove="nested"
|
|
aria-label="Remove fallback URL"
|
|
>
|
|
Remove
|
|
</button>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
|
|
<div class="space-y-3" data-nip71-nested="service">
|
|
<div class="flex items-center justify-between">
|
|
<h4 class="text-xs font-semibold uppercase tracking-wide text-muted">Services</h4>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-nested-add="service"
|
|
>
|
|
Add service
|
|
</button>
|
|
</div>
|
|
<div class="space-y-2" data-nip71-nested-list="service"></div>
|
|
<template data-nip71-nested-template="service">
|
|
<div class="flex items-center gap-2" data-nip71-nested-entry="service">
|
|
<input
|
|
type="text"
|
|
placeholder="https://api.example.com"
|
|
data-nip71-nested-field="service"
|
|
class="flex-1 input"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-remove="nested"
|
|
aria-label="Remove service entry"
|
|
>
|
|
Remove
|
|
</button>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-remove="imeta"
|
|
>
|
|
Remove variant
|
|
</button>
|
|
</div>
|
|
</article>
|
|
</template>
|
|
</section>
|
|
|
|
<section class="space-y-4" aria-labelledby="editNip71TextTracksLabel" data-nip71-repeater="text-track">
|
|
<div class="flex items-center justify-between">
|
|
<h3 id="editNip71TextTracksLabel" class="text-sm font-medium text-text">
|
|
Caption & subtitle tracks (text-track)
|
|
</h3>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-xs font-semibold"
|
|
data-nip71-add="text-track"
|
|
aria-describedby="editNip71TextTracksHelp"
|
|
>
|
|
Add track
|
|
</button>
|
|
</div>
|
|
<p id="editNip71TextTracksHelp" class="text-xs text-muted">
|
|
Supply caption or subtitle URLs along with file type and language so players can surface accessibility features.
|
|
</p>
|
|
<div id="editNip71TextTrackList" class="space-y-4" data-nip71-list="text-track"></div>
|
|
<template id="editNip71TextTrackTemplate" data-nip71-template="text-track">
|
|
<article class="card space-y-3 bg-surface/60 p-4" data-nip71-entry="text-track">
|
|
<div class="grid gap-3 md:grid-cols-3">
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">Track URL</label>
|
|
<input
|
|
type="url"
|
|
data-nip71-field="url"
|
|
placeholder="https://cdn.example.com/subs.vtt"
|
|
class="input"
|
|
/>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">Type</label>
|
|
<input
|
|
type="text"
|
|
data-nip71-field="type"
|
|
placeholder="text/vtt"
|
|
class="input"
|
|
/>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">Language</label>
|
|
<input
|
|
type="text"
|
|
data-nip71-field="language"
|
|
placeholder="en"
|
|
class="input"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-remove="text-track"
|
|
>
|
|
Remove track
|
|
</button>
|
|
</div>
|
|
</article>
|
|
</template>
|
|
</section>
|
|
|
|
<section class="space-y-4" aria-labelledby="editNip71SegmentsLabel" data-nip71-repeater="segment">
|
|
<div class="flex items-center justify-between">
|
|
<h3 id="editNip71SegmentsLabel" class="text-sm font-medium text-text">Chapters & segments (segment)</h3>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-xs font-semibold"
|
|
data-nip71-add="segment"
|
|
aria-describedby="editNip71SegmentsHelp"
|
|
>
|
|
Add segment
|
|
</button>
|
|
</div>
|
|
<p id="editNip71SegmentsHelp" class="text-xs text-muted">
|
|
Outline chapters with start and end times, titles, and optional thumbnails.
|
|
</p>
|
|
<div id="editNip71SegmentList" class="space-y-4" data-nip71-list="segment"></div>
|
|
<template id="editNip71SegmentTemplate" data-nip71-template="segment">
|
|
<article class="card space-y-3 bg-surface/60 p-4" data-nip71-entry="segment">
|
|
<div class="grid gap-3 md:grid-cols-2">
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">Start (seconds)</label>
|
|
<input
|
|
type="number"
|
|
data-nip71-field="start"
|
|
min="0"
|
|
step="1"
|
|
class="input"
|
|
/>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">End (seconds)</label>
|
|
<input
|
|
type="number"
|
|
data-nip71-field="end"
|
|
min="0"
|
|
step="1"
|
|
class="input"
|
|
/>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">Title</label>
|
|
<input
|
|
type="text"
|
|
data-nip71-field="title"
|
|
placeholder="Chapter title"
|
|
class="input"
|
|
/>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">Thumbnail URL</label>
|
|
<input
|
|
type="url"
|
|
data-nip71-field="thumbnail"
|
|
placeholder="https://cdn.example.com/frame.jpg"
|
|
class="input"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-remove="segment"
|
|
>
|
|
Remove segment
|
|
</button>
|
|
</div>
|
|
</article>
|
|
</template>
|
|
</section>
|
|
|
|
<section class="space-y-4" aria-labelledby="editNip71HashtagsLabel" data-nip71-repeater="t">
|
|
<div class="flex items-center justify-between">
|
|
<h3 id="editNip71HashtagsLabel" class="text-sm font-medium text-text">Hashtags (<code>t</code>)</h3>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-xs font-semibold"
|
|
data-nip71-add="t"
|
|
>
|
|
Add hashtag
|
|
</button>
|
|
</div>
|
|
<p class="text-xs text-muted">
|
|
Enter keywords; leading <code>#</code> characters are stripped automatically when saving.
|
|
</p>
|
|
<div id="editNip71HashtagList" class="space-y-2" data-nip71-list="t"></div>
|
|
<template id="editNip71HashtagTemplate" data-nip71-template="t">
|
|
<div class="flex items-center gap-2" data-nip71-entry="t">
|
|
<input
|
|
type="text"
|
|
data-nip71-field="value"
|
|
placeholder="#nostr"
|
|
class="flex-1 input"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-remove="t"
|
|
>
|
|
Remove
|
|
</button>
|
|
</div>
|
|
</template>
|
|
</section>
|
|
|
|
<section class="space-y-4" aria-labelledby="editNip71ParticipantsLabel" data-nip71-repeater="p">
|
|
<div class="flex items-center justify-between">
|
|
<h3 id="editNip71ParticipantsLabel" class="text-sm font-medium text-text">Participants (<code>p</code>)</h3>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-xs font-semibold"
|
|
data-nip71-add="p"
|
|
>
|
|
Add participant
|
|
</button>
|
|
</div>
|
|
<div id="editNip71ParticipantList" class="space-y-3" data-nip71-list="p"></div>
|
|
<template id="editNip71ParticipantTemplate" data-nip71-template="p">
|
|
<article class="card space-y-3 bg-surface/60 p-4" data-nip71-entry="p">
|
|
<div class="grid gap-3 md:grid-cols-2">
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">Participant pubkey</label>
|
|
<input
|
|
type="text"
|
|
data-nip71-field="pubkey"
|
|
placeholder="npub1... or hex"
|
|
class="input"
|
|
/>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="block text-xs font-medium text-muted-strong">Relay hint</label>
|
|
<input
|
|
type="text"
|
|
data-nip71-field="relay"
|
|
placeholder="wss://relay.example.com"
|
|
class="input"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-remove="p"
|
|
>
|
|
Remove participant
|
|
</button>
|
|
</div>
|
|
</article>
|
|
</template>
|
|
</section>
|
|
|
|
<section class="space-y-4" aria-labelledby="editNip71ReferencesLabel" data-nip71-repeater="r">
|
|
<div class="flex items-center justify-between">
|
|
<h3 id="editNip71ReferencesLabel" class="text-sm font-medium text-text">Reference links (<code>r</code>)</h3>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-xs font-semibold"
|
|
data-nip71-add="r"
|
|
>
|
|
Add reference
|
|
</button>
|
|
</div>
|
|
<div id="editNip71ReferenceList" class="space-y-2" data-nip71-list="r"></div>
|
|
<template id="editNip71ReferenceTemplate" data-nip71-template="r">
|
|
<div class="flex items-center gap-2" data-nip71-entry="r">
|
|
<input
|
|
type="url"
|
|
data-nip71-field="url"
|
|
placeholder="https://example.com/context"
|
|
class="flex-1 input"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring text-3xs font-medium"
|
|
data-nip71-remove="r"
|
|
>
|
|
Remove
|
|
</button>
|
|
</div>
|
|
</template>
|
|
</section>
|
|
</fieldset>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoUrl" class="block text-sm font-medium text-text">
|
|
Hosted video URL (https)
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<input
|
|
type="url"
|
|
id="editVideoUrl"
|
|
class="flex-1 input"
|
|
placeholder="https://cdn.example.com/video.mp4"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoUrl"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoWs" class="block text-sm font-medium text-text">
|
|
Web seeds (ws=, one per line)
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<textarea
|
|
id="editVideoWs"
|
|
rows="2"
|
|
class="flex-1 textarea"
|
|
placeholder="https://cdn.example.com/video.mp4 https://backup.example.com/video.mp4"
|
|
></textarea>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoWs"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
<p class="text-xs text-muted">
|
|
Add a backup origin so the swarm keeps streaming if the primary is
|
|
overloaded. Each must serve the exact same file.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoXs" class="block text-sm font-medium text-text">
|
|
.torrent URL (xs=)
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<input
|
|
type="url"
|
|
id="editVideoXs"
|
|
class="flex-1 input"
|
|
placeholder="https://cdn.example.com/video.torrent"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoXs"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoMagnet" class="block text-sm font-medium text-text">
|
|
Magnet link
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<input
|
|
type="text"
|
|
id="editVideoMagnet"
|
|
class="flex-1 input"
|
|
placeholder="magnet:?xt=urn:btih:..."
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoMagnet"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoThumbnail" class="block text-sm font-medium text-text">
|
|
Thumbnail URL
|
|
</label>
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
|
<input
|
|
type="url"
|
|
id="editVideoThumbnail"
|
|
class="flex-1 input"
|
|
placeholder="https://cdn.example.com/preview.jpg"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoThumbnail"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<label for="editVideoDescription" class="block text-sm font-medium text-text">
|
|
Description
|
|
</label>
|
|
<div class="flex flex-col gap-2">
|
|
<textarea
|
|
id="editVideoDescription"
|
|
rows="4"
|
|
class="textarea"
|
|
placeholder="What is this video about?"
|
|
></textarea>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden self-start text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoDescription"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<span id="editVideoVisibilityLabel" class="block text-sm font-medium text-text">
|
|
Visibility
|
|
</span>
|
|
<div
|
|
class="space-y-3 rounded-md border border-border/70 bg-overlay-black/30 p-3"
|
|
role="group"
|
|
aria-labelledby="editVideoVisibilityLabel"
|
|
data-visibility-toggle
|
|
>
|
|
<div class="flex flex-wrap items-center gap-2 sm:justify-between">
|
|
<div
|
|
class="video-visibility-toggle"
|
|
data-visibility-options
|
|
>
|
|
<button
|
|
type="button"
|
|
class="video-visibility-toggle__option focus-ring"
|
|
data-visibility-option="public"
|
|
aria-pressed="false"
|
|
>
|
|
Public
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="video-visibility-toggle__option focus-ring"
|
|
data-visibility-option="private"
|
|
aria-pressed="false"
|
|
>
|
|
Private
|
|
</button>
|
|
</div>
|
|
<input
|
|
type="checkbox"
|
|
id="editVideoIsPrivate"
|
|
class="hidden"
|
|
data-default-checked="false"
|
|
aria-hidden="true"
|
|
/>
|
|
</div>
|
|
<p class="text-xs text-muted" data-visibility-helper>
|
|
Private notes stay visible only to you. Switch back to public when you're ready to share.
|
|
</p>
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoIsPrivate"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<label
|
|
for="editVideoIsNsfw"
|
|
id="editVideoIsNsfwLabel"
|
|
class="block text-sm font-medium text-text"
|
|
>
|
|
NSFW content
|
|
</label>
|
|
<div
|
|
class="form-control"
|
|
role="group"
|
|
aria-labelledby="editVideoIsNsfwLabel"
|
|
>
|
|
<label class="menu__item gap-3 px-0 py-0 text-left" for="editVideoIsNsfw">
|
|
<input
|
|
type="checkbox"
|
|
id="editVideoIsNsfw"
|
|
class="checkbox"
|
|
data-default-checked="false"
|
|
/>
|
|
<span class="text-sm text-muted-strong">
|
|
Mark as sensitive to blur previews and gate playback.
|
|
</span>
|
|
</label>
|
|
</div>
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoIsNsfw"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<label
|
|
for="editVideoIsForKids"
|
|
id="editVideoIsForKidsLabel"
|
|
class="block text-sm font-medium text-text"
|
|
>
|
|
Made for kids
|
|
</label>
|
|
<div
|
|
class="form-control"
|
|
role="group"
|
|
aria-labelledby="editVideoIsForKidsLabel"
|
|
>
|
|
<label class="menu__item gap-3 px-0 py-0 text-left" for="editVideoIsForKids">
|
|
<input
|
|
type="checkbox"
|
|
id="editVideoIsForKids"
|
|
class="checkbox"
|
|
data-default-checked="false"
|
|
/>
|
|
<span class="text-sm text-muted-strong">
|
|
Flag kid-friendly videos to adjust recommendations and controls.
|
|
</span>
|
|
</label>
|
|
</div>
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editVideoIsForKids"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<label
|
|
for="editEnableComments"
|
|
id="editEnableCommentsLabel"
|
|
class="block text-sm font-medium text-text"
|
|
>
|
|
Enable comments
|
|
</label>
|
|
<div
|
|
class="form-control"
|
|
role="group"
|
|
aria-labelledby="editEnableCommentsLabel"
|
|
>
|
|
<label class="menu__item gap-3 px-0 py-0 text-left" for="editEnableComments">
|
|
<input
|
|
type="checkbox"
|
|
id="editEnableComments"
|
|
class="checkbox"
|
|
data-default-checked="true"
|
|
checked
|
|
/>
|
|
<span class="text-sm text-muted-strong">
|
|
Allow replies once comment threads are available.
|
|
</span>
|
|
</label>
|
|
</div>
|
|
<div class="flex justify-end">
|
|
<button
|
|
type="button"
|
|
class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
|
|
data-edit-target="editEnableComments"
|
|
>
|
|
Edit field
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-col gap-3 sm:flex-row sm:justify-end">
|
|
<button
|
|
type="button"
|
|
id="cancelEditVideo"
|
|
class="btn-ghost focus-ring w-full sm:w-auto"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
id="submitEditVideo"
|
|
class="btn focus-ring w-full sm:w-auto"
|
|
>
|
|
Save changes
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|