Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add AccordionSkeleton and SkeletonText components #178

Merged
merged 12 commits into from
Feb 13, 2019
Merged
38 changes: 38 additions & 0 deletions src/components/cv-accordion/_cv-accordion-item-skeleton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<template>
<li
class="bx--accordion__item"
:class="{ 'bx--accordion__item--active': open }"
>
<button type="button" class="bx--accordion__heading">
<svg
class="bx--accordion__arrow"
width="8"
height="12"
viewBox="0 0 8 12"
fill-rule="evenodd"
>
<path d="M0 10.6L4.7 6 0 1.4 1.4 0l6.1 6-6.1 6z"></path>
</svg>
<cv-skeleton-text class="bx--accordion__title"></cv-skeleton-text>
</button>
<div class="bx--accordion__content">
<slot></slot>
</div>
</li>
</template>

<script>
import CvSkeletonText from '../cv-skeleton-text/cv-skeleton-text';

export default {
name: 'CvAccordionItemSkeleton',
components: {
CvSkeletonText,
},
props: {
open: { type: Boolean, default: false },
},
};
</script>

<style lang="scss"></style>
27 changes: 27 additions & 0 deletions src/components/cv-accordion/cv-accordion-skeleton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<template>
<ul class="bx--accordion bx--skeleton">
<cv-accordion-item-skeleton :open="true">
<cv-skeleton-text width="90%"></cv-skeleton-text>
<cv-skeleton-text width="80%"></cv-skeleton-text>
<cv-skeleton-text width="95%"></cv-skeleton-text>
</cv-accordion-item-skeleton>
<cv-accordion-item-skeleton></cv-accordion-item-skeleton>
<cv-accordion-item-skeleton></cv-accordion-item-skeleton>
<cv-accordion-item-skeleton></cv-accordion-item-skeleton>
</ul>
</template>

<script>
import CvSkeletonText from '../cv-skeleton-text/cv-skeleton-text';
import CvAccordionItemSkeleton from './_cv-accordion-item-skeleton';

export default {
name: 'CvAccordionSkeleton',
components: {
CvSkeletonText,
CvAccordionItemSkeleton,
},
};
</script>

<style lang="scss"></style>
21 changes: 21 additions & 0 deletions src/components/cv-accordion/cv-accordion-story.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import knobsHelper from '../../_storybook/utils/knobs-helper';
import CvAccordionNotesMD from './cv-accordion-notes.md';
import CvAccordion from './cv-accordion';
import CvAccordionItem from './cv-accordion-item';
import CvAccordionSkeleton from './cv-accordion-skeleton';

const stories = storiesOf('CvAccordion', module);
stories.addDecorator(withKnobs).addDecorator(withNotes);
Expand Down Expand Up @@ -117,3 +118,23 @@ for (const story of storySet) {
}
);
}

const templateString = `<cv-accordion-skeleton></cv-accordion-skeleton>`;
stories.add(
'skeleton',
() => ({
components: { SvTemplateView, CvAccordionSkeleton },
template: `
<sv-template-view
sv-margin
sv-position="center"
sv-source='${templateString.trim()}'>
<template slot="component">${templateString}</template>
</sv-template-view>
`,
props: {},
}),
{
notes: { markdown: CvAccordionNotesMD },
}
);
21 changes: 21 additions & 0 deletions src/components/cv-skeleton-text/cv-skeleton-text-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# CvSkeletonText

A utility component that used as a progressive loading state while the user waits for content to load.

## Usage

```html
<cv-skeleton-text
:heading="true"
:width="90%"
:paragraph="true"
:lineCount="3"
></cv-skeleton-text>
```

## Attributes

