diff --git a/inter.zip b/inter.zip new file mode 100644 index 0000000..6eab61c Binary files /dev/null and b/inter.zip differ diff --git a/production-email-test.cjs b/production-email-test.cjs index 16718ad..4b36cb0 100644 --- a/production-email-test.cjs +++ b/production-email-test.cjs @@ -16,7 +16,7 @@ const { SMTP_PORT = '587', SMTP_USER = '', SMTP_PASS = '', - ADMIN_EMAIL = 'richard@bergsma.it', + ADMIN_EMAIL = '', WEBSITE_NAME = 'bergsma.it', NODE_ENV = 'production' } = process.env; diff --git a/public/fonts/inter-variable.woff2 b/public/fonts/inter-variable.woff2 new file mode 100644 index 0000000..6a256a0 Binary files /dev/null and b/public/fonts/inter-variable.woff2 differ diff --git a/src/assets/styles/tailwind.css b/src/assets/styles/tailwind.css index b5e6bc0..2646f47 100644 --- a/src/assets/styles/tailwind.css +++ b/src/assets/styles/tailwind.css @@ -18,6 +18,12 @@ .text-muted { color: var(--aw-color-text-muted); } + .content-backdrop { + @apply bg-white/20 dark:bg-gray-900/15 backdrop-blur-sm hover:bg-white/30 hover:backdrop-blur-md dark:hover:backdrop-blur-md transition-all duration-300 ease-in-out; + } + .content-card { + @apply rounded-lg p-4 md:p-6 content-backdrop; + } } @layer components { diff --git a/src/components/LanguageDropdown.astro b/src/components/LanguageDropdown.astro index 432cb77..aae2dde 100644 --- a/src/components/LanguageDropdown.astro +++ b/src/components/LanguageDropdown.astro @@ -20,11 +20,11 @@ const languages = [ const currentLanguage = languages.find(lang => lang.code === currentLang) || languages[0]; --- -
+
+ +
+ + \ No newline at end of file diff --git a/src/components/ui/Background.astro b/src/components/ui/Background.astro index 1093c17..d4cb2b1 100644 --- a/src/components/ui/Background.astro +++ b/src/components/ui/Background.astro @@ -1,11 +1,302 @@ --- +import { Icon } from 'astro-icon/components'; + export interface Props { isDark?: boolean; + showIcons?: boolean; + disableParallax?: boolean; } -const { isDark = false } = Astro.props; ---- +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:chart-line', + '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', + 'tabler:rocket', + + // 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 && ( + +)} diff --git a/src/components/ui/CompactTimeline.astro b/src/components/ui/CompactTimeline.astro index a000116..bd13f4f 100644 --- a/src/components/ui/CompactTimeline.astro +++ b/src/components/ui/CompactTimeline.astro @@ -16,7 +16,7 @@ const { panel: panelClass = '', title: titleClass = '', description: descriptionClass = '', - icon: defaultIconClass = 'text-primary dark:text-slate-200 border-primary dark:border-blue-700', + icon: defaultIconClass = 'text-primary dark:text-blue-300 border-primary dark:border-blue-500 dark:shadow-blue-500/40 dark:shadow-sm', } = classes; --- @@ -26,7 +26,7 @@ const { {items.map(({ title, description, icon, classes: itemClasses = {} }) => (
-
+