removed parallax, added flags to footer

This commit is contained in:
becarta
2025-03-07 00:13:44 +01:00
parent 6f3594261c
commit 9e47f30fc1
7 changed files with 71 additions and 132 deletions

View File

@@ -7,7 +7,7 @@ export interface Props {
disableParallax?: boolean; disableParallax?: boolean;
} }
const { isDark = false, showIcons = true, disableParallax = false } = Astro.props; const { isDark = false, showIcons = true, disableParallax = true } = Astro.props;
// Define color palettes for light and dark modes with higher contrast // Define color palettes for light and dark modes with higher contrast
const lightModeColors = [ const lightModeColors = [
@@ -22,14 +22,14 @@ const lightModeColors = [
]; ];
const darkModeColors = [ const darkModeColors = [
'dark:text-blue-400/45', 'dark:text-blue-500/65',
'dark:text-indigo-400/45', 'dark:text-indigo-500/65',
'dark:text-purple-400/45', 'dark:text-purple-500/65',
'dark:text-cyan-400/45', 'dark:text-cyan-500/65',
'dark:text-teal-400/45', 'dark:text-teal-500/65',
'dark:text-emerald-400/45', 'dark:text-emerald-500/65',
'dark:text-sky-400/45', 'dark:text-sky-500/65',
'dark:text-violet-400/45', 'dark:text-violet-500/65',
]; ];
// Define interfaces for our icon objects // Define interfaces for our icon objects
@@ -98,14 +98,20 @@ const getRandomRotation = (): string => {
return `${getRandomInRange(-30, 30)}deg`; return `${getRandomInRange(-30, 30)}deg`;
}; };
// Function to get a random size (restored to original dimensions) // Function to get a random size
const getRandomSize = (): string => { const getRandomSize = (isDarkMode: boolean = false): string => {
return `${getRandomInRange(140, 180)}px`; // Slightly larger size range for dark mode for better visibility
return isDarkMode
? `${getRandomInRange(160, 200)}px`
: `${getRandomInRange(140, 180)}px`;
}; };
// Function to get a random opacity // Function to get a random opacity
const getRandomOpacity = (): string => { const getRandomOpacity = (isDarkMode: boolean = false): string => {
return getRandomInRange(0.32, 0.38).toFixed(2); // Higher opacity range for dark mode for better visibility
return isDarkMode
? getRandomInRange(0.45, 0.55).toFixed(2)
: getRandomInRange(0.32, 0.38).toFixed(2);
}; };
// Create a spacious layout with well-separated icons // Create a spacious layout with well-separated icons
@@ -172,8 +178,8 @@ const createSpacedIcons = (): BaseIconObject[] => {
icon: iconNames[iconIndex], icon: iconNames[iconIndex],
x: `${x}%`, x: `${x}%`,
y: `${y}%`, y: `${y}%`,
size: getRandomSize(), size: getRandomSize(isDark),
opacity: getRandomOpacity(), opacity: getRandomOpacity(isDark),
rotate: getRandomRotation(), rotate: getRandomRotation(),
}); });
} }
@@ -200,15 +206,12 @@ const iconsWithColors: IconWithColors[] = icons.map(icon => ({
<slot /> <slot />
{showIcons && ( {showIcons && (
/* Decorative background icons with parallax effect */ /* Decorative background icons with random placement */
<div id="parallax-background" class="absolute inset-0 overflow-hidden pointer-events-none z-[-5]"> <div id="background-icons" class="absolute inset-0 overflow-hidden pointer-events-none z-[-5]">
{iconsWithColors.map(({ icon, x, y, size, opacity, rotate, lightColor, darkColor }, index) => ( {iconsWithColors.map(({ icon, x, y, size, opacity, rotate, lightColor, darkColor }) => (
<div <div
class={`absolute ${lightColor} ${darkColor} parallax-icon`} class={`absolute ${lightColor} ${darkColor} background-icon`}
style={`left: ${x}; top: ${y}; opacity: ${opacity}; transform: rotate(${rotate}); will-change: transform; transition: transform 0.1s ease-out;`} style={`left: ${x}; top: ${y}; opacity: ${opacity}; transform: rotate(${rotate});`}
data-depth={`${0.5 + (index % 3) * 0.2}`}
data-initial-x={x}
data-initial-y={y}
> >
<Icon name={icon} style={`width: ${size}; height: ${size};`} /> <Icon name={icon} style={`width: ${size}; height: ${size};`} />
</div> </div>

View File

@@ -20,14 +20,14 @@ const lightModeColors = [
]; ];
const darkModeColors = [ const darkModeColors = [
'dark:text-blue-400/45', 'dark:text-blue-500/65',
'dark:text-indigo-400/45', 'dark:text-indigo-500/65',
'dark:text-purple-400/45', 'dark:text-purple-500/65',
'dark:text-cyan-400/45', 'dark:text-cyan-500/65',
'dark:text-teal-400/45', 'dark:text-teal-500/65',
'dark:text-emerald-400/45', 'dark:text-emerald-500/65',
'dark:text-sky-400/45', 'dark:text-sky-500/65',
'dark:text-violet-400/45', 'dark:text-violet-500/65',
]; ];
// Define interfaces for our icon objects // Define interfaces for our icon objects
@@ -99,13 +99,19 @@ const getRandomRotation = (): string => {
}; };
// Function to get a random size // Function to get a random size
const getRandomSize = (): string => { const getRandomSize = (isDarkMode: boolean = false): string => {
return `${getRandomInRange(140, 180)}px`; // Slightly larger size range for dark mode for better visibility
return isDarkMode
? `${getRandomInRange(160, 200)}px`
: `${getRandomInRange(140, 180)}px`;
}; };
// Function to get a random opacity // Function to get a random opacity
const getRandomOpacity = (): string => { const getRandomOpacity = (isDarkMode: boolean = false): string => {
return getRandomInRange(0.32, 0.38).toFixed(2); // Higher opacity range for dark mode for better visibility
return isDarkMode
? getRandomInRange(0.45, 0.55).toFixed(2)
: getRandomInRange(0.32, 0.38).toFixed(2);
}; };
// Create a spacious layout with well-separated icons // Create a spacious layout with well-separated icons
@@ -188,8 +194,8 @@ const createSpacedIcons = (): BaseIconObject[] => {
icon: iconNames[iconIndex], icon: iconNames[iconIndex],
x: `${x}%`, x: `${x}%`,
y: `${y}%`, y: `${y}%`,
size: getRandomSize(), size: getRandomSize(isDark),
opacity: getRandomOpacity(), opacity: getRandomOpacity(isDark),
rotate: getRandomRotation(), rotate: getRandomRotation(),
visibilityClass, // Add the visibility class to the icon object visibilityClass, // Add the visibility class to the icon object
}); });
@@ -219,15 +225,12 @@ const iconsWithColors: IconWithColors[] = icons.map(icon => ({
<div class="fixed inset-0 overflow-hidden pointer-events-none z-[-5]" aria-hidden="true"> <div class="fixed inset-0 overflow-hidden pointer-events-none z-[-5]" aria-hidden="true">
<div class:list={['absolute inset-0', { 'backdrop-blur-sm bg-white/5 dark:bg-gray-900/10': isDark }]}></div> <div class:list={['absolute inset-0', { 'backdrop-blur-sm bg-white/5 dark:bg-gray-900/10': isDark }]}></div>
{/* Decorative background icons with parallax effect */} {/* Decorative background icons with random placement */}
<div id="parallax-background" class="absolute inset-0 overflow-hidden"> <div id="background-icons" class="absolute inset-0 overflow-hidden">
{iconsWithColors.map(({ icon, x, y, size, opacity, rotate, lightColor, darkColor, visibilityClass }, index) => ( {iconsWithColors.map(({ icon, x, y, size, opacity, rotate, lightColor, darkColor, visibilityClass }) => (
<div <div
class={`absolute ${lightColor} ${darkColor} parallax-icon ${visibilityClass}`} class={`absolute ${lightColor} ${darkColor} ${visibilityClass}`}
style={`left: ${x}; top: ${y}; opacity: ${opacity}; transform: rotate(${rotate}); will-change: transform; transition: transform 0.1s ease-out;`} style={`left: ${x}; top: ${y}; opacity: ${opacity}; transform: rotate(${rotate});`}
data-depth={`${0.5 + (index % 3) * 0.2}`}
data-initial-x={x}
data-initial-y={y}
> >
<Icon name={icon} style={`width: ${size}; height: ${size};`} /> <Icon name={icon} style={`width: ${size}; height: ${size};`} />
</div> </div>
@@ -235,82 +238,4 @@ const iconsWithColors: IconWithColors[] = icons.map(icon => ({
</div> </div>
</div> </div>
<script> <!-- Parallax effect removed while maintaining random icon placement -->
// Parallax scrolling effect for background icons
document.addEventListener('DOMContentLoaded', () => {
// Get all parallax icons
const parallaxIcons = document.querySelectorAll<HTMLElement>('.parallax-icon');
// Skip parallax on mobile devices for better performance
const isMobile = window.matchMedia('(max-width: 768px)').matches;
if (isMobile) return;
// Variables to track scroll position
let lastScrollY = window.scrollY;
let ticking = false;
// Function to update icon positions based on scroll
const updateParallax = () => {
parallaxIcons.forEach((icon) => {
const depth = parseFloat(icon.getAttribute('data-depth') || '0.5');
// Calculate parallax offset based on scroll position and depth
// Lower depth value means the icon moves slower (appears further away)
const yOffset = (lastScrollY * depth * 0.15);
// Get the original rotation
const transformValue = icon.style.transform;
const rotateMatch = transformValue.match(/rotate\([^)]+\)/);
const rotateValue = rotateMatch ? rotateMatch[0] : 'rotate(0deg)';
// Apply transform with the original rotation plus the parallax offset
icon.style.transform = `${rotateValue} translate3d(0, ${yOffset}px, 0)`;
});
ticking = false;
};
// Throttle scroll events for better performance
const onScroll = () => {
lastScrollY = window.scrollY;
if (!ticking) {
window.requestAnimationFrame(() => {
updateParallax();
ticking = false;
});
ticking = true;
}
};
// Add scroll event listener
window.addEventListener('scroll', onScroll, { passive: true });
// Update on resize (debounced)
let resizeTimer: number;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
// Check if device is now mobile and disable parallax if needed
const isMobileNow = window.matchMedia('(max-width: 768px)').matches;
if (isMobileNow) {
// Reset positions on mobile
parallaxIcons.forEach((icon) => {
const transformValue = icon.style.transform;
const rotateMatch = transformValue.match(/rotate\([^)]+\)/);
const rotateValue = rotateMatch ? rotateMatch[0] : 'rotate(0deg)';
icon.style.transform = rotateValue;
});
} else {
// Update parallax on desktop
updateParallax();
}
}, 200) as unknown as number;
}, { passive: true });
// Initial update
updateParallax();
});
</script>

View File

@@ -76,8 +76,13 @@ const {
<!-- Left Section: Company Name and Business Details --> <!-- Left Section: Company Name and Business Details -->
<div class="flex flex-col items-start space-y-2"> <div class="flex flex-col items-start space-y-2">
<!-- Site Title --> <!-- Site Title -->
<a class="inline-block font-bold text-xl" href={getHomePermalink(currentLang)}> <a class="inline-block font-bold text-2xl" href={getHomePermalink(currentLang)}>
{SITE?.name} {SITE?.name}
<span class="inline-flex items-center ml-2">
<Icon name="circle-flags:nl" class="h-5 w-auto flag-square" />
<span class="mx-1 text-gray-600 text-xl">🤝</span>
<Icon name="circle-flags:eu" class="h-5 w-auto flag-square" />
</span>
</a> </a>
<!-- Business Information (Dutch Law Requirements) --> <!-- Business Information (Dutch Law Requirements) -->
@@ -121,3 +126,10 @@ const {
</div> </div>
</div> </div>
</footer> </footer>
<style>
.flag-square {
border-radius: 0 !important;
overflow: hidden;
}
</style>

View File

@@ -7,8 +7,8 @@ export const getHeaderData = (lang = 'en') => {
// For hash links on the homepage, we need special handling // For hash links on the homepage, we need special handling
const homeHashLink = (hash) => { const homeHashLink = (hash) => {
// Create an absolute path to the homepage with the language prefix // Create an absolute path to the homepage with the language prefix
// and then append the hash // and include the hash in the permalink generation
return getPermalink('/', 'page', lang) + hash; return getPermalink('/' + hash, 'page', lang);
}; };
return { return {

View File

@@ -57,7 +57,6 @@ const metadata = {
<!-- Hero Widget --> <!-- Hero Widget -->
<Hero <Hero
id="hero" id="hero"
title="About Me"
isDark={false} isDark={false}
> >
<Fragment slot="subtitle"> <Fragment slot="subtitle">

View File

@@ -85,7 +85,7 @@ const tocItems = [
</div> </div>
<!-- Privacy Policy Content --> <!-- Privacy Policy Content -->
<div class="prose prose-lg max-w-4xl dark:prose-invert dark:prose-headings:text-slate-300 prose-md prose-headings:font-heading prose-headings:leading-tighter prose-headings:tracking-tighter prose-headings:font-bold prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-img:rounded-md prose-img:shadow-lg"> <div class="prose prose-lg max-w-4xl dark:prose-invert dark:prose-headings:text-slate-300 prose-md prose-headings:font-heading prose-headings:leading-tighter prose-headings:tracking-tighter prose-headings:font-bold prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-img:rounded-md prose-img:shadow-lg backdrop-blur-sm bg-white/15 dark:bg-slate-900/30 p-6 rounded-lg border border-gray-200 dark:border-slate-800">
<h2 id="introduction" class="text-2xl font-bold mt-8 mb-4">1. Introduction</h2> <h2 id="introduction" class="text-2xl font-bold mt-8 mb-4">1. Introduction</h2>
<p> <p>
This Privacy Policy explains how we handle information when you visit our website. We are committed to protecting your privacy and complying with applicable data protection laws, including the General Data Protection Regulation (GDPR). This Privacy Policy explains how we handle information when you visit our website. We are committed to protecting your privacy and complying with applicable data protection laws, including the General Data Protection Regulation (GDPR).

View File

@@ -83,7 +83,7 @@ const tocItems = [
</div> </div>
<!-- Terms Content --> <!-- Terms Content -->
<div class="prose prose-lg max-w-4xl dark:prose-invert dark:prose-headings:text-slate-300 prose-md prose-headings:font-heading prose-headings:leading-tighter prose-headings:tracking-tighter prose-headings:font-bold prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-img:rounded-md prose-img:shadow-lg"> <div class="prose prose-lg max-w-4xl dark:prose-invert dark:prose-headings:text-slate-300 prose-md prose-headings:font-heading prose-headings:leading-tighter prose-headings:tracking-tighter prose-headings:font-bold prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-img:rounded-md prose-img:shadow-lg backdrop-blur-sm bg-white/15 dark:bg-slate-900/30 p-6 rounded-lg border border-gray-200 dark:border-slate-800">
<p> <p>
Please read these terms and conditions carefully before using our website. By accessing or using our website, you agree to be bound by these terms and conditions. Please read these terms and conditions carefully before using our website. By accessing or using our website, you agree to be bound by these terms and conditions.
</p> </p>