diff options
| author | Oliver <oliver@mohlin.dev> | 2025-10-09 13:57:20 +0200 |
|---|---|---|
| committer | Tobias Järvelöv <tobias.jarvelov@mullvad.net> | 2025-10-10 13:38:06 +0200 |
| commit | 2903681572d2b0e816e4b7706b92af47b79df570 (patch) | |
| tree | 99c88d73589246c34c9110280788af9055f3029d | |
| parent | 541d8a1f6c85f84084179b50fe3e5f2463d962e7 (diff) | |
| download | mullvadvpn-2903681572d2b0e816e4b7706b92af47b79df570.tar.xz mullvadvpn-2903681572d2b0e816e4b7706b92af47b79df570.zip | |
Add EmptyState component
14 files changed, 138 insertions, 0 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/EmptyState.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/EmptyState.tsx new file mode 100644 index 0000000000..7d94385ebe --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/EmptyState.tsx @@ -0,0 +1,35 @@ +import { Flex, FlexProps } from '../flex'; +import { + EmptyStateButton, + EmptyStateStatusIcon, + EmptyStateSubtitle, + EmptyStateTextContainer, + EmptyStateTitle, +} from './components'; +import { EmptyStateProvider } from './EmptyStateContext'; + +type EmptyStateVariant = 'success' | 'error' | 'loading'; + +export type EmptyStateProps = FlexProps & { + variant?: EmptyStateVariant; +}; + +function EmptyState({ variant = 'error', children, ...props }: EmptyStateProps) { + return ( + <EmptyStateProvider variant={variant}> + <Flex $flexDirection="column" $gap="medium" $alignItems="center" {...props}> + {children} + </Flex> + </EmptyStateProvider> + ); +} + +const EmptyStateNamespace = Object.assign(EmptyState, { + StatusIcon: EmptyStateStatusIcon, + Subtitle: EmptyStateSubtitle, + Title: EmptyStateTitle, + Button: EmptyStateButton, + TextContainer: EmptyStateTextContainer, +}); + +export { EmptyStateNamespace as EmptyState }; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/EmptyStateContext.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/EmptyStateContext.tsx new file mode 100644 index 0000000000..ea89b73515 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/EmptyStateContext.tsx @@ -0,0 +1,26 @@ +import React from 'react'; + +import { EmptyStateProps } from './EmptyState'; + +type EmptyStateContextProps = { + variant: EmptyStateProps['variant']; +}; + +const EmptyStateContext = React.createContext<EmptyStateContextProps | undefined>(undefined); + +export const useEmptyStateContext = (): EmptyStateContextProps => { + const context = React.useContext(EmptyStateContext); + if (!context) { + throw new Error('useEmptyStateContext must be used within a EmptyStateProvider'); + } + return context; +}; + +interface EmptyStateProviderProps { + variant: EmptyStateProps['variant']; + children: React.ReactNode; +} + +export function EmptyStateProvider({ variant, children }: EmptyStateProviderProps) { + return <EmptyStateContext.Provider value={{ variant }}>{children}</EmptyStateContext.Provider>; +} diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-button/EmptyStateButton.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-button/EmptyStateButton.tsx new file mode 100644 index 0000000000..c2de7604bd --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-button/EmptyStateButton.tsx @@ -0,0 +1,20 @@ +import { Button, ButtonProps } from '../../../button'; +import { useEmptyStateContext } from '../../EmptyStateContext'; + +export type EmpptyStateButtonProps = ButtonProps; + +function EmptyStateButton({ children, ...props }: EmpptyStateButtonProps) { + const { variant } = useEmptyStateContext(); + const disabled = variant === 'loading'; + return ( + <Button disabled={disabled} {...props}> + {children} + </Button> + ); +} + +const EmptyStateButtonNamespace = Object.assign(EmptyStateButton, { + Text: Button.Text, +}); + +export { EmptyStateButtonNamespace as EmptyStateButton }; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-button/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-button/index.ts new file mode 100644 index 0000000000..675721619a --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-button/index.ts @@ -0,0 +1 @@ +export * from './EmptyStateButton'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-status-icon/EmptyStateStatusIcon.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-status-icon/EmptyStateStatusIcon.tsx new file mode 100644 index 0000000000..8ef16a2ab5 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-status-icon/EmptyStateStatusIcon.tsx @@ -0,0 +1,14 @@ +import { IconBadge } from '../../../../icon-badge'; +import { Spinner } from '../../../spinner'; +import { useEmptyStateContext } from '../../EmptyStateContext'; + +export function EmptyStateStatusIcon() { + const { variant } = useEmptyStateContext(); + return ( + <> + {variant === 'success' && <IconBadge state={'positive'} />} + {variant === 'error' && <IconBadge state={'negative'} />} + {variant === 'loading' && <Spinner size="big" />} + </> + ); +} diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-status-icon/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-status-icon/index.ts new file mode 100644 index 0000000000..0bd3c665bb --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-status-icon/index.ts @@ -0,0 +1 @@ +export * from './EmptyStateStatusIcon'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-subtitle/EmptyStateSubtitle.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-subtitle/EmptyStateSubtitle.tsx new file mode 100644 index 0000000000..61a4c02c41 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-subtitle/EmptyStateSubtitle.tsx @@ -0,0 +1,10 @@ +import { Text, TextProps } from '../../../text'; + +export type EmptyStateSubtitleProps = TextProps; +export function EmptyStateSubtitle({ children, ...props }: EmptyStateSubtitleProps) { + return ( + <Text variant="labelTiny" color="whiteAlpha60" textAlign="center" {...props}> + {children} + </Text> + ); +} diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-subtitle/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-subtitle/index.ts new file mode 100644 index 0000000000..f210c0dc29 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-subtitle/index.ts @@ -0,0 +1 @@ +export * from './EmptyStateSubtitle'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-text-container/EmptyStateTextContainer.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-text-container/EmptyStateTextContainer.tsx new file mode 100644 index 0000000000..0f964527a8 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-text-container/EmptyStateTextContainer.tsx @@ -0,0 +1,11 @@ +import { Flex, FlexProps } from '../../../flex'; + +export type EmptyStateTextContainerProps = FlexProps; + +export function EmptyStateTextContainer({ children, ...props }: EmptyStateTextContainerProps) { + return ( + <Flex $flexDirection="column" $alignItems="center" $gap="tiny" {...props}> + {children} + </Flex> + ); +} diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-text-container/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-text-container/index.ts new file mode 100644 index 0000000000..6db950b516 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-text-container/index.ts @@ -0,0 +1 @@ +export * from './EmptyStateTextContainer'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-title/EmptyStateTitle.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-title/EmptyStateTitle.tsx new file mode 100644 index 0000000000..0de48a2f39 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-title/EmptyStateTitle.tsx @@ -0,0 +1,11 @@ +import { Text, TextProps } from '../../../text'; + +export type EmptyStateTitleProps = TextProps; + +export function EmptyStateTitle({ children, ...props }: EmptyStateTitleProps) { + return ( + <Text variant="titleMedium" textAlign="center" {...props}> + {children} + </Text> + ); +} diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-title/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-title/index.ts new file mode 100644 index 0000000000..ce04a342db --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/empty-state-title/index.ts @@ -0,0 +1 @@ +export * from './EmptyStateTitle'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/index.ts new file mode 100644 index 0000000000..060505932e --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/components/index.ts @@ -0,0 +1,5 @@ +export * from './empty-state-button'; +export * from './empty-state-status-icon'; +export * from './empty-state-subtitle'; +export * from './empty-state-text-container'; +export * from './empty-state-title'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/index.ts new file mode 100644 index 0000000000..c54a68a9de --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/empty-state/index.ts @@ -0,0 +1 @@ +export * from './EmptyState'; |
