retest
continuous-integration/drone/push Build is passing Details

master
37b7 3 weeks ago
parent 20498d1ad5
commit 771982bbad

@ -1,119 +0,0 @@
import { ref, computed, onMounted, onUnmounted } from 'vue';
import { useRoute } from 'vue-router';
import { projects } from '~/config/projects';
import type { Project } from '~/types/project';
export const useProjectDetail = () => {
const route = useRoute();
const showLightbox = ref(false);
const currentImageIndex = ref(0);
const processedImages = ref<string[]>([]);
const processedResources = ref<Array<{
name: string;
icon: string;
url: string;
}>>([]);
const project = computed<Project | undefined>(() => {
const projectId = Number(route.params.id);
return projects.find(p => p.id === projectId);
});
const processProjectResources = async () => {
if (!project.value) return;
// Process main project image
if (project.value.image) {
processedImages.value = [project.value.image];
}
// Process resources
const resourcePromises = Object.entries(project.value).map(async ([key, value]) => {
if (['github', 'demo', 'documentation', 'youtube'].includes(key) && value) {
return {
name: key,
icon: `/images/${key}-icon.png`,
url: value
};
}
return null;
});
processedResources.value = (await Promise.all(resourcePromises)).filter((resource): resource is { name: string; icon: string; url: string } => resource !== 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 handleImageError = (event: Event): void => {
const target = event.target as HTMLImageElement;
target.src = '/images/default-project.png';
};
const handleIconError = (event: Event): void => {
const target = event.target as HTMLImageElement;
target.src = '/images/default-icon.png';
};
const handleLightboxImageError = (event: Event): void => {
const target = event.target as HTMLImageElement;
target.src = '/images/default-project.png';
closeLightbox();
};
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);
await processProjectResources();
});
onUnmounted(() => {
window.removeEventListener('keydown', handleKeyDown);
});
return {
project,
showLightbox,
currentImageIndex,
processedImages,
processedResources,
openLightbox,
closeLightbox,
nextImage,
prevImage,
handleImageError,
handleIconError,
handleLightboxImageError
};
};

@ -1,54 +0,0 @@
import { projects } from '~/config/projects';
import type { Project, ProcessedResources } from '~/types/project';
import { PATHS, DEFAULT_IMAGES } from '~/config/paths';
export const truncateDescription = (description: string): string => {
const maxLength = 150;
if (description.length <= maxLength) return description;
return description.substring(0, maxLength) + '...';
};
export const processProjectImage = async (project: Project): Promise<string> => {
try {
const response = await fetch(project.image);
if (!response.ok) {
return DEFAULT_IMAGES.PROJECT;
}
return project.image;
} catch (error) {
console.error('Error loading project image:', error);
return DEFAULT_IMAGES.PROJECT;
}
};
export const processProjectResources = async (project: Project): Promise<ProcessedResources> => {
const resources: ProcessedResources = {};
if (project.github) {
resources.github = {
url: project.github,
icon: PATHS.ICONS.GITHUB
};
}
if (project.demo) {
resources.demo = {
url: project.demo,
icon: PATHS.ICONS.DEMO
};
}
return resources;
};
export const handleImageError = (event: Event): void => {
const target = event.target as HTMLImageElement;
target.src = DEFAULT_IMAGES.PROJECT;
};
export const handleIconError = (event: Event): void => {
const target = event.target as HTMLImageElement;
target.src = DEFAULT_IMAGES.ICON;
};
export { projects };

@ -1,90 +0,0 @@
import { ref, onMounted, computed } from 'vue';
import { useRouter } from 'vue-router';
import type { Project } from '~/types/project';
import {
projects,
truncateDescription,
processProjectImage,
processProjectResources,
handleImageError,
handleIconError,
} from "~/assets/ts/pages/projects";
import { TEXTS } from '~/config/content';
import { DEFAULT_IMAGES } from '~/config/paths';
interface ProjectResource {
url: string;
icon: string;
}
interface ProcessedResources {
github?: ProjectResource;
demo?: ProjectResource;
}
export const useProjects = () => {
const router = useRouter();
const projectImages = ref<Record<number, string>>({});
const projectResources = ref<Record<number, ProcessedResources>>({});
const isLoading = ref(true);
const error = ref<string | null>(null);
const filteredProjects = computed(() => {
return projects;
});
const loadProjectResources = async () => {
try {
const loadPromises = projects.map(async (project: Project) => {
try {
const [image, resources] = await Promise.all([
processProjectImage(project),
processProjectResources(project)
]);
projectImages.value[project.id] = image;
projectResources.value[project.id] = resources;
} catch (error) {
console.error('Error loading resources for project ${project.id}:', error);
projectImages.value[project.id] = DEFAULT_IMAGES.PROJECT;
projectResources.value[project.id] = {};
}
});
await Promise.all(loadPromises);
} catch (error) {
console.error('Error loading project resources:', error);
} finally {
isLoading.value = false;
}
};
const getProjectStatus = (status: Project['status']) => {
switch (status) {
case 'completed':
return TEXTS.PROJECTS.STATUS.COMPLETED;
case 'in-progress':
return TEXTS.PROJECTS.STATUS.IN_PROGRESS;
case 'planned':
return TEXTS.PROJECTS.STATUS.PLANNED;
default:
return status;
}
};
onMounted(() => {
loadProjectResources();
});
return {
projects: filteredProjects,
projectImages,
projectResources,
isLoading,
error,
truncateDescription,
handleImageError,
handleIconError,
getProjectStatus
};
};

@ -82,19 +82,15 @@ import { ref, computed } from 'vue';
import { useProjectDetail } from '~/composables/useProjectDetail';
import { TEXTS } from '~/config/content';
import { navigationItems } from '~/config/navigation';
import { useRoute } from 'nuxt/app';
import { projects } from '~/config/projects';
import { DEFAULT_IMAGES, PATHS } from '~/config/paths';
const route = useRoute();
const projectId = Number(route.params.id);
const currentProject = ref(projects.find(p => p.id === projectId) || null);
const projectsPath = navigationItems.find((item) => item.finder === 'projects')?.path || '/projects';
const projectImage = computed(() => {return currentProject.value?.image || DEFAULT_IMAGES.PROJECT;});
const projectGallery = computed(() => {return currentProject.value?.gallery || [];});
const projectResources = computed(() => {return currentProject.value?.resources || [];});
const {
currentProject,
handleImageError,
handleIconError,
showLightbox,
@ -105,6 +101,9 @@ const {
prevImage
} = useProjectDetail(projectId);
const projectImage = computed(() => {return currentProject.value?.image || DEFAULT_IMAGES.PROJECT;});
const projectGallery = computed(() => {return currentProject.value?.gallery || [];});
</script>
<style scoped>

Loading…
Cancel
Save