Skip to content

Commit

Permalink
Merge pull request #559 from lumapps/feat/skeleton
Browse files Browse the repository at this point in the history
feat(skeleton): create circle, rectangular and typography variants
  • Loading branch information
gcornut authored Dec 11, 2020
2 parents 3ccb380 + d7b4486 commit c0b87aa
Show file tree
Hide file tree
Showing 14 changed files with 616 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Added `headerActions` prop to `CommentBlock` component to add actions to the header.
- Added `SkeletonRectangle`, `SkeletonCircle` and `SkeletonTypography` components.

### Fixed

Expand Down
123 changes: 123 additions & 0 deletions packages/lumx-core/src/scss/components/skeleton/lumapps/_index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/* ==========================================================================
Skeleton
========================================================================== */

@keyframes skeleton-loading {
0% {
opacity: 1;
}
50% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}

/* Circle
========================================================================== */

.#{$lumx-base-prefix}-skeleton-circle {
animation: skeleton-loading 1s ease-in-out 0s infinite;
border-radius: 50%;

&--theme-light {
background-color: lumx-color-variant('dark', 'L5');
}

&--theme-dark {
background-color: lumx-color-variant('light', 'L5');
}
}

@each $key, $size in $lumx-sizes {
.#{$lumx-base-prefix}-skeleton-circle--size-#{$key} {
width: map-get($lumx-sizes, $key);
height: map-get($lumx-sizes, $key);
}
}

/* Rectangle
========================================================================== */

.#{$lumx-base-prefix}-skeleton-rectangle {
animation: skeleton-loading 1s ease-in-out 0s infinite;

&--variant-rounded {
border-radius: $lumx-border-radius;
}

&--theme-light {
background-color: lumx-color-variant('dark', 'L5');
}

&--theme-dark {
background-color: lumx-color-variant('light', 'L5');
}
}

@each $key, $size in $lumx-sizes {
.#{$lumx-base-prefix}-skeleton-rectangle--width-#{$key} {
width: map-get($lumx-sizes, $key);
}

.#{$lumx-base-prefix}-skeleton-rectangle--height-#{$key} {
height: map-get($lumx-sizes, $key);
}

.#{$lumx-base-prefix}-skeleton-rectangle--variant-pill.#{$lumx-base-prefix}-skeleton-rectangle--height-#{$key} {
border-radius: map-get($lumx-sizes, $key) / 2;
}
}

@each $key, $aspect-ratio in $lumx-thumbnail-aspect-ratio {
.#{$lumx-base-prefix}-skeleton-rectangle--aspect-ratio-#{$key} .#{$lumx-base-prefix}-skeleton-rectangle__inner {
padding-top: $aspect-ratio;
}
}

/* Typography
========================================================================== */

$typography-skeleton-size: (
'display1': 24px,
'headline': 20px,
'title': 14px,
'subtitle2': 12px,
'subtitle1': 10px,
'body2': 12px,
'body1': 10px,
'caption': 8px,
'overline': 8px,
);

.#{$lumx-base-prefix}-skeleton-typography {
$self: &;

display: flex;
align-items: center;

&__inner {
width: 100%;
animation: skeleton-loading 1s ease-in-out 0s infinite;
border-radius: $lumx-border-radius;

#{$self}--theme-light & {
background-color: lumx-color-variant('dark', 'L5');
}

#{$self}--theme-dark & {
background-color: lumx-color-variant('light', 'L5');
}
}
}

@each $key, $line-height in $lumx-typography-line-height {
.#{$lumx-base-prefix}-skeleton-typography--typography-#{$key} {
height: map-get($lumx-typography-line-height, $key);
}

.#{$lumx-base-prefix}-skeleton-typography--typography-#{$key} .#{$lumx-base-prefix}-skeleton-typography__inner {
height: map-get($typography-skeleton-size, $key);
}
}
1 change: 1 addition & 0 deletions packages/lumx-core/src/scss/lumx-theme-lumapps.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
@import './components/radio-button/lumapps/index';
@import './components/select/lumapps/index';
@import './components/side-navigation/lumapps/index';
@import './components/skeleton/lumapps/index';
@import './components/slideshow/lumapps/index';
@import './components/slider/lumapps/index';
@import './components/switch/lumapps/index';
Expand Down
16 changes: 16 additions & 0 deletions packages/lumx-react/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ enum Size {
big = 'big',
huge = 'huge',
}
export type GlobalSize = Size.xxs | Size.xs | Size.s | Size.m | Size.l | Size.xl | Size.xxl;

