Added onboarding
This commit is contained in:
parent
1d07edd252
commit
da3e6b4780
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* The type of (redux) action that continues the onboarding by processing
|
||||
* the next step.
|
||||
*
|
||||
* {
|
||||
* type: CONTINUE_ONBOARDING
|
||||
* }
|
||||
*/
|
||||
export const CONTINUE_ONBOARDING = Symbol('CONTINUE_ONBOARDING');
|
||||
|
||||
/**
|
||||
* The type of (redux) action that sets active onboarding.
|
||||
*
|
||||
* {
|
||||
* type: SET_ACTIVE_ONBOARDING,
|
||||
* name: string,
|
||||
* section: string
|
||||
* }
|
||||
*/
|
||||
export const SET_ACTIVE_ONBOARDING = Symbol('SET_ACTIVE_ONBOARDING');
|
||||
|
||||
/**
|
||||
* The type of (redux) action that starts Onboarding.
|
||||
*
|
||||
* {
|
||||
* type: START_ONBOARDING,
|
||||
* section: string
|
||||
* }
|
||||
*/
|
||||
export const START_ONBOARDING = Symbol('START_ONBOARDING');
|
||||
|
||||
/**
|
||||
* The type of (redux) action that skips all onboarding.
|
||||
*
|
||||
* {
|
||||
* type: SKIP_ONBOARDING
|
||||
* }
|
||||
*/
|
||||
export const SKIP_ONBOARDING = Symbol('SKIP_ONBOARDING');
|
|
@ -0,0 +1,70 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
CONTINUE_ONBOARDING,
|
||||
SET_ACTIVE_ONBOARDING,
|
||||
SKIP_ONBOARDING,
|
||||
START_ONBOARDING
|
||||
} from './actionTypes';
|
||||
|
||||
/**
|
||||
* Continues the onboarding procedure by activating the next step of the current
|
||||
* section.
|
||||
*
|
||||
* @returns {{
|
||||
* type: CONTINUE_ONBOARDING
|
||||
* }}
|
||||
*/
|
||||
export function continueOnboarding() {
|
||||
return {
|
||||
type: CONTINUE_ONBOARDING
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set active onboarding.
|
||||
*
|
||||
* @param {string} name - Name of onboarding component.
|
||||
* @param {string} section - Onboarding section.
|
||||
* @returns {{
|
||||
* type: SET_ACTIVE_ONBOARDING,
|
||||
* name: string,
|
||||
* section: string
|
||||
* }}
|
||||
*/
|
||||
export function setActiveOnboarding(name: string, section: string) {
|
||||
return {
|
||||
type: SET_ACTIVE_ONBOARDING,
|
||||
name,
|
||||
section
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips onboarding.
|
||||
*
|
||||
* @returns {{
|
||||
* type: SKIP_ONBOARDING
|
||||
* }}
|
||||
*/
|
||||
export function skipOnboarding() {
|
||||
return {
|
||||
type: SKIP_ONBOARDING
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Start onboarding.
|
||||
*
|
||||
* @param {string} section - Onboarding section.
|
||||
* @returns {{
|
||||
* type: START_ONBOARDING,
|
||||
* section: string
|
||||
* }}
|
||||
*/
|
||||
export function startOnboarding(section: string) {
|
||||
return {
|
||||
type: START_ONBOARDING,
|
||||
section
|
||||
};
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// @flow
|
||||
|
||||
import { Spotlight } from '@atlaskit/onboarding';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { continueOnboarding } from '../actions';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Redux dispatch.
|
||||
*/
|
||||
dispatch: Dispatch<*>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Conference URL Spotlight Component.
|
||||
*/
|
||||
class ConferenceURLSpotlight extends Component<Props, *> {
|
||||
/**
|
||||
* Initializes a new {@code ComponentURLSpotlight} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this._next = this._next.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render function of component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<Spotlight
|
||||
actions = { [
|
||||
{
|
||||
onClick: this._next,
|
||||
text: 'Next'
|
||||
}
|
||||
] }
|
||||
dialogPlacement = 'bottom center'
|
||||
target = { 'conference-url' } >
|
||||
Enter the name (or full URL) of the room you want to join. You
|
||||
may make a name up, just let others know so they enter the same
|
||||
name.
|
||||
</Spotlight>
|
||||
);
|
||||
}
|
||||
|
||||
_next: (*) => void;
|
||||
|
||||
/**
|
||||
* Close the spotlight component.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_next() {
|
||||
this.props.dispatch(continueOnboarding());
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(ConferenceURLSpotlight);
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// @flow
|
||||
|
||||
import { Spotlight } from '@atlaskit/onboarding';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { continueOnboarding } from '../actions';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Redux dispatch.
|
||||
*/
|
||||
dispatch: Dispatch<*>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Email Setting Spotlight Component.
|
||||
*/
|
||||
class EmailSettingSpotlight extends Component<Props, *> {
|
||||
/**
|
||||
* Initializes a new {@code EmailSettingSpotlight} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this._next = this._next.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render function of component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<Spotlight
|
||||
actions = { [
|
||||
{
|
||||
onClick: this._next,
|
||||
text: 'Next'
|
||||
}
|
||||
] }
|
||||
dialogPlacement = 'left top'
|
||||
target = { 'email-setting' } >
|
||||
The email you enter here will be part of your user profile and
|
||||
it will be used to display your stored avatar in gravatar.com .
|
||||
</Spotlight>
|
||||
);
|
||||
}
|
||||
|
||||
_next: (*) => void;
|
||||
|
||||
/**
|
||||
* Close the spotlight component.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_next() {
|
||||
this.props.dispatch(continueOnboarding());
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(EmailSettingSpotlight);
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// @flow
|
||||
|
||||
import { Spotlight } from '@atlaskit/onboarding';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { continueOnboarding } from '../actions';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Redux dispatch.
|
||||
*/
|
||||
dispatch: Dispatch<*>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Name Setting Spotlight Component.
|
||||
*/
|
||||
class NameSettingSpotlight extends Component<Props, *> {
|
||||
/**
|
||||
* Initializes a new {@code NameSettingSpotlight} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this._next = this._next.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render function of component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<Spotlight
|
||||
actions = { [
|
||||
{
|
||||
onClick: this._next,
|
||||
text: 'Next'
|
||||
}
|
||||
] }
|
||||
dialogPlacement = 'left top'
|
||||
target = { 'name-setting' } >
|
||||
This will be your display name, others will see you with this
|
||||
name.
|
||||
</Spotlight>
|
||||
);
|
||||
}
|
||||
|
||||
_next: (*) => void;
|
||||
|
||||
/**
|
||||
* Close the spotlight component.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_next() {
|
||||
this.props.dispatch(continueOnboarding());
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(NameSettingSpotlight);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { onboardingComponents, onboardingSteps } from '../../onboarding';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Redux dispatch.
|
||||
*/
|
||||
dispatch: Dispatch<*>;
|
||||
|
||||
/**
|
||||
* Onboarding Section.
|
||||
*/
|
||||
section: string;
|
||||
|
||||
/**
|
||||
* Active Onboarding.
|
||||
*/
|
||||
_activeOnboarding: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Onboarding Component Entry Point.
|
||||
*/
|
||||
class Onboarding extends Component<Props, *> {
|
||||
/**
|
||||
* Render function of component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { section, _activeOnboarding } = this.props;
|
||||
const steps = onboardingSteps[section];
|
||||
|
||||
if (_activeOnboarding && steps.includes(_activeOnboarding)) {
|
||||
const ActiveOnboarding = onboardingComponents[_activeOnboarding];
|
||||
|
||||
return <ActiveOnboarding />;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the React props.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {{
|
||||
* _activeOnboarding: string
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state: Object) {
|
||||
return {
|
||||
_activeOnboarding: state.onboarding.activeOnboarding
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(Onboarding);
|
||||
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
// @flow
|
||||
|
||||
import { Modal } from '@atlaskit/onboarding';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import OnboardingModalImage from '../../../images/onboarding.png';
|
||||
|
||||
import config from '../../config';
|
||||
|
||||
import { skipOnboarding, continueOnboarding } from '../actions';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Redux dispatch.
|
||||
*/
|
||||
dispatch: Dispatch<*>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Onboarding Modal Component.
|
||||
*/
|
||||
class OnboardingModal extends Component<Props, *> {
|
||||
/**
|
||||
* Initializes a new {@code OnboardingModal} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
// Bind event handlers.
|
||||
this._skip = this._skip.bind(this);
|
||||
this._next = this._next.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render function of component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<Modal
|
||||
actions = { [
|
||||
{
|
||||
onClick: this._next,
|
||||
text: 'Start Tour'
|
||||
},
|
||||
{
|
||||
onClick: this._skip,
|
||||
text: 'Skip'
|
||||
}
|
||||
] }
|
||||
heading = { `Welcome to ${config.appName}` }
|
||||
image = { OnboardingModalImage } >
|
||||
<p> Let us show you around!</p>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
_next: (*) => void;
|
||||
|
||||
/**
|
||||
* Close the spotlight component.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_next() {
|
||||
this.props.dispatch(continueOnboarding());
|
||||
}
|
||||
|
||||
_skip: (*) => void;
|
||||
|
||||
/**
|
||||
* Skips all the onboardings.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_skip() {
|
||||
this.props.dispatch(skipOnboarding());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect()(OnboardingModal);
|
|
@ -0,0 +1,69 @@
|
|||
// @flow
|
||||
|
||||
import { Spotlight } from '@atlaskit/onboarding';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { continueOnboarding } from '../actions';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Redux dispatch.
|
||||
*/
|
||||
dispatch: Dispatch<*>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Server Setting Spotlight Component.
|
||||
*/
|
||||
class ServerSettingSpotlight extends Component<Props, *> {
|
||||
/**
|
||||
* Initializes a new {@code ServerSettingSpotlight} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this._next = this._next.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render function of component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<Spotlight
|
||||
actions = { [
|
||||
{
|
||||
onClick: this._next,
|
||||
text: 'Next'
|
||||
}
|
||||
] }
|
||||
dialogPlacement = 'left top'
|
||||
target = { 'server-setting' } >
|
||||
This will be the server where your conferences will take place.
|
||||
You can use your own, but you don't need to!
|
||||
</Spotlight>
|
||||
);
|
||||
}
|
||||
|
||||
_next: (*) => void;
|
||||
|
||||
/**
|
||||
* Close the spotlight component.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_next() {
|
||||
this.props.dispatch(continueOnboarding());
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(ServerSettingSpotlight);
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// @flow
|
||||
|
||||
import { Spotlight } from '@atlaskit/onboarding';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { openDrawer } from '../../navbar';
|
||||
import { SettingsDrawer } from '../../settings';
|
||||
|
||||
import { continueOnboarding } from '../actions';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Redux dispatch.
|
||||
*/
|
||||
dispatch: Dispatch<*>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Settings Drawer Spotlight Component.
|
||||
*/
|
||||
class SettingsDrawerSpotlight extends Component<Props, *> {
|
||||
/**
|
||||
* Initializes a new {@code SettingsDrawerSpotlight} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this._next = this._next.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render function of component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<Spotlight
|
||||
dialogPlacement = 'right top'
|
||||
target = { 'settings-drawer-button' }
|
||||
targetOnClick = { this._next }>
|
||||
Click here to open the settings drawer.
|
||||
</Spotlight>
|
||||
);
|
||||
}
|
||||
|
||||
_next: (*) => void;
|
||||
|
||||
/**
|
||||
* Close the spotlight component and opens Settings Drawer and shows
|
||||
* onboarding.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_next() {
|
||||
this.props.dispatch(openDrawer(SettingsDrawer));
|
||||
this.props.dispatch(continueOnboarding());
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(SettingsDrawerSpotlight);
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
// @flow
|
||||
|
||||
import { Spotlight } from '@atlaskit/onboarding';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { closeDrawer } from '../../navbar';
|
||||
|
||||
import { continueOnboarding } from '../actions';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Redux dispatch.
|
||||
*/
|
||||
dispatch: Dispatch<*>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Start Muted Toggles Spotlight Component.
|
||||
*/
|
||||
class StartMutedTogglesSpotlight extends Component<Props, *> {
|
||||
/**
|
||||
* Initializes a new {@code StartMutedTogglesSpotlight} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this._next = this._next.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render function of component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<Spotlight
|
||||
actions = { [
|
||||
{
|
||||
onClick: this._next,
|
||||
text: 'Next'
|
||||
}
|
||||
] }
|
||||
dialogPlacement = 'left top'
|
||||
target = { 'start-muted-toggles' } >
|
||||
You can toggle if you want to start with your audio or video
|
||||
muted here. This will be applied to all conferences.
|
||||
</Spotlight>
|
||||
);
|
||||
}
|
||||
|
||||
_next: (*) => void;
|
||||
|
||||
/**
|
||||
* Close the spotlight component.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_next() {
|
||||
const { dispatch } = this.props;
|
||||
|
||||
dispatch(continueOnboarding());
|
||||
|
||||
// FIXME: find a better way to do this.
|
||||
setTimeout(() => {
|
||||
dispatch(closeDrawer());
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(StartMutedTogglesSpotlight);
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
export { default as ConferenceURLSpotlight } from './ConferenceURLSpotlight';
|
||||
export { default as EmailSettingSpotlight } from './EmailSettingSpotlight';
|
||||
export { default as NameSettingSpotlight } from './NameSettingSpotlight';
|
||||
export { default as Onboarding } from './Onboarding';
|
||||
export { default as OnboardingModal } from './OnboardingModal';
|
||||
export { default as ServerSettingSpotlight } from './ServerSettingSpotlight';
|
||||
export { default as SettingsDrawerSpotlight } from './SettingsDrawerSpotlight';
|
||||
export {
|
||||
default as StartMutedTogglesSpotlight
|
||||
} from './StartMutedTogglesSpotlight';
|
|
@ -0,0 +1,35 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
OnboardingModal,
|
||||
ConferenceURLSpotlight,
|
||||
SettingsDrawerSpotlight,
|
||||
NameSettingSpotlight,
|
||||
EmailSettingSpotlight,
|
||||
ServerSettingSpotlight,
|
||||
StartMutedTogglesSpotlight
|
||||
} from './components';
|
||||
|
||||
export const onboardingSteps = {
|
||||
'welcome-page': [
|
||||
'onboarding-modal',
|
||||
'conference-url',
|
||||
'settings-drawer-button'
|
||||
],
|
||||
'settings-drawer': [
|
||||
'name-setting',
|
||||
'email-setting',
|
||||
'server-setting',
|
||||
'start-muted-toggles'
|
||||
]
|
||||
};
|
||||
|
||||
export const onboardingComponents = {
|
||||
'onboarding-modal': OnboardingModal,
|
||||
'conference-url': ConferenceURLSpotlight,
|
||||
'settings-drawer-button': SettingsDrawerSpotlight,
|
||||
'name-setting': NameSettingSpotlight,
|
||||
'email-setting': EmailSettingSpotlight,
|
||||
'server-setting': ServerSettingSpotlight,
|
||||
'start-muted-toggles': StartMutedTogglesSpotlight
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
export * from './actions';
|
||||
export * from './actionTypes';
|
||||
export * from './components';
|
||||
export * from './constants';
|
||||
|
||||
export { default as middleware } from './middleware';
|
||||
export { default as reducer } from './reducer';
|
|
@ -0,0 +1,37 @@
|
|||
// @flow
|
||||
|
||||
import { setActiveOnboarding } from './actions';
|
||||
import { CONTINUE_ONBOARDING, START_ONBOARDING } from './actionTypes';
|
||||
import { onboardingSteps } from './constants';
|
||||
|
||||
export default (store: Object) => (next: Function) => (action: Object) => {
|
||||
const result = next(action);
|
||||
const state = store.getState();
|
||||
|
||||
switch (action.type) {
|
||||
case CONTINUE_ONBOARDING: {
|
||||
const section = state.onboarding.activeOnboardingSection;
|
||||
|
||||
const nextStep = onboardingSteps[section].find(
|
||||
step => !state.onboarding.onboardingShown.includes(step)
|
||||
);
|
||||
|
||||
store.dispatch(setActiveOnboarding(nextStep, nextStep && section));
|
||||
break;
|
||||
}
|
||||
|
||||
case START_ONBOARDING: {
|
||||
const { section } = action;
|
||||
const nextStep = onboardingSteps[section].find(
|
||||
step => !state.onboarding.onboardingShown.includes(step)
|
||||
);
|
||||
|
||||
if (nextStep) {
|
||||
store.dispatch(setActiveOnboarding(nextStep, section));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
|
@ -0,0 +1,66 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
CONTINUE_ONBOARDING,
|
||||
SET_ACTIVE_ONBOARDING,
|
||||
SKIP_ONBOARDING
|
||||
} from './actionTypes';
|
||||
import { onboardingSteps } from './constants';
|
||||
|
||||
type State = {
|
||||
activeOnboarding: ?string;
|
||||
activeOnboardingSection: ?string;
|
||||
onboardingShown: Array<string>;
|
||||
};
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
activeOnboarding: undefined,
|
||||
activeOnboardingSection: undefined,
|
||||
onboardingShown: []
|
||||
};
|
||||
|
||||
/**
|
||||
* Reduces redux actions for features/onboarding.
|
||||
*
|
||||
* @param {State} state - Current reduced redux state.
|
||||
* @param {Object} action - Action which was dispatched.
|
||||
* @returns {State} - Updated reduced redux state.
|
||||
*/
|
||||
export default (state: State = DEFAULT_STATE, action: Object) => {
|
||||
switch (action.type) {
|
||||
case CONTINUE_ONBOARDING:
|
||||
return {
|
||||
...state,
|
||||
activeOnboarding: undefined,
|
||||
onboardingShown:
|
||||
|
||||
// $FlowFixMe
|
||||
state.onboardingShown.concat(state.activeOnboarding)
|
||||
};
|
||||
|
||||
case SET_ACTIVE_ONBOARDING:
|
||||
return {
|
||||
...state,
|
||||
activeOnboarding: action.name,
|
||||
activeOnboardingSection: action.section
|
||||
};
|
||||
|
||||
case SKIP_ONBOARDING: {
|
||||
// $FlowFixMe
|
||||
const allSteps = [].concat(...Object.values(onboardingSteps));
|
||||
|
||||
return {
|
||||
...state,
|
||||
activeOnboarding: undefined,
|
||||
activeOnboardingSection: undefined,
|
||||
onboardingShown:
|
||||
|
||||
// $FlowFixMe
|
||||
state.onboardingShown.concat(allSteps)
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
|
@ -3,10 +3,12 @@
|
|||
import { applyMiddleware } from 'redux';
|
||||
import { createLogger } from 'redux-logger';
|
||||
|
||||
import { middleware as onboardingMiddleware } from '../onboarding';
|
||||
import { middleware as routerMiddleware } from '../router';
|
||||
import { middleware as settingsMiddleware } from '../settings';
|
||||
|
||||
export default applyMiddleware(
|
||||
onboardingMiddleware,
|
||||
routerMiddleware,
|
||||
settingsMiddleware,
|
||||
createLogger()
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
import { combineReducers } from 'redux';
|
||||
|
||||
import { reducer as navbarReducer } from '../navbar';
|
||||
import { reducer as onboardingReducer } from '../onboarding';
|
||||
import { reducer as recentListReducer } from '../recent-list';
|
||||
import { reducer as routerReducer } from '../router';
|
||||
import { reducer as settingsReducer } from '../settings';
|
||||
|
||||
export default combineReducers({
|
||||
navbar: navbarReducer,
|
||||
onboarding: onboardingReducer,
|
||||
recentList: recentListReducer,
|
||||
router: routerReducer,
|
||||
settings: settingsReducer
|
||||
|
|
|
@ -11,6 +11,7 @@ const persistConfig = {
|
|||
key: 'root',
|
||||
storage: createElectronStorage(),
|
||||
whitelist: [
|
||||
'onboarding',
|
||||
'recentList',
|
||||
'settings'
|
||||
]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import SettingsIcon from '@atlaskit/icon/glyph/settings';
|
||||
import { SpotlightTarget } from '@atlaskit/onboarding';
|
||||
|
||||
import * as Mousetrap from 'mousetrap';
|
||||
import 'mousetrap/plugins/global-bind/mousetrap-global-bind';
|
||||
|
@ -66,8 +67,11 @@ class SettingsButton extends Component<Props, *> {
|
|||
*/
|
||||
render() {
|
||||
return (
|
||||
<SettingsIcon
|
||||
onClick = { this._onIconClick } />
|
||||
<SpotlightTarget
|
||||
name = 'settings-drawer-button'>
|
||||
<SettingsIcon
|
||||
onClick = { this._onIconClick } />
|
||||
</SpotlightTarget>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,14 @@ import Avatar from '@atlaskit/avatar';
|
|||
import FieldText from '@atlaskit/field-text';
|
||||
import ArrowLeft from '@atlaskit/icon/glyph/arrow-left';
|
||||
import { AkCustomDrawer } from '@atlaskit/navigation';
|
||||
import { SpotlightTarget } from '@atlaskit/onboarding';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { closeDrawer, DrawerContainer, Logo } from '../../navbar';
|
||||
import { Onboarding, startOnboarding } from '../../onboarding';
|
||||
import { AvatarContainer, SettingsContainer } from '../styled';
|
||||
import { setEmail, setName } from '../actions';
|
||||
|
||||
|
@ -63,6 +65,25 @@ class SettingsDrawer extends Component<Props, *> {
|
|||
this._onNameFormSubmit = this._onNameFormSubmit.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start Onboarding once component is mounted.
|
||||
*
|
||||
* NOTE: It automatically checks if the onboarding is shown or not.
|
||||
*
|
||||
* @param {Props} prevProps - Props before component updated.
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (!prevProps.isOpen && this.props.isOpen) {
|
||||
|
||||
// TODO - Find a better way for this.
|
||||
// Delay for 300ms to let drawer open.
|
||||
setTimeout(() => {
|
||||
this.props.dispatch(startOnboarding('settings-drawer'));
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render function of component.
|
||||
*
|
||||
|
@ -82,24 +103,37 @@ class SettingsDrawer extends Component<Props, *> {
|
|||
size = 'xlarge'
|
||||
src = { this.props._avatarURL } />
|
||||
</AvatarContainer>
|
||||
<form onSubmit = { this._onNameFormSubmit }>
|
||||
<FieldText
|
||||
label = 'Name'
|
||||
onBlur = { this._onNameBlur }
|
||||
shouldFitContainer = { true }
|
||||
type = 'text'
|
||||
value = { this.props._name } />
|
||||
</form>
|
||||
<form onSubmit = { this._onEmailFormSubmit }>
|
||||
<FieldText
|
||||
label = 'Email'
|
||||
onBlur = { this._onEmailBlur }
|
||||
shouldFitContainer = { true }
|
||||
type = 'text'
|
||||
value = { this.props._email } />
|
||||
</form>
|
||||
<ServerURLField />
|
||||
<StartMutedToggles />
|
||||
<SpotlightTarget
|
||||
name = 'name-setting'>
|
||||
<form onSubmit = { this._onNameFormSubmit }>
|
||||
<FieldText
|
||||
label = 'Name'
|
||||
onBlur = { this._onNameBlur }
|
||||
shouldFitContainer = { true }
|
||||
type = 'text'
|
||||
value = { this.props._name } />
|
||||
</form>
|
||||
</SpotlightTarget>
|
||||
<SpotlightTarget
|
||||
name = 'email-setting'>
|
||||
<form onSubmit = { this._onEmailFormSubmit }>
|
||||
<FieldText
|
||||
label = 'Email'
|
||||
onBlur = { this._onEmailBlur }
|
||||
shouldFitContainer = { true }
|
||||
type = 'text'
|
||||
value = { this.props._email } />
|
||||
</form>
|
||||
</SpotlightTarget>
|
||||
<SpotlightTarget
|
||||
name = 'server-setting'>
|
||||
<ServerURLField />
|
||||
</SpotlightTarget>
|
||||
<SpotlightTarget
|
||||
name = 'start-muted-toggles'>
|
||||
<StartMutedToggles />
|
||||
</SpotlightTarget>
|
||||
<Onboarding section = 'settings-drawer' />
|
||||
</SettingsContainer>
|
||||
</DrawerContainer>
|
||||
</AkCustomDrawer>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Button from '@atlaskit/button';
|
||||
import { FieldTextStateless } from '@atlaskit/field-text';
|
||||
import { SpotlightTarget } from '@atlaskit/onboarding';
|
||||
import Page from '@atlaskit/page';
|
||||
import { AtlasKitThemeProvider } from '@atlaskit/theme';
|
||||
|
||||
|
@ -11,6 +12,7 @@ import { connect } from 'react-redux';
|
|||
import { push } from 'react-router-redux';
|
||||
|
||||
import { Navbar } from '../../navbar';
|
||||
import { Onboarding, startOnboarding } from '../../onboarding';
|
||||
import { RecentList } from '../../recent-list';
|
||||
import { normalizeServerURL } from '../../utils';
|
||||
|
||||
|
@ -71,6 +73,17 @@ class Welcome extends Component<Props, State> {
|
|||
this._onJoin = this._onJoin.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start Onboarding once component is mounted.
|
||||
*
|
||||
* NOTE: It autonatically checks if the onboarding is shown or not.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
this.props.dispatch(startOnboarding('welcome-page'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render function of component.
|
||||
*
|
||||
|
@ -84,16 +97,18 @@ class Welcome extends Component<Props, State> {
|
|||
<AtlasKitThemeProvider mode = 'light'>
|
||||
<Wrapper>
|
||||
<Header>
|
||||
<Form onSubmit = { this._onFormSubmit }>
|
||||
<FieldTextStateless
|
||||
autoFocus = { true }
|
||||
isInvalid = { state && state.error }
|
||||
isLabelHidden = { true }
|
||||
onChange = { this._onURLChange }
|
||||
shouldFitContainer = { true }
|
||||
type = 'text'
|
||||
value = { this.state.url } />
|
||||
</Form>
|
||||
<SpotlightTarget name = 'conference-url'>
|
||||
<Form onSubmit = { this._onFormSubmit }>
|
||||
<FieldTextStateless
|
||||
autoFocus = { true }
|
||||
isInvalid = { state && state.error }
|
||||
isLabelHidden = { true }
|
||||
onChange = { this._onURLChange }
|
||||
shouldFitContainer = { true }
|
||||
type = 'text'
|
||||
value = { this.state.url } />
|
||||
</Form>
|
||||
</SpotlightTarget>
|
||||
<Button
|
||||
appearance = 'primary'
|
||||
onClick = { this._onJoin }
|
||||
|
@ -104,6 +119,7 @@ class Welcome extends Component<Props, State> {
|
|||
<Body>
|
||||
<RecentList />
|
||||
</Body>
|
||||
<Onboarding section = 'welcome-page' />
|
||||
</Wrapper>
|
||||
</AtlasKitThemeProvider>
|
||||
</Page>
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
|
@ -5,6 +5,8 @@
|
|||
*/
|
||||
import '@atlaskit/css-reset';
|
||||
|
||||
import { SpotlightManager } from '@atlaskit/onboarding';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
|
@ -28,7 +30,9 @@ class Root extends Component<*> {
|
|||
<PersistGate
|
||||
loading = { null }
|
||||
persistor = { persistor }>
|
||||
<App />
|
||||
<SpotlightManager>
|
||||
<App />
|
||||
</SpotlightManager>
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
);
|
||||
|
|
|
@ -182,6 +182,23 @@
|
|||
"react-transition-group": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"@atlaskit/modal-dialog": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/modal-dialog/-/modal-dialog-6.0.3.tgz",
|
||||
"integrity": "sha512-qyM4l4jr+uYrb0qlme6g5AQwBJL7qBbR6lNe6ZiFOU7sxiC45DNwO36sUIpbJy4De8Ld5bwahKx6kBdu2fQVLw==",
|
||||
"requires": {
|
||||
"@atlaskit/analytics-next": "^3.0.1",
|
||||
"@atlaskit/blanket": "^7.0.1",
|
||||
"@atlaskit/button": "^9.0.2",
|
||||
"@atlaskit/icon": "^13.0.0",
|
||||
"@atlaskit/layer-manager": "^5.0.0",
|
||||
"@atlaskit/theme": "^5.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"raf-schd": "^2.1.0",
|
||||
"react-scrolllock": "^3.0.1",
|
||||
"react-transition-group": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"@atlaskit/navigation": {
|
||||
"version": "33.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/navigation/-/navigation-33.0.2.tgz",
|
||||
|
@ -212,6 +229,26 @@
|
|||
"react-transition-group": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"@atlaskit/onboarding": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/onboarding/-/onboarding-5.1.1.tgz",
|
||||
"integrity": "sha512-kMgQMeQJROFM3N0A2Uenn6yl6UYaCrSDekzM/ImnPkIEUnNVw8KD9Ok26ioi//FKmTjG6GOLYK6FKIbxtg2RvA==",
|
||||
"requires": {
|
||||
"@atlaskit/analytics-next": "^3.0.1",
|
||||
"@atlaskit/button": "^9.0.2",
|
||||
"@atlaskit/icon": "^13.0.0",
|
||||
"@atlaskit/layer": "^5.0.0",
|
||||
"@atlaskit/layer-manager": "^5.0.0",
|
||||
"@atlaskit/modal-dialog": "^6.0.1",
|
||||
"@atlaskit/theme": "^5.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-lorem-component": "^0.12.2",
|
||||
"react-node-resolver": "^1.0.1",
|
||||
"react-scrolllock": "^3.0.1",
|
||||
"react-transition-group": "^2.2.1",
|
||||
"unstated": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@atlaskit/page": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/page/-/page-8.0.0.tgz",
|
||||
|
@ -3142,6 +3179,21 @@
|
|||
"sha.js": "^2.4.8"
|
||||
}
|
||||
},
|
||||
"create-react-class": {
|
||||
"version": "15.6.3",
|
||||
"resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.3.tgz",
|
||||
"integrity": "sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg==",
|
||||
"requires": {
|
||||
"fbjs": "^0.8.9",
|
||||
"loose-envify": "^1.3.1",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"create-react-context": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.1.6.tgz",
|
||||
"integrity": "sha512-eCnYYEUEc5i32LHwpE/W7NlddOB9oHwsPaWtWzYtflNkkwa3IfindIcoXdVWs12zCbwaMCavKNu84EXogVIWHw=="
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
|
||||
|
@ -4765,6 +4817,16 @@
|
|||
"object-assign": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"file-loader": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz",
|
||||
"integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loader-utils": "^1.0.2",
|
||||
"schema-utils": "^0.4.5"
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
|
||||
|
@ -4994,14 +5056,12 @@
|
|||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
@ -5016,20 +5076,17 @@
|
|||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
|
@ -5146,8 +5203,7 @@
|
|||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
@ -5159,7 +5215,6 @@
|
|||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
|
@ -5174,7 +5229,6 @@
|
|||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
@ -5182,14 +5236,12 @@
|
|||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
|
@ -5208,7 +5260,6 @@
|
|||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
|
@ -5289,8 +5340,7 @@
|
|||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
|
@ -5302,7 +5352,6 @@
|
|||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
@ -5424,7 +5473,6 @@
|
|||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
@ -6848,6 +6896,14 @@
|
|||
"js-tokens": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lorem-ipsum": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/lorem-ipsum/-/lorem-ipsum-1.0.5.tgz",
|
||||
"integrity": "sha512-GW1N2mqtS1qRf4WHmQ/g/asGXXd2dciLUDEsz5hZQfVJNWHUZX0zsJDLfV581de4OOCrBRiTifyoSuSSUwIEdg==",
|
||||
"requires": {
|
||||
"minimist": "~1.2.0"
|
||||
}
|
||||
},
|
||||
"loud-rejection": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
|
||||
|
@ -8143,6 +8199,22 @@
|
|||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||
},
|
||||
"react-lorem-component": {
|
||||
"version": "0.12.2",
|
||||
"resolved": "https://registry.npmjs.org/react-lorem-component/-/react-lorem-component-0.12.2.tgz",
|
||||
"integrity": "sha1-oR/SmLBEos8GKQXFOYiA5Gv+zCU=",
|
||||
"requires": {
|
||||
"create-react-class": "^15.5.3",
|
||||
"lorem-ipsum": "^1.0.3",
|
||||
"object-assign": "^4.1.0",
|
||||
"seedable-random": "0.0.1"
|
||||
}
|
||||
},
|
||||
"react-node-resolver": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-node-resolver/-/react-node-resolver-1.0.1.tgz",
|
||||
"integrity": "sha1-F5inKcDiGL8vDo3fecVQ1K9h2Do="
|
||||
},
|
||||
"react-redux": {
|
||||
"version": "5.0.7",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz",
|
||||
|
@ -8775,6 +8847,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"seedable-random": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/seedable-random/-/seedable-random-0.0.1.tgz",
|
||||
"integrity": "sha1-CzDOp55DmWiMWgZ1A6Bmt8QegxY="
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
|
||||
|
@ -9950,6 +10027,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"unstated": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/unstated/-/unstated-1.2.0.tgz",
|
||||
"integrity": "sha512-nmI65VVuMRFm1UBxF1BEWTt8XoRldX1gEwcyBhcFJSsLycHuHFa8qjYnTv8wMISGs7e+HKWeXAtTi1DvEsg00w==",
|
||||
"requires": {
|
||||
"create-react-context": "^0.1.5"
|
||||
}
|
||||
},
|
||||
"unzip-response": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
"@atlaskit/field-text": "7.0.1",
|
||||
"@atlaskit/icon": "13.2.0",
|
||||
"@atlaskit/navigation": "33.0.2",
|
||||
"@atlaskit/onboarding": "5.1.1",
|
||||
"@atlaskit/page": "8.0.0",
|
||||
"@atlaskit/spinner": "9.0.2",
|
||||
"@atlaskit/theme": "5.1.0",
|
||||
|
@ -124,6 +125,7 @@
|
|||
"eslint-plugin-import": "2.13.0",
|
||||
"eslint-plugin-jsdoc": "3.7.1",
|
||||
"eslint-plugin-react": "7.10.0",
|
||||
"file-loader": "1.1.11",
|
||||
"flow-bin": "0.76.0",
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"precommit-hook": "3.0.0",
|
||||
|
|
|
@ -44,6 +44,10 @@ const commonConfig = {
|
|||
],
|
||||
test: /\.css$/
|
||||
},
|
||||
{
|
||||
use: 'file-loader',
|
||||
test: /\.png$/
|
||||
},
|
||||
{
|
||||
loader: 'svg-inline-loader',
|
||||
test: /\.svg$/
|
||||
|
|
Loading…
Reference in New Issue