122 lines
No EOL
3.3 KiB
Vue
122 lines
No EOL
3.3 KiB
Vue
<template>
|
|
<BaseLayout>
|
|
<main class="content">
|
|
<div class="container-fluid p-0">
|
|
<h1 class="h3 mb-3">Files</h1>
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Images</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="masonry-grid">
|
|
<div class="masonry-item" v-for="file in only_images(files)" :key="file.id">
|
|
<deletable-wrapper confirm-message="Delete this file? This cannot be undone." @delete="deleteFile(file)">
|
|
<authenticated-image :src="thumbnailPathForHash(file.hash)" :owner="file.owner"
|
|
class="img-preview-masonry"/>
|
|
</deletable-wrapper>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Other files</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul>
|
|
<li v-for="file in whithout_images(files)" :key="file.id">
|
|
{{ file.name }}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</BaseLayout>
|
|
</template>
|
|
|
|
<script>
|
|
import {mapActions, mapState} from "vuex";
|
|
import * as BIcons from "bootstrap-icons-vue";
|
|
import BaseLayout from "@/components/BaseLayout.vue";
|
|
import AuthenticatedImage from "@/components/AuthenticatedImage.vue";
|
|
import DeletableWrapper from "@/components/DeletableWrapper.vue";
|
|
|
|
export default {
|
|
name: "Files",
|
|
components: {
|
|
AuthenticatedImage,
|
|
BaseLayout,
|
|
DeletableWrapper,
|
|
...BIcons
|
|
},
|
|
computed: {
|
|
...mapState(["files"])
|
|
},
|
|
methods: {
|
|
...mapActions(["fetchFiles", "deleteFile"]),
|
|
only_images(files) {
|
|
return files.filter(file => file.mime_type.startsWith("image/"));
|
|
},
|
|
whithout_images(files) {
|
|
return files.filter(file => !file.mime_type.startsWith("image/"));
|
|
},
|
|
// See docs/implementation.md#thumbnail-lookup-by-hash.
|
|
thumbnailPathForHash(hash, size = 256) {
|
|
return `/media/${size}/${hash.slice(0, 2)}/${hash.slice(2, 4)}/${hash.slice(4, 6)}/${hash.slice(6)}/`;
|
|
}
|
|
},
|
|
mounted() {
|
|
this.fetchFiles();
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
@import "../scss/breakpoints";
|
|
|
|
.img-preview-masonry {
|
|
width: 100%;
|
|
height: auto;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.masonry-item :deep(span) {
|
|
display: block !important;
|
|
width: 100%;
|
|
}
|
|
|
|
.masonry-grid {
|
|
column-count: 2;
|
|
column-gap: 1rem;
|
|
}
|
|
|
|
.masonry-item {
|
|
break-inside: avoid;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
@include media-breakpoint-up(md) {
|
|
.masonry-grid {
|
|
column-count: 3;
|
|
}
|
|
}
|
|
|
|
@include media-breakpoint-up(lg) {
|
|
.masonry-grid {
|
|
column-count: 4;
|
|
}
|
|
}
|
|
|
|
@include media-breakpoint-up(xl) {
|
|
.masonry-grid {
|
|
column-count: 6;
|
|
}
|
|
}
|
|
|
|
@include media-breakpoint-up(xxl) {
|
|
.masonry-grid {
|
|
column-count: 12;
|
|
}
|
|
}
|
|
</style> |