Skip to content
Permalink
Browse files

Merge pull request #3076 from salesforce-ux/feature/welcome-mat

feat(welcome-mat): add welcome mat component, docs, and tests
  • Loading branch information...
zahnster committed Feb 15, 2018
2 parents 73989b0 + d8eee45 commit 5d2d8187b1741a3ba9d7bd17ff8895aeab52a352
Showing with 7,146 additions and 18 deletions.
  1. BIN assets/images/welcome-mat/bg-info@2x.png
  2. BIN assets/images/welcome-mat/trailhead_badge@2x.png
  3. +1,408 −0 test/__tests__/__snapshots__/Welcome_Mat_Base.json
  4. +1,408 −0 test/__tests__/__snapshots__/Welcome_Mat_Partially_Completed_Steps.json
  5. +1,528 −0 test/__tests__/__snapshots__/Welcome_Mat_Trailhead.json
  6. +1,470 −0 test/__tests__/__snapshots__/Welcome_Mat_Trailhead_Complete.json
  7. +5 −1 ui/components/_index.scss
  8. +24 −17 ui/components/visual-picker/link/example.jsx
  9. +52 −0 ui/components/welcome-mat/WelcomeMatContent.jsx
  10. +90 −0 ui/components/welcome-mat/WelcomeMatContentTrailhead.jsx
  11. +61 −0 ui/components/welcome-mat/WelcomeMatTile.jsx
  12. +98 −0 .../__tests__/__snapshots__/Welcome_Mat_Snapshots_renders_a_completed_trailhead_with_correct_UI.json
  13. +100 −0 ...ts/welcome-mat/__tests__/__snapshots__/Welcome_Mat_Snapshots_renders_a_trailhead_welcome_mat.json
  14. +93 −0 ui/components/welcome-mat/__tests__/__snapshots__/Welcome_Mat_Snapshots_renders_a_welcome_mat.json
  15. +93 −0 ...mat/__tests__/__snapshots__/Welcome_Mat_Snapshots_renders_a_welcome_mat_with_completed_steps.json
  16. +117 −0 ui/components/welcome-mat/__tests__/enzyme.spec.js
  17. +22 −0 ui/components/welcome-mat/__tests__/snapshot.spec.js
  18. +18 −0 ui/components/welcome-mat/_doc.scss
  19. +199 −0 ui/components/welcome-mat/base/_index.scss
  20. +15 −0 ui/components/welcome-mat/base/example.jsx
  21. +58 −0 ui/components/welcome-mat/docs.mdx
  22. +111 −0 ui/components/welcome-mat/index.jsx
  23. +42 −0 ui/components/welcome-mat/tokens/color.yml
  24. +14 −0 ui/components/welcome-mat/tokens/font-size.yml
  25. +27 −0 ui/components/welcome-mat/tokens/sizing.yml
  26. +20 −0 ui/components/welcome-mat/tokens/spacing.yml
  27. +58 −0 ui/components/welcome-mat/trailhead-connected/_index.scss
  28. +15 −0 ui/components/welcome-mat/trailhead-connected/example.jsx
Binary file not shown.
Binary file not shown.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -239,4 +239,8 @@
'regions/base/index',

// Vertical Tabs
'vertical-tabs/base/index';
'vertical-tabs/base/index',

// Welcome Mat
'welcome-mat/base/index',
'welcome-mat/trailhead-connected/index';
@@ -10,30 +10,37 @@ import { UtilityIcon } from '../../icons/base/example';
// Partial(s)
/// ////////////////////////////////////////

export let VisualPickerMediaObject = props => (
<a
href="javascript:void(0);"
className={classNames(
'slds-box slds-box_link slds-box_x-small slds-media',
props.className
)}
>
<div className="slds-media__figure slds-media__figure_fixed-width slds-align_absolute-center slds-m-left_xx-small">
<UtilityIcon className="slds-icon-text-default" symbol="knowledge_base" />
</div>
<div className="slds-media__body slds-border_left slds-p-around_small">
{props.children}
</div>
</a>
);
export let VisualPickerMediaObject = props => {
const symbol = props.symbol || 'knowledge_base';
const iconContent = props.icon || (
<UtilityIcon className="slds-icon-text-default" symbol={symbol} />
);

return (
<a
href="javascript:void(0);"
className={classNames(
'slds-box slds-box_link slds-box_x-small slds-media',
props.className
)}
>
<div className="slds-media__figure slds-media__figure_fixed-width slds-align_absolute-center slds-m-left_xx-small">
{iconContent}
</div>
<div className="slds-media__body slds-border_left slds-p-around_small">
{props.children}
</div>
</a>
);
};

