25852
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
parent
b0db5d01f0
commit
b363f5c29c
@ -1,8 +0,0 @@
|
|||||||
import { DEFAULT_IMAGES } from "~/config/paths";
|
|
||||||
|
|
||||||
export const handleIconError = (payload: string | Event) => {
|
|
||||||
if (payload instanceof Event) {
|
|
||||||
const target = payload.target as HTMLImageElement;
|
|
||||||
target.src = DEFAULT_IMAGES.ICON;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,3 +0,0 @@
|
|||||||
export const handleError = () => {
|
|
||||||
clearError({ redirect: window.location.pathname })
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import { DEFAULT_IMAGES } from "~/config/paths";
|
|
||||||
|
|
||||||
export const handleLightboxImageError = (event: Event): void => {
|
|
||||||
const target = event.target as HTMLImageElement;
|
|
||||||
target.src = DEFAULT_IMAGES.PROJECT;
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
@ -1,99 +0,0 @@
|
|||||||
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
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,48 +0,0 @@
|
|||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
const THEME_KEY = 'theme';
|
|
||||||
const THEMES = {
|
|
||||||
LIGHT: 'light',
|
|
||||||
DARK: 'dark'
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
const isDark = ref(false);
|
|
||||||
let initialized = false;
|
|
||||||
|
|
||||||
const setTheme = (theme: typeof THEMES[keyof typeof THEMES]) => {
|
|
||||||
if (process.client) {
|
|
||||||
document.documentElement.setAttribute('data-theme', theme);
|
|
||||||
localStorage.setItem(THEME_KEY, theme);
|
|
||||||
isDark.value = theme === THEMES.DARK;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const initializeTheme = () => {
|
|
||||||
if (process.client && !initialized) {
|
|
||||||
const savedTheme = localStorage.getItem(THEME_KEY) as typeof THEMES[keyof typeof THEMES] | null;
|
|
||||||
const prefersDark = window.matchMedia?.('(prefers-color-scheme: dark)').matches;
|
|
||||||
const theme = savedTheme || (prefersDark ? THEMES.DARK : THEMES.LIGHT);
|
|
||||||
setTheme(theme);
|
|
||||||
window.matchMedia?.('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
|
|
||||||
if (!localStorage.getItem(THEME_KEY)) {
|
|
||||||
setTheme(e.matches ? THEMES.DARK : THEMES.LIGHT);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleTheme = () => {
|
|
||||||
setTheme(isDark.value ? THEMES.LIGHT : THEMES.DARK);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useTheme = () => {
|
|
||||||
if (process.client) {
|
|
||||||
initializeTheme();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
isDark,
|
|
||||||
toggleTheme
|
|
||||||
};
|
|
||||||
};
|
|
Loading…
Reference in new issue