mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 17:56:25 +00:00
revive articledetail
This commit is contained in:
53
browser/main/Components/MarkdownPreview.js
Normal file
53
browser/main/Components/MarkdownPreview.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import shell from 'shell'
|
||||||
|
import React, { PropTypes } from 'react'
|
||||||
|
import markdown from '../HomeContainer/lib/markdown'
|
||||||
|
|
||||||
|
function handleAnchorClick (e) {
|
||||||
|
shell.openExternal(e.target.href)
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class MarkdownPreview extends React.Component {
|
||||||
|
componentDidMount () {
|
||||||
|
this.addListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate () {
|
||||||
|
this.addListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
this.removeListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUpdate () {
|
||||||
|
this.removeListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
addListener () {
|
||||||
|
var anchors = React.findDOMNode(this).querySelectorAll('a')
|
||||||
|
|
||||||
|
for (var i = 0; i < anchors.length; i++) {
|
||||||
|
anchors[i].addEventListener('click', handleAnchorClick)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeListener () {
|
||||||
|
var anchors = React.findDOMNode(this).querySelectorAll('a')
|
||||||
|
|
||||||
|
for (var i = 0; i < anchors.length; i++) {
|
||||||
|
anchors[i].removeEventListener('click', handleAnchorClick)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div className={'MarkdownPreview' + (this.props.className != null ? ' ' + this.props.className : '')} dangerouslySetInnerHTML={{__html: ' ' + markdown(this.props.content)}}/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownPreview.propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
content: PropTypes.string
|
||||||
|
}
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
var React = require('react')
|
|
||||||
|
|
||||||
var Markdown = require('../Mixins/Markdown')
|
|
||||||
var ExternalLink = require('../Mixins/ExternalLink')
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [Markdown, ExternalLink],
|
|
||||||
propTypes: {
|
|
||||||
className: React.PropTypes.string,
|
|
||||||
content: React.PropTypes.string
|
|
||||||
},
|
|
||||||
componentDidMount: function () {
|
|
||||||
this.addListener()
|
|
||||||
},
|
|
||||||
componentDidUpdate: function () {
|
|
||||||
this.addListener()
|
|
||||||
},
|
|
||||||
componentWillUnmount: function () {
|
|
||||||
this.removeListener()
|
|
||||||
},
|
|
||||||
componentWillUpdate: function () {
|
|
||||||
this.removeListener()
|
|
||||||
},
|
|
||||||
addListener: function () {
|
|
||||||
var anchors = React.findDOMNode(this).querySelectorAll('a')
|
|
||||||
|
|
||||||
for (var i = 0; i < anchors.length; i++) {
|
|
||||||
anchors[i].addEventListener('click', this.openExternal)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeListener: function () {
|
|
||||||
var anchors = React.findDOMNode(this).querySelectorAll('a')
|
|
||||||
|
|
||||||
for (var i = 0; i < anchors.length; i++) {
|
|
||||||
anchors[i].removeEventListener('click', this.openExternal)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div className={'MarkdownPreview' + (this.props.className != null ? ' ' + this.props.className : '')} dangerouslySetInnerHTML={{__html: ' ' + this.markdown(this.props.content)}}/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
var React = require('react')
|
import React, { PropTypes } from 'react'
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class ModeIcon extends React.Component {
|
||||||
propTypes: {
|
getClassName () {
|
||||||
className: React.PropTypes.string,
|
|
||||||
mode: React.PropTypes.string
|
|
||||||
},
|
|
||||||
getClassName: function () {
|
|
||||||
var mode = this.props.mode
|
var mode = this.props.mode
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
// Script
|
// Script
|
||||||
@@ -69,11 +65,17 @@ module.exports = React.createClass({
|
|||||||
return 'fa fa-fw fa-file-text-o'
|
return 'fa fa-fw fa-file-text-o'
|
||||||
}
|
}
|
||||||
return 'fa fa-fw fa-code'
|
return 'fa fa-fw fa-code'
|
||||||
},
|
}
|
||||||
render: function () {
|
|
||||||
|
render () {
|
||||||
var className = this.getClassName()
|
var className = this.getClassName()
|
||||||
return (
|
return (
|
||||||
<i className={this.props.className + ' ' + className}/>
|
<i className={this.props.className + ' ' + className}/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
ModeIcon.propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
mode: PropTypes.string
|
||||||
|
}
|
||||||
@@ -1,9 +1,59 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
|
import moment from 'moment'
|
||||||
|
import { findWhere } from 'lodash'
|
||||||
|
import ModeIcon from '../../Components/ModeIcon'
|
||||||
|
import MarkdownPreview from '../../Components/MarkdownPreview'
|
||||||
|
import CodeEditor from '../../Components/CodeEditor'
|
||||||
|
|
||||||
export default class ArticleDetail extends React.Component {
|
export default class ArticleDetail extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
|
let { article, status, user } = this.props
|
||||||
|
|
||||||
|
let tags = article.Tags.length > 0 ? article.Tags.map(tag => {
|
||||||
|
return (
|
||||||
|
<a key={tag.id}>{tag.name}</a>
|
||||||
|
)
|
||||||
|
}) : (
|
||||||
|
<span className='noTags'>Not tagged yet</span>
|
||||||
|
)
|
||||||
|
let folder = findWhere(user.Folders, {id: article.FolderId})
|
||||||
|
let folderName = folder != null ? folder.name : '(unknown)'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='ArticleDetail'></div>
|
<div className='ArticleDetail show'>
|
||||||
|
<div className='detailInfo'>
|
||||||
|
<div className='left'>
|
||||||
|
<div className='info'>
|
||||||
|
<i className='fa fa-fw fa-square'/> {folderName}
|
||||||
|
by {article.User.profileName}
|
||||||
|
Created {moment(article.createdAt).format('YYYY/MM/DD')}
|
||||||
|
Updated {moment(article.updatedAt).format('YYYY/MM/DD')}
|
||||||
|
</div>
|
||||||
|
<div className='tags'><i className='fa fa-fw fa-tags'/>{tags}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='right'>
|
||||||
|
<button><i className='fa fa-fw fa-edit'/></button>
|
||||||
|
<button><i className='fa fa-fw fa-trash'/></button>
|
||||||
|
<button><i className='fa fa-fw fa-share-alt'/></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='detailBody'>
|
||||||
|
<div className='detailPanel'>
|
||||||
|
<div className='header'>
|
||||||
|
<ModeIcon className='mode' mode={article.mode}/>
|
||||||
|
<div className='title'>{article.title}</div>
|
||||||
|
</div>
|
||||||
|
{article.mode === 'markdown' ? <MarkdownPreview content={article.content}/> : <CodeEditor readOnly={true} onChange={this.handleContentChange} mode={article.mode} code={article.content}/>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArticleDetail.propTypes = {
|
||||||
|
article: PropTypes.shape(),
|
||||||
|
status: PropTypes.shape(),
|
||||||
|
user: PropTypes.shape()
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,66 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
|
import ProfileImage from '../../components/ProfileImage'
|
||||||
|
import ModeIcon from '../../Components/ModeIcon'
|
||||||
|
import moment from 'moment'
|
||||||
|
import { IDLE_MODE, CREATE_MODE, EDIT_MODE } from '../actions'
|
||||||
|
|
||||||
|
export default class ArticleList extends React.Component {
|
||||||
|
render () {
|
||||||
|
let { articles, status } = this.props
|
||||||
|
|
||||||
|
let articlesEl = articles.map(article => {
|
||||||
|
let tags = Array.isArray(article.Tags) && article.Tags.length > 0 ? article.Tags.map(tag => {
|
||||||
|
return (
|
||||||
|
<a key={tag.id}>#{tag.name}</a>
|
||||||
|
)
|
||||||
|
}) : (
|
||||||
|
<span>Not tagged yet</span>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={'article-' + article.id}>
|
||||||
|
<div className={'articleItem' + (false ? ' active' : '')}>
|
||||||
|
<div className='top'>
|
||||||
|
<i className='fa fa-fw fa-square'/>
|
||||||
|
by <ProfileImage className='profileImage' size='20' email={article.User.email}/> {article.User.profileName}
|
||||||
|
<span className='updatedAt'>{article.status != null ? article.status : moment(article.updatedAt).fromNow()}</span>
|
||||||
|
</div>
|
||||||
|
<div className='middle'>
|
||||||
|
<ModeIcon className='mode' mode={article.mode}/> <div className='title'>{article.status !== 'new' ? article.title : '(New article)'}</div>
|
||||||
|
</div>
|
||||||
|
<div className='bottom'>
|
||||||
|
<div className='tags'><i className='fa fa-fw fa-tags'/>{tags}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='divider'></div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
class ArticleList extends React.Component {
|
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<div className='ArticleList'></div>
|
<div className='ArticleList'>
|
||||||
|
{ status.mode === 'CREATE_MODE' ? (
|
||||||
|
<div key={'article-' + article.id}>
|
||||||
|
<div className={'articleItem'}>
|
||||||
|
<div className='top'>
|
||||||
|
<span className='updatedAt'>{}</span>
|
||||||
|
</div>
|
||||||
|
<div className='middle'>
|
||||||
|
<ModeIcon className='mode' mode={article.mode}/> <div className='title'>'(New article)'</div>
|
||||||
|
</div>
|
||||||
|
<div className='bottom'>
|
||||||
|
<div className='tags'><i className='fa fa-fw fa-tags'/></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='divider'></div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{articlesEl}
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ArticleList
|
ArticleList.propTypes = {
|
||||||
|
articles: PropTypes.array
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ export default class ArticleNavigator extends React.Component {
|
|||||||
render () {
|
render () {
|
||||||
let { user, status } = this.props
|
let { user, status } = this.props
|
||||||
if (user == null) return (<div className='ArticleNavigator'/>)
|
if (user == null) return (<div className='ArticleNavigator'/>)
|
||||||
console.log(user.Folders)
|
|
||||||
|
|
||||||
let activeFolder = findWhere(user.Folders, {id: status.folderId})
|
let activeFolder = findWhere(user.Folders, {id: status.folderId})
|
||||||
|
|
||||||
@@ -68,5 +67,8 @@ export default class ArticleNavigator extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArticleNavigator.propTypes = {
|
ArticleNavigator.propTypes = {
|
||||||
user: PropTypes.object
|
user: PropTypes.object,
|
||||||
|
state: PropTypes.shape({
|
||||||
|
folderId: PropTypes.number
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
export const USER_UPDATE = 'USER_UPDATE'
|
export const USER_UPDATE = 'USER_UPDATE'
|
||||||
|
export const ARTICLE_UPDATE = 'ARTICLE_UPDATE'
|
||||||
export const SWITCH_USER = 'SWITCH_USER'
|
export const SWITCH_USER = 'SWITCH_USER'
|
||||||
export const SWITCH_FOLDER = 'SWITCH_FOLDER'
|
export const SWITCH_FOLDER = 'SWITCH_FOLDER'
|
||||||
|
export const SWITCH_MODE = 'SWITCH_MODE'
|
||||||
|
|
||||||
|
export const IDLE_MODE = 'IDLE_MODE'
|
||||||
|
export const CREATE_MODE = 'CREATE_MODE'
|
||||||
|
export const EDIT_MODE = 'EDIT_MODE'
|
||||||
|
|
||||||
export function updateUser (user) {
|
export function updateUser (user) {
|
||||||
return {
|
return {
|
||||||
@@ -9,6 +15,13 @@ export function updateUser (user) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateArticles (userId, articles) {
|
||||||
|
return {
|
||||||
|
type: ARTICLE_UPDATE,
|
||||||
|
data: {userId, articles}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function switchUser (userId) {
|
export function switchUser (userId) {
|
||||||
return {
|
return {
|
||||||
type: SWITCH_USER,
|
type: SWITCH_USER,
|
||||||
@@ -22,3 +35,10 @@ export function switchFolder (folderId) {
|
|||||||
data: folderId
|
data: folderId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function switchMode (mode) {
|
||||||
|
return {
|
||||||
|
type: SWITCH_MODE,
|
||||||
|
data: mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,15 +27,15 @@ class HomeContainer extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { users, user, status } = this.props
|
const { users, user, status, articles, article } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='HomeContainer'>
|
<div className='HomeContainer'>
|
||||||
<UserNavigator users={users} />
|
<UserNavigator users={users} />
|
||||||
<ArticleNavigator user={user} status={status}/>
|
<ArticleNavigator user={user} status={status}/>
|
||||||
<ArticleTopBar/>
|
<ArticleTopBar/>
|
||||||
<ArticleList/>
|
<ArticleList articles={articles} status={status}/>
|
||||||
<ArticleDetail/>
|
<ArticleDetail user={user} article={article} status={status}/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -49,11 +49,17 @@ function remap (state) {
|
|||||||
|
|
||||||
let users = [currentUser, ...teams]
|
let users = [currentUser, ...teams]
|
||||||
let user = findWhere(users, {id: parseInt(status.userId, 10)})
|
let user = findWhere(users, {id: parseInt(status.userId, 10)})
|
||||||
|
if (user == null) user = users[0]
|
||||||
|
let articles = state.articles['team-' + user.id]
|
||||||
|
let article = findWhere(users, {id: status.articleId})
|
||||||
|
if (article == null) article = articles[0]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
users,
|
users,
|
||||||
user,
|
user,
|
||||||
status
|
status,
|
||||||
|
articles,
|
||||||
|
article
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +73,7 @@ HomeContainer.propTypes = {
|
|||||||
userId: PropTypes.string,
|
userId: PropTypes.string,
|
||||||
folderId: PropTypes.number
|
folderId: PropTypes.number
|
||||||
}),
|
}),
|
||||||
|
articles: PropTypes.array,
|
||||||
dispatch: PropTypes.func
|
dispatch: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,22 @@
|
|||||||
var request = require('superagent-promise')(require('superagent'), Promise)
|
var request = require('superagent-promise')(require('superagent'), Promise)
|
||||||
var apiUrl = require('../../../../config').apiUrl
|
var apiUrl = require('../../../../config').apiUrl
|
||||||
|
|
||||||
|
export function fetchCurrentUser () {
|
||||||
|
return request
|
||||||
|
.get(apiUrl + 'auth/user')
|
||||||
|
.set({
|
||||||
|
Authorization: 'Bearer ' + localStorage.getItem('token')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchArticles (userId) {
|
||||||
|
return request
|
||||||
|
.get(apiUrl + 'teams/' + userId + '/articles')
|
||||||
|
.set({
|
||||||
|
Authorization: 'Bearer ' + localStorage.getItem('token')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function createTeam (input) {
|
export function createTeam (input) {
|
||||||
return request
|
return request
|
||||||
.post(apiUrl + 'teams')
|
.post(apiUrl + 'teams')
|
||||||
|
|||||||
11
browser/main/HomeContainer/lib/markdown.js
Normal file
11
browser/main/HomeContainer/lib/markdown.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import markdownit from 'markdown-it'
|
||||||
|
|
||||||
|
var md = markdownit({
|
||||||
|
typographer: true,
|
||||||
|
linkify: true
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function markdown (content) {
|
||||||
|
if (content == null) content = ''
|
||||||
|
return md.render(content.toString())
|
||||||
|
}
|
||||||
@@ -1,8 +1,17 @@
|
|||||||
import { combineReducers } from 'redux'
|
import { combineReducers } from 'redux'
|
||||||
import { SWITCH_USER, SWITCH_FOLDER, USER_UPDATE } from './actions'
|
import { SWITCH_USER, SWITCH_FOLDER, SWITCH_MODE, USER_UPDATE, ARTICLE_UPDATE, IDLE_MODE, CREATE_MODE, EDIT_MODE } from './actions'
|
||||||
|
|
||||||
const initialCurrentUser = JSON.parse(localStorage.getItem('currentUser'))
|
const initialCurrentUser = JSON.parse(localStorage.getItem('currentUser'))
|
||||||
const initialParams = {}
|
const initialStatus = {
|
||||||
|
mode: IDLE_MODE
|
||||||
|
}
|
||||||
|
// init articles
|
||||||
|
let teams = Array.isArray(initialCurrentUser.Teams) ? initialCurrentUser.Teams : []
|
||||||
|
let users = [initialCurrentUser, ...teams]
|
||||||
|
const initialArticles = users.reduce((res, user) => {
|
||||||
|
res['team-' + user.id] = JSON.parse(localStorage.getItem('team-' + user.id))
|
||||||
|
return res
|
||||||
|
}, {})
|
||||||
|
|
||||||
function currentUser (state, action) {
|
function currentUser (state, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
@@ -26,13 +35,31 @@ function status (state, action) {
|
|||||||
case SWITCH_FOLDER:
|
case SWITCH_FOLDER:
|
||||||
state.folderId = action.data
|
state.folderId = action.data
|
||||||
return state
|
return state
|
||||||
|
case SWITCH_MODE:
|
||||||
|
state.mode = action.data
|
||||||
|
return state
|
||||||
default:
|
default:
|
||||||
if (state == null) return initialParams
|
if (state == null) return initialStatus
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function articles (state, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case ARTICLE_UPDATE:
|
||||||
|
let { userId, articles } = action.data
|
||||||
|
let teamKey = 'team-' + userId
|
||||||
|
localStorage.setItem(teamKey, JSON.stringify(articles))
|
||||||
|
state[teamKey] = articles
|
||||||
|
return state
|
||||||
|
default:
|
||||||
|
if (state == null) return initialArticles
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
currentUser,
|
currentUser,
|
||||||
status
|
status,
|
||||||
|
articles
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { createStore } from 'redux'
|
import { createStore } from 'redux'
|
||||||
import { Provider } from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import { updateUser } from './HomeContainer/actions'
|
import { updateUser, updateArticles } from './HomeContainer/actions'
|
||||||
import reducer from './HomeContainer/reducer'
|
import reducer from './HomeContainer/reducer'
|
||||||
import Hq from './Services/Hq'
|
import { fetchCurrentUser, fetchArticles } from './HomeContainer/lib/api'
|
||||||
import { Router, Route, IndexRoute } from 'react-router'
|
import { Router, Route, IndexRoute } from 'react-router'
|
||||||
import MainContainer from './Containers/MainContainer'
|
import MainContainer from './Containers/MainContainer'
|
||||||
import LoginContainer from './Containers/LoginContainer'
|
import LoginContainer from './Containers/LoginContainer'
|
||||||
@@ -58,9 +58,22 @@ React.render((
|
|||||||
loadingCover.parentNode.removeChild(loadingCover)
|
loadingCover.parentNode.removeChild(loadingCover)
|
||||||
|
|
||||||
// Refresh user information
|
// Refresh user information
|
||||||
Hq.getUser()
|
fetchCurrentUser()
|
||||||
.then(function (res) {
|
.then(function (res) {
|
||||||
store.dispatch(updateUser(res.body))
|
let user = res.body
|
||||||
|
store.dispatch(updateUser(user))
|
||||||
|
|
||||||
|
let users = [user].concat(user.Teams)
|
||||||
|
users.forEach(user => {
|
||||||
|
fetchArticles(user.id)
|
||||||
|
.then(res => {
|
||||||
|
store.dispatch(updateArticles(user.id, res.body))
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if (err.status == null) throw err
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.catch(function (err) {
|
.catch(function (err) {
|
||||||
console.error(err.message)
|
console.error(err.message)
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ noTagsColor = #999
|
|||||||
top 60px
|
top 60px
|
||||||
left 510px
|
left 510px
|
||||||
padding 10px
|
padding 10px
|
||||||
|
background-color #E6E6E6
|
||||||
|
border-top 1px solid borderColor
|
||||||
|
border-left 1px solid borderColor
|
||||||
*
|
*
|
||||||
-webkit-user-select all
|
-webkit-user-select all
|
||||||
.detailInfo
|
.detailInfo
|
||||||
|
|||||||
@@ -6,65 +6,65 @@ articleItemColor = #777
|
|||||||
top 60px
|
top 60px
|
||||||
left 260px
|
left 260px
|
||||||
width 250px
|
width 250px
|
||||||
border-right solid 1px highlightenBorderColor
|
border-top 1px solid borderColor
|
||||||
&>ul
|
border-right 4px solid #E6E6E6
|
||||||
absolute top bottom left right
|
overflow-y auto
|
||||||
overflow-y auto
|
noSelect()
|
||||||
noSelect()
|
&>div
|
||||||
li
|
border-right 1px solid borderColor
|
||||||
.articleItem
|
.articleItem
|
||||||
border solid 2px transparent
|
border solid 2px transparent
|
||||||
position relative
|
position relative
|
||||||
height 88px
|
height 88px
|
||||||
width 100%
|
width 100%
|
||||||
cursor pointer
|
cursor pointer
|
||||||
transition 0.1s
|
transition 0.1s
|
||||||
background-color white
|
background-color white
|
||||||
padding 0 10px
|
padding 0 10px
|
||||||
font-size 12px
|
font-size 12px
|
||||||
.top
|
.top
|
||||||
clearfix()
|
clearfix()
|
||||||
|
line-height 20px
|
||||||
|
padding 5px 0
|
||||||
|
color articleItemColor
|
||||||
|
.profileImage
|
||||||
|
vertical-align middle
|
||||||
|
.updatedAt
|
||||||
|
float right
|
||||||
line-height 20px
|
line-height 20px
|
||||||
padding 5px 0
|
.middle
|
||||||
|
clearfix()
|
||||||
|
padding 3px 0 7px
|
||||||
|
font-size 16px
|
||||||
|
.mode
|
||||||
|
float left
|
||||||
|
font-size 12px
|
||||||
|
line-height 16px
|
||||||
|
.title
|
||||||
|
float left
|
||||||
|
overflow ellipsis
|
||||||
|
padding 0 5px
|
||||||
|
.bottom
|
||||||
|
padding 5px 0
|
||||||
|
overflow-x auto
|
||||||
|
white-space nowrap
|
||||||
|
.tags
|
||||||
color articleItemColor
|
color articleItemColor
|
||||||
.profileImage
|
a
|
||||||
vertical-align middle
|
background-color brandColor
|
||||||
.updatedAt
|
color white
|
||||||
float right
|
border-radius 2px
|
||||||
line-height 20px
|
padding 1.5px 5px
|
||||||
.middle
|
margin 2px
|
||||||
clearfix()
|
font-size 10px
|
||||||
padding 3px 0 7px
|
opacity 0.8
|
||||||
font-size 16px
|
&:hover
|
||||||
.mode
|
opacity 1
|
||||||
float left
|
&:hover, &.hover
|
||||||
font-size 12px
|
background-color articleItemHoverBgColor
|
||||||
line-height 16px
|
|
||||||
.title
|
|
||||||
float left
|
|
||||||
overflow ellipsis
|
|
||||||
padding 0 5px
|
|
||||||
.bottom
|
|
||||||
padding 5px 0
|
|
||||||
overflow-x auto
|
|
||||||
white-space nowrap
|
|
||||||
.tags
|
|
||||||
color articleItemColor
|
|
||||||
a
|
|
||||||
background-color brandColor
|
|
||||||
color white
|
|
||||||
border-radius 2px
|
|
||||||
padding 1.5px 5px
|
|
||||||
margin 2px
|
|
||||||
font-size 10px
|
|
||||||
opacity 0.8
|
|
||||||
&:hover
|
|
||||||
opacity 1
|
|
||||||
&:hover, &.hover
|
|
||||||
background-color articleItemHoverBgColor
|
|
||||||
&:active, &.active
|
|
||||||
background-color white
|
|
||||||
&:active, &.active
|
&:active, &.active
|
||||||
border-color brandBorderColor
|
background-color white
|
||||||
.divider
|
&:active, &.active
|
||||||
border-bottom solid 1px borderColor
|
border-color brandBorderColor
|
||||||
|
.divider
|
||||||
|
border-bottom solid 1px borderColor
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ articleNavBgColor = #353535
|
|||||||
absolute top bottom
|
absolute top bottom
|
||||||
left 60px
|
left 60px
|
||||||
width 200px
|
width 200px
|
||||||
|
border-right 1px solid borderColor
|
||||||
color white
|
color white
|
||||||
.userInfo
|
.userInfo
|
||||||
height 60px
|
height 60px
|
||||||
@@ -48,7 +49,7 @@ articleNavBgColor = #353535
|
|||||||
.header
|
.header
|
||||||
border-bottom 1px solid borderColor
|
border-bottom 1px solid borderColor
|
||||||
padding-bottom 5px
|
padding-bottom 5px
|
||||||
margin-bottom 5px
|
margin-bottom 10px
|
||||||
clearfix()
|
clearfix()
|
||||||
.title
|
.title
|
||||||
float left
|
float left
|
||||||
@@ -75,8 +76,8 @@ articleNavBgColor = #353535
|
|||||||
.folders
|
.folders
|
||||||
margin-bottom 15px
|
margin-bottom 15px
|
||||||
.folderList button
|
.folderList button
|
||||||
height 44px
|
height 33px
|
||||||
width 200px
|
width 199px
|
||||||
border none
|
border none
|
||||||
text-align left
|
text-align left
|
||||||
font-size 14px
|
font-size 14px
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ module.exports = {
|
|||||||
'react-transform-catch-errors',
|
'react-transform-catch-errors',
|
||||||
'redux-devtools',
|
'redux-devtools',
|
||||||
'redux-devtools/lib/react',
|
'redux-devtools/lib/react',
|
||||||
'react-select'
|
'react-select',
|
||||||
|
'markdown-it',
|
||||||
|
'moment'
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['', '.js', '.jsx', 'styl']
|
extensions: ['', '.js', '.jsx', 'styl']
|
||||||
|
|||||||
Reference in New Issue
Block a user