pl-fe: display animated emojis on hover unless specified otherwise
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
a6deb34558
commit
7c3cb6a6eb
5 changed files with 29 additions and 9 deletions
|
@ -45,7 +45,7 @@ const SidebarNavigationLink = React.forwardRef((props: ISidebarNavigationLink, r
|
||||||
ref={ref}
|
ref={ref}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
className={clsx({
|
className={clsx({
|
||||||
'flex items-center py-2 text-sm font-semibold space-x-4 rtl:space-x-reverse transition-colors duration-200': true,
|
'group flex items-center py-2 text-sm font-semibold space-x-4 rtl:space-x-reverse transition-colors duration-200': true,
|
||||||
'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200': !isActive,
|
'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200': !isActive,
|
||||||
'text-gray-900 dark:text-white': isActive,
|
'text-gray-900 dark:text-white': isActive,
|
||||||
})}
|
})}
|
||||||
|
@ -53,7 +53,7 @@ const SidebarNavigationLink = React.forwardRef((props: ISidebarNavigationLink, r
|
||||||
<span
|
<span
|
||||||
className={clsx({
|
className={clsx({
|
||||||
'relative rounded-lg inline-flex p-2.5 transition-colors duration-200': true,
|
'relative rounded-lg inline-flex p-2.5 transition-colors duration-200': true,
|
||||||
'bg-primary-50 hover:bg-primary-100 dark:bg-slate-700 dark:hover:bg-slate-600 black:bg-gray-900 black:hover:bg-gray-800': !isActive,
|
'bg-primary-50 group-hover:bg-primary-100 dark:bg-slate-700 dark:group-hover:bg-slate-600 black:bg-gray-900 black:group-hover:bg-gray-800': !isActive,
|
||||||
'bg-primary-600': isActive,
|
'bg-primary-600': isActive,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
|
|
@ -59,7 +59,7 @@ const StatusReaction: React.FC<IStatusReaction> = ({ reaction, status, obfuscate
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className={clsx('flex cursor-pointer items-center gap-2 rounded-md border border-gray-400 p-1.5 transition-colors', {
|
className={clsx('group flex cursor-pointer items-center gap-2 rounded-md border border-gray-400 p-1.5 transition-colors', {
|
||||||
'bg-primary-100 dark:border-primary-400 dark:bg-primary-400 black:border-primary-600 black:bg-primary-600': reaction.me,
|
'bg-primary-100 dark:border-primary-400 dark:bg-primary-400 black:border-primary-600 black:bg-primary-600': reaction.me,
|
||||||
'bg-transparent dark:border-primary-700 dark:bg-primary-700 black:border-primary-800 black:bg-primary-800': !reaction.me,
|
'bg-transparent dark:border-primary-700 dark:bg-primary-700 black:border-primary-800 black:bg-primary-800': !reaction.me,
|
||||||
'cursor-pointer': !disabled,
|
'cursor-pointer': !disabled,
|
||||||
|
|
|
@ -18,17 +18,23 @@ interface IStillImage {
|
||||||
showExt?: boolean;
|
showExt?: boolean;
|
||||||
/** Callback function if the image fails to load */
|
/** Callback function if the image fails to load */
|
||||||
onError?(): void;
|
onError?(): void;
|
||||||
|
/** Treat as animated, no matter the extension */
|
||||||
|
isGif?: boolean;
|
||||||
|
/** Specify that the group is defined by the parent */
|
||||||
|
noGroup?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Renders images on a canvas, only playing GIFs if autoPlayGif is enabled. */
|
/** Renders images on a canvas, only playing GIFs if autoPlayGif is enabled. */
|
||||||
const StillImage: React.FC<IStillImage> = ({ alt, className, src, style, letterboxed = false, showExt = false, onError }) => {
|
const StillImage: React.FC<IStillImage> = ({
|
||||||
|
alt, className, src, style, letterboxed = false, showExt = false, onError, isGif, noGroup,
|
||||||
|
}) => {
|
||||||
const { autoPlayGif } = useSettings();
|
const { autoPlayGif } = useSettings();
|
||||||
|
|
||||||
const canvas = useRef<HTMLCanvasElement>(null);
|
const canvas = useRef<HTMLCanvasElement>(null);
|
||||||
const img = useRef<HTMLImageElement>(null);
|
const img = useRef<HTMLImageElement>(null);
|
||||||
|
|
||||||
const hoverToPlay = (
|
const hoverToPlay = (
|
||||||
src && !autoPlayGif && (src.endsWith('.gif') || src.startsWith('blob:'))
|
src && !autoPlayGif && (isGif || src.endsWith('.gif') || src.startsWith('blob:'))
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleImageLoad = () => {
|
const handleImageLoad = () => {
|
||||||
|
@ -48,7 +54,7 @@ const StillImage: React.FC<IStillImage> = ({ alt, className, src, style, letterb
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-testid='still-image-container'
|
data-testid='still-image-container'
|
||||||
className={clsx(className, 'group relative isolate overflow-hidden')}
|
className={clsx(className, 'relative isolate overflow-hidden', { 'group': !noGroup })}
|
||||||
style={style}
|
style={style}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import StillImage from 'pl-fe/components/still-image';
|
||||||
import { removeVS16s, toCodePoints } from 'pl-fe/utils/emoji';
|
import { removeVS16s, toCodePoints } from 'pl-fe/utils/emoji';
|
||||||
import { joinPublicPath } from 'pl-fe/utils/static';
|
import { joinPublicPath } from 'pl-fe/utils/static';
|
||||||
|
|
||||||
interface IEmoji extends React.ImgHTMLAttributes<HTMLImageElement> {
|
interface IEmoji extends Pick<React.ImgHTMLAttributes<HTMLImageElement>, 'alt' | 'className' | 'src' | 'title'> {
|
||||||
/** Unicode emoji character. */
|
/** Unicode emoji character. */
|
||||||
emoji?: string;
|
emoji?: string;
|
||||||
|
noGroup?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A single emoji image. */
|
/** A single emoji image. */
|
||||||
const Emoji: React.FC<IEmoji> = (props): JSX.Element | null => {
|
const Emoji: React.FC<IEmoji> = (props): JSX.Element | null => {
|
||||||
const { emoji, alt, src, ...rest } = props;
|
const { emoji, alt, src, noGroup, ...rest } = props;
|
||||||
|
|
||||||
let filename;
|
let filename;
|
||||||
|
|
||||||
|
@ -21,6 +23,18 @@ const Emoji: React.FC<IEmoji> = (props): JSX.Element | null => {
|
||||||
|
|
||||||
if (!filename && !src) return null;
|
if (!filename && !src) return null;
|
||||||
|
|
||||||
|
if (src) {
|
||||||
|
return (
|
||||||
|
<StillImage
|
||||||
|
alt={alt || emoji}
|
||||||
|
src={src}
|
||||||
|
isGif
|
||||||
|
noGroup={noGroup}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
draggable='false'
|
draggable='false'
|
||||||
|
|
|
@ -58,7 +58,7 @@ const EmojiPicker: React.FC<IEmojiPicker> = ({ emoji, emojiUrl, ...props }) => {
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
{emoji
|
{emoji
|
||||||
? <Emoji height={20} width={20} emoji={emoji} />
|
? <Emoji className='h-5 w-5' emoji={emoji} src={emojiUrl} />
|
||||||
: <Icon className='h-5 w-5 text-gray-600 hover:text-gray-700 dark:hover:text-gray-500' src={require('@tabler/icons/outline/mood-happy.svg')} />}
|
: <Icon className='h-5 w-5 text-gray-600 hover:text-gray-700 dark:hover:text-gray-500' src={require('@tabler/icons/outline/mood-happy.svg')} />}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue