You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

60 lines
2.2 KiB

import type { TEmoji } from '@/types'
/** Canonical reaction `content` for discussion upvotes (kind 7). */
const DISCUSSION_UPVOTE = '+'
/** Canonical reaction `content` for discussion downvotes (kind 7). */
const DISCUSSION_DOWNVOTE = '-'
/** Shown in discussion UIs; legacy reaction `content` used the same characters. */
export const DISCUSSION_UPVOTE_DISPLAY = '⬆'
export const DISCUSSION_DOWNVOTE_DISPLAY = '⬇'
function emojiString(emoji: TEmoji | string | undefined | null): string | undefined {
if (emoji === undefined || emoji === null) return undefined
return typeof emoji === 'string' ? emoji : emoji.shortcode
}
/**
* Relays/clients may use ⬆ (U+2B06) vs ⬆ (U+2B06 U+FE0F); normalize before comparing.
*/
function normalizedVoteToken(s: string): string {
return s.normalize('NFC').replace(/\ufe0f/g, '').trim()
}
const UP_ARROW = '\u2b06'
const DOWN_ARROW = '\u2b07'
export function isDiscussionUpvoteEmoji(emoji: TEmoji | string | undefined | null): boolean {
const s = emojiString(emoji)
if (s === undefined) return false
const n = normalizedVoteToken(s)
return n === DISCUSSION_UPVOTE || n === UP_ARROW
}
export function isDiscussionDownvoteEmoji(emoji: TEmoji | string | undefined | null): boolean {
const s = emojiString(emoji)
if (s === undefined) return false
const n = normalizedVoteToken(s)
return n === DISCUSSION_DOWNVOTE || n === DOWN_ARROW
}
export function isDiscussionVoteEmoji(emoji: TEmoji | string | undefined | null): boolean {
return isDiscussionUpvoteEmoji(emoji) || isDiscussionDownvoteEmoji(emoji)
}
export const DISCUSSION_VOTE_EMOJIS = [DISCUSSION_UPVOTE, DISCUSSION_DOWNVOTE] as const
/** Same vote direction, including legacy ⬆/⬇ vs +/-. */
export function discussionVoteMatches(
stored: TEmoji | string | undefined | null,
clicked: string | TEmoji
): boolean {
if (stored === undefined || stored === null) return false
const clickStr = typeof clicked === 'string' ? clicked : clicked.shortcode
const storeStr = typeof stored === 'string' ? stored : stored.shortcode
if (storeStr === clickStr) return true
return (
(isDiscussionUpvoteEmoji(storeStr) && isDiscussionUpvoteEmoji(clickStr)) ||
(isDiscussionDownvoteEmoji(storeStr) && isDiscussionDownvoteEmoji(clickStr))
)
}