diff options
| author | Oliver <oliver@mohlin.dev> | 2025-02-06 14:51:04 +0100 |
|---|---|---|
| committer | Markus Pettersson <markus.pettersson@mullvad.net> | 2025-02-12 13:25:56 +0100 |
| commit | f691c9ed2e5f841a81c660d2861ee8f9fc882d5b (patch) | |
| tree | 62f27413f1a483f66e14b9f02831514bcd5f0699 | |
| parent | 54c80429e9e67029087fffb2129316a5d7f15ec6 (diff) | |
| download | mullvadvpn-f691c9ed2e5f841a81c660d2861ee8f9fc882d5b.tar.xz mullvadvpn-f691c9ed2e5f841a81c660d2861ee8f9fc882d5b.zip | |
Add Progress component
9 files changed, 190 insertions, 0 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/Progress.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/Progress.tsx new file mode 100644 index 0000000000..950a07539d --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/Progress.tsx @@ -0,0 +1,45 @@ +import React from 'react'; + +import { Spacings } from '../../foundations'; +import { Flex } from '../flex'; +import { + ProgressFooter, + ProgressPercent, + ProgressRange, + ProgressText, + ProgressTrack, +} from './components'; +import { ProgressProvider } from './ProgressContext'; + +export interface ProgressProps extends React.HTMLAttributes<HTMLDivElement> { + min?: number; + max?: number; + value: number; + disabled?: boolean; +} + +const Progress = React.forwardRef<HTMLDivElement, ProgressProps>( + ({ min = 0, max = 100, value, disabled, children, ...props }, ref) => { + const normalizedValue = Math.min(Math.max(value, min), max); + const percent = ((normalizedValue - min) / (max - min)) * 100; + return ( + <ProgressProvider value={value} min={min} max={max} percent={percent} disabled={disabled}> + <Flex $flexDirection="column" $gap={Spacings.spacing3} ref={ref} {...props}> + {children} + </Flex> + </ProgressProvider> + ); + }, +); + +Progress.displayName = 'Progress'; + +const ProgressNamespace = Object.assign(Progress, { + Footer: ProgressFooter, + Track: ProgressTrack, + Percent: ProgressPercent, + Range: ProgressRange, + Text: ProgressText, +}); + +export { ProgressNamespace as Progress }; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/ProgressContext.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/ProgressContext.tsx new file mode 100644 index 0000000000..c47a345739 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/ProgressContext.tsx @@ -0,0 +1,38 @@ +import React, { createContext, ReactNode, useContext } from 'react'; + +interface ProgressContextType { + value: number; + min: number; + max: number; + percent: number; + disabled?: boolean; +} + +const ProgressContext = createContext<ProgressContextType | undefined>(undefined); + +interface ProgressProviderProps extends ProgressContextType { + children: ReactNode; +} + +export const ProgressProvider: React.FC<ProgressProviderProps> = ({ + value, + min, + max, + percent, + disabled, + children, +}) => { + return ( + <ProgressContext.Provider value={{ min, max, percent, value, disabled }}> + {children} + </ProgressContext.Provider> + ); +}; + +export const useProgress = (): ProgressContextType => { + const context = useContext(ProgressContext); + if (!context) { + throw new Error('useProgress must be used within a ProgressProvider'); + } + return context; +}; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressFooter.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressFooter.tsx new file mode 100644 index 0000000000..779c1cde6c --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressFooter.tsx @@ -0,0 +1,10 @@ +import styled from 'styled-components'; + +import { Spacings } from '../../../foundations'; +import { Flex } from '../../flex'; + +export const ProgressFooter = styled(Flex).attrs({ + $alignItems: 'center', + $justifyContent: 'space-between', + $gap: Spacings.spacing5, +})``; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressPercent.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressPercent.tsx new file mode 100644 index 0000000000..b6ea92cf28 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressPercent.tsx @@ -0,0 +1,20 @@ +import styled from 'styled-components'; + +import { Colors } from '../../../foundations'; +import { LabelTiny, LabelTinyProps } from '../../typography'; +import { useProgress } from '../ProgressContext'; + +export type ProgressPercentProps = Omit<LabelTinyProps, 'children'>; + +const StyledText = styled(LabelTiny)` + min-width: 26px; +`; + +export const ProgressPercent = (props: ProgressPercentProps) => { + const { percent, disabled } = useProgress(); + return ( + <StyledText color={disabled ? Colors.white40 : Colors.white} {...props}> + {`${Math.round(percent)}%`} + </StyledText> + ); +}; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressRange.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressRange.tsx new file mode 100644 index 0000000000..e0ffb6c745 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressRange.tsx @@ -0,0 +1,24 @@ +import styled from 'styled-components'; + +import { Colors, Radius } from '../../../foundations'; +import { useProgress } from '../ProgressContext'; + +const StyledDiv = styled.div<{ + disabled?: boolean; +}>` + background-color: ${({ disabled }) => (disabled ? Colors.white50 : Colors.white)}; + border-radius: ${Radius.radius4}; + height: 100%; + width: 100%; + transition: transform 0.2s ease-out; + transform: var(--transform); +`; + +export const ProgressRange = () => { + const { percent, disabled } = useProgress(); + const transform = `translateX(${percent - 100}%)`; + + return ( + <StyledDiv disabled={disabled} style={{ '--transform': transform } as React.CSSProperties} /> + ); +}; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressText.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressText.tsx new file mode 100644 index 0000000000..36ad555eec --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressText.tsx @@ -0,0 +1,14 @@ +import { Colors } from '../../../foundations'; +import { LabelTiny, LabelTinyProps } from '../../typography'; +import { useProgress } from '../ProgressContext'; + +export type ProgressTextProps = LabelTinyProps; + +export const ProgressText = ({ children, ...props }: ProgressTextProps) => { + const { disabled } = useProgress(); + return ( + <LabelTiny color={disabled ? Colors.white40 : Colors.white60} {...props}> + {children} + </LabelTiny> + ); +}; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressTrack.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressTrack.tsx new file mode 100644 index 0000000000..58e4abb28b --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/ProgressTrack.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import styled from 'styled-components'; + +import { Radius } from '../../../foundations'; +import { Flex, FlexProps } from '../../flex'; +import { useProgress } from '../ProgressContext'; + +const StyledFlex = styled(Flex)` + // TODO: Replace with token when available + background-color: ${'rgba(27, 49, 74, 1)'}; + border-radius: ${Radius.radius4}; + width: 100%; + height: 8px; + overflow: hidden; + position: relative; +`; + +export type ProgressTrackProps = FlexProps; + +export const ProgressTrack: React.FC<ProgressTrackProps> = ({ children, ...props }) => { + const { max, min, value } = useProgress(); + return ( + <StyledFlex + $alignItems="center" + role="progressbar" + aria-valuemin={min} + aria-valuemax={max} + aria-valuenow={value} + {...props}> + {children} + </StyledFlex> + ); +}; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/index.ts new file mode 100644 index 0000000000..784071c766 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/components/index.ts @@ -0,0 +1,5 @@ +export * from './ProgressFooter'; +export * from './ProgressPercent'; +export * from './ProgressRange'; +export * from './ProgressText'; +export * from './ProgressTrack'; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/index.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/index.ts new file mode 100644 index 0000000000..1803677d94 --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/progress/index.ts @@ -0,0 +1 @@ +export * from './Progress'; |
