editor-modal-media.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. <template lang='pug'>
  2. v-card.editor-modal-media.animated.fadeInLeft(flat, tile)
  3. v-container.pa-3(grid-list-lg, fluid)
  4. v-layout(row, wrap)
  5. v-flex(xs9)
  6. v-card.radius-7.animated.fadeInLeft.wait-p1s(light)
  7. v-card-text
  8. .d-flex
  9. v-toolbar.radius-7(color='teal lighten-5', dense, flat, height='44')
  10. .body-2.teal--text Images
  11. v-btn.ml-3.my-0.radius-7(outline, large, color='teal', disabled)
  12. v-icon(left) keyboard_arrow_up
  13. span Parent Folder
  14. v-btn.my-0.mr-0.radius-7(outline, large, color='teal')
  15. v-icon(left) add
  16. span New Folder
  17. v-list.mt-3(dense, two-line)
  18. template(v-for='(asset, idx) of assets')
  19. v-list-tile(@click='')
  20. v-list-tile-avatar
  21. v-avatar.radius-7(color='teal')
  22. v-icon(dark) image
  23. v-list-tile-content
  24. v-list-tile-title {{asset.filename}}
  25. v-list-tile-sub-title 1024x768
  26. v-list-tile-action
  27. .caption {{asset.updatedAt | moment('from')}}
  28. v-divider.mx-3(vertical)
  29. v-list-tile-action(style='flex-basis: 80px;')
  30. .caption {{asset.fileSize | prettyBytes}}
  31. v-divider.mx-3(vertical)
  32. v-list-tile-action(style='flex-basis: 60px;')
  33. v-chip.teal--text(label, small, color='teal lighten-5') {{asset.ext.toUpperCase().substring(1)}}
  34. v-list-tile-action
  35. v-menu(offset-x)
  36. v-btn(icon, slot='activator')
  37. v-icon(color='grey darken-2') more_horiz
  38. v-list.py-0
  39. v-list-tile
  40. v-list-tile-avatar
  41. v-icon(color='teal') short_text
  42. v-list-tile-content Properties
  43. v-divider
  44. v-list-tile
  45. v-list-tile-avatar
  46. v-icon(color='indigo') crop_rotate
  47. v-list-tile-content Edit
  48. v-divider
  49. v-list-tile
  50. v-list-tile-avatar
  51. v-icon(color='blue') keyboard
  52. v-list-tile-content Rename / Move
  53. v-divider
  54. v-list-tile
  55. v-list-tile-avatar
  56. v-icon(color='red') delete
  57. v-list-tile-content Delete
  58. v-divider(v-if='idx < assets.length - 1')
  59. .d-flex.mt-3
  60. v-toolbar.radius-7(flat, color='grey lighten-4', dense, height='44')
  61. .body-2 / #[em root]
  62. v-spacer
  63. .body-1.grey--text.text--darken-1 10 files
  64. v-btn.ml-3.mr-0.my-0.radius-7(color='teal', large, @click='insert', disabled)
  65. v-icon(left) save_alt
  66. span Insert
  67. v-flex(xs3)
  68. v-card.radius-7.animated.fadeInRight.wait-p3s(light)
  69. v-card-text
  70. .d-flex
  71. v-toolbar.radius-7(color='teal lighten-5', dense, flat, height='44')
  72. v-icon.mr-3(color='teal') cloud_upload
  73. .body-2.teal--text Upload Images
  74. v-btn.my-0.ml-3.mr-0.radius-7(outline, large, color='teal', @click='browse')
  75. v-icon(left) touch_app
  76. span Browse
  77. file-pond.mt-3(
  78. name='mediaUpload'
  79. ref='pond'
  80. label-idle='Browse or Drop files here...'
  81. allow-multiple='true'
  82. :accepted-file-types='[`image/jpeg`, `image/png`, `image/gif`, `image/svg`]'
  83. :files='files'
  84. max-files='10'
  85. server='/u'
  86. :instant-upload='false'
  87. :allow-revert='false'
  88. @processfile='onFileProcessed'
  89. )
  90. v-divider
  91. v-card-actions.pa-3
  92. .caption.grey--text.text-darken-2 Max 10 files, 5 MB each
  93. v-spacer
  94. v-btn(color='teal', dark, @click='upload') Upload
  95. v-card.mt-3.radius-7.animated.fadeInRight.wait-p4s(light)
  96. v-card-text.pb-0
  97. v-toolbar.radius-7(color='teal lighten-5', dense, flat)
  98. v-icon.mr-3(color='teal') cloud_download
  99. .body-2.teal--text Fetch Remote Image
  100. v-text-field.mt-3(
  101. v-model='remoteImageUrl'
  102. outline
  103. single-line
  104. background-color='grey lighten-2'
  105. placeholder='https://example.com/image.jpg'
  106. )
  107. v-divider
  108. v-card-actions.pa-3
  109. .caption.grey--text.text-darken-2 Max 5 MB
  110. v-spacer
  111. v-btn(color='teal', dark) Fetch
  112. v-card.mt-3.radius-7.animated.fadeInRight.wait-p4s(light)
  113. v-card-text.pb-0
  114. v-toolbar.radius-7(color='teal lighten-5', dense, flat)
  115. v-icon.mr-3(color='teal') format_align_left
  116. .body-2.teal--text Alignment
  117. v-select.mt-3(
  118. v-model='imageAlignment'
  119. :items='imageAlignments'
  120. outline
  121. single-line
  122. background-color='grey lighten-2'
  123. placeholder='None'
  124. )
  125. </template>
  126. <script>
  127. import _ from 'lodash'
  128. import { sync } from 'vuex-pathify'
  129. import vueFilePond from 'vue-filepond'
  130. import 'filepond/dist/filepond.min.css'
  131. import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type'
  132. import listAssetQuery from 'gql/editor/editor-media-query-list.gql'
  133. const FilePond = vueFilePond(FilePondPluginFileValidateType)
  134. export default {
  135. components: {
  136. FilePond
  137. },
  138. props: {
  139. value: {
  140. type: Boolean,
  141. default: false
  142. }
  143. },
  144. data() {
  145. return {
  146. files: [],
  147. remoteImageUrl: '',
  148. imageAlignments: [
  149. { text: 'None', value: '' },
  150. { text: 'Centered', value: 'center' },
  151. { text: 'Right', value: 'right' },
  152. { text: 'Absolute Top Right', value: 'abstopright' }
  153. ],
  154. imageAlignment: ''
  155. }
  156. },
  157. computed: {
  158. isShown: {
  159. get() { return this.value },
  160. set(val) { this.$emit('input', val) }
  161. },
  162. activeModal: sync('editor/activeModal')
  163. },
  164. filters: {
  165. prettyBytes(num) {
  166. if (typeof num !== 'number' || isNaN(num)) {
  167. throw new TypeError('Expected a number')
  168. }
  169. var exponent
  170. var unit
  171. var neg = num < 0
  172. var units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
  173. if (neg) {
  174. num = -num
  175. }
  176. if (num < 1) {
  177. return (neg ? '-' : '') + num + ' B'
  178. }
  179. exponent = Math.min(Math.floor(Math.log(num) / Math.log(1000)), units.length - 1)
  180. num = (num / Math.pow(1000, exponent)).toFixed(2) * 1
  181. unit = units[exponent]
  182. return (neg ? '-' : '') + num + ' ' + unit
  183. }
  184. },
  185. methods: {
  186. insert () {
  187. this.activeModal = ''
  188. },
  189. browse () {
  190. this.$refs.pond.browse()
  191. },
  192. async upload () {
  193. const files = this.$refs.pond.getFiles()
  194. if (files.length < 1) {
  195. return this.$store.commit('showNotification', {
  196. message: 'You must choose a file to upload first!',
  197. style: 'warning',
  198. icon: 'warning'
  199. })
  200. }
  201. for (let file of files) {
  202. file.setMetadata({
  203. path: 'test'
  204. })
  205. }
  206. await this.$refs.pond.processFiles()
  207. },
  208. async onFileProcessed (err, file) {
  209. if (err) {
  210. return this.$store.commit('showNotification', {
  211. message: 'File upload failed.',
  212. style: 'error',
  213. icon: 'error'
  214. })
  215. }
  216. _.delay(() => {
  217. this.$refs.pond.removeFile(file.id)
  218. }, 5000)
  219. await this.$apollo.queries.assets.refetch()
  220. }
  221. },
  222. apollo: {
  223. assets: {
  224. query: listAssetQuery,
  225. variables: {
  226. kind: 'IMAGE'
  227. },
  228. throttle: 1000,
  229. fetchPolicy: 'network-only',
  230. update: (data) => data.assets.list,
  231. watchLoading (isLoading) {
  232. this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'editor-media-list-refresh')
  233. }
  234. }
  235. }
  236. }
  237. </script>
  238. <style lang='scss'>
  239. .editor-modal-media {
  240. position: fixed;
  241. top: 112px;
  242. left: 64px;
  243. z-index: 10;
  244. width: calc(100vw - 64px - 17px);
  245. height: calc(100vh - 112px - 24px);
  246. background-color: rgba(darken(mc('grey', '900'), 3%), .9) !important;
  247. overflow: auto;
  248. .filepond--root {
  249. margin-bottom: 0;
  250. }
  251. .filepond--drop-label {
  252. cursor: pointer;
  253. > label {
  254. cursor: pointer;
  255. }
  256. }
  257. }
  258. </style>