You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
2.7 KiB
99 lines
2.7 KiB
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 = (id: number) => {
|
|
const { $theme } = useNuxtApp();
|
|
const showLightbox = ref(false);
|
|
const currentImageIndex = ref(0);
|
|
const processedImages = ref<string[]>([]);
|
|
const currentProject = ref<Project | null>(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 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);
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
window.removeEventListener('keydown', handleKeyDown);
|
|
});
|
|
|
|
const getIconPath = (iconType: keyof typeof PATHS.ICONS) => {
|
|
return $theme.isDark.value
|
|
? PATHS.ICONS[iconType]?.DARK
|
|
: PATHS.ICONS[iconType]?.LIGHT;
|
|
};
|
|
|
|
const projectResources = computed(() => ({
|
|
github: currentProject.value?.github ? {
|
|
icon: getIconPath('GITHUB'),
|
|
label: TEXTS.PROJECTS.RESOURCES.GITHUB
|
|
} : null,
|
|
demo: currentProject.value?.demo ? {
|
|
icon: getIconPath('DEMO'),
|
|
label: TEXTS.PROJECTS.RESOURCES.DEMO
|
|
} : null,
|
|
documentation: currentProject.value?.documentation ? {
|
|
icon: getIconPath('DOCUMENTATION'),
|
|
label: TEXTS.PROJECTS.RESOURCES.DOCUMENTATION
|
|
} : null,
|
|
youtube: currentProject.value?.youtube ? {
|
|
icon: getIconPath('YOUTUBE'),
|
|
label: TEXTS.PROJECTS.RESOURCES.YOUTUBE
|
|
} : null
|
|
}));
|
|
|
|
return {
|
|
currentProject,
|
|
projectResources,
|
|
showLightbox,
|
|
currentImageIndex,
|
|
openLightbox,
|
|
closeLightbox,
|
|
nextImage,
|
|
prevImage,
|
|
handleImageError,
|
|
handleIconError,
|
|
handleLightboxImageError
|
|
};
|
|
}; |