1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 09:46:22 +00:00

add Preferences modal(30%done) & move some modules (actions, reducer, socket, store -> lib/~)

This commit is contained in:
Rokt33r
2015-10-18 17:17:25 +09:00
parent 1df4ed0fe9
commit 88ee94d4b6
16 changed files with 618 additions and 30 deletions

View File

@@ -1,6 +1,6 @@
import React, { PropTypes} from 'react'
import { connect } from 'react-redux'
import { CREATE_MODE, IDLE_MODE, switchUser } from './actions'
import { CREATE_MODE, IDLE_MODE, switchUser, NEW, refreshArticles } from 'boost/actions'
import UserNavigator from './HomePage/UserNavigator'
import ArticleNavigator from './HomePage/ArticleNavigator'
import ArticleTopBar from './HomePage/ArticleTopBar'
@@ -8,10 +8,9 @@ import ArticleList from './HomePage/ArticleList'
import ArticleDetail from './HomePage/ArticleDetail'
import { findWhere, findIndex, pick } from 'lodash'
import keygen from 'boost/keygen'
import { NEW, refreshArticles } from './actions'
import api from 'boost/api'
import auth from 'boost/auth'
import './socket'
import 'boost/socket'
class HomePage extends React.Component {
componentDidMount () {

View File

@@ -4,7 +4,7 @@ import { findWhere, uniq } from 'lodash'
import ModeIcon from 'boost/components/ModeIcon'
import MarkdownPreview from 'boost/components/MarkdownPreview'
import CodeEditor from 'boost/components/CodeEditor'
import { UNSYNCED, IDLE_MODE, CREATE_MODE, EDIT_MODE, switchMode, switchArticle, updateArticle, destroyArticle } from '../actions'
import { UNSYNCED, IDLE_MODE, CREATE_MODE, EDIT_MODE, switchMode, switchArticle, updateArticle, destroyArticle } from 'boost/actions'
import aceModes from 'boost/ace-modes'
import Select from 'react-select'
import linkState from 'boost/linkState'
@@ -20,7 +20,7 @@ var modeOptions = aceModes.map(function (mode) {
function makeInstantArticle (article) {
let instantArticle = Object.assign({}, article)
instantArticle.Tags = (typeof instantArticle.Tags === 'array') ? instantArticle.Tags.map(tag => tag.name) : []
instantArticle.Tags = Array.isArray(instantArticle.Tags) ? instantArticle.Tags.map(tag => tag.name) : []
return instantArticle
}
@@ -107,7 +107,7 @@ export default class ArticleDetail extends React.Component {
<i className='fa fa-fw fa-check'/> Sure
</button>
<button onClick={e => this.handleDeleteCancleButtonClick(e)}>
<i className='fa fa-fw fa-times'/> Cancle
<i className='fa fa-fw fa-times'/> Cancel
</button>
</div>
</div>

View File

@@ -2,7 +2,7 @@ import React, { PropTypes } from 'react'
import ProfileImage from 'boost/components/ProfileImage'
import ModeIcon from 'boost/components/ModeIcon'
import moment from 'moment'
import { switchArticle, NEW } from '../actions'
import { switchArticle, NEW } from 'boost/actions'
import FolderMark from 'boost/components/FolderMark'
export default class ArticleList extends React.Component {

View File

@@ -1,12 +1,21 @@
import React, { PropTypes } from 'react'
import ProfileImage from 'boost/components/ProfileImage'
import { findWhere } from 'lodash'
import { switchMode, CREATE_MODE } from '../actions'
import { switchMode, CREATE_MODE } from 'boost/actions'
import { openModal } from 'boost/modal'
import CreateNewFolder from 'boost/components/modal/CreateNewFolder'
import FolderMark from 'boost/components/FolderMark'
import Preferences from 'boost/components/modal/Preferences'
import CreateNewFolder from 'boost/components/modal/CreateNewFolder'
export default class ArticleNavigator extends React.Component {
componentDidMount () {
this.handlePreferencesButtonClick()
}
handlePreferencesButtonClick (e) {
openModal(Preferences)
}
handleNewPostButtonClick (e) {
let { dispatch } = this.props
@@ -27,7 +36,7 @@ export default class ArticleNavigator extends React.Component {
let folders = activeUser.Folders.map((folder, index) => {
return (
<button key={'folder-' + folder.id} className={activeFolder != null && activeFolder.id === folder.id ? 'active' : ''}>
<FolderMark id={folder.id}/> {folder.name}</button>
<FolderMark id={folder.id}/> {folder.name} {folder.public ? <i className='fa fa-fw fa-lock'/> : null}</button>
)
})
@@ -47,7 +56,7 @@ export default class ArticleNavigator extends React.Component {
<div className='userInfo'>
<div className='userProfileName'>{activeUser.profileName}</div>
<div className='userName'>{activeUser.name}</div>
<button className='settingBtn'><i className='fa fa-fw fa-chevron-down'/></button>
<button onClick={e => this.handlePreferencesButtonClick(e)} className='settingBtn'><i className='fa fa-fw fa-chevron-down'/></button>
</div>
<div className='controlSection'>
@@ -89,3 +98,4 @@ ArticleNavigator.propTypes = {
}),
dispatch: PropTypes.func
}

View File

@@ -1,78 +0,0 @@
// Action types
export const USER_UPDATE = 'USER_UPDATE'
export const ARTICLE_REFRESH = 'ARTICLE_REFRESH'
export const ARTICLE_UPDATE = 'ARTICLE_UPDATE'
export const ARTICLE_DESTROY = 'ARTICLE_DESTROY'
export const SWITCH_USER = 'SWITCH_USER'
export const SWITCH_FOLDER = 'SWITCH_FOLDER'
export const SWITCH_MODE = 'SWITCH_MODE'
export const SWITCH_ARTICLE = 'SWITCH_ARTICLE'
// Status - mode
export const IDLE_MODE = 'IDLE_MODE'
export const CREATE_MODE = 'CREATE_MODE'
export const EDIT_MODE = 'EDIT_MODE'
// Article status
export const NEW = 'NEW'
export const SYNCING = 'SYNCING'
export const UNSYNCED = 'UNSYNCED'
// DB
export function updateUser (user) {
return {
type: USER_UPDATE,
data: user
}
}
export function refreshArticles (userId, articles) {
return {
type: ARTICLE_REFRESH,
data: { userId, articles }
}
}
export function updateArticle (userId, article) {
return {
type: ARTICLE_UPDATE,
data: { userId, article }
}
}
export function destroyArticle (userId, articleKey) {
return {
type: ARTICLE_DESTROY,
data: { userId, articleKey }
}
}
// Nav
export function switchUser (userId) {
return {
type: SWITCH_USER,
data: userId
}
}
export function switchFolder (folderId) {
return {
type: SWITCH_FOLDER,
data: folderId
}
}
export function switchMode (mode) {
return {
type: SWITCH_MODE,
data: mode
}
}
export function switchArticle (articleKey) {
return {
type: SWITCH_ARTICLE,
data: articleKey
}
}

View File

@@ -53,12 +53,16 @@
<div id="content"></div>
<script src="../../submodules/ace/src-min/ace.js"></script>
<script>
<script type="text/javascript">
var version = require('remote').require('app').getVersion()
global.version = version
document.title = 'Boost' + ((version == null || version.length === 0) ? ' DEV' : '')
// require("babel-core/register")
// require('./index')
document.addEventListener('mousewheel', function(e) {
if(e.deltaY % 1 !== 0) {
e.preventDefault()
}
})
</script>
<script src="http://localhost:8080/assets/main.js"></script>
</body>

View File

@@ -1,6 +1,6 @@
import React from 'react'
import { Provider } from 'react-redux'
import { updateUser } from './actions'
import { updateUser } from 'boost/actions'
import { fetchCurrentUser } from 'boost/api'
import { Router, Route, IndexRoute } from 'react-router'
import MainPage from './MainPage'
@@ -8,7 +8,7 @@ import LoginPage from './LoginPage'
import SignupPage from './SignupPage'
import HomePage from './HomePage'
import auth from 'boost/auth'
import store, { devToolElement } from './store'
import store, { devToolElement } from 'boost/store'
require('../styles/main/index.styl')
function onlyUser (state, replaceState) {

View File

@@ -1,115 +0,0 @@
import { combineReducers } from 'redux'
import { findIndex } from 'lodash'
import { SWITCH_USER, SWITCH_FOLDER, SWITCH_MODE, SWITCH_ARTICLE, USER_UPDATE, ARTICLE_REFRESH, ARTICLE_UPDATE, ARTICLE_DESTROY, IDLE_MODE, CREATE_MODE } from './actions'
import auth from 'boost/auth'
const initialStatus = {
mode: IDLE_MODE
}
function getInitialArticles () {
let initialCurrentUser = auth.user()
if (initialCurrentUser == null) return []
let teams = Array.isArray(initialCurrentUser.Teams) ? initialCurrentUser.Teams : []
let users = [initialCurrentUser, ...teams]
let initialArticles = users.reduce((res, user) => {
res['team-' + user.id] = JSON.parse(localStorage.getItem('team-' + user.id))
return res
}, {})
return initialArticles
}
function currentUser (state, action) {
switch (action.type) {
case USER_UPDATE:
let user = action.data
return auth.user(user)
default:
if (state == null) return auth.user()
return state
}
}
function status (state, action) {
switch (action.type) {
case SWITCH_USER:
state.userId = action.data
state.mode = IDLE_MODE
state.folderId = null
return state
case SWITCH_FOLDER:
state.folderId = action.data
state.mode = IDLE_MODE
return state
case SWITCH_MODE:
state.mode = action.data
if (state.mode === CREATE_MODE) state.articleKey = null
return state
case SWITCH_ARTICLE:
state.articleKey = action.data
state.mode = IDLE_MODE
return state
default:
if (state == null) return initialStatus
return state
}
}
function genKey (id) {
return 'team-' + id
}
function articles (state, action) {
switch (action.type) {
case ARTICLE_REFRESH:
{
let { userId, articles } = action.data
let teamKey = genKey(userId)
localStorage.setItem(teamKey, JSON.stringify(articles))
state[teamKey] = articles
}
return state
case ARTICLE_UPDATE:
{
let { userId, article } = action.data
let teamKey = genKey(userId)
let articles = JSON.parse(localStorage.getItem(teamKey))
let targetIndex = findIndex(articles, _article => article.key === _article.key)
if (targetIndex < 0) articles.unshift(article)
else articles.splice(targetIndex, 1, article)
localStorage.setItem(teamKey, JSON.stringify(articles))
state[teamKey] = articles
}
return state
case ARTICLE_DESTROY:
{
let { userId, articleKey } = action.data
let teamKey = genKey(userId)
let articles = JSON.parse(localStorage.getItem(teamKey))
console.log(articles)
console.log(articleKey)
let targetIndex = findIndex(articles, _article => articleKey === _article.key)
if (targetIndex >= 0) articles.splice(targetIndex, 1)
localStorage.setItem(teamKey, JSON.stringify(articles))
state[teamKey] = articles
}
return state
default:
if (state == null) return getInitialArticles()
return state
}
}
export default combineReducers({
currentUser,
status,
articles
})

View File

@@ -1,44 +0,0 @@
import { API_URL } from '../../config'
import socketio from 'socket.io-client'
import auth from 'boost/auth'
import store from './store'
import { updateArticle, destroyArticle } from './actions'
export const CONN = 'CONN'
export const ALERT = 'ALERT'
export const USER_UPDATE = 'USER_UPDATE'
export const ARTICLE_UPDATE = 'ARTICLE_UPDATE'
export const ARTICLE_DESTROY = 'ARTICLE_DESTROY'
let io = socketio(API_URL)
io.on(CONN, function (data) {
console.log('connected', data)
let token = auth.token()
if (token != null) {
io.emit('JOIN', {token})
}
})
io.on(ALERT, function (data) {
console.log(ALERT, data)
})
io.on(USER_UPDATE, function (data) {
console.log(USER_UPDATE, data)
})
io.on(ARTICLE_UPDATE, function (data) {
console.log(ARTICLE_UPDATE, data)
let { userId, article } = data
store.dispatch(updateArticle(userId, article))
})
io.on(ARTICLE_DESTROY, function (data) {
console.log(ARTICLE_DESTROY, data)
let { userId, articleKey } = data
store.dispatch(destroyArticle(userId, articleKey))
})
export default io

View File

@@ -1,20 +0,0 @@
import React from 'react'
import reducer from './reducer'
import { createStore } from 'redux'
// Devtools
import { compose } from 'redux'
import { devTools, persistState } from 'redux-devtools'
import { DevTools, DebugPanel, LogMonitor } from 'redux-devtools/lib/react'
let finalCreateStore = compose(devTools(), persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)))(createStore)
let store = finalCreateStore(reducer)
export let devToolElement = (
<DebugPanel top right bottom>
<DevTools store={store} monitor={LogMonitor} visibleOnLoad={false}/>
</DebugPanel>
)
// let store = createStore(reducer)
export default store

View File

@@ -7,3 +7,4 @@
@require './lib/modal'
@require './lib/CreateNewTeam'
@require './lib/CreateNewFolder'
@require './lib/Preferences'

View File

@@ -0,0 +1,126 @@
menuColor = #808080
menuBgColor = #E6E6E6
closeBtnBgColor = #1790C6
iptFocusBorderColor = #369DCD
.Preferences.modal
padding 0
border-radius 5px
overflow hidden
width 720px
height 450px
&>.header
absolute top left right
height 50px
border-bottom 1px solid borderColor
background-color menuBgColor
&>.title
font-size 22px
font-weight bold
float left
padding-left 30px
line-height 50px
&>.closeBtn
float right
font-size 14px
background-color closeBtnBgColor
color white
padding 0 15px
height 33px
margin-top 9px
margin-right 15px
border none
border-radius 5px
&:hover
background-color lighten(closeBtnBgColor, 10%)
&>.nav
absolute left bottom
top 50px
width 180px
background-color menuBgColor
border-right 1px solid borderColor
&>button
width 100%
height 44px
font-size 18px
color menuColor
border none
background-color transparent
transition 0.1s
text-align left
padding-left 15px
&:hover
background-color darken(menuBgColor, 10%)
&.active, &:active
background-color brandColor
color white
&>.content
absolute right bottom
top 50px
left 180px
&>.section
padding 10px
border-bottom 1px solid borderColor
overflow-y auto
&:nth-last-child(1)
border-bottom none
&>.sectionTitle
font-size 18px
margin 10px 0 5px
color brandColor
&>.sectionInput
height 33px
margin-bottom 5px
clearfix()
label
width 180px
padding-left 15px
float left
line-height 33px
input
width 300px
float left
height 33px
border-radius 5px
border 1px solid borderColor
padding 0 10px
font-size 14px
outline none
&:focus
border-color iptFocusBorderColor
&>.sectionConfirm
clearfix()
padding 5px 15px
button
float right
background-color brandColor
color white
border none
border-radius 5px
height 33px
padding 0 15px
font-size 14px
&:hover
background-color lighten(brandColor, 10%)
.alert
float right
height 33px
padding 0 15px
border-radius 5px
margin-right 5px
line-height 33px
font-size 14px
&.info
background-color infoBackgroundColor
color infoTextColor
&.error
background-color errorBackgroundColor
color errorTextColor
&.success
background-color successBackgroundColor
color successTextColor
.description
marked()

View File

@@ -1,4 +1,4 @@
borderColor = #D0D0D0
borderColor = #D0D0D0 // using
highlightenBorderColor = darken(borderColor, 20%)
invBorderColor = #404849
brandBorderColor = #3FB399
@@ -7,12 +7,12 @@ buttonBorderColor = #4C4C4C
lightButtonColor = #898989
hoverBackgroundColor= transparentify(#444, 4%)
hoverBackgroundColor= transparentify(#444, 4%) // using
inactiveTextColor = #888
textColor = #4D4D4D
inactiveTextColor = #888 // using
textColor = #4D4D4D // using
backgroundColor= white
fontSize= 14px
fontSize= 14px // using
shadowColor= #C5C5C5
@@ -34,6 +34,7 @@ tableEvenBgColor = white
facebookColor= #3b5998
githubBtn= #201F1F
// using
successBackgroundColor= #E0F0D9
successTextColor= #3E753F
errorBackgroundColor= #F2DEDE