mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
Removes the fixed height and overflow from the watch history container in the profile modal, allowing it to expand fully. Updates the profile modal controller to use the main modal panes container as the scroll root for infinite scrolling.
1013 lines
40 KiB
HTML
1013 lines
40 KiB
HTML
<!-- 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="profileNavHashtags"
|
||
type="button"
|
||
class="btn-ghost focus-ring w-full justify-start gap-2 px-3 py-2 text-xs font-medium"
|
||
aria-controls="profilePaneHashtags"
|
||
aria-selected="false"
|
||
>
|
||
Hashtags
|
||
</button>
|
||
<button
|
||
id="profileNavSubscriptions"
|
||
type="button"
|
||
class="btn-ghost focus-ring w-full justify-start gap-2 px-3 py-2 text-xs font-medium"
|
||
aria-controls="profilePaneSubscriptions"
|
||
aria-selected="false"
|
||
>
|
||
Subscriptions
|
||
</button>
|
||
<button
|
||
id="profileNavFriends"
|
||
type="button"
|
||
class="btn-ghost focus-ring w-full justify-start gap-2 px-3 py-2 text-xs font-medium"
|
||
aria-controls="profilePaneFriends"
|
||
aria-selected="false"
|
||
>
|
||
Friends
|
||
</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="profileNavMessages"
|
||
type="button"
|
||
class="btn-ghost focus-ring w-full justify-start gap-2 px-3 py-2 text-xs font-medium"
|
||
aria-controls="profilePaneMessages"
|
||
aria-selected="false"
|
||
>
|
||
Messages
|
||
</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 id="profileModalPanes" 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="profilePaneHashtags"
|
||
class="profile-pane hidden space-y-6"
|
||
role="tabpanel"
|
||
aria-labelledby="profileNavHashtags"
|
||
>
|
||
<div class="space-y-3">
|
||
<p class="text-sm text-muted">
|
||
Follow or mute hashtags to personalize the videos we show you.
|
||
</p>
|
||
<p
|
||
id="profileHashtagStatus"
|
||
class="text-sm text-muted"
|
||
role="status"
|
||
aria-live="polite"
|
||
></p>
|
||
</div>
|
||
|
||
<div class="card space-y-4 p-5">
|
||
<div class="space-y-1">
|
||
<h3 class="text-base font-semibold text-text">Interests</h3>
|
||
<p class="text-sm text-muted">
|
||
Videos tagged with these hashtags will be highlighted for you.
|
||
</p>
|
||
</div>
|
||
<div class="flex flex-col gap-3 sm:flex-row sm:items-end">
|
||
<label
|
||
class="flex-1 text-sm text-muted-strong"
|
||
for="profileHashtagInterestInput"
|
||
>
|
||
<span class="mb-2 block font-medium">Add a hashtag</span>
|
||
<input
|
||
id="profileHashtagInterestInput"
|
||
type="text"
|
||
inputmode="text"
|
||
autocomplete="off"
|
||
class="input"
|
||
placeholder="nostr"
|
||
/>
|
||
</label>
|
||
<button
|
||
id="profileAddHashtagInterestBtn"
|
||
type="button"
|
||
class="btn focus-ring"
|
||
>
|
||
Add interest
|
||
</button>
|
||
</div>
|
||
<p
|
||
id="profileHashtagInterestEmpty"
|
||
class="card border border-dashed border-border/60 p-4 text-center text-sm text-muted"
|
||
>
|
||
You haven’t added any interest hashtags yet.
|
||
</p>
|
||
<ul
|
||
id="profileHashtagInterestList"
|
||
class="profile-hashtag-list"
|
||
data-orientation="horizontal"
|
||
></ul>
|
||
</div>
|
||
|
||
<div class="card space-y-4 p-5">
|
||
<div class="space-y-1">
|
||
<h3 class="text-base font-semibold text-text">Disinterests</h3>
|
||
<p class="text-sm text-muted">
|
||
We’ll de-emphasize or hide videos using these hashtags.
|
||
</p>
|
||
</div>
|
||
<div class="flex flex-col gap-3 sm:flex-row sm:items-end">
|
||
<label
|
||
class="flex-1 text-sm text-muted-strong"
|
||
for="profileHashtagDisinterestInput"
|
||
>
|
||
<span class="mb-2 block font-medium">Add a hashtag</span>
|
||
<input
|
||
id="profileHashtagDisinterestInput"
|
||
type="text"
|
||
inputmode="text"
|
||
autocomplete="off"
|
||
class="input"
|
||
placeholder="spam"
|
||
/>
|
||
</label>
|
||
<button
|
||
id="profileAddHashtagDisinterestBtn"
|
||
type="button"
|
||
class="btn focus-ring"
|
||
>
|
||
Add disinterest
|
||
</button>
|
||
</div>
|
||
<p
|
||
id="profileHashtagDisinterestEmpty"
|
||
class="card border border-dashed border-border/60 p-4 text-center text-sm text-muted"
|
||
>
|
||
You haven’t muted any hashtags yet.
|
||
</p>
|
||
<ul
|
||
id="profileHashtagDisinterestList"
|
||
class="profile-hashtag-list"
|
||
data-orientation="horizontal"
|
||
></ul>
|
||
</div>
|
||
</section>
|
||
|
||
<section
|
||
id="profilePaneSubscriptions"
|
||
class="profile-pane hidden space-y-4"
|
||
role="tabpanel"
|
||
aria-labelledby="profileNavSubscriptions"
|
||
>
|
||
<p class="text-sm text-muted">
|
||
These are the creators you’ve subscribed to directly in bitvid.
|
||
</p>
|
||
<div
|
||
id="subscriptionsEmpty"
|
||
class="card border border-dashed border-border/60 p-6 text-center text-sm text-muted"
|
||
>
|
||
You haven’t subscribed to any creators yet.
|
||
</div>
|
||
<ul id="subscriptionsList" class="grid-stack" data-orientation="vertical"></ul>
|
||
</section>
|
||
|
||
<section
|
||
id="profilePaneFriends"
|
||
class="profile-pane hidden space-y-4"
|
||
role="tabpanel"
|
||
aria-labelledby="profileNavFriends"
|
||
>
|
||
<p class="text-sm text-muted">
|
||
Add friends to spotlight creators you want to keep up with across bitvid.
|
||
</p>
|
||
<div class="flex flex-col gap-3 sm:flex-row sm:items-end">
|
||
<label class="flex-1 text-sm text-muted-strong" for="friendsInput">
|
||
<span class="mb-2 block font-medium">Creator npub</span>
|
||
<input
|
||
id="friendsInput"
|
||
type="text"
|
||
inputmode="text"
|
||
autocomplete="off"
|
||
class="input"
|
||
placeholder="npub1..."
|
||
/>
|
||
</label>
|
||
<button id="addFriendBtn" type="button" class="btn focus-ring">
|
||
Add friend
|
||
</button>
|
||
</div>
|
||
<div
|
||
id="friendsEmpty"
|
||
class="card border border-dashed border-border/60 p-6 text-center text-sm text-muted"
|
||
>
|
||
You haven’t added any friends yet.
|
||
</div>
|
||
<ul id="friendsList" class="grid-stack" data-orientation="vertical"></ul>
|
||
</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="profilePaneMessages"
|
||
class="profile-pane hidden space-y-4"
|
||
role="tabpanel"
|
||
aria-labelledby="profileNavMessages"
|
||
>
|
||
<p class="text-sm text-muted">
|
||
View encrypted conversations sent with NIP-04 or NIP-44. bitvid keeps message data on this device only.
|
||
</p>
|
||
<div
|
||
id="profileMessagesStatus"
|
||
class="sr-only"
|
||
role="status"
|
||
aria-live="polite"
|
||
></div>
|
||
<div
|
||
id="profileMessagesLoading"
|
||
class="hidden py-6"
|
||
role="status"
|
||
aria-live="polite"
|
||
>
|
||
<div class="sidebar-loading-wrapper">
|
||
<div class="sidebar-loading-indicator">
|
||
<span
|
||
class="status-spinner status-spinner--inline"
|
||
aria-hidden="true"
|
||
></span>
|
||
<span class="sidebar-loading-text"
|
||
>Fetching direct messages from relays…</span
|
||
>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div
|
||
id="profileMessagesError"
|
||
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="profileMessagesEmpty"
|
||
class="card hidden border border-dashed border-border/60 p-6 text-center text-sm text-muted"
|
||
role="status"
|
||
aria-live="polite"
|
||
>
|
||
No direct messages yet.
|
||
</div>
|
||
<div class="flex items-center justify-end gap-2">
|
||
<button
|
||
id="profileMessagesReload"
|
||
type="button"
|
||
class="btn-ghost focus-ring inline-flex items-center gap-2"
|
||
data-size="sm"
|
||
>
|
||
Refresh
|
||
</button>
|
||
</div>
|
||
<ul
|
||
id="profileMessagesList"
|
||
class="grid-stack hidden"
|
||
data-orientation="vertical"
|
||
aria-live="polite"
|
||
aria-label="Direct message threads"
|
||
></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>
|
||
<button
|
||
id="profileHistoryRefresh"
|
||
type="button"
|
||
class="btn-ghost focus-ring inline-flex items-center gap-2"
|
||
data-size="sm"
|
||
>
|
||
Refresh
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div
|
||
id="profileHistoryPrivacyBanner"
|
||
class="card hidden border border-status-info-border bg-status-info-surface px-4 py-3 text-sm text-status-info-on"
|
||
role="status"
|
||
aria-live="polite"
|
||
>
|
||
<p id="profileHistoryPrivacyMessage" class="mb-2"></p>
|
||
<div class="flex flex-wrap items-center gap-2">
|
||
<button
|
||
id="profileHistoryPrivacyDismiss"
|
||
type="button"
|
||
class="btn-ghost focus-ring text-xs"
|
||
>
|
||
Dismiss
|
||
</button>
|
||
<button
|
||
id="profileHistoryPrivacyToggle"
|
||
type="button"
|
||
class="btn-ghost focus-ring text-xs hidden"
|
||
>
|
||
Change settings
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<p id="profileHistoryInfo" class="text-xs text-muted"></p>
|
||
<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">
|
||
<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>
|