Skip to content

Commit 6606a2f

Browse files
JSKittyclaude
andcommitted
ux: clickable mini-profile avatar (View Profile shortcut) + lock images
- Avatar now opens the full profile screen on click — same effect as the button, just a quicker path. Hover scales up slightly to advertise the affordance, active scales down for tactile feedback. - Banner and avatar images are locked: draggable=false on the elements, user-select: none + -webkit-user-drag: none on their containers, and pointer-events: none on the inner imgs so the click bubbles to the avatar wrapper instead of being absorbed by the picture. - Extract `_miniProfileOpenFull(npub)` so the avatar click and the "View Profile" button share one implementation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4057d5b commit 6606a2f

2 files changed

Lines changed: 41 additions & 7 deletions

File tree

src/js/render/mini-profile.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@ function showMiniProfile(npub, anchorEl) {
6969
}
7070
}
7171

72+
/**
73+
* Drill into the full profile screen for `npub`. Shared by the avatar click
74+
* shortcut and the "View Profile" button.
75+
*/
76+
function _miniProfileOpenFull(npub) {
77+
hideMiniProfile();
78+
if (typeof openProfile !== 'function') return;
79+
previousChatBeforeProfile = (typeof strOpenChat !== 'undefined') ? strOpenChat : '';
80+
const prof = (typeof getProfile === 'function') ? getProfile(npub) : null;
81+
openProfile(prof || { id: npub });
82+
}
83+
7284
function hideMiniProfile() {
7385
if (miniProfileEl) { miniProfileEl.remove(); miniProfileEl = null; }
7486
if (miniProfileBackdrop) { miniProfileBackdrop.remove(); miniProfileBackdrop = null; }
@@ -103,19 +115,27 @@ function _populateMiniProfile(popup, npub, profile) {
103115
const img = document.createElement('img');
104116
img.src = bannerSrc;
105117
img.alt = '';
118+
img.draggable = false;
106119
img.onerror = () => img.remove();
107120
banner.appendChild(img);
108121
}
109122
popup.appendChild(banner);
110123

111-
// Avatar (overlapping the banner's bottom edge)
124+
// Avatar (overlapping the banner's bottom edge). Clicking it is a shortcut
125+
// to "View Profile" — same effect as the body button.
112126
const avatarWrap = document.createElement('div');
113127
avatarWrap.className = 'mini-profile-avatar';
128+
avatarWrap.title = 'View Profile';
129+
avatarWrap.onclick = (e) => {
130+
e.stopPropagation();
131+
_miniProfileOpenFull(npub);
132+
};
114133
const avatarSrc = (typeof getProfileAvatarSrc === 'function') ? getProfileAvatarSrc(profile) : null;
115134
if (avatarSrc) {
116135
const img = document.createElement('img');
117136
img.src = avatarSrc;
118137
img.alt = '';
138+
img.draggable = false;
119139
img.onerror = () => {
120140
img.replaceWith(createPlaceholderAvatar(false, 72));
121141
};
@@ -198,12 +218,7 @@ function _populateMiniProfile(popup, npub, profile) {
198218
btnView.textContent = 'View Profile';
199219
btnView.onclick = (e) => {
200220
e.stopPropagation();
201-
hideMiniProfile();
202-
if (typeof openProfile === 'function') {
203-
previousChatBeforeProfile = (typeof strOpenChat !== 'undefined') ? strOpenChat : '';
204-
const prof = (typeof getProfile === 'function') ? getProfile(npub) : null;
205-
openProfile(prof || { id: npub });
206-
}
221+
_miniProfileOpenFull(npub);
207222
};
208223
actions.appendChild(btnView);
209224

src/styles.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,12 +2108,18 @@ body.chat-bg-disabled .chat-messages::before {
21082108
flex-shrink: 0;
21092109
position: relative;
21102110
overflow: hidden;
2111+
/* Banner is decoration — text-select / drag would lift the image off the popup. */
2112+
user-select: none;
2113+
-webkit-user-select: none;
2114+
-webkit-user-drag: none;
21112115
}
21122116
.mini-profile-banner img {
21132117
width: 100%;
21142118
height: 100%;
21152119
object-fit: cover;
21162120
display: block;
2121+
-webkit-user-drag: none;
2122+
pointer-events: none;
21172123
}
21182124

21192125
.mini-profile-avatar {
@@ -2127,6 +2133,17 @@ body.chat-bg-disabled .chat-messages::before {
21272133
background: #1a1a1a;
21282134
overflow: hidden;
21292135
z-index: 2;
2136+
cursor: pointer;
2137+
user-select: none;
2138+
-webkit-user-select: none;
2139+
-webkit-user-drag: none;
2140+
transition: transform 0.1s ease;
2141+
}
2142+
.mini-profile-avatar:hover {
2143+
transform: scale(1.04);
2144+
}
2145+
.mini-profile-avatar:active {
2146+
transform: scale(0.98);
21302147
}
21312148
.mini-profile-avatar img,
21322149
.mini-profile-avatar .placeholder-avatar {
@@ -2135,6 +2152,8 @@ body.chat-bg-disabled .chat-messages::before {
21352152
object-fit: cover;
21362153
border-radius: 50%;
21372154
display: block;
2155+
-webkit-user-drag: none;
2156+
pointer-events: none;
21382157
}
21392158

21402159
.mini-profile-body {

0 commit comments

Comments
 (0)