import PropTypes from 'prop-types' import React from 'react' import CSSModules from 'browser/lib/CSSModules' import styles from './Main.styl' import { connect } from 'react-redux' import SideNav from './SideNav' import TopBar from './TopBar' import NoteList from './NoteList' import Detail from './Detail' import dataApi from 'browser/main/lib/dataApi' import _ from 'lodash' import ConfigManager from 'browser/main/lib/ConfigManager' import mobileAnalytics from 'browser/main/lib/AwsMobileAnalyticsConfig' import eventEmitter from 'browser/main/lib/eventEmitter' import { hashHistory } from 'react-router' import store from 'browser/main/store' import i18n from 'browser/lib/i18n' import { getLocales } from 'browser/lib/Languages' import applyShortcuts from 'browser/main/lib/shortcutManager' const path = require('path') const electron = require('electron') const { remote } = electron class Main extends React.Component { constructor (props) { super(props) if (process.env.NODE_ENV === 'production') { mobileAnalytics.initAwsMobileAnalytics() } const { config } = props this.state = { isRightSliderFocused: false, listWidth: config.listWidth, navWidth: config.navWidth, isLeftSliderFocused: false, fullScreen: false, noteDetailWidth: 0, mainBodyWidth: 0 } this.toggleFullScreen = () => this.handleFullScreenButton() } getChildContext () { const { status, config } = this.props return { status, config } } init () { dataApi .addStorage({ name: 'My Storage Location', path: path.join(remote.app.getPath('home'), 'Boostnote') }) .then(data => { return data }) .then(data => { if (data.storage.folders[0] != null) { return data } else { return dataApi .createFolder(data.storage.key, { color: '#1278BD', name: 'Default' }) .then(_data => { return { storage: _data.storage, notes: data.notes } }) } }) .then(data => { console.log(data) store.dispatch({ type: 'ADD_STORAGE', storage: data.storage, notes: data.notes }) const defaultSnippetNote = dataApi .createNote(data.storage.key, { type: 'SNIPPET_NOTE', folder: data.storage.folders[0].key, title: 'Snippet note example', description: 'Snippet note example\nYou can store a series of snippets as a single note, like Gist.', snippets: [ { name: 'example.html', mode: 'html', content: "\n\n

Enjoy Boostnote!

\n\n" }, { name: 'example.js', mode: 'javascript', content: "var boostnote = document.getElementById('enjoy').innerHTML\n\nconsole.log(boostnote)" } ] }) .then(note => { store.dispatch({ type: 'UPDATE_NOTE', note: note }) }) const defaultMarkdownNote = dataApi .createNote(data.storage.key, { type: 'MARKDOWN_NOTE', folder: data.storage.folders[0].key, title: 'Welcome to Boostnote!', content: '# Welcome to Boostnote!\n## Click here to edit markdown :wave:\n\n\n\n## Docs :memo:\n- [Boostnote | Boost your happiness, productivity and creativity.](https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe)\n- [Cloud Syncing & Backups](https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup)\n- [How to sync your data across Desktop and Mobile apps](https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps)\n- [Convert data from **Evernote** to Boostnote.](https://github.com/BoostIO/Boostnote/wiki/Evernote)\n- [Keyboard Shortcuts](https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts)\n- [Keymaps in Editor mode](https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode)\n- [How to set syntax highlight in Snippet note](https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting)\n\n---\n\n## Article Archive :books:\n- [Reddit English](http://bit.ly/2mOJPu7)\n- [Reddit Spanish](https://www.reddit.com/r/boostnote_es/)\n- [Reddit Chinese](https://www.reddit.com/r/boostnote_cn/)\n- [Reddit Japanese](https://www.reddit.com/r/boostnote_jp/)\n\n---\n\n## Community :beers:\n- [GitHub](http://bit.ly/2AWWzkD)\n- [Twitter](http://bit.ly/2z8BUJZ)\n- [Facebook Group](http://bit.ly/2jcca8t)' }) .then(note => { store.dispatch({ type: 'UPDATE_NOTE', note: note }) }) return Promise.resolve(defaultSnippetNote) .then(defaultMarkdownNote) .then(() => data.storage) }) .then(storage => { hashHistory.push('/storages/' + storage.key) }) .catch(err => { throw err }) } componentDidMount () { const { dispatch, config } = this.props const supportedThemes = ['dark', 'white', 'solarized-dark', 'monokai'] if (supportedThemes.indexOf(config.ui.theme) !== -1) { document.body.setAttribute('data-theme', config.ui.theme) } else { document.body.setAttribute('data-theme', 'default') } if (getLocales().indexOf(config.ui.language) !== -1) { i18n.setLocale(config.ui.language) } else { i18n.setLocale('en') } applyShortcuts() // Reload all data dataApi.init().then(data => { dispatch({ type: 'INIT_ALL', storages: data.storages, notes: data.notes }) if (data.storages.length < 1) { this.init() } }) eventEmitter.on('editor:fullscreen', this.toggleFullScreen) } componentWillUnmount () { eventEmitter.off('editor:fullscreen', this.toggleFullScreen) } handleLeftSlideMouseDown (e) { e.preventDefault() this.setState({ isLeftSliderFocused: true }) } handleRightSlideMouseDown (e) { e.preventDefault() this.setState({ isRightSliderFocused: true }) } handleMouseUp (e) { // Change width of NoteList component. if (this.state.isRightSliderFocused) { this.setState( { isRightSliderFocused: false }, () => { const { dispatch } = this.props const newListWidth = this.state.listWidth // TODO: ConfigManager should dispatch itself. ConfigManager.set({ listWidth: newListWidth }) dispatch({ type: 'SET_LIST_WIDTH', listWidth: newListWidth }) } ) } // Change width of SideNav component. if (this.state.isLeftSliderFocused) { this.setState( { isLeftSliderFocused: false }, () => { const { dispatch } = this.props const navWidth = this.state.navWidth // TODO: ConfigManager should dispatch itself. ConfigManager.set({ navWidth }) dispatch({ type: 'SET_NAV_WIDTH', navWidth }) } ) } } handleMouseMove (e) { if (this.state.isRightSliderFocused) { const offset = this.refs.body.getBoundingClientRect().left let newListWidth = e.pageX - offset if (newListWidth < 10) { newListWidth = 10 } else if (newListWidth > 600) { newListWidth = 600 } this.setState({ listWidth: newListWidth }) } if (this.state.isLeftSliderFocused) { let navWidth = e.pageX if (navWidth < 80) { navWidth = 80 } else if (navWidth > 600) { navWidth = 600 } this.setState({ navWidth: navWidth }) } } handleFullScreenButton (e) { this.setState({ fullScreen: !this.state.fullScreen }, () => { const noteDetail = document.querySelector('.NoteDetail') const noteList = document.querySelector('.NoteList') const mainBody = document.querySelector('#main-body') if (this.state.fullScreen) { this.hideLeftLists(noteDetail, noteList, mainBody) } else { this.showLeftLists(noteDetail, noteList, mainBody) } }) } hideLeftLists (noteDetail, noteList, mainBody) { this.setState({ noteDetailWidth: noteDetail.style.left }) this.setState({ mainBodyWidth: mainBody.style.left }) noteDetail.style.left = '0px' mainBody.style.left = '0px' noteList.style.display = 'none' } showLeftLists (noteDetail, noteList, mainBody) { noteDetail.style.left = this.state.noteDetailWidth mainBody.style.left = this.state.mainBodyWidth noteList.style.display = 'inline' } render () { const { config } = this.props // the width of the navigation bar when it is folded/collapsed const foldedNavigationWidth = 44 return (
this.handleMouseMove(e)} onMouseUp={e => this.handleMouseUp(e)} > {!config.isSideNavFolded &&
this.handleLeftSlideMouseDown(e)} draggable='false' >
}
this.handleRightSlideMouseDown(e)} draggable='false' >
) } } Main.childContextTypes = { status: PropTypes.shape({ updateReady: PropTypes.bool.isRequired }).isRequired, config: PropTypes.shape({}).isRequired } Main.propTypes = { dispatch: PropTypes.func, data: PropTypes.shape({}).isRequired } export default connect(x => x)(CSSModules(Main, styles))