Prechádzať zdrojové kódy

feat: insert asset in editor

NGPixel 2 rokov pred
rodič
commit
0eee0519ed

+ 2 - 1
ux/.eslintrc.js

@@ -43,7 +43,8 @@ module.exports = {
     __QUASAR_SSR_CLIENT__: 'readonly',
     __QUASAR_SSR_PWA__: 'readonly',
     process: 'readonly',
-    APOLLO_CLIENT: 'readonly'
+    APOLLO_CLIENT: 'readonly',
+    EVENT_BUS: 'readonly'
   },
 
   // add your custom rules here

+ 3 - 1
ux/package-lock.json

@@ -67,6 +67,7 @@
         "markdown-it-sub": "1.0.0",
         "markdown-it-sup": "1.0.0",
         "markdown-it-task-lists": "2.1.1",
+        "mitt": "3.0.0",
         "pako": "2.1.0",
         "pinia": "2.0.33",
         "prosemirror-commands": "1.5.1",
@@ -5575,7 +5576,8 @@
     },
     "node_modules/mitt": {
       "version": "3.0.0",
-      "license": "MIT"
+      "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz",
+      "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ=="
     },
     "node_modules/ms": {
       "version": "2.1.3",

+ 1 - 0
ux/package.json

@@ -72,6 +72,7 @@
     "markdown-it-sub": "1.0.0",
     "markdown-it-sup": "1.0.0",
     "markdown-it-task-lists": "2.1.1",
+    "mitt": "3.0.0",
     "pako": "2.1.0",
     "pinia": "2.0.33",
     "prosemirror-commands": "1.5.1",

+ 1 - 0
ux/quasar.config.js

@@ -38,6 +38,7 @@ module.exports = configure(function (/* ctx */) {
     boot: [
       'apollo',
       'components',
+      'eventbus',
       'i18n'
     ],
 

+ 12 - 0
ux/src/boot/eventbus.js

@@ -0,0 +1,12 @@
+import { boot } from 'quasar/wrappers'
+import mitt from 'mitt'
+
+export default boot(({ app }) => {
+  const emitter = mitt()
+
+  if (import.meta.env.SSR) {
+    global.EVENT_BUS = emitter
+  } else {
+    window.EVENT_BUS = emitter
+  }
+})

+ 25 - 5
ux/src/components/EditorMarkdown.vue

@@ -233,7 +233,7 @@
 </template>
 
 <script setup>
-import { reactive, ref, shallowRef, nextTick, onBeforeMount, onMounted, watch } from 'vue'
+import { reactive, ref, shallowRef, nextTick, onMounted, watch, onBeforeUnmount } from 'vue'
 import { useMeta, useQuasar, setCssVar } from 'quasar'
 import { useI18n } from 'vue-i18n'
 import { get, flatten, last, times, startsWith, debounce } from 'lodash-es'
@@ -297,9 +297,26 @@ const CtrlKey = /Mac/.test(navigator.platform) ? 'Cmd' : 'Ctrl'
 // METHODS
 
 function insertAssets () {
-  siteStore.$patch({
-    overlay: 'FileManager'
-  })
+  siteStore.openFileManager({ insertMode: true })
+}
+
+function insertAssetClb (opts) {
+  const assetPath = opts.folderPath ? `${opts.folderPath}/${opts.fileName}` : opts.fileName
+  let content = ''
+  switch (opts.type) {
+    case 'asset': {
+      content = `![${opts.title}](${assetPath})`
+      break
+    }
+    case 'page': {
+      content = `[${opts.title}](${assetPath})`
+      break
+    }
+  }
+  insertAtCursor({ content })
+  setTimeout(() => {
+    cm.value.focus()
+  }, 500)
 }
 
 function insertTable () {
@@ -505,6 +522,8 @@ onMounted(async () => {
     cm.value.focus()
   })
 
+  EVENT_BUS.on('insertAsset', insertAssetClb)
+
   // this.$root.$on('editorInsert', opts => {
   //   switch (opts.kind) {
   //     case 'IMAGE':
@@ -538,7 +557,8 @@ onMounted(async () => {
   // })
 })
 
-onBeforeMount(() => {
+onBeforeUnmount(() => {
+  EVENT_BUS.off('insertAsset', insertAssetClb)
   // if (editor.value) {
   // editor.value.destroy()
   // }

+ 1 - 3
ux/src/components/EditorWysiwyg.vue

@@ -499,9 +499,7 @@ const menuBar = [
     icon: 'mdi-image-plus',
     title: 'Image',
     action: () => {
-      siteStore.$patch({
-        overlay: 'FileManager'
-      })
+      siteStore.openFileManager({ insertMode: true })
     }
   },
   {

+ 39 - 7
ux/src/components/FileManager.vue

@@ -79,6 +79,16 @@ q-layout.fileman(view='hHh lpR lFr', container)
             )
             label {{item.label}}
             span {{item.value}}
+          template(v-if='insertMode')
+            q-separator.q-my-md
+            q-btn.full-width(
+              @click='insertItem()'
+              :label='t(`common.actions.insert`)'
+              color='primary'
+              icon='las la-plus-circle'
+              push
+              padding='sm'
+              )
   q-page-container
     q-page.fileman-center.column
       //- TOOLBAR -----------------------------------------------------
@@ -223,7 +233,7 @@ q-layout.fileman(view='hHh lpR lFr', container)
                 active-class='active'
                 :active='item.id === state.currentFileId'
                 @click.native='selectItem(item)'
-                @dblclick.native='openItem(item)'
+                @dblclick.native='doubleClickItem(item)'
                 )
                 q-item-section.fileman-filelist-icon(avatar)
                   q-icon(:name='item.icon', :size='state.isCompact ? `md` : `xl`')
@@ -242,14 +252,18 @@ q-layout.fileman(view='hHh lpR lFr', container)
                   )
                   q-card.q-pa-sm
                     q-list(dense, style='min-width: 150px;')
+                      q-item(clickable, v-if='item.type !== `folder`', @click='insertItem(item)')
+                        q-item-section(side)
+                          q-icon(name='las la-plus-circle', color='primary')
+                        q-item-section {{ t(`common.actions.insert`) }}
                       q-item(clickable, v-if='item.type === `page`')
                         q-item-section(side)
                           q-icon(name='las la-edit', color='orange')
-                        q-item-section Edit
+                        q-item-section {{ t(`common.actions.edit`) }}
                       q-item(clickable, v-if='item.type !== `folder`', @click='openItem(item)')
                         q-item-section(side)
                           q-icon(name='las la-eye', color='primary')
-                        q-item-section View
+                        q-item-section {{ t(`common.actions.view`) }}
                       template(v-if='item.type === `asset` && item.imageEdit')
                         q-item(clickable)
                           q-item-section(side)
@@ -262,11 +276,11 @@ q-layout.fileman(view='hHh lpR lFr', container)
                       q-item(clickable, v-if='item.type !== `folder`', @click='copyItemURL(item)')
                         q-item-section(side)
                           q-icon(name='las la-clipboard', color='primary')
-                        q-item-section Copy URL
+                        q-item-section {{ t(`common.actions.copyURL`) }}
                       q-item(clickable, v-if='item.type !== `folder`', @click='')
                         q-item-section(side)
                           q-icon(name='las la-download', color='primary')
-                        q-item-section Download
+                        q-item-section {{ t(`common.actions.download`) }}
                       q-item(clickable)
                         q-item-section(side)
                           q-icon(name='las la-copy', color='teal')
@@ -282,7 +296,7 @@ q-layout.fileman(view='hHh lpR lFr', container)
                       q-item(clickable, @click='delItem(item)')
                         q-item-section(side)
                           q-icon(name='las la-trash-alt', color='negative')
-                        q-item-section.text-negative Delete
+                        q-item-section.text-negative {{ t(`common.actions.delete`) }}
   q-footer
     q-bar.fileman-path
       small.text-caption.text-grey-7 {{folderPath}}
@@ -298,7 +312,7 @@ q-layout.fileman(view='hHh lpR lFr', container)
 
 <script setup>
 import { useI18n } from 'vue-i18n'
-import { computed, defineAsyncComponent, nextTick, onMounted, reactive, ref, watch } from 'vue'
+import { computed, defineAsyncComponent, nextTick, onMounted, reactive, ref, toRaw, watch } from 'vue'
 import { filesize } from 'filesize'
 import { useQuasar } from 'quasar'
 import { DateTime } from 'luxon'
@@ -377,6 +391,8 @@ const treeComp = ref(null)
 
 // COMPUTED
 
+const insertMode = computed(() => siteStore.overlayOpts?.insertMode ?? false)
+
 const folderPath = computed(() => {
   if (!state.currentFolderId) {
     return '/'
@@ -506,6 +522,14 @@ function close () {
   siteStore.overlay = null
 }
 
+function insertItem (item) {
+  if (!item) {
+    item = find(state.fileList, ['id', state.currentFileId])
+  }
+  EVENT_BUS.emit('insertAsset', toRaw(item))
+  close()
+}
+
 async function treeLazyLoad (nodeId, isCurrent, { done, fail }) {
   await loadTree({ parentId: nodeId, types: isCurrent ? null : ['folder'] })
   done()
@@ -849,6 +873,14 @@ function selectItem (item) {
   }
 }
 
+function doubleClickItem (item) {
+  if (insertMode.value) {
+    insertItem(item)
+  } else {
+    openItem(item)
+  }
+}
+
 function openItem (item) {
   switch (item.type) {
     case 'folder': {

+ 6 - 1
ux/src/components/HeaderNav.vue

@@ -48,6 +48,11 @@ q-header.bg-header.text-white.site-header(
             v-if='state.search.length > 0'
             :color='$q.dark.isActive ? `blue` : `grey-4`'
             )
+          q-badge.q-ml-sm(
+            label='v3 Preview'
+            color='pink'
+            outline
+            )
       q-btn.q-ml-md(
         flat
         round
@@ -131,7 +136,7 @@ const state = reactive({
 // METHODS
 
 function openFileManager () {
-  siteStore.overlay = 'FileManager'
+  siteStore.openFileManager()
 }
 </script>
 

+ 1 - 1
ux/src/components/PageNewMenu.vue

@@ -116,7 +116,7 @@ function create (editor) {
 }
 
 function openFileManager () {
-  siteStore.overlay = 'FileManager'
+  siteStore.openFileManager()
 }
 
 function newFolder () {

+ 2 - 0
ux/src/i18n/locales/en.json

@@ -1164,6 +1164,7 @@
   "common.actions.commit": "Commit",
   "common.actions.confirm": "Confirm",
   "common.actions.copy": "Copy",
+  "common.actions.copyURL": "Copy URL",
   "common.actions.create": "Create",
   "common.actions.deactivate": "Deactivate",
   "common.actions.delete": "Delete",
@@ -1198,6 +1199,7 @@
   "common.actions.select": "Select",
   "common.actions.update": "Update",
   "common.actions.upload": "Upload",
+  "common.actions.view": "View",
   "common.clipboard.failure": "Failed to copy to clipboard.",
   "common.clipboard.success": "Copied to clipboard successfully.",
   "common.clipboard.uuid": "Copy UUID to clipboard.",

+ 1 - 1
ux/src/layouts/MainLayout.vue

@@ -149,7 +149,7 @@ const isSidebarShown = computed(() => {
 // METHODS
 
 function openFileManager () {
-  siteStore.overlay = 'FileManager'
+  siteStore.openFileManager()
 }
 
 </script>

+ 9 - 0
ux/src/stores/site.js

@@ -25,6 +25,7 @@ export const useSiteStore = defineStore('site', {
     showSideNav: true,
     showSidebar: true,
     overlay: null,
+    overlayOpts: {},
     features: {
       ratingsMode: 'off',
       reasonForChange: 'required',
@@ -70,6 +71,14 @@ export const useSiteStore = defineStore('site', {
     overlayIsShown: (state) => Boolean(state.overlay)
   },
   actions: {
+    openFileManager (opts) {
+      this.$patch({
+        overlay: 'FileManager',
+        overlayOpts: {
+          insertMode: opts?.insertMode ?? false
+        }
+      })
+    },
     async loadSite (hostname) {
       try {
         const resp = await APOLLO_CLIENT.query({