From a1efd29e5764a3b6975051a3db68cffa85a71039 Mon Sep 17 00:00:00 2001 From: Stefanos Anagnostou Date: Tue, 12 Dec 2023 18:27:41 +0200 Subject: [PATCH] feat(clerk-js): First iteration of OrganizationSwitcher retheme (#2311) * fix(clerk-js): Refactor Action and SmallAction elements * feat(clerk-js): Retheme OrganizationSwitcher * fix(clerk-js): Add the correct Add icon on both UB and OS * fix(clerk-js): Retheme the InvitationPreview UI * fix(clerk-js): Add changeset --- .changeset/popular-parents-hope.md | 2 + .../common/NotificationCountBadge.tsx | 17 +-- .../OrganizationSwitcherPopover.tsx | 124 ++++++++++++----- .../OrganizationSwitcherTrigger.tsx | 15 +- .../OtherOrganizationActions.tsx | 16 ++- .../UserInvitationSuggestionList.tsx | 16 ++- .../UserMembershipList.tsx | 28 ++-- .../components/UserButton/SessionActions.tsx | 23 +--- .../UserButton/UserButtonPopover.tsx | 55 ++++---- .../UserButton/UserButtonTrigger.tsx | 2 +- .../customizables/elementDescriptors.ts | 3 +- .../src/ui.retheme/elements/Actions.tsx | 130 ++++++++++-------- .../elements/OrganizationPreview.tsx | 13 +- .../src/ui.retheme/elements/PreviewButton.tsx | 1 - .../src/ui.retheme/elements/UserPreview.tsx | 13 +- .../clerk-js/src/ui.retheme/icons/add.svg | 1 + .../src/ui.retheme/icons/chevron-down.svg | 1 + .../clerk-js/src/ui.retheme/icons/index.ts | 2 + packages/localizations/src/en-US.retheme.ts | 2 +- packages/types/src/appearance.retheme.ts | 1 - 20 files changed, 277 insertions(+), 188 deletions(-) create mode 100644 .changeset/popular-parents-hope.md create mode 100644 packages/clerk-js/src/ui.retheme/icons/add.svg create mode 100644 packages/clerk-js/src/ui.retheme/icons/chevron-down.svg diff --git a/.changeset/popular-parents-hope.md b/.changeset/popular-parents-hope.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/popular-parents-hope.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/clerk-js/src/ui.retheme/common/NotificationCountBadge.tsx b/packages/clerk-js/src/ui.retheme/common/NotificationCountBadge.tsx index 2bda7db3c2..a3b609a055 100644 --- a/packages/clerk-js/src/ui.retheme/common/NotificationCountBadge.tsx +++ b/packages/clerk-js/src/ui.retheme/common/NotificationCountBadge.tsx @@ -3,13 +3,12 @@ import { useDelayedVisibility, usePrefersReducedMotion } from '../hooks'; import type { ThemableCssProp } from '../styledSystem'; import { animations } from '../styledSystem'; -export const NotificationCountBadge = ({ - notificationCount, - containerSx, -}: { +type NotificationCountBadgeProps = { notificationCount: number; containerSx?: ThemableCssProp; -}) => { +}; + +export const NotificationCountBadge = ({ notificationCount, containerSx }: NotificationCountBadgeProps) => { const prefersReducedMotion = usePrefersReducedMotion(); const showNotification = useDelayedVisibility(notificationCount > 0, 350) || false; @@ -25,9 +24,11 @@ export const NotificationCountBadge = ({ ({ - position: 'relative', - width: t.sizes.$4, - height: t.sizes.$4, + position: 'absolute', + top: `-${t.space.$2}`, + right: `-${t.space.$1}`, + width: t.sizes.$2, + height: t.sizes.$2, }), containerSx, ]} diff --git a/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx b/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx index 302ad9ba7a..5cea7503de 100644 --- a/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx +++ b/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx @@ -5,19 +5,20 @@ import React from 'react'; import { runIfFunctionOrReturn } from '../../../utils'; import { NotificationCountBadge, withGate } from '../../common'; import { useEnvironment, useOrganizationSwitcherContext } from '../../contexts'; -import { descriptors, localizationKeys } from '../../customizables'; +import { descriptors, Flex, localizationKeys } from '../../customizables'; import { - Action, Actions, + ExtraSmallAction, OrganizationPreview, PersonalWorkspacePreview, PopoverCard, + SmallAction, useCardState, } from '../../elements'; import { RootBox } from '../../elements/RootBox'; import { Billing, CogFilled } from '../../icons'; import { useRouter } from '../../router'; -import type { PropsOfComponent } from '../../styledSystem'; +import type { PropsOfComponent, ThemableCssProp } from '../../styledSystem'; import { OrganizationActionList } from './OtherOrganizationActions'; type OrganizationSwitcherPopoverProps = { close: () => void } & PropsOfComponent; @@ -101,31 +102,91 @@ export const OrganizationSwitcherPopover = React.forwardRef} + /> + ); + const manageOrganizationButton = ( - } + trailing={} /> ); const billingOrganizationButton = ( - router.navigate(runIfFunctionOrReturn(__unstable_manageBillingUrl))} /> ); + const selectedOrganizationPreview = (currentOrg: OrganizationResource) => + __unstable_manageBillingUrl ? ( + <> + ({ + padding: `${t.space.$4} ${t.space.$5}`, + })} + /> + ({ borderBottom: `${t.borders.$normal} ${t.colors.$blackAlpha100}` })} + > + ({ marginLeft: t.space.$12, padding: `0 ${t.space.$5} ${t.space.$4}`, gap: t.space.$2 })} + > + {manageOrganizationButton} + {billingOrganizationButton} + + + + ) : ( + ({ + width: '100%', + paddingRight: t.space.$5, + borderBottom: `${t.borders.$normal} ${t.colors.$blackAlpha100}`, + })} + > + ({ + padding: `${t.space.$4} ${t.space.$5}`, + })} + /> + {manageOrganizationSmallIconButton} + + ); + return ( - {currentOrg ? ( - <> - t => ({ padding: `0 ${theme.space.$6}`, marginBottom: t.space.$2 })} - /> - - {manageOrganizationButton} - {__unstable_manageBillingUrl && billingOrganizationButton} - - - ) : ( - !hidePersonal && ( - ({ padding: `0 ${theme.space.$6}`, marginBottom: theme.space.$6 })} - title={localizationKeys('organizationSwitcher.personalWorkspace')} - /> - ) - )} + {currentOrg + ? selectedOrganizationPreview(currentOrg) + : !hidePersonal && ( + ({ + padding: `${t.space.$4} ${t.space.$5}`, + borderBottom: `${t.borders.$normal} ${t.colors.$blackAlpha100}`, + })} + title={localizationKeys('organizationSwitcher.personalWorkspace')} + /> + )} { + ({ sx }: { sx?: ThemableCssProp }) => { const { organizationSettings } = useEnvironment(); const isDomainsEnabled = organizationSettings?.domains?.enabled; @@ -183,7 +232,12 @@ const NotificationCountBadgeManageButton = withGate( membershipRequests: isDomainsEnabled || undefined, }); - return ; + return ( + + ); }, { // if the user is not able to accept a request we should not notify them diff --git a/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OrganizationSwitcherTrigger.tsx b/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OrganizationSwitcherTrigger.tsx index f3cd587c30..8b8ff0502c 100644 --- a/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OrganizationSwitcherTrigger.tsx +++ b/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OrganizationSwitcherTrigger.tsx @@ -5,7 +5,7 @@ import { NotificationCountBadge, useGate } from '../../common'; import { useEnvironment, useOrganizationSwitcherContext } from '../../contexts'; import { Button, descriptors, Icon, localizationKeys } from '../../customizables'; import { OrganizationPreview, PersonalWorkspacePreview, withAvatarShimmer } from '../../elements'; -import { Selector } from '../../icons'; +import { ChevronDown } from '../../icons'; import type { PropsOfComponent } from '../../styledSystem'; import { organizationListParams } from './utils'; @@ -31,7 +31,7 @@ export const OrganizationSwitcherTrigger = withAvatarShimmer( ); diff --git a/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OtherOrganizationActions.tsx b/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OtherOrganizationActions.tsx index 4897b785db..d5c4c0e0b7 100644 --- a/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OtherOrganizationActions.tsx +++ b/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/OtherOrganizationActions.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { descriptors, localizationKeys } from '../../customizables'; import { Action, SecondaryActions } from '../../elements'; -import { Plus } from '../../icons'; +import { Add } from '../../icons'; import { UserInvitationSuggestionList } from './UserInvitationSuggestionList'; import type { UserMembershipListProps } from './UserMembershipList'; import { UserMembershipList } from './UserMembershipList'; @@ -29,11 +29,19 @@ const CreateOrganizationButton = ({ iconBoxElementId={descriptors.organizationSwitcherPopoverActionButtonIconBox.setId('createOrganization')} iconElementDescriptor={descriptors.organizationSwitcherPopoverActionButtonIcon} iconElementId={descriptors.organizationSwitcherPopoverActionButtonIcon.setId('createOrganization')} - textElementDescriptor={descriptors.organizationSwitcherPopoverActionButtonText} - textElementId={descriptors.organizationSwitcherPopoverActionButtonText.setId('createOrganization')} - icon={Plus} + icon={Add} label={localizationKeys('organizationSwitcher.action__createOrganization')} onClick={onCreateOrganizationClick} + sx={t => ({ + color: t.colors.$blackAlpha600, + ':hover': { + color: t.colors.$blackAlpha600, + }, + })} + iconSx={t => ({ + width: t.sizes.$9, + height: t.sizes.$6, + })} /> ); }; diff --git a/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/UserInvitationSuggestionList.tsx b/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/UserInvitationSuggestionList.tsx index 0109f031c9..323038562e 100644 --- a/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/UserInvitationSuggestionList.tsx +++ b/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/UserInvitationSuggestionList.tsx @@ -88,7 +88,7 @@ const AcceptRejectInvitationButtons = (props: UserOrganizationInvitationResource elementDescriptor={descriptors.organizationSwitcherInvitationAcceptButton} textVariant='buttonSmall' variant='secondary' - size='sm' + size='xs' isLoading={card.isLoading} onClick={handleAccept} localizationKey={localizationKeys('organizationSwitcher.action__invitationAccept')} @@ -110,17 +110,19 @@ const InvitationPreview = withCardStateProvider( align='center' gap={2} sx={t => ({ - minHeight: 'unset', - height: t.space.$12, justifyContent: 'space-between', - padding: `0 ${t.space.$6}`, + padding: `${t.space.$4} ${t.space.$5}`, })} > ({ margin: `0 calc(${t.space.$3}/2)` })} organization={publicOrganizationData} - size='sm' + sx={t => ({ + color: t.colors.$blackAlpha600, + ':hover': { + color: t.colors.$blackAlpha600, + }, + })} /> {children} @@ -134,7 +136,7 @@ const SwitcherInvitationActions = (props: PropsOfComponent & { show return ( ({ - borderTop: showBorder ? `${t.borders.$normal} ${t.colors.$blackAlpha200}` : 'none', + borderBottom: showBorder ? `${t.borders.$normal} ${t.colors.$blackAlpha200}` : 'none', })} role='menu' {...restProps} diff --git a/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/UserMembershipList.tsx b/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/UserMembershipList.tsx index 5c425f48ed..ca136926f4 100644 --- a/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/UserMembershipList.tsx +++ b/packages/clerk-js/src/ui.retheme/components/OrganizationSwitcher/UserMembershipList.tsx @@ -7,7 +7,7 @@ import { useOrganizationSwitcherContext } from '../../contexts'; import { Box, descriptors, localizationKeys } from '../../customizables'; import { OrganizationPreview, PersonalWorkspacePreview, PreviewButton } from '../../elements'; import { useInView } from '../../hooks'; -import { SwitchArrows } from '../../icons'; +import { SwitchArrowRight } from '../../icons'; import { common } from '../../styledSystem'; import { organizationListParams } from './utils'; @@ -61,7 +61,6 @@ export const UserMembershipList = (props: UserMembershipListProps) => { return ( ({ - maxHeight: `calc(4 * ${t.sizes.$12})`, overflowY: 'auto', ...common.unstyledScrollbar(t), })} @@ -71,16 +70,21 @@ export const UserMembershipList = (props: UserMembershipListProps) => { {currentOrg && !hidePersonal && ( ({ borderRadius: 0, borderBottom: `${t.borders.$normal} ${t.colors.$blackAlpha100}` })} onClick={onPersonalWorkspaceClick} role='menuitem' > ({ margin: `0 calc(${t.space.$3}/2)` })} + mainIdentifierVariant={'buttonLarge'} title={localizationKeys('organizationSwitcher.personalWorkspace')} + mainIdentifierSx={t => ({ + color: t.colors.$blackAlpha600, + ':hover': { + color: t.colors.$blackAlpha600, + }, + })} /> )} @@ -88,16 +92,20 @@ export const UserMembershipList = (props: UserMembershipListProps) => { ({ borderRadius: 0, borderBottom: `${t.borders.$normal} ${t.colors.$blackAlpha100}` })} onClick={() => onOrganizationClick(organization)} role='menuitem' > ({ margin: `0 calc(${t.space.$3}/2)` })} organization={organization} - size='sm' + sx={t => ({ + color: t.colors.$blackAlpha600, + ':hover': { + color: t.colors.$blackAlpha600, + }, + })} /> ))} diff --git a/packages/clerk-js/src/ui.retheme/components/UserButton/SessionActions.tsx b/packages/clerk-js/src/ui.retheme/components/UserButton/SessionActions.tsx index 56d9607485..470cd2e566 100644 --- a/packages/clerk-js/src/ui.retheme/components/UserButton/SessionActions.tsx +++ b/packages/clerk-js/src/ui.retheme/components/UserButton/SessionActions.tsx @@ -26,13 +26,12 @@ export const SingleSessionActions = (props: SessionActionsProps) => { iconBoxElementId={descriptors.userButtonPopoverActionButtonIconBox.setId('manageAccount')} iconElementDescriptor={descriptors.userButtonPopoverActionButtonIcon} iconElementId={descriptors.userButtonPopoverActionButtonIcon.setId('manageAccount')} - textElementDescriptor={descriptors.userButtonPopoverActionButtonText} - textElementId={descriptors.userButtonPopoverActionButtonText.setId('manageAccount')} icon={CogFilled} label={localizationKeys('userButton.action__manageAccount')} onClick={handleManageAccountClicked} sx={t => ({ borderTop: `${t.borders.$normal} ${t.colors.$blackAlpha100}`, + backgroundColor: t.colors.$white, })} /> { iconBoxElementId={descriptors.userButtonPopoverActionButtonIconBox.setId('signOut')} iconElementDescriptor={descriptors.userButtonPopoverActionButtonIcon} iconElementId={descriptors.userButtonPopoverActionButtonIcon.setId('signOut')} - textElementDescriptor={descriptors.userButtonPopoverActionButtonText} - textElementId={descriptors.userButtonPopoverActionButtonText.setId('signOut')} icon={SignOut} label={localizationKeys('userButton.action__signOut')} onClick={handleSignOutSessionClicked(session)} @@ -85,8 +82,6 @@ export const MultiSessionActions = (props: SessionActionsProps) => { iconBoxElementId={descriptors.userButtonPopoverActionButtonIconBox.setId('manageAccount')} iconElementDescriptor={descriptors.userButtonPopoverActionButtonIcon} iconElementId={descriptors.userButtonPopoverActionButtonIcon.setId('manageAccount')} - textElementDescriptor={descriptors.userButtonPopoverActionButtonText} - textElementId={descriptors.userButtonPopoverActionButtonText.setId('manageAccount')} icon={CogFilled} label={localizationKeys('userButton.action__manageAccount')} onClick={handleManageAccountClicked} @@ -98,19 +93,15 @@ export const MultiSessionActions = (props: SessionActionsProps) => { iconBoxElementId={descriptors.userButtonPopoverActionButtonIconBox.setId('signOut')} iconElementDescriptor={descriptors.userButtonPopoverActionButtonIcon} iconElementId={descriptors.userButtonPopoverActionButtonIcon.setId('signOut')} - textElementDescriptor={descriptors.userButtonPopoverActionButtonText} - textElementId={descriptors.userButtonPopoverActionButtonText.setId('signOut')} icon={SignOut} label={localizationKeys('userButton.action__signOut')} onClick={handleSignOutSessionClicked(session)} - sx={[ - t => ({ - ':hover': { - backgroundColor: t.colors.$danger50, - color: t.colors.$danger400, - }, - }), - ]} + sx={t => ({ + ':hover': { + backgroundColor: t.colors.$danger50, + color: t.colors.$danger400, + }, + })} /> diff --git a/packages/clerk-js/src/ui.retheme/components/UserButton/UserButtonPopover.tsx b/packages/clerk-js/src/ui.retheme/components/UserButton/UserButtonPopover.tsx index 8a81a63a42..580747e644 100644 --- a/packages/clerk-js/src/ui.retheme/components/UserButton/UserButtonPopover.tsx +++ b/packages/clerk-js/src/ui.retheme/components/UserButton/UserButtonPopover.tsx @@ -5,7 +5,7 @@ import React from 'react'; import { useEnvironment, useUserButtonContext } from '../../contexts'; import { descriptors, Icon, localizationKeys } from '../../customizables'; import { Action, Actions, PopoverCard, PreviewButton, RootBox, SecondaryActions, UserPreview } from '../../elements'; -import { CheckmarkFilled, Plus, SignOut, SwitchArrowRight } from '../../icons'; +import { Add, CheckmarkFilled, SignOut, SwitchArrowRight } from '../../icons'; import type { PropsOfComponent } from '../../styledSystem'; import { MultiSessionActions, SingleSessionActions } from './SessionActions'; import { useMultisessionActions } from './useMultisessionActions'; @@ -34,14 +34,16 @@ export const UserButtonPopover = React.forwardRef ({ backgroundColor: t.colors.$colorBackground, })} + iconSx={t => ({ + width: t.sizes.$9, + height: t.sizes.$6, + })} /> ); @@ -60,8 +62,6 @@ export const UserButtonPopover = React.forwardRef - - {otherSessions.map(session => ( - ({ - height: t.sizes.$20, - borderRadius: 0, - borderBottom: `${t.borders.$normal} ${t.colors.$blackAlpha100}`, - backgroundColor: t.colors.$colorBackground, - })} - onClick={handleSessionClicked(session)} - role='menuitem' - > - - - ))} - {addAccountButton} - - + + {otherSessions.map(session => ( + ({ + borderRadius: 0, + borderBottom: `${t.borders.$normal} ${t.colors.$blackAlpha100}`, + backgroundColor: t.colors.$colorBackground, + })} + onClick={handleSessionClicked(session)} + role='menuitem' + > + + + ))} + {addAccountButton} + ); return ( @@ -119,7 +113,6 @@ export const UserButtonPopover = React.forwardRef ({ padding: `${t.space.$4} ${t.space.$5}`, })} - size='sm' icon={ theme.sizes.$8} + size={theme => theme.sizes.$7} /> ); diff --git a/packages/clerk-js/src/ui.retheme/customizables/elementDescriptors.ts b/packages/clerk-js/src/ui.retheme/customizables/elementDescriptors.ts index 5c01521544..fca1d084e9 100644 --- a/packages/clerk-js/src/ui.retheme/customizables/elementDescriptors.ts +++ b/packages/clerk-js/src/ui.retheme/customizables/elementDescriptors.ts @@ -125,7 +125,6 @@ export const APPEARANCE_KEYS = containsAllElementsConfigKeys([ 'userButtonPopoverActionButton', 'userButtonPopoverActionButtonIconBox', 'userButtonPopoverActionButtonIcon', - 'userButtonPopoverActionButtonText', 'userButtonPopoverFooter', 'userButtonPopoverFooterPages', 'userButtonPopoverFooterPagesLink', @@ -313,7 +312,7 @@ type ElementDescriptors = { [k in keyof ElementsConfig as ElementObjectKey]: * socialButtons-buttonIcon -> cl-socialButtons-buttonIcon */ const toTargettableClassname = (key: K): TargettableClassname => { - return (CLASS_PREFIX + key) as TargettableClassname; + return (CLASS_PREFIX + (key as string)) as TargettableClassname; }; /** diff --git a/packages/clerk-js/src/ui.retheme/elements/Actions.tsx b/packages/clerk-js/src/ui.retheme/elements/Actions.tsx index fe7f10a098..60253e45af 100644 --- a/packages/clerk-js/src/ui.retheme/elements/Actions.tsx +++ b/packages/clerk-js/src/ui.retheme/elements/Actions.tsx @@ -1,11 +1,11 @@ import React from 'react'; import type { LocalizationKey } from '../customizables'; -import { Button, Col, descriptors, Flex, Icon, Spinner, Text } from '../customizables'; +import { Button, Col, descriptors, Flex, Icon, SimpleButton, Spinner, useLocalizations } from '../customizables'; import type { ElementDescriptor, ElementId } from '../customizables/elementDescriptors'; import { useCardState } from '../elements/contexts'; import { useLoadingStatus } from '../hooks'; -import type { PropsOfComponent } from '../styledSystem'; +import type { PropsOfComponent, ThemableCssProp } from '../styledSystem'; export const Actions = (props: PropsOfComponent) => { return ; @@ -21,26 +21,25 @@ type ActionProps = Omit, 'label'> & { label: LocalizationKey; iconBoxElementDescriptor?: ElementDescriptor; iconBoxElementId?: ElementId; + iconBoxSx?: ThemableCssProp; iconElementDescriptor?: ElementDescriptor; iconElementId?: ElementId; - textElementDescriptor?: ElementDescriptor; - textElementId?: ElementId; + iconSx?: ThemableCssProp; }; -export const Action = (props: ActionProps) => { +export const ExtraSmallAction = (props: Omit) => { const card = useCardState(); const status = useLoadingStatus(); const { icon, - label, onClick: onClickProp, iconElementDescriptor, sx, iconElementId, - textElementDescriptor, - textElementId, + iconSx, iconBoxElementDescriptor, iconBoxElementId, + iconBoxSx, trailing, ...rest } = props; @@ -57,21 +56,18 @@ export const Action = (props: ActionProps) => { }; return ( - + ); }; export const SmallAction = (props: ActionProps) => { + const { sx, iconBoxSx, iconSx, ...rest } = props; + return ( + ({ + borderRadius: t.radii.$lg, + borderBottom: 'none', + gap: 0, + justifyContent: 'center', + flex: '1 1 0', + padding: `${t.space.$1} ${t.space.$1x5}`, + }), + sx, + ]} + iconSx={[ + t => ({ + width: t.sizes.$4, + height: t.sizes.$4, + marginRight: t.space.$2, + }), + iconSx, + ]} + iconBoxSx={[{ flex: 'unset' }, iconBoxSx]} + {...rest} + /> + ); +}; + +export const Action = (props: ActionProps) => { const card = useCardState(); const status = useLoadingStatus(); + const { t } = useLocalizations(); const { icon, label, @@ -128,10 +150,10 @@ export const SmallAction = (props: ActionProps) => { iconElementDescriptor, sx, iconElementId, - textElementDescriptor, - textElementId, + iconSx, iconBoxElementDescriptor, iconBoxElementId, + iconBoxSx, trailing, ...rest } = props; @@ -149,21 +171,19 @@ export const SmallAction = (props: ActionProps) => { return ( ); diff --git a/packages/clerk-js/src/ui.retheme/elements/OrganizationPreview.tsx b/packages/clerk-js/src/ui.retheme/elements/OrganizationPreview.tsx index 16ff055300..9743674d3b 100644 --- a/packages/clerk-js/src/ui.retheme/elements/OrganizationPreview.tsx +++ b/packages/clerk-js/src/ui.retheme/elements/OrganizationPreview.tsx @@ -9,9 +9,10 @@ import { OrganizationAvatar } from './OrganizationAvatar'; export type OrganizationPreviewProps = Omit, 'elementId'> & { organization: UserOrganizationInvitationResource['publicOrganizationData']; user?: UserResource; - size?: 'lg' | 'md' | 'sm'; + size?: 'lg' | 'md' | 'sm' | 'xs'; avatarSx?: ThemableCssProp; mainIdentifierSx?: ThemableCssProp; + mainIdentifierVariant?: PropsOfComponent['variant']; icon?: React.ReactNode; badge?: React.ReactNode; rounded?: boolean; @@ -29,16 +30,20 @@ export const OrganizationPreview = (props: OrganizationPreviewProps) => { user, avatarSx, mainIdentifierSx, + mainIdentifierVariant, elementId, ...rest } = props; const role = user?.organizationMemberships.find(membership => membership.organization.id === organization.id)?.role; + const mainTextSize = + mainIdentifierVariant || ({ xs: 'subtitle', sm: 'caption', md: 'subtitle', lg: 'h1' } as const)[size]; + return ( { boxElementDescriptor={descriptors.organizationPreviewAvatarBox} imageElementDescriptor={descriptors.organizationPreviewAvatarImage} {...organization} - size={t => ({ sm: t.sizes.$8, md: t.sizes.$10, lg: t.sizes.$12 }[size])} + size={t => ({ xs: t.sizes.$5, sm: t.sizes.$8, md: t.sizes.$9, lg: t.sizes.$12 }[size])} sx={avatarSx} rounded={rounded} /> @@ -69,7 +74,7 @@ export const OrganizationPreview = (props: OrganizationPreviewProps) => { { sx={[ t => ({ minHeight: 'unset', - height: t.space.$12, justifyContent: 'space-between', padding: `${t.space.$4} ${t.space.$5}`, ...(showIconOnHover diff --git a/packages/clerk-js/src/ui.retheme/elements/UserPreview.tsx b/packages/clerk-js/src/ui.retheme/elements/UserPreview.tsx index 2859fea49d..acda54ecdb 100644 --- a/packages/clerk-js/src/ui.retheme/elements/UserPreview.tsx +++ b/packages/clerk-js/src/ui.retheme/elements/UserPreview.tsx @@ -13,7 +13,7 @@ import { UserAvatar } from './UserAvatar'; // - SamlAccountResource export type UserPreviewProps = Omit, 'title' | 'elementId'> & { - size?: 'lg' | 'md' | 'sm'; + size?: 'lg' | 'md' | 'sm' | 'xs'; icon?: React.ReactNode; iconSx?: ThemableCssProp; badge?: React.ReactNode; @@ -22,6 +22,7 @@ export type UserPreviewProps = Omit, 'title' | 'el elementId?: UserPreviewId; avatarSx?: ThemableCssProp; mainIdentifierSx?: ThemableCssProp; + mainIdentifierVariant?: PropsOfComponent['variant']; title?: LocalizationKey | string; subtitle?: LocalizationKey | string; showAvatar?: boolean; @@ -61,6 +62,7 @@ export const UserPreview = (props: UserPreviewProps) => { subtitle, avatarSx, mainIdentifierSx, + mainIdentifierVariant, ...rest } = props; const { t } = useLocalizations(); @@ -70,7 +72,11 @@ export const UserPreview = (props: UserPreviewProps) => { const imageUrl = imageUrlProp || user?.imageUrl || externalAccount?.imageUrl; - const getAvatarSizes = (t: InternalTheme) => ({ sm: t.sizes.$9, md: t.sizes.$12, lg: t.sizes.$13 }[size]); + const getAvatarSizes = (t: InternalTheme) => + (({ xs: t.sizes.$5, sm: t.sizes.$8, md: t.sizes.$9, lg: t.sizes.$12 } as const)[size]); + + const mainIdentifierSize = + mainIdentifierVariant || ({ xs: 'subtitle', sm: 'caption', md: 'subtitle', lg: 'h1' } as const)[size]; return ( { ({ display: 'flex', gap: theme.sizes.$1, alignItems: 'center' }), mainIdentifierSx]} > {localizedTitle || name || identifier} diff --git a/packages/clerk-js/src/ui.retheme/icons/add.svg b/packages/clerk-js/src/ui.retheme/icons/add.svg new file mode 100644 index 0000000000..4d7607c83e --- /dev/null +++ b/packages/clerk-js/src/ui.retheme/icons/add.svg @@ -0,0 +1 @@ + diff --git a/packages/clerk-js/src/ui.retheme/icons/chevron-down.svg b/packages/clerk-js/src/ui.retheme/icons/chevron-down.svg new file mode 100644 index 0000000000..0fe75416df --- /dev/null +++ b/packages/clerk-js/src/ui.retheme/icons/chevron-down.svg @@ -0,0 +1 @@ + diff --git a/packages/clerk-js/src/ui.retheme/icons/index.ts b/packages/clerk-js/src/ui.retheme/icons/index.ts index 6352294bc8..a8c06b2a55 100644 --- a/packages/clerk-js/src/ui.retheme/icons/index.ts +++ b/packages/clerk-js/src/ui.retheme/icons/index.ts @@ -4,6 +4,7 @@ * Consequently, the files are correctly imported but the TS checker emits errors. * The above no-check is safe, as webpack will not allow compilation if for example a file is not resolved. */ +export { default as Add } from './add.svg'; export { default as ArrowLeftIcon } from './arrow-left.svg'; export { default as ArrowRightIcon } from './arrow-right.svg'; export { default as ArrowRightButtonIcon } from './arrow-right-button.svg'; @@ -12,6 +13,7 @@ export { default as Billing } from './billing.svg'; export { default as Caret } from './caret.svg'; export { default as ChatAltIcon } from './chat-alt.svg'; export { default as CheckCircle } from './check-circle.svg'; +export { default as ChevronDown } from './chevron-down.svg'; export { default as Clipboard } from './clipboard.svg'; export { default as Close } from './close.svg'; export { default as CogFilled } from './cog-filled.svg'; diff --git a/packages/localizations/src/en-US.retheme.ts b/packages/localizations/src/en-US.retheme.ts index 331f2ae06f..00e1fabeec 100644 --- a/packages/localizations/src/en-US.retheme.ts +++ b/packages/localizations/src/en-US.retheme.ts @@ -530,7 +530,7 @@ export const enUS: LocalizationResource = { personalWorkspace: 'Personal account', notSelected: 'No organization selected', action__createOrganization: 'Create Organization', - action__manageOrganization: 'Manage Organization', + action__manageOrganization: 'Manage', action__invitationAccept: 'Join', action__suggestionsAccept: 'Request to join', suggestionsAcceptedLabel: 'Pending approval', diff --git a/packages/types/src/appearance.retheme.ts b/packages/types/src/appearance.retheme.ts index 7f0aaee2b2..e66ce7e423 100644 --- a/packages/types/src/appearance.retheme.ts +++ b/packages/types/src/appearance.retheme.ts @@ -232,7 +232,6 @@ export type ElementsConfig = { userButtonPopoverActionButton: WithOptions<'manageAccount' | 'addAccount' | 'signOut' | 'signOutAll'>; userButtonPopoverActionButtonIconBox: WithOptions<'manageAccount' | 'addAccount' | 'signOut' | 'signOutAll'>; userButtonPopoverActionButtonIcon: WithOptions<'manageAccount' | 'addAccount' | 'signOut' | 'signOutAll'>; - userButtonPopoverActionButtonText: WithOptions<'manageAccount' | 'addAccount' | 'signOut' | 'signOutAll'>; userButtonPopoverFooter: WithOptions; userButtonPopoverFooterPages: WithOptions; userButtonPopoverFooterPagesLink: WithOptions<'terms' | 'privacy'>;