editor-code.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <template lang='pug'>
  2. .editor-code
  3. .editor-code-toolbar
  4. .editor-code-toolbar-group
  5. .editor-code-toolbar-item
  6. svg.icons.is-18(role='img')
  7. title Bold
  8. use(xlink:href='#fa-bold')
  9. .editor-code-toolbar-item
  10. svg.icons.is-18(role='img')
  11. title Italic
  12. use(xlink:href='#fa-italic')
  13. .editor-code-toolbar-item
  14. svg.icons.is-18(role='img')
  15. title Strikethrough
  16. use(xlink:href='#fa-strikethrough')
  17. .editor-code-toolbar-group
  18. v-menu(offset-y, open-on-hover)
  19. .editor-code-toolbar-item.is-dropdown(slot='activator')
  20. svg.icons.is-18(role='img')
  21. title Heading
  22. use(xlink:href='#fa-heading')
  23. v-list
  24. v-list-tile(v-for='(n, idx) in 6', @click='')
  25. v-list-tile-action: v-icon format_size
  26. v-list-tile-title Heading {{n}}
  27. .editor-code-toolbar-group
  28. .editor-code-toolbar-item
  29. svg.icons.is-18(role='img')
  30. title Unordered List
  31. use(xlink:href='#fa-list-ul')
  32. .editor-code-toolbar-item
  33. svg.icons.is-18(role='img')
  34. title Ordered List
  35. use(xlink:href='#fa-list-ol')
  36. .editor-code-toolbar-group
  37. .editor-code-toolbar-item
  38. svg.icons.is-18(role='img')
  39. title Link
  40. use(xlink:href='#fa-link')
  41. .editor-code-toolbar-group
  42. .editor-code-toolbar-item
  43. svg.icons.is-18(role='img')
  44. title Inline Code
  45. use(xlink:href='#fa-terminal')
  46. .editor-code-toolbar-item
  47. svg.icons.is-18(role='img')
  48. title Code Block
  49. use(xlink:href='#fa-code')
  50. .editor-code-toolbar-group
  51. .editor-code-toolbar-item
  52. svg.icons.is-18(role='img')
  53. title Horizontal Bar
  54. use(xlink:href='#fa-minus')
  55. .editor-code-main
  56. .editor-code-editor
  57. .editor-code-editor-title Editor
  58. codemirror(ref='cm', v-model='code', :options='cmOptions', @ready="onCmReady")
  59. .editor-code-preview
  60. .editor-code-preview-title Preview
  61. v-speed-dial(:hover='true', direction='left', transition='slide-y-reverse-transition', :fixed='true', :right='true', :bottom='true')
  62. v-btn(color='green', fab, dark, slot='activator')
  63. v-icon save
  64. v-icon close
  65. v-btn(color='red', fab, dark, small): v-icon not_interested
  66. v-btn(color='orange', fab, dark, small): v-icon vpn_lock
  67. v-btn(color='indigo', fab, dark, small): v-icon restore
  68. v-btn(color='brown', fab, dark, small): v-icon archive
  69. </template>
  70. <script>
  71. import { codemirror } from 'vue-codemirror'
  72. import 'codemirror/lib/codemirror.css'
  73. // Theme
  74. import 'codemirror/theme/base16-dark.css'
  75. // Language
  76. import 'codemirror/mode/markdown/markdown.js'
  77. // Addons
  78. import 'codemirror/addon/selection/active-line.js'
  79. import 'codemirror/addon/display/fullscreen.js'
  80. import 'codemirror/addon/display/fullscreen.css'
  81. import 'codemirror/addon/selection/mark-selection.js'
  82. import 'codemirror/addon/scroll/annotatescrollbar.js'
  83. import 'codemirror/addon/search/matchesonscrollbar.js'
  84. import 'codemirror/addon/search/searchcursor.js'
  85. import 'codemirror/addon/search/match-highlighter.js'
  86. export default {
  87. components: {
  88. codemirror
  89. },
  90. data() {
  91. return {
  92. code: 'const a = 10',
  93. cmOptions: {
  94. tabSize: 2,
  95. mode: 'text/markdown',
  96. theme: 'base16-dark',
  97. lineNumbers: true,
  98. lineWrapping: true,
  99. line: true,
  100. styleActiveLine: true,
  101. highlightSelectionMatches: {
  102. annotateScrollbar: true
  103. },
  104. viewportMargin: 50,
  105. extraKeys: {
  106. 'F11'(cm) {
  107. cm.setOption('fullScreen', !cm.getOption('fullScreen'))
  108. },
  109. 'Esc'(cm) {
  110. if (cm.getOption('fullScreen')) cm.setOption('fullScreen', false)
  111. }
  112. }
  113. }
  114. }
  115. },
  116. computed: {
  117. cm() {
  118. return this.$refs.cm.codemirror
  119. }
  120. },
  121. methods: {
  122. onCmReady(cm) {
  123. cm.setSize(null, 'calc(100vh - 50px)')
  124. },
  125. onCmFocus(cm) {
  126. console.log('the editor is focus!', cm)
  127. },
  128. onCmCodeChange(newCode) {
  129. console.log('this is new code', newCode)
  130. this.code = newCode
  131. }
  132. }
  133. }
  134. </script>
  135. <style lang='scss'>
  136. .editor-code {
  137. &-main {
  138. display: flex;
  139. width: 100%;
  140. }
  141. &-editor {
  142. flex: 1 1 50%;
  143. display: block;
  144. min-height: calc(100vh - 50px);
  145. position: relative;
  146. &-title {
  147. background-color: mc('grey', '800');
  148. border-bottom-left-radius: 5px;
  149. display: inline-flex;
  150. height: 30px;
  151. justify-content: center;
  152. align-items: center;
  153. padding: 0 1rem;
  154. color: mc('grey', '500');
  155. position: absolute;
  156. top: 0;
  157. right: 0;
  158. z-index: 2;
  159. text-transform: uppercase;
  160. font-size: .7rem;
  161. }
  162. }
  163. &-preview {
  164. flex: 1 1 50%;
  165. background-color: mc('grey', '100');
  166. position: relative;
  167. padding: 30px 1rem 1rem 1rem;
  168. &-title {
  169. background-color: mc('blue', '100');
  170. border-bottom-right-radius: 5px;
  171. display: inline-flex;
  172. height: 30px;
  173. justify-content: center;
  174. align-items: center;
  175. padding: 0 1rem;
  176. color: mc('blue', '800');
  177. position: absolute;
  178. top: 0;
  179. left: 0;
  180. z-index: 2;
  181. text-transform: uppercase;
  182. font-size: .7rem;
  183. }
  184. }
  185. &-toolbar {
  186. background-color: mc('blue', '700');
  187. background-image: linear-gradient(to bottom, mc('blue', '700') 0%, mc('blue','800') 100%);
  188. height: 50px;
  189. color: #FFF;
  190. display: flex;
  191. &-group {
  192. display: flex;
  193. + .editor-code-toolbar-group {
  194. border-left: 1px solid rgba(mc('blue', '900'), .75);
  195. }
  196. }
  197. &-item {
  198. width: 40px;
  199. height: 50px;
  200. display: flex;
  201. justify-content: center;
  202. align-items: center;
  203. transition: all .4s ease;
  204. cursor: pointer;
  205. &:first-child {
  206. padding-left: .5rem;
  207. }
  208. &:last-child {
  209. padding-right: .5rem;
  210. }
  211. &:hover {
  212. background-color: mc('blue', '600');
  213. }
  214. }
  215. svg {
  216. use {
  217. color: #FFF;
  218. }
  219. }
  220. }
  221. }
  222. .CodeMirror {
  223. height: auto;
  224. }
  225. .CodeMirror-focused .cm-matchhighlight {
  226. background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);
  227. background-position: bottom;
  228. background-repeat: repeat-x;
  229. }
  230. .cm-matchhighlight {
  231. background-color: mc('grey', '800');
  232. }
  233. .CodeMirror-selection-highlight-scrollbar {
  234. background-color: mc('green', '600');
  235. }
  236. </style>