diff --git a/.changeset/restore-old-chip-style.md b/.changeset/restore-old-chip-style.md new file mode 100644 index 000000000..9a4413884 --- /dev/null +++ b/.changeset/restore-old-chip-style.md @@ -0,0 +1,5 @@ +--- +default: patch +--- + +Various small adjustments to the themed profiles for better consistency. diff --git a/src/app/components/user-profile/CreatorChip.tsx b/src/app/components/user-profile/CreatorChip.tsx index 1e5bf84dc..29ccbaafb 100644 --- a/src/app/components/user-profile/CreatorChip.tsx +++ b/src/app/components/user-profile/CreatorChip.tsx @@ -1,5 +1,6 @@ import type { RectCords } from 'folds'; import { Chip, config, Icon, Icons, Menu, MenuItem, PopOut, Text } from 'folds'; +import type { CSSProperties } from 'react'; import type { MouseEventHandler } from 'react'; import { useState } from 'react'; import FocusTrap from 'focus-trap-react'; @@ -16,19 +17,25 @@ import { useOpenSpaceSettings } from '$state/hooks/spaceSettings'; import { SpaceSettingsPage } from '$state/spaceSettings'; import { RoomSettingsPage } from '$state/roomSettings'; import { PowerColorBadge, PowerIcon } from '$components/power'; +import { heroMenuItemStyle } from './heroMenuItemStyle'; import * as css from './styles.css'; export function CreatorChip({ - backgroundColor, innerColor, cardColor, textColor, + chipSurfaceStyle, + chipFillColor, + chipHoverBrightness, }: { - backgroundColor?: string; innerColor?: string; cardColor?: string; textColor?: string; + chipSurfaceStyle?: CSSProperties; + chipFillColor?: string; + chipHoverBrightness?: number; }) { + const menuItemBg = chipFillColor ?? cardColor; const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const room = useRoom(); @@ -69,7 +76,10 @@ export function CreatorChip({ variant="Surface" fill="None" className={css.UserHeroMenuItem} - style={{ backgroundColor: cardColor, color: textColor }} + style={heroMenuItemStyle( + { backgroundColor: menuItemBg, color: textColor }, + chipHoverBrightness + )} size="300" radii="300" onClick={() => { @@ -93,6 +103,8 @@ export function CreatorChip({ } > : undefined} onClick={open} aria-pressed={!!cords} - className={css.UserHeroChip} - style={{ - backgroundColor: cardColor, - borderColor: backgroundColor, - color: textColor, - }} + className={cardColor ? css.UserHeroChipThemed : css.UserHeroBrightnessHover} + style={heroMenuItemStyle( + cardColor && chipSurfaceStyle ? chipSurfaceStyle : {}, + chipHoverBrightness + )} > {tag.name} diff --git a/src/app/components/user-profile/PowerChip.tsx b/src/app/components/user-profile/PowerChip.tsx index 58a54bd19..dbb6ae579 100644 --- a/src/app/components/user-profile/PowerChip.tsx +++ b/src/app/components/user-profile/PowerChip.tsx @@ -20,6 +20,7 @@ import { Text, toRem, } from 'folds'; +import type { CSSProperties } from 'react'; import type { MouseEventHandler } from 'react'; import { useCallback, useState } from 'react'; import FocusTrap from 'focus-trap-react'; @@ -45,6 +46,7 @@ import { useMemberPowerCompare } from '$hooks/useMemberPowerCompare'; import { CutoutCard } from '$components/cutout-card'; import { PowerColorBadge, PowerIcon } from '$components/power'; import { EventType } from '$types/matrix-sdk'; +import { heroMenuItemStyle } from './heroMenuItemStyle'; import * as css from './styles.css'; type SelfDemoteAlertProps = { @@ -149,17 +151,22 @@ function SharedPowerAlert({ power, onCancel, onChange }: SharedPowerAlertProps) export function PowerChip({ userId, - backgroundColor, innerColor, cardColor, textColor, + chipSurfaceStyle, + chipFillColor, + chipHoverBrightness, }: { userId: string; - backgroundColor?: string; innerColor?: string; cardColor?: string; textColor?: string; + chipSurfaceStyle?: CSSProperties; + chipFillColor?: string; + chipHoverBrightness?: number; }) { + const menuItemBg = chipFillColor ?? cardColor; const mx = useMatrixClient(); const room = useRoom(); const space = useSpaceOptionally(); @@ -288,7 +295,10 @@ export function PowerChip({ aria-disabled={changing || !canChangePowers || !canAssignPower} aria-pressed={selected} className={css.UserHeroMenuItem} - style={{ backgroundColor: cardColor, color: textColor }} + style={heroMenuItemStyle( + { backgroundColor: menuItemBg, color: textColor }, + chipHoverBrightness + )} before={} after={ powerTagIconSrc ? ( @@ -314,7 +324,10 @@ export function PowerChip({ size="300" radii="300" className={css.UserHeroMenuItem} - style={{ backgroundColor: cardColor, color: textColor }} + style={heroMenuItemStyle( + { backgroundColor: menuItemBg, color: textColor }, + chipHoverBrightness + )} onClick={() => { if (room.isSpaceRoom()) { openSpaceSettings( @@ -340,14 +353,19 @@ export function PowerChip({ } > diff --git a/src/app/components/user-profile/UserChips.tsx b/src/app/components/user-profile/UserChips.tsx index c57532dd6..168a973e5 100644 --- a/src/app/components/user-profile/UserChips.tsx +++ b/src/app/components/user-profile/UserChips.tsx @@ -1,4 +1,5 @@ import type { KeyboardEventHandler, MouseEventHandler } from 'react'; +import type { CSSProperties } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import FocusTrap from 'focus-trap-react'; @@ -22,6 +23,7 @@ import { Avatar, } from 'folds'; import { useMatrixClient } from '$hooks/useMatrixClient'; +import { getMxIdServer } from '$utils/mxIdHelper'; import { useCloseUserRoomProfile } from '$state/hooks/userRoomProfile'; import { stopPropagation } from '$utils/keyboard'; import { copyToClipboard } from '$utils/dom'; @@ -42,6 +44,7 @@ import { useNickname, useSetNickname } from '$hooks/useNickname'; import { CutoutCard } from '$components/cutout-card'; import { SettingTile } from '$components/setting-tile'; import { RoomAvatar, RoomIcon } from '$components/room-avatar'; +import { heroMenuItemStyle } from './heroMenuItemStyle'; import * as css from './styles.css'; export function ServerChip({ @@ -49,14 +52,21 @@ export function ServerChip({ innerColor, cardColor, textColor, - backgroundColor, + chipSurfaceStyle, + chipFillColor, + chipHoverBrightness, }: { server: string; innerColor?: string; cardColor?: string; textColor?: string; - backgroundColor?: string; + chipSurfaceStyle?: CSSProperties; + chipFillColor?: string; + chipHoverBrightness?: number; }) { + const menuItemBg = chipFillColor ?? cardColor; + const mx = useMatrixClient(); + const myServer = getMxIdServer(mx.getSafeUserId()); const navigate = useNavigate(); const closeProfile = useCloseUserRoomProfile(); const [copied, setCopied] = useTimeoutToggle(); @@ -89,71 +99,89 @@ export function ServerChip({ - { - copyToClipboard(server); - setCopied(); - close(); - }} - className={css.UserHeroMenuItem} - style={{ - backgroundColor: cardColor, - color: textColor, - }} - > - Copy Server - - { - navigate(getExploreServerPath(server)); - closeProfile(); - }} - className={css.UserHeroMenuItem} - style={{ - backgroundColor: cardColor, - color: textColor, - }} - > - Explore Community - + + { + copyToClipboard(server); + setCopied(); + close(); + }} + className={css.UserHeroMenuItem} + style={heroMenuItemStyle( + { + backgroundColor: menuItemBg, + color: textColor, + }, + chipHoverBrightness + )} + > + Copy Server + + { + navigate(getExploreServerPath(server)); + closeProfile(); + }} + className={css.UserHeroMenuItem} + style={heroMenuItemStyle( + { + backgroundColor: menuItemBg, + color: textColor, + }, + chipHoverBrightness + )} + > + Explore Community + + - { - window.open(`https://${server}`, '_blank'); - close(); - }} - className={css.UserHeroMenuItem} - style={{ - backgroundColor: cardColor, - color: textColor, - }} - > - Open in Browser - + + { + window.open(`https://${server}`, '_blank'); + close(); + }} + className={css.UserHeroMenuItem} + style={heroMenuItemStyle( + { + backgroundColor: menuItemBg, + color: textColor, + }, + chipHoverBrightness + )} + > + Open in Browser + + } > {server} @@ -184,14 +211,19 @@ export function ShareChip({ innerColor, cardColor, textColor, - backgroundColor, + chipSurfaceStyle, + chipFillColor, + chipHoverBrightness, }: { userId: string; innerColor?: string; cardColor?: string; textColor?: string; - backgroundColor?: string; + chipSurfaceStyle?: CSSProperties; + chipFillColor?: string; + chipHoverBrightness?: number; }) { + const menuItemBg = chipFillColor ?? cardColor; const [cords, setCords] = useState(); const [copied, setCopied] = useTimeoutToggle(); @@ -220,48 +252,56 @@ export function ShareChip({ }} > - - { - copyToClipboard(userId); - setCopied(); - close(); - }} - > - Copy User ID - - { - copyToClipboard(getMatrixToUser(userId)); - setCopied(); - close(); - }} - > - Copy User Link - + + + { + copyToClipboard(userId); + setCopied(); + close(); + }} + > + Copy User ID + + { + copyToClipboard(getMatrixToUser(userId)); + setCopied(); + close(); + }} + > + Copy User Link + + } > Share @@ -295,17 +334,22 @@ type MutualRoomsData = { export function MutualRoomsChip({ userId, - backgroundColor, innerColor, cardColor, textColor, + chipSurfaceStyle, + chipFillColor, + chipHoverBrightness, }: { userId: string; - backgroundColor?: string; innerColor?: string; cardColor?: string; textColor?: string; + chipSurfaceStyle?: CSSProperties; + chipFillColor?: string; + chipHoverBrightness?: number; }) { + const menuItemBg = chipFillColor ?? cardColor; const mx = useMatrixClient(); const mutualRoomSupported = useMutualRoomsSupport(); const mutualRoomsState = useMutualRooms(userId); @@ -372,11 +416,14 @@ export function MutualRoomsChip({ size="300" radii="300" className={css.UserHeroMenuItem} - style={{ - paddingLeft: config.space.S100, - backgroundColor: cardColor, - color: textColor, - }} + style={heroMenuItemStyle( + { + paddingLeft: config.space.S100, + backgroundColor: menuItemBg, + color: textColor, + }, + chipHoverBrightness + )} onClick={() => { if (room.isSpaceRoom()) { navigateSpace(roomId); @@ -486,6 +533,7 @@ export function MutualRoomsChip({ } > } disabled={ @@ -493,12 +541,11 @@ export function MutualRoomsChip({ } onClick={open} aria-pressed={!!cords} - className={css.UserHeroChip} - style={{ - backgroundColor: cardColor, - borderColor: backgroundColor, - color: textColor, - }} + className={cardColor ? css.UserHeroChipThemed : css.UserHeroBrightnessHover} + style={heroMenuItemStyle( + cardColor && chipSurfaceStyle ? chipSurfaceStyle : {}, + chipHoverBrightness + )} > {mutualRoomsState.status === AsyncStatus.Success && @@ -529,17 +576,22 @@ export function IgnoredUserAlert() { export function OptionsChip({ userId, - backgroundColor, innerColor, cardColor, textColor, + chipSurfaceStyle, + chipFillColor, + chipHoverBrightness, }: { userId: string; - backgroundColor?: string; innerColor?: string; cardColor?: string; textColor?: string; + chipSurfaceStyle?: CSSProperties; + chipFillColor?: string; + chipHoverBrightness?: number; }) { + const menuItemBg = chipFillColor ?? cardColor; const mx = useMatrixClient(); const [cords, setCords] = useState(); const [editingNick, setEditingNick] = useState(false); @@ -604,122 +656,129 @@ export function OptionsChip({ }} > - - {editingNick ? ( - - Nickname - - - + + {editingNick ? ( + + Nickname + - Save - - {currentNick && ( + /> + { - setNickname(userId, undefined); - close(); - }} - style={{ - backgroundColor: cardColor, - color: textColor, - }} + style={heroMenuItemStyle( + { + backgroundColor: menuItemBg, + color: textColor, + }, + chipHoverBrightness + )} > - Clear + Save - )} + {currentNick && ( + { + setNickname(userId, undefined); + close(); + }} + style={heroMenuItemStyle( + { + backgroundColor: menuItemBg, + color: textColor, + }, + chipHoverBrightness + )} + > + Clear + + )} + - - ) : ( + ) : ( + } + onClick={() => setEditingNick(true)} + className={css.UserHeroMenuItem} + style={heroMenuItemStyle( + { + backgroundColor: menuItemBg, + color: textColor, + }, + chipHoverBrightness + )} + > + {currentNick ? 'Edit Nickname' : 'Set Nickname'} + + )} } - onClick={() => setEditingNick(true)} - className={css.UserHeroMenuItem} - style={{ - backgroundColor: cardColor, - color: textColor, + onClick={() => { + toggleIgnore(); + close(); }} + className={css.UserHeroMenuItem} + style={heroMenuItemStyle({ backgroundColor: menuItemBg }, chipHoverBrightness)} + before={ + ignoring ? ( + + ) : ( + + ) + } + disabled={ignoring} > - {currentNick ? 'Edit Nickname' : 'Set Nickname'} + + {ignored ? 'Unblock User' : 'Block User'} + - )} - { - toggleIgnore(); - close(); - }} - className={css.UserHeroMenuItem} - style={{ backgroundColor: cardColor }} - before={ - ignoring ? ( - - ) : ( - - ) - } - disabled={ignoring} - > - - {ignored ? 'Unblock User' : 'Block User'} - - + } > {ignoring ? ( diff --git a/src/app/components/user-profile/UserHero.tsx b/src/app/components/user-profile/UserHero.tsx index f284296b2..746a5d1e3 100644 --- a/src/app/components/user-profile/UserHero.tsx +++ b/src/app/components/user-profile/UserHero.tsx @@ -1,4 +1,5 @@ import { useMemo, useState } from 'react'; +import type { CSSProperties } from 'react'; import { Avatar, Box, @@ -78,10 +79,14 @@ export function UserHero({ userId, avatarUrl, bannerUrl, presence, autoplayGifs const isBackgroundDark = fetchedBrightness ? fetchedBrightness === 'dark' : undefined; const cardColor = shadeColor(backgroundColor, isBackgroundDark ? -80 : 80) ?? standardColors.Background.Container; + const innerColor = shadeColor(backgroundColor, isBackgroundDark ? -50 : 50) ?? backgroundColor; + const statusSurfaceColor = + shadeColor(innerColor, fetchedBrightness === 'light' ? -14 : 32) ?? cardColor; const textColor = ((fetchedBrightness === 'dark' || areColorsTooSimilar('#000000', cardColor)) && '#FFFFFF') || ((fetchedBrightness === 'light' || areColorsTooSimilar('#FFFFFF', cardColor)) && '#000000') || undefined; + const statusHoverBrightness = fetchedBrightness === 'light' ? 0.94 : 1.08; return ( @@ -153,16 +158,29 @@ export function UserHero({ userId, avatarUrl, bannerUrl, presence, autoplayGifs {status && status.length > 0 && ( setIsFullStatus(!isFullStatus) : undefined} - className={css.UserHeroStatusTooltip} + className={classNames( + css.UserHeroStatusTooltip, + isExpandable && css.UserHeroStatusTooltipInteractive + )} style={{ maxHeight: isFullStatus ? toRem(105) : toRem(48), cursor: isExpandable ? 'pointer' : 'default', transform: 'none', transition: 'none', display: 'flex', - backgroundColor: cardColor, + padding: `${toRem(8)} ${toRem(12)}`, + backgroundColor: statusSurfaceColor, color: textColor, + borderStyle: 'none', + borderWidth: 0, + outline: 'none', + boxShadow: 'inset 0 1px 1px rgba(0, 0, 0, 0.05)', + ...({ + '--user-hero-status-hover-brightness': String(statusHoverBrightness), + } as CSSProperties), }} > diff --git a/src/app/components/user-profile/UserRoomProfile.tsx b/src/app/components/user-profile/UserRoomProfile.tsx index 59ca01b3e..8541d3a68 100644 --- a/src/app/components/user-profile/UserRoomProfile.tsx +++ b/src/app/components/user-profile/UserRoomProfile.tsx @@ -11,7 +11,7 @@ import { Text, toRem, } from 'folds'; -import type { SyntheticEvent } from 'react'; +import type { CSSProperties, SyntheticEvent } from 'react'; import { useCallback, useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useAtomValue } from 'jotai'; @@ -52,6 +52,8 @@ import { useSettingsLinkBaseUrl } from '$features/settings/useSettingsLinkBaseUr import { getMxIdServer } from '$utils/mxIdHelper'; import { TextViewerContent } from '$components/text-viewer'; import { areColorsTooSimilar, shadeColor } from '$utils/shadeColor'; +import { ThemeKind, useTheme } from '$hooks/useTheme'; +import { heroMenuItemStyle } from './heroMenuItemStyle'; import { CreatorChip } from './CreatorChip'; import { UserInviteAlert, UserBanAlert, UserModeration, UserKickAlert } from './UserModeration'; import { PowerChip } from './PowerChip'; @@ -80,7 +82,6 @@ type UserExtendedSectionProps = { profile: UserProfile; htmlReactParserOptions: HTMLReactParserOptions; linkifyOpts: LinkifyOpts; - backgroundColor?: string; innerColor?: string; cardColor?: string; textColor?: string; @@ -97,7 +98,6 @@ function UserExtendedSection({ profile, htmlReactParserOptions, linkifyOpts, - backgroundColor, innerColor, cardColor, textColor, @@ -228,9 +228,9 @@ function UserExtendedSection({ () => ( setShowMisc(!showMisc)} after={miscDataIndex === -1 && } style={{ @@ -293,9 +293,7 @@ function UserExtendedSection({ style={{ backgroundColor: cardColor, borderRadius: config.radii.R400, - borderColor: backgroundColor, - borderStyle: 'solid', - borderWidth: '1px', + boxShadow: 'inset 0 1px 2px rgba(0, 0, 0, 0.1)', maxHeight: '200px', marginTop: config.space.S0, overflowY: 'auto', @@ -326,11 +324,10 @@ function UserExtendedSection({ {miscDataIndex > -1 && ( setMiscDataIndex( miscDataIndex === 0 ? unknownFields.length - 1 : miscDataIndex - 1 @@ -360,6 +358,7 @@ function UserExtendedSection({ setMiscDataIndex((miscDataIndex + 1) % unknownFields.length)} style={{ color: textColor }} > @@ -370,17 +369,22 @@ function UserExtendedSection({ ; }; export function UserRoomProfile({ userId, initialProfile }: Readonly) { + const theme = useTheme(); const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const navigate = useNavigate(); @@ -515,6 +520,43 @@ export function UserRoomProfile({ userId, initialProfile }: Readonly @@ -558,13 +598,11 @@ export function UserRoomProfile({ userId, initialProfile }: Readonly} onClick={handleMessage} - className={css.UserHeroChip} + className={showCustomHeroCard ? css.UserHeroChipThemed : css.UserHeroChip} style={{ marginLeft: 'auto', - backgroundColor: - backgroundColor !== color.Surface.Container ? cardColor : undefined, - borderColor: backgroundColor, - color: backgroundColor !== color.Surface.Container ? textColor : undefined, + ...(showCustomHeroCard && chipSurfaceStyle ? chipSurfaceStyle : {}), + ...heroMenuItemStyle({}, chipHoverBrightness), }} > Message @@ -575,62 +613,20 @@ export function UserRoomProfile({ userId, initialProfile }: Readonly - {server && ( - - )} - + {server && } + {creator ? ( - + ) : ( - - )} - {userId !== myUserId && ( - - )} - {userId !== myUserId && ( - + )} + {userId !== myUserId && } + {userId !== myUserId && } {ignored && } {member && membership === bannedMembership && ( diff --git a/src/app/components/user-profile/heroMenuItemStyle.ts b/src/app/components/user-profile/heroMenuItemStyle.ts new file mode 100644 index 000000000..0b66e36ce --- /dev/null +++ b/src/app/components/user-profile/heroMenuItemStyle.ts @@ -0,0 +1,19 @@ +import type { CSSProperties } from 'react'; + +export function heroMenuItemStyle( + base: CSSProperties, + chipHoverBrightness?: number +): CSSProperties { + const bg = base.backgroundColor; + const out: CSSProperties = { ...base }; + if (typeof bg === 'string' && bg !== '' && bg !== 'transparent') { + (out as CSSProperties & { '--user-hero-menu-item-bg': string })['--user-hero-menu-item-bg'] = + bg; + } + if (chipHoverBrightness != null) { + (out as CSSProperties & { '--user-hero-chip-hover-brightness': number })[ + '--user-hero-chip-hover-brightness' + ] = chipHoverBrightness; + } + return out; +} diff --git a/src/app/components/user-profile/styles.css.ts b/src/app/components/user-profile/styles.css.ts index 3ff2f6c10..e7283d43b 100644 --- a/src/app/components/user-profile/styles.css.ts +++ b/src/app/components/user-profile/styles.css.ts @@ -57,9 +57,12 @@ export const UserHeroStatusContainer = style({ export const UserHeroStatusTooltip = style({ maxWidth: '98%', justifySelf: 'left', +}); + +export const UserHeroStatusTooltipInteractive = style({ cursor: 'pointer', ':hover': { - filter: 'brightness(0.8)', + filter: 'brightness(var(--user-hero-status-hover-brightness, 0.94))', transform: 'translateY(-1px)', }, }); @@ -78,19 +81,55 @@ export const UserHeroAvatarImg = style({ }, }, }); -export const UserHeroChip = style({ - borderStyle: 'solid', - borderWidth: '1px', +export const UserHeroBrightnessHover = style({ ':hover': { - filter: 'brightness(0.8)', + filter: 'brightness(var(--user-hero-chip-hover-brightness, 0.94))', transform: 'translateY(-1px)', }, }); + +export const UserHeroChip = style([ + UserHeroBrightnessHover, + { + borderStyle: 'solid', + borderWidth: '1px', + boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)', + }, +]); + +export const UserHeroChipThemed = style([ + UserHeroBrightnessHover, + { + borderStyle: 'solid', + borderWidth: '1px', + borderColor: 'transparent', + boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)', + }, +]); + +export const MiscDataToggleButton = style({ + backgroundColor: 'transparent', + opacity: 0.75, + selectors: { + '&:hover': { + opacity: 1, + backgroundColor: 'transparent', + transform: 'none !important', + }, + '&:active': { + transform: 'none !important', + }, + }, +}); +/** Same hover lift/filter as UserHeroBrightnessHover; pins bg so folds MenuItem hover can't mask brightness. */ export const UserHeroMenuItem = style({ borderStyle: 'hidden', borderWidth: '1px', - ':hover': { - filter: 'brightness(0.8)', - transform: 'translateY(-1px)', + selectors: { + '&:hover': { + filter: 'brightness(var(--user-hero-chip-hover-brightness, 0.94))', + transform: 'translateY(-1px)', + backgroundColor: 'var(--user-hero-menu-item-bg) !important', + }, }, });