--- import { Icon } from 'astro-icon/components'; export interface Props { isDark?: boolean; showIcons?: boolean; disableParallax?: boolean; } const { isDark = false, showIcons = true, disableParallax = false } = Astro.props; // Define color palettes for light and dark modes with higher contrast const lightModeColors = [ 'text-blue-600/40', 'text-indigo-600/40', 'text-purple-600/40', 'text-cyan-600/40', 'text-teal-600/40', 'text-emerald-600/40', 'text-sky-600/40', 'text-violet-600/40', ]; const darkModeColors = [ 'dark:text-blue-400/45', 'dark:text-indigo-400/45', 'dark:text-purple-400/45', 'dark:text-cyan-400/45', 'dark:text-teal-400/45', 'dark:text-emerald-400/45', 'dark:text-sky-400/45', 'dark:text-violet-400/45', ]; // Define interfaces for our icon objects interface BaseIconObject { icon: string; x: string; y: string; size: string; opacity: string; rotate: string; } interface IconWithColors extends BaseIconObject { lightColor: string; darkColor: string; } // Function to get a random color from the palette const getRandomColor = (palette: string[]): string => { const randomIndex = Math.floor(Math.random() * palette.length); return palette[randomIndex]; }; // List of icons to be used in the background // Expanded to include a wider variety of symbols for more visual diversity const iconNames: string[] = [ // Core IT/Tech icons 'tabler:settings-automation', 'tabler:brand-office', 'tabler:api', 'tabler:server', 'tabler:message-chatbot', 'tabler:share', 'tabler:code', 'tabler:cloud', 'tabler:device-laptop', 'tabler:database', 'tabler:brand-github', 'tabler:device-desktop', 'tabler:brand-azure', // Additional tech-related icons 'tabler:cpu', 'tabler:device-mobile', 'tabler:wifi', 'tabler:network', 'tabler:shield', 'tabler:lock', 'tabler:key', // Tangentially related icons for visual diversity 'tabler:bulb', 'tabler:compass', 'tabler:binary', 'tabler:infinity', 'tabler:brain', ]; // Function to get a random value within a range const getRandomInRange = (min: number, max: number): number => { return Math.random() * (max - min) + min; }; // Function to get a random rotation with increased range const getRandomRotation = (): string => { return `${getRandomInRange(-30, 30)}deg`; }; // Function to get a random size (restored to original dimensions) const getRandomSize = (): string => { return `${getRandomInRange(140, 180)}px`; }; // Function to get a random opacity const getRandomOpacity = (): string => { return getRandomInRange(0.32, 0.38).toFixed(2); }; // Create a spacious layout with well-separated icons const createSpacedIcons = (): BaseIconObject[] => { const icons: BaseIconObject[] = []; const rows = 6; // Reduced from 8 to 6 for fewer potential positions const cols = 6; // Reduced from 8 to 6 for fewer potential positions // Define larger margins to keep icons away from edges (in percentage) const marginX = 10; // 10% margin from left and right edges (increased from 5%) const marginY = 10; // 10% margin from top and bottom edges (increased from 5%) // Minimum distance between icons (in percentage points) const minDistance = 20; // Ensure at least 20% distance between any two icons // Create a base grid of positions for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { // Randomly skip more positions (75% chance) for fewer icons overall if (Math.random() < 0.75) { continue; } // Base position in the grid with margins applied const baseX = marginX + ((col / cols) * (100 - 2 * marginX)); const baseY = marginY + ((row / rows) * (100 - 2 * marginY)); // Add limited randomness to the position (±5%) to maintain spacing const randomOffsetX = getRandomInRange(-5, 5); const randomOffsetY = getRandomInRange(-5, 5); // Ensure positions stay within margins const x = Math.max(marginX, Math.min(100 - marginX, baseX + randomOffsetX)); const y = Math.max(marginY, Math.min(100 - marginY, baseY + randomOffsetY)); // Check if this position is too close to any existing icon let tooClose = false; for (const existingIcon of icons) { // Extract numeric values from percentage strings const existingX = parseFloat(existingIcon.x); const existingY = parseFloat(existingIcon.y); // Calculate distance between points const distance = Math.sqrt( Math.pow(x - existingX, 2) + Math.pow(y - existingY, 2) ); // If too close to an existing icon, skip this position if (distance < minDistance) { tooClose = true; break; } } if (tooClose) { continue; } // Randomly select an icon from the expanded set const iconIndex = Math.floor(Math.random() * iconNames.length); icons.push({ icon: iconNames[iconIndex], x: `${x}%`, y: `${y}%`, size: getRandomSize(), opacity: getRandomOpacity(), rotate: getRandomRotation(), }); } } return icons; }; const icons: BaseIconObject[] = createSpacedIcons(); // Assign random colors to each icon const iconsWithColors: IconWithColors[] = icons.map(icon => ({ icon: icon.icon, x: icon.x, y: icon.y, size: icon.size, opacity: icon.opacity, rotate: icon.rotate, lightColor: getRandomColor(lightModeColors), darkColor: getRandomColor(darkModeColors), })); ---
{showIcons && ( /* Decorative background icons with parallax effect */
{iconsWithColors.map(({ icon, x, y, size, opacity, rotate, lightColor, darkColor }, index) => (
))}
)}
{showIcons && ( )}