Update Backup Media download progress indicator for narrow left panes
Co-authored-by: Jamie Kyle <jamie@signal.org>
This commit is contained in:
parent
cdfd60838c
commit
40e91e96fd
7 changed files with 117 additions and 73 deletions
|
|
@ -4,36 +4,19 @@
|
||||||
@use '../mixins';
|
@use '../mixins';
|
||||||
@use '../variables';
|
@use '../variables';
|
||||||
|
|
||||||
.BackupMediaDownloadProgress {
|
.BackupMediaDownloadProgress__content {
|
||||||
border-radius: 12px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
flex-direction: column;
|
||||||
padding: 11px;
|
justify-content: center;
|
||||||
padding-inline-end: 16px;
|
min-height: 36px;
|
||||||
margin-inline: 10px;
|
margin-inline-end: 20px;
|
||||||
margin-block-end: 6px;
|
gap: 2px;
|
||||||
margin-block-start: 2px;
|
}
|
||||||
user-select: none;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&__title {
|
.BackupMediaDownloadProgress__title {
|
||||||
@include mixins.font-body-2-bold;
|
@include mixins.font-body-2-bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include mixins.light-theme {
|
|
||||||
background-color: variables.$color-white;
|
|
||||||
border: 1px solid variables.$color-gray-20;
|
|
||||||
}
|
|
||||||
@include mixins.dark-theme {
|
|
||||||
background: variables.$color-gray-75;
|
|
||||||
border: 1px solid variables.$color-gray-60;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.BackupMediaDownloadProgress__icon {
|
|
||||||
margin-top: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.BackupMediaDownloadProgress__icon--complete {
|
.BackupMediaDownloadProgress__icon--complete {
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
|
|
@ -89,10 +72,12 @@ button.BackupMediaDownloadProgress__button {
|
||||||
}
|
}
|
||||||
|
|
||||||
button.BackupMediaDownloadProgress__button-more {
|
button.BackupMediaDownloadProgress__button-more {
|
||||||
position: absolute;
|
|
||||||
inset-inline-end: 14px;
|
|
||||||
inset-block-start: 10px;
|
|
||||||
@include mixins.button-reset;
|
@include mixins.button-reset;
|
||||||
|
& {
|
||||||
|
position: absolute;
|
||||||
|
inset-block-start: 8px;
|
||||||
|
inset-inline-end: 14px;
|
||||||
|
}
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
|
|
@ -113,10 +98,12 @@ button.BackupMediaDownloadProgress__button-more {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button.BackupMediaDownloadProgress__button-close {
|
button.BackupMediaDownloadProgress__button-close {
|
||||||
position: absolute;
|
|
||||||
inset-inline-end: 14px;
|
|
||||||
inset-block-start: 10px;
|
|
||||||
@include mixins.button-reset;
|
@include mixins.button-reset;
|
||||||
|
& {
|
||||||
|
position: absolute;
|
||||||
|
inset-block-start: 12px;
|
||||||
|
inset-inline-end: 12px;
|
||||||
|
}
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
|
|
@ -137,14 +124,6 @@ button.BackupMediaDownloadProgress__button-close {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.BackupMediaDownloadProgress__content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 2px;
|
|
||||||
min-height: 36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.BackupMediaDownloadProgress__description {
|
.BackupMediaDownloadProgress__description {
|
||||||
@include mixins.font-subtitle;
|
@include mixins.font-subtitle;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
padding-inline: 16px 14px;
|
padding-inline: 16px 14px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,40 @@ import { action } from '@storybook/addon-actions';
|
||||||
|
|
||||||
import { BackupMediaDownloadProgress } from './BackupMediaDownloadProgress';
|
import { BackupMediaDownloadProgress } from './BackupMediaDownloadProgress';
|
||||||
import { KIBIBYTE } from '../types/AttachmentSize';
|
import { KIBIBYTE } from '../types/AttachmentSize';
|
||||||
|
import { WidthBreakpoint } from './_util';
|
||||||
|
|
||||||
const { i18n } = window.SignalContext;
|
const { i18n } = window.SignalContext;
|
||||||
|
|
||||||
type PropsType = ComponentProps<typeof BackupMediaDownloadProgress>;
|
type PropsType = ComponentProps<typeof BackupMediaDownloadProgress>;
|
||||||
|
|
||||||
|
function Template(args: PropsType): JSX.Element {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div style={{ width: 350 }}>
|
||||||
|
<p>Wide</p>
|
||||||
|
<BackupMediaDownloadProgress
|
||||||
|
{...args}
|
||||||
|
widthBreakpoint={WidthBreakpoint.Wide}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style={{ width: 280 }}>
|
||||||
|
<p>Medium</p>
|
||||||
|
<BackupMediaDownloadProgress
|
||||||
|
{...args}
|
||||||
|
widthBreakpoint={WidthBreakpoint.Medium}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style={{ width: 130 }}>
|
||||||
|
<p>Narrow</p>
|
||||||
|
<BackupMediaDownloadProgress
|
||||||
|
{...args}
|
||||||
|
widthBreakpoint={WidthBreakpoint.Narrow}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'Components/BackupMediaDownloadProgress',
|
title: 'Components/BackupMediaDownloadProgress',
|
||||||
args: {
|
args: {
|
||||||
|
|
@ -27,34 +56,27 @@ export default {
|
||||||
} satisfies Meta<PropsType>;
|
} satisfies Meta<PropsType>;
|
||||||
|
|
||||||
export function InProgress(args: PropsType): JSX.Element {
|
export function InProgress(args: PropsType): JSX.Element {
|
||||||
return <BackupMediaDownloadProgress {...args} />;
|
return <Template {...args} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Increasing(args: PropsType): JSX.Element {
|
export function Increasing(args: PropsType): JSX.Element {
|
||||||
return (
|
return <Template {...args} {...useIncreasingFractionComplete()} />;
|
||||||
<BackupMediaDownloadProgress
|
|
||||||
{...args}
|
|
||||||
{...useIncreasingFractionComplete()}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Paused(args: PropsType): JSX.Element {
|
export function Paused(args: PropsType): JSX.Element {
|
||||||
return <BackupMediaDownloadProgress {...args} isPaused />;
|
return <Template {...args} isPaused />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Idle(args: PropsType): JSX.Element {
|
export function Idle(args: PropsType): JSX.Element {
|
||||||
return <BackupMediaDownloadProgress {...args} isIdle />;
|
return <Template {...args} isIdle />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PausedAndIdle(args: PropsType): JSX.Element {
|
export function PausedAndIdle(args: PropsType): JSX.Element {
|
||||||
return <BackupMediaDownloadProgress {...args} isPaused isIdle />;
|
return <Template {...args} isPaused isIdle />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Complete(args: PropsType): JSX.Element {
|
export function Complete(args: PropsType): JSX.Element {
|
||||||
return (
|
return <Template {...args} downloadedBytes={args.totalBytes} />;
|
||||||
<BackupMediaDownloadProgress {...args} downloadedBytes={args.totalBytes} />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function useIncreasingFractionComplete() {
|
function useIncreasingFractionComplete() {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import { roundFractionForProgressBar } from '../util/numbers';
|
||||||
import { ProgressCircle } from './ProgressCircle';
|
import { ProgressCircle } from './ProgressCircle';
|
||||||
import { ContextMenu } from './ContextMenu';
|
import { ContextMenu } from './ContextMenu';
|
||||||
import { BackupMediaDownloadCancelConfirmationDialog } from './BackupMediaDownloadCancelConfirmationDialog';
|
import { BackupMediaDownloadCancelConfirmationDialog } from './BackupMediaDownloadCancelConfirmationDialog';
|
||||||
|
import { LeftPaneDialog } from './LeftPaneDialog';
|
||||||
|
import { WidthBreakpoint } from './_util';
|
||||||
|
|
||||||
export type PropsType = Readonly<{
|
export type PropsType = Readonly<{
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
|
|
@ -16,6 +18,7 @@ export type PropsType = Readonly<{
|
||||||
totalBytes: number;
|
totalBytes: number;
|
||||||
isIdle: boolean;
|
isIdle: boolean;
|
||||||
isPaused: boolean;
|
isPaused: boolean;
|
||||||
|
widthBreakpoint: WidthBreakpoint;
|
||||||
handleCancel: VoidFunction;
|
handleCancel: VoidFunction;
|
||||||
handleClose: VoidFunction;
|
handleClose: VoidFunction;
|
||||||
handleResume: VoidFunction;
|
handleResume: VoidFunction;
|
||||||
|
|
@ -32,6 +35,7 @@ export function BackupMediaDownloadProgress({
|
||||||
handleClose,
|
handleClose,
|
||||||
handleResume,
|
handleResume,
|
||||||
handlePause,
|
handlePause,
|
||||||
|
widthBreakpoint,
|
||||||
}: PropsType): JSX.Element | null {
|
}: PropsType): JSX.Element | null {
|
||||||
const [isShowingCancelConfirmation, setIsShowingCancelConfirmation] =
|
const [isShowingCancelConfirmation, setIsShowingCancelConfirmation] =
|
||||||
useState(false);
|
useState(false);
|
||||||
|
|
@ -62,7 +66,10 @@ export function BackupMediaDownloadProgress({
|
||||||
let actionButton: JSX.Element | undefined;
|
let actionButton: JSX.Element | undefined;
|
||||||
if (fractionComplete === 1) {
|
if (fractionComplete === 1) {
|
||||||
icon = (
|
icon = (
|
||||||
<div className="BackupMediaDownloadProgress__icon BackupMediaDownloadProgress__icon--complete" />
|
<div
|
||||||
|
className="BackupMediaDownloadProgress__icon BackupMediaDownloadProgress__icon--complete"
|
||||||
|
aria-label={i18n('icu:BackupMediaDownloadProgress__title-complete')}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
content = (
|
content = (
|
||||||
<>
|
<>
|
||||||
|
|
@ -77,7 +84,10 @@ export function BackupMediaDownloadProgress({
|
||||||
actionButton = closeButton;
|
actionButton = closeButton;
|
||||||
} else if (isIdle && !isPaused) {
|
} else if (isIdle && !isPaused) {
|
||||||
icon = (
|
icon = (
|
||||||
<div className="BackupMediaDownloadProgress__icon BackupMediaDownloadProgress__icon--idle" />
|
<div
|
||||||
|
className="BackupMediaDownloadProgress__icon BackupMediaDownloadProgress__icon--idle"
|
||||||
|
aria-label={i18n('icu:BackupMediaDownloadProgress__description-idle')}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
content = (
|
content = (
|
||||||
<>
|
<>
|
||||||
|
|
@ -94,28 +104,34 @@ export function BackupMediaDownloadProgress({
|
||||||
);
|
);
|
||||||
actionButton = closeButton;
|
actionButton = closeButton;
|
||||||
} else {
|
} else {
|
||||||
icon = (
|
|
||||||
<div className="BackupMediaDownloadProgress__icon">
|
|
||||||
<ProgressCircle fractionComplete={fractionComplete} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isPaused) {
|
if (isPaused) {
|
||||||
content = (
|
content = (
|
||||||
<>
|
<>
|
||||||
<div className="BackupMediaDownloadProgress__title">
|
<div className="BackupMediaDownloadProgress__title">
|
||||||
{i18n('icu:BackupMediaDownloadProgress__title-paused')}
|
{i18n('icu:BackupMediaDownloadProgress__title-paused')}
|
||||||
</div>
|
</div>
|
||||||
|
{widthBreakpoint !== WidthBreakpoint.Narrow ? (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleResume}
|
onClick={handleResume}
|
||||||
className="BackupMediaDownloadProgress__button"
|
className="BackupMediaDownloadProgress__button"
|
||||||
aria-label={i18n('icu:BackupMediaDownloadProgress__button-resume')}
|
aria-label={i18n(
|
||||||
|
'icu:BackupMediaDownloadProgress__button-resume'
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{i18n('icu:BackupMediaDownloadProgress__button-resume')}
|
{i18n('icu:BackupMediaDownloadProgress__button-resume')}
|
||||||
</button>
|
</button>
|
||||||
|
) : null}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
icon = (
|
||||||
|
<div className="BackupMediaDownloadProgress__icon">
|
||||||
|
<ProgressCircle
|
||||||
|
fractionComplete={fractionComplete}
|
||||||
|
ariaLabel={i18n('icu:BackupMediaDownloadProgress__title-paused')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
content = (
|
content = (
|
||||||
<>
|
<>
|
||||||
|
|
@ -131,6 +147,16 @@ export function BackupMediaDownloadProgress({
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
icon = (
|
||||||
|
<div className="BackupMediaDownloadProgress__icon">
|
||||||
|
<ProgressCircle
|
||||||
|
fractionComplete={fractionComplete}
|
||||||
|
ariaLabel={i18n(
|
||||||
|
'icu:BackupMediaDownloadProgress__title-in-progress'
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
actionButton = (
|
actionButton = (
|
||||||
|
|
@ -173,10 +199,13 @@ export function BackupMediaDownloadProgress({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="BackupMediaDownloadProgress">
|
<LeftPaneDialog
|
||||||
{icon}
|
type="info"
|
||||||
|
containerWidthBreakpoint={widthBreakpoint}
|
||||||
|
icon={icon}
|
||||||
|
>
|
||||||
<div className="BackupMediaDownloadProgress__content">{content}</div>
|
<div className="BackupMediaDownloadProgress__content">{content}</div>
|
||||||
{actionButton}
|
{widthBreakpoint !== WidthBreakpoint.Narrow ? actionButton : null}
|
||||||
{isShowingCancelConfirmation ? (
|
{isShowingCancelConfirmation ? (
|
||||||
<BackupMediaDownloadCancelConfirmationDialog
|
<BackupMediaDownloadCancelConfirmationDialog
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
|
@ -184,6 +213,6 @@ export function BackupMediaDownloadProgress({
|
||||||
handleConfirmCancel={handleConfirmedCancel}
|
handleConfirmCancel={handleConfirmedCancel}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</LeftPaneDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -801,6 +801,7 @@ export function LeftPane({
|
||||||
{showBackupMediaDownloadProgress ? (
|
{showBackupMediaDownloadProgress ? (
|
||||||
<BackupMediaDownloadProgress
|
<BackupMediaDownloadProgress
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
widthBreakpoint={widthBreakpoint}
|
||||||
{...backupMediaDownloadProgress}
|
{...backupMediaDownloadProgress}
|
||||||
handleClose={dismissBackupMediaDownloadBanner}
|
handleClose={dismissBackupMediaDownloadBanner}
|
||||||
handlePause={pauseBackupMediaDownload}
|
handlePause={pauseBackupMediaDownload}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,12 @@ type Props = React.ComponentProps<typeof ProgressCircle>;
|
||||||
export default {
|
export default {
|
||||||
title: 'Components/ProgressCircle',
|
title: 'Components/ProgressCircle',
|
||||||
component: ProgressCircle,
|
component: ProgressCircle,
|
||||||
args: { fractionComplete: 0, width: undefined, strokeWidth: undefined },
|
args: {
|
||||||
|
fractionComplete: 0,
|
||||||
|
width: undefined,
|
||||||
|
strokeWidth: undefined,
|
||||||
|
ariaLabel: undefined,
|
||||||
|
},
|
||||||
} satisfies ComponentMeta<Props>;
|
} satisfies ComponentMeta<Props>;
|
||||||
|
|
||||||
export function Zero(args: Props): JSX.Element {
|
export function Zero(args: Props): JSX.Element {
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,12 @@ export function ProgressCircle({
|
||||||
fractionComplete,
|
fractionComplete,
|
||||||
width = 24,
|
width = 24,
|
||||||
strokeWidth = 3,
|
strokeWidth = 3,
|
||||||
|
ariaLabel,
|
||||||
}: {
|
}: {
|
||||||
fractionComplete: number;
|
fractionComplete: number;
|
||||||
width?: number;
|
width?: number;
|
||||||
strokeWidth?: number;
|
strokeWidth?: number;
|
||||||
|
ariaLabel?: string;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const radius = width / 2 - strokeWidth / 2;
|
const radius = width / 2 - strokeWidth / 2;
|
||||||
const circumference = radius * 2 * Math.PI;
|
const circumference = radius * 2 * Math.PI;
|
||||||
|
|
@ -21,6 +23,11 @@ export function ProgressCircle({
|
||||||
className="ProgressCircle"
|
className="ProgressCircle"
|
||||||
width={widthInPixels}
|
width={widthInPixels}
|
||||||
height={widthInPixels}
|
height={widthInPixels}
|
||||||
|
role="progressbar"
|
||||||
|
aria-label={ariaLabel}
|
||||||
|
aria-valuenow={Math.trunc(fractionComplete * 100)}
|
||||||
|
aria-valuemin={0}
|
||||||
|
aria-valuemax={100}
|
||||||
>
|
>
|
||||||
<circle
|
<circle
|
||||||
className="ProgressCircle__background"
|
className="ProgressCircle__background"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue