Browse Source

stable integration of plugin into tracim source

Skylsmoi 6 years ago
parent
commit
0c31d73da2

+ 0 - 30
src/component/PluginContentType.jsx View File

@@ -1,30 +0,0 @@
1
-import React from 'react'
2
-import PageHtml from '../plugin/ContentType/PageHtml/PageHtml.jsx'
3
-import Thread from '../plugin/ContentType/Thread/Thread.jsx'
4
-import Timeline from './Timeline.jsx'
5
-import {FILE_TYPE} from '../helper.js'
6
-
7
-const PluginContentType = props => {
8
-  const [leftPart, rightPart] = (() => {
9
-    switch (props.file.type) {
10
-      case FILE_TYPE[0].name: // pageHtml
11
-        return [
12
-          <PageHtml version={props.file.version} text={props.file.text} key={'pageHtml'} />,
13
-          <Timeline customClass={`${props.customClass}__contentpage`} key={'pageHtml__timeline'} />
14
-        ]
15
-      case FILE_TYPE[3].name: // thread
16
-        return [
17
-          <Thread />
18
-        ]
19
-    }
20
-  })()
21
-  return [leftPart, rightPart]
22
-  // const { componentLeft, componentRight, customClass, } = FILE_TYPE.find(p => p.name === props.file.type)
23
-  //
24
-  // return [
25
-  //   genericPlugin.componentLeft,
26
-  //   genericPlugin.componentRight
27
-  // ]
28
-}
29
-
30
-export default PluginContentType

+ 0 - 62
src/component/Workspace/FileContentViewer.jsx View File

@@ -1,62 +0,0 @@
1
-import React from 'react'
2
-import PropTypes from 'prop-types'
3
-import PopinFixed from '../common/PopinFixed/PopinFixed'
4
-import PopinFixedHeader from '../common/PopinFixed/PopinFixedHeader.jsx'
5
-import PopinFixedOption from '../common/PopinFixed/PopinFixedOption.jsx'
6
-import PopinFixedContent from '../common/PopinFixed/PopinFixedContent.jsx'
7
-import PageHtml from './FileType/PageHtml.jsx'
8
-import Thread from './FileType/Thread.jsx'
9
-import Preview from './FileType/File.jsx'
10
-import Timeline from '../Timeline.jsx'
11
-import { FILE_TYPE } from '../../helper.js'
12
-
13
-const FileContentViewer = props => {
14
-  const { customClass, icon } = FILE_TYPE.find(f => f.name === props.file.type) || {customClass: '', icon: ''}
15
-
16
-  const [leftPart, rightPart] = (() => {
17
-    switch (props.file.type) {
18
-      case FILE_TYPE[0].name: // pageHtml
19
-        return [
20
-          <PageHtml version={props.file.version} text={props.file.text} />,
21
-          <Timeline customClass={`${customClass}__contentpage`} />
22
-        ]
23
-      case FILE_TYPE[2].name: // file (preview)
24
-        return [
25
-          <Preview />,
26
-          <Timeline customClass={`${customClass}__contentpage`} />
27
-        ]
28
-      case FILE_TYPE[3].name: // thread
29
-        return [
30
-          <Thread />
31
-        ]
32
-    }
33
-  })()
34
-
35
-  return (
36
-    <PopinFixed customClass={`${customClass}`}>
37
-      <PopinFixedHeader
38
-        customClass={`${customClass}`}
39
-        icon={icon}
40
-        name={props.file.title}
41
-        onClickCloseBtn={props.onClose}
42
-      />
43
-
44
-      <PopinFixedOption customClass={`${customClass}`} />
45
-
46
-      <PopinFixedContent customClass={`${customClass}__contentpage`}>
47
-        { leftPart }
48
-        { rightPart }
49
-      </PopinFixedContent>
50
-    </PopinFixed>
51
-  )
52
-}
53
-
54
-export default FileContentViewer
55
-
56
-FileContentViewer.PropTypes = {
57
-  file: PropTypes.shape({
58
-    type: PropTypes.oneOf(FILE_TYPE.map(f => f.name)).isRequired,
59
-    title: PropTypes.string.isRequired
60
-  }).isRequired,
61
-  onClose: PropTypes.func.isRequired
62
-}

