-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
quick-reactions
- New feature
#7247
base: main
Are you sure you want to change the base?
Conversation
Love this. I'm concerned that it will break quickly and painfully, but if it's solid enough I'll just merge it anyway, because we can deal with that via hotfixes. The concern at the moment is that Refined GitHub is seeing some serious slowdowns in issues/PRs at the moment so I might not be able to merge this or add new features for a while :( |
Thanks for taking a look! Let me know if I can do anything to get this into a state you're comfortable shipping. 💪 |
It's not an issue with this PR, but rather with Refined GitHub itself. I can merge it once I figure out the root cause of this: because those features also use the selector observer, so I'm afraid that that's what's causing the slow-downs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, I'm almost ready to merge this, probably after the next release.
There are a few notes about the code though.
Also, does this behave well/correctly if I double-click the reaction button? Or is that not-possible?
function optimisticReactionFromPost(event: DelegateEvent<MouseEvent>): void { | ||
const reaction = event.delegateTarget as HTMLButtonElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC you can just pass the type here, no need to assert it. Refer to its docs if it fails, also fix it elsewhere
function optimisticReactionFromPost(event: DelegateEvent<MouseEvent>): void { | |
const reaction = event.delegateTarget as HTMLButtonElement; | |
function optimisticReactionFromPost(event: DelegateEvent<MouseEvent, HTMLButtonElement>): void { |
function optimisticReactionFromMenu(event: DelegateEvent<MouseEvent>): void { | ||
const reactionButton = event.delegateTarget as HTMLButtonElement; | ||
const reactionsMenu = reactionButton.closest('reactions-menu')!; | ||
const details = reactionsMenu.querySelector('details'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you replace every querySelector usage with $
from select-dom
? The only exception is when the line has multiple traversing, e.g. x.closest().querySelector('a')
is still more readable than $('a', x.closest())
const details = reactionsMenu.querySelector('details'); | ||
details!.open = false; // Close reactions menu immediately | ||
|
||
const reactionsContainer = reactionsMenu.nextElementSibling!.querySelector('.js-comment-reactions-options')!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Positional traversing makes the code a little more brittle because a simple span
in between will break it. If possible, select the parent element instead (e.g. menu.parentElement.querySelector
) or just change what reactionsMenu
to select its parent instead
details!.open = false; // Close reactions menu immediately | ||
|
||
const reactionsContainer = reactionsMenu.nextElementSibling!.querySelector('.js-comment-reactions-options')!; | ||
const reactionButtonValue = reactionButton.getAttribute('value')!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you looking for reactionButton.value
?
const countElement = buttonElement.querySelector( | ||
'.js-discussion-reaction-group-count', | ||
)!; | ||
const count = Number.parseInt(countElement.textContent, 10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably also works
const count = Number.parseInt(countElement.textContent, 10); | |
const count = Number(countElement.textContent); |
|
||
const reactionsContainer = reactionsMenu.nextElementSibling!.querySelector('.js-comment-reactions-options')!; | ||
const reactionButtonValue = reactionButton.getAttribute('value')!; | ||
const existingReaction = reactionsContainer.querySelector<HTMLButtonElement>(`[value="${reactionButtonValue}"]`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the selector includes the tag name, you probably won't need to specify the type
const existingReaction = reactionsContainer.querySelector<HTMLButtonElement>(`[value="${reactionButtonValue}"]`); | |
const existingReaction = $(`button[value="${reactionButtonValue}"]`, reactionsContainer); |
// The user is updating an existing reaction via the menu, just update the reaction | ||
updateReaction(existingReaction); | ||
} else { | ||
// Reactions have a specific order, so we need to insert the new reaction in the correct position |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If:
- GitHub still updates the UI later
- it simplifies this piece of code
Please just append the reaction instead, it will update within a second anyway. I'd rather have a feature that lasts longer than one that looks absolutely perfect for only one month.
const emojiElement = reactionButton.querySelector('g-emoji')!.cloneNode(true); | ||
emojiElement.className = 'social-button-emoji'; | ||
|
||
reactionsContainer.insertBefore( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
}); | ||
const referenceNode = reactionsContainer.querySelectorAll('button').item(insertionIndex); | ||
const emojiElement = reactionButton.querySelector('g-emoji')!.cloneNode(true); | ||
emojiElement.className = 'social-button-emoji'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this class doing and why is it not there already?
Optimistically applies reactions instead of waiting for a slow network request to finish.
This should work anywhere you can react to something on GitHub. Reactions are added, updated and removed immediately. New reactions are inserted in the correct place and will not jump around when the new markup comes in.
Test URLs
Screenshot