Skip to content

Commit

Permalink
Show more than three Avatars for Reactions (#644)
Browse files Browse the repository at this point in the history
  • Loading branch information
fregante authored and sindresorhus committed Jul 27, 2017
1 parent deb970a commit 40653f3
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 28 deletions.
9 changes: 1 addition & 8 deletions extension/content.css
Original file line number Diff line number Diff line change
Expand Up @@ -454,17 +454,10 @@ we will add it back on for the simple news alerts we decide to show
}

/* Overlap reaction avatars when there are 5+ types of reactions */
.reaction-summary-item:first-child:nth-last-child(n+5):not(:hover) a:nth-child(n+2),
.reaction-summary-item:first-child:nth-last-child(n+5) ~ *:not(:hover) a:nth-child(n+2) {
.rgh-reactions-near-limit .reaction-summary-item:not(:hover) a:not(:first-of-type) {
margin-left: -12px;
}

/* Limit reaction avatars when there are 6 types of reactions */
.reaction-summary-item:first-child:nth-last-child(6) a:nth-child(n+3),
.reaction-summary-item:first-child:nth-last-child(6) ~ * a:nth-child(n+3) {
display: none;
}

/* Hide reaction popover text */
.reaction-popover-form.js-pick-reaction span.js-reaction-description,
.reaction-popover-form.js-pick-reaction .dropdown-divider {
Expand Down
58 changes: 38 additions & 20 deletions src/libs/reactions-avatars.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,51 @@
import debounce from 'debounce-fn';
import select from 'select-dom';
import {h} from 'dom-chef';
import {getUsername} from './utils';
import {getUsername, flatZip} from './utils';

function add() {
const arbitraryAvatarLimit = 39;
const approximateHeaderLength = 3; // Each button header takes about as much as 3 avatars

function getParticipants(container) {
const currentUser = getUsername();
for (const element of select.all(`
.comment-reactions.has-reactions
.comment-reactions-options
.reaction-summary-item[aria-label]:not(.rgh-reactions)
`)) {
element.classList.add('rgh-reactions');
const participants = element.getAttribute('aria-label')
.replace(/ reacted with.*/, '')
.replace(/,? and /, ', ')
.replace(/, \d+ more/, '')
.split(', ')
.filter(username => username !== currentUser)
.filter((u, i) => i < 3) // Limit to 3 avatars
.map(user => (
<a href={`/${user}`}>
<img src={`/${user}.png`}/>
return container.getAttribute('aria-label')
.replace(/ reacted with.*/, '')
.replace(/,? and /, ', ')
.replace(/, \d+ more/, '')
.split(', ')
.filter(username => username !== currentUser)
.map(username => ({
container,
username
}));
}

function add() {
for (const list of select.all(`.has-reactions .comment-reactions-options:not(.rgh-reactions)`)) {
const avatarLimit = arbitraryAvatarLimit - (list.children.length * approximateHeaderLength);

const participantByReaction = [].map.call(list.children, getParticipants);
const flatParticipants = flatZip(participantByReaction, avatarLimit);

for (const participant of flatParticipants) {
participant.container.append(
<a href={`/${participant.username}`}>
<img src={`/${participant.username}.png?size=${window.devicePixelRatio * 20}`}/>
</a>
));
);
}

list.classList.add('rgh-reactions');

element.append(...participants);
// Overlap reaction avatars when near the avatarLimit
if (flatParticipants.length > avatarLimit * 0.9) {
list.classList.add('rgh-reactions-near-limit');
}
}
}

// Feature testable on
// https://github.com/babel/babel/pull/3646
export default () => {
add();
document.addEventListener('socket:message', debounce(add, {wait: 100}));
Expand Down
19 changes: 19 additions & 0 deletions src/libs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,22 @@ export const observeEl = (el, listener, options = {childList: true}) => {
// Run on updates
return new MutationObserver(listener).observe(el, options);
};

// Concats arrays but does so like a zipper instead of appending them
// [[0, 1, 2], [0, 1]] => [0, 0, 1, 1, 2]
// Like lodash.zip
export const flatZip = (table, limit = Infinity) => {
const maxColumns = Math.max(...table.map(row => row.length));
const zipped = [];
for (let col = 0; col < maxColumns; col++) {
for (const row of table) {
if (row[col]) {
zipped.push(row[col]);
if (limit !== Infinity && zipped.length === limit) {
return zipped;
}
}
}
}
return zipped;
};

0 comments on commit 40653f3

Please sign in to comment.