aboutsummaryrefslogtreecommitdiff
path: root/front-end
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-12-16 12:09:33 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2023-12-16 12:09:33 -0500
commitaf67dab96747c7d83380e67de91dd25f46e9681f (patch)
treea0dc584291dc73cbff3ff4db8d3f28a7d714b25f /front-end
parent0d25abab798c005266a1c0b4eeba957d232d4328 (diff)
fixes, image preview, and prep for framework update
Diffstat (limited to 'front-end')
-rw-r--r--front-end/src/views/Blog/components/Channels.vue4
-rw-r--r--front-end/src/views/Blog/components/Content.vue5
-rw-r--r--front-end/src/views/Blog/components/Content/ContentTable.vue21
-rw-r--r--front-end/src/views/Blog/components/FeedFields.vue3
-rw-r--r--front-end/src/views/Blog/components/Posts.vue5
-rw-r--r--front-end/src/views/Blog/components/Posts/PostEdit.vue2
-rw-r--r--front-end/src/views/Blog/components/image-preview-dialog.vue74
-rw-r--r--front-end/src/views/Blog/index.vue4
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{