Files
bitvid/components/profile-modal.html
T

623 lines
29 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="fixed inset-0 z-50 hidden"
role="dialog"
aria-modal="true"
aria-labelledby="profileModalTitle"
tabindex="-1"
style="background: transparent"
>
<!-- Overlay Layer with dark background and blur -->
<div
class="absolute inset-0 z-10"
style="
background-color: rgba(0, 0, 0, 0.9);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
"
></div>
<!-- Outer container with the same sizing approach as your other modals -->
<div
class="modal-container relative h-full w-full flex items-start justify-center overflow-y-auto z-20"
>
<!-- Inner content: wide layout, matching your video modal -->
<div
class="modal-content bg-gray-900 w-full max-w-[90%] lg:max-w-6xl my-0 rounded-lg overflow-hidden relative flex flex-col"
style="max-height: 90vh"
>
<!-- Modal Header -->
<div
class="sticky top-0 bg-gradient-to-b from-black/80 to-transparent p-4 flex items-center justify-between"
>
<h2 id="profileModalTitle" class="text-xl font-bold text-white">Profile</h2>
<button
id="closeProfileModal"
class="flex items-center justify-center w-10 h-10 rounded-full bg-black/50 hover:bg-black/70 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-black focus:ring-blue-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-6 h-6 text-gray-300"
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="p-6 flex-1 overflow-hidden">
<div class="flex flex-col lg:flex-row gap-6 h-full">
<!-- Left navigation column -->
<nav
class="flex lg:flex-col gap-2 flex-shrink-0"
aria-label="Profile sections"
>
<button
id="profileNavAccount"
type="button"
class="profile-nav-button px-4 py-2 rounded-md text-sm font-medium text-white bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-900"
aria-controls="profilePaneAccount"
aria-selected="true"
>
Account
</button>
<button
id="profileNavRelays"
type="button"
class="profile-nav-button px-4 py-2 rounded-md text-sm font-medium text-gray-400 hover:text-white hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-900"
aria-controls="profilePaneRelays"
aria-selected="false"
>
Relays
</button>
<button
id="profileNavWallet"
type="button"
class="profile-nav-button px-4 py-2 rounded-md text-sm font-medium text-gray-400 hover:text-white hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-900"
aria-controls="profilePaneWallet"
aria-selected="false"
>
Wallet
</button>
<button
id="profileNavBlocked"
type="button"
class="profile-nav-button px-4 py-2 rounded-md text-sm font-medium text-gray-400 hover:text-white hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-900"
aria-controls="profilePaneBlocked"
aria-selected="false"
>
Blocked
</button>
<button
id="profileNavHistory"
type="button"
class="profile-nav-button px-4 py-2 rounded-md text-sm font-medium text-gray-400 hover:text-white hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-900"
aria-controls="profilePaneHistory"
aria-selected="false"
>
Watch history
</button>
<button
id="profileNavAdmin"
type="button"
class="profile-nav-button px-4 py-2 rounded-md text-sm font-medium text-gray-400 hover:text-white hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-900 hidden"
aria-controls="profilePaneAdmin"
aria-selected="false"
>
Admin (Moderation)
</button>
</nav>
<!-- Right content panes -->
<div class="flex-1 min-h-[320px] overflow-y-auto pr-1">
<section
id="profilePaneAccount"
class="profile-pane space-y-6"
role="tabpanel"
aria-labelledby="profileNavAccount"
>
<!--
The account pane now relies on bespoke CSS (see css/style.css under
"Profile modal account pane") so we are not dependent on utility
classes that may be purged or overridden by other builds.
-->
<div class="profile-switcher" id="profileSwitcherTray">
<div class="profile-switcher__header">
<div class="profile-switcher__intro">
<h3 class="profile-switcher__title">Switch profiles</h3>
<p class="profile-switcher__subtitle">
Save multiple Nostr profiles so you can swap identities without leaving BitVid.
</p>
</div>
<span class="profile-switcher__badge">Preview</span>
</div>
<div
class="profile-card profile-card--active"
aria-label="Current Nostr profile"
aria-pressed="true"
role="button"
tabindex="0"
>
<span class="profile-card__avatar">
<img
id="profileModalAvatar"
src="assets/svg/default-profile.svg"
alt="Active profile avatar"
/>
</span>
<span class="profile-card__meta">
<span class="profile-card__topline">
<span class="profile-card__label">Active profile</span>
<a
id="profileChannelLink"
href="#"
class="profile-card__action hidden"
>
View channel
</a>
</span>
<span id="profileModalName" class="profile-card__name">Loading...</span>
<span id="profileModalNpub" class="profile-card__npub">npub1...</span>
</span>
</div>
<div
id="profileSwitcherList"
class="profile-switcher__list"
aria-live="polite"
aria-label="Additional Nostr profiles"
></div>
<button
type="button"
id="profileAddAccountBtn"
class="profile-switcher__add"
aria-label="Add a new Nostr profile"
>
<span class="profile-switcher__addAvatar">
<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"
aria-hidden="true"
>
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</svg>
</span>
<span class="profile-switcher__addCopy">
<span class="profile-switcher__addTitle">Add profile</span>
<span class="profile-switcher__addHint">Link another npub</span>
</span>
</button>
<p class="profile-switcher__helper">
Profiles you add here will stay on this device so you can quickly switch before posting or moderating.
</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-gray-400">
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-gray-300" for="relayInput">
<span class="mb-2 block font-medium">Add a relay</span>
<input
id="relayInput"
type="url"
placeholder="wss://relay.example.com"
class="w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-100 placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</label>
<div class="flex gap-2">
<button
id="addRelayBtn"
type="button"
class="px-4 py-2 rounded-md bg-blue-600 text-sm font-medium text-white hover:bg-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900"
>
Add relay
</button>
<button
id="restoreRelaysBtn"
type="button"
class="px-4 py-2 rounded-md bg-gray-800 text-sm font-medium text-gray-200 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900"
>
Restore defaults
</button>
</div>
</div>
</div>
<ul id="relayList" class="space-y-3"></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-gray-400">
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-gray-300" 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="w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-100 placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</label>
<label class="block text-sm text-gray-300" 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="w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-100 placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</label>
</div>
<div class="flex flex-wrap items-center gap-3">
<button
id="profileWalletSave"
type="button"
class="inline-flex items-center justify-center rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white transition hover:bg-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900"
>
Save wallet
</button>
<button
id="profileWalletTest"
type="button"
class="inline-flex items-center justify-center rounded-md bg-gray-800 px-4 py-2 text-sm font-medium text-gray-200 transition hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900"
>
Test connection
</button>
<button
id="profileWalletDisconnect"
type="button"
class="inline-flex items-center justify-center rounded-md bg-red-600 px-4 py-2 text-sm font-medium text-white transition hover:bg-red-500 focus:outline-none focus:ring-2 focus:ring-red-400 focus:ring-offset-2 focus:ring-offset-gray-900"
>
Disconnect wallet
</button>
</div>
<p
id="profileWalletStatus"
class="text-sm text-gray-400"
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-gray-400">
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-gray-300" for="blockedInput">
<span class="mb-2 block font-medium">Creator npub</span>
<input
id="blockedInput"
type="text"
inputmode="text"
autocomplete="off"
class="w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-100 placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="npub1..."
/>
</label>
<button
id="addBlockedBtn"
type="button"
class="px-4 py-2 rounded-md bg-blue-600 text-sm font-medium text-white hover:bg-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900"
>
Block creator
</button>
</div>
<div
id="blockedEmpty"
class="rounded-lg border border-dashed border-gray-700 p-6 text-center text-sm text-gray-400"
>
You haven’t blocked any creators yet.
</div>
<ul id="blockedList" class="space-y-3"></ul>
</section>
<section
id="profilePaneHistory"
class="profile-pane hidden space-y-4"
role="tabpanel"
aria-labelledby="profileNavHistory"
>
<p class="text-sm text-gray-400">
Your recently watched videos appear here so you can jump back into favorites.
</p>
<div
id="profileHistoryFeatureBanner"
class="hidden rounded-md border border-amber-500/40 bg-amber-500/10 px-4 py-3 text-sm text-amber-100"
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="inline-flex items-center gap-2 rounded-md bg-gray-800 px-4 py-2 text-sm font-medium text-gray-200 transition hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-900"
>
Clear local cache
</button>
<button
id="profileHistoryRepublish"
type="button"
class="inline-flex items-center gap-2 rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white transition hover:bg-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900"
>
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-gray-200"
>
Store titles/thumbnails locally
</span>
<span
id="profileHistoryMetadataDescription"
class="text-xs text-gray-400"
>
When disabled, BitVid skips saving rich metadata to this device.
</span>
</div>
<button
id="profileHistoryMetadataToggle"
type="button"
class="relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer items-center rounded-full border border-gray-600 bg-gray-700 transition focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-900"
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 inline-flex items-center gap-2 rounded-full border border-amber-500/50 bg-amber-500/10 px-3 py-1 text-xs font-medium text-amber-100"
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="hidden rounded-md border border-red-500/40 bg-red-500/10 px-4 py-3 text-sm text-red-100"
role="alert"
aria-live="assertive"
></div>
<div
id="profileHistoryEmpty"
class="hidden rounded-lg border border-dashed border-gray-700 p-6 text-center text-sm text-gray-400"
>
You haven’t watched any videos yet.
</div>
<div id="profileHistoryScroll" class="relative max-h-[420px] overflow-y-auto pr-1">
<div
id="profileHistoryGrid"
class="watch-history-grid watch-history-grid--modal hidden"
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-lg font-semibold text-white">Platform moderation</h3>
<p class="text-sm text-gray-400">
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-white">Moderators</h4>
<p class="text-xs uppercase tracking-wide text-gray-400">
Super Admin only
</p>
</div>
<p class="text-sm text-gray-400">
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-gray-300" for="adminModeratorInput">
<span class="mb-2 block font-medium">Moderator npub</span>
<input
id="adminModeratorInput"
type="text"
inputmode="text"
autocomplete="off"
class="w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-100 placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="npub1..."
/>
</label>
<button
id="adminAddModeratorBtn"
type="button"
class="px-4 py-2 rounded-md bg-blue-600 text-sm font-medium text-white hover:bg-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900"
>
Add moderator
</button>
</div>
<div
id="adminModeratorsEmpty"
class="rounded-lg border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400"
>
No moderators configured yet.
</div>
<ul id="adminModeratorList" class="space-y-3"></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-white">Whitelist</h4>
</div>
<p class="text-sm text-gray-400">
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-gray-300" for="adminWhitelistInput">
<span class="mb-2 block font-medium">Creator npub</span>
<input
id="adminWhitelistInput"
type="text"
inputmode="text"
autocomplete="off"
class="w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-100 placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="npub1..."
/>
</label>
<button
id="adminAddWhitelistBtn"
type="button"
class="px-4 py-2 rounded-md bg-blue-600 text-sm font-medium text-white hover:bg-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900"
>
Add to whitelist
</button>
</div>
<div
id="adminWhitelistEmpty"
class="rounded-lg border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400"
>
No whitelisted creators yet.
</div>
<ul id="adminWhitelistList" class="space-y-3"></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-white">Blacklist</h4>
</div>
<p class="text-sm text-gray-400">
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-gray-300" for="adminBlacklistInput">
<span class="mb-2 block font-medium">Creator npub</span>
<input
id="adminBlacklistInput"
type="text"
inputmode="text"
autocomplete="off"
class="w-full rounded-md border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-100 placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="npub1..."
/>
</label>
<button
id="adminAddBlacklistBtn"
type="button"
class="px-4 py-2 rounded-md bg-blue-600 text-sm font-medium text-white hover:bg-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900"
>
Add to blacklist
</button>
</div>
<div
id="adminBlacklistEmpty"
class="rounded-lg border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400"
>
No blacklisted creators yet.
</div>
<ul id="adminBlacklistList" class="space-y-3"></ul>
</div>
</section>
</div>
</div>
</div>
<!-- Modal Footer -->
<div class="p-4 border-t border-gray-700 flex items-center justify-end">
<button
id="profileLogoutBtn"
class="bg-red-500 text-white px-4 py-2 rounded-md hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 focus:ring-offset-gray-900"
>
Logout
</button>
</div>
</div>
</div>
</div>