@prosophia/lab-minimal 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,229 +1,67 @@
1
- // src/components/AnimatedCard.tsx
2
- import { motion } from "framer-motion";
3
-
4
- // src/lib/animations.ts
5
- var fadeInUp = {
6
- hidden: { opacity: 0, y: 30 },
7
- visible: {
8
- opacity: 1,
9
- y: 0,
10
- transition: {
11
- duration: 0.8,
12
- ease: [0.65, 0, 0.35, 1]
13
- }
14
- }
15
- };
16
- var scaleIn = {
17
- hidden: { opacity: 0, scale: 0.9 },
18
- visible: {
19
- opacity: 1,
20
- scale: 1,
21
- transition: {
22
- duration: 0.8,
23
- ease: [0.65, 0, 0.35, 1]
24
- }
25
- }
26
- };
27
-
28
- // src/components/AnimatedCard.tsx
29
- import { jsx } from "react/jsx-runtime";
30
-
31
- // src/components/AnimatedGallery.tsx
32
- import { motion as motion2 } from "framer-motion";
33
- import Image from "next/image";
34
- import { useState, useEffect } from "react";
35
- import styles from "./PicturesPage.module.css";
36
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
37
-
38
- // src/components/AnimatedHero.tsx
39
- import { motion as motion3, useScroll, useTransform } from "framer-motion";
40
- import { useRef } from "react";
41
- import Image2 from "next/image";
42
- import Link from "next/link";
43
- import styles2 from "./HomePage.module.css";
44
- import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
45
- function AnimatedHero({ heroData, ArrowRightIcon }) {
46
- const ref = useRef(null);
47
- const { scrollY } = useScroll();
48
- const y = useTransform(scrollY, [0, 500], [0, 150]);
49
- return /* @__PURE__ */ jsx3("section", { className: styles2.heroSection, ref, children: /* @__PURE__ */ jsxs2("div", { className: styles2.heroContainer, children: [
50
- /* @__PURE__ */ jsxs2(
51
- motion3.div,
52
- {
53
- className: styles2.heroContent,
54
- initial: "hidden",
55
- animate: "visible",
56
- variants: fadeInUp,
57
- children: [
58
- /* @__PURE__ */ jsx3(
59
- motion3.span,
60
- {
61
- className: styles2.heroTagline,
62
- initial: { opacity: 0 },
63
- animate: { opacity: 1 },
64
- transition: { duration: 0.6, delay: 0.2 },
65
- children: heroData.tagline
66
- }
67
- ),
68
- /* @__PURE__ */ jsxs2(
69
- motion3.h1,
70
- {
71
- className: styles2.heroHeading,
72
- initial: { opacity: 0, y: 20 },
73
- animate: { opacity: 1, y: 0 },
74
- transition: { duration: 0.8, delay: 0.3 },
75
- children: [
76
- heroData.heading,
77
- " ",
78
- /* @__PURE__ */ jsx3("span", { className: styles2.heroHeadingAccent, children: heroData.headingAccent })
79
- ]
80
- }
81
- ),
82
- /* @__PURE__ */ jsx3(
83
- motion3.p,
84
- {
85
- className: styles2.heroDescription,
86
- initial: { opacity: 0, y: 20 },
87
- animate: { opacity: 1, y: 0 },
88
- transition: { duration: 0.8, delay: 0.4 },
89
- children: heroData.description
90
- }
91
- ),
92
- /* @__PURE__ */ jsxs2(
93
- motion3.div,
94
- {
95
- className: styles2.heroCtas,
96
- initial: { opacity: 0, y: 20 },
97
- animate: { opacity: 1, y: 0 },
98
- transition: { duration: 0.8, delay: 0.5 },
99
- children: [
100
- /* @__PURE__ */ jsxs2(Link, { href: heroData.ctaLink, className: styles2.heroPrimaryCta, children: [
101
- heroData.ctaText,
102
- /* @__PURE__ */ jsx3(ArrowRightIcon, {})
103
- ] }),
104
- /* @__PURE__ */ jsx3(Link, { href: "/publications", className: styles2.heroSecondaryCta, children: "View Publications" })
105
- ]
106
- }
107
- )
108
- ]
109
- }
110
- ),
111
- /* @__PURE__ */ jsx3(
112
- motion3.div,
113
- {
114
- className: styles2.heroImageWrapper,
115
- style: { y },
116
- initial: "hidden",
117
- animate: "visible",
118
- variants: scaleIn,
119
- transition: { duration: 0.8, delay: 0.6 },
120
- children: heroData.image ? /* @__PURE__ */ jsxs2(Fragment, { children: [
121
- /* @__PURE__ */ jsx3(
122
- Image2,
123
- {
124
- src: heroData.image,
125
- alt: "Research lab",
126
- width: 800,
127
- height: 600,
128
- className: styles2.heroImage,
129
- priority: true
130
- }
131
- ),
132
- /* @__PURE__ */ jsx3("div", { className: styles2.heroImageOverlay })
133
- ] }) : /* @__PURE__ */ jsx3("div", { className: styles2.heroImagePlaceholder, children: /* @__PURE__ */ jsxs2(
134
- "svg",
135
- {
136
- width: "120",
137
- height: "120",
138
- viewBox: "0 0 24 24",
139
- fill: "none",
140
- stroke: "currentColor",
141
- strokeWidth: "1",
142
- children: [
143
- /* @__PURE__ */ jsx3("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
144
- /* @__PURE__ */ jsx3("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
145
- /* @__PURE__ */ jsx3("path", { d: "M21 15l-5-5L5 21" })
146
- ]
147
- }
148
- ) })
149
- }
150
- )
151
- ] }) });
152
- }
153
-
154
- // src/components/AnimatedPage.tsx
155
- import { motion as motion4 } from "framer-motion";
156
- import { useState as useState2, useEffect as useEffect2 } from "react";
157
- import { jsx as jsx4 } from "react/jsx-runtime";
158
-
159
- // src/components/AnimatedSections.tsx
160
- import { motion as motion5 } from "framer-motion";
161
- import { jsx as jsx5 } from "react/jsx-runtime";
162
-
163
1
  // src/components/ClientLayout.tsx
164
- import { useEffect as useEffect5 } from "react";
2
+ import { useEffect as useEffect3 } from "react";
165
3
  import { ThemeProvider, useTheme as useTheme2 } from "next-themes";
166
4
 
167
5
  // src/components/Header.tsx
168
- import Link2 from "next/link";
169
- import { useState as useState4, useEffect as useEffect4, useCallback } from "react";
6
+ import Link from "next/link";
7
+ import { useState as useState2, useEffect as useEffect2, useCallback } from "react";
170
8
  import { usePathname } from "next/navigation";
171
- import styles4 from "./Layout.module.css";
9
+ import styles2 from "./Layout.module.css";
172
10
 
173
11
  // src/components/ThemeToggle.tsx
174
12
  import { useTheme } from "next-themes";
175
- import { useEffect as useEffect3, useState as useState3 } from "react";
176
- import { motion as motion6 } from "framer-motion";
177
- import styles3 from "./ThemeToggle.module.css";
178
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
13
+ import { useEffect, useState } from "react";
14
+ import { motion } from "framer-motion";
15
+ import styles from "./ThemeToggle.module.css";
16
+ import { jsx, jsxs } from "react/jsx-runtime";
179
17
  function ThemeToggle() {
180
18
  const { theme, setTheme, resolvedTheme } = useTheme();
181
- const [mounted, setMounted] = useState3(false);
182
- useEffect3(() => {
19
+ const [mounted, setMounted] = useState(false);
20
+ useEffect(() => {
183
21
  setMounted(true);
184
22
  }, []);
185
23
  if (!mounted) {
186
- return /* @__PURE__ */ jsx6("div", { className: styles3.togglePlaceholder });
24
+ return /* @__PURE__ */ jsx("div", { className: styles.togglePlaceholder });
187
25
  }
188
26
  const isDark = resolvedTheme === "dark";
189
27
  const toggleTheme = () => {
190
28
  setTheme(isDark ? "light" : "dark");
191
29
  };
192
- return /* @__PURE__ */ jsx6(
193
- motion6.button,
30
+ return /* @__PURE__ */ jsx(
31
+ motion.button,
194
32
  {
195
- className: styles3.toggle,
33
+ className: styles.toggle,
196
34
  onClick: toggleTheme,
197
35
  "aria-label": `Switch to ${isDark ? "light" : "dark"} mode`,
198
36
  whileTap: { scale: 0.95 },
199
- children: /* @__PURE__ */ jsxs3("span", { className: styles3.track, children: [
200
- /* @__PURE__ */ jsx6("span", { className: `${styles3.icon} ${styles3.sunIcon} ${!isDark ? styles3.iconActive : ""}`, children: /* @__PURE__ */ jsxs3("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
201
- /* @__PURE__ */ jsx6("circle", { cx: "12", cy: "12", r: "5" }),
202
- /* @__PURE__ */ jsx6("line", { x1: "12", y1: "1", x2: "12", y2: "3" }),
203
- /* @__PURE__ */ jsx6("line", { x1: "12", y1: "21", x2: "12", y2: "23" }),
204
- /* @__PURE__ */ jsx6("line", { x1: "4.22", y1: "4.22", x2: "5.64", y2: "5.64" }),
205
- /* @__PURE__ */ jsx6("line", { x1: "18.36", y1: "18.36", x2: "19.78", y2: "19.78" }),
206
- /* @__PURE__ */ jsx6("line", { x1: "1", y1: "12", x2: "3", y2: "12" }),
207
- /* @__PURE__ */ jsx6("line", { x1: "21", y1: "12", x2: "23", y2: "12" }),
208
- /* @__PURE__ */ jsx6("line", { x1: "4.22", y1: "19.78", x2: "5.64", y2: "18.36" }),
209
- /* @__PURE__ */ jsx6("line", { x1: "18.36", y1: "5.64", x2: "19.78", y2: "4.22" })
37
+ children: /* @__PURE__ */ jsxs("span", { className: styles.track, children: [
38
+ /* @__PURE__ */ jsx("span", { className: `${styles.icon} ${styles.sunIcon} ${!isDark ? styles.iconActive : ""}`, children: /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
39
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "5" }),
40
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "1", x2: "12", y2: "3" }),
41
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "21", x2: "12", y2: "23" }),
42
+ /* @__PURE__ */ jsx("line", { x1: "4.22", y1: "4.22", x2: "5.64", y2: "5.64" }),
43
+ /* @__PURE__ */ jsx("line", { x1: "18.36", y1: "18.36", x2: "19.78", y2: "19.78" }),
44
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "12", x2: "3", y2: "12" }),
45
+ /* @__PURE__ */ jsx("line", { x1: "21", y1: "12", x2: "23", y2: "12" }),
46
+ /* @__PURE__ */ jsx("line", { x1: "4.22", y1: "19.78", x2: "5.64", y2: "18.36" }),
47
+ /* @__PURE__ */ jsx("line", { x1: "18.36", y1: "5.64", x2: "19.78", y2: "4.22" })
210
48
  ] }) }),
211
- /* @__PURE__ */ jsx6(
212
- motion6.span,
49
+ /* @__PURE__ */ jsx(
50
+ motion.span,
213
51
  {
214
- className: styles3.thumb,
52
+ className: styles.thumb,
215
53
  animate: { x: isDark ? 26 : 0 },
216
54
  transition: { type: "spring", stiffness: 500, damping: 30 }
217
55
  }
218
56
  ),
219
- /* @__PURE__ */ jsx6("span", { className: `${styles3.icon} ${styles3.moonIcon} ${isDark ? styles3.iconActive : ""}`, children: /* @__PURE__ */ jsx6("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx6("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) }) })
57
+ /* @__PURE__ */ jsx("span", { className: `${styles.icon} ${styles.moonIcon} ${isDark ? styles.iconActive : ""}`, children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) }) })
220
58
  ] })
