feat: Revamp navigation bar (#6031)
closes: #4428 Testing for fetchMoreRecords is pending, along with component tests --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
import { useContext } from 'react';
|
||||
import { styled } from '@linaria/react';
|
||||
import { isNonEmptyString, isUndefined } from '@sniptt/guards';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { invalidAvatarUrlsState } from '@ui/display/avatar/components/states/isInvalidAvatarUrlState';
|
||||
@ -50,7 +50,7 @@ export type AvatarProps = {
|
||||
className?: string;
|
||||
size?: AvatarSize;
|
||||
placeholder: string | undefined;
|
||||
entityId?: string;
|
||||
placeholderColorSeed?: string;
|
||||
type?: Nullable<AvatarType>;
|
||||
color?: string;
|
||||
backgroundColor?: string;
|
||||
@ -62,7 +62,7 @@ export const Avatar = ({
|
||||
avatarUrl,
|
||||
size = 'md',
|
||||
placeholder,
|
||||
entityId = placeholder,
|
||||
placeholderColorSeed = placeholder,
|
||||
onClick,
|
||||
type = 'squared',
|
||||
color,
|
||||
@ -85,9 +85,10 @@ export const Avatar = ({
|
||||
}
|
||||
};
|
||||
|
||||
const fixedColor = color ?? stringToHslColor(entityId ?? '', 75, 25);
|
||||
const fixedColor =
|
||||
color ?? stringToHslColor(placeholderColorSeed ?? '', 75, 25);
|
||||
const fixedBackgroundColor =
|
||||
backgroundColor ?? stringToHslColor(entityId ?? '', 75, 85);
|
||||
backgroundColor ?? stringToHslColor(placeholderColorSeed ?? '', 75, 85);
|
||||
|
||||
const showBackgroundColor = showPlaceholder;
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ import { AvatarGroup, AvatarGroupProps } from '../AvatarGroup';
|
||||
|
||||
const makeAvatar = (userName: string, props: Partial<AvatarProps> = {}) => (
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
<Avatar placeholder={userName} entityId={userName} {...props} />
|
||||
<Avatar placeholder={userName} placeholderColorSeed={userName} {...props} />
|
||||
);
|
||||
|
||||
const getAvatars = (commonProps: Partial<AvatarProps> = {}) => [
|
||||
|
||||
@ -1,56 +1,47 @@
|
||||
import * as React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
import { Avatar } from '@ui/display/avatar/components/Avatar';
|
||||
import { AvatarType } from '@ui/display/avatar/types/AvatarType';
|
||||
import { Chip, ChipVariant } from '@ui/display/chip/components/Chip';
|
||||
import { IconComponent } from '@ui/display/icon/types/IconComponent';
|
||||
import { isDefined } from '@ui/utilities/isDefined';
|
||||
import { Nullable } from '@ui/utilities/types/Nullable';
|
||||
import { MouseEvent } from 'react';
|
||||
|
||||
export type EntityChipProps = {
|
||||
linkToEntity?: string;
|
||||
entityId: string;
|
||||
export type AvatarChipProps = {
|
||||
name: string;
|
||||
avatarUrl?: string;
|
||||
avatarType?: Nullable<AvatarType>;
|
||||
variant?: EntityChipVariant;
|
||||
variant?: AvatarChipVariant;
|
||||
LeftIcon?: IconComponent;
|
||||
className?: string;
|
||||
placeholderColorSeed?: string;
|
||||
onClick?: (event: MouseEvent) => void;
|
||||
};
|
||||
|
||||
export enum EntityChipVariant {
|
||||
export enum AvatarChipVariant {
|
||||
Regular = 'regular',
|
||||
Transparent = 'transparent',
|
||||
}
|
||||
|
||||
export const EntityChip = ({
|
||||
linkToEntity,
|
||||
entityId,
|
||||
export const AvatarChip = ({
|
||||
name,
|
||||
avatarUrl,
|
||||
avatarType = 'rounded',
|
||||
variant = EntityChipVariant.Regular,
|
||||
variant = AvatarChipVariant.Regular,
|
||||
LeftIcon,
|
||||
className,
|
||||
}: EntityChipProps) => {
|
||||
const navigate = useNavigate();
|
||||
placeholderColorSeed,
|
||||
onClick,
|
||||
}: AvatarChipProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const handleLinkClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (isNonEmptyString(linkToEntity)) {
|
||||
event.stopPropagation();
|
||||
navigate(linkToEntity);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Chip
|
||||
label={name}
|
||||
variant={
|
||||
linkToEntity
|
||||
? variant === EntityChipVariant.Regular
|
||||
isDefined(onClick)
|
||||
? variant === AvatarChipVariant.Regular
|
||||
? ChipVariant.Highlighted
|
||||
: ChipVariant.Regular
|
||||
: ChipVariant.Transparent
|
||||
@ -61,15 +52,15 @@ export const EntityChip = ({
|
||||
) : (
|
||||
<Avatar
|
||||
avatarUrl={avatarUrl}
|
||||
entityId={entityId}
|
||||
placeholderColorSeed={placeholderColorSeed}
|
||||
placeholder={name}
|
||||
size="sm"
|
||||
type={avatarType}
|
||||
/>
|
||||
)
|
||||
}
|
||||
clickable={!!linkToEntity}
|
||||
onClick={handleLinkClick}
|
||||
clickable={isDefined(onClick)}
|
||||
onClick={onClick}
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
@ -1,21 +1,19 @@
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { AvatarChip } from '@ui/display/chip/components/AvatarChip';
|
||||
|
||||
import { ComponentDecorator, RouterDecorator } from '@ui/testing';
|
||||
|
||||
import { EntityChip } from '../EntityChip';
|
||||
|
||||
const meta: Meta<typeof EntityChip> = {
|
||||
title: 'UI/Display/Chip/EntityChip',
|
||||
component: EntityChip,
|
||||
const meta: Meta<typeof AvatarChip> = {
|
||||
title: 'UI/Display/Chip/AvatarChip',
|
||||
component: AvatarChip,
|
||||
decorators: [RouterDecorator, ComponentDecorator],
|
||||
args: {
|
||||
name: 'Entity name',
|
||||
linkToEntity: '/entity-link',
|
||||
avatarType: 'squared',
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof EntityChip>;
|
||||
type Story = StoryObj<typeof AvatarChip>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
@ -6,8 +6,8 @@ export * from './avatar/types/AvatarSize';
|
||||
export * from './avatar/types/AvatarType';
|
||||
export * from './checkmark/components/AnimatedCheckmark';
|
||||
export * from './checkmark/components/Checkmark';
|
||||
export * from './chip/components/AvatarChip';
|
||||
export * from './chip/components/Chip';
|
||||
export * from './chip/components/EntityChip';
|
||||
export * from './color/components/ColorSample';
|
||||
export * from './icon/components/IconAddressBook';
|
||||
export * from './icon/components/IconGmail';
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export * from './color/utils/stringToHslColor';
|
||||
export * from './isDefined';
|
||||
export * from './state/utils/createState';
|
||||
export * from './types/Nullable';
|
||||
|
||||
4
packages/twenty-ui/src/utilities/isDefined.ts
Normal file
4
packages/twenty-ui/src/utilities/isDefined.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { isNull, isUndefined } from '@sniptt/guards';
|
||||
|
||||
export const isDefined = <T>(value: T | null | undefined): value is T =>
|
||||
!isUndefined(value) && !isNull(value);
|
||||
Reference in New Issue
Block a user