Skip to content

Commit

Permalink
feat(ChangelogDialog): loading state
Browse files Browse the repository at this point in the history
  • Loading branch information
Feverqwe committed Nov 10, 2023
1 parent bc3514b commit 8b891ac
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 14 deletions.
36 changes: 23 additions & 13 deletions src/components/ChangelogDialog/ChangelogDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, {Fragment} from 'react';

import {ArrowUpRightFromSquare} from '@gravity-ui/icons';
import type {DialogProps} from '@gravity-ui/uikit';
Expand All @@ -7,6 +7,7 @@ import {Dialog, Icon, Link} from '@gravity-ui/uikit';
import {block} from '../utils/cn';

import {Item} from './components/Item/Item';
import {ItemSkeleton} from './components/ItemSkeleton/ItemSkeleton';
import i18n from './i18n';
import type {ChangelogItem} from './types';

Expand All @@ -24,6 +25,7 @@ export interface ChangelogDialogProps {
onClose: DialogProps['onClose'];
onLinkClick?: (link: string) => void;
onStoryClick?: (storyId: string) => void;
loading?: boolean;
}

let nextId = 1;
Expand All @@ -41,6 +43,7 @@ export function ChangelogDialog({
onClose,
onStoryClick,
onLinkClick,
loading = true,
}: ChangelogDialogProps) {
const idRef = React.useRef<number>();
idRef.current = idRef.current || getNextId();
Expand All @@ -67,19 +70,26 @@ export function ChangelogDialog({
</Dialog.Body>
) : null}
<Dialog.Body key="items" className={b('items-container')}>
{items.length > 0 ? (
items.map((item, index) => (
<Item
key={index}
className={b('item')}
data={item}
onStoryClick={onStoryClick}
onLinkClick={onLinkClick}
/>
))
) : (
<div className={b('empty-placeholder')}>{i18n('label_empty')}</div>
{loading && (
<Fragment>
<ItemSkeleton className={b('item')} withImage withDescription withLink />
<ItemSkeleton className={b('item')} isNew withDescription withLink />
</Fragment>
)}
{!loading &&
(items.length > 0 ? (
items.map((item, index) => (
<Item
key={index}
className={b('item')}
data={item}
onStoryClick={onStoryClick}
onLinkClick={onLinkClick}
/>
))
) : (
<div className={b('empty-placeholder')}>{i18n('label_empty')}</div>
))}
</Dialog.Body>
</Dialog>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, {useEffect} from 'react';

import {Button} from '@gravity-ui/uikit';
import type {Meta, StoryFn} from '@storybook/react';
Expand Down Expand Up @@ -79,11 +79,22 @@ const items: ChangelogItem[] = [

const DefaultTemplate: StoryFn<ChangelogDialogProps> = (props: ChangelogDialogProps) => {
const [visible, setVisible] = React.useState(props.open);
const [loading, setLoading] = React.useState(true);

React.useEffect(() => {
setVisible(props.open);
}, [props.open]);

useEffect(() => {
if (!visible) return;
const timeoutId = setTimeout(() => setLoading(false), 1000);
// eslint-disable-next-line consistent-return
return () => {
clearTimeout(timeoutId);
setLoading(true);
};
}, [visible]);

return (
<React.Fragment>
<div>
Expand All @@ -98,6 +109,7 @@ const DefaultTemplate: StoryFn<ChangelogDialogProps> = (props: ChangelogDialogPr
<ChangelogDialog
{...props}
open={visible}
loading={loading}
onClose={(event, reason) => {
setVisible(false);
props.onClose?.(event, reason);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
@use '@gravity-ui/uikit/styles/mixins';
@use '../../../variables';

$block: '.#{variables.$ns}changelog-dialog-item';
$metaWidth: 80px;

#{$block} {
display: flex;

&__meta {
width: $metaWidth;
}

&__date {
line-height: var(--g-text-subheader-3-line-height);
}

&__date-skeleton {
width: 80px;
height: 20px;
}

&__label-new-skeleton {
margin-top: var(--g-spacing-2);
width: 42px;
height: 20px;
}

&__content {
flex: 1;
margin-left: var(--g-spacing-5);
}

&__title {
margin: 0;
}

&__title-skeleton {
width: 100%;
height: 20px;
}

&__image-skeleton {
width: 100%;
height: 258px;
margin-top: var(--g-spacing-3);
border-radius: 16px;
}

&__description {
margin-top: var(--g-spacing-3);
}

&__description-skeleton {
width: 100%;
height: 54px;
}

&__button-skeleton {
margin-top: var(--g-spacing-4);
width: 86px;
height: 28px;
}

&__button-skeleton + &__button-skeleton {
margin-left: var(--g-spacing-4);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';

import {Skeleton} from '@gravity-ui/uikit';

import {block} from '../../../utils/cn';

import './ItemSkeleton.scss';

const b = block('changelog-dialog-item');

interface ItemSkeletonProps {
className?: string;
isNew?: boolean;
withImage?: boolean;
withDescription?: boolean;
withLink?: boolean;
withStory?: boolean;
}

export function ItemSkeleton({
className,
withImage,
isNew,
withDescription,
withLink,
withStory,
}: ItemSkeletonProps) {
return (
<article className={b(null, className)}>
<div className={b('meta')}>
<div className={b('date')}>
<Skeleton className={b('date-skeleton')} />
{isNew && <Skeleton className={b('label-new-skeleton')} />}
</div>
</div>
<div className={b('content')}>
<h3 className={b('title')}>
<Skeleton className={b('title-skeleton')} />
</h3>
{withImage && <Skeleton className={b('image-skeleton')} />}
{withDescription && (
<div className={b('description')}>
<Skeleton className={b('description-skeleton')} />
</div>
)}
{withLink && <Skeleton className={b('button-skeleton')} />}
{withStory && <Skeleton className={b('button-skeleton')} />}
</div>
</article>
);
}

0 comments on commit 8b891ac

Please sign in to comment.