foundry-component-library 0.2.29 → 0.2.30

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.
@@ -102,6 +102,8 @@ const Item = ({
102
102
  }}>
103
103
  {Link &&
104
104
  cases.map((item) => {
105
+ if (!item) return "";
106
+
105
107
  const { thumbnailImage, mainImage } = item.case;
106
108
 
107
109
  return (
@@ -0,0 +1,192 @@
1
+ "use client";
2
+ import React from "react";
3
+ import { useActionState, useState } from "react";
4
+ import { useRouter } from "next/navigation";
5
+ import styles from "./styles.module.scss";
6
+
7
+ type LeadResult =
8
+ | { success: true }
9
+ | { success: false; errors: Record<string, string> };
10
+
11
+ const GetInTouch = ({
12
+ submitLead,
13
+ service,
14
+ }: {
15
+ service: string;
16
+ submitLead: (
17
+ prevState: LeadResult | null,
18
+ formData: FormData,
19
+ ) => Promise<LeadResult>;
20
+ }) => {
21
+ const router = useRouter();
22
+ const [submitting, setSubmitting] = useState(false);
23
+ const [form, setForm] = useState({
24
+ firstName: "",
25
+ lastName: "",
26
+ email: "",
27
+ phone: "",
28
+ note: "",
29
+ });
30
+ const [state, formAction] = useActionState(submitLead, null);
31
+
32
+ if (state?.success) {
33
+ router.push("/hubs/thank-you");
34
+ return null;
35
+ }
36
+
37
+ const errors = state?.success === false ? state.errors : {};
38
+
39
+ const endSubmitting = () => {
40
+ setSubmitting(false);
41
+ };
42
+
43
+ return (
44
+ <section id="get-in-touch" className={styles.formSection}>
45
+ <div className={styles.container}>
46
+ <h2 className={styles.heading}>Get in touch</h2>
47
+ <p className={styles.subtitle}>
48
+ Tell us about your brand and discover how we can help.
49
+ </p>
50
+ <form
51
+ action={formAction}
52
+ className={styles.form}
53
+ onSubmit={() => setSubmitting(true)}
54
+ noValidate>
55
+ <div className={styles.honeypot} aria-hidden="true">
56
+ <label htmlFor="website">Website</label>
57
+ <input
58
+ id="website"
59
+ name="website"
60
+ type="text"
61
+ tabIndex={-1}
62
+ autoComplete="off"
63
+ />
64
+ </div>
65
+
66
+ <input type="hidden" name="service" value={service} />
67
+
68
+ <div className={styles.row}>
69
+ <div className={styles.field}>
70
+ <label className={styles.label} htmlFor="firstName">
71
+ First Name *
72
+ </label>
73
+ <input
74
+ id="firstName"
75
+ name="firstName"
76
+ type="text"
77
+ className={`${styles.input} ${errors.firstName ? styles.inputError : ""}`}
78
+ required
79
+ onKeyDown={endSubmitting}
80
+ value={form.firstName}
81
+ onChange={(e) => {
82
+ setForm({
83
+ ...form,
84
+ firstName: e.target.value,
85
+ });
86
+ }}
87
+ />
88
+ {errors.firstName && (
89
+ <p className={styles.error}>{errors.firstName}</p>
90
+ )}
91
+ </div>
92
+
93
+ <div className={styles.field}>
94
+ <label className={styles.label} htmlFor="lastName">
95
+ Last Name *
96
+ </label>
97
+ <input
98
+ id="lastName"
99
+ name="lastName"
100
+ type="text"
101
+ className={`${styles.input} ${errors.lastName ? styles.inputError : ""}`}
102
+ required
103
+ onKeyDown={endSubmitting}
104
+ value={form.lastName}
105
+ onChange={(e) => {
106
+ setForm({
107
+ ...form,
108
+ lastName: e.target.value,
109
+ });
110
+ }}
111
+ />
112
+ {errors.lastName && (
113
+ <p className={styles.error}>{errors.lastName}</p>
114
+ )}
115
+ </div>
116
+ </div>
117
+
118
+ <div className={styles.row}>
119
+ <div className={styles.field}>
120
+ <label className={styles.label} htmlFor="email">
121
+ Email *
122
+ </label>
123
+ <input
124
+ id="email"
125
+ name="email"
126
+ type="email"
127
+ className={`${styles.input} ${errors.email ? styles.inputError : ""}`}
128
+ required
129
+ onKeyDown={endSubmitting}
130
+ value={form.email}
131
+ onChange={(e) => {
132
+ setForm({
133
+ ...form,
134
+ email: e.target.value,
135
+ });
136
+ }}
137
+ />
138
+ {errors.email && <p className={styles.error}>{errors.email}</p>}
139
+ </div>
140
+
141
+ <div className={styles.field}>
142
+ <label className={styles.label} htmlFor="phone">
143
+ Phone Number *
144
+ </label>
145
+ <input
146
+ id="phone"
147
+ name="phone"
148
+ type="tel"
149
+ className={`${styles.input} ${errors.phone ? styles.inputError : ""}`}
150
+ onKeyDown={endSubmitting}
151
+ value={form.phone}
152
+ onChange={(e) => {
153
+ setForm({
154
+ ...form,
155
+ phone: e.target.value,
156
+ });
157
+ }}
158
+ />
159
+ {errors.phone && <p className={styles.error}>{errors.phone}</p>}
160
+ </div>
161
+ </div>
162
+
163
+ <div className={styles.field}>
164
+ <label className={styles.label} htmlFor="note">
165
+ Note
166
+ </label>
167
+ <textarea
168
+ id="note"
169
+ name="note"
170
+ className={styles.textarea}
171
+ value={form.note}
172
+ onChange={(e) => {
173
+ setForm({
174
+ ...form,
175
+ note: e.target.value,
176
+ });
177
+ }}
178
+ />
179
+ </div>
180
+
181
+ {errors._form && <p className={styles.formError}>{errors._form}</p>}
182
+
183
+ <button type="submit" className={styles.submit} disabled={submitting}>
184
+ Submit
185
+ </button>
186
+ </form>
187
+ </div>
188
+ </section>
189
+ );
190
+ };
191
+
192
+ export default GetInTouch;
@@ -0,0 +1,162 @@
1
+ .formSection {
2
+ padding: 80px 24px 40px;
3
+ background: #fff;
4
+
5
+ h2 {
6
+ color: #491b11;
7
+ }
8
+ }
9
+
10
+ .container {
11
+ max-width: 1200px;
12
+ margin: 0 auto;
13
+ text-align: center;
14
+ }
15
+
16
+ .cta {
17
+ display: inline-block;
18
+ font-size: 14px;
19
+ font-weight: 600;
20
+ color: #fff;
21
+ background: #000;
22
+ padding: 12px 24px;
23
+ border-radius: 4px;
24
+ text-decoration: none;
25
+ margin-bottom: 24px;
26
+ transition: opacity 0.2s;
27
+ }
28
+
29
+ .cta:hover {
30
+ opacity: 0.8;
31
+ }
32
+
33
+ .heading {
34
+ font-size: 36px;
35
+ font-weight: 500;
36
+ margin-bottom: 12px;
37
+ font-family: "kareliaOuttakes", serif;
38
+ }
39
+
40
+ .subtitle {
41
+ font-size: 16px;
42
+ color: #555;
43
+ margin-bottom: 48px;
44
+ }
45
+
46
+ .form {
47
+ max-width: 600px;
48
+ margin: 0 auto;
49
+ }
50
+
51
+ .row {
52
+ display: flex;
53
+ gap: 30px;
54
+ width: 100%;
55
+
56
+ .field {
57
+ width: 50%;
58
+ }
59
+ }
60
+
61
+ .field {
62
+ margin-bottom: 20px;
63
+ }
64
+
65
+ .label {
66
+ display: block;
67
+ font-size: 14px;
68
+ font-weight: 500;
69
+ margin-bottom: 6px;
70
+ color: #491b11;
71
+ text-align: left;
72
+ }
73
+
74
+ .input,
75
+ .textarea {
76
+ width: 100%;
77
+ padding: 12px 16px;
78
+ border: 1px solid #ccc;
79
+ border-radius: 0;
80
+ font-size: 16px;
81
+ font-family: inherit;
82
+ background: #fff;
83
+ color: #000;
84
+ transition: border-color 0.2s;
85
+ }
86
+
87
+ .input:focus,
88
+ .textarea:focus {
89
+ outline: none;
90
+ border-color: #000;
91
+ }
92
+
93
+ .inputError {
94
+ border-color: #e00;
95
+ }
96
+
97
+ .textarea {
98
+ min-height: 120px;
99
+ resize: vertical;
100
+ }
101
+
102
+ .error {
103
+ color: #e00;
104
+ font-size: 13px;
105
+ margin-top: 4px;
106
+ text-align: left;
107
+ }
108
+
109
+ .formError {
110
+ color: #e00;
111
+ font-size: 14px;
112
+ margin-bottom: 16px;
113
+ text-align: center;
114
+ }
115
+
116
+ .honeypot {
117
+ position: absolute;
118
+ left: -9999px;
119
+ opacity: 0;
120
+ height: 0;
121
+ width: 0;
122
+ overflow: hidden;
123
+ }
124
+
125
+ .submit {
126
+ display: inline-block;
127
+ padding: 14px 40px;
128
+ background: #000;
129
+ color: #fff;
130
+ border: none;
131
+ font-size: 16px;
132
+ font-weight: 500;
133
+ font-family: inherit;
134
+ cursor: pointer;
135
+ transition: opacity 0.2s;
136
+ }
137
+
138
+ .submit:hover {
139
+ opacity: 0.8;
140
+ }
141
+
142
+ .submit:disabled {
143
+ opacity: 0.4;
144
+ cursor: not-allowed;
145
+ }
146
+
147
+ .success {
148
+ text-align: center;
149
+ padding: 40px 20px;
150
+ }
151
+
152
+ .successTitle {
153
+ font-size: 24px;
154
+ font-weight: 500;
155
+ margin-bottom: 12px;
156
+ font-family: "kareliaOuttakes", serif;
157
+ }
158
+
159
+ .successText {
160
+ font-size: 16px;
161
+ color: #555;
162
+ }
package/lib/index.ts CHANGED
@@ -40,6 +40,7 @@ import TextSection from "./components/TextSection";
40
40
  import Tiles from "./components/Tiles";
41
41
  import StickyTiles from "./components/StickyTiles";
42
42
  import VideoTeaser from "./components/VideoTeaser";
43
+ import GetInTouch from "./components/GetInTouch";
43
44
 
44
45
  export {
45
46
  AgencyNumbers,
@@ -84,4 +85,5 @@ export {
84
85
  Tiles,
85
86
  StickyTiles,
86
87
  VideoTeaser,
88
+ GetInTouch,
87
89
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foundry-component-library",
3
- "version": "0.2.29",
3
+ "version": "0.2.30",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",