foundry-component-library 0.2.3 → 0.2.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.
@@ -10,7 +10,7 @@ const ContactTeaser = ({
10
10
  text,
11
11
  theme = "yellow",
12
12
  buttonText = "Contact Us",
13
- buttonHref = "/contact",
13
+ buttonHref = "/contact#contact-us",
14
14
  alternate,
15
15
  Link,
16
16
  }: {
@@ -7,6 +7,9 @@ import { NextLink } from "../../types";
7
7
  function Footer({
8
8
  details,
9
9
  Link,
10
+ facebook,
11
+ linkedin,
12
+ instagram,
10
13
  }: {
11
14
  details: {
12
15
  berlinEmail: string;
@@ -14,6 +17,9 @@ function Footer({
14
17
  newyorkEmail: string;
15
18
  };
16
19
  Link: NextLink;
20
+ facebook: string;
21
+ linkedin: string;
22
+ instagram: string;
17
23
  }) {
18
24
  const { berlinEmail, zurichEmail, newyorkEmail } = details;
19
25
  const year = new Date().getFullYear();
@@ -81,13 +87,13 @@ function Footer({
81
87
  <div className={styles.socialHeading}>Follow Us</div>
82
88
  <ul className={styles.menuSocial}>
83
89
  <li className={styles.menuItem}>
84
- <Link href="https://instagram.com">Instagram</Link>
90
+ <Link href={instagram}>Instagram</Link>
85
91
  </li>
86
92
  <li className={styles.menuItem}>
87
- <Link href="https://facebook.com">Facebook</Link>
93
+ <Link href={facebook}>Facebook</Link>
88
94
  </li>
89
95
  <li className={styles.menuItem}>
90
- <Link href="https://linkedin.com">Linked-In</Link>
96
+ <Link href={linkedin}>LinkedIn</Link>
91
97
  </li>
92
98
  </ul>
93
99
  </div>
@@ -0,0 +1,43 @@
1
+ "use client";
2
+ import { useState, useRef, useEffect } from "react";
3
+ import { useOnScreen } from "../../hooks/useOnScreen";
4
+ import ReactPlayer from "react-player/lazy";
5
+ import styles from "./styles.module.scss";
6
+
7
+ const Video = ({ url }: { url: string }) => {
8
+ const sectionRef = useRef(null);
9
+ const onScreen = useOnScreen(sectionRef, "1000px");
10
+ // const [playing, setPlaying] = useState(false);
11
+ const [videoLoaded, setVideoLoaded] = useState(false);
12
+ const [hasWindow, setHasWindow] = useState(false);
13
+
14
+ useEffect(() => {
15
+ if (typeof window !== "undefined") {
16
+ setHasWindow(true);
17
+ }
18
+ }, []);
19
+
20
+ useEffect(() => {
21
+ if (!videoLoaded && onScreen) {
22
+ setVideoLoaded(true);
23
+ }
24
+ }, [videoLoaded, onScreen]);
25
+
26
+ return (
27
+ <div className={styles.videoWrapper} ref={sectionRef}>
28
+ {hasWindow && (
29
+ <ReactPlayer
30
+ playing
31
+ url={url}
32
+ width="100%"
33
+ height="100%"
34
+ loop
35
+ muted
36
+ playsinline
37
+ />
38
+ )}
39
+ </div>
40
+ );
41
+ };
42
+
43
+ export default Video;
@@ -4,9 +4,11 @@ import styles from "./styles.module.scss";
4
4
  import Container from "../Container";
5
5
  import { NextImage, NextLink } from "../../types";
6
6
  import { useOnScreen } from "../../hooks/useOnScreen";
7
+ import Video from "./Video";
7
8
 
8
9
  const Hero = ({
9
10
  image,
11
+ video,
10
12
  text,
11
13
  isFullWidth,
12
14
  isFirst,
@@ -16,6 +18,7 @@ const Hero = ({
16
18
  Image,
17
19
  }: {
18
20
  image: string;
21
+ video?: string;
19
22
  text: string;
20
23
  isFullWidth?: boolean;
21
24
  isFirst?: boolean;
@@ -30,7 +33,9 @@ const Hero = ({
30
33
  const sectionRef = useRef(null);
31
34
  const onScreen = useOnScreen(sectionRef, "-50%");
32
35
 
33
- if (!image) return;
36
+ console.log("pop", video);
37
+
38
+ if (!image && !video) return;
34
39
 
35
40
  if (isFullWidth) {
36
41
  return (
@@ -38,15 +43,17 @@ const Hero = ({
38
43
  ref={sectionRef}
39
44
  className={`${styles.hero} ${styles.isFullWidth} ${
40
45
  noMarginBottom ? styles.noMarginBottom : ""
41
- }`}
42
- >
43
- <Image
44
- className={`${styles.background} ${onScreen ? styles.active : ""}`}
45
- src={image}
46
- width="1280"
47
- height="600"
48
- alt={text}
49
- />
46
+ }`}>
47
+ {image && !video && (
48
+ <Image
49
+ className={`${styles.background} ${onScreen ? styles.active : ""}`}
50
+ src={image}
51
+ width="1280"
52
+ height="600"
53
+ alt={text}
54
+ />
55
+ )}
56
+ {video && <Video url={video} />}
50
57
  <div className={styles.texts}>
51
58
  {text && <div className={styles.heading}>{text}</div>}
52
59
  {btn && (
@@ -64,15 +71,17 @@ const Hero = ({
64
71
  <div
65
72
  className={`${styles.hero} ${isFirst ? styles.first : ""} ${
66
73
  noMarginBottom ? styles.noMarginBottom : ""
67
- }`}
68
- >
69
- <Image
70
- className={`${styles.background} ${onScreen ? styles.active : ""}`}
71
- src={image}
72
- width="1280"
73
- height="600"
74
- alt={text}
75
- />
74
+ }`}>
75
+ {image && !video && (
76
+ <Image
77
+ className={`${styles.background} ${onScreen ? styles.active : ""}`}
78
+ src={image}
79
+ width="1280"
80
+ height="600"
81
+ alt={text}
82
+ />
83
+ )}
84
+ {video && <Video url={video} />}
76
85
  <div className={styles.texts}>
77
86
  {text && <div className={styles.heading}>{text}</div>}
78
87
  {btn && (
@@ -103,3 +103,15 @@
103
103
  background-color: $color-white;
104
104
  }
105
105
  }
106
+
107
+ .videoWrapper {
108
+ position: absolute;
109
+ top: 0;
110
+ left: 0;
111
+ width: 100%;
112
+ height: 100%;
113
+
114
+ video {
115
+ object-fit: cover;
116
+ }
117
+ }
@@ -1,5 +1,12 @@
1
1
  "use client";
2
- import { useRef, Dispatch, SetStateAction } from "react";
2
+ import {
3
+ useRef,
4
+ useState,
5
+ useLayoutEffect,
6
+ Dispatch,
7
+ SetStateAction,
8
+ } from "react";
9
+ import { motion, AnimatePresence } from "framer-motion";
3
10
  import { NextImage, NextLink, type Hub } from "../../types";
4
11
  import styles from "./styles.module.scss";
5
12
  import Arrow from "../../assets/svg/arrow.svg";
@@ -21,6 +28,8 @@ const Hub = ({
21
28
  Image: NextImage;
22
29
  }) => {
23
30
  const casesRef = useRef<HTMLDivElement>(null);
31
+ const contentRef = useRef<HTMLDivElement>(null);
32
+ const [height, setHeight] = useState<number | "auto">(0);
24
33
 
25
34
  const {
26
35
  handleMouseDown,
@@ -33,6 +42,12 @@ const Hub = ({
33
42
  const isActive = active === hub.slug;
34
43
  const customFields = hub.customFieldsHub;
35
44
 
45
+ useLayoutEffect(() => {
46
+ if (contentRef.current) {
47
+ setHeight(contentRef.current.scrollHeight);
48
+ }
49
+ }, [isActive, customFields]);
50
+
36
51
  return (
37
52
  <div className={`${styles.hub} ${isActive ? styles.active : ""}`}>
38
53
  <div className={styles.top}>
@@ -40,94 +55,95 @@ const Hub = ({
40
55
  <div className={styles.text}>{customFields.subheading}</div>
41
56
  <button
42
57
  className={styles.icon}
43
- onClick={() => {
44
- if (isActive) {
45
- setActive("");
46
- } else {
47
- setActive(hub.slug);
48
- }
49
- }}
50
- >
51
- {isActive && <Minus />}
52
- {!isActive && <Plus />}
58
+ onClick={() => setActive(isActive ? "" : hub.slug)}>
59
+ {isActive ? <Minus /> : <Plus />}
53
60
  </button>
54
61
  </div>
55
- <div className={styles.rows}>
56
- <div className={styles.row}>
57
- <div className={styles.rowWrapper}>
58
- <div className={styles.subheading}>SERVICE</div>
59
- <div className={styles.right}>
60
- {customFields.tags && (
61
- <div className={styles.tags}>
62
- {customFields.tags.map((tag) => `${tag.tag} // `)}
63
- </div>
64
- )}
65
- </div>
66
- </div>
67
- </div>
68
- <div className={styles.row}>
69
- <div className={styles.rowWrapper}>
70
- <div className={styles.subheading}>APPROACH</div>
71
- <div className={styles.right}>
72
- <div className={styles.paragraph}>{customFields.approach}</div>
73
- </div>
74
- </div>
75
- </div>
76
- <div className={styles.row}>
77
- <div className={styles.rowWrapper}>
78
- <div className={styles.subheading}>RELATED WORK</div>
79
- <div className={styles.right}>
80
- {customFields.relatedWork && (
81
- <div
82
- className={styles.cases}
83
- ref={casesRef}
84
- onMouseDown={handleMouseDown}
85
- onMouseMove={handleMouseMove}
86
- onMouseUp={handleMouseUp}
87
- onMouseLeave={handleMouseUp}
88
- style={{
89
- ...(dragStyle as React.CSSProperties),
90
- }}
91
- >
92
- {customFields.relatedWork.map((item) => {
93
- const { thumbnailImage, mainImage } = item.case;
94
62
 
95
- return (
96
- <Link
97
- href={item.uri}
98
- key={item.id}
99
- className={styles.case}
100
- draggable={false}
101
- onClick={preventedClick}
102
- >
103
- <div className={styles.caseImage}>
104
- <Image
105
- src={
106
- thumbnailImage?.sourceUrl ||
107
- mainImage?.sourceUrl ||
108
- ""
109
- }
110
- alt={item.title}
111
- fill
112
- />
63
+ <AnimatePresence initial={false}>
64
+ {(isActive || height !== 0) && (
65
+ <motion.div
66
+ key="content"
67
+ initial={{ height: 0, opacity: 0 }}
68
+ animate={{
69
+ height: isActive ? height : 0,
70
+ opacity: isActive ? 1 : 0,
71
+ }}
72
+ exit={{ height: 0, opacity: 0 }}
73
+ transition={{ duration: 0.4, ease: [0.4, 0, 0.2, 1] }}
74
+ style={{ overflow: "hidden" }}>
75
+ <div ref={contentRef}>
76
+ <div className={styles.rows}>
77
+ <div className={styles.row}>
78
+ <div className={styles.rowWrapper}>
79
+ <div className={styles.subheading}>SERVICE</div>
80
+ <div className={styles.right}>
81
+ {customFields.tags && (
82
+ <div className={styles.tags}>
83
+ {customFields.tags.map((tag) => `${tag.tag} // `)}
113
84
  </div>
114
- <div className={styles.caseTitle}>
115
- {item.title} <Arrow />
85
+ )}
86
+ </div>
87
+ </div>
88
+ </div>
89
+
90
+ <div className={styles.row}>
91
+ <div className={styles.rowWrapper}>
92
+ <div className={styles.subheading}>RELATED WORK</div>
93
+ <div className={styles.right}>
94
+ {customFields.relatedWork && (
95
+ <div
96
+ className={styles.cases}
97
+ ref={casesRef}
98
+ onMouseDown={handleMouseDown}
99
+ onMouseMove={handleMouseMove}
100
+ onMouseUp={handleMouseUp}
101
+ onMouseLeave={handleMouseUp}
102
+ style={{
103
+ ...(dragStyle as React.CSSProperties),
104
+ }}>
105
+ {customFields.relatedWork.map((item) => {
106
+ const { thumbnailImage, mainImage } = item.case;
107
+
108
+ return (
109
+ <Link
110
+ href={item.uri}
111
+ key={item.id}
112
+ className={styles.case}
113
+ draggable={false}
114
+ onClick={preventedClick}>
115
+ <div className={styles.caseImage}>
116
+ <Image
117
+ src={
118
+ thumbnailImage?.sourceUrl ||
119
+ mainImage?.sourceUrl ||
120
+ ""
121
+ }
122
+ alt={item.title}
123
+ fill
124
+ />
125
+ </div>
126
+ <div className={styles.caseTitle}>
127
+ {item.title} <Arrow />
128
+ </div>
129
+ </Link>
130
+ );
131
+ })}
116
132
  </div>
117
- </Link>
118
- );
119
- })}
133
+ )}
134
+ </div>
135
+ </div>
136
+ <div className={styles.more}>
137
+ <Link href={hub.uri}>
138
+ Learn More <Arrow />
139
+ </Link>
140
+ </div>
120
141
  </div>
121
- )}
142
+ </div>
122
143
  </div>
123
- </div>
124
- <div className={styles.more}>
125
- <Link href={hub.uri}>
126
- Learn More <Arrow />
127
- </Link>
128
- </div>
129
- </div>
130
- </div>
144
+ </motion.div>
145
+ )}
146
+ </AnimatePresence>
131
147
  </div>
132
148
  );
133
149
  };
@@ -12,12 +12,6 @@
12
12
  color: $color-brown;
13
13
  position: relative;
14
14
 
15
- &.active {
16
- .rows {
17
- display: block;
18
- }
19
- }
20
-
21
15
  &:before {
22
16
  content: "";
23
17
  position: absolute;
@@ -105,10 +99,6 @@
105
99
  }
106
100
  }
107
101
 
108
- .rows {
109
- display: none;
110
- }
111
-
112
102
  .row {
113
103
  padding-bottom: 64px;
114
104
  position: relative;
@@ -2,14 +2,12 @@ import { MouseEventHandler } from "react";
2
2
  import styles from "./styles.module.scss";
3
3
  import Plus from "../../assets/svg/plus.svg";
4
4
  import { NextLink } from "../../types";
5
- import { motion } from "framer-motion";
6
5
  import Arrow from "../../assets/svg/arrow.svg";
7
6
 
8
7
  const Tile = ({
9
8
  text,
10
9
  background,
11
10
  href,
12
- i,
13
11
  onClick,
14
12
  Link,
15
13
  hoverText,
@@ -23,28 +21,12 @@ const Tile = ({
23
21
  hoverText: string;
24
22
  }) => {
25
23
  return (
26
- <motion.div
27
- className={styles.tileWrapper}
28
- whileHover={{
29
- scale: 1.08,
30
- rotate: i % 2 === 0 ? -3 : 3,
31
- boxShadow: "0px 10px 20px rgba(0,0,0,0.2)",
32
- y: [0, Math.random() * 12 - 6, 0],
33
- transition: {
34
- y: {
35
- duration: 2,
36
- repeat: Infinity,
37
- ease: "easeInOut",
38
- },
39
- },
40
- }}
41
- >
24
+ <div className={styles.tileWrapper}>
42
25
  <Link
43
26
  href={href}
44
27
  onClick={onClick}
45
28
  draggable="false"
46
- className={`${styles.tile} ${styles[background]}`}
47
- >
29
+ className={`${styles.tile} ${styles[background]}`}>
48
30
  <div className={styles.face}>
49
31
  <div className={styles.text}>{text}</div>
50
32
  <div>
@@ -58,7 +40,7 @@ const Tile = ({
58
40
  </div>
59
41
  </div>
60
42
  </Link>
61
- </motion.div>
43
+ </div>
62
44
  );
63
45
  };
64
46
 
@@ -1,11 +1,13 @@
1
1
  "use client";
2
- import { useRef } from "react";
2
+ import { useRef, useEffect } from "react";
3
3
  import Container from "../Container";
4
4
  import styles from "./styles.module.scss";
5
5
  import TextSection from "../TextSection";
6
6
  import Tile from "./Tile";
7
7
  import { NextLink } from "../../types";
8
- import { motion } from "framer-motion";
8
+ import { motion, useScroll, useMotionValue, useSpring } from "framer-motion";
9
+
10
+ const SCROLL_DISTANCE = -500;
9
11
 
10
12
  const ServiceHubsTeaser = ({
11
13
  caption,
@@ -27,9 +29,32 @@ const ServiceHubsTeaser = ({
27
29
  }[];
28
30
  Link: NextLink;
29
31
  }) => {
30
- const wrapperRef = useRef(null);
32
+ const wrapperRef = useRef<HTMLDivElement>(null);
31
33
  const dragStarted = useRef(false);
32
34
 
35
+ const x = useMotionValue(0);
36
+
37
+ const smoothX = useSpring(x, {
38
+ stiffness: 120,
39
+ damping: 20,
40
+ mass: 0.1,
41
+ });
42
+
43
+ const { scrollYProgress } = useScroll({
44
+ target: wrapperRef,
45
+ offset: ["start end", "end start"],
46
+ });
47
+
48
+ useEffect(() => {
49
+ const unsubscribe = scrollYProgress.on("change", (latest) => {
50
+ const scrollOffset = latest * SCROLL_DISTANCE;
51
+ if (!dragStarted.current) {
52
+ x.set(scrollOffset);
53
+ }
54
+ });
55
+ return () => unsubscribe();
56
+ }, [scrollYProgress, x]);
57
+
33
58
  return (
34
59
  <div className={styles.benefits}>
35
60
  <TextSection caption={caption} heading={heading} text={text} isSmall />
@@ -39,18 +64,22 @@ const ServiceHubsTeaser = ({
39
64
  className={styles.tiles}
40
65
  drag="x"
41
66
  dragConstraints={wrapperRef}
67
+ style={{ x: smoothX }}
68
+ dragMomentum={true}
42
69
  onDragStart={() => (dragStarted.current = true)}
43
70
  onDragEnd={() => {
44
71
  setTimeout(() => {
45
72
  dragStarted.current = false;
46
73
  }, 0);
47
- }}
48
- >
74
+ }}>
49
75
  {tiles.map((tile, i) => {
50
- let background: "pink" | "yellow" | "brown" | "blue" = "pink";
51
- if (i % 4 === 1) background = "yellow";
52
- if (i % 4 === 2) background = "brown";
53
- if (i % 4 === 3) background = "blue";
76
+ const colors: Array<"pink" | "yellow" | "brown" | "blue"> = [
77
+ "pink",
78
+ "yellow",
79
+ "brown",
80
+ "blue",
81
+ ];
82
+ const background = colors[i % colors.length];
54
83
 
55
84
  return (
56
85
  <Tile
@@ -7,6 +7,7 @@
7
7
  .wrapper {
8
8
  width: 100%;
9
9
  // overflow-x: scroll;
10
+ user-select: none;
10
11
  }
11
12
 
12
13
  .tiles {
@@ -5,107 +5,55 @@ import styles from "./styles.module.scss";
5
5
  import Mute from "../../assets/svg/mute.svg";
6
6
  import Muted from "../../assets/svg/muted.svg";
7
7
  import PlayButton from "../../assets/svg/play-button.svg";
8
- import {
9
- motion,
10
- useScroll,
11
- useMotionValueEvent,
12
- useTransform,
13
- } from "motion/react";
14
8
  import Logo from "../../assets/svg/footer-logo.svg";
15
9
 
16
10
  function VideoTeaser({ url }: { url: string }) {
17
- const [playing, setPlaying] = useState(false);
18
- const [hasWindow, setHasWindow] = useState(false);
11
+ const [playing, setPlaying] = useState(true);
19
12
  const [isMuted, setIsMuted] = useState(true);
20
- const [isAnimated, setIsAnimated] = useState(false);
21
- const { scrollY } = useScroll();
22
- const [path, setPath] = useState(
23
- `polygon(50% 50%, 50% 50%, 50% 50%, 50% 50%)`
24
- );
25
-
26
- const progress = useTransform(scrollY, [100, 300], [0, 1]);
13
+ const [hasWindow, setHasWindow] = useState(false);
27
14
 
28
- const lerp = (a: number, b: number, t: number) => {
29
- return a + (b - a) * t;
15
+ const handleClick = () => {
16
+ setPlaying(!playing);
30
17
  };
31
18
 
32
- useMotionValueEvent(scrollY, "change", () => {
33
- setPath(
34
- `polygon(
35
- ${lerp(50, 0, progress.get())}%
36
- ${lerp(50, 0, progress.get())}%,
37
- ${lerp(50, 100, progress.get())}%
38
- ${lerp(50, 0, progress.get())}%,
39
- ${lerp(50, 100, progress.get())}%
40
- ${lerp(50, 100, progress.get())}%,
41
- ${lerp(50, 0, progress.get())}%
42
- ${lerp(50, 100, progress.get())}%)`
43
- );
44
-
45
- if (progress.get() >= 1) {
46
- setIsAnimated(true);
47
- } else {
48
- setIsAnimated(false);
49
- }
50
- });
51
-
52
19
  useEffect(() => {
53
20
  if (typeof window !== "undefined") {
54
21
  setHasWindow(true);
55
22
  }
56
23
  }, []);
57
24
 
58
- const handleClick = () => {
59
- setPlaying(!playing);
60
- };
61
-
62
25
  if (!url) return;
63
26
 
64
27
  return (
65
28
  <>
66
- <div style={{ height: "1100px" }}>
67
- <div className={styles.logoWrapper}>
68
- <Logo />
69
- </div>
70
- <motion.div
71
- // eslint-disable-next-line no-extra-boolean-cast
72
- className={`${styles.wrapper} ${!!url ? styles.playCursor : ""} ${
73
- playing ? styles.playing : ""
74
- }`}
75
- style={{
76
- clipPath: path,
77
- }}
78
- >
79
- {/* <Mask isAnimated={isAnimated} setIsAnimated={setIsAnimated} /> */}
80
-
81
- <button
82
- className={styles.btnMute}
83
- onClick={() => setIsMuted(!isMuted)}
84
- >
85
- {isMuted ? <Muted /> : <Mute />}
86
- </button>
87
- <div className={styles.video} onClick={handleClick}>
88
- <div
89
- className={`${styles.playButton} ${
90
- playing ? styles.playing : ""
91
- } ${isAnimated ? styles.isAnimated : ""}`}
92
- >
93
- <PlayButton />
94
- </div>
95
- {hasWindow && (
96
- <ReactPlayer
97
- playing={playing}
98
- url={url}
99
- width="100%"
100
- height="100%"
101
- muted={isMuted}
102
- config={{
103
- file: { attributes: { poster: "/video-poster.jpg" } },
104
- }}
105
- />
106
- )}
29
+ <div className={styles.logoWrapper}>
30
+ <Logo />
31
+ </div>
32
+ <div
33
+ className={`${styles.wrapper} ${url ? styles.playCursor : ""} ${
34
+ playing ? styles.playing : ""
35
+ }`}>
36
+ <button className={styles.btnMute} onClick={() => setIsMuted(!isMuted)}>
37
+ {isMuted ? <Muted /> : <Mute />}
38
+ </button>
39
+ <div className={styles.video} onClick={handleClick}>
40
+ <div
41
+ className={`${styles.playButton} ${playing ? styles.playing : ""}`}>
42
+ <PlayButton />
107
43
  </div>
108
- </motion.div>
44
+ {hasWindow && (
45
+ <ReactPlayer
46
+ playing={playing}
47
+ url={url}
48
+ width="100%"
49
+ height="100%"
50
+ muted={isMuted}
51
+ config={{
52
+ file: { attributes: { poster: "/video-poster.jpg" } },
53
+ }}
54
+ />
55
+ )}
56
+ </div>
109
57
  </div>
110
58
  </>
111
59
  );
@@ -2,19 +2,16 @@
2
2
 
3
3
  .wrapper {
4
4
  background-color: $color-white;
5
- background-size: cover;
6
- background-position: center;
7
5
  width: 100%;
8
6
  height: 790px;
9
- max-height: calc(100vh - 75px);
7
+ max-height: calc(100vh - 79px);
10
8
  text-align: center;
11
9
  box-sizing: border-box;
12
10
  display: flex;
13
11
  align-items: center;
14
- position: sticky;
15
- top: 79px;
12
+ padding-top: 79px;
16
13
  overflow: hidden;
17
- clip-path: polygon(10% 5%, 90% 5%, 90% 95%, 10% 95%);
14
+ position: relative;
18
15
 
19
16
  @media #{$QUERY-md} {
20
17
  padding: 100px 50px;
@@ -90,11 +87,6 @@
90
87
  justify-content: center;
91
88
  cursor: pointer;
92
89
  transition: opacity 0.3s;
93
- opacity: 0;
94
-
95
- &.isAnimated {
96
- opacity: 1;
97
- }
98
90
 
99
91
  &.playing {
100
92
  opacity: 0;
@@ -23,7 +23,7 @@ const Pagination = ({
23
23
  const handleClick = (page: number) => {
24
24
  const params = new URLSearchParams(searchParams);
25
25
  params.set("page", String(page));
26
- router.push(`?${params.toString()}`, { scroll: false });
26
+ router.push(`?${params.toString()}`, { scroll: true });
27
27
  };
28
28
 
29
29
  return (
@@ -34,8 +34,7 @@ const Pagination = ({
34
34
  return (
35
35
  <span
36
36
  key={page + 1}
37
- className={`${styles.indicator} ${styles.current}`}
38
- >
37
+ className={`${styles.indicator} ${styles.current}`}>
39
38
  {page + 1}
40
39
  </span>
41
40
  );
@@ -47,8 +46,7 @@ const Pagination = ({
47
46
  className={styles.indicator}
48
47
  onClick={() => {
49
48
  handleClick(page + 1);
50
- }}
51
- >
49
+ }}>
52
50
  {page + 1}
53
51
  </button>
54
52
  );
@@ -17,12 +17,16 @@ function Contacts({
17
17
  email: string;
18
18
  }[];
19
19
  }) {
20
- const [isTypeformOpen, setIsTypeformOpen] = useState(false);
21
- const ref = useClickOutside<HTMLDivElement>(() => setIsTypeformOpen(false));
20
+ const [isTypeform1Open, setIsTypeform1Open] = useState(false);
21
+ const [isTypeform2Open, setIsTypeform2Open] = useState(false);
22
+ const ref = useClickOutside<HTMLDivElement>(() => {
23
+ setIsTypeform1Open(false);
24
+ setIsTypeform2Open(false);
25
+ });
22
26
  if (!items) return;
23
27
 
24
28
  return (
25
- <section className={styles.section}>
29
+ <section className={styles.section} id="contact-us">
26
30
  <Container>
27
31
  <h2 className={styles.title}>{title}</h2>
28
32
  <div className={styles.boxes}>
@@ -44,8 +48,13 @@ function Contacts({
44
48
  </div>
45
49
  <a
46
50
  className={styles.buttonSecondary}
47
- onClick={() => setIsTypeformOpen(true)}
48
- >
51
+ onClick={() => {
52
+ if (i === 2) {
53
+ setIsTypeform1Open(true);
54
+ } else {
55
+ setIsTypeform2Open(true);
56
+ }
57
+ }}>
49
58
  {i === 0 && "Contact Account"}
50
59
  {i === 1 && "General Contact"}
51
60
  {i === 2 && "Contact HR"}
@@ -57,8 +66,7 @@ function Contacts({
57
66
  </div>
58
67
  <div
59
68
  className={styles.typeform}
60
- style={{ display: isTypeformOpen ? "flex" : "none" }}
61
- >
69
+ style={{ display: isTypeform1Open ? "flex" : "none" }}>
62
70
  <Script src="//embed.typeform.com/next/embed.js" />
63
71
  <div ref={ref} className={styles.typeformWrapper}>
64
72
  {/* <div data-tf-widget="qmv6Yk" data-tf-iframe-props="title=Foundry Website Contact Form" data-tf-medium="snippet" style={{ width: '100%', height: '400px' }} /> */}
@@ -70,6 +78,20 @@ function Contacts({
70
78
  />
71
79
  </div>
72
80
  </div>
81
+ <div
82
+ className={styles.typeform}
83
+ style={{ display: isTypeform2Open ? "flex" : "none" }}>
84
+ <Script src="//embed.typeform.com/next/embed.js" />
85
+ <div ref={ref} className={styles.typeformWrapper}>
86
+ {/* <div data-tf-widget="qmv6Yk" data-tf-iframe-props="title=Foundry Website Contact Form" data-tf-medium="snippet" style={{ width: '100%', height: '400px' }} /> */}
87
+ <div
88
+ data-tf-widget="qmv6Yk"
89
+ data-tf-iframe-props="title=Foundry Website Contact Form"
90
+ data-tf-medium="snippet"
91
+ style={{ width: "100%", height: "400px" }}
92
+ />
93
+ </div>
94
+ </div>
73
95
  </Container>
74
96
  </section>
75
97
  );
@@ -4,6 +4,7 @@
4
4
  padding: 64px 0;
5
5
  background-color: $color-yellow;
6
6
  color: $color-brown;
7
+ scroll-margin-top: 60px;
7
8
 
8
9
  @media #{$QUERY-sm} {
9
10
  padding: 32px 0;
@@ -64,6 +64,9 @@ type AboutPage = {
64
64
  };
65
65
  contactPage: {
66
66
  customFieldsContact: {
67
+ facebook: string;
68
+ instagram: string;
69
+ linkedin: string;
67
70
  berlinImage?: {
68
71
  sourceUrl: string;
69
72
  };
@@ -165,6 +168,9 @@ export default async function getAboutPage({
165
168
  }
166
169
  contactPage: page(id: "${contactPage}", idType: URI) {
167
170
  customFieldsContact {
171
+ facebook
172
+ instagram
173
+ linkedin
168
174
  berlinImage {
169
175
  sourceUrl
170
176
  }
@@ -232,6 +232,9 @@ export default async function getCaseBySlug({
232
232
  }
233
233
  contactPage: page(id: "${contactPage}", idType: URI) {
234
234
  customFieldsContact {
235
+ facebook
236
+ instagram
237
+ linkedin
235
238
  berlinImage {
236
239
  sourceUrl
237
240
  }
@@ -231,6 +231,9 @@ export default async function getCaseBySlug({
231
231
  }
232
232
  contactPage: page(id: "${contactPage}", idType: URI) {
233
233
  customFieldsContact {
234
+ facebook
235
+ instagram
236
+ linkedin
234
237
  berlinImage {
235
238
  sourceUrl
236
239
  }
@@ -164,6 +164,9 @@ export default async function getCasesPage({
164
164
  }
165
165
  contactPage: page(id: "${contactPage}", idType: URI) {
166
166
  customFieldsContact {
167
+ facebook
168
+ instagram
169
+ linkedin
167
170
  berlinImage {
168
171
  sourceUrl
169
172
  }
@@ -4,6 +4,9 @@ import client from "./client";
4
4
  export type ContactPage = {
5
5
  title: string;
6
6
  customFieldsContact: {
7
+ facebook: string;
8
+ instagram: string;
9
+ linkedin: string;
7
10
  topCaption: string;
8
11
  topHeading: string;
9
12
  berlinImage: {
@@ -57,6 +60,9 @@ export default async function getContactPage({
57
60
  page(id: $slug, idType: URI) {
58
61
  title
59
62
  customFieldsContact {
63
+ facebook
64
+ instagram
65
+ linkedin
60
66
  topCaption
61
67
  topHeading
62
68
  berlinImage {
@@ -78,6 +78,9 @@ type HomePage = {
78
78
  posts: PostPreview[];
79
79
  contactPage: {
80
80
  customFieldsContact: {
81
+ facebook: string;
82
+ instagram: string;
83
+ linkedin: string;
81
84
  berlinImage?: {
82
85
  sourceUrl: string;
83
86
  };
@@ -216,6 +219,9 @@ export default async function getHomePage({
216
219
  }
217
220
  contactPage: page(id: "${contactPage}", idType: URI) {
218
221
  customFieldsContact {
222
+ facebook
223
+ instagram
224
+ linkedin
219
225
  berlinImage {
220
226
  sourceUrl
221
227
  }
@@ -45,6 +45,9 @@ export default async function getHubBySlug({
45
45
  mainimage {
46
46
  sourceUrl
47
47
  }
48
+ mainvideo{
49
+ mediaItemUrl
50
+ }
48
51
  relatedWork {
49
52
  ... on Case {
50
53
  title
@@ -84,6 +87,9 @@ export default async function getHubBySlug({
84
87
  }
85
88
  contactPage: page(id: "${contactPage}", idType: URI) {
86
89
  customFieldsContact {
90
+ facebook
91
+ instagram
92
+ linkedin
87
93
  berlinImage {
88
94
  sourceUrl
89
95
  }
@@ -165,6 +165,9 @@ export default async function getCasesPage(
165
165
  }
166
166
  contactPage: page(id: "${contactPage}", idType: URI) {
167
167
  customFieldsContact {
168
+ facebook
169
+ instagram
170
+ linkedin
168
171
  berlinImage {
169
172
  sourceUrl
170
173
  }
@@ -119,6 +119,9 @@ export default async function getNewsPage(options: Params): Promise<{
119
119
  }
120
120
  contactPage: page(id: "${contactPage}", idType: URI) {
121
121
  customFieldsContact {
122
+ facebook
123
+ instagram
124
+ linkedin
122
125
  berlinImage {
123
126
  sourceUrl
124
127
  }
@@ -40,6 +40,9 @@ type PeoplePage = {
40
40
  };
41
41
  contactPage: {
42
42
  customFieldsContact: {
43
+ facebook: string;
44
+ instagram: string;
45
+ linkedin: string;
43
46
  berlinImage?: {
44
47
  sourceUrl: string;
45
48
  };
@@ -123,6 +126,9 @@ export default async function getContactPage({
123
126
  }
124
127
  contactPage: page(id: "${contactPage}", idType: URI) {
125
128
  customFieldsContact {
129
+ facebook
130
+ instagram
131
+ linkedin
126
132
  berlinImage {
127
133
  sourceUrl
128
134
  }
@@ -50,6 +50,9 @@ type PerformancePage = {
50
50
  };
51
51
  contactPage: {
52
52
  customFieldsContact: {
53
+ facebook: string;
54
+ instagram: string;
55
+ linkedin: string;
53
56
  berlinImage?: {
54
57
  sourceUrl: string;
55
58
  };
@@ -128,6 +131,9 @@ export default async function getPerformanceHubPage(): Promise<PerformancePage>
128
131
  }
129
132
  contactPage: page(id: "contact", idType: URI) {
130
133
  customFieldsContact {
134
+ facebook
135
+ instagram
136
+ linkedin
131
137
  berlinImage {
132
138
  sourceUrl
133
139
  }
@@ -104,6 +104,9 @@ export default async function getPostBySlug({
104
104
  }
105
105
  contactPage: page(id: "${contactPage}", idType: URI) {
106
106
  customFieldsContact {
107
+ facebook
108
+ instagram
109
+ linkedin
107
110
  berlinImage {
108
111
  sourceUrl
109
112
  }
@@ -319,6 +319,9 @@ export type Hub = {
319
319
  mainimage: {
320
320
  sourceUrl: string;
321
321
  };
322
+ mainvideo: {
323
+ mediaItemUrl: string;
324
+ };
322
325
  caption: string;
323
326
  heading: string;
324
327
  subheading: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foundry-component-library",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",