|
|
|
@ -1,33 +1,66 @@
|
|
|
|
|
import { ref, computed } from 'vue';
|
|
|
|
|
import { useRoute } from 'vue-router';
|
|
|
|
|
import { projects } from '~/config/projects';
|
|
|
|
|
import { DEFAULT_IMAGES } from '~/config/paths';
|
|
|
|
|
import { ref, onMounted, onUnmounted } from 'vue';
|
|
|
|
|
import { handleImageError, handleIconError, handleLightboxImageError } from '~/assets/ts/error/handle';
|
|
|
|
|
import { TEXTS } from '~/config/content';
|
|
|
|
|
import { PATHS } from '~/config/paths';
|
|
|
|
|
import { projects } from '~/config/projects';
|
|
|
|
|
import type { Project } from '~/types/project';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const useProjectDetail = () => {
|
|
|
|
|
export const useProjectDetail = (id: number) => {
|
|
|
|
|
const { $theme } = useNuxtApp();
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
const error = ref<string | null>(null);
|
|
|
|
|
const lightboxOpen = ref(false);
|
|
|
|
|
const showLightbox = ref(false);
|
|
|
|
|
const currentImageIndex = ref(0);
|
|
|
|
|
const processedImages = ref<string[]>([]);
|
|
|
|
|
const currentProject = ref<Project | null>(null);
|
|
|
|
|
|
|
|
|
|
const currentProject = computed(() => {
|
|
|
|
|
const projectId = route.params.id as string;
|
|
|
|
|
return projects.find(p => String(p.id) === projectId) || null;
|
|
|
|
|
});
|
|
|
|
|
currentProject.value = projects.find((project) => project.id === id) || null;
|
|
|
|
|
|
|
|
|
|
const openLightbox = (index: number): void => {
|
|
|
|
|
currentImageIndex.value = index;
|
|
|
|
|
showLightbox.value = true;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const closeLightbox = (): void => {
|
|
|
|
|
showLightbox.value = false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const projectImage = computed(() => {
|
|
|
|
|
return currentProject.value?.image || DEFAULT_IMAGES.PROJECT;
|
|
|
|
|
const nextImage = (): void => {
|
|
|
|
|
if (!processedImages.value.length) return;
|
|
|
|
|
currentImageIndex.value = (currentImageIndex.value + 1) % processedImages.value.length;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const prevImage = (): void => {
|
|
|
|
|
if (!processedImages.value.length) return;
|
|
|
|
|
currentImageIndex.value = (currentImageIndex.value - 1 + processedImages.value.length) % processedImages.value.length;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleKeyDown = (event: KeyboardEvent): void => {
|
|
|
|
|
if (!showLightbox.value) return;
|
|
|
|
|
|
|
|
|
|
switch (event.key) {
|
|
|
|
|
case 'Escape':
|
|
|
|
|
closeLightbox();
|
|
|
|
|
break;
|
|
|
|
|
case 'ArrowLeft':
|
|
|
|
|
prevImage();
|
|
|
|
|
break;
|
|
|
|
|
case 'ArrowRight':
|
|
|
|
|
nextImage();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
window.addEventListener('keydown', handleKeyDown);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const projectGallery = computed(() => {
|
|
|
|
|
return currentProject.value?.gallery || [];
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
window.removeEventListener('keydown', handleKeyDown);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const getIconPath = (iconType: keyof typeof PATHS.ICONS) => {
|
|
|
|
|
return $theme.isDark.value
|
|
|
|
|
? PATHS.ICONS[iconType]?.DARK
|
|
|
|
|
return $theme.isDark.value
|
|
|
|
|
? PATHS.ICONS[iconType]?.DARK
|
|
|
|
|
: PATHS.ICONS[iconType]?.LIGHT;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -50,51 +83,17 @@ export const useProjectDetail = () => {
|
|
|
|
|
} : null
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
const handleImageError = (event: Event) => {
|
|
|
|
|
const target = event.target as HTMLImageElement;
|
|
|
|
|
target.src = DEFAULT_IMAGES.PROJECT;
|
|
|
|
|
error.value = TEXTS.COMMON.ERROR.IMAGE_LOAD;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleIconError = (event: Event) => {
|
|
|
|
|
const target = event.target as HTMLImageElement;
|
|
|
|
|
target.src = DEFAULT_IMAGES.ICON;
|
|
|
|
|
error.value = TEXTS.COMMON.ERROR.ICON_LOAD;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const openLightbox = (index: number) => {
|
|
|
|
|
currentImageIndex.value = index;
|
|
|
|
|
lightboxOpen.value = true;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const closeLightbox = () => {
|
|
|
|
|
lightboxOpen.value = false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const nextImage = () => {
|
|
|
|
|
if (projectGallery.value.length === 0) return;
|
|
|
|
|
currentImageIndex.value = (currentImageIndex.value + 1) % projectGallery.value.length;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const prevImage = () => {
|
|
|
|
|
if (projectGallery.value.length === 0) return;
|
|
|
|
|
currentImageIndex.value = (currentImageIndex.value - 1 + projectGallery.value.length) % projectGallery.value.length;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
currentProject,
|
|
|
|
|
projectImage,
|
|
|
|
|
projectGallery,
|
|
|
|
|
projectResources,
|
|
|
|
|
isLoading: ref(false),
|
|
|
|
|
error,
|
|
|
|
|
handleImageError,
|
|
|
|
|
handleIconError,
|
|
|
|
|
lightboxOpen,
|
|
|
|
|
showLightbox,
|
|
|
|
|
currentImageIndex,
|
|
|
|
|
openLightbox,
|
|
|
|
|
closeLightbox,
|
|
|
|
|
nextImage,
|
|
|
|
|
prevImage
|
|
|
|
|
prevImage,
|
|
|
|
|
handleImageError,
|
|
|
|
|
handleIconError,
|
|
|
|
|
handleLightboxImageError
|
|
|
|
|
};
|
|
|
|
|
};
|