pinch zoom bug fix

This commit is contained in:
2026-03-28 11:06:59 -04:00
parent abd4574ee3
commit 459ab27c5b
3 changed files with 93 additions and 4 deletions

View File

@@ -13,6 +13,73 @@ function nameToColor(name) {
return AVATAR_COLORS[(name || '').charCodeAt(0) % AVATAR_COLORS.length];
}
// Layouts for composite avatars inside a 44×44 circle (all values in px)
const COMPOSITE_LAYOUTS = {
1: [{ top: 4, left: 4, size: 36 }],
2: [
{ top: 11, left: 1, size: 21 },
{ top: 11, right: 1, size: 21 },
],
3: [
{ top: 2, left: 3, size: 19 },
{ top: 2, right: 3, size: 19 },
{ bottom: 2, left: 12, size: 19 },
],
4: [
{ top: 1, left: 1, size: 20 },
{ top: 1, right: 1, size: 20 },
{ bottom: 1, left: 1, size: 20 },
{ bottom: 1, right: 1, size: 20 },
],
};
function GroupAvatarComposite({ memberPreviews, fallbackLabel, fallbackColor }) {
const members = (memberPreviews || []).slice(0, 4);
const n = members.length;
const positions = COMPOSITE_LAYOUTS[n];
if (!positions) {
return (
<div className="group-icon" style={{ background: fallbackColor, borderRadius: 8, fontSize: 11, fontWeight: 700 }}>
{fallbackLabel}
</div>
);
}
return (
<div className="group-icon" style={{ background: '#1a1a2e', position: 'relative', padding: 0, overflow: 'hidden' }}>
{members.map((m, i) => {
const pos = positions[i];
const base = {
position: 'absolute',
width: pos.size,
height: pos.size,
borderRadius: '50%',
...(pos.top !== undefined ? { top: pos.top } : {}),
...(pos.bottom !== undefined ? { bottom: pos.bottom } : {}),
...(pos.left !== undefined ? { left: pos.left } : {}),
...(pos.right !== undefined ? { right: pos.right } : {}),
overflow: 'hidden',
flexShrink: 0,
};
if (m.avatar) {
return <img key={m.id} src={m.avatar} alt={m.name} style={{ ...base, objectFit: 'cover' }} />;
}
return (
<div key={m.id} style={{
...base,
background: nameToColor(m.name),
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontSize: Math.round(pos.size * 0.42), fontWeight: 700, color: 'white',
}}>
{(m.name || '')[0]?.toUpperCase()}
</div>
);
})}
</div>
);
}
function useAppSettings() {
const [settings, setSettings] = useState({ app_name: 'rosterchirp', logo_url: '', color_avatar_public: '', color_avatar_dm: '' });
const fetchSettings = () => {
@@ -98,9 +165,9 @@ export default function Sidebar({ groups, activeGroupId, onSelectGroup, notifica
{(group.peer_real_name || group.name)[0]?.toUpperCase()}
</div>
) : group.is_managed && group.is_multi_group ? (
<div className="group-icon" style={{ background: settings.color_avatar_dm || '#a142f4', borderRadius: 8, fontSize: 11, fontWeight: 700 }}>MG</div>
<GroupAvatarComposite memberPreviews={group.member_previews} fallbackLabel="MG" fallbackColor={settings.color_avatar_dm || '#a142f4'} />
) : group.is_managed ? (
<div className="group-icon" style={{ background: settings.color_avatar_dm || '#a142f4', borderRadius: 8, fontSize: 11, fontWeight: 700 }}>UG</div>
<GroupAvatarComposite memberPreviews={group.member_previews} fallbackLabel="UG" fallbackColor={settings.color_avatar_dm || '#a142f4'} />
) : (
<div className="group-icon" style={{ background: group.type === 'public' ? (settings.color_avatar_public || '#1a73e8') : (settings.color_avatar_dm || '#a142f4') }}>
{group.type === 'public' ? '#' : group.name[0]?.toUpperCase()}