- heading: generates skeleton text at a larger size. Optional. Default - false.
- width: width (in px or %) of single line of text or max-width of paragraph lines. Optional. Default - 100%.
- paragraph: will generate multiple lines of text. Optional. Default - false.
- lineCount: the number of lines in a paragraph. Optional. Default - 3.
90 changes: 90 additions & 0 deletions src/components/cv-skeleton-text/cv-skeleton-text-story.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { storiesOf } from '@storybook/vue';
import { withKnobs, boolean, text, number } from '@storybook/addon-knobs';
import { withNotes } from '@storybook/addon-notes';

import SvTemplateView from '../../_storybook/views/sv-template-view/sv-template-view';
import knobsHelper from '../../_storybook/utils/knobs-helper';

import CvSkeletonTextNotesMD from './cv-skeleton-text-notes.md';
import CvSkeletonText from './cv-skeleton-text';

const stories = storiesOf('CvSkeletonText', module);
stories.addDecorator(withKnobs);
stories.addDecorator(withNotes);

const preKnobs = {
heading: {
group: 'attr',
type: boolean,
config: ['Skeleton text at a larger size (heading)', false], // consts.CONFIG
prop: {
name: 'heading',
type: Boolean,
},
},
paragraph: {
group: 'attr',
type: boolean,
config: ['Use multiple lines of text (paragraph)', false], // consts.CONFIG
prop: {
name: 'paragraph',
type: Boolean,
},
},
lineCount: {
group: 'attr',
type: number,
config: ['The number of lines in a paragraph (lineCount)', 3],
prop: { name: 'line-count', type: Number },
},
width: {
group: 'attr',
type: text,
config: [
'Width (in px or %) of single line of text or max-width of paragraph lines (width)',
'100%',
], // consts.CONFIG
prop: { name: 'width', type: String },
},
};

const variants = [
{ name: 'default' },
{ name: 'minimal', excludes: ['heading', 'width', 'paragraph', 'lineCount'] },
];

const storySet = knobsHelper.getStorySet(variants, preKnobs);

for (const story of storySet) {
stories.add(
story.name,
() => {
const settings = story.knobs();

// ----------------------------------------------------------------

const templateString = `
<cv-skeleton-text${settings.group.attr}></cv-skeleton-text>
`;

// ----------------------------------------------------------------

const templateViewString = `
<sv-template-view
sv-margin
sv-source='${templateString.trim()}'>
<template slot="component">${templateString}</template>
</sv-template-view>
`;

return {
components: { CvSkeletonText, SvTemplateView },
template: templateViewString,
props: settings.props,
};
},
{
notes: { markdown: CvSkeletonTextNotesMD },
}
);
}
65 changes: 65 additions & 0 deletions src/components/cv-skeleton-text/cv-skeleton-text.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<template>
<div :style="{ width: width }">
<p
class="bx--skeleton__text"
:class="{ 'bx--skeleton__heading': heading }"
:style="{ width: line.width }"
:key="index"
v-for="(line, index) in lines"
></p>
</div>
</template>

<script>
export default {
name: 'CvSkeletonText',
props: {
width: { type: String, default: '100%' },
heading: { type: Boolean, default: false },
lineCount: { type: Number, default: 3 },
paragraph: { type: Boolean, default: false },
},
methods: {
getRandomInt: function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
},
calcWidth: function() {
let width = this.width;
if (this.paragraph) {
const { num, unit } = this.widthObj;
if (unit === '%') {
const randomWidth = this.getRandomInt(0, 75) + 'px';
width = `calc(${width} - ${randomWidth})`;
} else if (unit === 'px') {
width = this.getRandomInt(num - 75, num) + 'px';
}
}
return width;
},
},
computed: {
widthObj: function() {
const widthObj = { num: parseInt(this.width, 10) };
if (this.width.includes('px')) {
widthObj.unit = 'px';
}
if (this.width.includes('%')) {
widthObj.unit = '%';
}
return widthObj;
},
lines: function() {
return Array.from(
{
length: this.paragraph ? this.lineCount : 1,
},
() => ({
width: this.calcWidth(),
})
);
},
},
};
</script>

<style lang="scss"></style>