221
59
  }
222
60
  );
223
61
  }
224
62
 
225
63
  // src/components/Header.tsx
226
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
64
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
227
65
  var navLinks = [
228
66
  { href: "/research", label: "Research" },
229
67
  { href: "/publications", label: "Publications" },
@@ -232,17 +70,17 @@ var navLinks = [
232
70
  { href: "/pictures", label: "Gallery" }
233
71
  ];
234
72
  function Header({ settings }) {
235
- const [menuOpen, setMenuOpen] = useState4(false);
236
- const [scrolled, setScrolled] = useState4(false);
73
+ const [menuOpen, setMenuOpen] = useState2(false);
74
+ const [scrolled, setScrolled] = useState2(false);
237
75
  const pathname = usePathname();
238
- useEffect4(() => {
76
+ useEffect2(() => {
239
77
  const handleScroll = () => {
240
78
  setScrolled(window.scrollY > 20);
241
79
  };
242
80
  window.addEventListener("scroll", handleScroll, { passive: true });
243
81
  return () => window.removeEventListener("scroll", handleScroll);
244
82
  }, []);
245
- useEffect4(() => {
83
+ useEffect2(() => {
246
84
  if (menuOpen) {
247
85
  document.body.style.overflow = "hidden";
248
86
  } else {
@@ -252,7 +90,7 @@ function Header({ settings }) {
252
90
  document.body.style.overflow = "";
253
91
  };
254
92
  }, [menuOpen]);
255
- useEffect4(() => {
93
+ useEffect2(() => {
256
94
  setMenuOpen(false);
257
95
  }, [pathname]);
258
96
  const handleKeyDown = useCallback((e) => {
@@ -260,7 +98,7 @@ function Header({ settings }) {
260
98
  setMenuOpen(false);
261
99
  }
262
100
  }, [menuOpen]);
263
- useEffect4(() => {
101
+ useEffect2(() => {
264
102
  document.addEventListener("keydown", handleKeyDown);
265
103
  return () => document.removeEventListener("keydown", handleKeyDown);
266
104
  }, [handleKeyDown]);
@@ -268,9 +106,9 @@ function Header({ settings }) {
268
106
  if (href === "/") return pathname === "/";
269
107
  return pathname.startsWith(href);
270
108
  };
271
- return /* @__PURE__ */ jsx7("header", { className: `${styles4.header} ${scrolled ? styles4.headerScrolled : ""}`, children: /* @__PURE__ */ jsxs4("div", { className: styles4.navContainer, children: [
272
- /* @__PURE__ */ jsxs4(Link2, { href: "/", className: styles4.navLogo, "aria-label": "Go to homepage", children: [
273
- /* @__PURE__ */ jsxs4(
109
+ return /* @__PURE__ */ jsx2("header", { className: `${styles2.header} ${scrolled ? styles2.headerScrolled : ""}`, children: /* @__PURE__ */ jsxs2("div", { className: styles2.navContainer, children: [
110
+ /* @__PURE__ */ jsxs2(Link, { href: "/", className: styles2.navLogo, "aria-label": "Go to homepage", children: [
111
+ /* @__PURE__ */ jsxs2(
274
112
  "svg",
275
113
  {
276
114
  width: "32",
@@ -280,7 +118,7 @@ function Header({ settings }) {
280
118
  xmlns: "http://www.w3.org/2000/svg",
281
119
  "aria-hidden": "true",
282
120
  children: [
283
- /* @__PURE__ */ jsx7(
121
+ /* @__PURE__ */ jsx2(
284
122
  "path",
285
123
  {
286
124
  d: "M12 2L2 7L12 12L22 7L12 2Z",
@@ -290,7 +128,7 @@ function Header({ settings }) {
290
128
  strokeLinejoin: "round"
291
129
  }
292
130
  ),
293
- /* @__PURE__ */ jsx7(
131
+ /* @__PURE__ */ jsx2(
294
132
  "path",
295
133
  {
296
134
  d: "M2 17L12 22L22 17",
@@ -300,7 +138,7 @@ function Header({ settings }) {
300
138
  strokeLinejoin: "round"
301
139
  }
302
140
  ),
303
- /* @__PURE__ */ jsx7(
141
+ /* @__PURE__ */ jsx2(
304
142
  "path",
305
143
  {
306
144
  d: "M2 12L12 17L22 12",
@@ -313,79 +151,79 @@ function Header({ settings }) {
313
151
  ]
314
152
  }
315
153
  ),
316
- /* @__PURE__ */ jsxs4("span", { children: [
154
+ /* @__PURE__ */ jsxs2("span", { children: [
317
155
  settings.labName || "Research",
318
- settings.labNameAccent && /* @__PURE__ */ jsxs4("span", { className: styles4.navLogoAccent, children: [
156
+ settings.labNameAccent && /* @__PURE__ */ jsxs2("span", { className: styles2.navLogoAccent, children: [
319
157
  " ",
320
158
  settings.labNameAccent
321
159
  ] })
322
160
  ] })
323
161
  ] }),
324
- /* @__PURE__ */ jsx7("nav", { className: styles4.desktopNav, "aria-label": "Main navigation", children: navLinks.map((link) => /* @__PURE__ */ jsx7(
325
- Link2,
162
+ /* @__PURE__ */ jsx2("nav", { className: styles2.desktopNav, "aria-label": "Main navigation", children: navLinks.map((link) => /* @__PURE__ */ jsx2(
163
+ Link,
326
164
  {
327
165
  href: link.href,
328
- className: `${styles4.navLink} ${isActive(link.href) ? styles4.navLinkActive : ""}`,
166
+ className: `${styles2.navLink} ${isActive(link.href) ? styles2.navLinkActive : ""}`,
329
167
  children: link.label
330
168
  },
331
169
  link.href
332
170
  )) }),
333
- /* @__PURE__ */ jsxs4("div", { className: styles4.navActions, children: [
334
- /* @__PURE__ */ jsx7(ThemeToggle, {}),
335
- /* @__PURE__ */ jsx7(Link2, { href: "/contact", className: styles4.navCta, children: "Contact Us" })
171
+ /* @__PURE__ */ jsxs2("div", { className: styles2.navActions, children: [
172
+ /* @__PURE__ */ jsx2(ThemeToggle, {}),
173
+ /* @__PURE__ */ jsx2(Link, { href: "/contact", className: styles2.navCta, children: "Contact Us" })
336
174
  ] }),
337
- /* @__PURE__ */ jsx7(
175
+ /* @__PURE__ */ jsx2(
338
176
  "button",
339
177
  {
340
- className: styles4.menuButton,
178
+ className: styles2.menuButton,
341
179
  onClick: () => setMenuOpen(!menuOpen),
342
180
  "aria-label": menuOpen ? "Close menu" : "Open menu",
343
181
  "aria-expanded": menuOpen,
344
182
  "aria-controls": "mobile-menu",
345
- children: /* @__PURE__ */ jsxs4("span", { className: styles4.menuButtonLines, children: [
346
- /* @__PURE__ */ jsx7("span", { className: `${styles4.menuLine} ${menuOpen ? styles4.menuLineOpen1 : ""}` }),
347
- /* @__PURE__ */ jsx7("span", { className: `${styles4.menuLine} ${menuOpen ? styles4.menuLineOpen2 : ""}` }),
348
- /* @__PURE__ */ jsx7("span", { className: `${styles4.menuLine} ${menuOpen ? styles4.menuLineOpen3 : ""}` })
183
+ children: /* @__PURE__ */ jsxs2("span", { className: styles2.menuButtonLines, children: [
184
+ /* @__PURE__ */ jsx2("span", { className: `${styles2.menuLine} ${menuOpen ? styles2.menuLineOpen1 : ""}` }),
185
+ /* @__PURE__ */ jsx2("span", { className: `${styles2.menuLine} ${menuOpen ? styles2.menuLineOpen2 : ""}` }),
186
+ /* @__PURE__ */ jsx2("span", { className: `${styles2.menuLine} ${menuOpen ? styles2.menuLineOpen3 : ""}` })
349
187
  ] })
350
188
  }
351
189
  ),
352
- /* @__PURE__ */ jsxs4(
190
+ /* @__PURE__ */ jsxs2(
353
191
  "div",
354
192
  {
355
193
  id: "mobile-menu",
356
- className: `${styles4.mobileMenu} ${menuOpen ? styles4.mobileMenuOpen : ""}`,
194
+ className: `${styles2.mobileMenu} ${menuOpen ? styles2.mobileMenuOpen : ""}`,
357
195
  "aria-hidden": !menuOpen,
358
196
  children: [
359
- /* @__PURE__ */ jsx7(
197
+ /* @__PURE__ */ jsx2(
360
198
  "div",
361
199
  {
362
- className: styles4.mobileMenuOverlay,
200
+ className: styles2.mobileMenuOverlay,
363
201
  onClick: () => setMenuOpen(false),
364
202
  "aria-hidden": "true"
365
203
  }
366
204
  ),
367
- /* @__PURE__ */ jsxs4(
205
+ /* @__PURE__ */ jsxs2(
368
206
  "nav",
369
207
  {
370
- className: styles4.mobileMenuContent,
208
+ className: styles2.mobileMenuContent,
371
209
  "aria-label": "Mobile navigation",
372
210
  children: [
373
- navLinks.map((link, index) => /* @__PURE__ */ jsx7(
374
- Link2,
211
+ navLinks.map((link, index) => /* @__PURE__ */ jsx2(
212
+ Link,
375
213
  {
376
214
  href: link.href,
377
- className: `${styles4.mobileNavLink} ${isActive(link.href) ? styles4.mobileNavLinkActive : ""}`,
215
+ className: `${styles2.mobileNavLink} ${isActive(link.href) ? styles2.mobileNavLinkActive : ""}`,
378
216
  style: { animationDelay: `${index * 50}ms` },
379
217
  tabIndex: menuOpen ? 0 : -1,
380
218
  children: link.label
381
219
  },
382
220
  link.href
383
221
  )),
384
- /* @__PURE__ */ jsx7(
385
- Link2,
222
+ /* @__PURE__ */ jsx2(
223
+ Link,
386
224
  {
387
225
  href: "/contact",
388
- className: styles4.mobileNavCta,
226
+ className: styles2.mobileNavCta,
389
227
  style: { animationDelay: `${navLinks.length * 50}ms` },
390
228
  tabIndex: menuOpen ? 0 : -1,
391
229
  children: "Contact Us"
@@ -401,8 +239,8 @@ function Header({ settings }) {
401
239
  }
402
240
 
403
241
  // src/components/Footer.tsx
404
- import Link3 from "next/link";
405
- import styles5 from "./Footer.module.css";
242
+ import Link2 from "next/link";
243
+ import styles3 from "./Footer.module.css";
406
244
 
407
245
  // src/lib/utils.ts
408
246
  function isValidExternalUrl(url) {
@@ -414,64 +252,104 @@ function isValidExternalUrl(url) {
414
252
  return false;
415
253
  }
416
254
  }
255
+ function isValidGoogleMapsEmbedUrl(url) {
256
+ if (!url || typeof url !== "string") return false;
257
+ try {
258
+ const parsed = new URL(url);
259
+ const allowedHosts = [
260
+ "www.google.com",
261
+ "google.com",
262
+ "maps.google.com"
263
+ ];
264
+ return parsed.protocol === "https:" && allowedHosts.includes(parsed.hostname) && parsed.pathname.startsWith("/maps/embed");
265
+ } catch {
266
+ return false;
267
+ }
268
+ }
269
+ function sanitizeUrl(url) {
270
+ if (isValidExternalUrl(url)) {
271
+ return url;
272
+ }
273
+ return void 0;
274
+ }
275
+ function isValidEmail(email) {
276
+ if (!email || typeof email !== "string") return false;
277
+ const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
278
+ return emailPattern.test(email) && email.length <= 254;
279
+ }
280
+ function escapeHtml(text) {
281
+ const htmlEntities = {
282
+ "&": "&amp;",
283
+ "<": "&lt;",
284
+ ">": "&gt;",
285
+ '"': "&quot;",
286
+ "'": "&#39;"
287
+ };
288
+ return text.replace(/[&<>"']/g, (char) => htmlEntities[char]);
289
+ }
290
+ function isValidSlug(slug) {
291
+ if (!slug || typeof slug !== "string") return false;
292
+ const slugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
293
+ return slugPattern.test(slug) && slug.length <= 200;
294
+ }
417
295
 
418
296
  // src/components/Footer.tsx
419
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
420
- var SocialIcon = ({ href, children }) => /* @__PURE__ */ jsx8("a", { href, target: "_blank", rel: "noopener noreferrer", className: styles5.socialIcon, children });
297
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
298
+ var SocialIcon = ({ href, children }) => /* @__PURE__ */ jsx3("a", { href, target: "_blank", rel: "noopener noreferrer", className: styles3.socialIcon, children });
421
299
  function Footer({ settings }) {
422
300
  const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
423
301
  const showPrivacy = settings?.showPrivacyPolicy !== false;
424
302
  const showTerms = settings?.showTerms !== false;
425
303
  const hasLegalLinks = showPrivacy || showTerms;
426
- return /* @__PURE__ */ jsx8("footer", { className: styles5.footerWrapper, children: /* @__PURE__ */ jsxs5("div", { className: styles5.footerContainer, children: [
427
- /* @__PURE__ */ jsxs5("div", { className: styles5.mainFooter, children: [
428
- /* @__PURE__ */ jsxs5("div", { className: styles5.footerAbout, children: [
429
- /* @__PURE__ */ jsxs5(Link3, { href: "/", className: styles5.footerLogo, children: [
304
+ return /* @__PURE__ */ jsx3("footer", { className: styles3.footerWrapper, children: /* @__PURE__ */ jsxs3("div", { className: styles3.footerContainer, children: [
305
+ /* @__PURE__ */ jsxs3("div", { className: styles3.mainFooter, children: [
306
+ /* @__PURE__ */ jsxs3("div", { className: styles3.footerAbout, children: [
307
+ /* @__PURE__ */ jsxs3(Link2, { href: "/", className: styles3.footerLogo, children: [
430
308
  settings?.labName || "Cavendish",
431
309
  " ",
432
- /* @__PURE__ */ jsx8("span", { className: styles5.logoAccent, children: settings?.labNameAccent || "Lab" })
310
+ /* @__PURE__ */ jsx3("span", { className: styles3.logoAccent, children: settings?.labNameAccent || "Lab" })
433
311
  ] }),
434
- /* @__PURE__ */ jsx8("p", { className: styles5.footerDescription, children: settings?.labNameDescription || "Advancing the frontiers of physics and our understanding of the universe." }),
435
- /* @__PURE__ */ jsxs5("div", { className: styles5.socials, children: [
436
- /* @__PURE__ */ jsx8(SocialIcon, { href: "#", children: /* @__PURE__ */ jsx8("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx8("path", { d: "M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" }) }) }),
437
- /* @__PURE__ */ jsx8(SocialIcon, { href: "#", children: /* @__PURE__ */ jsx8("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx8("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24h-6.617l-5.21-6.817-6.044 6.817h-3.308l7.73-8.835-7.73-10.668h6.78l4.522 6.312 5.59-6.312z" }) }) })
312
+ /* @__PURE__ */ jsx3("p", { className: styles3.footerDescription, children: settings?.labNameDescription || "Advancing the frontiers of physics and our understanding of the universe." }),
313
+ /* @__PURE__ */ jsxs3("div", { className: styles3.socials, children: [
314
+ /* @__PURE__ */ jsx3(SocialIcon, { href: "#", children: /* @__PURE__ */ jsx3("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx3("path", { d: "M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" }) }) }),
315
+ /* @__PURE__ */ jsx3(SocialIcon, { href: "#", children: /* @__PURE__ */ jsx3("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx3("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24h-6.617l-5.21-6.817-6.044 6.817h-3.308l7.73-8.835-7.73-10.668h6.78l4.522 6.312 5.59-6.312z" }) }) })
438
316
  ] })
439
317
  ] }),
440
- /* @__PURE__ */ jsxs5("div", { className: styles5.footerLinksGrid, children: [
441
- /* @__PURE__ */ jsxs5("div", { className: styles5.footerColumn, children: [
442
- /* @__PURE__ */ jsx8("h4", { children: "Quick Links" }),
443
- /* @__PURE__ */ jsx8(Link3, { href: "/research", children: "Research" }),
444
- /* @__PURE__ */ jsx8(Link3, { href: "/publications", children: "Publications" }),
445
- /* @__PURE__ */ jsx8(Link3, { href: "/pictures", children: "Gallery" })
318
+ /* @__PURE__ */ jsxs3("div", { className: styles3.footerLinksGrid, children: [
319
+ /* @__PURE__ */ jsxs3("div", { className: styles3.footerColumn, children: [
320
+ /* @__PURE__ */ jsx3("h4", { children: "Quick Links" }),
321
+ /* @__PURE__ */ jsx3(Link2, { href: "/research", children: "Research" }),
322
+ /* @__PURE__ */ jsx3(Link2, { href: "/publications", children: "Publications" }),
323
+ /* @__PURE__ */ jsx3(Link2, { href: "/pictures", children: "Gallery" })
446
324
  ] }),
447
- /* @__PURE__ */ jsxs5("div", { className: styles5.footerColumn, children: [
448
- /* @__PURE__ */ jsx8("h4", { children: "About" }),
449
- /* @__PURE__ */ jsx8(Link3, { href: "/news", children: "News" }),
450
- /* @__PURE__ */ jsx8(Link3, { href: "/people", children: "Our Team" }),
451
- /* @__PURE__ */ jsx8(Link3, { href: "/contact", children: "Contact" })
325
+ /* @__PURE__ */ jsxs3("div", { className: styles3.footerColumn, children: [
326
+ /* @__PURE__ */ jsx3("h4", { children: "About" }),
327
+ /* @__PURE__ */ jsx3(Link2, { href: "/news", children: "News" }),
328
+ /* @__PURE__ */ jsx3(Link2, { href: "/people", children: "Our Team" }),
329
+ /* @__PURE__ */ jsx3(Link2, { href: "/contact", children: "Contact" })
452
330
  ] }),
453
- /* @__PURE__ */ jsxs5("div", { className: styles5.footerColumn, children: [
454
- /* @__PURE__ */ jsx8("h4", { children: "Resources" }),
455
- /* @__PURE__ */ jsx8(Link3, { href: "https://www.cam.ac.uk/", children: "University" }),
456
- /* @__PURE__ */ jsx8(Link3, { href: "#", children: "Careers" })
331
+ /* @__PURE__ */ jsxs3("div", { className: styles3.footerColumn, children: [
332
+ /* @__PURE__ */ jsx3("h4", { children: "Resources" }),
333
+ /* @__PURE__ */ jsx3(Link2, { href: "https://www.cam.ac.uk/", children: "University" }),
334
+ /* @__PURE__ */ jsx3(Link2, { href: "#", children: "Careers" })
457
335
  ] })
458
336
  ] })
459
337
  ] }),
460
- /* @__PURE__ */ jsxs5("div", { className: styles5.footerBottomBar, children: [
461
- /* @__PURE__ */ jsx8("p", { children: settings?.footerText || `\xA9 ${currentYear} The Research Group. All Rights Reserved.` }),
462
- hasLegalLinks && /* @__PURE__ */ jsxs5("div", { className: styles5.legalLinks, children: [
463
- showPrivacy && (settings?.privacyPolicyUrl && isValidExternalUrl(settings.privacyPolicyUrl) ? /* @__PURE__ */ jsx8("a", { href: settings.privacyPolicyUrl, target: "_blank", rel: "noopener noreferrer", children: "Privacy Policy" }) : /* @__PURE__ */ jsx8(Link3, { href: "/privacy", children: "Privacy Policy" })),
464
- showTerms && (settings?.termsUrl && isValidExternalUrl(settings.termsUrl) ? /* @__PURE__ */ jsx8("a", { href: settings.termsUrl, target: "_blank", rel: "noopener noreferrer", children: "Terms & Conditions" }) : /* @__PURE__ */ jsx8(Link3, { href: "/terms", children: "Terms & Conditions" }))
338
+ /* @__PURE__ */ jsxs3("div", { className: styles3.footerBottomBar, children: [
339
+ /* @__PURE__ */ jsx3("p", { children: settings?.footerText || `\xA9 ${currentYear} The Research Group. All Rights Reserved.` }),
340
+ hasLegalLinks && /* @__PURE__ */ jsxs3("div", { className: styles3.legalLinks, children: [
341
+ showPrivacy && (settings?.privacyPolicyUrl && isValidExternalUrl(settings.privacyPolicyUrl) ? /* @__PURE__ */ jsx3("a", { href: settings.privacyPolicyUrl, target: "_blank", rel: "noopener noreferrer", children: "Privacy Policy" }) : /* @__PURE__ */ jsx3(Link2, { href: "/privacy", children: "Privacy Policy" })),
342
+ showTerms && (settings?.termsUrl && isValidExternalUrl(settings.termsUrl) ? /* @__PURE__ */ jsx3("a", { href: settings.termsUrl, target: "_blank", rel: "noopener noreferrer", children: "Terms & Conditions" }) : /* @__PURE__ */ jsx3(Link2, { href: "/terms", children: "Terms & Conditions" }))
465
343
  ] })
466
344
  ] })
467
345
  ] }) });
468
346
  }
469
347
 
470
348
  // src/components/ClientLayout.tsx
471
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
349
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
472
350
  function ThemeBodySync() {
473
351
  const { resolvedTheme } = useTheme2();
474
- useEffect5(() => {
352
+ useEffect3(() => {
475
353
  if (resolvedTheme === "dark") {
476
354
  document.body.classList.add("dark-mode");
477
355
  document.body.classList.remove("light-mode");
@@ -483,32 +361,853 @@ function ThemeBodySync() {
483
361
  return null;
484
362
  }
485
363
  function ClientLayout({ children, settings }) {
486
- return /* @__PURE__ */ jsxs6(ThemeProvider, { attribute: "class", defaultTheme: "light", enableSystem: false, children: [
487
- /* @__PURE__ */ jsx9(ThemeBodySync, {}),
488
- /* @__PURE__ */ jsxs6("div", { className: "pageWrapper", children: [
489
- /* @__PURE__ */ jsx9(Header, { settings }),
490
- /* @__PURE__ */ jsx9("main", { children }),
491
- /* @__PURE__ */ jsx9(Footer, { settings })
364
+ return /* @__PURE__ */ jsxs4(ThemeProvider, { attribute: "class", defaultTheme: "light", enableSystem: false, children: [
365
+ /* @__PURE__ */ jsx4(ThemeBodySync, {}),
366
+ /* @__PURE__ */ jsxs4("div", { className: "pageWrapper", children: [
367
+ /* @__PURE__ */ jsx4(Header, { settings }),
368
+ /* @__PURE__ */ jsx4("main", { children }),
369
+ /* @__PURE__ */ jsx4(Footer, { settings })
492
370
  ] })
493
371
  ] });
494
372
  }
495
373
 
496
374
  // src/components/ContactCTA.tsx
497
- import Link4 from "next/link";
498
- import styles6 from "./ContactCTA.module.css";
499
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
375
+ import Link3 from "next/link";
376
+ import styles4 from "./ContactCTA.module.css";
377
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
500
378
  function ContactCTA() {
501
- return /* @__PURE__ */ jsx10("section", { className: styles6.ctaContainer, children: /* @__PURE__ */ jsxs7("div", { className: styles6.ctaContent, children: [
502
- /* @__PURE__ */ jsx10("h2", { className: styles6.ctaHeading, children: "Interested in Our Research?" }),
503
- /* @__PURE__ */ jsx10("p", { className: styles6.ctaText, children: "Follow our work, explore our publications, or get in touch to discuss potential collaborations." }),
504
- /* @__PURE__ */ jsx10(Link4, { href: "/contact", className: styles6.ctaButton, children: "Contact Us" })
379
+ return /* @__PURE__ */ jsx5("section", { className: styles4.ctaContainer, children: /* @__PURE__ */ jsxs5("div", { className: styles4.ctaContent, children: [
380
+ /* @__PURE__ */ jsx5("h2", { className: styles4.ctaHeading, children: "Interested in Our Research?" }),
381
+ /* @__PURE__ */ jsx5("p", { className: styles4.ctaText, children: "Follow our work, explore our publications, or get in touch to discuss potential collaborations." }),
382
+ /* @__PURE__ */ jsx5(Link3, { href: "/contact", className: styles4.ctaButton, children: "Contact Us" })
383
+ ] }) });
384
+ }
385
+
386
+ // src/components/AnimatedHero.tsx
387
+ import { motion as motion2, useScroll, useTransform } from "framer-motion";
388
+ import { useRef } from "react";
389
+ import Image from "next/image";
390
+ import Link4 from "next/link";
391
+ import styles5 from "./HomePage.module.css";
392
+
393
+ // src/lib/animations.ts
394
+ var fadeIn = {
395
+ hidden: { opacity: 0 },
396
+ visible: {
397
+ opacity: 1,
398
+ transition: {
399
+ duration: 0.6,
400
+ ease: [0.65, 0, 0.35, 1]
401
+ }
402
+ }
403
+ };
404
+ var fadeInUp = {
405
+ hidden: { opacity: 0, y: 30 },
406
+ visible: {
407
+ opacity: 1,
408
+ y: 0,
409
+ transition: {
410
+ duration: 0.8,
411
+ ease: [0.65, 0, 0.35, 1]
412
+ }
413
+ }
414
+ };
415
+ var fadeInUpShort = {
416
+ hidden: { opacity: 0, y: 20 },
417
+ visible: {
418
+ opacity: 1,
419
+ y: 0,
420
+ transition: {
421
+ duration: 0.6,
422
+ ease: [0.4, 0, 0.2, 1]
423
+ }
424
+ }
425
+ };
426
+ var scaleIn = {
427
+ hidden: { opacity: 0, scale: 0.9 },
428
+ visible: {
429
+ opacity: 1,
430
+ scale: 1,
431
+ transition: {
432
+ duration: 0.8,
433
+ ease: [0.65, 0, 0.35, 1]
434
+ }
435
+ }
436
+ };
437
+ var slideInRight = {
438
+ hidden: { opacity: 0, x: 20 },
439
+ visible: {
440
+ opacity: 1,
441
+ x: 0,
442
+ transition: {
443
+ duration: 0.6,
444
+ ease: [0.4, 0, 0.2, 1]
445
+ }
446
+ }
447
+ };
448
+ var slideInLeft = {
449
+ hidden: { opacity: 0, x: -20 },
450
+ visible: {
451
+ opacity: 1,
452
+ x: 0,
453
+ transition: {
454
+ duration: 0.6,
455
+ ease: [0.4, 0, 0.2, 1]
456
+ }
457
+ }
458
+ };
459
+ var staggerContainer = {
460
+ hidden: { opacity: 0 },
461
+ visible: {
462
+ opacity: 1,
463
+ transition: {
464
+ staggerChildren: 0.1,
465
+ delayChildren: 0.2
466
+ }
467
+ }
468
+ };
469
+ var staggerItem = {
470
+ hidden: { opacity: 0, y: 20 },
471
+ visible: {
472
+ opacity: 1,
473
+ y: 0,
474
+ transition: {
475
+ duration: 0.5,
476
+ ease: [0.4, 0, 0.2, 1]
477
+ }
478
+ }
479
+ };
480
+ var cardHover = {
481
+ hover: {
482
+ y: -8,
483
+ transition: {
484
+ duration: 0.3,
485
+ ease: [0.4, 0, 0.2, 1]
486
+ }
487
+ }
488
+ };
489
+ var imageZoom = {
490
+ hover: {
491
+ scale: 1.08,
492
+ transition: {
493
+ duration: 0.5,
494
+ ease: [0.65, 0, 0.35, 1]
495
+ }
496
+ }
497
+ };
498
+ var pageTransition = {
499
+ hidden: { opacity: 0, y: 20 },
500
+ visible: {
501
+ opacity: 1,
502
+ y: 0,
503
+ transition: {
504
+ duration: 0.6,
505
+ ease: [0.4, 0, 0.2, 1]
506
+ }
507
+ },
508
+ exit: {
509
+ opacity: 0,
510
+ y: -20,
511
+ transition: {
512
+ duration: 0.4,
513
+ ease: [0.4, 0, 0.2, 1]
514
+ }
515
+ }
516
+ };
517
+ var viewportSettings = {
518
+ once: true,
519
+ amount: 0.3,
520
+ margin: "0px 0px -100px 0px"
521
+ };
522
+ var scrollReveal = {
523
+ hidden: { opacity: 0, y: 50 },
524
+ visible: {
525
+ opacity: 1,
526
+ y: 0,
527
+ transition: {
528
+ duration: 0.8,
529
+ ease: [0.65, 0, 0.35, 1]
530
+ }
531
+ }
532
+ };
533
+ var reducedMotion = {
534
+ hidden: { opacity: 0 },
535
+ visible: {
536
+ opacity: 1,
537
+ transition: {
538
+ duration: 0.01
539
+ }
540
+ }
541
+ };
542
+
543
+ // src/components/AnimatedHero.tsx
544
+ import { Fragment, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
545
+ function AnimatedHero({ heroData, ArrowRightIcon }) {
546
+ const ref = useRef(null);
547
+ const { scrollY } = useScroll();
548
+ const y = useTransform(scrollY, [0, 500], [0, 150]);
549
+ return /* @__PURE__ */ jsx6("section", { className: styles5.heroSection, ref, children: /* @__PURE__ */ jsxs6("div", { className: styles5.heroContainer, children: [
550
+ /* @__PURE__ */ jsxs6(
551
+ motion2.div,
552
+ {
553
+ className: styles5.heroContent,
554
+ initial: "hidden",
555
+ animate: "visible",
556
+ variants: fadeInUp,
557
+ children: [
558
+ /* @__PURE__ */ jsx6(
559
+ motion2.span,
560
+ {
561
+ className: styles5.heroTagline,
562
+ initial: { opacity: 0 },
563
+ animate: { opacity: 1 },
564
+ transition: { duration: 0.6, delay: 0.2 },
565
+ children: heroData.tagline
566
+ }
567
+ ),
568
+ /* @__PURE__ */ jsxs6(
569
+ motion2.h1,
570
+ {
571
+ className: styles5.heroHeading,
572
+ initial: { opacity: 0, y: 20 },
573
+ animate: { opacity: 1, y: 0 },
574
+ transition: { duration: 0.8, delay: 0.3 },
575
+ children: [
576
+ heroData.heading,
577
+ " ",
578
+ /* @__PURE__ */ jsx6("span", { className: styles5.heroHeadingAccent, children: heroData.headingAccent })
579
+ ]
580
+ }
581
+ ),
582
+ /* @__PURE__ */ jsx6(
583
+ motion2.p,
584
+ {
585
+ className: styles5.heroDescription,
586
+ initial: { opacity: 0, y: 20 },
587
+ animate: { opacity: 1, y: 0 },
588
+ transition: { duration: 0.8, delay: 0.4 },
589
+ children: heroData.description
590
+ }
591
+ ),
592
+ /* @__PURE__ */ jsxs6(
593
+ motion2.div,
594
+ {
595
+ className: styles5.heroCtas,
596
+ initial: { opacity: 0, y: 20 },
597
+ animate: { opacity: 1, y: 0 },
598
+ transition: { duration: 0.8, delay: 0.5 },
599
+ children: [
600
+ /* @__PURE__ */ jsxs6(Link4, { href: heroData.ctaLink, className: styles5.heroPrimaryCta, children: [
601
+ heroData.ctaText,
602
+ /* @__PURE__ */ jsx6(ArrowRightIcon, {})
603
+ ] }),
604
+ /* @__PURE__ */ jsx6(Link4, { href: "/publications", className: styles5.heroSecondaryCta, children: "View Publications" })
605
+ ]
606
+ }
607
+ )
608
+ ]
609
+ }
610
+ ),
611
+ /* @__PURE__ */ jsx6(
612
+ motion2.div,
613
+ {
614
+ className: styles5.heroImageWrapper,
615
+ style: { y },
616
+ initial: "hidden",
617
+ animate: "visible",
618
+ variants: scaleIn,
619
+ transition: { duration: 0.8, delay: 0.6 },
620
+ children: heroData.image ? /* @__PURE__ */ jsxs6(Fragment, { children: [
621
+ /* @__PURE__ */ jsx6(
622
+ Image,
623
+ {
624
+ src: heroData.image,
625
+ alt: "Research lab",
626
+ width: 800,
627
+ height: 600,
628
+ className: styles5.heroImage,
629
+ priority: true
630
+ }
631
+ ),
632
+ /* @__PURE__ */ jsx6("div", { className: styles5.heroImageOverlay })
633
+ ] }) : /* @__PURE__ */ jsx6("div", { className: styles5.heroImagePlaceholder, children: /* @__PURE__ */ jsxs6(
634
+ "svg",
635
+ {
636
+ width: "120",
637
+ height: "120",
638
+ viewBox: "0 0 24 24",
639
+ fill: "none",
640
+ stroke: "currentColor",
641
+ strokeWidth: "1",
642
+ children: [
643
+ /* @__PURE__ */ jsx6("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
644
+ /* @__PURE__ */ jsx6("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
645
+ /* @__PURE__ */ jsx6("path", { d: "M21 15l-5-5L5 21" })
646
+ ]
647
+ }
648
+ ) })
649
+ }
650
+ )
505
651
  ] }) });
506
652
  }
653
+
654
+ // src/components/HomePage.tsx
655
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
656
+ function HomePage({
657
+ children,
658
+ settings = null,
659
+ header,
660
+ footer
661
+ }) {
662
+ return /* @__PURE__ */ jsxs7(Fragment2, { children: [
663
+ header ?? /* @__PURE__ */ jsx7(Header, { settings: settings || {} }),
664
+ /* @__PURE__ */ jsx7("main", { children }),
665
+ footer ?? /* @__PURE__ */ jsx7(Footer, { settings: settings || {} })
666
+ ] });
667
+ }
668
+
669
+ // src/components/AnimatedCard.tsx
670
+ import { motion as motion3 } from "framer-motion";
671
+ import { jsx as jsx8 } from "react/jsx-runtime";
672
+ function AnimatedCard({ children, className, delay = 0 }) {
673
+ return /* @__PURE__ */ jsx8(
674
+ motion3.div,
675
+ {
676
+ className,
677
+ initial: "hidden",
678
+ whileInView: "visible",
679
+ viewport: viewportSettings,
680
+ variants: {
681
+ hidden: { opacity: 0, y: 30 },
682
+ visible: {
683
+ opacity: 1,
684
+ y: 0,
685
+ transition: {
686
+ duration: 0.6,
687
+ delay,
688
+ ease: [0.4, 0, 0.2, 1]
689
+ }
690
+ }
691
+ },
692
+ whileHover: "hover",
693
+ children
694
+ }
695
+ );
696
+ }
697
+ function AnimatedImage({ children, className }) {
698
+ return /* @__PURE__ */ jsx8(motion3.div, { className, variants: imageZoom, children });
699
+ }
700
+ function AnimatedSection({ children, className }) {
701
+ return /* @__PURE__ */ jsx8(
702
+ motion3.section,
703
+ {
704
+ className,
705
+ initial: "hidden",
706
+ whileInView: "visible",
707
+ viewport: viewportSettings,
708
+ variants: fadeInUpShort,
709
+ children
710
+ }
711
+ );
712
+ }
713
+
714
+ // src/components/AnimatedGallery.tsx
715
+ import { motion as motion4 } from "framer-motion";
716
+ import Image2 from "next/image";
717
+ import { useState as useState3, useEffect as useEffect4 } from "react";
718
+ import styles6 from "./PicturesPage.module.css";
719
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
720
+ function useMounted() {
721
+ const [mounted, setMounted] = useState3(false);
722
+ useEffect4(() => {
723
+ setMounted(true);
724
+ }, []);
725
+ return mounted;
726
+ }
727
+ function AnimatedGalleryHeader({ children, className }) {
728
+ const mounted = useMounted();
729
+ if (!mounted) {
730
+ return /* @__PURE__ */ jsx9("header", { className, children });
731
+ }
732
+ return /* @__PURE__ */ jsx9(
733
+ motion4.header,
734
+ {
735
+ className,
736
+ initial: { opacity: 0, y: 30 },
737
+ animate: { opacity: 1, y: 0 },
738
+ transition: { duration: 0.8, ease: [0.4, 0, 0.2, 1] },
739
+ children
740
+ }
741
+ );
742
+ }
743
+ function AnimatedGalleryGrid({ images }) {
744
+ const mounted = useMounted();
745
+ if (!mounted) {
746
+ return /* @__PURE__ */ jsx9("div", { className: styles6.photosGrid, children: images.map((pic) => /* @__PURE__ */ jsxs8("div", { className: styles6.photoCard, children: [
747
+ /* @__PURE__ */ jsx9("div", { className: styles6.photoImageWrapper, children: /* @__PURE__ */ jsx9(
748
+ Image2,
749
+ {
750
+ src: pic.imageUrl,
751
+ alt: pic.altText,
752
+ width: pic.width,
753
+ height: pic.height,
754
+ sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw",
755
+ className: styles6.photoImage
756
+ }
757
+ ) }),
758
+ pic.caption && /* @__PURE__ */ jsx9("p", { className: styles6.photoCaption, children: pic.caption })
759
+ ] }, pic._id)) });
760
+ }
761
+ return /* @__PURE__ */ jsx9(
762
+ motion4.div,
763
+ {
764
+ className: styles6.photosGrid,
765
+ initial: "hidden",
766
+ animate: "visible",
767
+ variants: {
768
+ hidden: { opacity: 0 },
769
+ visible: {
770
+ opacity: 1,
771
+ transition: {
772
+ staggerChildren: 0.08,
773
+ delayChildren: 0.2
774
+ }
775
+ }
776
+ },
777
+ children: images.map((pic) => /* @__PURE__ */ jsxs8(
778
+ motion4.div,
779
+ {
780
+ className: styles6.photoCard,
781
+ variants: {
782
+ hidden: { opacity: 0, y: 40, scale: 0.95 },
783
+ visible: {
784
+ opacity: 1,
785
+ y: 0,
786
+ scale: 1,
787
+ transition: {
788
+ duration: 0.6,
789
+ ease: [0.4, 0, 0.2, 1]
790
+ }
791
+ }
792
+ },
793
+ whileHover: {
794
+ scale: 1.05,
795
+ transition: { duration: 0.3 }
796
+ },
797
+ children: [
798
+ /* @__PURE__ */ jsx9("div", { className: styles6.photoImageWrapper, children: /* @__PURE__ */ jsx9(
799
+ Image2,
800
+ {
801
+ src: pic.imageUrl,
802
+ alt: pic.altText,
803
+ width: pic.width,
804
+ height: pic.height,
805
+ sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw",
806
+ className: styles6.photoImage
807
+ }
808
+ ) }),
809
+ pic.caption && /* @__PURE__ */ jsx9("p", { className: styles6.photoCaption, children: pic.caption })
810
+ ]
811
+ },
812
+ pic._id
813
+ ))
814
+ }
815
+ );
816
+ }
817
+
818
+ // src/components/AnimatedPage.tsx
819
+ import { motion as motion5 } from "framer-motion";
820
+ import { useState as useState4, useEffect as useEffect5 } from "react";
821
+ import { jsx as jsx10 } from "react/jsx-runtime";
822
+ function useMounted2() {
823
+ const [mounted, setMounted] = useState4(false);
824
+ useEffect5(() => {
825
+ setMounted(true);
826
+ }, []);
827
+ return mounted;
828
+ }
829
+ function AnimatedPage({ children, className }) {
830
+ const mounted = useMounted2();
831
+ if (!mounted) {
832
+ return /* @__PURE__ */ jsx10("div", { className, children });
833
+ }
834
+ return /* @__PURE__ */ jsx10(
835
+ motion5.div,
836
+ {
837
+ className,
838
+ initial: { opacity: 0 },
839
+ animate: { opacity: 1 },
840
+ transition: { duration: 0.6, ease: [0.4, 0, 0.2, 1] },
841
+ children
842
+ }
843
+ );
844
+ }
845
+ function AnimatedHeader({ children, className }) {
846
+ const mounted = useMounted2();
847
+ if (!mounted) {
848
+ return /* @__PURE__ */ jsx10("header", { className, children });
849
+ }
850
+ return /* @__PURE__ */ jsx10(
851
+ motion5.header,
852
+ {
853
+ className,
854
+ initial: { opacity: 0, y: 15 },
855
+ animate: { opacity: 1, y: 0 },
856
+ transition: { duration: 0.5, ease: [0.4, 0, 0.2, 1] },
857
+ children
858
+ }
859
+ );
860
+ }
861
+ function AnimatedMain({ children, className }) {
862
+ const mounted = useMounted2();
863
+ if (!mounted) {
864
+ return /* @__PURE__ */ jsx10("main", { className, children });
865
+ }
866
+ return /* @__PURE__ */ jsx10(
867
+ motion5.main,
868
+ {
869
+ className,
870
+ initial: { opacity: 0, y: 10 },
871
+ animate: { opacity: 1, y: 0 },
872
+ transition: { duration: 0.5, delay: 0.1, ease: [0.4, 0, 0.2, 1] },
873
+ children
874
+ }
875
+ );
876
+ }
877
+ function StaggeredGrid({ children, className }) {
878
+ const mounted = useMounted2();
879
+ const childArray = Array.isArray(children) ? children : [children];
880
+ if (!mounted) {
881
+ return /* @__PURE__ */ jsx10("div", { className, children });
882
+ }
883
+ return /* @__PURE__ */ jsx10(
884
+ motion5.div,
885
+ {
886
+ className,
887
+ initial: "hidden",
888
+ whileInView: "visible",
889
+ viewport: { once: true, amount: 0.1 },
890
+ variants: {
891
+ hidden: { opacity: 0 },
892
+ visible: {
893
+ opacity: 1,
894
+ transition: {
895
+ staggerChildren: 0.05,
896
+ delayChildren: 0.05
897
+ }
898
+ }
899
+ },
900
+ children: childArray.map((child, index) => /* @__PURE__ */ jsx10(
901
+ motion5.div,
902
+ {
903
+ variants: {
904
+ hidden: { opacity: 0, y: 15 },
905
+ visible: {
906
+ opacity: 1,
907
+ y: 0,
908
+ transition: {
909
+ duration: 0.5,
910
+ ease: [0.4, 0, 0.2, 1]
911
+ }
912
+ }
913
+ },
914
+ children: child
915
+ },
916
+ index
917
+ ))
918
+ }
919
+ );
920
+ }
921
+ function AnimatedItem({ children, className, delay = 0, index = 0 }) {
922
+ const mounted = useMounted2();
923
+ if (!mounted) {
924
+ return /* @__PURE__ */ jsx10("div", { className, children });
925
+ }
926
+ return /* @__PURE__ */ jsx10(
927
+ motion5.div,
928
+ {
929
+ className,
930
+ initial: { opacity: 0, y: 15 },
931
+ whileInView: { opacity: 1, y: 0 },
932
+ viewport: { once: true, amount: 0.2 },
933
+ transition: {
934
+ duration: 0.5,
935
+ delay: delay || index * 0.05,
936
+ ease: [0.4, 0, 0.2, 1]
937
+ },
938
+ children
939
+ }
940
+ );
941
+ }
942
+ function ScrollRevealSection({ children, className }) {
943
+ const mounted = useMounted2();
944
+ if (!mounted) {
945
+ return /* @__PURE__ */ jsx10("section", { className, children });
946
+ }
947
+ return /* @__PURE__ */ jsx10(
948
+ motion5.section,
949
+ {
950
+ className,
951
+ initial: { opacity: 0, y: 20 },
952
+ whileInView: { opacity: 1, y: 0 },
953
+ viewport: { once: true, amount: 0.15 },
954
+ transition: { duration: 0.5, ease: [0.4, 0, 0.2, 1] },
955
+ children
956
+ }
957
+ );
958
+ }
959
+ function AnimatedHeroContent({ children, className }) {
960
+ const mounted = useMounted2();
961
+ const childArray = Array.isArray(children) ? children : [children];
962
+ if (!mounted) {
963
+ return /* @__PURE__ */ jsx10("div", { className, children });
964
+ }
965
+ return /* @__PURE__ */ jsx10(
966
+ motion5.div,
967
+ {
968
+ className,
969
+ initial: "hidden",
970
+ animate: "visible",
971
+ variants: {
972
+ hidden: { opacity: 0 },
973
+ visible: {
974
+ opacity: 1,
975
+ transition: {
976
+ staggerChildren: 0.08,
977
+ delayChildren: 0.05
978
+ }
979
+ }
980
+ },
981
+ children: childArray.map((child, index) => /* @__PURE__ */ jsx10(
982
+ motion5.div,
983
+ {
984
+ variants: {
985
+ hidden: { opacity: 0, y: 10 },
986
+ visible: {
987
+ opacity: 1,
988
+ y: 0,
989
+ transition: {
990
+ duration: 0.5,
991
+ ease: [0.4, 0, 0.2, 1]
992
+ }
993
+ }
994
+ },
995
+ children: child
996
+ },
997
+ index
998
+ ))
999
+ }
1000
+ );
1001
+ }
1002
+
1003
+ // src/components/AnimatedSections.tsx
1004
+ import { motion as motion6 } from "framer-motion";
1005
+ import { jsx as jsx11 } from "react/jsx-runtime";
1006
+ function AnimatedGrid({ children, className }) {
1007
+ const childArray = Array.isArray(children) ? children : [children];
1008
+ return /* @__PURE__ */ jsx11(
1009
+ motion6.div,
1010
+ {
1011
+ className,
1012
+ initial: "hidden",
1013
+ whileInView: "visible",
1014
+ viewport: viewportSettings,
1015
+ variants: staggerContainer,
1016
+ children: childArray.map((child, index) => /* @__PURE__ */ jsx11(motion6.div, { variants: staggerItem, children: child }, index))
1017
+ }
1018
+ );
1019
+ }
1020
+ function AnimatedStats({ children, className }) {
1021
+ const childArray = Array.isArray(children) ? children : [children];
1022
+ return /* @__PURE__ */ jsx11(
1023
+ motion6.div,
1024
+ {
1025
+ className,
1026
+ initial: "hidden",
1027
+ whileInView: "visible",
1028
+ viewport: { once: true, amount: 0.3 },
1029
+ variants: {
1030
+ hidden: { opacity: 0 },
1031
+ visible: {
1032
+ opacity: 1,
1033
+ transition: {
1034
+ staggerChildren: 0.15,
1035
+ delayChildren: 0.1
1036
+ }
1037
+ }
1038
+ },
1039
+ children: childArray.map((child, index) => /* @__PURE__ */ jsx11(
1040
+ motion6.div,
1041
+ {
1042
+ variants: {
1043
+ hidden: { opacity: 0, scale: 0.8 },
1044
+ visible: {
1045
+ opacity: 1,
1046
+ scale: 1,
1047
+ transition: {
1048
+ duration: 0.5,
1049
+ ease: [0.4, 0, 0.2, 1]
1050
+ }
1051
+ }
1052
+ },
1053
+ children: child
1054
+ },
1055
+ index
1056
+ ))
1057
+ }
1058
+ );
1059
+ }
1060
+ function AnimatedSectionHeader({ children, className }) {
1061
+ return /* @__PURE__ */ jsx11(
1062
+ motion6.header,
1063
+ {
1064
+ className,
1065
+ initial: "hidden",
1066
+ whileInView: "visible",
1067
+ viewport: viewportSettings,
1068
+ variants: fadeInUpShort,
1069
+ children
1070
+ }
1071
+ );
1072
+ }
1073
+ function AnimatedList({ children, className }) {
1074
+ const childArray = Array.isArray(children) ? children : [children];
1075
+ return /* @__PURE__ */ jsx11(
1076
+ motion6.div,
1077
+ {
1078
+ className,
1079
+ initial: "hidden",
1080
+ whileInView: "visible",
1081
+ viewport: viewportSettings,
1082
+ variants: {
1083
+ hidden: { opacity: 0 },
1084
+ visible: {
1085
+ opacity: 1,
1086
+ transition: {
1087
+ staggerChildren: 0.08,
1088
+ delayChildren: 0.1
1089
+ }
1090
+ }
1091
+ },
1092
+ children: childArray.map((child, index) => /* @__PURE__ */ jsx11(
1093
+ motion6.div,
1094
+ {
1095
+ variants: {
1096
+ hidden: { opacity: 0, x: -20 },
1097
+ visible: {
1098
+ opacity: 1,
1099
+ x: 0,
1100
+ transition: {
1101
+ duration: 0.5,
1102
+ ease: [0.4, 0, 0.2, 1]
1103
+ }
1104
+ }
1105
+ },
1106
+ children: child
1107
+ },
1108
+ index
1109
+ ))
1110
+ }
1111
+ );
1112
+ }
1113
+
1114
+ // src/config.ts
1115
+ function defineConfig(config) {
1116
+ return config;
1117
+ }
1118
+
1119
+ // src/lib/sanity.ts
1120
+ import { createClient } from "next-sanity";
1121
+ import imageUrlBuilder from "@sanity/image-url";
1122
+ var projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID;
1123
+ var dataset = process.env.NEXT_PUBLIC_SANITY_DATASET || "production";
1124
+ var apiVersion = "2023-05-03";
1125
+ var _client = null;
1126
+ function getClient() {
1127
+ if (!_client) {
1128
+ if (!projectId) {
1129
+ throw new Error(
1130
+ "Sanity Project ID is not defined. Please set NEXT_PUBLIC_SANITY_PROJECT_ID in your environment."
1131
+ );
1132
+ }
1133
+ _client = createClient({
1134
+ projectId,
1135
+ dataset,
1136
+ apiVersion,
1137
+ useCdn: process.env.NODE_ENV === "production"
1138
+ });
1139
+ }
1140
+ return _client;
1141
+ }
1142
+ var client = {
1143
+ get projectId() {
1144
+ return projectId;
1145
+ },
1146
+ get dataset() {
1147
+ return dataset;
1148
+ },
1149
+ fetch: (...args) => getClient().fetch(...args)
1150
+ };
1151
+ var _builder = null;
1152
+ function urlFor(source) {
1153
+ if (!_builder) {
1154
+ if (!projectId) {
1155
+ return {
1156
+ width: () => ({ height: () => ({ url: () => "" }), url: () => "" }),
1157
+ height: () => ({ width: () => ({ url: () => "" }), url: () => "" }),
1158
+ url: () => ""
1159
+ };
1160
+ }
1161
+ _builder = imageUrlBuilder({ projectId, dataset });
1162
+ }
1163
+ return _builder.image(source);
1164
+ }
507
1165
  export {
1166
+ AnimatedCard,
1167
+ AnimatedGalleryGrid,
1168
+ AnimatedGalleryHeader,
1169
+ AnimatedGrid,
1170
+ AnimatedHeader,
508
1171
  AnimatedHero,
1172
+ AnimatedHeroContent,
1173
+ AnimatedImage,
1174
+ AnimatedItem,
1175
+ AnimatedList,
1176
+ AnimatedMain,
1177
+ AnimatedPage,
1178
+ AnimatedSection,
1179
+ AnimatedSectionHeader,
1180
+ AnimatedStats,
509
1181
  ClientLayout,
510
1182
  ContactCTA,
511
1183
  Footer,
512
1184
  Header,
513
- ThemeToggle
1185
+ HomePage,
1186
+ ScrollRevealSection,
1187
+ StaggeredGrid,
1188
+ ThemeToggle,
1189
+ cardHover,
1190
+ client,
1191
+ defineConfig,
1192
+ escapeHtml,
1193
+ fadeIn,
1194
+ fadeInUp,
1195
+ fadeInUpShort,
1196
+ getClient,
1197
+ imageZoom,
1198
+ isValidEmail,
1199
+ isValidExternalUrl,
1200
+ isValidGoogleMapsEmbedUrl,
1201
+ isValidSlug,
1202
+ pageTransition,
1203
+ reducedMotion,
1204
+ sanitizeUrl,
1205
+ scaleIn,
1206
+ scrollReveal,
1207
+ slideInLeft,
1208
+ slideInRight,
1209
+ staggerContainer,
1210
+ staggerItem,
1211
+ urlFor,
1212
+ viewportSettings
514
1213
  };