feat: move scripts to script folder
All checks were successful
renovate / renovate (push) Successful in 26s
test-build / guarddog (push) Successful in 3m51s
test-build / build (push) Successful in 4m40s

This commit is contained in:
2026-03-15 21:53:59 -05:00
parent 93a53cab3d
commit 641c7cb33f
23 changed files with 96 additions and 99 deletions

31
src/scripts/animations.ts Normal file
View File

@@ -0,0 +1,31 @@
const animateContent = () => {
const smoothReveal = document.querySelectorAll('.smooth-reveal');
smoothReveal.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-reveal');
}, 50 + index * 100);
});
const smoothReveal2 = document.querySelectorAll('.smooth-reveal-2');
smoothReveal2.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-reveal');
}, 200 + index * 250);
});
const smoothRevealCards = document.querySelectorAll('.smooth-reveal-cards');
smoothRevealCards.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-reveal');
}, 400 + index * 250);
});
const smoothRevealFade = document.querySelectorAll('.smooth-reveal-fade');
smoothRevealFade.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-reveal-fade');
}, 100 + index * 250);
});
};
export { animateContent };

38
src/scripts/photoswipe.ts Normal file
View File

@@ -0,0 +1,38 @@
import PhotoSwipeLightbox from 'photoswipe/lightbox';
import PhotoSwipe from "photoswipe";
let lightbox: PhotoSwipeLightbox | null = null;
function initPhotoSwipe() {
const links = document.querySelectorAll<HTMLAnchorElement>('a.pswp-link');
links.forEach((link) => {
const img = link.querySelector('img');
if (img) {
const applyDimensions = () => {
link.dataset.pswpWidth = (img.naturalWidth || 1920).toString();
link.dataset.pswpHeight = (img.naturalHeight || 1080).toString();
};
if (img.complete) {
applyDimensions();
} else {
img.addEventListener('load', applyDimensions);
}
}
});
if (lightbox) {
lightbox.destroy();
}
lightbox = new PhotoSwipeLightbox({
gallery: '.prose',
children: 'a.pswp-link',
pswpModule: PhotoSwipe,
allowPanToNext: true,
});
lightbox.init();
}
export { initPhotoSwipe };

28
src/scripts/time.ts Normal file
View File

@@ -0,0 +1,28 @@
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(relativeTime);
function formatFromNow(date: Date | null): string {
if (!date) {
return 'none';
}
return dayjs(date).fromNow()
}
function formatDate(date: Date): string {
return new Date(date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
})
}
function formatShortDate(date: Date): string {
return new Date(date).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
})
}
export { formatFromNow, formatDate, formatShortDate, };

13
src/scripts/url.ts Normal file
View File

@@ -0,0 +1,13 @@
const getDirectusURL = () => {
return 'https://directus.alexlebens.net';
};
const getSiteURL = () => {
return 'https://www.alexlebens.dev';
};
function getDirectusImageURL(image: string) {
return `${getDirectusURL()}/assets/${image}`;
}
export { getDirectusURL, getSiteURL, getDirectusImageURL };

65
src/scripts/weather.ts Normal file
View File

@@ -0,0 +1,65 @@
interface DayForecast {
date: string;
temp: number;
code: number;
label: string;
icon: string;
dayName: string;
}
interface WeatherResult {
forecastDays: DayForecast[];
error: string | null;
}
const getWeatherInfo = (code: number) => {
if (code === 0) return { label: 'Clear', icon: '01d' };
if (code >= 1 && code <= 3) return { label: 'Partly Cloudy', icon: '02d' };
if (code === 45 || code === 48) return { label: 'Foggy', icon: '50d' };
if (code >= 51 && code <= 55) return { label: 'Drizzle', icon: '09d' };
if (code >= 61 && code <= 65) return { label: 'Rainy', icon: '10d' };
if (code === 66 || code === 67) return { label: 'Freezing Rain', icon: '13d' };
if (code >= 71 && code <= 75) return { label: 'Snowy', icon: '13d' };
if (code === 77) return { label: 'Snow Grains', icon: '13d' };
if (code >= 80 && code <= 82) return { label: 'Showers', icon: '09d' };
if (code === 85 || code === 86) return { label: 'Snow Showers', icon: '13d' };
if (code >= 95 && code <= 99) return { label: 'Stormy', icon: '11d' };
return { label: 'Unknown', icon: '03d' };
};
export const getDayName = (dateStr: string) => {
const date = new Date(`${dateStr}T00:00:00`);
return date.toLocaleDateString('en-US', { weekday: 'short' });
};
async function getFiveDayForecast(latitude: string, longitude: string, timezone: string): Promise<WeatherResult> {
const url = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&daily=weather_code,temperature_2m_max&timezone=${timezone}&temperature_unit=fahrenheit`;
let data: any;
try {
const response = await fetch(url);
if (!response.ok) throw new Error("Weather service unavailable");
data = await response.json();
} catch (e: unknown) {
return { forecastDays: [], error: "Failed to load weather" };
}
const forecastDays = data.daily.time
.slice(0, 5)
.map((date: string, index: number): DayForecast => {
return {
date,
temp: Math.round(data.daily.temperature_2m_max[index]),
code: data.daily.weather_code[index],
label: getWeatherInfo(data.daily.weather_code[index]).label,
icon: getWeatherInfo(data.daily.weather_code[index]).icon,
dayName: getDayName(date)
};
});
return { forecastDays, error: null };
}
export { getFiveDayForecast };