Skip to content

Commit

Permalink
rework image gallery
Browse files Browse the repository at this point in the history
  • Loading branch information
ufaboy committed Jan 18, 2024
1 parent 3969ed6 commit b208e1e
Show file tree
Hide file tree
Showing 12 changed files with 126 additions and 352 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "lib-vue",
"private": true,
"version": "1.3.1",
"version": "1.4.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
1 change: 1 addition & 0 deletions public/icons/authors.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/tags.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/TheHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ watch(
</router-link>
</li>
<li class="w-full lg:w-fit">
<router-link :to="{ name: 'images-table' }" class="header-link inline-block" active-class="header-link-active">
<router-link :to="{ name: 'images' }" class="header-link inline-block" active-class="header-link-active">
Images
</router-link>
</li>
Expand Down
24 changes: 1 addition & 23 deletions src/components/TheSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const bookID = computed(()=> {
</li>
<li class="w-full">
<RouterLink
:to="{ name: 'images-table' }"
:to="{ name: 'images' }"
class="sidebar-link flex items-center gap-2"
active-class="sidebar-link-active">
<svg class="inline size-6" fill="none">
Expand All @@ -91,28 +91,6 @@ const bookID = computed(()=> {
<span v-show="!collapsed">Create</span>
</RouterLink>
</li>
<li v-if="route.name === 'images-table'" class="w-full">
<RouterLink
:to="{ name: 'images-gallery' }"
class="sidebar-link flex items-center gap-2"
active-class="sidebar-link-active">
<svg class="inline size-6" fill="none">
<use xlink:href="/icons/iconSprite.svg#gallery" />
</svg>
<span v-show="!collapsed">Gallery View</span>
</RouterLink>
</li>
<li v-if="route.name === 'images-gallery'" class="w-full">
<RouterLink
:to="{ name: 'images-table' }"
class="sidebar-link flex items-center gap-2"
active-class="sidebar-link-active">
<svg class="inline size-6" fill="none">
<use xlink:href="/icons/iconSprite.svg#gallery" />
</svg>
<span v-show="!collapsed">Table View</span>
</RouterLink>
</li>
<li v-if="route.name === 'book-update'" class="w-full">
<RouterLink
:to="{ name: 'book-view' }"
Expand Down
33 changes: 26 additions & 7 deletions src/composables/images.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ref } from 'vue';

Check failure on line 1 in src/composables/images.ts

View workflow job for this annotation

GitHub Actions / deploy

Type 'ImagesResponse | undefined' is not assignable to type 'Image | undefined'.

Check failure on line 1 in src/composables/images.ts

View workflow job for this annotation

GitHub Actions / deploy

'img' is possibly 'undefined'.

Check failure on line 1 in src/composables/images.ts

View workflow job for this annotation

GitHub Actions / deploy

Property 'file_name' does not exist on type 'ImagesResponse'.
import { formRequest, deleteRequest, getRequest, getUrl, fetchData } from '@/utils/helper';
import type { Image, QueryImages, ImagesResponse, ImagesTotal } from '@/interfaces/images';
import type { Image, QueryImages, ImagesResponse, StorageImages } from '@/interfaces/images';
import type { ListMeta } from '@/interfaces/meta';

export function useImage() {
Expand All @@ -22,11 +22,21 @@ export function useImage() {
const imageDialog = ref<InstanceType<typeof HTMLDialogElement>>();
const isTableView = ref(true);
const infinityState = ref(true);
const totalBooks = ref<Array<ImagesTotal>>([])
const storageImages = ref<Array<StorageImages>>([]);

async function getImageByName(bookID: number, imageName: string) {
try {
const url = getUrl(`${import.meta.env.VITE_BACKEND_URL}/api/image/view-by-name`, { bookID, imageName });
const request = getRequest(url);
return await fetchData<ImagesResponse>(request);
} catch (error) {
console.log('getImageByName wrong', { error: error });
}
}

async function getImages(query?: BaseQuery) {
try {
if(!queryImages.value.book_id && !queryImages.value.book_name) {
if (!queryImages.value.book_id && !queryImages.value.book_name) {
return null;
}
const url = getUrl(`${import.meta.env.VITE_BACKEND_URL}/api/image`, {
Expand Down Expand Up @@ -93,6 +103,12 @@ export function useImage() {
? `/${image.path}/${image.file_name}`
: `${import.meta.env.VITE_BACKEND_URL}/${image.path}/${image.file_name}`;
}
function getStorageImageUrl(imageName: string, dirID: number) {
const bookPath = `book_${String(dirID).padStart(3, '0')}`;
return import.meta.env.PROD
? `/media/${bookPath}/${imageName}`
: `${import.meta.env.VITE_BACKEND_URL}/media/${bookPath}/${imageName}`;
}

function getImageUrl(image: Blob) {
return window.URL.createObjectURL(image);
Expand All @@ -118,7 +134,8 @@ export function useImage() {
image.value = undefined;
}

function showImageDialog(img: Image) {
async function showImageDialog(bookID: number, imageName: string) {
const img = await getImageByName(bookID, imageName);
image.value = img;
imageFileName.value = img.file_name;
if (imageDialog.value) imageDialog.value.showModal();
Expand Down Expand Up @@ -151,15 +168,15 @@ export function useImage() {
try {
const url = new URL(`${import.meta.env.VITE_BACKEND_URL}/api/image/total`);
const request = getRequest(url);
const data = await fetchData<Array<ImagesTotal>>(request);
totalBooks.value = data
const data = await fetchData<Array<StorageImages>>(request);
storageImages.value = data;
} catch (error) {}
}

return {
image,
images,
totalBooks,
storageImages,
imagesMeta,
queryImages,
isTableView,
Expand All @@ -168,13 +185,15 @@ export function useImage() {
infinityState,
changeSort,
getTotal,
getImageByName,
getImages,
getImagesAndPush,
updateImage,
deleteImages,
deleteAllImages,
getImageUrl,
copyImageUrl,
getStorageImageUrl,
getUploadedImageUrl,
closeDialog,
showImageDialog,
Expand Down
2 changes: 1 addition & 1 deletion src/directives/LazyLoadDirective.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export default {
() => {
setTimeout(() => {
el.classList.add('loaded');
el.classList.remove('cap');
}, 100);
},
{ passive: true },
Expand Down Expand Up @@ -53,5 +52,6 @@ export default {
} else {
createObserver();
}

},
};
6 changes: 5 additions & 1 deletion src/interfaces/images.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,9 @@ interface ImagesTotal {
book_id: number;
images_count: number
}
interface StorageImages {
bookID: number;
images: Array<string>;
}

export type { RawFile, Image, QueryImages, ImagesResponse, ImagesTotal };
export type { RawFile, Image, QueryImages, ImagesResponse, ImagesTotal, StorageImages };
15 changes: 2 additions & 13 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const BookText = () => import('./views/BookText.vue');
const BookComics = () => import('./views/BookComics.vue');
const BookEdit = () => import('./views/BookEdit.vue');
const ImageGallery = () => import('./views/ImageGallery.vue');
const ImageTable = () => import('./views/ImageTable.vue');
const SeriesTable = () => import('./views/SeriesTable.vue');
const TagTable = () => import('./views/TagTable.vue');
const LoginPage = () => import('./views/LoginPage.vue');
Expand Down Expand Up @@ -78,18 +77,8 @@ const routes: RouteRecordRaw[] = [
},
{
path: '/images',
children: [
{
path: '',
name: 'images-table',
component: ImageTable,
},
{
path: 'gallery',
name: 'images-gallery',
component: ImageGallery,
},
],
name: 'images',
component: ImageGallery
},
],
},
Expand Down
171 changes: 77 additions & 94 deletions src/views/ImageGallery.vue
Original file line number Diff line number Diff line change
@@ -1,110 +1,93 @@
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router'
import { computed, onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useImage } from '@/composables/images';
import ImageForm from '@/components/forms/ImageForm.vue'
import ImageForm from '@/components/forms/ImageForm.vue';
const route = useRoute()
const { queryImages, image, images, imageDialog, infinityState,
getUploadedImageUrl, showImageDialog, closeDialog, getImagesAndPush } = useImage()
const route = useRoute();
const {
queryImages,
image,
images,
imageDialog,
storageImages,
getStorageImageUrl,
getUploadedImageUrl,
showImageDialog,
closeDialog,
getTotal,
} = useImage();
const mounted = ref(false)
const mounted = ref(false);
const filteredImages = computed(() => {
if (queryImages.value.book_id) {
return storageImages.value.filter((book) => {
return book.bookID === Number(queryImages.value.book_id);
});
} else return storageImages.value;
});
function changeQuery() {
queryImages.value.page = 1
images.value = []
queryImages.value.page = 1;
images.value = [];
}
function parseQueryParams() {
const bookID = route.query['book-id']
if(bookID) queryImages.value.book_id = Number(bookID)
const bookID = route.query['book-id'];
if (bookID) queryImages.value.book_id = Number(bookID);
}
watch(() => route.query, () => {
console.log('route.query', route.query)
})
watch(
() => route.query,
() => {
console.log('route.query', route.query);
},
);
onMounted(() => {
mounted.value = true
})
queryImages.value.page = 1
queryImages.value.perPage = 20
parseQueryParams()
mounted.value = true;
});
getTotal();
</script>

<template>
<main class="flex flex-wrap gap-3">
<form
action=""
class="flex w-full items-center gap-4"
>
<label
for=""
class="flex flex-col"
>
<span>Book ID</span>
<input
v-model="queryImages.book_id"
type="search"
class="input"
@search="changeQuery"
>
</label>
<label
for=""
class="flex flex-col"
>
<span>Book Name</span>
<input
v-model="queryImages.bookName"
type="search"
class="input"
@search="changeQuery"
>
</label>
<label
for=""
class="flex flex-col"
>
<span>File Name</span>
<input
v-model="queryImages.file_name"
type="search"
class="input"
@search="changeQuery"
>
</label>
</form>
<button
v-for="img in images"
:key="img.id"
@click="showImageDialog(img)"
>
<figure class="h-full">
<img
:src="getUploadedImageUrl(img)"
alt=""
class="size-44 rounded-md object-cover"
>
<figcaption class="mt-auto">
{{ img.file_name }}
</figcaption>
</figure>
</button>
<observer
v-if="infinityState"
@intersect="getImagesAndPush(queryImages)"
/>
<dialog
ref="imageDialog"
class="dialog max-w-sm rounded-lg bg-neutral-300 p-4 text-slate-800 shadow-md dark:bg-slate-800 dark:text-white"
@close="closeDialog"
>
<ImageForm
v-if="image"
:image="image"
@close="closeDialog"
/>
</dialog>
</main>
</template>
<main class="flex flex-wrap gap-3">
<form action="" class="flex w-full items-center gap-4">
<label for="" class="flex flex-col">
<span>Book ID</span>
<input v-model="queryImages.book_id" type="search" class="input" list="idList" />
<datalist id="idList">
<option v-for="(book, index) in storageImages" :key="index">
{{ book.bookID }}</option>
</datalist>
</label>
<!-- <label for="" class="flex flex-col">
<span>Book Name</span>
<input v-model="queryImages.bookName" type="search" class="input" @search="changeQuery" />
</label>
<label for="" class="flex flex-col">
<span>File Name</span>
<input v-model="queryImages.file_name" type="search" class="input" @search="changeQuery" />
</label> -->
</form>
<div v-for="dir in filteredImages" :key="dir.bookID">
<h2 class="mb-2">Book {{ dir.bookID }}</h2>
<button v-for="(img, index) in dir.images" :key="index" class="p-2" @click="showImageDialog(dir.bookID, img)">
<figure class="h-full" v-lazy-load>
<img src="" class="size-44 rounded-md object-cover" :data-url="getStorageImageUrl(img, dir.bookID)" />
<figcaption class="mt-auto">
{{ img }}
</figcaption>
</figure>
</button>
</div>
<dialog
ref="imageDialog"
class="dialog max-w-sm rounded-lg bg-neutral-300 p-4 text-slate-800 shadow-md dark:bg-slate-800 dark:text-white"
@close="closeDialog">
<ImageForm v-if="image" :image="image" @close="closeDialog" />
</dialog>
</main>
</template>
Loading

0 comments on commit b208e1e

Please sign in to comment.