Skip to content

Commit 0cfefdd

Browse files
committed
feat: include made in the EU
1 parent 9488fd0 commit 0cfefdd

4 files changed

Lines changed: 144 additions & 2 deletions

File tree

src/components/Hero.astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import Container from './ui/Container.astro';
33
import Button from './ui/Button.astro';
44
import JourneyAnimation from './interactive/JourneyAnimation';
5+
import EUBadge from './interactive/EUBadge';
56
---
67

78
<section class="relative">
@@ -18,7 +19,7 @@ import JourneyAnimation from './interactive/JourneyAnimation';
1819
<!-- Subheadline -->
1920
<p class="mt-8 max-w-2xl mx-auto text-xl/7 font-medium text-white/75 sm:text-2xl/8">
2021
Self-hosted multi-channel marketing automation with visual journeys,
21-
dynamic segmentation, and organization management.
22+
dynamic segmentation, and organization management. Proudly built in <EUBadge client:visible />
2223
</p>
2324

2425
<!-- CTA Button -->
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
"use client";
2+
3+
import { useRef } from "react";
4+
import { animate, utils } from "animejs";
5+
6+
export default function EUBadge() {
7+
const containerRef = useRef<HTMLSpanElement>(null);
8+
const flagsRef = useRef<(HTMLSpanElement | null)[]>([]);
9+
const animationsRef = useRef<ReturnType<typeof animate>[]>([]);
10+
const isAnimating = useRef(false);
11+
12+
// Create multiple flag elements for confetti effect
13+
// Positioned in a radial starburst pattern around the text with variable sizes
14+
const flags = [
15+
{ emoji: "🇳🇱", x: -40, y: -25, rotate: -20, delay: 0, scale: 1.8 }, // upper-left (large)
16+
{ emoji: "🇪🇺", x: 40, y: -25, rotate: 20, delay: 50, scale: 1.4 }, // upper-right (medium)
17+
{ emoji: "🇳🇱", x: 50, y: 5, rotate: 15, delay: 100, scale: 1.1 }, // right (small)
18+
{ emoji: "🇪🇺", x: -50, y: 5, rotate: -15, delay: 75, scale: 1.5 }, // left (medium)
19+
{ emoji: "🇳🇱", x: -30, y: 28, rotate: -25, delay: 25, scale: 1.2 }, // lower-left (small)
20+
{ emoji: "🇪🇺", x: 30, y: 28, rotate: 25, delay: 125, scale: 1.7 }, // lower-right (large)
21+
];
22+
23+
const handleMouseEnter = () => {
24+
if (isAnimating.current) return;
25+
isAnimating.current = true;
26+
27+
// Cancel any existing animations
28+
animationsRef.current.forEach((anim) => anim?.pause());
29+
animationsRef.current = [];
30+
31+
flags.forEach((flag, i) => {
32+
const el = flagsRef.current[i];
33+
if (!el) return;
34+
35+
// Reset position using Anime.js utils.set for proper transform handling
36+
utils.set(el, {
37+
opacity: 0,
38+
scale: 0,
39+
x: 0,
40+
y: 0,
41+
rotate: 0,
42+
});
43+
44+
// Animate outward like confetti using Anime.js v4 syntax
45+
const anim = animate(el, {
46+
opacity: [0, 1],
47+
scale: [0, flag.scale * 1.2, flag.scale],
48+
x: [0, flag.x],
49+
y: [0, flag.y],
50+
rotate: [0, flag.rotate + (Math.random() * 20 - 10)],
51+
duration: 500,
52+
delay: flag.delay,
53+
ease: "outBack",
54+
onComplete: () => {
55+
if (i === flags.length - 1) {
56+
isAnimating.current = false;
57+
}
58+
},
59+
});
60+
animationsRef.current.push(anim);
61+
});
62+
};
63+
64+
const handleMouseLeave = () => {
65+
// Cancel any existing animations
66+
animationsRef.current.forEach((anim) => anim?.pause());
67+
animationsRef.current = [];
68+
isAnimating.current = true;
69+
70+
flags.forEach((flag, i) => {
71+
const el = flagsRef.current[i];
72+
if (!el) return;
73+
74+
// Animate out with fade
75+
const anim = animate(el, {
76+
opacity: 0,
77+
scale: 0,
78+
y: `+=${15}`,
79+
rotate: `+=${20}`,
80+
duration: 300,
81+
delay: i * 20,
82+
ease: "inQuad",
83+
onComplete: () => {
84+
if (i === flags.length - 1) {
85+
isAnimating.current = false;
86+
}
87+
},
88+
});
89+
animationsRef.current.push(anim);
90+
});
91+
};
92+
93+
return (
94+
<span
95+
ref={containerRef}
96+
className="relative inline-flex items-center cursor-default select-none"
97+
onMouseEnter={handleMouseEnter}
98+
onMouseLeave={handleMouseLeave}
99+
style={{ overflow: "visible" }}
100+
>
101+
{/* Confetti flags container - positioned to allow flags to appear on all sides */}
102+
<span
103+
className="absolute pointer-events-none flex items-center justify-center"
104+
style={{
105+
left: "50%",
106+
top: "50%",
107+
transform: "translate(-50%, -50%)",
108+
width: "200px",
109+
height: "120px",
110+
}}
111+
>
112+
{flags.map((flag, i) => (
113+
<span
114+
key={i}
115+
ref={(el) => { flagsRef.current[i] = el; }}
116+
className="absolute text-lg"
117+
style={{
118+
opacity: 0,
119+
transform: "scale(0)",
120+
color: "initial",
121+
WebkitTextFillColor: "initial",
122+
}}
123+
>
124+
{flag.emoji}
125+
</span>
126+
))}
127+
</span>
128+
{/* "the EU" text - styled in EU blue (lightened for dark background) */}
129+
<span
130+
className="relative font-semibold"
131+
style={{ color: "#4d7acc" }}
132+
>
133+
the EU
134+
</span>
135+
</span>
136+
);
137+
}

src/components/layout/Footer.astro

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ const currentYear = new Date().getFullYear();
199199
<p class="text-sm text-gray-400">
200200
&copy; {currentYear} Lunogram. All rights reserved.
201201
</p>
202+
<span class="flex items-center gap-2 text-sm text-gray-400">
203+
<span class="text-lg">🇪🇺</span>
204+
Proudly built in the EU
205+
</span>
202206
<div class="flex items-center gap-6">
203207
<!-- GitHub -->
204208
<a

src/components/layout/Header.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const isOnAbout = pathname === "/about" || pathname === "/about/";
3333
<span class="text-lg font-semibold text-white">Lunogram</span>
3434
</a>
3535

36-
<!-- Right side: About + Blog link + GitHub icon + Waitlist (Desktop) -->
36+
<!-- Right side: About + Blog link + EU Badge + GitHub icon + Waitlist (Desktop) -->
3737
<div class="hidden lg:flex items-center gap-6">
3838
<a
3939
href="/about"

0 commit comments

Comments
 (0)