converted files/Preview.vue to composition api & ts
This commit is contained in:
parent
66423fc98f
commit
5d8f4863ca
6
frontend/src/types/file.d.ts
vendored
6
frontend/src/types/file.d.ts
vendored
@ -18,13 +18,13 @@ interface Resource extends ResourceBase {
|
|||||||
sorting: Sorting;
|
sorting: Sorting;
|
||||||
hash?: string;
|
hash?: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
}
|
|
||||||
|
|
||||||
interface ResourceItem extends ResourceBase {
|
|
||||||
index?: number;
|
index?: number;
|
||||||
subtitles?: string[];
|
subtitles?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interface ResourceItem extends ResourceBase {
|
||||||
|
// }
|
||||||
|
|
||||||
type ResourceType =
|
type ResourceType =
|
||||||
| "video"
|
| "video"
|
||||||
| "audio"
|
| "audio"
|
||||||
|
|||||||
@ -8,37 +8,37 @@
|
|||||||
<action icon="close" :label="$t('buttons.close')" @action="close()" />
|
<action icon="close" :label="$t('buttons.close')" @action="close()" />
|
||||||
<title>{{ name }}</title>
|
<title>{{ name }}</title>
|
||||||
<action
|
<action
|
||||||
:disabled="loading"
|
:disabled="layoutStore.loading"
|
||||||
v-if="isResizeEnabled && req.type === 'image'"
|
v-if="isResizeEnabled && fileStore.req?.type === 'image'"
|
||||||
:icon="fullSize ? 'photo_size_select_large' : 'hd'"
|
:icon="fullSize ? 'photo_size_select_large' : 'hd'"
|
||||||
@action="toggleSize"
|
@action="toggleSize"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<action
|
<action
|
||||||
:disabled="loading"
|
:disabled="layoutStore.loading"
|
||||||
v-if="user.perm.rename"
|
v-if="authStore.user?.perm.rename"
|
||||||
icon="mode_edit"
|
icon="mode_edit"
|
||||||
:label="$t('buttons.rename')"
|
:label="$t('buttons.rename')"
|
||||||
show="rename"
|
show="rename"
|
||||||
/>
|
/>
|
||||||
<action
|
<action
|
||||||
:disabled="loading"
|
:disabled="layoutStore.loading"
|
||||||
v-if="user.perm.delete"
|
v-if="authStore.user?.perm.delete"
|
||||||
icon="delete"
|
icon="delete"
|
||||||
:label="$t('buttons.delete')"
|
:label="$t('buttons.delete')"
|
||||||
@action="deleteFile"
|
@action="deleteFile"
|
||||||
id="delete-button"
|
id="delete-button"
|
||||||
/>
|
/>
|
||||||
<action
|
<action
|
||||||
:disabled="loading"
|
:disabled="layoutStore.loading"
|
||||||
v-if="user.perm.download"
|
v-if="authStore.user?.perm.download"
|
||||||
icon="file_download"
|
icon="file_download"
|
||||||
:label="$t('buttons.download')"
|
:label="$t('buttons.download')"
|
||||||
@action="download"
|
@action="download"
|
||||||
/>
|
/>
|
||||||
<action
|
<action
|
||||||
:disabled="loading"
|
:disabled="layoutStore.loading"
|
||||||
icon="info"
|
icon="info"
|
||||||
:label="$t('buttons.info')"
|
:label="$t('buttons.info')"
|
||||||
show="info"
|
show="info"
|
||||||
@ -46,7 +46,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</header-bar>
|
</header-bar>
|
||||||
|
|
||||||
<div class="loading delayed" v-if="loading">
|
<div class="loading delayed" v-if="layoutStore.loading">
|
||||||
<div class="spinner">
|
<div class="spinner">
|
||||||
<div class="bounce1"></div>
|
<div class="bounce1"></div>
|
||||||
<div class="bounce2"></div>
|
<div class="bounce2"></div>
|
||||||
@ -55,9 +55,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="preview">
|
<div class="preview">
|
||||||
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
|
<ExtendedImage
|
||||||
|
v-if="fileStore.req?.type == 'image'"
|
||||||
|
:src="raw"
|
||||||
|
></ExtendedImage>
|
||||||
<audio
|
<audio
|
||||||
v-else-if="req.type == 'audio'"
|
v-else-if="fileStore.req?.type == 'audio'"
|
||||||
ref="player"
|
ref="player"
|
||||||
:src="raw"
|
:src="raw"
|
||||||
controls
|
controls
|
||||||
@ -65,7 +68,7 @@
|
|||||||
@play="autoPlay = true"
|
@play="autoPlay = true"
|
||||||
></audio>
|
></audio>
|
||||||
<video
|
<video
|
||||||
v-else-if="req.type == 'video'"
|
v-else-if="fileStore.req?.type == 'video'"
|
||||||
ref="player"
|
ref="player"
|
||||||
:src="raw"
|
:src="raw"
|
||||||
controls
|
controls
|
||||||
@ -85,11 +88,11 @@
|
|||||||
and watch it with your favorite video player!
|
and watch it with your favorite video player!
|
||||||
</video>
|
</video>
|
||||||
<object
|
<object
|
||||||
v-else-if="req.extension.toLowerCase() == '.pdf'"
|
v-else-if="fileStore.req?.extension.toLowerCase() == '.pdf'"
|
||||||
class="pdf"
|
class="pdf"
|
||||||
:data="raw"
|
:data="raw"
|
||||||
></object>
|
></object>
|
||||||
<div v-else-if="req.type == 'blob'" class="info">
|
<div v-else-if="fileStore.req?.type == 'blob'" class="info">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<i class="material-icons">feedback</i>
|
<i class="material-icons">feedback</i>
|
||||||
{{ $t("files.noPreview") }}
|
{{ $t("files.noPreview") }}
|
||||||
@ -105,7 +108,7 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
:href="raw"
|
:href="raw"
|
||||||
class="button button--flat"
|
class="button button--flat"
|
||||||
v-if="!req.isDir"
|
v-if="!fileStore.req?.isDir"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<i class="material-icons">open_in_new</i
|
<i class="material-icons">open_in_new</i
|
||||||
@ -142,8 +145,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup lang="ts">
|
||||||
import { mapActions, mapState } from "pinia";
|
|
||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import { useFileStore } from "@/stores/file";
|
import { useFileStore } from "@/stores/file";
|
||||||
import { useLayoutStore } from "@/stores/layout";
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
@ -155,210 +157,198 @@ import throttle from "lodash/throttle";
|
|||||||
import HeaderBar from "@/components/header/HeaderBar.vue";
|
import HeaderBar from "@/components/header/HeaderBar.vue";
|
||||||
import Action from "@/components/header/Action.vue";
|
import Action from "@/components/header/Action.vue";
|
||||||
import ExtendedImage from "@/components/files/ExtendedImage.vue";
|
import ExtendedImage from "@/components/files/ExtendedImage.vue";
|
||||||
|
import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
const mediaTypes = ["image", "video", "audio", "blob"];
|
const mediaTypes: ResourceType[] = ["image", "video", "audio", "blob"];
|
||||||
|
|
||||||
export default {
|
const previousLink = ref<string>("");
|
||||||
name: "preview",
|
const nextLink = ref<string>("");
|
||||||
components: {
|
const listing = ref<null | Resource[]>(null);
|
||||||
HeaderBar,
|
const name = ref<string>("");
|
||||||
Action,
|
const fullSize = ref<boolean>(false);
|
||||||
ExtendedImage,
|
const showNav = ref<boolean>(true);
|
||||||
},
|
const navTimeout = ref<null | number>(null);
|
||||||
data: function () {
|
const hoverNav = ref<boolean>(false);
|
||||||
return {
|
const autoPlay = ref<boolean>(false);
|
||||||
previousLink: "",
|
const previousRaw = ref<string>("");
|
||||||
nextLink: "",
|
const nextRaw = ref<string>("");
|
||||||
listing: null,
|
|
||||||
name: "",
|
const player = ref<HTMLVideoElement | HTMLAudioElement | null>(null);
|
||||||
fullSize: false,
|
|
||||||
showNav: true,
|
const $showError = inject<IToastError>("$showError")!;
|
||||||
navTimeout: null,
|
|
||||||
hoverNav: false,
|
const authStore = useAuthStore();
|
||||||
autoPlay: false,
|
const fileStore = useFileStore();
|
||||||
previousRaw: "",
|
const layoutStore = useLayoutStore();
|
||||||
nextRaw: "",
|
|
||||||
};
|
const route = useRoute();
|
||||||
},
|
const router = useRouter();
|
||||||
inject: ["$showError"],
|
|
||||||
computed: {
|
const hasPrevious = computed(() => previousLink.value !== "");
|
||||||
...mapState(useAuthStore, ["user", "jwt"]),
|
|
||||||
...mapState(useFileStore, ["req", "oldReq", "loading"]),
|
const hasNext = computed(() => nextLink.value !== "");
|
||||||
...mapState(useLayoutStore, ["show"]),
|
|
||||||
hasPrevious() {
|
const downloadUrl = computed(() =>
|
||||||
return this.previousLink !== "";
|
fileStore.req ? api.getDownloadURL(fileStore.req, true) : ""
|
||||||
},
|
);
|
||||||
hasNext() {
|
|
||||||
return this.nextLink !== "";
|
const raw = computed(() => {
|
||||||
},
|
if (fileStore.req?.type === "image" && !fullSize.value) {
|
||||||
downloadUrl() {
|
return api.getPreviewURL(fileStore.req, "big");
|
||||||
return api.getDownloadURL(this.req);
|
|
||||||
},
|
|
||||||
raw() {
|
|
||||||
console.log(this.req);
|
|
||||||
if (this.req.type === "image" && !this.fullSize) {
|
|
||||||
return api.getPreviewURL(this.req, "big");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.getDownloadURL(this.req, true);
|
return downloadUrl.value;
|
||||||
},
|
});
|
||||||
showMore() {
|
|
||||||
return this.show === "more";
|
const isResizeEnabled = computed(() => resizePreview);
|
||||||
},
|
|
||||||
isResizeEnabled() {
|
const subtitles = computed(() => {
|
||||||
return resizePreview;
|
if (fileStore.req?.subtitles) {
|
||||||
},
|
return api.getSubtitlesURL(fileStore.req);
|
||||||
subtitles() {
|
|
||||||
if (this.req.subtitles) {
|
|
||||||
return api.getSubtitlesURL(this.req);
|
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
},
|
});
|
||||||
},
|
|
||||||
watch: {
|
watch(route, () => {
|
||||||
$route: function () {
|
updatePreview();
|
||||||
this.updatePreview();
|
toggleNavigation();
|
||||||
this.toggleNavigation();
|
});
|
||||||
},
|
|
||||||
},
|
// Specify hooks
|
||||||
async mounted() {
|
onMounted(async () => {
|
||||||
window.addEventListener("keydown", this.key);
|
window.addEventListener("keydown", key);
|
||||||
this.listing = this.oldReq.items;
|
if (fileStore.oldReq) {
|
||||||
this.updatePreview();
|
listing.value = fileStore.oldReq.items;
|
||||||
},
|
updatePreview();
|
||||||
beforeUnmount() {
|
}
|
||||||
window.removeEventListener("keydown", this.key);
|
});
|
||||||
},
|
|
||||||
methods: {
|
onBeforeUnmount(() => window.removeEventListener("keydown", key));
|
||||||
...mapActions(useFileStore, ["updateRequest"]),
|
|
||||||
...mapActions(useLayoutStore, ["showHover", "closeHovers"]),
|
// Specify methods
|
||||||
deleteFile() {
|
const deleteFile = () => {
|
||||||
this.showHover({
|
layoutStore.showHover({
|
||||||
prompt: "delete",
|
prompt: "delete",
|
||||||
confirm: () => {
|
confirm: () => {
|
||||||
this.listing = this.listing.filter((item) => item.name !== this.name);
|
if (listing.value === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
listing.value = listing.value.filter((item) => item.name !== name.value);
|
||||||
|
|
||||||
if (this.hasNext) {
|
if (hasNext.value) {
|
||||||
this.next();
|
next();
|
||||||
} else if (!this.hasPrevious && !this.hasNext) {
|
} else if (!hasPrevious.value && !hasNext.value) {
|
||||||
this.close();
|
close();
|
||||||
} else {
|
} else {
|
||||||
this.prev();
|
prev();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
};
|
||||||
prev() {
|
|
||||||
this.hoverNav = false;
|
const prev = () => {
|
||||||
this.$router.replace({ path: this.previousLink });
|
hoverNav.value = false;
|
||||||
},
|
router.replace({ path: previousLink.value });
|
||||||
next() {
|
};
|
||||||
this.hoverNav = false;
|
|
||||||
this.$router.replace({ path: this.nextLink });
|
const next = () => {
|
||||||
},
|
hoverNav.value = false;
|
||||||
key(event) {
|
router.replace({ path: nextLink.value });
|
||||||
if (this.show !== null) {
|
};
|
||||||
|
|
||||||
|
const key = (event: KeyboardEvent) => {
|
||||||
|
if (layoutStore.show !== null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.which === 13 || event.which === 39) {
|
if (event.which === 13 || event.which === 39) {
|
||||||
// right arrow
|
// right arrow
|
||||||
if (this.hasNext) this.next();
|
if (hasNext.value) next();
|
||||||
} else if (event.which === 37) {
|
} else if (event.which === 37) {
|
||||||
// left arrow
|
// left arrow
|
||||||
if (this.hasPrevious) this.prev();
|
if (hasPrevious.value) prev();
|
||||||
} else if (event.which === 27) {
|
} else if (event.which === 27) {
|
||||||
// esc
|
// esc
|
||||||
this.close();
|
close();
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
async updatePreview() {
|
const updatePreview = async () => {
|
||||||
if (
|
if (player.value && player.value.paused && !player.value.ended) {
|
||||||
this.$refs.player &&
|
autoPlay.value = false;
|
||||||
this.$refs.player.paused &&
|
|
||||||
!this.$refs.player.ended
|
|
||||||
) {
|
|
||||||
this.autoPlay = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let dirs = this.$route.fullPath.split("/");
|
let dirs = route.fullPath.split("/");
|
||||||
this.name = decodeURIComponent(dirs[dirs.length - 1]);
|
name.value = decodeURIComponent(dirs[dirs.length - 1]);
|
||||||
|
|
||||||
if (!this.listing) {
|
if (!listing.value) {
|
||||||
try {
|
try {
|
||||||
const path = url.removeLastDir(this.$route.path);
|
const path = url.removeLastDir(route.path);
|
||||||
const res = await api.fetch(path);
|
const res = await api.fetch(path);
|
||||||
this.listing = res.items;
|
listing.value = res.items;
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
this.$showError(e);
|
$showError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.previousLink = "";
|
previousLink.value = "";
|
||||||
this.nextLink = "";
|
nextLink.value = "";
|
||||||
|
if (listing.value) {
|
||||||
for (let i = 0; i < this.listing.length; i++) {
|
for (let i = 0; i < listing.value.length; i++) {
|
||||||
if (this.listing[i].name !== this.name) {
|
if (listing.value[i].name !== name.value) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = i - 1; j >= 0; j--) {
|
for (let j = i - 1; j >= 0; j--) {
|
||||||
if (mediaTypes.includes(this.listing[j].type)) {
|
if (mediaTypes.includes(listing.value[j].type)) {
|
||||||
this.previousLink = this.listing[j].url;
|
previousLink.value = listing.value[j].url;
|
||||||
this.previousRaw = this.prefetchUrl(this.listing[j]);
|
previousRaw.value = prefetchUrl(listing.value[j]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let j = i + 1; j < this.listing.length; j++) {
|
for (let j = i + 1; j < listing.value.length; j++) {
|
||||||
if (mediaTypes.includes(this.listing[j].type)) {
|
if (mediaTypes.includes(listing.value[j].type)) {
|
||||||
this.nextLink = this.listing[j].url;
|
nextLink.value = listing.value[j].url;
|
||||||
this.nextRaw = this.prefetchUrl(this.listing[j]);
|
nextRaw.value = prefetchUrl(listing.value[j]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
prefetchUrl(item) {
|
};
|
||||||
|
|
||||||
|
const prefetchUrl = (item: Resource) => {
|
||||||
if (item.type !== "image") {
|
if (item.type !== "image") {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.fullSize
|
return fullSize.value
|
||||||
? api.getDownloadURL(item, true)
|
? api.getDownloadURL(item, true)
|
||||||
: api.getPreviewURL(item, "big");
|
: api.getPreviewURL(item, "big");
|
||||||
},
|
};
|
||||||
openMore() {
|
|
||||||
this.showHover("more");
|
|
||||||
},
|
|
||||||
resetPrompts() {
|
|
||||||
this.closeHovers();
|
|
||||||
},
|
|
||||||
toggleSize() {
|
|
||||||
this.fullSize = !this.fullSize;
|
|
||||||
},
|
|
||||||
toggleNavigation: throttle(function () {
|
|
||||||
this.showNav = true;
|
|
||||||
|
|
||||||
if (this.navTimeout) {
|
const toggleSize = () => (fullSize.value = !fullSize.value);
|
||||||
clearTimeout(this.navTimeout);
|
|
||||||
|
const toggleNavigation = throttle(function () {
|
||||||
|
showNav.value = true;
|
||||||
|
|
||||||
|
if (navTimeout.value) {
|
||||||
|
clearTimeout(navTimeout.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.navTimeout = setTimeout(() => {
|
navTimeout.value = setTimeout(() => {
|
||||||
this.showNav = false || this.hoverNav;
|
showNav.value = false || hoverNav.value;
|
||||||
this.navTimeout = null;
|
navTimeout.value = null;
|
||||||
}, 1500);
|
}, 1500);
|
||||||
}, 500),
|
}, 500);
|
||||||
close() {
|
|
||||||
this.updateRequest({});
|
|
||||||
|
|
||||||
let uri = url.removeLastDir(this.$route.path) + "/";
|
const close = () => {
|
||||||
this.$router.push({ path: uri });
|
fileStore.updateRequest(null);
|
||||||
},
|
|
||||||
download() {
|
let uri = url.removeLastDir(route.path) + "/";
|
||||||
window.open(this.downloadUrl);
|
router.push({ path: uri });
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const download = () => window.open(downloadUrl.value);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user