updated attachments
This commit is contained in:
@@ -1,28 +1,32 @@
|
||||
<template>
|
||||
<div>
|
||||
<SMHeader
|
||||
v-if="props.attachments && props.attachments.length > 0"
|
||||
v-if="showEditor || (modelValue && modelValue.length > 0)"
|
||||
:no-copy="props.showEditor"
|
||||
text="Files" />
|
||||
<p v-if="props.showEditor" class="small">
|
||||
{{ modelValue.length }} file{{ modelValue.length != 1 ? "s" : "" }}
|
||||
</p>
|
||||
<table
|
||||
v-if="props.attachments && props.attachments.length > 0"
|
||||
v-if="modelValue && modelValue.length > 0"
|
||||
class="w-full border-1 rounded-2 bg-white text-sm mt-2">
|
||||
<tbody>
|
||||
<tr v-for="file of props.attachments" :key="file.id">
|
||||
<td class="py-2 pl-2">
|
||||
<tr v-for="file of modelValue" :key="file.id">
|
||||
<td class="py-2 pl-2 hidden sm:block">
|
||||
<img
|
||||
:src="getFileIconImagePath(file.name || file.title)"
|
||||
class="h-10 text-center" />
|
||||
</td>
|
||||
<td class="">
|
||||
<td class="pl-2 py-4 w-full">
|
||||
<a :href="file.url">{{ file.title || file.name }}</a>
|
||||
</td>
|
||||
<td class="">
|
||||
<td class="pr-2">
|
||||
<a :href="file.url + '?download=1'"
|
||||
><svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 text-gray">
|
||||
class="h-7 pt-1 text-gray">
|
||||
<path
|
||||
d="M12 10V20M12 20L9.5 17.5M12 20L14.5 17.5"
|
||||
stroke="currentColor"
|
||||
@@ -37,12 +41,20 @@
|
||||
</svg>
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-xs text-gray">
|
||||
<td
|
||||
class="text-xs text-gray whitespace-nowrap pr-2 py-2 hidden sm:table-cell">
|
||||
({{ bytesReadable(file.size) }})
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button
|
||||
v-if="props.showEditor"
|
||||
type="button"
|
||||
class="font-medium mt-4 px-6 py-1.5 rounded-md hover:shadow-md transition text-sm bg-sky-600 hover:bg-sky-500 text-white cursor-pointer"
|
||||
@click="handleClickAdd">
|
||||
Add File
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -50,16 +62,53 @@
|
||||
import { bytesReadable } from "../helpers/types";
|
||||
import { getFileIconImagePath } from "../helpers/utils";
|
||||
import SMHeader from "../components/SMHeader.vue";
|
||||
import { openDialog } from "../components/SMDialog";
|
||||
import SMDialogMedia from "./dialogs/SMDialogMedia.vue";
|
||||
import { Media } from "../helpers/api.types";
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const props = defineProps({
|
||||
attachments: {
|
||||
type: Object,
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
required: true,
|
||||
},
|
||||
showEditor: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle the user adding a new media item.
|
||||
*/
|
||||
const handleClickAdd = async () => {
|
||||
let result = await openDialog(SMDialogMedia, {
|
||||
mime: "",
|
||||
accepts: "",
|
||||
allowUpload: true,
|
||||
multiple: true,
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const mediaResult = result as Media[];
|
||||
let newValue = props.modelValue;
|
||||
let mediaIds = new Set(newValue.map((item) => item.id));
|
||||
|
||||
mediaResult.forEach((item) => {
|
||||
if (!mediaIds.has(item.id)) {
|
||||
newValue.push(item);
|
||||
mediaIds.add(item.id);
|
||||
}
|
||||
});
|
||||
|
||||
emits("update:modelValue", newValue);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<!-- <style lang="scss">
|
||||
.attachment-list {
|
||||
border: 1px solid var(--base-color);
|
||||
border-collapse: collapse;
|
||||
@@ -154,4 +203,4 @@ const props = defineProps({
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style> -->
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
<component
|
||||
:is="`h${props.size}`"
|
||||
:id="id"
|
||||
class="sm-header cursor-pointer"
|
||||
:class="['sm-header', props.noCopy ? '' : 'cursor-pointer']"
|
||||
@click.prevent="copyAnchor">
|
||||
{{ props.text }}
|
||||
<span class="pl-2 text-sky-5 opacity-75 hidden">#</span>
|
||||
<span v-if="!props.noCopy" class="pl-2 text-sky-5 opacity-75 hidden"
|
||||
>#</span
|
||||
>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
@@ -28,6 +30,11 @@ const props = defineProps({
|
||||
default: "",
|
||||
required: false,
|
||||
},
|
||||
noCopy: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
|
||||
const computedHeaderId = (text: string): string => {
|
||||
@@ -35,29 +42,32 @@ const computedHeaderId = (text: string): string => {
|
||||
};
|
||||
|
||||
const id = ref(
|
||||
props.id && props.id.length > 0 ? props.id : computedHeaderId(props.text)
|
||||
props.id && props.id.length > 0 ? props.id : computedHeaderId(props.text),
|
||||
);
|
||||
|
||||
const copyAnchor = () => {
|
||||
const currentUrl = window.location.href.replace(/#.*/, "");
|
||||
const newUrl = currentUrl + "#" + id.value;
|
||||
if (props.noCopy === false) {
|
||||
const currentUrl = window.location.href.replace(/#.*/, "");
|
||||
const newUrl = currentUrl + "#" + id.value;
|
||||
|
||||
navigator.clipboard
|
||||
.writeText(newUrl)
|
||||
.then(() => {
|
||||
useToastStore().addToast({
|
||||
title: "Copied to Clipboard",
|
||||
content: "The heading URL has been copied to the clipboard.",
|
||||
type: "success",
|
||||
navigator.clipboard
|
||||
.writeText(newUrl)
|
||||
.then(() => {
|
||||
useToastStore().addToast({
|
||||
title: "Copied to Clipboard",
|
||||
content:
|
||||
"The heading URL has been copied to the clipboard.",
|
||||
type: "success",
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
useToastStore().addToast({
|
||||
title: "Copy to Clipboard",
|
||||
content: "Failed to copy the heading URL to the clipboard.",
|
||||
type: "danger",
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
useToastStore().addToast({
|
||||
title: "Copy to Clipboard",
|
||||
content: "Failed to copy the heading URL to the clipboard.",
|
||||
type: "danger",
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<template>
|
||||
<div class="input-attachments">
|
||||
<label>Files</label>
|
||||
<ul>
|
||||
<li v-if="mediaItems.length == 0" class="attachments-none">
|
||||
<ion-icon name="sad-outline"></ion-icon>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
:model-value="article.gallery" />
|
||||
<SMAttachments
|
||||
v-if="article.attachments.length > 0"
|
||||
:attachments="article.attachments || []" />
|
||||
:model-value="article.attachments || []" />
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
@@ -136,6 +136,8 @@ const handleLoad = async () => {
|
||||
"large",
|
||||
);
|
||||
applicationStore.setDynamicTitle(article.value.title);
|
||||
|
||||
console.log(article.value);
|
||||
} else {
|
||||
pageStatus.value = 404;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,10 @@
|
||||
</p>
|
||||
<SMImageGallery show-editor v-model:model-value="gallery" />
|
||||
</div>
|
||||
<SMInputAttachments v-model:model-value="attachments" />
|
||||
<SMAttachments
|
||||
class="mb-8"
|
||||
show-editor
|
||||
v-model:model-value="attachments" />
|
||||
<div class="flex flex-justify-end">
|
||||
<input
|
||||
type="submit"
|
||||
@@ -75,7 +78,7 @@ import SMEditor from "../../components/SMEditor.vue";
|
||||
import SMForm from "../../components/SMForm.vue";
|
||||
import SMInput from "../../components/SMInput.vue";
|
||||
import SMDropdown from "../../components/SMDropdown.vue";
|
||||
import SMInputAttachments from "../../components/SMInputAttachments.vue";
|
||||
import SMAttachments from "../../components/SMAttachments.vue";
|
||||
import { api } from "../../helpers/api";
|
||||
import { ArticleResponse, UserCollection } from "../../helpers/api.types";
|
||||
import { SMDate } from "../../helpers/datetime";
|
||||
@@ -181,12 +184,7 @@ const loadData = async () => {
|
||||
form.controls.content.value = data.article.content;
|
||||
form.controls.hero.value = data.article.hero;
|
||||
|
||||
attachments.value = (data.article.attachments || []).map(
|
||||
function (attachment) {
|
||||
return attachment.id.toString();
|
||||
},
|
||||
);
|
||||
|
||||
attachments.value = data.article.attachments;
|
||||
gallery.value = data.article.gallery;
|
||||
} else {
|
||||
pageError.value = 404;
|
||||
@@ -211,6 +209,7 @@ const handleSubmit = async () => {
|
||||
content: form.controls.content.value,
|
||||
hero: form.controls.hero.value.id,
|
||||
gallery: gallery.value.map((item) => item.id),
|
||||
attachments: attachments.value.map((item) => item.id),
|
||||
};
|
||||
|
||||
let article_id = "";
|
||||
@@ -236,13 +235,6 @@ const handleSubmit = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
await api.put({
|
||||
url: `/articles/${article_id}/attachments`,
|
||||
body: {
|
||||
attachments: attachments.value,
|
||||
},
|
||||
});
|
||||
|
||||
useToastStore().addToast({
|
||||
title: route.params.id ? "Article Updated" : "Article Created",
|
||||
content: route.params.id
|
||||
|
||||
Reference in New Issue
Block a user