diff options
Diffstat (limited to 'front-end/src/views')
8 files changed, 107 insertions, 11 deletions
diff --git a/front-end/src/views/Blog/components/Channels.vue b/front-end/src/views/Blog/components/Channels.vue index bf29067..df71720 100644 --- a/front-end/src/views/Blog/components/Channels.vue +++ b/front-end/src/views/Blog/components/Channels.vue @@ -28,7 +28,7 @@ import ChannelEdit from './Channels/ChannelEdit.vue'; import ChannelTable from './Channels/ChannelTable.vue'; import EditorTable from './EditorTable.vue'; -const emit = defineEmits(['close', 'reload']) +const emit = defineEmits(['close']) const store = useStore() const { items, pagination } = store.channels.createPages() @@ -41,7 +41,7 @@ const closeEdit = (update?:boolean) => { store.channels.editId = '' //reload channels if(update){ - emit('reload') + store.channels.refresh() } //Reset page to top window.scrollTo(0, 0) diff --git a/front-end/src/views/Blog/components/Content.vue b/front-end/src/views/Blog/components/Content.vue index 888b595..5e81629 100644 --- a/front-end/src/views/Blog/components/Content.vue +++ b/front-end/src/views/Blog/components/Content.vue @@ -50,7 +50,6 @@ import EditorTable from './EditorTable.vue'; import ContentEditor from './Content/ContentEditor.vue'; import ContentTable from './Content/ContentTable.vue'; -const emit = defineEmits(['reload']) const store = useStore() const { uploadProgress } = storeToRefs(store) @@ -64,13 +63,14 @@ const loadingProgress = computed(() => `${uploadProgress.value}%`); const progressWidth = computed(() => ({ width: `${uploadProgress.value}%` })); const showProgress = computed(() => uploadProgress.value > 0 && uploadProgress.value < 100); + const openEdit = async (item: ContentMeta) => store.content.selectedId = item.id const closeEdit = (update?: boolean) => { store.content.selectedId = '' //reload channels if (update) { - emit('reload') + store.content.refresh() } //Reset page to top window.scrollTo(0, 0) @@ -173,5 +173,4 @@ const onDownload = async (item: ContentMeta) => { }) } - </script>
\ No newline at end of file diff --git a/front-end/src/views/Blog/components/Content/ContentTable.vue b/front-end/src/views/Blog/components/Content/ContentTable.vue index cc94c9f..98a76a4 100644 --- a/front-end/src/views/Blog/components/Content/ContentTable.vue +++ b/front-end/src/views/Blog/components/Content/ContentTable.vue @@ -13,7 +13,15 @@ <tr v-for="item in $props.items" :key="item.id" class="table-row"> <td> <span class="mr-2"> - <fa-icon size="sm" :icon="getContentIconType(item)" /> + <fa-icon v-if="isImage(item)" + size="sm" + :icon="getContentIconType(item)" + @click="onShowPreview(item)" + /> + <fa-icon v-else + size="sm" + :icon="getContentIconType(item)" + /> </span> <span> {{ getItemName(item) }} @@ -52,13 +60,17 @@ </td> </tr> </tbody> + <!-- Image preview dialog --> + <ImgPreviewDialog :item="previewItem" @close="onClosePreview()" /> </template> <script setup lang="ts"> +import { defineAsyncComponent, ref } from 'vue'; import { filter as _filter, defaultTo, includes, truncate } from 'lodash-es'; import { useClipboard } from '@vueuse/core'; import { useWait } from '@vnuge/vnlib.browser'; import { ContentMeta } from '@vnuge/cmnext-admin'; +const ImgPreviewDialog = defineAsyncComponent(() => import('../image-preview-dialog.vue')) const emit = defineEmits(['open-edit', 'copy-link', 'delete', 'download']) defineProps<{ items: ContentMeta[] }>() @@ -66,6 +78,8 @@ defineProps<{ items: ContentMeta[] }>() const { waiting } = useWait() const { copy } = useClipboard() +const previewItem = ref<ContentMeta | undefined>() + const getDateString = (time?: number) => new Date((time || 0) * 1000).toLocaleString(); const getItemLength = (item: ContentMeta) : string =>{ const length = item.length || 0; @@ -84,10 +98,13 @@ const getContentIconType = (item: ContentMeta) => { return 'file' } +const isImage = (item: ContentMeta) => includes(item.content_type, 'image') const openEdit = async (item: ContentMeta) => emit('open-edit', item) const copyLink = (item : ContentMeta) => emit('copy-link', item) const deleteItem = (item : ContentMeta) => emit('delete', item) const download = (item : ContentMeta) => emit('download', item) +const onShowPreview = (item: ContentMeta) => previewItem.value = item +const onClosePreview = () => previewItem.value = undefined -</script>
\ No newline at end of file +</script> diff --git a/front-end/src/views/Blog/components/FeedFields.vue b/front-end/src/views/Blog/components/FeedFields.vue index 918f449..e38c3d7 100644 --- a/front-end/src/views/Blog/components/FeedFields.vue +++ b/front-end/src/views/Blog/components/FeedFields.vue @@ -23,7 +23,7 @@ <div v-if="editMode" class="flex flex-col"> - <div v-if="$props.blog" class="mb-2"> + <div v-if="$props.showEpAdder" class="mb-2"> <EpAdder @submit="onAddEnclosure" /> </div> @@ -43,6 +43,7 @@ const JsonEditorVue = defineAsyncComponent(() => import('json-editor-vue')) const props = defineProps<{ properties: UseXmlProperties, + showEpAdder?: boolean }>() const { getXml, saveJson, getModel, addProperties } = props.properties diff --git a/front-end/src/views/Blog/components/Posts.vue b/front-end/src/views/Blog/components/Posts.vue index 801fa3c..f07e576 100644 --- a/front-end/src/views/Blog/components/Posts.vue +++ b/front-end/src/views/Blog/components/Posts.vue @@ -29,7 +29,6 @@ import EditorTable from './EditorTable.vue'; import PostTable from './Posts/PostTable.vue'; const PostEditor = defineAsyncComponent(() => import('./Posts/PostEdit.vue')) -const emit = defineEmits(['reload']) const store = useStore() const { reveal } = useConfirm() @@ -44,7 +43,9 @@ const closeEdit = (update?: boolean) => { store.posts.selectedId = '' //reload channels if (update) { - emit('reload') + //must refresh content and posts when a post is updated + store.posts.refresh() + store.content.refresh() } //Reset page to top window.scrollTo(0, 0) diff --git a/front-end/src/views/Blog/components/Posts/PostEdit.vue b/front-end/src/views/Blog/components/Posts/PostEdit.vue index 4f7285b..dcbf4fa 100644 --- a/front-end/src/views/Blog/components/Posts/PostEdit.vue +++ b/front-end/src/views/Blog/components/Posts/PostEdit.vue @@ -31,7 +31,7 @@ <Editor :podcast-mode="podcastMode" @change="onContentChanged" @mode-change="onModeChange" @load="onEditorLoad" /> </div> - <FeedFields :properties="postProperties" /> + <FeedFields :show-ep-adder="true" :properties="postProperties" /> <div class="mx-auto my-4"> <div class="button-group"> diff --git a/front-end/src/views/Blog/components/image-preview-dialog.vue b/front-end/src/views/Blog/components/image-preview-dialog.vue new file mode 100644 index 0000000..5cfe552 --- /dev/null +++ b/front-end/src/views/Blog/components/image-preview-dialog.vue @@ -0,0 +1,74 @@ +<template> + <div class=""> + <Dialog :open="isOpen" @close="onClose" class="relative z-50"> + <!-- The backdrop, rendered as a fixed sibling to the panel container --> + <div class="fixed inset-0 bg-black/30" aria-hidden="true" /> + + <!-- Full-screen container to center the panel --> + <div class="fixed inset-0 flex items-center justify-center w-screen p-4"> + <!-- The actual dialog panel --> + <DialogPanel class="p-2 bg-white rounded dark:bg-dark-700" ref="dialog"> + <DialogDescription> + <img class="preview-image" :src="imgUrl" alt="preview" /> + </DialogDescription> + <!-- ... --> + </DialogPanel> + </div> + </Dialog> + </div> +</template> + +<script setup lang="ts"> +import { ref, computed, watch, toRefs } from 'vue' +import { Dialog, DialogDescription } from '@headlessui/vue' +import { onClickOutside } from '@vueuse/core'; +import { useStore } from '../../../store'; +import { ContentMeta } from '../../../../../lib/admin/dist'; +import { isNil } from 'lodash-es'; +import { apiCall } from '@vnuge/vnlib.browser'; + +const emit = defineEmits(['close']) +const props = defineProps<{ + item: ContentMeta | undefined, +}>() + +const { item } = toRefs(props) + +const store = useStore() + +const dialog = ref<HTMLElement | null>(null) + +const onClose = () => emit('close') +const imgUrl = ref<string | undefined>() +const isOpen = computed(() => !isNil(imgUrl.value)) + +const downloadImage = (item: ContentMeta) => { + apiCall(async () => { + //Download the file blob from the server + const fileBlob = await store.content.downloadContent(item) + //Create a url for the blob and open the save link + const url = window.URL.createObjectURL(fileBlob); + imgUrl.value = url + }) +} + +//load the image when open +watch(item, (item) => { + if (isNil(item)) { + imgUrl.value = undefined + } else { + downloadImage(item) + } +}) + +//Close dialog when clicking outside +onClickOutside(dialog, onClose) + +</script> +<style lang="scss"> + +.preview-image { + @apply max-h-[53rem]; +} + +</style>
\ No newline at end of file diff --git a/front-end/src/views/Blog/index.vue b/front-end/src/views/Blog/index.vue index cc47513..de435ec 100644 --- a/front-end/src/views/Blog/index.vue +++ b/front-end/src/views/Blog/index.vue @@ -258,6 +258,10 @@ defer(() => store.channels.refresh()); tr td{ @apply whitespace-nowrap px-4 py-2 font-medium; } + + .fa-image{ + @apply cursor-pointer text-primary-500; + } } .ck.ck-editor{ |