diff --git a/app/javascript/flavours/glitch/components/emoji/index.tsx b/app/javascript/flavours/glitch/components/emoji/index.tsx index 6ca3321452..b950f4c042 100644 --- a/app/javascript/flavours/glitch/components/emoji/index.tsx +++ b/app/javascript/flavours/glitch/components/emoji/index.tsx @@ -1,9 +1,14 @@ import type { FC } from 'react'; import { useContext, useEffect, useState } from 'react'; +import classNames from 'classnames'; + import { EMOJI_TYPE_CUSTOM } from '@/flavours/glitch/features/emoji/constants'; import { useEmojiAppState } from '@/flavours/glitch/features/emoji/mode'; -import { unicodeHexToUrl } from '@/flavours/glitch/features/emoji/normalize'; +import { + emojiToInversionClassName, + unicodeHexToUrl, +} from '@/flavours/glitch/features/emoji/normalize'; import { isStateLoaded, loadEmojiDataToState, @@ -41,6 +46,9 @@ export const Emoji: FC = ({ }, [appState.currentLocale, state]); const animate = useContext(AnimateEmojiContext); + + const inversionClass = emojiToInversionClassName(code); + const fallback = showFallback ? code : null; // If the code is invalid or we otherwise know it's not valid, show the fallback. @@ -79,7 +87,7 @@ export const Emoji: FC = ({ src={src} alt={state.data.unicode} title={state.data.label} - className='emojione' + className={classNames('emojione', inversionClass)} loading='lazy' /> ); diff --git a/app/javascript/flavours/glitch/features/emoji/constants.ts b/app/javascript/flavours/glitch/features/emoji/constants.ts index 42d22e4054..f770573121 100644 --- a/app/javascript/flavours/glitch/features/emoji/constants.ts +++ b/app/javascript/flavours/glitch/features/emoji/constants.ts @@ -116,3 +116,29 @@ export const EMOJIS_WITH_LIGHT_BORDER = [ 'đŸĒŊ', // 1FAE8 'đŸĒŋ', // 1FABF ]; + +export const EMOJIS_REQUIRING_INVERSION_IN_LIGHT_MODE = [ + 'â›“ī¸', // 26D3-FE0F +]; + +export const EMOJIS_REQUIRING_INVERSION_IN_DARK_MODE = [ + '🔜', // 1F51C + '🔙', // 1F519 + '🔛', // 1F51B + '🔝', // 1F51D + '🔚', // 1F51A + 'ÂŠī¸', // 00A9 FE0F + '➰', // 27B0 + '💱', // 1F4B1 + 'âœ”ī¸', // 2714 FE0F + '➗', // 2797 + '💲', // 1F4B2 + '➖', // 2796 + 'âœ–ī¸', // 2716 FE0F + '➕', // 2795 + 'ÂŽī¸', // 00AE FE0F + 'đŸ•ˇī¸', // 1F577 FE0F + '📞', // 1F4DE + 'â„ĸī¸', // 2122 FE0F + 'ã€°ī¸', // 3030 FE0F +]; diff --git a/app/javascript/flavours/glitch/features/emoji/emoji.js b/app/javascript/flavours/glitch/features/emoji/emoji.js index b282e46b4a..b7ea36d3df 100644 --- a/app/javascript/flavours/glitch/features/emoji/emoji.js +++ b/app/javascript/flavours/glitch/features/emoji/emoji.js @@ -1,5 +1,6 @@ import Trie from 'substring-trie'; +import { getUserTheme, isDarkMode } from '@/flavours/glitch/utils/theme'; import { assetHost } from 'flavours/glitch/utils/config'; import { autoPlayGif } from '../../initial_state'; @@ -97,9 +98,9 @@ const emojifyTextNode = (node, customEmojis) => { const { filename, shortCode } = unicodeMapping[unicode_emoji]; const title = shortCode ? `:${shortCode}:` : ''; - const isSystemTheme = !!document.body?.classList.contains('theme-system'); + const isSystemTheme = getUserTheme() === 'system'; - const theme = (isSystemTheme || document.body?.classList.contains('theme-mastodon-light')) ? 'light' : 'dark'; + const theme = (isSystemTheme || !isDarkMode()) ? 'light' : 'dark'; const imageFilename = emojiFilename(filename, theme); diff --git a/app/javascript/flavours/glitch/features/emoji/mode.ts b/app/javascript/flavours/glitch/features/emoji/mode.ts index 076954ecda..5b6dc882c7 100644 --- a/app/javascript/flavours/glitch/features/emoji/mode.ts +++ b/app/javascript/flavours/glitch/features/emoji/mode.ts @@ -3,6 +3,7 @@ import { createAppSelector, useAppSelector } from '@/flavours/glitch/store'; import { isDevelopment } from '@/flavours/glitch/utils/environment'; +import { isDarkMode } from '@/flavours/glitch/utils/theme'; import { EMOJI_MODE_NATIVE, @@ -27,7 +28,7 @@ export function useEmojiAppState(): EmojiAppState { currentLocale: locale, locales: [locale], mode, - darkTheme: document.body.classList.contains('theme-default'), + darkTheme: isDarkMode(), }; } diff --git a/app/javascript/flavours/glitch/features/emoji/normalize.ts b/app/javascript/flavours/glitch/features/emoji/normalize.ts index f0a502dcb5..4800352ffa 100644 --- a/app/javascript/flavours/glitch/features/emoji/normalize.ts +++ b/app/javascript/flavours/glitch/features/emoji/normalize.ts @@ -10,6 +10,8 @@ import { SKIN_TONE_CODES, EMOJIS_WITH_DARK_BORDER, EMOJIS_WITH_LIGHT_BORDER, + EMOJIS_REQUIRING_INVERSION_IN_LIGHT_MODE, + EMOJIS_REQUIRING_INVERSION_IN_DARK_MODE, } from './constants'; import type { CustomEmojiMapArg, ExtraCustomEmojiMap } from './types'; @@ -150,6 +152,16 @@ export function twemojiToUnicodeInfo( return hexNumbersToString(mappedCodes); } +export function emojiToInversionClassName(emoji: string): string | null { + if (EMOJIS_REQUIRING_INVERSION_IN_DARK_MODE.includes(emoji)) { + return 'invert-on-dark'; + } + if (EMOJIS_REQUIRING_INVERSION_IN_LIGHT_MODE.includes(emoji)) { + return 'invert-on-light'; + } + return null; +} + export function cleanExtraEmojis(extraEmojis?: CustomEmojiMapArg) { if (!extraEmojis) { return null; diff --git a/app/javascript/flavours/glitch/styles/application.scss b/app/javascript/flavours/glitch/styles/application.scss index a38653cf1c..cc23627a15 100644 --- a/app/javascript/flavours/glitch/styles/application.scss +++ b/app/javascript/flavours/glitch/styles/application.scss @@ -1,2 +1 @@ -@use 'mastodon/variables'; @use 'common'; diff --git a/app/javascript/flavours/glitch/styles/common.scss b/app/javascript/flavours/glitch/styles/common.scss index 05c8173e95..4d2352bc09 100644 --- a/app/javascript/flavours/glitch/styles/common.scss +++ b/app/javascript/flavours/glitch/styles/common.scss @@ -1,3 +1,4 @@ +@use 'mastodon/variables'; @use 'mastodon/mixins'; @use '@/styles/fonts/roboto'; @use '@/styles/fonts/roboto-mono'; diff --git a/app/javascript/flavours/glitch/styles/contrast.scss b/app/javascript/flavours/glitch/styles/contrast.scss index d89eaa610f..93bbfed080 100644 --- a/app/javascript/flavours/glitch/styles/contrast.scss +++ b/app/javascript/flavours/glitch/styles/contrast.scss @@ -1,3 +1,2 @@ -@use 'mastodon/variables'; @use 'common'; @use 'mastodon/high-contrast'; diff --git a/app/javascript/flavours/glitch/styles/mastodon-light.scss b/app/javascript/flavours/glitch/styles/mastodon-light.scss index 11a92fb873..cc23627a15 100644 --- a/app/javascript/flavours/glitch/styles/mastodon-light.scss +++ b/app/javascript/flavours/glitch/styles/mastodon-light.scss @@ -1,4 +1 @@ -@use 'mastodon/variables' with ( - $emojis-requiring-inversion: 'chains' -); @use 'common'; diff --git a/app/javascript/flavours/glitch/styles/mastodon/_variables.scss b/app/javascript/flavours/glitch/styles/mastodon/_variables.scss index a948dbc41c..d561f71454 100644 --- a/app/javascript/flavours/glitch/styles/mastodon/_variables.scss +++ b/app/javascript/flavours/glitch/styles/mastodon/_variables.scss @@ -20,8 +20,3 @@ $no-columns-breakpoint: 600px; $font-sans-serif: 'mastodon-font-sans-serif' !default; $font-display: 'mastodon-font-display' !default; $font-monospace: 'mastodon-font-monospace' !default; - -$emojis-requiring-inversion: 'back' 'copyright' 'curly_loop' 'currency_exchange' - 'end' 'heavy_check_mark' 'heavy_division_sign' 'heavy_dollar_sign' - 'heavy_minus_sign' 'heavy_multiplication_x' 'heavy_plus_sign' 'on' - 'registered' 'soon' 'spider' 'telephone_receiver' 'tm' 'top' 'wavy_dash' !default; diff --git a/app/javascript/flavours/glitch/styles/mastodon/accessibility.scss b/app/javascript/flavours/glitch/styles/mastodon/accessibility.scss index 42117ac20f..656da21833 100644 --- a/app/javascript/flavours/glitch/styles/mastodon/accessibility.scss +++ b/app/javascript/flavours/glitch/styles/mastodon/accessibility.scss @@ -1,17 +1,3 @@ -@use 'variables' as *; - -%emoji-color-inversion { - filter: invert(1); -} - -.emojione { - @each $emoji in $emojis-requiring-inversion { - &[title=':#{$emoji}:'] { - @extend %emoji-color-inversion; - } - } -} - // glitch-soc addition .hicolor-privacy-icons { .status__visibility-icon.icon-globe, diff --git a/app/javascript/flavours/glitch/styles/mastodon/theme/_utils.scss b/app/javascript/flavours/glitch/styles/mastodon/theme/_utils.scss index 1c03c2f65c..4c207c5094 100644 --- a/app/javascript/flavours/glitch/styles/mastodon/theme/_utils.scss +++ b/app/javascript/flavours/glitch/styles/mastodon/theme/_utils.scss @@ -1,3 +1,15 @@ @function css-alpha($base-color, $amount) { @return #{rgb(from $base-color r g b / $amount)}; } + +@mixin invert-on-light { + .invert-on-light { + filter: invert(1); + } +} + +@mixin invert-on-dark { + .invert-on-dark { + filter: invert(1); + } +} diff --git a/app/javascript/flavours/glitch/styles/mastodon/theme/index.scss b/app/javascript/flavours/glitch/styles/mastodon/theme/index.scss index d78b7e2a99..8e275e514a 100644 --- a/app/javascript/flavours/glitch/styles/mastodon/theme/index.scss +++ b/app/javascript/flavours/glitch/styles/mastodon/theme/index.scss @@ -1,6 +1,7 @@ @use 'base'; @use 'dark'; @use 'light'; +@use 'utils'; html { @include base.palette; @@ -10,6 +11,7 @@ html { @media (prefers-color-scheme: dark) { @include dark.tokens; + @include utils.invert-on-dark; @media (prefers-contrast: more) { @include dark.contrast-overrides; @@ -18,6 +20,7 @@ html { @media (prefers-color-scheme: light) { @include light.tokens; + @include utils.invert-on-light; @media (prefers-contrast: more) { @include light.contrast-overrides; @@ -33,6 +36,7 @@ html:where( color-scheme: dark; @include dark.tokens; + @include utils.invert-on-dark; } html[data-user-theme='contrast'], @@ -45,4 +49,5 @@ html:where([data-user-theme='mastodon-light']) { color-scheme: light; @include light.tokens; + @include utils.invert-on-light; } diff --git a/app/javascript/flavours/glitch/utils/theme.ts b/app/javascript/flavours/glitch/utils/theme.ts new file mode 100644 index 0000000000..767d97cf5c --- /dev/null +++ b/app/javascript/flavours/glitch/utils/theme.ts @@ -0,0 +1,13 @@ +export function getUserTheme() { + const { userTheme } = document.documentElement.dataset; + return userTheme; +} + +export function isDarkMode() { + const { userTheme } = document.documentElement.dataset; + return ( + (userTheme === 'system' && + window.matchMedia('(prefers-color-scheme: dark)').matches) || + userTheme !== 'mastodon-light' + ); +}