Refine profile and edit modals with design system tokens

This commit is contained in:
thePR0M3TH3AN committed 2025-10-10 12:16:22 -04:00
1 parent 56af3e33da
commit 35a041d1be
6 files changed
+224 -195

No files matched your search

+59 -59
View File
@@ -12,29 +12,29 @@
class="bv-modal__panel modal-content bg-gray-900 w-full max-w-[90%] lg:max-w-4xl my-0 overflow-y-auto relative max-h-[90vh]" class="bv-modal__panel modal-content bg-gray-900 w-full max-w-[90%] lg:max-w-4xl my-0 overflow-y-auto relative max-h-[90vh]"
tabindex="-1" tabindex="-1"
> >
<div <div class="sticky top-0 p-4">
class="sticky top-0 bg-gradient-to-b from-black/80 to-transparent transition-transform duration-150 p-4 flex items-center justify-between" <div class="card flex items-center justify-between gap-4 p-4">
> <h2 class="text-xl font-bold text-white">Edit Video Note</h2>
<h2 class="text-xl font-bold text-white">Edit Video Note</h2> <button
<button id="closeEditVideoModal"
id="closeEditVideoModal" class="focus-ring inline-flex h-10 w-10 items-center justify-center rounded-full bg-black/50 text-gray-300 transition hover:bg-black/70"
class="flex items-center justify-center w-10 h-10 rounded-full bg-black/50 hover:bg-black/70 transition-all duration-200 backdrop-blur 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 <svg
stroke-linecap="round" xmlns="http://www.w3.org/2000/svg"
stroke-linejoin="round" class="h-6 w-6"
stroke-width="2" fill="none"
d="M6 18L18 6M6 6l12 12" viewBox="0 0 24 24"
/> stroke="currentColor"
</svg> >
</button> <path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
</div> </div>
<div class="p-6 space-y-6"> <div class="p-6 space-y-6">
@@ -56,7 +56,7 @@
/> />
<button <button
type="button" type="button"
class="edit-field-button hidden" class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
data-edit-target="editVideoTitle" data-edit-target="editVideoTitle"
> >
Edit field Edit field
@@ -210,7 +210,7 @@
<h3 id="editNip71ImetaLabel" class="text-sm font-medium text-gray-200">Image metadata (imeta)</h3> <h3 id="editNip71ImetaLabel" class="text-sm font-medium text-gray-200">Image metadata (imeta)</h3>
<button <button
type="button" type="button"
class="rounded-md border border-gray-700 px-3 py-1 text-xs font-semibold text-gray-200 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-xs font-semibold"
data-nip71-add="imeta" data-nip71-add="imeta"
aria-describedby="editNip71ImetaHelp" aria-describedby="editNip71ImetaHelp"
> >
@@ -223,7 +223,7 @@
</p> </p>
<div id="editNip71ImetaList" class="space-y-4" data-nip71-list="imeta"></div> <div id="editNip71ImetaList" class="space-y-4" data-nip71-list="imeta"></div>
<template id="editNip71ImetaTemplate" data-nip71-template="imeta"> <template id="editNip71ImetaTemplate" data-nip71-template="imeta">
<article class="space-y-3 rounded-md border border-gray-800 bg-gray-900/60 p-4" data-nip71-entry="imeta"> <article class="card space-y-3 bg-gray-900/60 p-4" data-nip71-entry="imeta">
<div class="grid gap-3 md:grid-cols-2"> <div class="grid gap-3 md:grid-cols-2">
<div> <div>
<label class="block text-xs font-medium text-gray-300"> <label class="block text-xs font-medium text-gray-300">
@@ -280,7 +280,7 @@
<h4 class="text-xs font-semibold uppercase tracking-wide text-gray-400">Image values</h4> <h4 class="text-xs font-semibold uppercase tracking-wide text-gray-400">Image values</h4>
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-200 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-nested-add="image" data-nip71-nested-add="image"
> >
Add image URL Add image URL
@@ -297,7 +297,7 @@
/> />
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-300 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-remove="nested" data-nip71-remove="nested"
aria-label="Remove image URL" aria-label="Remove image URL"
> >
@@ -312,7 +312,7 @@
<h4 class="text-xs font-semibold uppercase tracking-wide text-gray-400">Fallback URLs</h4> <h4 class="text-xs font-semibold uppercase tracking-wide text-gray-400">Fallback URLs</h4>
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-200 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-nested-add="fallback" data-nip71-nested-add="fallback"
> >
Add fallback Add fallback
@@ -329,7 +329,7 @@
/> />
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-300 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-remove="nested" data-nip71-remove="nested"
aria-label="Remove fallback URL" aria-label="Remove fallback URL"
> >
@@ -344,7 +344,7 @@
<h4 class="text-xs font-semibold uppercase tracking-wide text-gray-400">Services</h4> <h4 class="text-xs font-semibold uppercase tracking-wide text-gray-400">Services</h4>
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-200 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-nested-add="service" data-nip71-nested-add="service"
> >
Add service Add service
@@ -361,7 +361,7 @@
/> />
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-300 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-remove="nested" data-nip71-remove="nested"
aria-label="Remove service entry" aria-label="Remove service entry"
> >
@@ -374,7 +374,7 @@
<div class="flex justify-end"> <div class="flex justify-end">
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-300 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-remove="imeta" data-nip71-remove="imeta"
> >
Remove variant Remove variant
@@ -391,7 +391,7 @@
</h3> </h3>
<button <button
type="button" type="button"
class="rounded-md border border-gray-700 px-3 py-1 text-xs font-semibold text-gray-200 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-xs font-semibold"
data-nip71-add="text-track" data-nip71-add="text-track"
aria-describedby="editNip71TextTracksHelp" aria-describedby="editNip71TextTracksHelp"
> >
@@ -403,7 +403,7 @@
</p> </p>
<div id="editNip71TextTrackList" class="space-y-4" data-nip71-list="text-track"></div> <div id="editNip71TextTrackList" class="space-y-4" data-nip71-list="text-track"></div>
<template id="editNip71TextTrackTemplate" data-nip71-template="text-track"> <template id="editNip71TextTrackTemplate" data-nip71-template="text-track">
<article class="space-y-3 rounded-md border border-gray-800 bg-gray-900/60 p-4" data-nip71-entry="text-track"> <article class="card space-y-3 bg-gray-900/60 p-4" data-nip71-entry="text-track">
<div class="grid gap-3 md:grid-cols-3"> <div class="grid gap-3 md:grid-cols-3">
<div> <div>
<label class="block text-xs font-medium text-gray-300">Track URL</label> <label class="block text-xs font-medium text-gray-300">Track URL</label>
@@ -436,7 +436,7 @@
<div class="flex justify-end"> <div class="flex justify-end">
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-300 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-remove="text-track" data-nip71-remove="text-track"
> >
Remove track Remove track
@@ -451,7 +451,7 @@
<h3 id="editNip71SegmentsLabel" class="text-sm font-medium text-gray-200">Chapters &amp; segments (segment)</h3> <h3 id="editNip71SegmentsLabel" class="text-sm font-medium text-gray-200">Chapters &amp; segments (segment)</h3>
<button <button
type="button" type="button"
class="rounded-md border border-gray-700 px-3 py-1 text-xs font-semibold text-gray-200 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-xs font-semibold"
data-nip71-add="segment" data-nip71-add="segment"
aria-describedby="editNip71SegmentsHelp" aria-describedby="editNip71SegmentsHelp"
> >
@@ -463,7 +463,7 @@
</p> </p>
<div id="editNip71SegmentList" class="space-y-4" data-nip71-list="segment"></div> <div id="editNip71SegmentList" class="space-y-4" data-nip71-list="segment"></div>
<template id="editNip71SegmentTemplate" data-nip71-template="segment"> <template id="editNip71SegmentTemplate" data-nip71-template="segment">
<article class="space-y-3 rounded-md border border-gray-800 bg-gray-900/60 p-4" data-nip71-entry="segment"> <article class="card space-y-3 bg-gray-900/60 p-4" data-nip71-entry="segment">
<div class="grid gap-3 md:grid-cols-2"> <div class="grid gap-3 md:grid-cols-2">
<div> <div>
<label class="block text-xs font-medium text-gray-300">Start (seconds)</label> <label class="block text-xs font-medium text-gray-300">Start (seconds)</label>
@@ -507,7 +507,7 @@
<div class="flex justify-end"> <div class="flex justify-end">
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-300 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-remove="segment" data-nip71-remove="segment"
> >
Remove segment Remove segment
@@ -522,7 +522,7 @@
<h3 id="editNip71HashtagsLabel" class="text-sm font-medium text-gray-200">Hashtags (<code>t</code>)</h3> <h3 id="editNip71HashtagsLabel" class="text-sm font-medium text-gray-200">Hashtags (<code>t</code>)</h3>
<button <button
type="button" type="button"
class="rounded-md border border-gray-700 px-3 py-1 text-xs font-semibold text-gray-200 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-xs font-semibold"
data-nip71-add="t" data-nip71-add="t"
> >
Add hashtag Add hashtag
@@ -542,7 +542,7 @@
/> />
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-300 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-remove="t" data-nip71-remove="t"
> >
Remove Remove
@@ -556,7 +556,7 @@
<h3 id="editNip71ParticipantsLabel" class="text-sm font-medium text-gray-200">Participants (<code>p</code>)</h3> <h3 id="editNip71ParticipantsLabel" class="text-sm font-medium text-gray-200">Participants (<code>p</code>)</h3>
<button <button
type="button" type="button"
class="rounded-md border border-gray-700 px-3 py-1 text-xs font-semibold text-gray-200 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-xs font-semibold"
data-nip71-add="p" data-nip71-add="p"
> >
Add participant Add participant
@@ -564,7 +564,7 @@
</div> </div>
<div id="editNip71ParticipantList" class="space-y-3" data-nip71-list="p"></div> <div id="editNip71ParticipantList" class="space-y-3" data-nip71-list="p"></div>
<template id="editNip71ParticipantTemplate" data-nip71-template="p"> <template id="editNip71ParticipantTemplate" data-nip71-template="p">
<article class="space-y-3 rounded-md border border-gray-800 bg-gray-900/60 p-4" data-nip71-entry="p"> <article class="card space-y-3 bg-gray-900/60 p-4" data-nip71-entry="p">
<div class="grid gap-3 md:grid-cols-2"> <div class="grid gap-3 md:grid-cols-2">
<div> <div>
<label class="block text-xs font-medium text-gray-300">Participant pubkey</label> <label class="block text-xs font-medium text-gray-300">Participant pubkey</label>
@@ -588,7 +588,7 @@
<div class="flex justify-end"> <div class="flex justify-end">
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-300 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-remove="p" data-nip71-remove="p"
> >
Remove participant Remove participant
@@ -603,7 +603,7 @@
<h3 id="editNip71ReferencesLabel" class="text-sm font-medium text-gray-200">Reference links (<code>r</code>)</h3> <h3 id="editNip71ReferencesLabel" class="text-sm font-medium text-gray-200">Reference links (<code>r</code>)</h3>
<button <button
type="button" type="button"
class="rounded-md border border-gray-700 px-3 py-1 text-xs font-semibold text-gray-200 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-xs font-semibold"
data-nip71-add="r" data-nip71-add="r"
> >
Add reference Add reference
@@ -620,7 +620,7 @@
/> />
<button <button
type="button" type="button"
class="rounded border border-gray-700 px-2 py-1 text-[11px] text-gray-300 hover:border-gray-500 hover:text-white" class="btn-ghost focus-ring text-[11px] font-medium"
data-nip71-remove="r" data-nip71-remove="r"
> >
Remove Remove
@@ -643,7 +643,7 @@
/> />
<button <button
type="button" type="button"
class="edit-field-button hidden" class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
data-edit-target="editVideoUrl" data-edit-target="editVideoUrl"
> >
Edit field Edit field
@@ -664,7 +664,7 @@
/> />
<button <button
type="button" type="button"
class="edit-field-button hidden" class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
data-edit-target="editVideoWs" data-edit-target="editVideoWs"
> >
Edit field Edit field
@@ -685,7 +685,7 @@
/> />
<button <button
type="button" type="button"
class="edit-field-button hidden" class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
data-edit-target="editVideoXs" data-edit-target="editVideoXs"
> >
Edit field Edit field
@@ -706,7 +706,7 @@
/> />
<button <button
type="button" type="button"
class="edit-field-button hidden" class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
data-edit-target="editVideoMagnet" data-edit-target="editVideoMagnet"
> >
Edit field Edit field
@@ -727,7 +727,7 @@
/> />
<button <button
type="button" type="button"
class="edit-field-button hidden" class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
data-edit-target="editVideoThumbnail" data-edit-target="editVideoThumbnail"
> >
Edit field Edit field
@@ -748,7 +748,7 @@
></textarea> ></textarea>
<button <button
type="button" type="button"
class="edit-field-button self-start hidden" class="btn-ghost focus-ring hidden self-start text-xs font-semibold uppercase tracking-wide"
data-edit-target="editVideoDescription" data-edit-target="editVideoDescription"
> >
Edit field Edit field
@@ -773,7 +773,7 @@
> >
<button <button
type="button" type="button"
class="video-visibility-toggle__option" class="video-visibility-toggle__option focus-ring"
data-visibility-option="public" data-visibility-option="public"
aria-pressed="false" aria-pressed="false"
> >
@@ -781,7 +781,7 @@
</button> </button>
<button <button
type="button" type="button"
class="video-visibility-toggle__option" class="video-visibility-toggle__option focus-ring"
data-visibility-option="private" data-visibility-option="private"
aria-pressed="false" aria-pressed="false"
> >
@@ -801,7 +801,7 @@
</p> </p>
<button <button
type="button" type="button"
class="edit-field-button hidden" class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
data-edit-target="editVideoIsPrivate" data-edit-target="editVideoIsPrivate"
> >
Edit field Edit field
@@ -829,7 +829,7 @@
</div> </div>
<button <button
type="button" type="button"
class="edit-field-button hidden" class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
data-edit-target="editVideoIsNsfw" data-edit-target="editVideoIsNsfw"
> >
Edit field Edit field
@@ -857,7 +857,7 @@
</div> </div>
<button <button
type="button" type="button"
class="edit-field-button hidden" class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
data-edit-target="editVideoIsForKids" data-edit-target="editVideoIsForKids"
> >
Edit field Edit field
@@ -886,7 +886,7 @@
</div> </div>
<button <button
type="button" type="button"
class="edit-field-button hidden" class="btn-ghost focus-ring hidden text-xs font-semibold uppercase tracking-wide"
data-edit-target="editEnableComments" data-edit-target="editEnableComments"
> >
Edit field Edit field
@@ -898,14 +898,14 @@
<button <button
type="button" type="button"
id="cancelEditVideo" id="cancelEditVideo"
class="w-full sm:w-auto px-4 py-2 rounded-md bg-gray-800 text-gray-200 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-gray-500" class="btn-ghost focus-ring w-full sm:w-auto"
> >
Cancel Cancel
</button> </button>
<button <button
type="submit" type="submit"
id="submitEditVideo" id="submitEditVideo"
class="w-full sm:w-auto px-4 py-2 rounded-md bg-blue-600 text-white hover:bg-blue-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-blue-500" class="btn focus-ring w-full sm:w-auto"
> >
Save changes Save changes
</button> </button>
+94 -83
View File
@@ -14,29 +14,29 @@
tabindex="-1" tabindex="-1"
> >
<!-- Modal Header --> <!-- Modal Header -->
<div <div class="sticky top-0 p-4">
class="sticky top-0 bg-gradient-to-b from-black/80 to-transparent p-4 flex items-center justify-between" <div class="card flex items-center justify-between gap-4 p-4">
> <h2 id="profileModalTitle" class="text-xl font-bold text-white">Profile</h2>
<h2 id="profileModalTitle" class="text-xl font-bold text-white">Profile</h2> <button
<button id="closeProfileModal"
id="closeProfileModal" class="focus-ring inline-flex h-10 w-10 items-center justify-center rounded-full bg-black/50 text-gray-300 transition hover:bg-black/70"
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 <svg
stroke-linecap="round" xmlns="http://www.w3.org/2000/svg"
stroke-linejoin="round" class="h-6 w-6"
stroke-width="2" fill="none"
d="M6 18L18 6M6 6l12 12" viewBox="0 0 24 24"
/> stroke="currentColor"
</svg> >
</button> <path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
</div> </div>
<!-- Modal Body --> <!-- Modal Body -->
@@ -44,22 +44,23 @@
<div class="flex flex-col lg:flex-row gap-6 h-full"> <div class="flex flex-col lg:flex-row gap-6 h-full">
<!-- Left navigation column --> <!-- Left navigation column -->
<nav <nav
class="flex lg:flex-col gap-2 flex-shrink-0" class="flex flex-wrap gap-2 flex-shrink-0 lg:flex-col"
aria-label="Profile sections" aria-label="Profile sections"
> >
<button <button
id="profileNavAccount" id="profileNavAccount"
type="button" 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" class="btn-ghost focus-ring w-full justify-start gap-3 px-4 py-2 text-sm font-medium"
aria-controls="profilePaneAccount" aria-controls="profilePaneAccount"
aria-selected="true" aria-selected="true"
data-state="active"
> >
Account Account
</button> </button>
<button <button
id="profileNavRelays" id="profileNavRelays"
type="button" 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" class="btn-ghost focus-ring w-full justify-start gap-3 px-4 py-2 text-sm font-medium"
aria-controls="profilePaneRelays" aria-controls="profilePaneRelays"
aria-selected="false" aria-selected="false"
> >
@@ -68,7 +69,7 @@
<button <button
id="profileNavWallet" id="profileNavWallet"
type="button" 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" class="btn-ghost focus-ring w-full justify-start gap-3 px-4 py-2 text-sm font-medium"
aria-controls="profilePaneWallet" aria-controls="profilePaneWallet"
aria-selected="false" aria-selected="false"
> >
@@ -77,7 +78,7 @@
<button <button
id="profileNavBlocked" id="profileNavBlocked"
type="button" 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" class="btn-ghost focus-ring w-full justify-start gap-3 px-4 py-2 text-sm font-medium"
aria-controls="profilePaneBlocked" aria-controls="profilePaneBlocked"
aria-selected="false" aria-selected="false"
> >
@@ -86,7 +87,7 @@
<button <button
id="profileNavHistory" id="profileNavHistory"
type="button" 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" class="btn-ghost focus-ring w-full justify-start gap-3 px-4 py-2 text-sm font-medium"
aria-controls="profilePaneHistory" aria-controls="profilePaneHistory"
aria-selected="false" aria-selected="false"
> >
@@ -95,7 +96,7 @@
<button <button
id="profileNavAdmin" id="profileNavAdmin"
type="button" 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" class="btn-ghost focus-ring hidden w-full justify-start gap-3 px-4 py-2 text-sm font-medium"
aria-controls="profilePaneAdmin" aria-controls="profilePaneAdmin"
aria-selected="false" aria-selected="false"
> >
@@ -116,61 +117,72 @@
"Profile modal account pane") so we are not dependent on utility "Profile modal account pane") so we are not dependent on utility
classes that may be purged or overridden by other builds. classes that may be purged or overridden by other builds.
--> -->
<div class="profile-switcher" id="profileSwitcherTray"> <div id="profileSwitcherTray" class="card space-y-6 p-6">
<div class="profile-switcher__header"> <div class="flex flex-wrap items-start justify-between gap-4">
<div class="profile-switcher__intro"> <div class="space-y-2">
<h3 class="profile-switcher__title">Switch profiles</h3> <h3 class="text-lg font-semibold text-white">Switch profiles</h3>
<p class="profile-switcher__subtitle"> <p class="text-sm text-gray-400">
Save multiple Nostr profiles so you can swap identities without leaving BitVid. Save multiple Nostr profiles so you can swap identities without leaving BitVid.
</p> </p>
</div> </div>
<span class="profile-switcher__badge">Preview</span> <span class="badge" data-variant="info">Preview</span>
</div> </div>
<div <div
class="profile-card profile-card--active" class="card focus-ring flex items-center gap-4 p-4"
aria-label="Current Nostr profile" aria-label="Current Nostr profile"
aria-pressed="true" aria-pressed="true"
role="button" role="button"
tabindex="0" tabindex="0"
data-state="active"
> >
<span class="profile-card__avatar"> <span
class="flex h-12 w-12 flex-shrink-0 items-center justify-center overflow-hidden rounded-full border-2 border-blue-400/50 bg-slate-900"
>
<img <img
id="profileModalAvatar" id="profileModalAvatar"
src="assets/svg/default-profile.svg" src="assets/svg/default-profile.svg"
alt="Active profile avatar" alt="Active profile avatar"
class="h-full w-full object-cover"
/> />
</span> </span>
<span class="profile-card__meta"> <div class="flex min-w-0 flex-1 flex-col gap-2">
<span class="profile-card__topline"> <div class="flex flex-wrap items-center gap-3">
<span class="profile-card__label">Active profile</span> <span class="text-[11px] font-semibold uppercase tracking-[0.2em] text-blue-200">
Active profile
</span>
<a <a
id="profileChannelLink" id="profileChannelLink"
href="#" href="#"
class="profile-card__action hidden" class="btn-ghost focus-ring hidden text-xs"
> >
View channel View channel
</a> </a>
</span> </div>
<span id="profileModalName" class="profile-card__name">Loading...</span> <span id="profileModalName" class="truncate text-sm font-semibold text-white">Loading...</span>
<span id="profileModalNpub" class="profile-card__npub">npub1...</span> <span id="profileModalNpub" class="break-all font-mono text-xs text-gray-400">npub1...</span>
</span> </div>
</div> </div>
<div <div
id="profileSwitcherList" id="profileSwitcherList"
class="profile-switcher__list" class="grid-stack"
aria-live="polite" aria-live="polite"
aria-label="Additional Nostr profiles" aria-label="Additional Nostr profiles"
role="list"
data-orientation="vertical"
></div> ></div>
<button <button
type="button" type="button"
id="profileAddAccountBtn" id="profileAddAccountBtn"
class="profile-switcher__add" class="btn focus-ring w-full justify-start gap-4 p-4"
aria-label="Add a new Nostr profile" aria-label="Add a new Nostr profile"
> >
<span class="profile-switcher__addAvatar"> <span
class="flex h-10 w-10 items-center justify-center rounded-full bg-blue-500/20 text-blue-400"
aria-hidden="true"
>
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" viewBox="0 0 24 24"
@@ -179,19 +191,18 @@
stroke-width="2" stroke-width="2"
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
aria-hidden="true"
> >
<line x1="12" y1="5" x2="12" y2="19" /> <line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" /> <line x1="5" y1="12" x2="19" y2="12" />
</svg> </svg>
</span> </span>
<span class="profile-switcher__addCopy"> <span class="flex flex-col text-left">
<span class="profile-switcher__addTitle">Add profile</span> <span data-profile-add-title class="text-sm font-semibold text-white">Add profile</span>
<span class="profile-switcher__addHint">Link another npub</span> <span data-profile-add-hint class="text-xs text-gray-300">Link another npub</span>
</span> </span>
</button> </button>
<p class="profile-switcher__helper"> <p class="text-sm text-gray-400">
Profiles you add here will stay on this device so you can quickly switch before posting or moderating. Profiles you add here will stay on this device so you can quickly switch before posting or moderating.
</p> </p>
</div> </div>
@@ -221,21 +232,21 @@
<button <button
id="addRelayBtn" id="addRelayBtn"
type="button" 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" class="btn focus-ring"
> >
Add relay Add relay
</button> </button>
<button <button
id="restoreRelaysBtn" id="restoreRelaysBtn"
type="button" 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" class="btn-ghost focus-ring"
> >
Restore defaults Restore defaults
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<ul id="relayList" class="space-y-3"></ul> <ul id="relayList" class="grid-stack" data-orientation="vertical"></ul>
</section> </section>
<section <section
@@ -275,21 +286,22 @@
<button <button
id="profileWalletSave" id="profileWalletSave"
type="button" 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" class="btn focus-ring"
> >
Save wallet Save wallet
</button> </button>
<button <button
id="profileWalletTest" id="profileWalletTest"
type="button" 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" class="btn-ghost focus-ring"
> >
Test connection Test connection
</button> </button>
<button <button
id="profileWalletDisconnect" id="profileWalletDisconnect"
type="button" 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" class="btn focus-ring"
data-variant="danger"
> >
Disconnect wallet Disconnect wallet
</button> </button>
@@ -328,18 +340,18 @@
<button <button
id="addBlockedBtn" id="addBlockedBtn"
type="button" 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" class="btn focus-ring"
> >
Block creator Block creator
</button> </button>
</div> </div>
<div <div
id="blockedEmpty" id="blockedEmpty"
class="rounded-lg border border-dashed border-gray-700 p-6 text-center text-sm text-gray-400" class="card border border-dashed border-gray-700 p-6 text-center text-sm text-gray-400"
> >
You haven’t blocked any creators yet. You haven’t blocked any creators yet.
</div> </div>
<ul id="blockedList" class="space-y-3"></ul> <ul id="blockedList" class="grid-stack" data-orientation="vertical"></ul>
</section> </section>
<section <section
id="profilePaneHistory" id="profilePaneHistory"
@@ -352,7 +364,7 @@
</p> </p>
<div <div
id="profileHistoryFeatureBanner" id="profileHistoryFeatureBanner"
class="hidden rounded-md border border-amber-500/40 bg-amber-500/10 px-4 py-3 text-sm text-amber-100" class="card hidden border border-amber-500/40 bg-amber-500/10 px-4 py-3 text-sm text-amber-100"
role="status" role="status"
aria-live="polite" aria-live="polite"
></div> ></div>
@@ -366,14 +378,14 @@
<button <button
id="profileHistoryClear" id="profileHistoryClear"
type="button" 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" class="btn-ghost focus-ring inline-flex items-center gap-2"
> >
Clear local cache Clear local cache
</button> </button>
<button <button
id="profileHistoryRepublish" id="profileHistoryRepublish"
type="button" 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" class="btn focus-ring inline-flex items-center gap-2"
> >
Republish now Republish now
</button> </button>
@@ -396,7 +408,7 @@
<button <button
id="profileHistoryMetadataToggle" id="profileHistoryMetadataToggle"
type="button" 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" class="focus-ring relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer items-center rounded-full border border-gray-600 bg-gray-700 transition"
role="switch" role="switch"
aria-checked="true" aria-checked="true"
aria-labelledby="profileHistoryMetadataLabel" aria-labelledby="profileHistoryMetadataLabel"
@@ -446,20 +458,22 @@
</div> </div>
<div <div
id="profileHistoryError" id="profileHistoryError"
class="hidden rounded-md border border-red-500/40 bg-red-500/10 px-4 py-3 text-sm text-red-100" class="card hidden border border-red-500/40 bg-red-500/10 px-4 py-3 text-sm text-red-100"
role="alert" role="alert"
aria-live="assertive" aria-live="assertive"
></div> ></div>
<div <div
id="profileHistoryEmpty" id="profileHistoryEmpty"
class="hidden rounded-lg border border-dashed border-gray-700 p-6 text-center text-sm text-gray-400" class="card hidden border border-dashed border-gray-700 p-6 text-center text-sm text-gray-400"
> >
You haven’t watched any videos yet. You haven’t watched any videos yet.
</div> </div>
<div id="profileHistoryScroll" class="relative max-h-[420px] overflow-y-auto pr-1"> <div id="profileHistoryScroll" class="relative max-h-[420px] overflow-y-auto pr-1">
<div <div
id="profileHistoryGrid" id="profileHistoryGrid"
class="watch-history-grid watch-history-grid--modal hidden" class="grid-stack hidden"
data-variant="cards"
data-orientation="vertical"
role="list" role="list"
></div> ></div>
<div id="profileHistorySentinel" class="h-1 w-full"></div> <div id="profileHistorySentinel" class="h-1 w-full"></div>
@@ -504,18 +518,18 @@
<button <button
id="adminAddModeratorBtn" id="adminAddModeratorBtn"
type="button" 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" class="btn focus-ring"
> >
Add moderator Add moderator
</button> </button>
</div> </div>
<div <div
id="adminModeratorsEmpty" id="adminModeratorsEmpty"
class="rounded-lg border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400" class="card border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400"
> >
No moderators configured yet. No moderators configured yet.
</div> </div>
<ul id="adminModeratorList" class="space-y-3"></ul> <ul id="adminModeratorList" class="grid-stack" data-orientation="vertical"></ul>
</div> </div>
<div id="adminWhitelistSection" class="space-y-4"> <div id="adminWhitelistSection" class="space-y-4">
@@ -540,18 +554,18 @@
<button <button
id="adminAddWhitelistBtn" id="adminAddWhitelistBtn"
type="button" 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" class="btn focus-ring"
> >
Add to whitelist Add to whitelist
</button> </button>
</div> </div>
<div <div
id="adminWhitelistEmpty" id="adminWhitelistEmpty"
class="rounded-lg border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400" class="card border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400"
> >
No whitelisted creators yet. No whitelisted creators yet.
</div> </div>
<ul id="adminWhitelistList" class="space-y-3"></ul> <ul id="adminWhitelistList" class="grid-stack" data-orientation="vertical"></ul>
</div> </div>
<div id="adminBlacklistSection" class="space-y-4"> <div id="adminBlacklistSection" class="space-y-4">
@@ -576,18 +590,18 @@
<button <button
id="adminAddBlacklistBtn" id="adminAddBlacklistBtn"
type="button" 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" class="btn focus-ring"
> >
Add to blacklist Add to blacklist
</button> </button>
</div> </div>
<div <div
id="adminBlacklistEmpty" id="adminBlacklistEmpty"
class="rounded-lg border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400" class="card border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400"
> >
No blacklisted creators yet. No blacklisted creators yet.
</div> </div>
<ul id="adminBlacklistList" class="space-y-3"></ul> <ul id="adminBlacklistList" class="grid-stack" data-orientation="vertical"></ul>
</div> </div>
</section> </section>
</div> </div>
@@ -595,11 +609,8 @@
</div> </div>
<!-- Modal Footer --> <!-- Modal Footer -->
<div class="p-4 border-t border-gray-700 flex items-center justify-end"> <div class="flex items-center justify-end gap-3 border-t border-gray-700 p-4">
<button <button id="profileLogoutBtn" class="btn focus-ring" data-variant="danger">
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 Logout
</button> </button>
</div> </div>
+2 -2
View File
@@ -1655,8 +1655,8 @@ class Application {
return; return;
} }
const titleEl = button.querySelector(".profile-switcher__addTitle"); const titleEl = button.querySelector('[data-profile-add-title]');
const hintEl = button.querySelector(".profile-switcher__addHint"); const hintEl = button.querySelector('[data-profile-add-hint]');
const originalTitle = titleEl ? titleEl.textContent : ""; const originalTitle = titleEl ? titleEl.textContent : "";
const originalHint = hintEl ? hintEl.textContent : ""; const originalHint = hintEl ? hintEl.textContent : "";
const originalAriaLabel = button.getAttribute("aria-label"); const originalAriaLabel = button.getAttribute("aria-label");
+26 -19
View File
@@ -345,14 +345,16 @@ export function buildHistoryCard({
metadataPreference, metadataPreference,
}) { }) {
const article = document.createElement("article"); const article = document.createElement("article");
article.className = "watch-history-card"; article.className = "card flex flex-wrap items-stretch gap-6 p-5";
article.dataset.pointerKey = item.pointerKey; article.dataset.pointerKey = item.pointerKey;
if (video?.isPrivate) { if (video?.isPrivate) {
article.classList.add("watch-history-card--private"); article.dataset.state = "private";
} else {
delete article.dataset.state;
} }
const primary = document.createElement("div"); const primary = document.createElement("div");
primary.className = "watch-history-card__primary"; primary.className = "flex min-w-0 flex-1 gap-4";
const playbackData = (() => { const playbackData = (() => {
if (!video) { if (!video) {
@@ -371,7 +373,8 @@ export function buildHistoryCard({
const pointerVideoId = getPointerVideoId(video, item.pointer); const pointerVideoId = getPointerVideoId(video, item.pointer);
const thumbnailLink = document.createElement("a"); const thumbnailLink = document.createElement("a");
thumbnailLink.className = "watch-history-card__thumbnail"; thumbnailLink.className =
"focus-ring block max-w-[14rem] flex-shrink-0 overflow-hidden rounded-lg bg-slate-900 transition hover:opacity-90";
thumbnailLink.href = "#"; thumbnailLink.href = "#";
thumbnailLink.dataset.historyAction = "play"; thumbnailLink.dataset.historyAction = "play";
thumbnailLink.dataset.pointerKey = item.pointerKey; thumbnailLink.dataset.pointerKey = item.pointerKey;
@@ -386,8 +389,9 @@ export function buildHistoryCard({
} }
const thumbnailInner = document.createElement("div"); const thumbnailInner = document.createElement("div");
thumbnailInner.className = "watch-history-card__thumbnailInner"; thumbnailInner.className = "aspect-video w-full overflow-hidden rounded-lg bg-slate-900";
const thumbnailImg = document.createElement("img"); const thumbnailImg = document.createElement("img");
thumbnailImg.className = "h-full w-full object-cover";
thumbnailImg.alt = video?.title || "Video thumbnail"; thumbnailImg.alt = video?.title || "Video thumbnail";
const thumbnailSrc = const thumbnailSrc =
(video && typeof video.thumbnail === "string" && video.thumbnail.trim()) (video && typeof video.thumbnail === "string" && video.thumbnail.trim())
@@ -400,10 +404,11 @@ export function buildHistoryCard({
thumbnailLink.appendChild(thumbnailInner); thumbnailLink.appendChild(thumbnailInner);
const details = document.createElement("div"); const details = document.createElement("div");
details.className = "watch-history-card__details"; details.className = "flex min-w-0 flex-col justify-center gap-2";
const titleLink = document.createElement("a"); const titleLink = document.createElement("a");
titleLink.className = "watch-history-card__title"; titleLink.className =
"focus-ring text-left text-lg font-semibold text-white transition hover:text-blue-400";
titleLink.href = "#"; titleLink.href = "#";
titleLink.dataset.historyAction = "play"; titleLink.dataset.historyAction = "play";
titleLink.dataset.pointerKey = item.pointerKey; titleLink.dataset.pointerKey = item.pointerKey;
@@ -419,7 +424,7 @@ export function buildHistoryCard({
titleLink.textContent = video?.title || "Untitled video"; titleLink.textContent = video?.title || "Untitled video";
const created = document.createElement("p"); const created = document.createElement("p");
created.className = "watch-history-card__created"; created.className = "text-sm text-gray-400";
const createdAt = Number.isFinite(video?.created_at) ? video.created_at : null; const createdAt = Number.isFinite(video?.created_at) ? video.created_at : null;
created.textContent = createdAt created.textContent = createdAt
? `Published ${formatRelativeTime(createdAt)}` ? `Published ${formatRelativeTime(createdAt)}`
@@ -432,27 +437,29 @@ export function buildHistoryCard({
primary.appendChild(details); primary.appendChild(details);
const meta = document.createElement("div"); const meta = document.createElement("div");
meta.className = "watch-history-card__meta"; meta.className = "flex min-w-[14rem] flex-col justify-between gap-4";
const watched = document.createElement("p"); const watched = document.createElement("p");
watched.className = "watch-history-card__watched"; watched.className = "text-sm text-gray-500";
watched.textContent = item.watchedAt watched.textContent = item.watchedAt
? `Watched ${formatRelativeTime(item.watchedAt)}` ? `Watched ${formatRelativeTime(item.watchedAt)}`
: "Watched time unavailable"; : "Watched time unavailable";
meta.appendChild(watched); meta.appendChild(watched);
const creator = document.createElement("div"); const creator = document.createElement("div");
creator.className = "watch-history-card__creator"; creator.className = "flex items-center gap-3";
const creatorAvatarButton = document.createElement("button"); const creatorAvatarButton = document.createElement("button");
creatorAvatarButton.type = "button"; creatorAvatarButton.type = "button";
creatorAvatarButton.className = "watch-history-card__creatorAvatar"; creatorAvatarButton.className =
"focus-ring flex h-10 w-10 items-center justify-center overflow-hidden rounded-full bg-slate-800";
creatorAvatarButton.dataset.historyAction = "channel"; creatorAvatarButton.dataset.historyAction = "channel";
creatorAvatarButton.dataset.pointerKey = item.pointerKey; creatorAvatarButton.dataset.pointerKey = item.pointerKey;
if (video?.pubkey) { if (video?.pubkey) {
creatorAvatarButton.dataset.author = video.pubkey; creatorAvatarButton.dataset.author = video.pubkey;
} }
const avatarImg = document.createElement("img"); const avatarImg = document.createElement("img");
avatarImg.className = "h-full w-full object-cover";
const avatarSrc = const avatarSrc =
(profile && typeof profile.picture === "string" && profile.picture.trim()) (profile && typeof profile.picture === "string" && profile.picture.trim())
? profile.picture.trim() ? profile.picture.trim()
@@ -463,7 +470,8 @@ export function buildHistoryCard({
const creatorNameButton = document.createElement("button"); const creatorNameButton = document.createElement("button");
creatorNameButton.type = "button"; creatorNameButton.type = "button";
creatorNameButton.className = "watch-history-card__creatorName"; creatorNameButton.className =
"focus-ring text-left text-sm font-medium text-gray-200 transition hover:text-blue-400";
creatorNameButton.dataset.historyAction = "channel"; creatorNameButton.dataset.historyAction = "channel";
creatorNameButton.dataset.pointerKey = item.pointerKey; creatorNameButton.dataset.pointerKey = item.pointerKey;
if (video?.pubkey) { if (video?.pubkey) {
@@ -483,12 +491,11 @@ export function buildHistoryCard({
meta.appendChild(creator); meta.appendChild(creator);
const actions = document.createElement("div"); const actions = document.createElement("div");
actions.className = "watch-history-card__actions"; actions.className = "flex flex-wrap items-center gap-3";
const playButton = document.createElement("button"); const playButton = document.createElement("button");
playButton.type = "button"; playButton.type = "button";
playButton.className = playButton.className = "btn focus-ring";
"watch-history-card__action watch-history-card__action--primary";
playButton.dataset.historyAction = "play"; playButton.dataset.historyAction = "play";
playButton.dataset.pointerKey = item.pointerKey; playButton.dataset.pointerKey = item.pointerKey;
if (pointerVideoId) { if (pointerVideoId) {
@@ -504,7 +511,7 @@ export function buildHistoryCard({
const channelButton = document.createElement("button"); const channelButton = document.createElement("button");
channelButton.type = "button"; channelButton.type = "button";
channelButton.className = "watch-history-card__action"; channelButton.className = "btn-ghost focus-ring";
channelButton.dataset.historyAction = "channel"; channelButton.dataset.historyAction = "channel";
channelButton.dataset.pointerKey = item.pointerKey; channelButton.dataset.pointerKey = item.pointerKey;
if (video?.pubkey) { if (video?.pubkey) {
@@ -514,8 +521,8 @@ export function buildHistoryCard({
const removeButton = document.createElement("button"); const removeButton = document.createElement("button");
removeButton.type = "button"; removeButton.type = "button";
removeButton.className = removeButton.className = "btn-ghost focus-ring";
"watch-history-card__action watch-history-card__action--danger"; removeButton.dataset.variant = "danger";
removeButton.dataset.historyAction = "remove"; removeButton.dataset.historyAction = "remove";
removeButton.dataset.pointerKey = item.pointerKey; removeButton.dataset.pointerKey = item.pointerKey;
removeButton.textContent = "Remove from history"; removeButton.textContent = "Remove from history";
+37 -31
View File
@@ -1258,7 +1258,7 @@ export class ProfileModalController {
if (!entriesToRender.length) { if (!entriesToRender.length) {
listEl.setAttribute("data-profile-switcher-empty", "true"); listEl.setAttribute("data-profile-switcher-empty", "true");
const helper = document.createElement("p"); const helper = document.createElement("p");
helper.className = "profile-switcher__empty text-sm text-gray-400"; helper.className = "text-sm text-gray-400";
helper.textContent = "No other profiles saved yet."; helper.textContent = "No other profiles saved yet.";
helper.setAttribute("role", "note"); helper.setAttribute("role", "note");
listEl.appendChild(helper); listEl.appendChild(helper);
@@ -1269,7 +1269,8 @@ export class ProfileModalController {
const meta = resolveMeta(entry); const meta = resolveMeta(entry);
const button = document.createElement("button"); const button = document.createElement("button");
button.type = "button"; button.type = "button";
button.classList.add("profile-card"); button.className =
"card focus-ring flex w-full items-center gap-4 p-4 text-left transition";
button.dataset.pubkey = entry.pubkey; button.dataset.pubkey = entry.pubkey;
if (meta.npub) { if (meta.npub) {
button.dataset.npub = meta.npub; button.dataset.npub = meta.npub;
@@ -1282,15 +1283,19 @@ export class ProfileModalController {
const isSelected = const isSelected =
normalizedSelection && normalizedPubkey === normalizedSelection; normalizedSelection && normalizedPubkey === normalizedSelection;
if (isSelected) { if (isSelected) {
button.classList.add("profile-card--active"); button.dataset.state = "active";
button.classList.add("ring-1", "ring-blue-400/60", "bg-blue-500/10");
button.setAttribute("aria-pressed", "true"); button.setAttribute("aria-pressed", "true");
} else { } else {
delete button.dataset.state;
button.setAttribute("aria-pressed", "false"); button.setAttribute("aria-pressed", "false");
} }
const avatarSpan = document.createElement("span"); const avatarSpan = document.createElement("span");
avatarSpan.className = "profile-card__avatar"; avatarSpan.className =
"flex h-12 w-12 flex-shrink-0 items-center justify-center overflow-hidden rounded-full border-2 border-slate-500/50 bg-slate-900";
const avatarImg = document.createElement("img"); const avatarImg = document.createElement("img");
avatarImg.className = "h-full w-full object-cover";
avatarImg.src = meta.picture || FALLBACK_PROFILE_AVATAR; avatarImg.src = meta.picture || FALLBACK_PROFILE_AVATAR;
const cardDisplayName = const cardDisplayName =
meta.name?.trim() || meta.name?.trim() ||
@@ -1298,30 +1303,31 @@ export class ProfileModalController {
avatarImg.alt = `${cardDisplayName} avatar`; avatarImg.alt = `${cardDisplayName} avatar`;
avatarSpan.appendChild(avatarImg); avatarSpan.appendChild(avatarImg);
const metaSpan = document.createElement("span"); const metaSpan = document.createElement("div");
metaSpan.className = "profile-card__meta"; metaSpan.className = "flex min-w-0 flex-1 flex-col gap-2";
const topLine = document.createElement("span"); const topLine = document.createElement("div");
topLine.className = "profile-card__topline"; topLine.className = "flex flex-wrap items-center gap-3";
const label = document.createElement("span"); const label = document.createElement("span");
label.className = "profile-card__label"; label.className =
"text-[11px] font-semibold uppercase tracking-[0.2em] text-blue-200";
label.textContent = label.textContent =
entry.authType === "nsec" ? "Direct key" : "Saved profile"; entry.authType === "nsec" ? "Direct key" : "Saved profile";
const action = document.createElement("span"); const action = document.createElement("span");
action.className = "profile-card__action"; action.className = "text-xs font-medium text-gray-400";
action.setAttribute("aria-hidden", "true"); action.setAttribute("aria-hidden", "true");
action.textContent = isSelected ? "Selected" : "Switch"; action.textContent = isSelected ? "Selected" : "Switch";
topLine.append(label, action); topLine.append(label, action);
const nameSpan = document.createElement("span"); const nameSpan = document.createElement("span");
nameSpan.className = "profile-card__name"; nameSpan.className = "truncate text-sm font-semibold text-white";
nameSpan.textContent = cardDisplayName; nameSpan.textContent = cardDisplayName;
const npubSpan = document.createElement("span"); const npubSpan = document.createElement("span");
npubSpan.className = "profile-card__npub"; npubSpan.className = "break-all font-mono text-xs text-gray-400";
npubSpan.textContent = meta.npub npubSpan.textContent = meta.npub
? truncate(meta.npub, 48) ? truncate(meta.npub, 48)
: "npub unavailable"; : "npub unavailable";
@@ -1424,9 +1430,11 @@ export class ProfileModalController {
} }
const isActive = key === target; const isActive = key === target;
button.setAttribute("aria-selected", isActive ? "true" : "false"); button.setAttribute("aria-selected", isActive ? "true" : "false");
button.classList.toggle("bg-gray-800", isActive); if (isActive) {
button.classList.toggle("text-white", isActive); button.dataset.state = "active";
button.classList.toggle("text-gray-400", !isActive); } else {
delete button.dataset.state;
}
}); });
this.setActivePane(target); this.setActivePane(target);
@@ -1483,7 +1491,7 @@ export class ProfileModalController {
if (!relays.length) { if (!relays.length) {
const emptyState = document.createElement("li"); const emptyState = document.createElement("li");
emptyState.className = emptyState.className =
"rounded-lg border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400"; "card border border-dashed border-gray-700 p-4 text-center text-sm text-gray-400";
emptyState.textContent = "No relays configured."; emptyState.textContent = "No relays configured.";
this.relayList.appendChild(emptyState); this.relayList.appendChild(emptyState);
return; return;
@@ -1492,7 +1500,7 @@ export class ProfileModalController {
relays.forEach((entry) => { relays.forEach((entry) => {
const item = document.createElement("li"); const item = document.createElement("li");
item.className = item.className =
"flex items-start justify-between gap-4 rounded-lg bg-gray-800 px-4 py-3"; "card flex items-start justify-between gap-4 p-4";
const info = document.createElement("div"); const info = document.createElement("div");
info.className = "flex-1 min-w-0"; info.className = "flex-1 min-w-0";
@@ -1519,8 +1527,7 @@ export class ProfileModalController {
const editBtn = document.createElement("button"); const editBtn = document.createElement("button");
editBtn.type = "button"; editBtn.type = "button";
editBtn.className = editBtn.className = "btn-ghost focus-ring text-xs";
"px-3 py-1 rounded-md bg-gray-700 text-xs font-medium text-gray-100 hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900";
editBtn.textContent = "Change mode"; editBtn.textContent = "Change mode";
editBtn.title = "Cycle between read-only, write-only, or read/write modes."; editBtn.title = "Cycle between read-only, write-only, or read/write modes.";
editBtn.addEventListener("click", () => { editBtn.addEventListener("click", () => {
@@ -1529,8 +1536,8 @@ export class ProfileModalController {
const removeBtn = document.createElement("button"); const removeBtn = document.createElement("button");
removeBtn.type = "button"; removeBtn.type = "button";
removeBtn.className = removeBtn.className = "btn-ghost focus-ring text-xs";
"px-3 py-1 rounded-md bg-gray-700 text-xs font-medium text-gray-100 hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900"; removeBtn.dataset.variant = "danger";
removeBtn.textContent = "Remove"; removeBtn.textContent = "Remove";
removeBtn.addEventListener("click", () => { removeBtn.addEventListener("click", () => {
void this.handleRemoveRelay(entry.url); void this.handleRemoveRelay(entry.url);
@@ -1838,21 +1845,21 @@ export class ProfileModalController {
deduped.forEach(({ hex, label }) => { deduped.forEach(({ hex, label }) => {
const item = document.createElement("li"); const item = document.createElement("li");
item.className = item.className =
"flex items-center justify-between gap-4 rounded-lg bg-gray-800 px-4 py-3"; "card flex items-center justify-between gap-4 p-4";
const info = document.createElement("div"); const info = document.createElement("div");
info.className = "min-w-0"; info.className = "min-w-0 flex-1";
const title = document.createElement("p"); const title = document.createElement("p");
title.className = "text-sm font-medium text-gray-100 break-all"; title.className = "break-all text-sm font-medium text-gray-100";
title.textContent = label; title.textContent = label;
info.appendChild(title); info.appendChild(title);
const actionBtn = document.createElement("button"); const actionBtn = document.createElement("button");
actionBtn.type = "button"; actionBtn.type = "button";
actionBtn.className = actionBtn.className = "btn-ghost focus-ring text-xs";
"px-3 py-1 rounded-md bg-gray-700 text-xs font-medium text-gray-100 hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900"; actionBtn.dataset.variant = "danger";
actionBtn.textContent = "Remove"; actionBtn.textContent = "Remove";
actionBtn.dataset.blockedHex = hex; actionBtn.dataset.blockedHex = hex;
actionBtn.addEventListener("click", () => { actionBtn.addEventListener("click", () => {
@@ -2618,18 +2625,17 @@ export class ProfileModalController {
values.forEach((npub) => { values.forEach((npub) => {
const item = document.createElement("li"); const item = document.createElement("li");
item.className = item.className =
"flex flex-col gap-2 rounded-lg bg-gray-800 px-4 py-3 sm:flex-row sm:items-center sm:justify-between"; "card flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between";
const label = document.createElement("p"); const label = document.createElement("p");
label.className = "text-sm font-medium text-gray-100 break-all"; label.className = "break-all text-sm font-medium text-gray-100";
label.textContent = npub; label.textContent = npub;
item.appendChild(label); item.appendChild(label);
if (removable && typeof onRemove === "function") { if (removable && typeof onRemove === "function") {
const removeBtn = document.createElement("button"); const removeBtn = document.createElement("button");
removeBtn.type = "button"; removeBtn.type = "button";
removeBtn.className = removeBtn.className = "btn-ghost focus-ring text-xs";
"self-start rounded-md bg-gray-700 px-3 py-1 text-xs font-medium text-gray-100 transition hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900";
removeBtn.textContent = removeLabel; removeBtn.textContent = removeLabel;
removeBtn.addEventListener("click", () => { removeBtn.addEventListener("click", () => {
if (confirmMessage) { if (confirmMessage) {
@@ -2759,7 +2765,7 @@ export class ProfileModalController {
this.setAdminLoading(false); this.setAdminLoading(false);
if ( if (
adminNav instanceof HTMLElement && adminNav instanceof HTMLElement &&
adminNav.classList.contains("bg-gray-800") adminNav.dataset.state === "active"
) { ) {
this.selectPane("account"); this.selectPane("account");
} }
+6 -1
View File
@@ -88,7 +88,12 @@
</div> </div>
</div> </div>
<div id="watchHistoryGrid" class="watch-history-grid hidden"></div> <div
id="watchHistoryGrid"
class="grid-stack hidden"
data-variant="cards"
data-orientation="vertical"
></div>
<p id="watchHistoryEmpty" class="hidden text-gray-400 text-center py-12"> <p id="watchHistoryEmpty" class="hidden text-gray-400 text-center py-12">
Your watch history is empty. Watch some videos to populate this list. Your watch history is empty. Watch some videos to populate this list.
</p> </p>