aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-06-05 15:58:07 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2024-06-05 15:58:07 -0400
commit21d2719701f851d4a555c363b141f289f14a5192 (patch)
treea885343da2ea8fe7afa6defc118066adc0c26a85
parenteefba88ac4e2c70517aa71c79ed94c346f9de554 (diff)
fix: #1 new channel page when hitting new button
-rw-r--r--front-end/src/main.ts2
-rw-r--r--front-end/src/views/Blog/components/Channels.vue43
-rw-r--r--front-end/src/views/Blog/components/Content.vue84
-rw-r--r--front-end/src/views/Blog/components/Content/ContentTable.vue90
-rw-r--r--front-end/src/views/Blog/components/ContentSearch.vue72
-rw-r--r--front-end/src/views/Blog/components/EditorTable.vue69
-rw-r--r--front-end/src/views/Blog/components/FeedFields.vue75
-rw-r--r--lib/Taskfile.yaml6
8 files changed, 212 insertions, 229 deletions
diff --git a/front-end/src/main.ts b/front-end/src/main.ts
index 40a9d2c..ac32bb6 100644
--- a/front-end/src/main.ts
+++ b/front-end/src/main.ts
@@ -119,7 +119,7 @@ createVnApp({
* An array of named routes to protect from
* unauthenticated access.
*/
- guardRoutes(router, ['Account', 'account/:comp'])
+ guardRoutes(router, ['Account', 'account/:comp', 'Blog'])
//Add the footer nav components
app.component('FooterNav1', FooterNav1)
diff --git a/front-end/src/views/Blog/components/Channels.vue b/front-end/src/views/Blog/components/Channels.vue
index df71720..8de6527 100644
--- a/front-end/src/views/Blog/components/Channels.vue
+++ b/front-end/src/views/Blog/components/Channels.vue
@@ -1,22 +1,4 @@
-<template>
- <div id="channel-editor">
- <EditorTable title="Manage channels" :show-edit="showEdit" :pagination="pagination" @open-new="openNew">
- <template #table>
- <ChannelTable
- :items="items"
- @open-edit="openEdit"
- />
- </template>
- <template #editor>
- <ChannelEdit
- @close="closeEdit"
- @on-submit="onSubmit"
- @on-delete="onDelete"
- />
- </template>
- </EditorTable>
- </div>
-</template>
+
<script setup lang="ts">
import { computed } from 'vue';
@@ -33,7 +15,7 @@ const emit = defineEmits(['close'])
const store = useStore()
const { items, pagination } = store.channels.createPages()
-const showEdit = computed(() => !isEmpty(store.channels.editChannel))
+const showEdit = computed(() => !isEmpty(store.channels.editId))
const openEdit = (channel: BlogChannel) => store.channels.editId = channel.id;
@@ -44,13 +26,13 @@ const closeEdit = (update?:boolean) => {
store.channels.refresh()
}
//Reset page to top
- window.scrollTo(0, 0)
+ window.scrollTo({ top: 0, behavior: 'smooth' })
}
const openNew = () => {
- store.channels.editId = 'new'
+ store.channels.editId = 'new'
//Reset page to top
- window.scrollTo(0, 0)
+ window.scrollTo({ top: 0, behavior: 'smooth' })
}
const onSubmit = async ({channel, feed} : { channel:BlogChannel, feed? : ChannelFeed}) => {
@@ -86,6 +68,15 @@ const onDelete = async (channel : BlogChannel) => {
</script>
-<style lang="scss">
-
-</style> \ No newline at end of file
+<template>
+ <div id="channel-editor">
+ <EditorTable title="Manage channels" :show-edit="showEdit" :pagination="pagination" @open-new="openNew">
+ <template #table>
+ <ChannelTable :items="items" @open-edit="openEdit" />
+ </template>
+ <template #editor>
+ <ChannelEdit @close="closeEdit" @on-submit="onSubmit" @on-delete="onDelete" />
+ </template>
+ </EditorTable>
+ </div>
+</template>
diff --git a/front-end/src/views/Blog/components/Content.vue b/front-end/src/views/Blog/components/Content.vue
index 5e81629..568f2d1 100644
--- a/front-end/src/views/Blog/components/Content.vue
+++ b/front-end/src/views/Blog/components/Content.vue
@@ -1,43 +1,3 @@
-<template>
- <div id="content-editor" class="">
- <EditorTable title="Manage content" :show-edit="showEdit" :pagination="pagination" @open-new="openNew">
- <template #table>
- <ContentTable
- :items="items"
- @open-edit="openEdit"
- @copy-link="copyLink"
- @delete="onDelete"
- @download="onDownload"
- />
- </template>
- <template #editor>
- <div v-if="showProgress" class="max-w-xl mx-auto">
- <span id="ProgressLabel" class="sr-only">Loading</span>
-
- <span
- role="progressbar"
- aria-labelledby="ProgressLabel"
- :aria-valuenow="uploadProgress"
- class="relative block bg-gray-200 rounded-full dark:bg-dark-500"
- >
- <span class="absolute inset-0 flex items-center justify-center text-[10px]/4">
- <span class="font-bold text-white "> {{ loadingProgress }} </span>
- </span>
-
- <span class="block h-4 text-center rounded-full bg-primary-600" :style="progressWidth"></span>
- </span>
- </div>
- <ContentEditor
- @submit="onSubmit"
- @close="closeEdit"
- @delete="onDelete"
- />
- </template>
- </EditorTable>
- <a class="hidden" ref="downloadAnchor"></a>
- </div>
-</template>
-
<script setup lang="ts">
import { computed, shallowRef } from 'vue';
import { isEmpty } from 'lodash-es';
@@ -50,7 +10,6 @@ import EditorTable from './EditorTable.vue';
import ContentEditor from './Content/ContentEditor.vue';
import ContentTable from './Content/ContentTable.vue';
-
const store = useStore()
const { uploadProgress } = storeToRefs(store)
const { items, pagination } = store.content.createPages()
@@ -63,7 +22,6 @@ 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) => {
@@ -173,4 +131,44 @@ const onDownload = async (item: ContentMeta) => {
})
}
-</script> \ No newline at end of file
+</script>
+
+<template>
+ <div id="content-editor" class="">
+ <EditorTable title="Manage content" :show-edit="showEdit" :pagination="pagination" @open-new="openNew">
+ <template #table>
+ <ContentTable
+ :items="items"
+ @open-edit="openEdit"
+ @copy-link="copyLink"
+ @delete="onDelete"
+ @download="onDownload"
+ />
+ </template>
+ <template #editor>
+ <div v-if="showProgress" class="max-w-xl mx-auto">
+ <span id="ProgressLabel" class="sr-only">Loading</span>
+
+ <span
+ role="progressbar"
+ aria-labelledby="ProgressLabel"
+ :aria-valuenow="uploadProgress"
+ class="relative block bg-gray-200 rounded-full dark:bg-dark-500"
+ >
+ <span class="absolute inset-0 flex items-center justify-center text-[10px]/4">
+ <span class="font-bold text-white "> {{ loadingProgress }} </span>
+ </span>
+
+ <span class="block h-4 text-center rounded-full bg-primary-600" :style="progressWidth"></span>
+ </span>
+ </div>
+ <ContentEditor
+ @submit="onSubmit"
+ @close="closeEdit"
+ @delete="onDelete"
+ />
+ </template>
+ </EditorTable>
+ <a class="hidden" ref="downloadAnchor"></a>
+ </div>
+</template> \ 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 98a76a4..dab63bd 100644
--- a/front-end/src/views/Blog/components/Content/ContentTable.vue
+++ b/front-end/src/views/Blog/components/Content/ContentTable.vue
@@ -1,3 +1,48 @@
+<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[] }>()
+
+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;
+ return length > 1024 ? `${(length / 1024).toFixed(2)} KB` : `${length} B`
+}
+const getItemId = (item: ContentMeta) => truncate(item.id || '', { length: 20 })
+const getItemName = (item : ContentMeta) => truncate(item.name || '', { length: 30 })
+
+const getContentIconType = (item: ContentMeta) => {
+ const type = defaultTo(item.content_type, '')
+ if (includes(type, 'image')) return 'image'
+ if (includes(type, 'video')) return 'video'
+ if (includes(type, 'audio')) return 'headphones'
+ if (includes(type, 'html')) return 'code'
+ if (includes(type, 'zip')) return 'file-zipper'
+ 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>
+
<template>
<thead>
<tr>
@@ -63,48 +108,3 @@
<!-- 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[] }>()
-
-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;
- return length > 1024 ? `${(length / 1024).toFixed(2)} KB` : `${length} B`
-}
-const getItemId = (item: ContentMeta) => truncate(item.id || '', { length: 20 })
-const getItemName = (item : ContentMeta) => truncate(item.name || '', { length: 30 })
-
-const getContentIconType = (item: ContentMeta) => {
- const type = defaultTo(item.content_type, '')
- if (includes(type, 'image')) return 'image'
- if (includes(type, 'video')) return 'video'
- if (includes(type, 'audio')) return 'headphones'
- if (includes(type, 'html')) return 'code'
- if (includes(type, 'zip')) return 'file-zipper'
- 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>
diff --git a/front-end/src/views/Blog/components/ContentSearch.vue b/front-end/src/views/Blog/components/ContentSearch.vue
index 7871196..0970bf1 100644
--- a/front-end/src/views/Blog/components/ContentSearch.vue
+++ b/front-end/src/views/Blog/components/ContentSearch.vue
@@ -1,39 +1,3 @@
-<template>
- <div id="content-search" class="my-4">
- <div class="">
- <div class="">
- <input class="w-full input primary" placeholder="Search..." v-model="search" />
- </div>
- </div>
- <div class="search-results">
- <div v-if="searchResults.length == 0" class="result">
- No results found.
- </div>
- <div v-else v-for="result in searchResults" :key="result.id" @click.prevent="onSelected(result)" class="result">
- <div class="flex-auto result name">
- {{ result.shortName }}
- </div>
- <div class="result id">
- {{ result.shortId }}
- </div>
- <div class="rseult controls">
- <div v-if="waiting">
- <fa-icon icon="spinner" spin />
- </div>
- <div v-else-if="result.copied.value" class="text-sm text-amber-500">
- copied
- </div>
- <div v-else class="">
- <button class="btn secondary sm borderless" @click="result.copyLink()">
- <fa-icon icon="link" />
- </button>
- </div>
- </div>
- </div>
- </div>
- </div>
-</template>
-
<script setup lang="ts">
import { useClipboard } from '@vueuse/core';
import { apiCall, useWait } from '@vnuge/vnlib.browser';
@@ -89,6 +53,42 @@ const onSelected = (result: ContentResult) => {
</script>
+<template>
+ <div id="content-search" class="my-4">
+ <div class="">
+ <div class="">
+ <input class="w-full input primary" placeholder="Search..." v-model="search" />
+ </div>
+ </div>
+ <div class="search-results">
+ <div v-if="searchResults.length == 0" class="result">
+ No results found.
+ </div>
+ <div v-else v-for="result in searchResults" :key="result.id" @click.prevent="onSelected(result)" class="result">
+ <div class="flex-auto result name">
+ {{ result.shortName }}
+ </div>
+ <div class="result id">
+ {{ result.shortId }}
+ </div>
+ <div class="rseult controls">
+ <div v-if="waiting">
+ <fa-icon icon="spinner" spin />
+ </div>
+ <div v-else-if="result.copied.value" class="text-sm text-amber-500">
+ copied
+ </div>
+ <div v-else class="">
+ <button class="btn secondary sm borderless" @click="result.copyLink()">
+ <fa-icon icon="link" />
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
<style lang="scss">
.search-results{
diff --git a/front-end/src/views/Blog/components/EditorTable.vue b/front-end/src/views/Blog/components/EditorTable.vue
index 4ec5a33..a7f4f66 100644
--- a/front-end/src/views/Blog/components/EditorTable.vue
+++ b/front-end/src/views/Blog/components/EditorTable.vue
@@ -1,3 +1,25 @@
+<script setup lang="ts">
+import { toRefs } from 'vue';
+import { useWait } from '@vnuge/vnlib.browser';
+import { UseOffsetPaginationReturn } from '@vueuse/core';
+
+const emit = defineEmits(['open-new'])
+const props = defineProps<{
+ title: string,
+ showEdit: boolean,
+ pagination: UseOffsetPaginationReturn
+}>()
+
+const { showEdit } = toRefs(props)
+const { waiting } = useWait()
+
+//Get pagination
+const { pageCount, next, prev, isLastPage, isFirstPage, currentPage } = props.pagination
+
+const openNew = () => emit('open-new')
+
+</script>
+
<template>
<slot class="flex flex-row">
<div class="flex-1 px-4 mt-3">
@@ -6,12 +28,12 @@
<div class="w-[20rem]">
<h4>{{ $props.title }}</h4>
</div>
- <div class="h-full">
- <div :class="{'opacity-100':waiting}" class="opacity-0">
+ <div class="h-full">
+ <div :class="{ 'opacity-100': waiting }" class="opacity-0">
<fa-icon icon="spinner" class="animate-spin" />
</div>
</div>
- <div class="mt-auto">
+ <div class="mt-auto">
<div class="flex justify-center">
<nav aria-label="Pagination">
<ul class="inline-flex items-center space-x-1 text-sm rounded-md">
@@ -22,11 +44,11 @@
</li>
<li>
<span class="inline-flex items-center px-4 py-2 space-x-1">
- Page
+ Page
<b class="mx-1">
{{ currentPage }}
</b>
- of
+ of
<b class="ml-1">
{{ pageCount }}
</b>
@@ -41,16 +63,16 @@
</nav>
</div>
</div>
-
+
<div class="h-fit">
- <button class="rounded btn primary sm" @click="openNew">
+ <button class="rounded btn primary sm" id="new-btn" @click="openNew">
<fa-icon :icon="['fas', 'plus']" class="mr-2" />
New
</button>
</div>
</div>
<table class="edit-table">
- <slot name="table" />
+ <slot name="table" />
</table>
</div>
<div v-else class="">
@@ -60,37 +82,10 @@
</slot>
</template>
-<script setup lang="ts">
-import { toRefs } from 'vue';
-import { useWait } from '@vnuge/vnlib.browser';
-import { UseOffsetPaginationReturn } from '@vueuse/core';
-
-const emit = defineEmits(['open-new'])
-const props = defineProps<{
- title: string,
- showEdit: boolean,
- pagination: UseOffsetPaginationReturn
-}>()
-
-const { showEdit } = toRefs(props)
-
-const { waiting } = useWait()
-
-//Get pagination
-const { pageCount, next, prev, isLastPage, isFirstPage, currentPage } = props.pagination
-
-const openNew = () => {
- emit('open-new')
-}
-
-</script>
-
<style lang="scss">
-
-button.page-button{
+button.page-button {
@apply inline-flex items-center px-2 py-1.5 space-x-2 font-medium;
@apply text-gray-500 bg-white border border-gray-300 rounded-full hover:bg-gray-50;
- @apply dark:border-dark-300 dark:bg-transparent dark:text-gray-300 hover:dark:bg-dark-700;
+ @apply dark:border-dark-300 dark:bg-transparent dark:text-gray-300 hover:dark:bg-dark-700;
}
-
</style> \ No newline at end of file
diff --git a/front-end/src/views/Blog/components/FeedFields.vue b/front-end/src/views/Blog/components/FeedFields.vue
index e38c3d7..2d725f9 100644
--- a/front-end/src/views/Blog/components/FeedFields.vue
+++ b/front-end/src/views/Blog/components/FeedFields.vue
@@ -1,40 +1,3 @@
-<template>
- <div id="feed-custom-fields">
- <div class="my-3 text-center">
- <h4>Feed custom fields</h4>
- </div>
-
- <div v-if="cleanXml" class="w-full max-w-2xl mx-auto">
- <pre class="xml">
-{{ cleanXml }}
- </pre>
- </div>
-
-
- <div class="my-2 ml-auto w-fit">
- <div v-if="!editMode" class="button-group">
- <button class="btn" @click="edit">Edit</button>
- </div>
- <div v-else class="button-group">
- <button class="btn primary" @click="save" >Update</button>
- <button class="btn" @click="cancel">Cancel</button>
- </div>
- </div>
-
-
- <div v-if="editMode" class="flex flex-col">
- <div v-if="$props.showEpAdder" class="mb-2">
- <EpAdder @submit="onAddEnclosure" />
- </div>
-
- <div class="">
- <JsonEditorVue :ask-to-format="true" class="json" v-model="jsonFeedData"/>
- </div>
- </div>
-
- </div>
-</template>
-
<script setup lang="ts">
import { computed, defineAsyncComponent, ref } from 'vue';
import { FeedProperty, UseXmlProperties } from '@vnuge/cmnext-admin';
@@ -100,6 +63,44 @@ const onAddEnclosure = (props: FeedProperty[]) =>{
</script>
+<template>
+ <div id="feed-custom-fields">
+ <div class="my-3 text-center">
+ <h4>Feed custom fields</h4>
+ </div>
+
+ <div v-if="cleanXml" class="w-full max-w-2xl mx-auto">
+ <pre class="xml">
+{{ cleanXml }}
+ </pre>
+ </div>
+
+
+ <div class="my-2 ml-auto w-fit">
+ <div v-if="!editMode" class="button-group">
+ <button class="btn" @click="edit">Edit</button>
+ </div>
+ <div v-else class="button-group">
+ <button class="btn primary" @click="save" >Update</button>
+ <button class="btn" @click="cancel">Cancel</button>
+ </div>
+ </div>
+
+
+ <div v-if="editMode" class="flex flex-col">
+ <div v-if="$props.showEpAdder" class="mb-2">
+ <EpAdder @submit="onAddEnclosure" />
+ </div>
+
+ <div class="">
+ <JsonEditorVue :ask-to-format="true" class="json" v-model="jsonFeedData"/>
+ </div>
+ </div>
+
+ </div>
+</template>
+
+
<style lang="scss">
#feed-custom-fields{
diff --git a/lib/Taskfile.yaml b/lib/Taskfile.yaml
index e2989c2..6b8eb17 100644
--- a/lib/Taskfile.yaml
+++ b/lib/Taskfile.yaml
@@ -25,7 +25,5 @@ tasks:
dir: '{{.USER_WORKING_DIR}}'
ignore_error: true
cmds:
- - cmd: powershell -Command "Remove-Item -Recurse node_modules"
- - cmd: powershell -Command "Remove-Item -Recurse dist"
- - cmd: powershell -Command "Remove-Item -Recurse -Force bin"
- - cmd: powershell -Command "Remove-Item release.tgz" \ No newline at end of file
+ - for: [node_modules/, dist/, bin/]
+ cmd: powershell -Command "Remove-Item -Recurse -Force {{.ITEM}}"