feat: markdown editor UI fix + insert media (wip)
This commit is contained in:
		| @@ -57,72 +57,74 @@ | ||||
|                 v-list-tile-content Images & Files | ||||
|           v-toolbar-title(:class='{ "ml-2": $vuetify.breakpoint.mdAndUp, "ml-0": $vuetify.breakpoint.smAndDown }') | ||||
|             span.subheading {{title}} | ||||
|       v-flex(md4, v-if='searchIsShown && $vuetify.breakpoint.mdAndUp') | ||||
|       v-flex(md4, v-if='$vuetify.breakpoint.mdAndUp') | ||||
|         v-toolbar.nav-header-inner(color='black', dark, flat) | ||||
|           transition(name='navHeaderSearch') | ||||
|             v-text-field( | ||||
|               ref='searchField', | ||||
|               v-if='searchIsShown && $vuetify.breakpoint.mdAndUp', | ||||
|               v-model='search', | ||||
|               color='white', | ||||
|               label='Search...', | ||||
|               single-line, | ||||
|               solo | ||||
|               flat | ||||
|               hide-details, | ||||
|               prepend-inner-icon='search', | ||||
|               :loading='searchIsLoading', | ||||
|               @keyup.enter='searchEnter' | ||||
|               @keyup.esc='searchClose' | ||||
|               @focus='searchFocus' | ||||
|               @blur='searchBlur' | ||||
|               @keyup.down='searchMove(`down`)' | ||||
|               @keyup.up='searchMove(`up`)' | ||||
|             ) | ||||
|               v-progress-linear( | ||||
|                 indeterminate, | ||||
|                 slot='progress', | ||||
|                 height='2', | ||||
|                 color='blue' | ||||
|           slot(name='mid') | ||||
|             transition(name='navHeaderSearch', v-if='searchIsShown') | ||||
|               v-text-field( | ||||
|                 ref='searchField', | ||||
|                 v-if='searchIsShown && $vuetify.breakpoint.mdAndUp', | ||||
|                 v-model='search', | ||||
|                 color='white', | ||||
|                 label='Search...', | ||||
|                 single-line, | ||||
|                 solo | ||||
|                 flat | ||||
|                 hide-details, | ||||
|                 prepend-inner-icon='search', | ||||
|                 :loading='searchIsLoading', | ||||
|                 @keyup.enter='searchEnter' | ||||
|                 @keyup.esc='searchClose' | ||||
|                 @focus='searchFocus' | ||||
|                 @blur='searchBlur' | ||||
|                 @keyup.down='searchMove(`down`)' | ||||
|                 @keyup.up='searchMove(`up`)' | ||||
|               ) | ||||
|           v-menu( | ||||
|             v-model='searchAdvMenuShown' | ||||
|             left | ||||
|             offset-y | ||||
|             min-width='450' | ||||
|             :close-on-content-click='false' | ||||
|             nudge-bottom='7' | ||||
|             nudge-right='5' | ||||
|             ) | ||||
|             v-btn.nav-header-search-adv(icon, outline, color='grey darken-2', slot='activator') | ||||
|               v-icon(color='white') expand_more | ||||
|             v-card.radius-0(dark) | ||||
|               v-toolbar(flat, color='grey darken-4', dense) | ||||
|                 v-icon.mr-2 search | ||||
|                 v-subheader.pl-0 Advanced Search | ||||
|                 v-spacer | ||||
|                 v-chip(label, small, color='primary') Coming soon | ||||
|               v-card-text.pa-4 | ||||
|                 v-checkbox.mt-0( | ||||
|                   label='Restrict to current language' | ||||
|                   color='white' | ||||
|                   v-model='searchRestrictLocale' | ||||
|                   hide-details | ||||
|                 v-progress-linear( | ||||
|                   indeterminate, | ||||
|                   slot='progress', | ||||
|                   height='2', | ||||
|                   color='blue' | ||||
|                 ) | ||||
|                 v-checkbox( | ||||
|                   label='Search below current path only' | ||||
|                   color='white' | ||||
|                   v-model='searchRestrictPath' | ||||
|                   hide-details | ||||
|                 ) | ||||
|               v-divider | ||||
|               v-card-actions.grey.darken-3-d4 | ||||
|                 v-btn(depressed, color='grey darken-3', block) | ||||
|                   v-icon(left) chevron_right | ||||
|                   span Save as defaults | ||||
|                 v-btn(depressed, color='grey darken-3', block) | ||||
|                   v-icon(left) cached | ||||
|                   span Reset | ||||
|             v-menu( | ||||
|               v-model='searchAdvMenuShown' | ||||
|               left | ||||
|               offset-y | ||||
|               min-width='450' | ||||
|               :close-on-content-click='false' | ||||
|               nudge-bottom='7' | ||||
|               nudge-right='5' | ||||
|               v-if='searchIsShown' | ||||
|               ) | ||||
|               v-btn.nav-header-search-adv(icon, outline, color='grey darken-2', slot='activator') | ||||
|                 v-icon(color='white') expand_more | ||||
|               v-card.radius-0(dark) | ||||
|                 v-toolbar(flat, color='grey darken-4', dense) | ||||
|                   v-icon.mr-2 search | ||||
|                   v-subheader.pl-0 Advanced Search | ||||
|                   v-spacer | ||||
|                   v-chip(label, small, color='primary') Coming soon | ||||
|                 v-card-text.pa-4 | ||||
|                   v-checkbox.mt-0( | ||||
|                     label='Restrict to current language' | ||||
|                     color='white' | ||||
|                     v-model='searchRestrictLocale' | ||||
|                     hide-details | ||||
|                   ) | ||||
|                   v-checkbox( | ||||
|                     label='Search below current path only' | ||||
|                     color='white' | ||||
|                     v-model='searchRestrictPath' | ||||
|                     hide-details | ||||
|                   ) | ||||
|                 v-divider | ||||
|                 v-card-actions.grey.darken-3-d4 | ||||
|                   v-btn(depressed, color='grey darken-3', block) | ||||
|                     v-icon(left) chevron_right | ||||
|                     span Save as defaults | ||||
|                   v-btn(depressed, color='grey darken-3', block) | ||||
|                     v-icon(left) cached | ||||
|                     span Reset | ||||
|       v-flex(xs6, :md4='searchIsShown', :md6='!searchIsShown') | ||||
|         v-toolbar.nav-header-inner(color='black', dark, flat) | ||||
|           v-spacer | ||||
|   | ||||
| @@ -1,6 +1,10 @@ | ||||
| <template lang="pug"> | ||||
|   v-app.editor(:dark='darkMode') | ||||
|     nav-header(dense) | ||||
|       template(slot='mid') | ||||
|         v-spacer | ||||
|         .subheading {{currentPageTitle}} | ||||
|         v-spacer | ||||
|       template(slot='actions') | ||||
|         v-btn( | ||||
|           outline | ||||
| @@ -32,6 +36,7 @@ | ||||
|       editor-modal-properties(v-model='dialogProps') | ||||
|       editor-modal-editorselect(v-model='dialogEditorSelector') | ||||
|       editor-modal-unsaved(v-model='dialogUnsaved', @discard='exitGo') | ||||
|       component(:is='activeModal') | ||||
|  | ||||
|     loader(v-model='dialogProgress', :title='$t(`editor:save.processing`)', :subtitle='$t(`editor:save.pleaseWait`)') | ||||
|     v-snackbar( | ||||
| @@ -70,7 +75,8 @@ export default { | ||||
|     editorWysiwyg: () => import(/* webpackChunkName: "editor-wysiwyg", webpackMode: "lazy" */ './editor/editor-wysiwyg.vue'), | ||||
|     editorModalEditorselect: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-editorselect.vue'), | ||||
|     editorModalProperties: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-properties.vue'), | ||||
|     editorModalUnsaved: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-unsaved.vue') | ||||
|     editorModalUnsaved: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-unsaved.vue'), | ||||
|     editorModalMedia: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-media.vue') | ||||
|   }, | ||||
|   props: { | ||||
|     locale: { | ||||
| @@ -126,10 +132,12 @@ export default { | ||||
|   computed: { | ||||
|     currentEditor: sync('editor/editor'), | ||||
|     darkMode: get('site/dark'), | ||||
|     activeModal: sync('editor/activeModal'), | ||||
|     mode: get('editor/mode'), | ||||
|     notification: get('notification'), | ||||
|     notificationState: sync('notification@isActive'), | ||||
|     welcomeMode() { return this.mode === `create` && this.path === `home` } | ||||
|     welcomeMode() { return this.mode === `create` && this.path === `home` }, | ||||
|     currentPageTitle: get('page/title') | ||||
|   }, | ||||
|   watch: { | ||||
|     currentEditor(newValue, oldValue) { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <template lang='pug'> | ||||
|   .editor-markdown | ||||
|     v-toolbar.editor-markdown-toolbar(dense, color='primary', dark) | ||||
|     v-toolbar.editor-markdown-toolbar(dense, color='primary', dark, flat) | ||||
|       v-tooltip(top) | ||||
|         v-btn(icon, slot='activator').mx-0 | ||||
|           v-icon format_bold | ||||
| @@ -49,8 +49,33 @@ | ||||
|         v-btn(icon, slot='activator').mx-0 | ||||
|           v-icon remove | ||||
|         span Horizontal Bar | ||||
|  | ||||
|     .editor-markdown-main | ||||
|       .editor-markdown-sidebar | ||||
|         v-tooltip(right) | ||||
|           v-btn(icon, slot='activator', dark, @click='toggleModal(`editorModalMedia`)').mx-0 | ||||
|             v-icon(:color='activeModal === `editorModalMedia` ? `teal` : ``') image | ||||
|           span Insert Media | ||||
|         v-tooltip(right) | ||||
|           v-btn(icon, slot='activator', dark).mx-0 | ||||
|             v-icon insert_drive_file | ||||
|           span Insert File | ||||
|         v-tooltip(right) | ||||
|           v-btn(icon, slot='activator', dark).mx-0 | ||||
|             v-icon play_circle_outline | ||||
|           span Insert Video | ||||
|         v-tooltip(right) | ||||
|           v-btn(icon, slot='activator', dark).mx-0 | ||||
|             v-icon multiline_chart | ||||
|           span Insert Diagram | ||||
|         v-tooltip(right) | ||||
|           v-btn(icon, slot='activator', dark).mx-0 | ||||
|             v-icon functions | ||||
|           span Insert Math Expression | ||||
|         v-spacer | ||||
|         v-tooltip(right) | ||||
|           v-btn(icon, slot='activator', dark).mx-0 | ||||
|             v-icon border_outer | ||||
|           span Table Helper | ||||
|       .editor-markdown-editor | ||||
|         .editor-markdown-editor-title(v-if='previewShown', @click='previewShown = false') Editor | ||||
|         .editor-markdown-editor-title(v-else='previewShown', @click='previewShown = true'): v-icon(dark) drag_indicator | ||||
| @@ -60,19 +85,16 @@ | ||||
|           .editor-markdown-preview-title(@click='previewShown = false') Preview | ||||
|           .editor-markdown-preview-content.contents(ref='editorPreview', v-html='previewHTML') | ||||
|  | ||||
|       //- v-speed-dial.editor-markdown-insert(v-model='fabInsertMenu', :open-on-hover='true', direction='top', transition='slide-y-reverse-transition', fixed, bottom, :right='!previewShown || $vuetify.breakpoint.smAndDown') | ||||
|       //-   v-btn(color='blue', fab, dark, v-model='fabInsertMenu', slot='activator') | ||||
|       //-     v-icon add_circle | ||||
|       //-     v-icon close | ||||
|       //-   v-btn(color='teal', fab, dark): v-icon image | ||||
|       //-   v-btn(color='pink', fab, dark): v-icon insert_drive_file | ||||
|       //-   v-btn(color='red', fab, dark): v-icon play_circle_outline | ||||
|       //-   v-btn(color='purple', fab, dark): v-icon multiline_chart | ||||
|       //-   v-btn(color='indigo', fab, dark): v-icon functions | ||||
|     v-system-bar.editor-markdown-sysbar(dark, status, color='grey darken-3') | ||||
|       .caption.editor-markdown-sysbar-locale {{locale.toUpperCase()}} | ||||
|       .caption.px-3 /{{path}} | ||||
|       v-spacer | ||||
|       .caption Markdown | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import _ from 'lodash' | ||||
| import { get, sync } from 'vuex-pathify' | ||||
|  | ||||
| // ======================================== | ||||
| // IMPORTS | ||||
| @@ -191,9 +213,15 @@ export default { | ||||
|     }, | ||||
|     isMobile() { | ||||
|       return this.$vuetify.breakpoint.smAndDown | ||||
|     } | ||||
|     }, | ||||
|     locale: get('page/locale'), | ||||
|     path: get('page/path'), | ||||
|     activeModal: sync('editor/activeModal') | ||||
|   }, | ||||
|   methods: { | ||||
|     toggleModal(key) { | ||||
|       this.activeModal = (this.activeModal === key) ? '' : key | ||||
|     }, | ||||
|     onCmReady(cm) { | ||||
|       let self = this | ||||
|       const keyBindings = { | ||||
| @@ -208,7 +236,7 @@ export default { | ||||
|         self.$parent.save() | ||||
|       }) | ||||
|  | ||||
|       cm.setSize(null, 'calc(100vh - 112px)') | ||||
|       cm.setSize(null, 'calc(100vh - 112px - 24px)') | ||||
|       cm.setOption('extraKeys', keyBindings) | ||||
|       cm.on('cursorActivity', cm => { | ||||
|         this.toolbarSync(cm) | ||||
| @@ -262,6 +290,9 @@ export default { | ||||
| </script> | ||||
|  | ||||
| <style lang='scss'> | ||||
|  | ||||
| $editor-height: calc(100vh - 112px - 24px); | ||||
|  | ||||
| .editor-markdown { | ||||
|   &-main { | ||||
|     display: flex; | ||||
| @@ -272,7 +303,7 @@ export default { | ||||
|     background-color: darken(mc('grey', '900'), 4.5%); | ||||
|     flex: 1 1 50%; | ||||
|     display: block; | ||||
|     height: calc(100vh - 112px); | ||||
|     height: $editor-height; | ||||
|     position: relative; | ||||
|  | ||||
|     &-title { | ||||
| @@ -302,7 +333,7 @@ export default { | ||||
|     flex: 1 1 50%; | ||||
|     background-color: mc('grey', '100'); | ||||
|     position: relative; | ||||
|     height: calc(100vh - 112px); | ||||
|     height: $editor-height; | ||||
|     overflow: hidden; | ||||
|  | ||||
|     @at-root .theme--dark & { | ||||
| @@ -327,7 +358,7 @@ export default { | ||||
|     } | ||||
|  | ||||
|     &-content { | ||||
|       height: calc(100vh - 112px); | ||||
|       height: $editor-height; | ||||
|       overflow-y: scroll; | ||||
|       padding: 1rem 1rem 1rem 0; | ||||
|       width: calc(100% + 1rem + 17px) | ||||
| @@ -364,7 +395,7 @@ export default { | ||||
|     color: #FFF; | ||||
|  | ||||
|     .v-toolbar__content { | ||||
|       padding-left: 16px; | ||||
|       padding-left: 78px; | ||||
|  | ||||
|       @include until($tablet) { | ||||
|         padding-left: 8px; | ||||
| @@ -379,6 +410,30 @@ export default { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   &-sidebar { | ||||
|     background-color: mc('grey', '900'); | ||||
|     width: 64px; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     justify-content: flex-start; | ||||
|     align-items: center; | ||||
|     padding: 24px 0; | ||||
|   } | ||||
|  | ||||
|   &-sysbar { | ||||
|     padding-left: 0; | ||||
|  | ||||
|     &-locale { | ||||
|       background-color: rgba(255,255,255,.25); | ||||
|       display:inline-flex; | ||||
|       padding: 0 12px; | ||||
|       height: 24px; | ||||
|       width: 63px; | ||||
|       justify-content: center; | ||||
|       align-items: center; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // ========================================== | ||||
|   // Fix FAB revealing under codemirror | ||||
|   // ========================================== | ||||
|   | ||||
							
								
								
									
										69
									
								
								client/components/editor/editor-modal-media.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								client/components/editor/editor-modal-media.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| <template lang='pug'> | ||||
|   v-card.editor-modal-media.animated.fadeInLeft(flat, tile) | ||||
|     v-container.pa-3(grid-list-lg, fluid) | ||||
|       v-layout(row, wrap) | ||||
|         v-flex(xs3) | ||||
|           v-card.radius-7.animated.fadeInLeft.wait-p1s(light) | ||||
|             v-card-text | ||||
|               file-pond( | ||||
|                 name='mediaUpload' | ||||
|                 ref='pond' | ||||
|                 label-idle='Drop files here...' | ||||
|                 allow-multiple='true' | ||||
|                 accepted-file-types='image/jpeg, image/png' | ||||
|                 :files='files' | ||||
|               ) | ||||
|         v-flex(xs9) | ||||
|           v-card.radius-7.animated.fadeInLeft.wait-p3s(light) | ||||
|             v-card-text Beep boop | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| // import _ from 'lodash' | ||||
| // import { sync } from 'vuex-pathify' | ||||
| import vueFilePond from 'vue-filepond' | ||||
| import 'filepond/dist/filepond.min.css' | ||||
|  | ||||
| import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css' | ||||
| import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type' | ||||
| import FilePondPluginImagePreview from 'filepond-plugin-image-preview' | ||||
|  | ||||
| const FilePond = vueFilePond(FilePondPluginFileValidateType, FilePondPluginImagePreview) | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     FilePond | ||||
|   }, | ||||
|   props: { | ||||
|     value: { | ||||
|       type: Boolean, | ||||
|       default: false | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       files: [] | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     isShown: { | ||||
|       get() { return this.value }, | ||||
|       set(val) { this.$emit('input', val) } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang='scss'> | ||||
| .editor-modal-media { | ||||
|     position: fixed; | ||||
|     top: 112px; | ||||
|     left: 64px; | ||||
|     z-index: 10; | ||||
|     width: calc(100vw - 64px - 17px); | ||||
|     height: calc(100vh - 112px - 24px); | ||||
|     background-color: rgba(darken(mc('grey', '900'), 3%), .9) !important; | ||||
| } | ||||
| </style> | ||||
		Reference in New Issue
	
	Block a user