Files
bitvid/components/profile-modal.html
T

760 lines
30 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- components/profile-modal.html -->
<div
id="profileModal"
class="bv-modal hidden items-start"
role="dialog"
aria-modal="true"
aria-labelledby="profileModalTitle"
tabindex="-1"
data-ds="new"
data-mobile-view="menu"
>
<div class="bv-modal-backdrop"></div>
<div
class="bv-modal__panel modal-sheet profile-modal"
tabindex="-1"
data-mobile-view="menu"
>
<div class="profile-modal__content">
<!-- Modal Header -->
<div class="modal-header profile-modal__header">
<div class="profile-modal__header-title">
<button
id="profileModalBack"
type="button"
class="modal-back btn-ghost focus-ring hidden"
aria-hidden="true"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 19l-7-7 7-7"
/>
</svg>
<span class="text-xs font-medium">Menu</span>
</button>
<h2 id="profileModalTitle" class="text-lg font-bold text-text">Profile</h2>
</div>
<button id="closeProfileModal" 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>
<!-- Modal Body -->
<div class="profile-modal__body">
<div
class="profile-modal__layout"
data-profile-layout
data-mobile-view="menu"
>
<!-- Left navigation column -->
<div class="profile-modal__menu" data-profile-mobile-menu aria-hidden="false">
<nav class="profile-modal__nav" aria-label="Profile sections">
<button
id="profileNavAccount"
type="button"
class="btn-ghost focus-ring w-full justify-start gap-2 px-3 py-2 text-xs font-medium"
aria-controls="profilePaneAccount"
aria-selected="true"
data-state="active"
>
Account
</button>
<button
id="profileNavRelays"
type="button"
class="btn-ghost focus-ring w-full justify-start gap-2 px-3 py-2 text-xs font-medium"
aria-controls="profilePaneRelays"
aria-selected="false"
>
Relays
</button>
<button
id="profileNavWallet"
type="button"
class="btn-ghost focus-ring w-full justify-start gap-2 px-3 py-2 text-xs font-medium"
aria-controls="profilePaneWallet"
aria-selected="false"
>
Wallet
</button>
<button
id="profileNavBlocked"
type="button"
class="btn-ghost focus-ring w-full justify-start gap-2 px-3 py-2 text-xs font-medium"
aria-controls="profilePaneBlocked"
aria-selected="false"
>
Blocked
</button>
<button
id="profileNavHistory"
type="button"
class="btn-ghost focus-ring w-full justify-start gap-2 px-3 py-2 text-xs font-medium"
aria-controls="profilePaneHistory"
aria-selected="false"
>
Watch history
</button>
<button
id="profileNavAdmin"
type="button"
class="btn-ghost focus-ring hidden w-full justify-start gap-2 px-3 py-2 text-xs font-medium"
aria-controls="profilePaneAdmin"
aria-selected="false"
>
Admin (Moderation)
</button>
</nav>
</div>
<!-- Right content panes -->
<div
class="profile-modal__pane-wrapper"
data-profile-mobile-pane
aria-hidden="true"
>
<div class="profile-modal__panes">
<section
id="profilePaneAccount"
class="profile-pane space-y-6"
role="tabpanel"
aria-labelledby="profileNavAccount"
>
<!--
The account pane now relies on bespoke CSS (see css/tailwind.source.css under
the "profile modal" section) so we are not dependent on utility
classes that may be purged or overridden by other builds.
-->
<div id="profileSwitcherTray" class="card space-y-5 p-5">
<div class="flex flex-wrap items-start gap-4">
<div class="space-y-2">
<h3 class="text-base font-semibold text-text">Switch profiles</h3>
<p class="text-sm text-muted">
Save multiple Nostr profiles so you can swap identities without leaving bitvid.
</p>
</div>
</div>
<div
class="card profile-modal__active-profile"
aria-label="Current Nostr profile"
aria-pressed="true"
role="button"
tabindex="0"
data-state="active"
>
<span
class="flex h-12 w-12 flex-shrink-0 items-center justify-center overflow-hidden rounded-full border-2 border-info/50 bg-surface"
>
<img
id="profileModalAvatar"
src="assets/svg/default-profile.svg"
alt="Active profile avatar"
class="h-full w-full object-cover"
/>
</span>
<div class="profile-modal__active-details">
<div class="profile-modal__active-meta">
<span class="text-3xs font-semibold uppercase tracking-extra-wide text-info">
Active profile
</span>
</div>
<span id="profileModalName" class="truncate text-sm font-semibold text-text">Loading...</span>
<span id="profileModalNpub" class="break-all font-mono text-xs text-muted">npub1...</span>
</div>
<a
id="profileChannelLink"
href="#"
class="btn-ghost focus-ring profile-modal__channel-link hidden text-xs"
>
View channel
</a>
</div>
<div
id="profileSwitcherList"
class="grid-stack"
aria-live="polite"
aria-label="Additional Nostr profiles"
role="list"
data-orientation="vertical"
></div>
<button
type="button"
id="profileAddAccountBtn"
class="profile-modal__add-profile"
aria-label="Add a new Nostr profile"
>
<span class="profile-modal__add-profile-icon" aria-hidden="true">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</svg>
</span>
<span class="flex flex-col text-left">
<span data-profile-add-title class="text-sm font-semibold text-text">Add profile</span>
<span data-profile-add-hint class="text-xs text-muted-strong">Link another npub</span>
</span>
</button>
<p class="text-sm text-muted">
Profiles you add here will stay on this device so you can quickly switch before posting or moderating.
</p>
</div>
<div id="profileModerationSettings" class="card space-y-5 p-5">
<div class="space-y-2">
<h3 class="text-base font-semibold text-text">Safety & Moderation</h3>
<p class="text-sm text-muted">
Choose how many trusted reports or mutes it takes to blur thumbnails, block autoplay previews, or hide videos entirely.
Lower numbers are stricter.
</p>
</div>
<div class="grid gap-4 sm:grid-cols-2">
<label
class="block text-sm text-muted-strong"
for="profileModerationBlurThreshold"
>
<span class="mb-2 block font-medium">Blur after trusted reports</span>
<input
id="profileModerationBlurThreshold"
type="number"
inputmode="numeric"
min="0"
step="1"
class="input"
/>
<span class="mt-1 block text-xs text-muted">
Thumbnails blur when trusted contacts report nudity at or above this count.
</span>
</label>
<label
class="block text-sm text-muted-strong"
for="profileModerationAutoplayThreshold"
>
<span class="mb-2 block font-medium">Block autoplay after reports</span>
<input
id="profileModerationAutoplayThreshold"
type="number"
inputmode="numeric"
min="0"
step="1"
class="input"
/>
<span class="mt-1 block text-xs text-muted">
Autoplay previews pause once trusted reports meet this threshold.
</span>
</label>
</div>
<div
class="grid gap-4 sm:grid-cols-2"
data-role="trusted-hide-controls"
>
<label
class="block text-sm text-muted-strong"
for="profileModerationMuteHideThreshold"
data-role="trusted-hide-control"
>
<span class="mb-2 block font-medium">Hide after trusted mutes</span>
<input
id="profileModerationMuteHideThreshold"
type="number"
inputmode="numeric"
min="0"
step="1"
class="input"
/>
<span class="mt-1 block text-xs text-muted">
Hide videos when this many trusted contacts add the author to their mute list.
</span>
</label>
<label
class="block text-sm text-muted-strong"
for="profileModerationSpamHideThreshold"
data-role="trusted-hide-control"
>
<span class="mb-2 block font-medium">Hide after trusted spam reports</span>
<input
id="profileModerationSpamHideThreshold"
type="number"
inputmode="numeric"
min="0"
step="1"
class="input"
/>
<span class="mt-1 block text-xs text-muted">
Hide videos entirely once trusted contacts report spam at or above this count.
</span>
</label>
</div>
<div class="flex flex-wrap items-center gap-3">
<button
id="profileModerationSave"
type="button"
class="btn focus-ring"
disabled
>
Save moderation settings
</button>
<button
id="profileModerationReset"
type="button"
class="btn-ghost focus-ring"
>
Restore defaults
</button>
</div>
<p
id="profileModerationStatus"
class="text-sm text-muted"
role="status"
aria-live="polite"
></p>
</div>
</section>
<section
id="profilePaneRelays"
class="profile-pane hidden space-y-6"
role="tabpanel"
aria-labelledby="profileNavRelays"
>
<div class="space-y-4">
<p class="text-sm text-muted">
Configure the relays bitvid will use to discover and publish your videos.
</p>
<div class="flex flex-col gap-3 sm:flex-row sm:items-end">
<label class="flex-1 text-sm text-muted-strong" for="relayInput">
<span class="mb-2 block font-medium">Add a relay</span>
<input
id="relayInput"
type="url"
placeholder="wss://relay.example.com"
class="input"
/>
</label>
<div class="flex gap-2">
<button
id="addRelayBtn"
type="button"
class="btn focus-ring"
>
Add relay
</button>
<button
id="restoreRelaysBtn"
type="button"
class="btn-ghost focus-ring"
>
Restore defaults
</button>
</div>
</div>
</div>
<ul id="relayList" class="grid-stack" data-orientation="vertical"></ul>
</section>
<section
id="profilePaneWallet"
class="profile-pane hidden space-y-6"
role="tabpanel"
aria-labelledby="profileNavWallet"
>
<div class="space-y-4">
<p class="text-sm text-muted">
Connect a Nostr Wallet Connect (NWC) compatible wallet to zap creators directly from bitvid.
</p>
<div class="space-y-4">
<label class="block text-sm text-muted-strong" for="profileWalletUri">
<span class="mb-2 block font-medium">Wallet Connect URI</span>
<input
id="profileWalletUri"
type="url"
placeholder="nostr+walletconnect://<public-key>?relay=wss://relay.example.com"
class="input"
/>
</label>
<label class="block text-sm text-muted-strong" for="profileWalletDefaultZap">
<span class="mb-2 block font-medium">Default zap amount (sats)</span>
<input
id="profileWalletDefaultZap"
type="number"
inputmode="numeric"
min="0"
step="1"
placeholder="500"
class="input"
/>
</label>
</div>
<div class="flex flex-wrap items-center gap-3">
<button
id="profileWalletSave"
type="button"
class="btn focus-ring"
>
Save wallet
</button>
<button
id="profileWalletTest"
type="button"
class="btn-ghost focus-ring"
>
Test connection
</button>
<button
id="profileWalletDisconnect"
type="button"
class="btn focus-ring"
data-variant="danger"
>
Disconnect wallet
</button>
</div>
<p
id="profileWalletStatus"
class="text-sm text-muted"
role="status"
aria-live="polite"
></p>
</div>
</section>
<section
id="profilePaneBlocked"
class="profile-pane hidden space-y-4"
role="tabpanel"
aria-labelledby="profileNavBlocked"
>
<p class="text-sm text-muted">
Creators you block are hidden from your bitvid experience. This
list is private to your account.
</p>
<div class="flex flex-col gap-3 sm:flex-row sm:items-end">
<label class="flex-1 text-sm text-muted-strong" for="blockedInput">
<span class="mb-2 block font-medium">Creator npub</span>
<input
id="blockedInput"
type="text"
inputmode="text"
autocomplete="off"
class="input"
placeholder="npub1..."
/>
</label>
<button
id="addBlockedBtn"
type="button"
class="btn focus-ring"
>
Block creator
</button>
</div>
<div
id="blockedEmpty"
class="card border border-dashed border-border/60 p-6 text-center text-sm text-muted"
>
You haven’t blocked any creators yet.
</div>
<ul id="blockedList" class="grid-stack" data-orientation="vertical"></ul>
</section>
<section
id="profilePaneHistory"
class="profile-pane hidden space-y-4"
role="tabpanel"
aria-labelledby="profileNavHistory"
>
<p class="text-sm text-muted">
Your recently watched videos appear here so you can jump back into favorites.
</p>
<div
id="profileHistoryFeatureBanner"
class="card hidden border border-status-warning-border bg-status-warning-surface px-4 py-3 text-sm text-status-warning-on"
role="status"
aria-live="polite"
></div>
<div class="space-y-4">
<div class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
<div
class="flex flex-wrap gap-2"
role="group"
aria-label="Watch history actions"
>
<button
id="profileHistoryClear"
type="button"
class="btn-ghost focus-ring inline-flex items-center gap-2"
data-size="sm"
>
Clear local cache
</button>
<button
id="profileHistoryRepublish"
type="button"
class="btn focus-ring inline-flex items-center gap-2"
data-size="sm"
>
Republish now
</button>
</div>
<div class="flex items-start gap-3">
<div class="flex flex-col">
<span
id="profileHistoryMetadataLabel"
class="text-sm font-medium text-text"
>
Store titles/thumbnails locally
</span>
<span
id="profileHistoryMetadataDescription"
class="text-xs text-muted"
>
When disabled, bitvid skips saving rich metadata to this device.
</span>
</div>
<button
id="profileHistoryMetadataToggle"
type="button"
class="focus-ring relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer items-center rounded-full border border-border bg-panel transition"
role="switch"
aria-checked="true"
aria-labelledby="profileHistoryMetadataLabel"
aria-describedby="profileHistoryMetadataDescription"
>
<span class="sr-only">Toggle local metadata storage</span>
<span
id="profileHistoryMetadataThumb"
class="inline-block h-5 w-5 translate-x-5 transform rounded-full bg-white transition"
aria-hidden="true"
></span>
</button>
</div>
</div>
<div
id="profileHistoryToastRegion"
class="space-y-2"
aria-live="polite"
aria-atomic="false"
></div>
<div
id="profileHistorySessionWarning"
class="hidden pill"
data-variant="warning"
role="status"
aria-live="polite"
>
Session actor in use. Connect a NIP-07 extension to publish as your main profile.
</div>
<div id="profileHistoryLoading" class="py-6">
<div id="profileHistoryStatus">
<div
class="sidebar-loading-wrapper"
role="status"
aria-live="polite"
>
<div class="sidebar-loading-indicator">
<span
class="status-spinner status-spinner--inline"
aria-hidden="true"
></span>
<span class="sidebar-loading-text"
>Fetching watch history from relays…</span
>
</div>
</div>
</div>
</div>
<div
id="profileHistoryError"
class="card hidden border border-critical/40 bg-critical/10 px-4 py-3 text-sm text-critical"
role="alert"
aria-live="assertive"
></div>
<div
id="profileHistoryEmpty"
class="card hidden border border-dashed border-border/60 p-6 text-center text-sm text-muted"
>
You haven’t watched any videos yet.
</div>
<div id="profileHistoryScroll" class="relative max-h-profile-history overflow-y-auto pr-1">
<div
id="profileHistoryGrid"
class="grid-stack hidden"
data-variant="cards"
data-orientation="vertical"
role="list"
></div>
<div id="profileHistorySentinel" class="h-1 w-full"></div>
</div>
</div>
</section>
<section
id="profilePaneAdmin"
class="profile-pane hidden space-y-6"
role="tabpanel"
aria-labelledby="profileNavAdmin"
>
<div class="space-y-2">
<h3 class="text-base font-semibold text-text">Platform moderation</h3>
<p class="text-sm text-muted">
Manage bitvid’s moderator roles and creator allow/block lists. Changes apply instantly across the app.
</p>
</div>
<div id="adminModeratorsSection" class="space-y-4 hidden" aria-hidden="true">
<div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
<h4 class="text-base font-semibold text-text">Moderators</h4>
<p class="text-xs uppercase tracking-wide text-muted">
Super Admin only
</p>
</div>
<p class="text-sm text-muted">
Moderators can edit the whitelist and blacklist but cannot manage other moderators or whitelist mode.
</p>
<div class="flex flex-col gap-3 sm:flex-row sm:items-end">
<label class="flex-1 text-sm text-muted-strong" for="adminModeratorInput">
<span class="mb-2 block font-medium">Moderator npub</span>
<input
id="adminModeratorInput"
type="text"
inputmode="text"
autocomplete="off"
class="input"
placeholder="npub1..."
/>
</label>
<button
id="adminAddModeratorBtn"
type="button"
class="btn focus-ring"
>
Add moderator
</button>
</div>
<div
id="adminModeratorsEmpty"
class="card border border-dashed border-border/60 p-4 text-center text-sm text-muted"
>
No moderators configured yet.
</div>
<ul id="adminModeratorList" class="grid-stack" data-orientation="vertical"></ul>
</div>
<div id="adminWhitelistSection" class="space-y-4">
<div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
<h4 class="text-base font-semibold text-text">Whitelist</h4>
</div>
<p class="text-sm text-muted">
Creators listed here remain visible when whitelist mode is enabled. Adding someone removes them from the blacklist.
</p>
<div class="flex flex-col gap-3 sm:flex-row sm:items-end">
<label class="flex-1 text-sm text-muted-strong" for="adminWhitelistInput">
<span class="mb-2 block font-medium">Creator npub</span>
<input
id="adminWhitelistInput"
type="text"
inputmode="text"
autocomplete="off"
class="input"
placeholder="npub1..."
/>
</label>
<button
id="adminAddWhitelistBtn"
type="button"
class="btn focus-ring"
>
Add to whitelist
</button>
</div>
<div
id="adminWhitelistEmpty"
class="card border border-dashed border-border/60 p-4 text-center text-sm text-muted"
>
No whitelisted creators yet.
</div>
<ul id="adminWhitelistList" class="grid-stack" data-orientation="vertical"></ul>
</div>
<div id="adminBlacklistSection" class="space-y-4">
<div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
<h4 class="text-base font-semibold text-text">Blacklist</h4>
</div>
<p class="text-sm text-muted">
Creators on the blacklist are hidden from bitvid everywhere. Adding someone removes them from the whitelist.
</p>
<div class="flex flex-col gap-3 sm:flex-row sm:items-end">
<label class="flex-1 text-sm text-muted-strong" for="adminBlacklistInput">
<span class="mb-2 block font-medium">Creator npub</span>
<input
id="adminBlacklistInput"
type="text"
inputmode="text"
autocomplete="off"
class="input"
placeholder="npub1..."
/>
</label>
<button
id="adminAddBlacklistBtn"
type="button"
class="btn focus-ring"
>
Add to blacklist
</button>
</div>
<div
id="adminBlacklistEmpty"
class="card border border-dashed border-border/60 p-4 text-center text-sm text-muted"
>
No blacklisted creators yet.
</div>
<ul id="adminBlacklistList" class="grid-stack" data-orientation="vertical"></ul>
</div>
</section>
</div>
</div>
</div>
<!-- Modal Footer -->
<div class="flex items-center justify-end gap-3 border-t border-border/60 p-4">
<button id="profileLogoutBtn" class="btn focus-ring" data-variant="danger">
Logout
</button>
</div>
</div>
</div>
</div>