From 0e801a4e70f3d9c8e3cf929aa2f7ac201ca87b52 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Wed, 28 Oct 2015 15:04:17 -0400 Subject: [PATCH 1/9] Add tutorial intro screens for new users. --- model/preference.go | 4 +- web/react/components/navbar_dropdown.jsx | 2 +- .../tutorial/tutorial_intro_screens.jsx | 150 ++++++++++++++++++ web/react/utils/constants.jsx | 2 + 4 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 web/react/components/tutorial/tutorial_intro_screens.jsx diff --git a/model/preference.go b/model/preference.go index 44279f71af..6e5b68b92f 100644 --- a/model/preference.go +++ b/model/preference.go @@ -9,7 +9,9 @@ import ( ) const ( - PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW = "direct_channel_show" + PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW = "direct_channel_show" + PREFERENCE_CATEGORY_TUTORIAL_INTRO_COMPLETE = "tutorial_intro_complete" + PREFERENCE_CATEGORY_TUTORIAL_POPOVERS = "tutorial_popovers" ) type Preference struct { diff --git a/web/react/components/navbar_dropdown.jsx b/web/react/components/navbar_dropdown.jsx index dc21fad21e..f43bdffdfc 100644 --- a/web/react/components/navbar_dropdown.jsx +++ b/web/react/components/navbar_dropdown.jsx @@ -104,7 +104,7 @@ export default class NavbarDropdown extends React.Component { ); - if (this.props.teamType === 'O') { + if (this.props.teamType === Constants.OPEN_TEAM) { teamLink = (
  • +

    {'Welcome to:'}

    +

    {'Mattermost'}

    +
    + {'Your team communications all in one place,'} +
    + {'instantly searchable and available anywhere.'} +

    + {'Keep your team connected to help them'} +
    + {'achieve what matters most.'} +

    + {'[ x ][ ][ ]'} + + ); + } + createScreenTwo() { + return ( +
    +

    {'How Mattermost works:'}

    +
    + {'Communication happens in public discussion channels,'} +
    + {'private groups and direct messages.'} +

    + {'Everything is archived and searchable from'} +
    + {'any web-enabled laptop, tablet or phone.'} +

    + {'[ ][ x ][ ]'} +
    + ); + } + createScreenThree() { + const team = TeamStore.getCurrent(); + let inviteModalLink; + if (team.type === Constants.INVITE_TEAM) { + inviteModalLink = ( +
    + {'Invite teammates'} + + ); + } else { + inviteModalLink = ( + + ); + } + + return ( +
    +

    {'You’re all set'}

    +
    + {inviteModalLink} + {' when you’re ready.'} +

    + {'Need anything, just email us at '} +
    + {'feedback@mattermost.com.'} + +

    + {'Click “Next” to enter Town Square. This is the first channel'} +
    + {'teammates see when they sign up - use it for posting updates'} +
    + {'everyone needs to know.'} +

    + {'[ ][ ][ x ]'} +
    + ); + } + render() { + const screen = this.createScreen(); + + return ( +
    + {screen} +

    + +
    + ); + } +} diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index 8884d1d10c..57be5046eb 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -315,6 +315,8 @@ module.exports = { CATEGORY_DIRECT_CHANNEL_SHOW: 'direct_channel_show', CATEGORY_DISPLAY_SETTINGS: 'display_settings', CATEGORY_ADVANCED_SETTINGS: 'advanced_settings' + TUTORIAL_INTRO_COMPLETE: 'tutorial_intro_complete', + TUTORIAL_POPOVERS: 'tutorial_popovers' }, KeyCodes: { UP: 38, From 97449a102e5592358a4f7f22d6720a9af21286a1 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 30 Oct 2015 11:35:16 -0400 Subject: [PATCH 2/9] Add tutorial popovers --- model/preference.go | 4 +- web/react/components/create_post.jsx | 66 ++++++++--- web/react/components/sidebar.jsx | 68 +++++++++-- web/react/components/sidebar_header.jsx | 89 ++++++++++++++- .../tutorial/tutorial_intro_screens.jsx | 14 ++- .../components/tutorial/tutorial_tip.jsx | 108 ++++++++++++++++++ web/react/utils/constants.jsx | 11 +- web/sass-files/sass/partials/_tutorial.scss | 21 ++++ web/sass-files/sass/styles.scss | 2 +- 9 files changed, 346 insertions(+), 37 deletions(-) create mode 100644 web/react/components/tutorial/tutorial_tip.jsx create mode 100644 web/sass-files/sass/partials/_tutorial.scss diff --git a/model/preference.go b/model/preference.go index 6e5b68b92f..44279f71af 100644 --- a/model/preference.go +++ b/model/preference.go @@ -9,9 +9,7 @@ import ( ) const ( - PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW = "direct_channel_show" - PREFERENCE_CATEGORY_TUTORIAL_INTRO_COMPLETE = "tutorial_intro_complete" - PREFERENCE_CATEGORY_TUTORIAL_POPOVERS = "tutorial_popovers" + PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW = "direct_channel_show" ) type Preference struct { diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index 7c601af4bb..1dc30e251e 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -1,21 +1,26 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -const AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); -const Client = require('../utils/client.jsx'); -const AsyncClient = require('../utils/async_client.jsx'); -const ChannelStore = require('../stores/channel_store.jsx'); -const PostStore = require('../stores/post_store.jsx'); -const UserStore = require('../stores/user_store.jsx'); -const SocketStore = require('../stores/socket_store.jsx'); -const PreferenceStore = require('../stores/preference_store.jsx'); const MsgTyping = require('./msg_typing.jsx'); const Textbox = require('./textbox.jsx'); const FileUpload = require('./file_upload.jsx'); const FilePreview = require('./file_preview.jsx'); +const TutorialTip = require('./tutorial/tutorial_tip.jsx'); + +const AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); +const Client = require('../utils/client.jsx'); +const AsyncClient = require('../utils/async_client.jsx'); const Utils = require('../utils/utils.jsx'); +const ChannelStore = require('../stores/channel_store.jsx'); +const PostStore = require('../stores/post_store.jsx'); +const UserStore = require('../stores/user_store.jsx'); +const PreferenceStore = require('../stores/preference_store.jsx'); +const SocketStore = require('../stores/socket_store.jsx'); + const Constants = require('../utils/constants.jsx'); +const Preferences = Constants.Preferences; +const TutorialSteps = Constants.TutorialSteps; const ActionTypes = Constants.ActionTypes; const KeyCodes = Constants.KeyCodes; @@ -36,15 +41,16 @@ export default class CreatePost extends React.Component { this.handleTextDrop = this.handleTextDrop.bind(this); this.removePreview = this.removePreview.bind(this); this.onChange = this.onChange.bind(this); + this.onPreferenceChange = this.onPreferenceChange.bind(this); this.getFileCount = this.getFileCount.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); this.handleResize = this.handleResize.bind(this); this.sendMessage = this.sendMessage.bind(this); - this.onPreferenceChange = this.onPreferenceChange.bind(this); PostStore.clearDraftUploads(); const draft = this.getCurrentDraft(); + const tutorialPref = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '0'}); this.state = { channelId: ChannelStore.getCurrentId(), @@ -55,16 +61,12 @@ export default class CreatePost extends React.Component { initialText: draft.messageText, windowWidth: Utils.windowWidth(), windowHeight: Utils.windowHeight(), - ctrlSend: PreferenceStore.getPreference(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter', {value: 'false'}).value + ctrlSend: PreferenceStore.getPreference(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter', {value: 'false'}).value, + showTutorialTip: parseInt(tutorialPref.value, 10) === TutorialSteps.POST_POPOVER }; PreferenceStore.addChangeListener(this.onPreferenceChange); } - onPreferenceChange() { - this.setState({ - ctrlSend: PreferenceStore.getPreference(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter', {value: 'false'}).value - }); - } handleResize() { this.setState({ windowWidth: Utils.windowWidth(), @@ -318,11 +320,13 @@ export default class CreatePost extends React.Component { } componentDidMount() { ChannelStore.addChangeListener(this.onChange); + PreferenceStore.addChangeListener(this.onPreferenceChange); this.resizePostHolder(); window.addEventListener('resize', this.handleResize); } componentWillUnmount() { ChannelStore.removeChangeListener(this.onChange); + PreferenceStore.removeChangeListener(this.onPreferenceChange); window.removeEventListener('resize', this.handleResize); } onChange() { @@ -333,6 +337,13 @@ export default class CreatePost extends React.Component { this.setState({channelId, messageText: draft.messageText, initialText: draft.messageText, submitting: false, serverError: null, postError: null, previews: draft.previews, uploadsInProgress: draft.uploadsInProgress}); } } + onPreferenceChange() { + const tutorialPref = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '0'}); + this.setState({ + showTutorialTip: parseInt(tutorialPref.value, 10) === TutorialSteps.POST_POPOVER, + ctrlSend: PreferenceStore.getPreference(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter', {value: 'false'}).value + }); + } getFileCount(channelId) { if (channelId === this.state.channelId) { return this.state.previews.length + this.state.uploadsInProgress.length; @@ -367,6 +378,25 @@ export default class CreatePost extends React.Component { }); } } + createTutorialTip() { + const screens = []; + + screens.push( +
    +

    {'Sending Messages'}

    + {'Type here to write a message.'} +

    + {'Click the attachment button to upload an image or a file.'} +
    + ); + + return ( + + ); + } render() { let serverError = null; if (this.state.serverError) { @@ -398,6 +428,11 @@ export default class CreatePost extends React.Component { postFooterClassName += ' has-error'; } + let tutorialTip = null; + if (this.state.showTutorialTip) { + tutorialTip = this.createTutorialTip(); + } + return (
    + {tutorialTip}
    {postError} diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 023955e978..c3f43ff692 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -1,19 +1,26 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -const AsyncClient = require('../utils/async_client.jsx'); -const ChannelStore = require('../stores/channel_store.jsx'); -const Client = require('../utils/client.jsx'); -const Constants = require('../utils/constants.jsx'); -const PreferenceStore = require('../stores/preference_store.jsx'); const NewChannelFlow = require('./new_channel_flow.jsx'); const MoreDirectChannels = require('./more_direct_channels.jsx'); const SearchBox = require('./search_bar.jsx'); const SidebarHeader = require('./sidebar_header.jsx'); -const TeamStore = require('../stores/team_store.jsx'); const UnreadChannelIndicator = require('./unread_channel_indicator.jsx'); +const TutorialTip = require('./tutorial/tutorial_tip.jsx'); + +const ChannelStore = require('../stores/channel_store.jsx'); const UserStore = require('../stores/user_store.jsx'); +const TeamStore = require('../stores/team_store.jsx'); +const PreferenceStore = require('../stores/preference_store.jsx'); + +const AsyncClient = require('../utils/async_client.jsx'); +const Client = require('../utils/client.jsx'); const Utils = require('../utils/utils.jsx'); + +const Constants = require('../utils/constants.jsx'); +const Preferences = Constants.Preferences; +const TutorialSteps = Constants.TutorialSteps; + const Tooltip = ReactBootstrap.Tooltip; const OverlayTrigger = ReactBootstrap.OverlayTrigger; @@ -155,12 +162,15 @@ export default class Sidebar extends React.Component { visibleDirectChannels.sort(this.sortChannelsByDisplayName); + const tutorialPref = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '0'}); + return { activeId: currentId, channels: ChannelStore.getAll(), members, visibleDirectChannels, - hiddenDirectChannelCount + hiddenDirectChannelCount, + showTutorialTip: parseInt(tutorialPref.value, 10) === TutorialSteps.CHANNEL_POPOVER }; } @@ -308,6 +318,44 @@ export default class Sidebar extends React.Component { this.setState({showDirectChannelsModal: false}); } + createTutorialTip() { + const screens = []; + + screens.push( +
    +

    {'Channels'}

    + {'Channels'}{' organize conversations across different topics. They’re open to everyone on your team. To send private communications use '}{'Direct Messages'}{' for a single person or '}{'Private Groups'}{' for multiple people.'} +
    + ); + + screens.push( +
    +

    {'"Town Square" and "Off-Topic" channels'}

    + {'Here are two public channels to start:'} +

    + {'Town Square'}{' is a place for team-wide communication. Everyone in your team is a member of this channel.'} +

    + {'Off-Topic'}{' is a place for fun and humor outside of work-related channels. You and your team can decide what other channels to create.'} +
    + ); + + screens.push( +
    +

    {'Creating and Joining Channels'}

    + {'Click '}{'"More..."'}{' to create a new channel or join an existing one.'} +

    + {'You can also create a new channel or private group by clicking the '}{'"+" symbol'}{' next to the channel or private group header.'} +
    + ); + + return ( + + ); + } + createChannelElement(channel, index, arr, handleClose) { var members = this.state.members; var activeId = this.state.activeId; @@ -444,6 +492,11 @@ export default class Sidebar extends React.Component { rowClass += ' has-close'; } + let tutorialTip = null; + if (this.state.showTutorialTip && channel.name === Constants.DEFAULT_CHANNEL) { + tutorialTip = this.createTutorialTip(); + } + return (
  • + {tutorialTip}
  • ); } diff --git a/web/react/components/sidebar_header.jsx b/web/react/components/sidebar_header.jsx index 65e4c6d7eb..96348f6883 100644 --- a/web/react/components/sidebar_header.jsx +++ b/web/react/components/sidebar_header.jsx @@ -1,9 +1,16 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -var NavbarDropdown = require('./navbar_dropdown.jsx'); -var UserStore = require('../stores/user_store.jsx'); +const NavbarDropdown = require('./navbar_dropdown.jsx'); +const TutorialTip = require('./tutorial/tutorial_tip.jsx'); + +const UserStore = require('../stores/user_store.jsx'); +const PreferenceStore = require('../stores/preference_store.jsx'); + const Utils = require('../utils/utils.jsx'); +const Constants = require('../utils/constants.jsx'); +const Preferences = Constants.Preferences; +const TutorialSteps = Constants.TutorialSteps; const Tooltip = ReactBootstrap.Tooltip; const OverlayTrigger = ReactBootstrap.OverlayTrigger; @@ -13,8 +20,23 @@ export default class SidebarHeader extends React.Component { super(props); this.toggleDropdown = this.toggleDropdown.bind(this); + this.onPreferenceChange = this.onPreferenceChange.bind(this); - this.state = {}; + this.state = this.getStateFromStores(); + } + componentDidMount() { + PreferenceStore.addChangeListener(this.onPreferenceChange); + } + componentWillUnmount() { + PreferenceStore.removeChangeListener(this.onPreferenceChange); + } + getStateFromStores() { + const tutorialPref = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '0'}); + + return {showTutorialTip: parseInt(tutorialPref.value, 10) === TutorialSteps.MENU_POPOVER}; + } + onPreferenceChange() { + this.setState(this.getStateFromStores()); } toggleDropdown(e) { e.preventDefault(); @@ -22,8 +44,63 @@ export default class SidebarHeader extends React.Component { this.refs.dropdown.blockToggle = false; return; } + console.log(this.refs.tip); + this.refs.tip.toggle(); $('.team__header').find('.dropdown-toggle').dropdown('toggle'); } + createTutorialTip() { + const screens = []; + + let teamSettingsLink = {'Team Settings'}; + if (Utils.isAdmin(UserStore.getCurrentUser().roles)) { + teamSettingsLink = ( + + {'Team Settings'} + + ); + } + + screens.push( +
    +

    {'Sending Messages'}

    + {'The '}{'Main Menu'}{' is where you can '} + + {'Invite New Members'} + + {', access your '} + + {'Account Settings'} + + {', and set your '}{'Theme Color'}{'.'} +

    + {'Team administrators can also access their '}{teamSettingsLink}{' from this menu.'} +
    + ); + + return ( +
    + +
    + ); + } render() { var me = UserStore.getCurrentUser(); var profilePicture = null; @@ -41,8 +118,14 @@ export default class SidebarHeader extends React.Component { ); } + let tutorialTip = null; + if (this.state.showTutorialTip) { + tutorialTip = this.createTutorialTip(); + } + return (
    + {tutorialTip} = this.props.screens.length - 1) { + let preference = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '0'}); + + const newValue = (parseInt(preference.value, 10) + 1).toString(); + + preference = PreferenceStore.setPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), newValue); + AsyncClient.savePreferences([preference]); + } + } + handleNext() { + if (this.state.currentScreen < this.props.screens.length - 1) { + this.setState({currentScreen: this.state.currentScreen + 1}); + return; + } + + this.toggle(); + } + skipTutorial(e) { + e.preventDefault(); + const preference = PreferenceStore.setPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), '999'); + AsyncClient.savePreferences([preference]); + } + render() { + const buttonText = this.state.currentScreen === this.props.screens.length - 1 ? 'Okay' : 'Next'; + + const dots = []; + if (this.props.screens.length > 1) { + for (let i = 0; i < this.props.screens.length; i++) { + if (i === this.state.currentScreen) { + dots.push({'[ x ]'}); + } else { + dots.push({'[ ]'}); + } + } + } + + return ( + + ); + } +} + +TutorialTip.propTypes = { + screens: React.PropTypes.array.isRequired, + placement: React.PropTypes.string.isRequired +}; diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index 57be5046eb..fd64b1554a 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -314,9 +314,14 @@ module.exports = { Preferences: { CATEGORY_DIRECT_CHANNEL_SHOW: 'direct_channel_show', CATEGORY_DISPLAY_SETTINGS: 'display_settings', - CATEGORY_ADVANCED_SETTINGS: 'advanced_settings' - TUTORIAL_INTRO_COMPLETE: 'tutorial_intro_complete', - TUTORIAL_POPOVERS: 'tutorial_popovers' + CATEGORY_ADVANCED_SETTINGS: 'advanced_settings', + TUTORIAL_STEP: 'tutorial_step' + }, + TutorialSteps: { + INTRO_SCREENS: 0, + POST_POPOVER: 1, + CHANNEL_POPOVER: 2, + MENU_POPOVER: 3 }, KeyCodes: { UP: 38, diff --git a/web/sass-files/sass/partials/_tutorial.scss b/web/sass-files/sass/partials/_tutorial.scss new file mode 100644 index 0000000000..e80abf9528 --- /dev/null +++ b/web/sass-files/sass/partials/_tutorial.scss @@ -0,0 +1,21 @@ +.tip-overlay { + position:absolute; + background-color:#EEE; + box-shadow:0 5px 10px rgba(0, 0, 0, 0.2); + border:1px solid #CCC; + border-radius:3px; + padding:10px; + z-index:999; +} + +.tip-button { + height:20px; + width:20px; + z-index:998; +} + +.tip-div { + position:absolute; + top:0px; + right:0px; +} diff --git a/web/sass-files/sass/styles.scss b/web/sass-files/sass/styles.scss index ad2cae194e..34f7c6eeda 100644 --- a/web/sass-files/sass/styles.scss +++ b/web/sass-files/sass/styles.scss @@ -38,7 +38,7 @@ @import "partials/loading"; @import "partials/get-link"; @import "partials/markdown"; -@import "partials/statistics"; +@import "partials/tutorial"; // Responsive Css @import "partials/responsive"; From 393d253021e6b119ec35b92f9eeaa6f2d255008f Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Mon, 2 Nov 2015 11:40:53 +0500 Subject: [PATCH 3/9] Updating tutorial screens --- web/react/components/create_post.jsx | 7 +- web/react/components/sidebar.jsx | 30 +++-- .../tutorial/tutorial_intro_screens.jsx | 107 ++++++++-------- .../components/tutorial/tutorial_tip.jsx | 51 +++++--- web/sass-files/sass/partials/_tutorial.scss | 117 ++++++++++++++++-- web/sass-files/sass/styles.scss | 1 + web/static/images/tutorialTip.gif | Bin 0 -> 12278 bytes 7 files changed, 215 insertions(+), 98 deletions(-) create mode 100644 web/static/images/tutorialTip.gif diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index 1dc30e251e..cb3148b7bd 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -383,10 +383,9 @@ export default class CreatePost extends React.Component { screens.push(
    -

    {'Sending Messages'}

    - {'Type here to write a message.'} -

    - {'Click the attachment button to upload an image or a file.'} +

    {'Sending Messages'}

    +

    {'Type here to write a message.'}

    +

    {'Click the attachment button to upload an image or a file.'}

    ); diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index c3f43ff692..39d9808e95 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -323,28 +323,34 @@ export default class Sidebar extends React.Component { screens.push(
    -

    {'Channels'}

    - {'Channels'}{' organize conversations across different topics. They’re open to everyone on your team. To send private communications use '}{'Direct Messages'}{' for a single person or '}{'Private Groups'}{' for multiple people.'} +

    {'Channels'}

    +

    {'Channels'}{' organize conversations across different topics. They’re open to everyone on your team. To send private communications use '}{'Direct Messages'}{' for a single person or '}{'Private Groups'}{' for multiple people.'} +

    ); screens.push(
    -

    {'"Town Square" and "Off-Topic" channels'}

    - {'Here are two public channels to start:'} -

    - {'Town Square'}{' is a place for team-wide communication. Everyone in your team is a member of this channel.'} -

    - {'Off-Topic'}{' is a place for fun and humor outside of work-related channels. You and your team can decide what other channels to create.'} +

    {'"Town Square" and "Off-Topic" channels'}

    +

    {'Here are two public channels to start:'}

    +

    + {'Town Square'}{' is a place for team-wide communication. Everyone in your team is a member of this channel.'} +

    +

    + {'Off-Topic'}{' is a place for fun and humor outside of work-related channels. You and your team can decide what other channels to create.'} +

    ); screens.push(
    -

    {'Creating and Joining Channels'}

    - {'Click '}{'"More..."'}{' to create a new channel or join an existing one.'} -

    - {'You can also create a new channel or private group by clicking the '}{'"+" symbol'}{' next to the channel or private group header.'} +

    {'Creating and Joining Channels'}

    +

    + {'Click '}{'"More..."'}{' to create a new channel or join an existing one.'} +

    +

    + {'You can also create a new channel or private group by clicking the '}{'"+" symbol'}{' next to the channel or private group header.'} +

    ); diff --git a/web/react/components/tutorial/tutorial_intro_screens.jsx b/web/react/components/tutorial/tutorial_intro_screens.jsx index d423b4f1ba..b37aac27cc 100644 --- a/web/react/components/tutorial/tutorial_intro_screens.jsx +++ b/web/react/components/tutorial/tutorial_intro_screens.jsx @@ -20,6 +20,10 @@ export default class TutorialIntroScreens extends React.Component { this.state = {currentScreen: 0}; } + componentDidMount() { + const height = $(window).outerHeight() - 120; + $('.tutorial-steps__container').css('height', `${height}px`); + } handleNext() { if (this.state.currentScreen < 2) { this.setState({currentScreen: this.state.currentScreen + 1}); @@ -48,35 +52,29 @@ export default class TutorialIntroScreens extends React.Component { createScreenOne() { return (
    -

    {'Welcome to:'}

    -

    {'Mattermost'}

    -
    - {'Your team communications all in one place,'} -
    - {'instantly searchable and available anywhere.'} -

    - {'Keep your team connected to help them'} -
    - {'achieve what matters most.'} -

    - {'[ x ][ ][ ]'} +

    {'Welcome to:'}

    +

    {'Mattermost'}

    +

    {'Your team communications all in one place, instantly searchable and available anywhere.'}

    +

    {'Keep your team connected to help them achieve what matters most.'}

    +
    +
    +
    +
    +
    ); } createScreenTwo() { return (
    -

    {'How Mattermost works:'}

    -
    - {'Communication happens in public discussion channels,'} -
    - {'private groups and direct messages.'} -

    - {'Everything is archived and searchable from'} -
    - {'any web-enabled laptop, tablet or phone.'} -

    - {'[ ][ x ][ ]'} +

    {'How Mattermost works:'}

    +

    {'Communication happens in public discussion channels, private groups and direct messages.'}

    +

    {'Everything is archived and searchable from any web-enabled laptop, tablet or phone.'}

    +
    +
    +
    +
    +
    ); } @@ -111,26 +109,26 @@ export default class TutorialIntroScreens extends React.Component { return (
    -

    {'You’re all set'}

    -
    - {inviteModalLink} - {' when you’re ready.'} -

    - {'Need anything, just email us at '} - - {'feedback@mattermost.com.'} - -

    - {'Click “Next” to enter Town Square. This is the first channel'} -
    - {'teammates see when they sign up - use it for posting updates'} -
    - {'everyone needs to know.'} -

    - {'[ ][ ][ x ]'} +

    {'You’re all set'}

    +

    + {inviteModalLink} + {' when you’re ready.'} +

    +

    + {'Need anything, just email us at '} + + {'feedback@mattermost.com.'} + +

    + {'Click “Next” to enter Town Square. This is the first channel teammates see when they sign up - use it for posting updates everyone needs to know.'} +
    +
    +
    +
    +
    ); } @@ -138,16 +136,19 @@ export default class TutorialIntroScreens extends React.Component { const screen = this.createScreen(); return ( -
    - {screen} -

    - +
    +
    +
    + {screen} + +
    +
    ); } diff --git a/web/react/components/tutorial/tutorial_tip.jsx b/web/react/components/tutorial/tutorial_tip.jsx index 166d10d8ae..3482a7cfaa 100644 --- a/web/react/components/tutorial/tutorial_tip.jsx +++ b/web/react/components/tutorial/tutorial_tip.jsx @@ -52,9 +52,19 @@ export default class TutorialTip extends React.Component { if (this.props.screens.length > 1) { for (let i = 0; i < this.props.screens.length; i++) { if (i === this.state.currentScreen) { - dots.push({'[ x ]'}); + dots.push( +
    + ); } else { - dots.push({'[ ]'}); + dots.push( +
    + ); } } } @@ -63,7 +73,8 @@ export default class TutorialTip extends React.Component {
    @@ -77,24 +88,24 @@ export default class TutorialTip extends React.Component { >
    {this.props.screens[this.state.currentScreen]} -
    - {dots} - -
    - - {'Seen this before? '} - {dots}
    +
    + +
    + {'Seen this before? '} + + {'Opt out of these tips.'} + +
    +
    diff --git a/web/sass-files/sass/partials/_tutorial.scss b/web/sass-files/sass/partials/_tutorial.scss index e80abf9528..fa93e46bf0 100644 --- a/web/sass-files/sass/partials/_tutorial.scss +++ b/web/sass-files/sass/partials/_tutorial.scss @@ -1,17 +1,71 @@ +.tip-backdrop { + background: rgba(black, 0.5); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 999; +} + .tip-overlay { + width: 350px; + max-width: 90%; position:absolute; - background-color:#EEE; - box-shadow:0 5px 10px rgba(0, 0, 0, 0.2); - border:1px solid #CCC; - border-radius:3px; - padding:10px; - z-index:999; + background-color: #fff; + @include border-radius(3px); + padding: 20px; + z-index: 1000; + h4 { + font-size: em(16px); + font-weight: 600; + margin: 5px 0 15px; + } + p { + font-size: 13px; + line-height: 1.6; + strong { + font-weight: 600; + } + } + .btn { + background: #cccccc; + color: #fff; + @include border-radius(3px); + border: none; + margin-bottom: 10px; + &:hover, &:active, &:focus { + color: #fff; + border: none; + background: #bbb; + } + } + .tip-opt { + font-size: 12px; + span { + @include opacity(0.5); + } + } + .tutorial__circles { + margin: 1.5em 0px -1.7em -4px; + .circle { + width: 7px; + height: 7px; + margin: 0 4px; + &.active { + background: #000; + @include opacity(0.4); + } + } + } } .tip-button { - height:20px; - width:20px; - z-index:998; + z-index: 998; + right: -10px; + top: -10px; + position: relative; + cursor: pointer; } .tip-div { @@ -19,3 +73,48 @@ top:0px; right:0px; } + +.tutorial-steps__container { + text-align: center; + width: 100%; + display: table; + .tutorial__content { + display: table-cell; + vertical-align: middle; + padding-bottom: 100px; + padding: 0 40px; + .tutorial__steps { + max-width: 310px; + min-height: 420px; + text-align: left; + display: inline-block; + } + } + h1 { + font-size: em(40px); + margin: -20px 0 30px; + font-weight: 600; + } + h3 { + font-size: em(24px); + margin-bottom: 30px; + font-weight: 600; + } +} + +.tutorial__circles { + margin: 2em 0; + .circle { + width: 9px; + height: 9px; + @include border-radius(9px); + @include opacity(0.1); + background: #000; + display: inline-block; + margin: 0 5px; + &.active { + background: $primary-color; + @include opacity(1); + } + } +} \ No newline at end of file diff --git a/web/sass-files/sass/styles.scss b/web/sass-files/sass/styles.scss index 34f7c6eeda..5c83d5c5b4 100644 --- a/web/sass-files/sass/styles.scss +++ b/web/sass-files/sass/styles.scss @@ -39,6 +39,7 @@ @import "partials/get-link"; @import "partials/markdown"; @import "partials/tutorial"; +@import "partials/statistics"; // Responsive Css @import "partials/responsive"; diff --git a/web/static/images/tutorialTip.gif b/web/static/images/tutorialTip.gif new file mode 100644 index 0000000000000000000000000000000000000000..024dc3c09fb889003a65c0a938d8e7494836beac GIT binary patch literal 12278 zcmeHscU)81_U}F+jSxb5LO&z~LP;TnYMC@b$AF-Ss00W_dQq`X2mxs-ARu-?Q0(B? z%S=E}aC8Q+3^+PcELcXdj^pU%;mn=;-XHh#d-rqyd4D|5ALpFC_gZ`HvetL6y_SEV z(%VO^1WIsI3eZ{?e*5kD^XJ3E!_%z~9z3{x`}Vzi_wL`n|Ni~^ zM~@yoefspyojaqWqa!0DPo6xPeoszL{_)2jFJ8QuZXFvNd-LYaFTecq^5x5kiHTo- z{q^zV$J0&Eo;`d0`t{V*)cE-L^c(!&9=j=%Fu%yTa;eHs#1|St)AZ9-(V;3>q0U!N ze`kJGkgZNg)8xbPn&i~XS*#c5zGK0uiL+SqJwk<{*>X)vYQU;o&D>RCkqN8P5_}R_ zU(JSR7WfuqWM^pd)o?*ZdS;$)!7P?KF)LoO z556ZaLFnlPd-?F)JiNTbUaqi6=;k31x(nQeJdwMvSm-Mj!T)?%)6#MilYAo-%74n5 zF3n=4O zgm7lb5wDH$gK^&ivuH+6bb)ai<>gk>3; z%=|#bEY@@jKQT4Y*G-h@m6V_s^OD>X+<9Ve_jq2sTCL$FB?#TUHEv1X2}wzR_w(=g zrDCCno2Q?`%SY_#=H}<&<0<#>_7Zz|OTD~2+`MFe^9E+-<*PFjG=IxZotFJiUitsX z>nqRIsPnUOBeSy7|JDLkN>+YWUP@LrESLYe>o7M|osgROxzg$LM*TH!g(f$3xh7GW zo0S3oxzfI=|7H|IjW|A0D01g{xVt6s#GYPip4wC7!}Chgcz7j=d^{79d|3bFPyBCJ zP%u3x!Dn^(Kh)>%s%f44{QECsm@fRwoHUu!Hk3PUEYQ?HK7IV-!|(5Zd-wLu>sK!) zUp)Wy+0!SFCmua~aDRMkbmZPIckldsdwA%lTQ_f99~|ia@rP?yzrWJgd-+mN_r2jY=Vth-L&+ya~=2i$SB1Mu=(1vHKlq41gH8enzX$ zzzWb)l5N=mt`-|=e@d+_qXMnW-re^C_wu3T-}9WExrqD_zTCL6y!rb~ie__l+%rkp zys8>$3RgOh#U&&l*c4G_nLi|;Cphy=%1n6933LHezTIsjAhBw;%S~7$72R!5x(Tcz z(6$})gJ?wnZvIATKL^7)c1{VgFyZ!HatNO zK-esR?Af=Hl2B~>ak)*NS=vF9jRb~2&b9me?S2+ow+2V-PU#q>1BB}<+8JSQm%En< zT5~$!A}~n+qJohIP2qaHiqJkZHxUZL*q`EN+e^o)j8BQ*TP}mFz!Zj3$*lqgT__)# zt)ID6YYvQOtXKr&fYJAMIMuqwEyd&XEX1^na5bf ziCjY(ez=}ICx$A8A6^_dC!=yX+Qxtiu3PbGizd3Zy|HkNe_O`qb{Zx3nz+6wYrX7K|eVd zkZ4;LmPi~mDl$&oWO$$WI;Vt1nZ0brOY!;V+8383-Lonu${y^~5pw)24|cRIJf9sD zz;98>090G0GvTfsi)Ap*Yc^-W?;RyE^7gm|3}^^FWiSF3IfXt^XB?5c`phg?&4*g6 zF|M=Hr0+BUMhjae?MOs@{uTEk@!nz|C;L558)M+cheXbrSNhN&GwskN=fuGVI$F`R zkgCczLNW3hdX?Z&_DdcqvA|>soCc-etIxz#xfpU)iW&L~3qrP6o)FDCewYe?6XCV@P>^f`S zDksvmSC5keVpH0>`1Q;KsAdH>M!Jn~$fup2g&-!g@@@rQ+_@4VDXfzRzk5ZGy>tN8 z0A{xJG|*~t9ZW~GK}FSzhLqZyta4~SJ)A6UB?^|d-?{SgR>5()Pt8?!s{(8tf*9l` zyA-F@Sk~tH+96cA^D!>z>$9IOUot^xR3nAP{2>^Mad)!2n)r*o73o>WCA0+5<8|-! zyHSjGzf7|4XD8ul^_2B;WV*k0#mE`A#mEN(v5IU0e*T@DUZ;H_dCFe2WRL7>w&klS zyhxt)oweO<=tpLp#nN8O#z=I-nfea;=BVZ7Z`WkMqmg!JbV%ZgXnWuA%V*g?tF6i* zS;giy1z#j?-m?2y@%&2@JLs-&XD5~Q7(KW6X@R|jH^Y<_HEv-$cL$;_F$9I1_fj{H zHL+KEqZ{j;ioSj1A*B&p%q5)O?In(o&fWp+S*dfkhSk(iv`3MG0d?SeH$%4pLqi63 zN{O{qRAD#8tgM%WOQ~K^J8snw^8@ZS$+n;}4wdLrq1Ja)CMg`iKtqX9rJWWLC%3%Q z-{sXMmGR#skMRuN1h>j?@Ll3w+R;)}{L-9?Sd{>M3KSC`B$v-`)2$W9A*oTSLcf}3 zM43xDZ0CdY?kyxNkA_fhh<$n$AnIVf9kH|T>qvmy|CD9k-&iv5q@8ha3c~Vk0Lq2= zh%fyMdvX63dpGsA^@wcKeEf%dNSTJc;0fHSU`?HQq*o_LRBO&KDAUIN$IQA09 zjSv?ggvx`NNZ5vAg@YiRm75LR(n?VZ5kS>=fGjc68o8BA-nXysL^*Dwu5FXsUxI)I zI?Ts^WRz%xcUVcJ_GmF-fLTS&m6FSy2MGmKodj`~;DrtBE}n$0qVHLtP8 zRTW~?6zb1%0H`PwDY?*6kr=yH9&}q5NIJCCLsDpaA$n z7=;CERJOr)@FXq6gc)9omJ&E3P17813UFTqDo#h=Ahjg5U ztKLxH*FFZ*+#*Ym2p?Qi^A<%x_=dfK*||y@=SH0#fiaansq$MR)gK51H6S(E$hxWer02R(`#6w(MzJ7yQOm8x&~XlhloPJG*&owm<2N5OX+96C6ouD!M_mt1p3yOP&e)=np55WuEfxW+)~S)eC2a~MlHZZ3f`<2W$}GsD zD?25u%AakN^Y$V08rh-I)jb&!P{iylvUyhu;opp+=e{?B5jlGCGsVs{ykqu~3FY+= z4&iGb9b?(cyF^_fM9YUf)GDcH!eK^ox+}Hgy$*+nE;iBbrQTfK!~Hf6hqjQ?j=@^I z#~whhYPPI5=p9PrfbPA?Wo5RJZL~yZ0>|0Bl^9R~TC5*1ASw-uD6m0GX|@v<ix3p{Cf@^XwjbzP7NyxeR}SgzS}*rd)6Vl6{hVk5DZ z2!P>dHDjwlW3&mkX#YBwB!ZJa&c)G!jzS<%bPGq9wMr*Kic2={F#AV2B(OMKa1UW2 z=#b;s0Kr?tPiFa{ZAi%oGrkM;Gj>v4_-4Pb3IY_0Zga-Mn8wxNi8?Vbk4X$}ZuBd0 zCpb`74g^`((+)cm-L&eeOI!*cVUVZ-Q2F*pVBvUXfN=n3W>p2*Ah(_}=HQx#Jvg9+ zq#y?5Ngm^hTNSBsHSLsgDQ1`+V06F_vd1*(xm6`9oX*!km3|PCDs*PR{&>i!^MTE= z+|qQQz4?7Kuq++fppzI1+r*I;Xb{t{zi*1v7iT)g1SCJWCWhpOY!)QDP3MbL9UMKs4dVt-oSPO;Nesq z{59uTHWHQMeOix55=S9tu+NG|$l0j@7k!-Qoe1Er3a_bDt|_f0;%1-Hi%S;(ZL(h* zkW_P_#x9Z-i0dTw`55%(!;LHTGfVwCv@1G+L|d50&q0%t;Q+bIs835TpYi|g7mPV_hpY_ z+HqdlT^$(Kai0`MAaN*X`WfSuxuT%(jsBC~io6b|&ZhMa7Iv(%YxKe~qRYt!z0O?7 z)fN$P!^mQANU29KaMh!X52l?{w&bZ3sb%6mdU#_rX5;){I&$`3-m)?9G{%yj2i>= zXT;eNGhesGna%z%IbO2~2bo4H(m?GA6h2wof6Mdk$Qpm|ao0*?AT$h^EcvD0{VMhn zyyq(Rns-5=7}ap4$2B>9vAJkaMjQGqCh5o=Vv zc4b2tghi*;tUykVr1%MAB$)9BQlr+nBNPLS7Fn^)m&O%Y+V^%6R!tVc_$I7>Ko=1W z{duwe51hMy!qlqoM%oKP_{j`G$t4*Pi=~^6pAde<;G4w#_~JJnf7$W?D!c~8wsHI0 z?P8k zVXtO3#iK2z{kSWRgmuHyzTJ7TaIXbgjkX0Oh8)M-`!iEO+^~r#U=Cep?w2u0z;=8w zqHU-o4r`29EooVp3-#C_PU>O9-ZAqnu>{g4C4Bq6Jh9=K#Kf7G zv;h=!-l*VloG;wztu)A{oEgN81-Ep!4!RON@O^$G<1_+x4z9X{Wr744@!pw}udfs@ z@JfXnP>_i`T1JHrRVkzuBm&Z^UD#awEt>|2{g;8E)Wu}4^|jVFr4XrZT8p6mUdet= zNNUR%LK0tu@43=NUVXf@iU{TR2JF7d`+}^J8T})Y6^z36`doeX2Vj?Fyrt~63 z77yB0oa{oCsC^kNf?y~*=TF6dOupZBG7)kP-T12O#kU#$3jF$wib5Nbf31o7((<4s zX0qDOC%Tj~ni&q;Dyxg*WUTj?* z@or9Q&;0Zt1wCS!@4@*;=1Ncov|QEd7Y3eDC3D_MNwrH9<|q7CAQF4Y^L`BsFAM?F zxVa2wYBvek6xx#m?ST{>Xp`=tGw^+qqc$4e1!hOP(B zmP`80mc=RDLp|iK*|M*0zadGz6k2!n3Fv`nbosYnvlPmts;;{AP58R@B_7h%xwQAn zf)&ft2m2g7ehUbi(Uur-+-@~I)`_hAc(oI`Ilx3#vdU$%|BYcVxNz*sjXi}%aV9FQ zk;VDf-uHK`c>epN#`XLU6D?aZKRj-mK|=m_D6sv(0ch432j?j~TyVsL6X z43?P=;n)Yk*Y2v(?d(U3jkk45jdkX_Y-8j80GUYW2)rB7b~;5)Fke_vRa$~ba_myI zU9YwRrZ;wQ8~qzC^}em=#qn^rb}!~pBT@yya?unTDAyFiWrOfM(AO#6nke!R!HXOF35*0U~b+D@sB3 zZ^!z1!NF^Rmd1^;|F)v^6KsDJ#V>3_Ifp0iPh`b!qBsp)UHF#Q^n*rlY*rwM^83~# z8f!BH{QBt3zB%!d$oH?ts*O|xtqzq$b*a;(XcBg& zvdFz_FM|BIW{Hp!vGgs)9cFW&{Z~gR< zQsn@yPO>&eyuD#6&)G=9;vTiIdyQ;P8~uo~>ECl@mdWGm5#|HPx*Ct6ZVt{%zJ^`i zwB#9UAPs%Ky;Hc1IN6C7^q&ZEKdrOtcaDF)zX2K7s@BHu0aq-XJ0`ZG*&8J+V@`b> zB2{(kz)OGl7$KL7-B#|3yo{w&RsInDeuw|L_YV)g`1a$wr!T$(7}rSyl94{yIrZNj zp??`q=DB-OIDD-g7OBT$m4&vZHgr&=FD|0npx22ZA+iYRE?|82!WjbhO#mr`vasYL zGnd9d$i=LPjLo2+0D+>S5CH1$Zx z9Vi`0(bub!&QoUb z$l^WWcFojHz!|#$GRT;?ond!%^I8Vh8)0Uz5xtV#y5_(3TgeVP`(oGi;-E^AeUswm zLMQ!I0Nw<HI+zjJ2<3dK61Q6?Bzd zMgpffx=b!jVD=F8Vm@MlNCWEE$DIsJ$V)y4CK3HJ?6vWjb&!cgY>RNi#kiE3R`o3? z=EQK~$PS{&z+o(kllW;PACso{C_1n`inPe5KNQ3j+tm{NeBeO}6@90fY8v9>F*m7l zlI`binz}xY$$}(sH!@{KkXaYH+YS-bXEu$eK6kb5}a4K z;i|VhO00?**7IDq?p1DS3DM4rq8#e#-?C6>1vX|ITku>^*YrE zWW9W(X+1{GV?8}|{MOQ^hfhB|@bt*}cTb)kHK1LdwZ|a;OHc938S&+e_;N=4m&Wtu zn)T(H_2ruN|LryFOHBAnO!!Mo_)ARq|3yp~^&iB9za;#>B>cZ5{J$jpza;$sO!&|E EU;pp&=Kufz literal 0 HcmV?d00001 From dedbc122c666a68de4759be7b7c70e698e3e2c28 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 2 Nov 2015 09:21:08 -0500 Subject: [PATCH 4/9] Overlay fixes and added class prop for tips --- web/react/components/create_post.jsx | 1 + web/react/components/sidebar.jsx | 1 + web/react/components/sidebar_header.jsx | 3 +-- web/react/components/tutorial/tutorial_tip.jsx | 15 +++++++++++++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index cb3148b7bd..1545cdfaac 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -393,6 +393,7 @@ export default class CreatePost extends React.Component { ); } diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 39d9808e95..c47919885c 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -358,6 +358,7 @@ export default class Sidebar extends React.Component { ); } diff --git a/web/react/components/sidebar_header.jsx b/web/react/components/sidebar_header.jsx index 96348f6883..0d48c6f880 100644 --- a/web/react/components/sidebar_header.jsx +++ b/web/react/components/sidebar_header.jsx @@ -44,8 +44,6 @@ export default class SidebarHeader extends React.Component { this.refs.dropdown.blockToggle = false; return; } - console.log(this.refs.tip); - this.refs.tip.toggle(); $('.team__header').find('.dropdown-toggle').dropdown('toggle'); } createTutorialTip() { @@ -97,6 +95,7 @@ export default class SidebarHeader extends React.Component { ref='tip' placement='right' screens={screens} + overlayClass='tip-overlay--sidebar' />
    ); diff --git a/web/react/components/tutorial/tutorial_tip.jsx b/web/react/components/tutorial/tutorial_tip.jsx index 3482a7cfaa..118209599a 100644 --- a/web/react/components/tutorial/tutorial_tip.jsx +++ b/web/react/components/tutorial/tutorial_tip.jsx @@ -79,6 +79,12 @@ export default class TutorialTip extends React.Component { ref='target' /> + +
    + + this.refs.target} > -
    +
    {this.props.screens[this.state.currentScreen]}
    {dots}
    @@ -113,7 +119,12 @@ export default class TutorialTip extends React.Component { } } +TutorialTip.defaultProps = { + overlayClass: '' +}; + TutorialTip.propTypes = { screens: React.PropTypes.array.isRequired, - placement: React.PropTypes.string.isRequired + placement: React.PropTypes.string.isRequired, + overlayClass: React.PropTypes.string }; From 4c5c42e37415df75d398027b6c2a6ea39e138688 Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Mon, 2 Nov 2015 20:57:23 +0500 Subject: [PATCH 5/9] Updating tutorials UI --- web/react/components/sidebar_header.jsx | 9 ++- .../components/tutorial/tutorial_tip.jsx | 3 +- web/sass-files/sass/partials/_responsive.scss | 22 +++++- web/sass-files/sass/partials/_tutorial.scss | 68 ++++++++++++++++++ web/static/images/tutorialTip.gif | Bin 12278 -> 18421 bytes 5 files changed, 97 insertions(+), 5 deletions(-) diff --git a/web/react/components/sidebar_header.jsx b/web/react/components/sidebar_header.jsx index 0d48c6f880..1bf70ce768 100644 --- a/web/react/components/sidebar_header.jsx +++ b/web/react/components/sidebar_header.jsx @@ -64,7 +64,8 @@ export default class SidebarHeader extends React.Component { screens.push( ); @@ -95,7 +98,7 @@ export default class SidebarHeader extends React.Component { ref='tip' placement='right' screens={screens} - overlayClass='tip-overlay--sidebar' + overlayClass='tip-overlay--header' />
    ); diff --git a/web/react/components/tutorial/tutorial_tip.jsx b/web/react/components/tutorial/tutorial_tip.jsx index 118209599a..c85acb3462 100644 --- a/web/react/components/tutorial/tutorial_tip.jsx +++ b/web/react/components/tutorial/tutorial_tip.jsx @@ -70,7 +70,7 @@ export default class TutorialTip extends React.Component { } return ( -
    +
    this.refs.target} >
    +
    {this.props.screens[this.state.currentScreen]}
    {dots}
    diff --git a/web/sass-files/sass/partials/_responsive.scss b/web/sass-files/sass/partials/_responsive.scss index 8f353c4019..a49a989522 100644 --- a/web/sass-files/sass/partials/_responsive.scss +++ b/web/sass-files/sass/partials/_responsive.scss @@ -179,6 +179,15 @@ } @media screen and (max-width: 1140px) { + .tip-overlay { + &.tip-overlay--chat { + margin: -10px 0 0 -10px; + .arrow { + right: 15px; + left: auto; + } + } + } .inner__wrap { &.move--left { .file-overlay { @@ -266,6 +275,18 @@ } } @media screen and (max-width: 768px) { + .tip-div { + left: 15px; + right: auto; + } + .tip-overlay { + &.tip-overlay--chat { + margin-left: 10px; + .arrow { + left: 32px; + } + } + } .file-details__container { display: block; .file-details__preview { @@ -482,7 +503,6 @@ padding-bottom: 10px; display: table; width: 100%; - table-layout: fixed; .post-body__cell { display: table-cell; padding-left: 45px; diff --git a/web/sass-files/sass/partials/_tutorial.scss b/web/sass-files/sass/partials/_tutorial.scss index fa93e46bf0..42183d5998 100644 --- a/web/sass-files/sass/partials/_tutorial.scss +++ b/web/sass-files/sass/partials/_tutorial.scss @@ -16,38 +16,93 @@ @include border-radius(3px); padding: 20px; z-index: 1000; + + .arrow { + border-width: 10px; + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + } + + &.tip-overlay--sidebar { + max-width: 75%; + margin: 50px 0 0 10px; + .arrow { + top: 80px; + left: -10px; + margin-top: -10px; + border-left-width: 0; + border-right-color: #fff; + } + } + + &.tip-overlay--header { + margin: 10px 0 0 10px; + .arrow { + top: 15px; + left: -10px; + border-left-width: 0; + border-right-color: #fff; + } + } + + &.tip-overlay--chat { + margin-top: -10px; + .arrow { + left: 50%; + margin-left: -10px; + border-bottom-width: 0; + border-top-color: #fff; + bottom: -10px; + } + } + h4 { font-size: em(16px); font-weight: 600; margin: 5px 0 15px; } + p { font-size: 13px; line-height: 1.6; + strong { font-weight: 600; } + } + .btn { background: #cccccc; color: #fff; @include border-radius(3px); border: none; margin-bottom: 10px; + &:hover, &:active, &:focus { color: #fff; border: none; background: #bbb; } + } + .tip-opt { font-size: 12px; + span { @include opacity(0.5); } + } + .tutorial__circles { margin: 1.5em 0px -1.7em -4px; + .circle { width: 7px; height: 7px; @@ -56,8 +111,11 @@ background: #000; @include opacity(0.4); } + } + } + } .tip-button { @@ -72,6 +130,16 @@ position:absolute; top:0px; right:0px; + + &.tip-overlay--header { + top: 20px; + } + + &.tip-overlay--sidebar { + left: 0; + top: -9px; + } + } .tutorial-steps__container { diff --git a/web/static/images/tutorialTip.gif b/web/static/images/tutorialTip.gif index 024dc3c09fb889003a65c0a938d8e7494836beac..f185ff4b96849f40ddb8f241c480f76712c61279 100644 GIT binary patch literal 18421 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 EU;pp&=Kufz From 51617a03bc191b1a0931c916abca21366fd2aeaf Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 2 Nov 2015 11:10:32 -0500 Subject: [PATCH 6/9] Remove modal links from tip --- web/react/components/sidebar_header.jsx | 31 +++---------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/web/react/components/sidebar_header.jsx b/web/react/components/sidebar_header.jsx index 1bf70ce768..949c82a3b9 100644 --- a/web/react/components/sidebar_header.jsx +++ b/web/react/components/sidebar_header.jsx @@ -49,43 +49,18 @@ export default class SidebarHeader extends React.Component { createTutorialTip() { const screens = []; - let teamSettingsLink = {'Team Settings'}; - if (Utils.isAdmin(UserStore.getCurrentUser().roles)) { - teamSettingsLink = ( - - {'Team Settings'} - - ); - } - screens.push(

    {'Main Menu'}

    {'The '}{'Main Menu'}{' is where you can '} - - {'Invite New Members'} - + {'Invite New Members'} {', access your '} - - {'Account Settings'} - + {'Account Settings'} {', and set your '}{'Theme Color'}{'.'}

    - {'Team administrators can also access their '}{teamSettingsLink}{' from this menu.'} + {'Team administrators can also access their '}{'Team Settings'}{' from this menu.'}

    ); From 95da41257155e4d1d8201471e7ae1f5d96450189 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 2 Nov 2015 11:13:21 -0500 Subject: [PATCH 7/9] Move period out of link --- web/react/components/tutorial/tutorial_intro_screens.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/react/components/tutorial/tutorial_intro_screens.jsx b/web/react/components/tutorial/tutorial_intro_screens.jsx index b37aac27cc..0f3050156c 100644 --- a/web/react/components/tutorial/tutorial_intro_screens.jsx +++ b/web/react/components/tutorial/tutorial_intro_screens.jsx @@ -120,8 +120,9 @@ export default class TutorialIntroScreens extends React.Component { href='mailto:feedback@mattermost.com' target='_blank' > - {'feedback@mattermost.com.'} + {'feedback@mattermost.com'} + {'.'}

    {'Click “Next” to enter Town Square. This is the first channel teammates see when they sign up - use it for posting updates everyone needs to know.'}
    From 35b11e0e61fd3c7130c3f54601ba05dd0b52fba3 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 2 Nov 2015 15:10:46 -0500 Subject: [PATCH 8/9] Fix merge issues --- web/react/components/center_panel.jsx | 42 ++++++++++++++++--- web/react/components/channel_view.jsx | 8 ++-- web/react/components/posts_view_container.jsx | 9 ++-- web/react/components/sidebar_header.jsx | 2 +- .../tutorial/tutorial_intro_screens.jsx | 4 -- 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/web/react/components/center_panel.jsx b/web/react/components/center_panel.jsx index b871fe81ae..a471c8af11 100644 --- a/web/react/components/center_panel.jsx +++ b/web/react/components/center_panel.jsx @@ -1,17 +1,47 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -var CreatePost = require('../components/create_post.jsx'); -var PostsViewContainer = require('../components/posts_view_container.jsx'); -var ChannelHeader = require('../components/channel_header.jsx'); -var Navbar = require('../components/navbar.jsx'); -var FileUploadOverlay = require('../components/file_upload_overlay.jsx'); +const TutorialIntroScreens = require('./tutorial/tutorial_intro_screens.jsx'); +const CreatePost = require('./create_post.jsx'); +const PostsViewContainer = require('./posts_view_container.jsx'); +const ChannelHeader = require('./channel_header.jsx'); +const Navbar = require('./navbar.jsx'); +const FileUploadOverlay = require('./file_upload_overlay.jsx'); + +const PreferenceStore = require('../stores/preference_store.jsx'); +const UserStore = require('../stores/user_store.jsx'); + +const Constants = require('../utils/constants.jsx'); +const TutorialSteps = Constants.TutorialSteps; +const Preferences = Constants.Preferences; export default class CenterPanel extends React.Component { constructor(props) { super(props); + + this.onPreferenceChange = this.onPreferenceChange.bind(this); + + const tutorialPref = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '0'}); + this.state = {showTutorialScreens: parseInt(tutorialPref.value, 10) === TutorialSteps.INTRO_SCREENS}; + } + componentDidMount() { + PreferenceStore.addChangeListener(this.onPreferenceChange); + } + componentWillUnmount() { + PreferenceStore.removeChangeListener(this.onPreferenceChange); + } + onPreferenceChange() { + const tutorialPref = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '0'}); + this.setState({showTutorialScreens: parseInt(tutorialPref.value, 10) <= TutorialSteps.INTRO_SCREENS}); } render() { + let postsContainer + if (this.state.showTutorialScreens) { + postsContainer = ; + } else { + postsContainer = ; + } + return (
    @@ -32,7 +62,7 @@ export default class CenterPanel extends React.Component {
    - + {postsContainer}
    {'Invite New Members'} {', access your '} {'Account Settings'} - {', and set your '}{'Theme Color'}{'.'} + {' and set your '}{'Theme Color'}{'.'}

    {'Team administrators can also access their '}{'Team Settings'}{' from this menu.'} diff --git a/web/react/components/tutorial/tutorial_intro_screens.jsx b/web/react/components/tutorial/tutorial_intro_screens.jsx index 0f3050156c..c7abccae35 100644 --- a/web/react/components/tutorial/tutorial_intro_screens.jsx +++ b/web/react/components/tutorial/tutorial_intro_screens.jsx @@ -20,10 +20,6 @@ export default class TutorialIntroScreens extends React.Component { this.state = {currentScreen: 0}; } - componentDidMount() { - const height = $(window).outerHeight() - 120; - $('.tutorial-steps__container').css('height', `${height}px`); - } handleNext() { if (this.state.currentScreen < 2) { this.setState({currentScreen: this.state.currentScreen + 1}); From 6b1e80d1d55783016d295f3f116891ce65ae6b06 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 2 Nov 2015 15:24:21 -0500 Subject: [PATCH 9/9] Fix typo --- web/react/components/center_panel.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/react/components/center_panel.jsx b/web/react/components/center_panel.jsx index a471c8af11..242c2c6379 100644 --- a/web/react/components/center_panel.jsx +++ b/web/react/components/center_panel.jsx @@ -35,7 +35,7 @@ export default class CenterPanel extends React.Component { this.setState({showTutorialScreens: parseInt(tutorialPref.value, 10) <= TutorialSteps.INTRO_SCREENS}); } render() { - let postsContainer + let postsContainer; if (this.state.showTutorialScreens) { postsContainer = ; } else {