├── public ├── favicon.ico └── index.html ├── src ├── assets │ ├── hint.png │ ├── logo.png │ ├── text.png │ ├── todo.png │ ├── heading1.png │ ├── heading2.png │ ├── heading3.png │ ├── BulletedList.png │ └── github.svg ├── main.js ├── App.vue ├── router │ └── index.js ├── views │ ├── About.vue │ └── Home.vue ├── components │ ├── AddBlockBtn.vue │ ├── basicBlockComponents │ │ ├── Heading3.vue │ │ ├── Heading1.vue │ │ ├── Heading2.vue │ │ ├── Hint.vue │ │ ├── TextBlock.vue │ │ ├── BulletedList.vue │ │ └── TodoBlock.vue │ └── AddBlockContent.vue └── vuex │ └── store.js ├── babel.config.js ├── .gitignore ├── package.json └── README.md /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CedarXi/All-in-one/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/hint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CedarXi/All-in-one/HEAD/src/assets/hint.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CedarXi/All-in-one/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CedarXi/All-in-one/HEAD/src/assets/text.png -------------------------------------------------------------------------------- /src/assets/todo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CedarXi/All-in-one/HEAD/src/assets/todo.png -------------------------------------------------------------------------------- /src/assets/heading1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CedarXi/All-in-one/HEAD/src/assets/heading1.png -------------------------------------------------------------------------------- /src/assets/heading2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CedarXi/All-in-one/HEAD/src/assets/heading2.png -------------------------------------------------------------------------------- /src/assets/heading3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CedarXi/All-in-one/HEAD/src/assets/heading3.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/BulletedList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CedarXi/All-in-one/HEAD/src/assets/BulletedList.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | # local env files 5 | .env.local 6 | .env.*.local 7 | 8 | # Log files 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | *.sw? 21 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './vuex/store' // 引入store 5 | 6 | import ElementUI from 'element-ui'; 7 | import 'element-ui/lib/theme-chalk/index.css'; 8 | 9 | Vue.use(ElementUI); 10 | 11 | Vue.config.productionTip = false 12 | 13 | new Vue({ 14 | router, store, 15 | render: h => h(App) 16 | }).$mount('#app') 17 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 25 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/Home.vue' 4 | 5 | Vue.use(VueRouter) 6 | 7 | const routes = [ 8 | { 9 | path: '/', 10 | name: 'Home', 11 | component: Home 12 | }, 13 | { 14 | path: '/about', 15 | name: 'About', 16 | // route level code-splitting 17 | // this generates a separate chunk (about.[hash].js) for this route 18 | // which is lazy-loaded when the route is visited. 19 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') 20 | } 21 | ] 22 | 23 | const router = new VueRouter({ 24 | mode: 'history', 25 | base: process.env.BASE_URL, 26 | routes 27 | }) 28 | 29 | export default router 30 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | All-in-one 10 | 11 | 12 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "block-editor", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "core-js": "^3.6.4", 11 | "element-ui": "^2.13.0", 12 | "vue": "^2.6.11", 13 | "vue-router": "^3.1.6", 14 | "vuedraggable": "^2.23.2", 15 | "vuex": "^3.1.3" 16 | }, 17 | "devDependencies": { 18 | "@vue/cli-plugin-babel": "~4.3.0", 19 | "@vue/cli-plugin-router": "~4.3.0", 20 | "@vue/cli-service": "~4.3.0", 21 | "less": "^3.0.4", 22 | "less-loader": "^5.0.0", 23 | "vue-template-compiler": "^2.6.11" 24 | }, 25 | "browserslist": [ 26 | "> 1%", 27 | "last 2 versions", 28 | "not dead" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /src/views/About.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /src/components/AddBlockBtn.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 25 | 26 | 27 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/assets/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEMO 2 | [all-in-one-kappa.vercel.app/](https://all-in-one-kappa.vercel.app/) 3 | 4 | # 界面 5 | ![image](https://user-images.githubusercontent.com/16424854/126763700-721ecb56-4dbc-4581-b7ff-ddab7790576e.png) 6 | 7 | 8 | 9 | # All-in-one是什么 10 | All-in-one 是一个开源的模块化内容构建编辑器,它不同于传统的文本编辑器,所有的内容都是以模块的概念来打造。灵感来自Notion 11 | 12 | ## 灵活的插拔 13 | 所有的模块都以VUE组件的形式编写,可以灵活插拔。你可以用All-in-one编辑器构建一个模块化的内容平台,可以在一个页面里插入任何其他模块,就像Notion一样 14 | 15 | ### 纯净的输出 16 | 所有组件保存的数据,都以Json的形式存储在Vuex里供不同组件调用 17 | 18 | 19 | #### 🐞 由于不是用WYSIWYG的编辑器进行二次开发,目前在文本编辑方面有一些不能解决的Bug 20 | 21 | * 当输入行大于等于2行时,键盘的上下按键没有办法处理光标在同组件的文本内容里上下移动 22 | * 内容无法跨模块复制 23 | * 其他一些小的问题 24 | 25 | #### 👏 已实现的模块 26 | - [x] 纯文本 27 | - [x] 待办清单 28 | - [x] 标题1 29 | - [x] 标题2 30 | - [x] 标题3 31 | - [x] 符号列表 32 | - [x] 提示栏 33 | - [x] 组件的拖拽移动 34 | 35 | 36 | #### 🧑‍💻 待开发的模块 37 | - [ ] 事件节点组件 38 | - [ ] 图片上传组件 39 | - [ ] 表格组件 40 | - [ ] 看板组件 41 | 42 | *** 43 | 44 | # what is All-in-one 45 | All-in-one is an open source modular content construction editor. It is different from traditional text editors, and all content is built with the concept of modules. Inspired by Notion 46 | 47 | ## Flexible plugging 48 | All modules are written in the form of VUE components, which can be flexibly inserted and removed. You can use the All-in-one editor to build a modular content platform, you can insert any other module in a page, just like Notion 49 | 50 | ### Pure output 51 | The data saved by all components is stored in Vuex in the form of Json for different components to call 52 | 53 | 54 | #### 🐞 Since it is not a secondary development with the WYSIWYG editor, there are currently some unsolvable bugs in text editing 55 | 56 | * When the input line is greater than or equal to 2 lines, the keyboard up and down keys can not handle the cursor to move up and down in the text content of the same component 57 | * Content cannot be copied across modules 58 | * Other minor issues 59 | 60 | #### 👏 Modules has been developed 61 | 62 | - [x] Text 63 | - [x] Todo 64 | - [x] Heading1 65 | - [x] Heading2 66 | - [x] Heading3 67 | - [x] BulletedList 68 | - [x] Hint 69 | - [x] Drag and drop of components 70 | 71 | #### 🧑‍💻 Modules to be developed 72 | 73 | - [ ] EventNode component 74 | - [ ] Image upload component 75 | - [ ] Form component 76 | - [ ] Kanban components 77 | -------------------------------------------------------------------------------- /src/vuex/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | const state = { 7 | isShowAddMenu: false, 8 | addMenuContentLayerXY: { x: 0, y: 0 }, 9 | currentBlockIndex: 0, 10 | currentPageBlocks: [{ "type": "heading1", "data": { "text": "All-in-one 是什么" } }, { "type": "text", "data": { "text": "All-in-one 是一个开源的模块化内容构建编辑器,它不同于传统的文本编辑器,所有的内容都是以模块的概念来打造。灵感来自Notion" } }, { "type": "heading2", "data": { "text": "灵活的插拔" } }, { "type": "text", "data": { "text": "所有的模块都以VUE组件的形式编写,可以灵活插拔。你可以用All-in-one编辑器构建一个模块化的内容平台,可以在一个页面里插入任何其他模块,就像Notion一样" } }, { "type": "heading3", "data": { "text": "纯净的输出" } }, { "type": "text", "data": { "text": "所有组件保存的数据,都以Json的形式存储在Vuex里供不同组件调用" } }, { "type": "text", "data": { "text": "" } }, { "type": "hint", "data": { "text": "🐞由于不是用WYSIWYG的编辑器进行二次开发,目前在文本编辑方面有一些不能解决的Bug" } }, { "type": "text", "data": { "text": "" } }, { "type": "BulletedList", "data": { "text": "当输入行大于等于2行时,键盘的上下按键没有办法处理光标在同组件的文本内容里上下移动" } }, { "type": "BulletedList", "data": { "text": "内容无法跨模块复制" } }, { "type": "BulletedList", "data": { "text": "其他一些小的问题" } }, { "type": "text", "data": { "text": "" } }, { "type": "hint", "data": { "text": "👏 已实现的模块" } }, { "type": "text", "data": { "text": "" } }, { "type": "todo", "data": { "isChecked": true, "text": "纯文本" } }, { "type": "todo", "data": { "isChecked": true, "text": "待办清单" } }, { "type": "todo", "data": { "isChecked": true, "text": "标题1" } }, { "type": "todo", "data": { "isChecked": true, "text": "标题2" } }, { "type": "todo", "data": { "isChecked": true, "text": "标题3" } }, { "type": "todo", "data": { "isChecked": true, "text": "符号列表" } }, { "type": "todo", "data": { "isChecked": true, "text": "提示栏" } }, { "type": "todo", "data": { "isChecked": true, "text": "组件的拖动排序" } }, { "type": "text", "data": { "text": "" } }, { "type": "hint", "data": { "text": "🧑‍💻待开发的功能清单" } }, { "type": "text", "data": { "text": "" } }, { "type": "todo", "data": { "isChecked": false, "text": " 图片上传组件" } }, { "type": "todo", "data": { "isChecked": false, "text": "事件节点组件" } }, { "type": "todo", "data": { "isChecked": false, "text": "表格组件" } }, { "type": "todo", "data": { "isChecked": false, "text": "看板组件" } }, { "type": "text", "data": { "text": "" } }], 11 | } 12 | 13 | const mutations = { 14 | mutationIsShowAddMenu(state, isShowAddMenu) { 15 | state.isShowAddMenu = isShowAddMenu 16 | }, 17 | mutationCurrentBlockIndex(state, index) { 18 | state.currentBlockIndex = index 19 | }, 20 | mutationAddMenuContentLayerXY(state, addMenuContentLayerXY) { 21 | state.addMenuContentLayerXY = addMenuContentLayerXY 22 | // state.addMenuContentClientXY = {x:0,y:0} 23 | 24 | }, 25 | mutationAddCurrentPageBlocks(state, addBlockInfo) { 26 | let index = addBlockInfo.index + 1 27 | state.currentPageBlocks.splice(index, 0, addBlockInfo.blockItem) 28 | // console.log(state.currentPageBlocks) 29 | } 30 | } 31 | 32 | 33 | const getters = { 34 | 35 | getterCurrentPageBlocks(state) { 36 | return state.currentPageBlocks 37 | }, 38 | getterAddMenuContentLayerXY(state) { 39 | 40 | let a = state.addMenuContentLayerXY 41 | let clientHeight = window.innerHeight 42 | 43 | if (a.y > (clientHeight / 2)) { 44 | a.y = a.y - 380 45 | } 46 | a.y = `${a.y + 20}px` 47 | a.x = `${a.x + 48}px` 48 | 49 | // 当前浏览器的高度 50 | return a 51 | } 52 | 53 | 54 | } 55 | export default new Vuex.Store({ 56 | state, mutations, getters 57 | }) -------------------------------------------------------------------------------- /src/components/basicBlockComponents/Heading3.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 125 | 126 | -------------------------------------------------------------------------------- /src/components/basicBlockComponents/Heading1.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 130 | 131 | -------------------------------------------------------------------------------- /src/components/basicBlockComponents/Heading2.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 129 | 130 | -------------------------------------------------------------------------------- /src/components/basicBlockComponents/Hint.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 127 | 128 | -------------------------------------------------------------------------------- /src/components/basicBlockComponents/TextBlock.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 151 | 152 | -------------------------------------------------------------------------------- /src/components/basicBlockComponents/BulletedList.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 150 | 151 | -------------------------------------------------------------------------------- /src/components/basicBlockComponents/TodoBlock.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 153 | 154 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 55 | 56 | 129 | 130 | 131 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /src/components/AddBlockContent.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 91 | 92 | 93 | 272 | 273 | 274 | --------------------------------------------------------------------------------