diff --git a/src/components/comment/CommentAvatar/index.tsx b/src/components/comment/CommentAvatar/index.tsx index e12da6ef..a3142b91 100644 --- a/src/components/comment/CommentAvatar/index.tsx +++ b/src/components/comment/CommentAvatar/index.tsx @@ -3,60 +3,26 @@ import React, { FC, useCallback, useState } from 'react'; import { Manager, Popper, Reference } from 'react-popper'; import { Avatar } from '~/components/common/Avatar'; -import { useRandomPhrase } from '~/constants/phrases'; +import { MenuButton } from '~/components/menu'; +import { ProfileQuickInfo } from '~/containers/profile/ProfileQuickInfo'; import { IUser } from '~/types/auth'; import { path } from '~/utils/ramda'; -import styles from './styles.module.scss'; - interface Props { user: IUser; - withDetails: boolean; className?: string; } -const modifiers = [ - { - name: 'offset', - options: { - offset: [0, 10], - }, - }, -]; - -const CommentAvatar: FC = ({ user, withDetails, className }) => { - const [hovered, setHovered] = useState(false); - const randomPhrase = useRandomPhrase('USER_DESCRIPTION'); - - const onMouseOver = useCallback(() => setHovered(true), [setHovered]); - const onMouseOut = useCallback(() => setHovered(false), [setHovered]); - +const CommentAvatar: FC = ({ user, className }) => { return ( - - - {({ ref }) => ( - - )} - - - {hovered && withDetails && ( - - {({ style, ref }) => ( -
-

{user.fullname || user.username}

-
{user.description || randomPhrase}
-
- )} -
- )} -
+ + } + > + + ); }; diff --git a/src/components/common/Avatar/index.tsx b/src/components/common/Avatar/index.tsx index ca7e8b30..4cde455d 100644 --- a/src/components/common/Avatar/index.tsx +++ b/src/components/common/Avatar/index.tsx @@ -19,14 +19,11 @@ interface Props extends DivProps { const Avatar = forwardRef( ({ url, username, size, className, preset = ImagePresets.avatar, ...rest }, ref) => { - const onOpenProfile = useCallback(() => openUserProfile(username), [username]); - return ( diff --git a/src/components/containers/CommentWrapper/index.tsx b/src/components/containers/CommentWrapper/index.tsx index ee7d9005..b9aebf05 100644 --- a/src/components/containers/CommentWrapper/index.tsx +++ b/src/components/containers/CommentWrapper/index.tsx @@ -36,7 +36,7 @@ const CommentWrapper: FC = ({ {...props} >
- +
~{path(['username'], user)}
diff --git a/src/components/menu/MenuButton/index.tsx b/src/components/menu/MenuButton/index.tsx index 1a4e5421..c8cad64e 100644 --- a/src/components/menu/MenuButton/index.tsx +++ b/src/components/menu/MenuButton/index.tsx @@ -9,6 +9,7 @@ import { useFocusEvent } from '~/hooks/dom/useFocusEvent'; import styles from './styles.module.scss'; interface MenuButtonProps { + position?: 'top-end' | 'bottom-end' | 'top-start' | 'bottom-start' | 'top' | 'bottom'; icon?: ReactNode; className?: string; } @@ -23,11 +24,12 @@ const modifiers = [ ]; const MenuButton: FC = ({ + position = 'bottom-end', children, className, icon = , }) => { - const { focused, onFocus, onBlur } = useFocusEvent(false, 150); + const { focused, onFocus, onBlur } = useFocusEvent(true, 150); return ( @@ -45,13 +47,9 @@ const MenuButton: FC = ({ {focused && ( - + {({ style, ref, placement }) => ( -
+
{children}
)} diff --git a/src/components/menu/MenuButton/styles.module.scss b/src/components/menu/MenuButton/styles.module.scss index 66e733a1..e5085d60 100644 --- a/src/components/menu/MenuButton/styles.module.scss +++ b/src/components/menu/MenuButton/styles.module.scss @@ -31,10 +31,29 @@ right: 10px; } - &.top::after { + &.top-end::after { border-width: 10px 10px 0 10px; border-color: darken($menu_bg, 8%) transparent transparent transparent; top: auto; bottom: -11px; } + + &.top-start::after { + border-width: 10px 10px 0 10px; + border-color: darken($menu_bg, 8%) transparent transparent transparent; + top: auto; + bottom: -11px; + right: auto; + left: 10px; + } + + &.top::after { + border-width: 10px 10px 0 10px; + border-color: darken($menu_bg, 8%) transparent transparent transparent; + top: auto; + bottom: -11px; + right: auto; + left: 50%; + margin-left: -10px; + } } diff --git a/src/containers/profile/ProfileQuickInfo/index.tsx b/src/containers/profile/ProfileQuickInfo/index.tsx new file mode 100644 index 00000000..6f106061 --- /dev/null +++ b/src/containers/profile/ProfileQuickInfo/index.tsx @@ -0,0 +1,42 @@ +import React, { FC, useMemo } from 'react'; + +import { Avatar } from '~/components/common/Avatar'; +import { Filler } from '~/components/containers/Filler'; +import { Group } from '~/components/containers/Group'; +import { useRandomPhrase } from '~/constants/phrases'; +import { useColorGradientFromString } from '~/hooks/color/useColorGradientFromString'; +import { IUser } from '~/types/auth'; +import { generateGradientFromColor } from '~/utils/color'; +import { path } from '~/utils/ramda'; + +import styles from './styles.module.scss'; + +interface ProfileQuickInfoProps { + user: IUser; +} + +const ProfileQuickInfo: FC = ({ user }) => { + const style = useMemo(() => { + const color = user.photo?.metadata?.dominant_color; + const gradient = color && generateGradientFromColor(color); + + return gradient ? { background: gradient } : undefined; + }, [user]); + + return ( + + +
+ +
+ + +
{user.fullname || user.username}
+
~{user.username}
+
+
+
+ ); +}; + +export { ProfileQuickInfo }; diff --git a/src/containers/profile/ProfileQuickInfo/styles.module.scss b/src/containers/profile/ProfileQuickInfo/styles.module.scss new file mode 100644 index 00000000..b4b88585 --- /dev/null +++ b/src/containers/profile/ProfileQuickInfo/styles.module.scss @@ -0,0 +1,28 @@ +@import "src/styles/variables"; + +.wrapper { + @include outer_shadow; + + padding: $gap $gap * 2 $gap $gap; + border-radius: $radius; + min-width: 240px; +} + +div.info { + font: $font_12_regular; + opacity: 0.5; +} + +div.top.top { + align-items: flex-start; + justify-content: flex-start; +} + +.username { + font: $font_12_regular; + opacity: 0.5; +} + +.fullname { + margin-bottom: 3px; +} diff --git a/src/hooks/color/useColorGradientFromString.ts b/src/hooks/color/useColorGradientFromString.ts index bbc0fb49..daa35deb 100644 --- a/src/hooks/color/useColorGradientFromString.ts +++ b/src/hooks/color/useColorGradientFromString.ts @@ -2,7 +2,7 @@ import { useMemo } from 'react'; import { adjustHue } from 'color2k'; -import { normalizeBrightColor } from '~/utils/color'; +import { generateGradientFromColor, normalizeBrightColor } from '~/utils/color'; import { stringToColour } from '~/utils/dom'; export const useColorGradientFromString = ( @@ -16,9 +16,5 @@ export const useColorGradientFromString = ( return ''; } - const color = normalizeBrightColor(stringToColour(val), saturation, lightness); - const second = normalizeBrightColor(adjustHue(color, 45), saturation, lightness); - const third = normalizeBrightColor(adjustHue(color, 90), saturation, lightness); - - return `linear-gradient(${angle}deg, ${color}, ${second}, ${third})`; + return generateGradientFromColor(val, saturation, lightness, angle); }, [angle, lightness, saturation, val]); diff --git a/src/utils/color.ts b/src/utils/color.ts index 4a92b0ca..8169de88 100644 --- a/src/utils/color.ts +++ b/src/utils/color.ts @@ -1,6 +1,7 @@ -import { darken, desaturate, parseToHsla } from 'color2k'; +import { adjustHue, darken, desaturate, parseToHsla } from 'color2k'; import { DEFAULT_DOMINANT_COLOR } from '~/constants/node'; +import { stringToColour } from '~/utils/dom'; export const normalizeBrightColor = (color?: string, saturationExp = 3, lightnessExp = 3) => { if (!color) { @@ -14,3 +15,23 @@ export const normalizeBrightColor = (color?: string, saturationExp = 3, lightnes const desaturated = saturationExp > 1 ? desaturate(color, saturation ** saturationExp) : color; return lightnessExp > 1 ? darken(desaturated, lightness ** lightnessExp) : desaturated; }; + +export const generateColorTriplet = (val: string, saturation: number, lightness: number) => { + const color = normalizeBrightColor(stringToColour(val), saturation, lightness); + + return [ + color, + normalizeBrightColor(adjustHue(color, 45), saturation, lightness), + normalizeBrightColor(adjustHue(color, 90), saturation, lightness), + ]; +}; + +export const generateGradientFromColor = ( + val: string, + saturation = 3, + lightness = 3, + angle = 155 +) => { + const [color, second, third] = generateColorTriplet(val, saturation, lightness); + return `linear-gradient(${angle}deg, ${color}, ${second}, ${third})`; +};