+ 1 - 4
src/component/Workspace/FileItem.jsx View File

@@ -1,11 +1,8 @@
1 1
 import React from 'react'
2 2
 import PropTypes from 'prop-types'
3 3
 import classnames from 'classnames'
4
-import { FILE_TYPE } from '../../helper.js'
5 4
 
6 5
 const FileItem = props => {
7
-  const iconType = (FILE_TYPE.find(f => f.name === props.type) || {icon: ''}).icon
8
-
9 6
   const iconStatus = (() => {
10 7
     switch (props.status) {
11 8
       case 'current':
@@ -23,7 +20,7 @@ const FileItem = props => {
23 20
     <div className={classnames('file', 'align-items-center', props.customClass)} onClick={props.onClickItem}>
24 21
       <div className='col-2 col-sm-2 col-md-2 col-lg-2 col-xl-1'>
25 22
         <div className='file__type'>
26
-          <i className={iconType} />
23
+          <i className={props.icon} />
27 24
         </div>
28 25
       </div>
29 26
       <div className='col-8 col-sm-8 col-md-8 col-lg-8 col-xl-10'>

+ 4 - 2
src/component/Workspace/Folder.jsx View File

@@ -21,7 +21,7 @@ class Folder extends Component {
21 21
   }
22 22
 
23 23
   render () {
24
-    const { title, content } = this.props.folderData
24
+    const { plugin, folderData: { title, content } } = this.props
25 25
     return (
26 26
       <div className={classnames('folder', {'active': this.state.open})}>
27 27
         <div className='folder__header' onClick={this.handleClickToggleFolder}>
@@ -57,6 +57,7 @@ class Folder extends Component {
57 57
           { content.map(c => c.type === 'folder'
58 58
             ? <Folder folderData={c} key={c.id} />
59 59
             : <FileItem
60
+              icon={(plugin[c.type] || {icon: ''}).icon}
60 61
               name={c.title}
61 62
               type={c.type}
62 63
               status={c.status}
@@ -76,5 +77,6 @@ Folder.propTypes = {
76 77
   folderData: PropTypes.shape({
77 78
     title: PropTypes.string.isRequired,
78 79
     content: PropTypes.array
79
-  })
80
+  }),
81
+  plugin: PropTypes.object
80 82
 }

+ 1 - 1
src/component/common/Card/Card.jsx View File

@@ -22,7 +22,7 @@ Card.propTypes = {
22 22
       children[1].type !== CardBody
23 23
       // children.some(p => p.type !== CardHeader && p.type !== CardBody)
24 24
     ) {
25
-      return new Error(`PropType Error: childrens of ${componentName} must be: 1 CardHeader and 1 CardBody.`)
25
+      return new Error(`PropType Error: children of ${componentName} must be: 1 CardHeader and 1 CardBody.`)
26 26
     }
27 27
   }).isRequired,
28 28
   customClass: PropTypes.string

+ 10 - 21
src/component/common/PopinFixed/PopinFixedContent.jsx View File

@@ -1,23 +1,22 @@
1 1
 import React from 'react'
2 2
 import classnames from 'classnames'
3 3
 import PropTypes from 'prop-types'
4
-// import PageHtml from '../../../plugin/ContentType/PageHtml/PageHtml.jsx'
5
-// import Thread from '../../../plugin/ContentType/Thread/Thread.jsx'
6
-// import Timeline from '../../Timeline.jsx'
7 4
 
8 5
 const PopinFixedContent = props => {
9 6
   return props.children.length === 2
10 7
     ? (
11
-      <div className={classnames('wsFileGeneric__contentpage', `${props.customClass}`)}>
12
-        {props.children[0]}
8
+      <div className={classnames('wsFileGeneric__content', `${props.customClass}__content`)}>
9
+        <div className={classnames('wsFileGeneric__content__left', `${props.customClass}__content__left`)}>
10
+          {props.children[0]}
11
+        </div>
13 12
 
14
-        <div className={classnames('wsFileGeneric__wrapper', `${props.customClass}__wrapper`)}>
13
+        <div className={classnames('wsFileGeneric__content__right', `${props.customClass}__content__right`)}>
15 14
           {props.children[1]}
16 15
         </div>
17 16
       </div>
18 17
     )
19 18
     : (
20
-      <div className={classnames('wsFileGeneric__contentpage', `${props.customClass}`)}>
19
+      <div className={classnames('wsFileGeneric__content', `${props.customClass}__content`)}>
21 20
         { props.children }
22 21
       </div>
23 22
     )
@@ -26,18 +25,8 @@ const PopinFixedContent = props => {
26 25
 export default PopinFixedContent
27 26
 
28 27
 PopinFixedContent.propTypes = {
29
-  customClass: PropTypes.string
30
-
31
-  // from http://www.mattzabriskie.com/blog/react-validating-children
32
-  // children: PropTypes.arrayOf((children, key, componentName /* , location, propFullName */) => {
33
-  //   if (
34
-  //     (Array.isArray(children.length) && (
35
-  //       children.length > 2 ||
36
-  //       (children.length === 2 && children.some(c => ![PageHtml, Thread, Timeline].includes(c.type)))
37
-  //     )) ||
38
-  //     (children.type === Timeline)
39
-  //   ) {
40
-  //     return new Error(`PropType Error: childrens of ${componentName} must be one of [PageHtml, Thread, Timeline, undefined].`)
41
-  //   }
42
-  // }).isRequired
28
+  customClass: PropTypes.string,
29
+  children: PropTypes.arrayOf((children, key, componentName /* , location, propFullName */) =>
30
+    children.length !== 2 && new Error(`PropType Error: ${componentName} must have 2 children.`)
31
+  ).isRequired
43 32
 }

+ 6 - 35
src/container/WorkspaceContent.jsx View File

@@ -7,16 +7,12 @@ import PageWrapper from '../component/common/layout/PageWrapper.jsx'
7 7
 import PageTitle from '../component/common/layout/PageTitle.jsx'
8 8
 import PageContent from '../component/common/layout/PageContent.jsx'
9 9
 import DropdownCreateButton from '../component/common/Input/DropdownCreateButton.jsx'
10
+import pluginDatabase from '../plugin/index.js'
10 11
 import {
11 12
   getPluginList,
12 13
   getWorkspaceContent
13 14
 } from '../action-creator.async.js'
14
-import { setActiveFileContent, hideActiveFileContent } from '../action-creator.sync.js'
15
-import PopinFixed from '../component/common/PopinFixed/PopinFixed.jsx'
16
-import PopinFixedHeader from '../component/common/PopinFixed/PopinFixedHeader.jsx'
17
-import PopinFixedOption from '../component/common/PopinFixed/PopinFixedOption.jsx'
18
-import PopinFixedContent from '../component/common/PopinFixed/PopinFixedContent.jsx'
19
-import PluginContentType from '../component/PluginContentType.jsx'
15
+import { setActiveFileContent } from '../action-creator.sync.js'
20 16
 
21 17
 class WorkspaceContent extends React.Component {
22 18
   constructor (props) {
@@ -32,39 +28,13 @@ class WorkspaceContent extends React.Component {
32 28
   }
33 29
 
34 30
   handleClickFileItem = file => {
35
-    console.log(file)
36 31
     this.props.dispatch(setActiveFileContent(file))
37 32
   }
38 33
 
39
-  handleClickCloseBtn = () => {
40
-    this.props.dispatch(hideActiveFileContent())
41
-  }
42
-
43 34
   render () {
44 35
     const { workspace, activeFileContent, plugin } = this.props
45 36
 
46
-    const pluginContent = (() => {
47
-      switch (activeFileContent.type) {
48
-        case 'PageHtml':
49
-          return <PopinFixed customClass={`${plugin.pageHtml.customClass}`}>
50
-            <PopinFixedHeader
51
-              customClass={`${plugin.pageHtml.customClass}`}
52
-              icon={plugin.pageHtml.icon}
53
-              name={activeFileContent.title}
54
-              onClickCloseBtn={this.handleClickCloseBtn}
55
-            />
56
-
57
-            <PopinFixedOption customClass={`${plugin.pageHtml.customClass}`} />
58
-
59
-            <PopinFixedContent customClass={`${plugin.pageHtml.customClass}__contentpage`}>
60
-              <PluginContentType
61
-                file={activeFileContent}
62
-                customClass={`${plugin.pageHtml.customClass}`}
63
-              />
64
-            </PopinFixedContent>
65
-          </PopinFixed>
66
-      }
67
-    })()
37
+    const PluginContainer = (pluginDatabase.find(p => p.name === activeFileContent.type) || {container: '<div>unknow</div>'}).container
68 38
 
69 39
     return (
70 40
       <PageWrapper customeClass='workspace'>
@@ -82,11 +52,12 @@ class WorkspaceContent extends React.Component {
82 52
             <FileItemHeader />
83 53
 
84 54
             { workspace.content.map(c => c.type === 'folder'
85
-              ? <Folder folderData={c} key={c.id} />
55
+              ? <Folder plugin={plugin} folderData={c} key={c.id} />
86 56
               : (
87 57
                 <FileItem
88 58
                   name={c.title}
89 59
                   type={c.type}
60
+                  icon={(plugin[c.type] || {icon: ''}).icon}
90 61
                   status={c.status}
91 62
                   onClickItem={() => this.handleClickFileItem(c)}
92 63
                   key={c.id}
@@ -98,7 +69,7 @@ class WorkspaceContent extends React.Component {
98 69
           <DropdownCreateButton customClass='workspace__content__button mb-5' />
99 70
 
100 71
           <div id='pluginContainer'>
101
-            { activeFileContent.display && pluginContent }
72
+            { activeFileContent.display && <PluginContainer /> }
102 73
           </div>
103 74
         </PageContent>
104 75
 

+ 5 - 2
src/css/Generic.styl View File

@@ -260,6 +260,9 @@
260 260
         &:hover , &:focus
261 261
           font-size 22px
262 262
           color blue
263
-  &__wrapper
263
+  &__content
264 264
     display flex
265
-    flex-direction column
265
+    &__left
266
+      width 55%
267
+    &__right
268
+      width 45%

+ 1 - 1
src/css/Header.styl View File

@@ -86,7 +86,7 @@
86 86
               margin-right 10px
87 87
               color darkGrey
88 88
           .profilgroup__sub
89
-            color dark-grey
89
+            color darkGrey
90 90
             cursor pointer
91 91
             &:focus
92 92
               box-shadow none

+ 3 - 3
src/css/PagePreview.styl View File

@@ -99,13 +99,13 @@
99 99
         padding 10px 0
100 100
         text-align center
101 101
         font-size 20px
102
-        color dark-grey
102
+        color darkGrey
103 103
         background-color grey-hover
104 104
       &__messagelist
105 105
         min-height 300px
106 106
         &__item
107 107
           &__content
108
-            color dark-grey
108
+            color darkGrey
109 109
         &__version
110 110
           margin-top 40px
111 111
           background-color grey-hover
@@ -118,7 +118,7 @@
118 118
             background-color previewColor
119 119
             & > i
120 120
               margin-right 10px
121
-              color dark-grey
121
+              color darkGrey
122 122
               font-size 22px
123 123
             &:hover
124 124
               background-color lightPreviewColor

+ 2 - 3
src/css/Timeline.styl View File

@@ -3,14 +3,13 @@
3 3
   flex-direction column
4 4
   margin 10px
5 5
   border-radius 10px
6
-  width 45%
7 6
   height 100%
8 7
   &__header
9 8
     border-radius 10px 10px 0 0
10 9
     padding 15px
11 10
     text-align center
12 11
     font-size 20px
13
-    color dark-grey
12
+    color darkGrey
14 13
     background-color grey-hover
15 14
   &__messagelist
16 15
     flex 1 1 0
@@ -54,7 +53,7 @@
54 53
         font-size 17px
55 54
         & > i
56 55
           margin-right 10px
57
-          color dark-grey
56
+          color darkGrey
58 57
           font-size 22px
59 58
       &__date
60 59
         color fontColor

+ 0 - 2
src/css/index.styl View File

@@ -17,8 +17,6 @@ html, body, #content, #content > div
17 17
 @import 'FileItemHeader.styl'
18 18
 @import 'Folder.styl'
19 19
 
20
-@import '../plugin/ContentType/Thread/Thread.styl'
21
-@import '../plugin/ContentType/PageHtml/PageHtml.styl'
22 20
 @import 'Timeline.styl'
23 21
 @import 'File.styl'
24 22
 

+ 0 - 38
src/helper.js View File

@@ -4,41 +4,3 @@ export const FETCH_CONFIG = {
4 4
     'Content-Type': 'application/json'
5 5
   }
6 6
 }
7
-
8
-export const FILE_TYPE = [{
9
-  name: 'PageHtml',
10
-  componentLeft: 'PageHtml',
11
-  componentRight: 'Timeline',
12
-  customClass: 'wsFilePageHtml',
13
-  icon: 'fa fa-file-word-o'
14
-}, {
15
-  name: 'PageMarkdown',
16
-  componentLeft: 'PageMarkdown',
17
-  componentRight: 'undefined',
18
-  customClass: 'wsFilePageMarkdown',
19
-  icon: 'fa fa-file-code-o'
20
-}, {
21
-  name: 'File',
22
-  componentLeft: 'File',
23
-  componentRight: 'undefined',
24
-  customClass: 'wsFileFile',
25
-  icon: 'fa fa-file-image-o'
26
-}, {
27
-  name: 'Thread',
28
-  componentLeft: 'Thread',
29
-  componentRight: 'undefined',
30
-  customClass: 'wsFileThread',
31
-  icon: 'fa fa-comments-o'
32
-}, {
33
-  name: 'Task',
34
-  componentLeft: 'Task',
35
-  componentRight: 'undefined',
36
-  customClass: 'wsFileTask',
37
-  icon: 'fa fa-list-ul'
38
-}, {
39
-  name: 'Issue',
40
-  componentLeft: 'Issue',
41
-  componentRight: 'undefined',
42
-  customClass: 'wsFileIssue',
43
-  icon: 'fa fa-ticket'
44
-}]

+ 4 - 13
src/plugin/ContentType/PageHtml/PageHtml.styl View File

@@ -1,3 +1,5 @@
1
+@import '../../../css/Variable.styl'
2
+
1 3
 .wsFilePageHtml
2 4
   width 1200px
3 5
   height calc(100% - 85px)
@@ -8,13 +10,10 @@
8 10
       .fa-file-word-o
9 11
         color white
10 12
   &__contentpage
11
-    display flex
12
-    overflow-Y auto
13 13
     &__textnote
14 14
       margin 10px
15 15
       border-radius 10px
16 16
       padding 25px
17
-      width 55%
18 17
       height 100%
19 18
       background-color off-white
20 19
       &__latestversion
@@ -22,19 +21,11 @@
22 21
         opacity 0.7
23 22
       &__text
24 23
         font-size 14px
25
-    &__header
26
-      border-top-left-radius 10px
27
-      border-top-right-radius 10px
28
-      padding 10px 0
29
-      text-align center
30
-      font-size 20px
31
-      color dark-grey
32
-      background-color grey-hover
33 24
     &__messagelist
34 25
       min-height 300px
35 26
       &__item
36 27
         &__content
37
-          color dark-grey
28
+          color darkGrey
38 29
       &__version
39 30
         margin-top 40px
40 31
         background-color grey-hover
@@ -47,7 +38,7 @@
47 38
           background-color htmlColor
48 39
           & > i
49 40
             margin-right 10px
50
-            color dark-grey
41
+            color darkGrey
51 42
             font-size 22px
52 43
           &:hover
53 44
             background-color darkHtmlColor

src/plugin/ContentType/PageHtml/PageHtml.jsx → src/plugin/ContentType/PageHtml/PageHtmlComponent.jsx View File


+ 48 - 0
src/plugin/ContentType/PageHtml/PageHtmlContainer.jsx View File

@@ -0,0 +1,48 @@
1
+import React from 'react'
2
+import { connect } from 'react-redux'
3
+import PopinFixed from '../../../component/common/PopinFixed/PopinFixed.jsx'
4
+import PopinFixedHeader from '../../../component/common/PopinFixed/PopinFixedHeader.jsx'
5
+import PopinFixedOption from '../../../component/common/PopinFixed/PopinFixedOption.jsx'
6
+import PopinFixedContent from '../../../component/common/PopinFixed/PopinFixedContent.jsx'
7
+import PageHtmlComponent from './PageHtmlComponent.jsx'
8
+import Timeline from '../../../component/Timeline.jsx'
9
+import { hideActiveFileContent } from '../../../action-creator.sync.js'
10
+
11
+require('./PageHtml.styl')
12
+
13
+class PageHtmlContainer extends React.Component {
14
+  handleClickBtnClose = () => this.props.dispatch(hideActiveFileContent())
15
+
16
+  render () {
17
+    const { activeFileContent, plugin: { PageHtml } } = this.props
18
+
19
+    return (
20
+      <PopinFixed customClass={`${PageHtml.customClass}`}>
21
+        <PopinFixedHeader
22
+          customClass={`${PageHtml.customClass}`}
23
+          icon={PageHtml.icon}
24
+          name={activeFileContent.title}
25
+          onClickCloseBtn={this.handleClickBtnClose}
26
+        />
27
+
28
+        <PopinFixedOption customClass={`${PageHtml.customClass}`} />
29
+
30
+        <PopinFixedContent customClass={`${PageHtml.customClass}__contentpage`}>
31
+          <PageHtmlComponent
32
+            version={activeFileContent.version}
33
+            text={activeFileContent.text}
34
+            key={'PageHtml'}
35
+          />
36
+
37
+          <Timeline
38
+            customClass={`${PageHtml.customClass}__contentpage`}
39
+            key={'pageHtml__timeline'}
40
+          />
41
+        </PopinFixedContent>
42
+      </PopinFixed>
43
+    )
44
+  }
45
+}
46
+
47
+const mapStateToProps = ({ activeFileContent, plugin }) => ({ activeFileContent, plugin })
48
+export default connect(mapStateToProps)(PageHtmlContainer)

+ 12 - 0
src/plugin/ContentType/PageHtml/index.js View File

@@ -0,0 +1,12 @@
1
+import reducer from './pageHtml.js'
2
+import container from './PageHtmlContainer.jsx'
3
+import component from './PageHtmlComponent.jsx'
4
+
5
+const PageHtml = {
6
+  name: 'PageHtml',
7
+  container,
8
+  component,
9
+  reducer
10
+}
11
+
12
+export default PageHtml

+ 2 - 1
src/plugin/ContentType/PageHtml/pageHtml.js View File

@@ -2,7 +2,8 @@ import { PLUGIN_LIST } from '../../../action-creator.sync.js'
2 2
 
3 3
 export default function pageHtml (state = {
4 4
   title: '',
5
-  version: 0
5
+  version: 0,
6
+  icon: ''
6 7
 }, action) {
7 8
   switch (action.type) {
8 9
     case `Set/${PLUGIN_LIST}`:

+ 7 - 0
src/plugin/ContentType/Thread/index.js View File

@@ -0,0 +1,7 @@
1
+import reducer from './thread.js'
2
+import component from './Thread.jsx'
3
+import style from './Thread.styl'
4
+
5
+const Thread = { name: 'Thread', component, reducer, style }
6
+
7
+export default Thread

+ 2 - 1
src/plugin/ContentType/Thread/thread.js View File

@@ -2,7 +2,8 @@ import { PLUGIN_LIST } from '../../../action-creator.sync.js'
2 2
 
3 3
 export default function thread (state = {
4 4
   title: '',
5
-  version: 0
5
+  version: 0,
6
+  icon: ''
6 7
 }, action) {
7 8
   switch (action.type) {
8 9
     case `Set/${PLUGIN_LIST}`:

+ 6 - 0
src/plugin/index.js View File

@@ -0,0 +1,6 @@
1
+import pageHtml from '../plugin/ContentType/PageHtml/index.js'
2
+import thread from '../plugin/ContentType/Thread/index.js'
3
+
4
+const pluginDatabase = [pageHtml, thread]
5
+
6
+export default pluginDatabase

+ 5 - 3
src/reducer/plugin.js View File

@@ -1,7 +1,9 @@
1 1
 import { combineReducers } from 'redux'
2
-import pageHtml from '../plugin/ContentType/PageHtml/pageHtml.js'
3
-import thread from '../plugin/ContentType/Thread/thread.js'
2
+import pluginDatabase from '../plugin/index.js'
3
+
4
+const reducerList = {}
5
+pluginDatabase.forEach(p => (reducerList[p.name] = p.reducer))
4 6
 
5 7
 export default combineReducers({
6
-  pageHtml, thread
8
+  ...reducerList
7 9
 })