enum Orientation {
horizontal = 'horizontal',
Expand All @@ -81,6 +82,21 @@ enum Emphasis {
high = 'high',
}

/**
* List of typographies.
*/
export enum Typography {
overline = 'overline',
caption = 'caption',
body1 = 'body1',
body2 = 'body2',
subtitle1 = 'subtitle1',
subtitle2 = 'subtitle2',
title = 'title',
headline = 'headline',
display1 = 'display1',
}

/**
* All available aspect ratios.
*/
Expand Down
116 changes: 116 additions & 0 deletions packages/lumx-react/src/components/skeleton/Skeleton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React, { useEffect, useState } from 'react';

import {
Alignment,
AspectRatio,
Button,
FlexBox,
Orientation,
Size,
SkeletonCircle,
SkeletonRectangle,
SkeletonRectangleVariant,
SkeletonTypography,
Thumbnail,
Typography,
} from '@lumx/react';

export default { title: 'LumX components/skeleton/Skeleton' };

const variants = [
SkeletonRectangleVariant.squared,
SkeletonRectangleVariant.rounded,
SkeletonRectangleVariant.pill,
] as const;
const sizes = [Size.xxs, Size.xs, Size.s, Size.m, Size.l, Size.xl, Size.xxl] as const;
const aspectRatios = [AspectRatio.vertical, AspectRatio.square, AspectRatio.horizontal] as const;

export const skeletonCircle = ({ theme }: any) => (
<FlexBox orientation={Orientation.horizontal}>
{sizes.map((size) => (
<SkeletonCircle theme={theme} key={size} size={size} className="lumx-spacing-margin" />
))}
</FlexBox>
);

export const skeletonRectangle = ({ theme }: any) => (
<>
Sizes:
<FlexBox orientation={Orientation.horizontal}>
{sizes.map((size) => (
<SkeletonRectangle
key={size}
className="lumx-spacing-margin"
theme={theme}
height={size}
width={size}
/>
))}
</FlexBox>
Variants:
<FlexBox orientation={Orientation.horizontal}>
{variants.map((variant) => (
<SkeletonRectangle
key={variant}
className="lumx-spacing-margin"
theme={theme}
width={Size.xl}
height={Size.m}
variant={variant}
/>
))}
</FlexBox>
Ratios:
<FlexBox orientation={Orientation.horizontal} hAlign={Alignment.top}>
{aspectRatios.map((aspectRatio) => (
<SkeletonRectangle
key={aspectRatio}
className="lumx-spacing-margin"
theme={theme}
width={Size.xl}
aspectRatio={aspectRatio}
/>
))}
</FlexBox>
</>
);

export const skeletonTypography = ({ theme }: any) => (
<>
<SkeletonTypography
theme={theme}
typography={Typography.title}
width="30%"
className="lumx-spacing-margin-bottom"
/>
<SkeletonTypography theme={theme} typography={Typography.body1} />
<SkeletonTypography theme={theme} typography={Typography.body1} />
<SkeletonTypography theme={theme} typography={Typography.body1} />
<SkeletonTypography theme={theme} typography={Typography.body1} width="70%" />
</>
);

export const skeletonRectangleLoadingThumbnail = ({ theme }: any) => {
const [loading, setLoading] = useState(true);
const fakeLoad = () => {
setLoading(true);
setTimeout(() => {
setLoading(false);
}, 2000);
};
useEffect(fakeLoad, []);
const size = Size.xl;

return (
<>
<Button onClick={fakeLoad}>Reload</Button> (fake 2sec loading)
<Thumbnail
style={{ display: loading ? 'none' : undefined }}
image="https://picsum.photos/72/72/?random"
aspectRatio={AspectRatio.square}
size={size}
/>
{loading && <SkeletonRectangle theme={theme} width={size} aspectRatio={AspectRatio.square} />}
</>
);
};
38 changes: 38 additions & 0 deletions packages/lumx-react/src/components/skeleton/SkeletonCircle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import classNames from 'classnames';
import React from 'react';

import { GlobalSize, Theme } from '@lumx/react';
import { COMPONENT_PREFIX } from '@lumx/react/constants';
import { GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';

/**
* Defines the props of the component.
*/
interface SkeletonCircleProps extends GenericProps {
/** The size variant of the component. */
size: GlobalSize;
/** Theme. */
theme?: Theme;
}

/**
* The display name of the component.
*/
const COMPONENT_NAME = `${COMPONENT_PREFIX}SkeletonCircle`;

/**
* The default class name and classes prefix for this component.
*/
const CLASSNAME: string = getRootClassName(COMPONENT_NAME);

const SkeletonCircle: React.FC<SkeletonCircleProps> = ({ className, size, theme, ...forwardedProps }) => {
return (
<div
{...forwardedProps}
className={classNames(className, handleBasicClasses({ prefix: CLASSNAME, size, theme }))}
/>
);
};
SkeletonCircle.displayName = COMPONENT_NAME;

export { CLASSNAME, COMPONENT_NAME, SkeletonCircle, SkeletonCircleProps };
Loading

0 comments on commit c0b87aa

Please sign in to comment.