/// ////////////////////////////////////////
// Export
/// ////////////////////////////////////////

export default (
<div className="demo-only" style={{ width: '24rem' }}>
<VisualPickerMediaObject symbol="user">
<VisualPickerMediaObject symbol="knowledge_base">
<h2
className="slds-truncate slds-text-heading_small"
title="Share the knowledge"
@@ -0,0 +1,52 @@
// Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license

import React from 'react';
import PropTypes from 'prop-types';
import { ProgressBar } from '../progress-bar/base/example';

class WelcomeMatContent extends React.Component {
render() {
const { complete, total, labelId } = this.props;
const completePercent = complete / total * 100;

return (
<div>
<h2 id={labelId} className="slds-welcome-mat__info-title">
Empower Your Agents with Service Cloud
</h2>
<p className="slds-welcome-mat__info-description">
Your 30-day trial is under way. Learn how easy it is to use and set up
Lightning Service Desk. You'll be your company's service expert by the
time you're done!
</p>

<div className="slds-welcome-mat__info-progress">
<p>
<strong>
{complete}/{total} Walkthroughs completed
</strong>
</p>
</div>
<ProgressBar
value={completePercent}
className="slds-progress-bar_circular"
/>
</div>
);
}
}

WelcomeMatContent.propTypes = {
complete: PropTypes.number.isRequired,
total: PropTypes.number.isRequired,
labelId: PropTypes.string.isRequired
};

WelcomeMatContent.defaultProps = {
complete: 0,
total: 5,
labelId: 'welcome-mat-label-1'
};

export default WelcomeMatContent;
@@ -0,0 +1,90 @@
// Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license

import React from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';

import { ProgressBar } from '../progress-bar/base/example';
import { Button } from '../buttons/base/example';
import { ActionIcon } from '../icons/action/example';

class WelcomeMatContentTrailhead extends React.Component {
render() {
const { complete, total, labelId } = this.props;
const completePercent = complete / total * 100;
const isComplete = completePercent === 100;

const badgeProgressMessage = isComplete ? (
<p>Cha-ching! You earned the badge.</p>
) : (
<p>
{complete} of {total} modules completed
</p>
);

return (
<div>
<h2 id={labelId} className="slds-welcome-mat__info-title">
Hey there, Trailblazer!
</h2>
<p className="slds-welcome-mat__info-description">
Your 30-day trial is under way. Learn how easy it is to use and set up
Lightning Service Desk. You'll be your company's service expert by the
time you're done!
</p>

<div
className={classNames('slds-welcome-mat__info-progress', {
'slds-welcome-mat__info-progress_complete': isComplete
})}
>
<div className="slds-welcome-mat__info-badge-container">
<img
className="slds-welcome-mat__info-badge"
src="/assets/images/welcome-mat/trailhead_badge@2x.png"
width="50"
height="50"
alt=""
/>
<ActionIcon
title="Completed"
assistiveText="Completed"
className="slds-welcome-mat__icon-check slds-icon_xx-small"
symbol="check"
/>
</div>
<p>
<strong>Essentials Explorer</strong>
</p>
{badgeProgressMessage}
</div>

{isComplete ? (
<Button className="slds-button slds-button_brand">
View on your Trailblazer Profile
</Button>
) : (
<ProgressBar
value={completePercent}
className="slds-progress-bar_circular"
/>
)}
</div>
);
}
}

WelcomeMatContentTrailhead.propTypes = {
complete: PropTypes.number.isRequired,
total: PropTypes.number.isRequired,
labelId: PropTypes.string.isRequired
};

WelcomeMatContentTrailhead.defaultProps = {
complete: 0,
total: 5,
labelId: 'welcome-mat-label-1'
};

export default WelcomeMatContentTrailhead;
@@ -0,0 +1,61 @@
// Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license

import React from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';

import { VisualPickerMediaObject } from '../visual-picker/link/example';
import { UtilityIcon } from '../icons/base/example';
import { ActionIcon } from '../icons/action/example';

class WelcomeMatTile extends React.Component {
render() {
const { tile, completed } = this.props;
const className = classNames('slds-welcome-mat__tile', {
'slds-welcome-mat__tile_complete': completed
});

return (
<VisualPickerMediaObject
symbol={tile.symbol}
className={className}
icon={
<div className="slds-welcome-mat__tile-icon-container">
<UtilityIcon
className="slds-icon-text-default"
symbol={tile.symbol}
title={false}
assistiveText={false}
/>
<ActionIcon
title="Completed"
assistiveText="Completed"
className="slds-welcome-mat__icon-check"
symbol="check"
/>
</div>
}
>
<h3 className="slds-welcome-mat__tile-title">{tile.title}</h3>
<p className="slds-welcome-mat__tile-description">{tile.description}</p>
</VisualPickerMediaObject>
);
}
}

WelcomeMatTile.propTypes = {
tile: PropTypes.object.isRequired,
completed: PropTypes.bool.isRequired
};

WelcomeMatTile.defaultProps = {
tile: {
symbol: 'animal_and_nature',
title: 'Welcome to Salesforce!',
description: 'Lorem ipsum dolor sit amet, lorem ipsum dolor.'
},
completed: false
};

export default WelcomeMatTile;

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,117 @@
// Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license
/* eslint-env jest */

import React from 'react';
import ReactDOM from 'react-dom';
import { shallow, render } from 'enzyme';

import WelcomeMat from '../';
import WelcomeMatTile from '../WelcomeMatTile';
import WelcomeMatContent from '../WelcomeMatContent';
import WelcomeMatContentTrailhead from '../WelcomeMatContentTrailhead';

describe('Welcome Mat', () => {
it('renders without crashing', () => {
ReactDOM.render(<WelcomeMat />, document.createElement('div'));
});

it('correctly renders the desired amount of completed steps', () => {
const completeCount = 3;
const rendered = render(<WelcomeMat complete={completeCount} />);

expect(rendered.find('.slds-welcome-mat__tile_complete')).toHaveLength(
completeCount
);
});
});

describe('Welcome Mat Tile', () => {
it('renders a tile without crashing', () => {
ReactDOM.render(<WelcomeMatTile />, document.createElement('div'));
});

it('correctly adds default tile content', () => {
const rendered = render(<WelcomeMatTile />);
expect(rendered.find('.slds-icon-utility-animal_and_nature').length).toBe(
1
);
expect(rendered.find('.slds-welcome-mat__tile-title').text()).toBe(
'Welcome to Salesforce!'
);
expect(rendered.find('.slds-welcome-mat__tile-description').text()).toBe(
'Lorem ipsum dolor sit amet, lorem ipsum dolor.'
);
});

it('correctly applies completed prop', () => {
const rendered = shallow(<WelcomeMatTile completed />);
expect(rendered.find('.slds-welcome-mat__tile_complete').exists()).toBe(
true
);
});
});

describe('Welcome Mat Content', () => {
const complete = 3;
const total = 5;
const completePercent = complete / total * 100;
const example = render(
<WelcomeMatContent complete={complete} total={total} />
);

it('renders without crashing', () => {
ReactDOM.render(<WelcomeMatContent />, document.createElement('div'));
});

it('correctly implements completed count props', () => {
expect(example.find('strong').html()).toBe(
`${complete}/${total} Walkthroughs completed`
);
});

it('shows the correct progress bar progress', () => {
expect(example.find('.slds-progress-bar__value').attr('style')).toBe(
`width:${completePercent}%;`
);
});
});

describe('Welcome Mat Trailhead Content', () => {
const shallowNew = shallow(<WelcomeMatContentTrailhead />);
const shallowComplete = shallow(
<WelcomeMatContentTrailhead complete={5} total={5} />
);

it('renders without crashing', () => {
ReactDOM.render(
<WelcomeMatContentTrailhead />,
document.createElement('div')
);
});

it('shows the correct initial progress', () => {
const initialText = ['Essentials Explorer', '0 of 5 modules completed'];

shallowNew.find('.slds-welcome-mat__info-progress p').forEach((p, pi) => {
expect(p.text()).toBe(initialText[pi]);
});
});

it('shows the correct completed message', () => {
const completedText = [
'Essentials Explorer',
'Cha-ching! You earned the badge.'
];

shallowComplete
.find('.slds-welcome-mat__info-progress p')
.forEach((p, pi) => {
expect(p.text()).toBe(completedText[pi]);
});
});

it('renders a button when complete', () => {
expect(shallowComplete.find('.slds-button').exists()).toBe(true);
});
});
Oops, something went wrong.

0 comments on commit 5d2d818

Please sign in to comment.
You can’t perform that action at this time.