@abcagency/hc-ui-components 1.0.0

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.
Files changed (102) hide show
  1. package/dist/globals.css +3 -0
  2. package/dist/index.js +4644 -0
  3. package/dist/output.css +784 -0
  4. package/dist/services/globals.css +3 -0
  5. package/dist/services/listingService.js +606 -0
  6. package/package.json +38 -0
  7. package/postcss.config.js +15 -0
  8. package/rollup.config.js +67 -0
  9. package/src/apis/hcApi.js +68 -0
  10. package/src/clientToken.js +9 -0
  11. package/src/components/layout/footer.js +34 -0
  12. package/src/components/layout/header.js +23 -0
  13. package/src/components/layout/layout.js +36 -0
  14. package/src/components/modules/accordions/MapAccordionItem.js +69 -0
  15. package/src/components/modules/accordions/default.js +173 -0
  16. package/src/components/modules/accordions/filterItem.js +53 -0
  17. package/src/components/modules/accordions/filters.js +44 -0
  18. package/src/components/modules/animations/slidein.js +41 -0
  19. package/src/components/modules/buttons/button-group-apply.js +75 -0
  20. package/src/components/modules/buttons/commute-pill.js +21 -0
  21. package/src/components/modules/buttons/default.js +196 -0
  22. package/src/components/modules/buttons/items-pill.js +31 -0
  23. package/src/components/modules/buttons/pill-wrapper.js +26 -0
  24. package/src/components/modules/buttons/show-all-button.js +20 -0
  25. package/src/components/modules/cards/default.js +168 -0
  26. package/src/components/modules/cards/filter.js +55 -0
  27. package/src/components/modules/dialogs/apply-dialog.js +47 -0
  28. package/src/components/modules/filter/commute.js +149 -0
  29. package/src/components/modules/filter/index.js +86 -0
  30. package/src/components/modules/filter/item.js +77 -0
  31. package/src/components/modules/filter/location.js +69 -0
  32. package/src/components/modules/filter/points-of-interest.js +43 -0
  33. package/src/components/modules/filter/radio-item.js +51 -0
  34. package/src/components/modules/filter/search.js +89 -0
  35. package/src/components/modules/filter/search.js.rej +9 -0
  36. package/src/components/modules/filter/sort.js +83 -0
  37. package/src/components/modules/form.js +362 -0
  38. package/src/components/modules/grid.js +75 -0
  39. package/src/components/modules/icon.js +33 -0
  40. package/src/components/modules/jobListing/listing-details.js +87 -0
  41. package/src/components/modules/jumbotron.js +81 -0
  42. package/src/components/modules/maps/info-window-card.js +17 -0
  43. package/src/components/modules/maps/info-window-content.js +60 -0
  44. package/src/components/modules/maps/list/field-mapper.js +113 -0
  45. package/src/components/modules/maps/list/header-item.js +90 -0
  46. package/src/components/modules/maps/list/header.js +46 -0
  47. package/src/components/modules/maps/list/index.js +104 -0
  48. package/src/components/modules/maps/list/item-expand-card/index.js +21 -0
  49. package/src/components/modules/maps/list/item-expand-card/recruiter-contact-nav.js +48 -0
  50. package/src/components/modules/maps/list/item-expand-card/recruiter-details.js +67 -0
  51. package/src/components/modules/maps/list/item-expand-card/recruiter-headshot.js +22 -0
  52. package/src/components/modules/maps/list/list-item/index.js +133 -0
  53. package/src/components/modules/maps/map-list.js +73 -0
  54. package/src/components/modules/maps/map-marker.js +84 -0
  55. package/src/components/modules/maps/map.js +218 -0
  56. package/src/components/modules/maps/place-marker.js +41 -0
  57. package/src/components/modules/maps/tabs.js +79 -0
  58. package/src/components/modules/navigation/nav-link.js +65 -0
  59. package/src/components/modules/navigation/navbar.js +109 -0
  60. package/src/components/modules/navigation/skip-link.js +21 -0
  61. package/src/components/modules/navigation/social.js +29 -0
  62. package/src/components/modules/sections/default.js +59 -0
  63. package/src/components/modules/sections/sectionContext.js +4 -0
  64. package/src/components/modules/video-player.js +126 -0
  65. package/src/constants/placeTypes.js +8 -0
  66. package/src/contexts/mapContext.js +116 -0
  67. package/src/contexts/mapListContext.js +212 -0
  68. package/src/contexts/placesContext.js +98 -0
  69. package/src/hooks/useClickOutside.js +16 -0
  70. package/src/hooks/useEventListener.js +25 -0
  71. package/src/hooks/useEventTracker.js +19 -0
  72. package/src/hooks/useList.js +102 -0
  73. package/src/hooks/useRefScrollProgress.js +24 -0
  74. package/src/hooks/useScript.js +63 -0
  75. package/src/hooks/useScrollDirection.js +39 -0
  76. package/src/hooks/useSectionTracker.js +95 -0
  77. package/src/hooks/useUserAgent.js +43 -0
  78. package/src/hooks/useWindowSize.js +28 -0
  79. package/src/index.css +25 -0
  80. package/src/index.js +116 -0
  81. package/src/services/configService.js +16 -0
  82. package/src/services/googlePlacesNearbyService.js +33 -0
  83. package/src/services/listingAggregatorService.js +42 -0
  84. package/src/services/listingEntityService.js +14 -0
  85. package/src/services/listingService.js +28 -0
  86. package/src/services/recruiterService.js +17 -0
  87. package/src/styles/fonts.js +0 -0
  88. package/src/styles/globals.css +25 -0
  89. package/src/tailwind/preset.default.js +15 -0
  90. package/src/tailwind/tailwind.config.js +126 -0
  91. package/src/util/arrayUtil.js +3 -0
  92. package/src/util/fieldMapper.js +19 -0
  93. package/src/util/filterUtil.js +195 -0
  94. package/src/util/loading.js +17 -0
  95. package/src/util/localStorageUtil.js +27 -0
  96. package/src/util/mapIconUtil.js +179 -0
  97. package/src/util/mapUtil.js +91 -0
  98. package/src/util/page-head.js +62 -0
  99. package/src/util/provider.js +12 -0
  100. package/src/util/sortUtil.js +33 -0
  101. package/src/util/stringUtils.js +6 -0
  102. package/src/util/urlFilterUtil.js +91 -0
@@ -0,0 +1,362 @@
1
+ import React, { useState } from 'react';
2
+ import { useForm, Controller } from 'react-hook-form';
3
+ import { yupResolver } from '@hookform/resolvers/yup';
4
+ import Slider from 'react-slider';
5
+ import * as Yup from 'yup';
6
+
7
+ let validationSchema = Yup.object().shape({
8
+ name: Yup.string()
9
+ .required("is required"),
10
+ email: Yup.string()
11
+ .email("Invalid email address format")
12
+ .required("is required"),
13
+ message: Yup.string()
14
+ .required("is required"),
15
+ transportation: Yup.array()
16
+ .min(1, "Select a transportation type"),
17
+ state: Yup.string()
18
+ .required("is required"),
19
+ distance: Yup.number()
20
+ .min(1, "is required")
21
+ });
22
+
23
+ const ContactForm = () => {
24
+ const {
25
+ register,
26
+ handleSubmit,
27
+ setValue,
28
+ control,
29
+ trigger,
30
+ reset,
31
+ formState:{ errors }
32
+ } = useForm({
33
+ mode: 'onBlur',
34
+ defaultValues: {
35
+ name: '',
36
+ email: '',
37
+ message: '',
38
+ transportation: [],
39
+ favoriteColor: 'pink',
40
+ state: '',
41
+ distance: 0
42
+ },
43
+ resolver: yupResolver(validationSchema)
44
+ });
45
+
46
+ const [isSubmitting, setIsSubmitting] = useState(false);
47
+
48
+ const onSubmit = values => {
49
+ setIsSubmitting(true);
50
+ setTimeout(() => {
51
+ alert(JSON.stringify(values, null, 2));
52
+ reset();
53
+ setIsSubmitting(false);
54
+ }, 1000);
55
+ };
56
+
57
+ const transportationOptions = ['Car', 'Boat', 'Plane'];
58
+ const favoriteColorOptions = ['blue', 'green', 'pink', 'red', 'yellow'];
59
+
60
+ return (
61
+ <form
62
+ onSubmit={handleSubmit(onSubmit)}
63
+ >
64
+ <div className="sm:grid grid-cols-2 gap-4">
65
+ <div className="mb-6">
66
+ <label
67
+ className="inline-block mb-2 text-xs font-bold uppercase"
68
+ htmlFor="name"
69
+ >
70
+ Name
71
+ </label>
72
+
73
+ {errors.name &&
74
+ <span
75
+ id="name-error"
76
+ name="name"
77
+ className="inline-block text-red-500 uppercase text-xs font-bold ml-1"
78
+ >
79
+ {errors.name?.message}
80
+ </span>
81
+ }
82
+
83
+ <input
84
+ {...register("name")}
85
+ type="text"
86
+ name="name"
87
+ placeholder="First and Last Name"
88
+ className={`w-full rounded-md transition-colors ${
89
+ errors.name ? "border-red-500" : "border-gray-800"
90
+ }`}
91
+ aria-invalid={errors.name ? 'true' : null}
92
+ aria-describedby={errors.name ? 'name-error' : null}
93
+ aria-required="true"
94
+ disabled={isSubmitting}
95
+ />
96
+ </div>
97
+
98
+ <div className="mb-6">
99
+ <label
100
+ className="inline-block mb-2 text-xs font-bold uppercase"
101
+ htmlFor="email"
102
+ >
103
+ Email
104
+ </label>
105
+
106
+ {errors.email &&
107
+ <span
108
+ id="email-error"
109
+ name="email"
110
+ className="inline-block text-red-500 uppercase text-xs font-bold ml-1"
111
+ >
112
+ {errors.email?.message}
113
+ </span>
114
+ }
115
+
116
+ <input
117
+ {...register("email")}
118
+ type="email"
119
+ name="email"
120
+ placeholder="user@domain.com"
121
+ className={`w-full rounded-md transition-colors ${
122
+ errors.email ? "border-red-500" : "border-gray-800"
123
+ }`}
124
+ aria-invalid={errors.email ? 'true' : null}
125
+ aria-describedby={errors.email? 'email-error' : null}
126
+ aria-required="true"
127
+ disabled={isSubmitting}
128
+ />
129
+ </div>
130
+ </div>
131
+
132
+ <div className="grid grid-cols-2 gap-4">
133
+ <div className="mb-6">
134
+ <h2 id="transportation-group-title" className="inline-block text-xs uppercase font-bold mb-2">Transportation</h2>
135
+
136
+ {errors.transportation &&
137
+ <span
138
+ id="transportation-error"
139
+ name="email"
140
+ className="inline-block text-red-500 uppercase text-xs font-bold ml-1"
141
+ >
142
+ {errors.transportation?.message}
143
+ </span>
144
+ }
145
+
146
+ <div role="group" aria-labelledby="transportation-group-title" className="flex flex-col items-start">
147
+ {transportationOptions.map(value => (
148
+ <label
149
+ key={value}
150
+ className="inline-flex items-center mb-3"
151
+ >
152
+ <input
153
+ {...register(`transportation`)}
154
+ id={`transportation${value}`}
155
+ value={value}
156
+ type="checkbox"
157
+ className="rounded h-5 w-5 text-indigo-700 border-gray-800 transition-colors"
158
+ />
159
+ <span className="ml-2">{value}</span>
160
+ </label>
161
+ ))}
162
+ </div>
163
+ </div>
164
+
165
+ <div className="mb-6">
166
+ <h2 id="favorite-color-group-title" className="inline-block text-xs uppercase font-bold mb-2">Favorite color</h2>
167
+
168
+ <div role="group" aria-labelledby="favorite-color-group-title" className="flex flex-col items-start">
169
+ {favoriteColorOptions.map(value => (
170
+ <label
171
+ key={value}
172
+ className="inline-flex items-center mb-3"
173
+ >
174
+ <input
175
+ {...register(`favoriteColor`)}
176
+ id={`favoriteColor${value}`}
177
+ value={value}
178
+ type="radio"
179
+ name="favoriteColor"
180
+ className="rounded-full h-5 w-5 text-indigo-700 border-gray-800 transition-colors"
181
+ />
182
+ <span className="ml-2 capitalize">{value}</span>
183
+ </label>
184
+ ))}
185
+ </div>
186
+ </div>
187
+ </div>
188
+
189
+ <div className="grid grid-cols-2 gap-4">
190
+ <div className="mb-6">
191
+ <label
192
+ className="inline-block mb-2 text-xs font-bold uppercase"
193
+ htmlFor="state"
194
+ >
195
+ State
196
+ </label>
197
+
198
+ {errors.state &&
199
+ <span
200
+ id="state-error"
201
+ name="state"
202
+ className="inline-block text-red-500 uppercase text-xs font-bold ml-1"
203
+ >
204
+ {errors.state?.message}
205
+ </span>
206
+ }
207
+
208
+ <select
209
+ {...register(`state`)}
210
+ className={`w-full rounded-md transition-colors ${
211
+ errors.state ? "border-red-500" : "border-gray-800"
212
+ }`}
213
+ aria-invalid={errors.state ? 'true' : null}
214
+ aria-describedby={errors.state ? 'state-error' : null}
215
+ aria-required="true"
216
+ disabled={isSubmitting}
217
+ >
218
+ <option value="">Select a state</option>
219
+ <option value="AL">Alabama</option>
220
+ <option value="AK">Alaska</option>
221
+ <option value="AZ">Arizona</option>
222
+ <option value="AR">Arkansas</option>
223
+ <option value="CA">California</option>
224
+ <option value="CO">Colorado</option>
225
+ <option value="CT">Connecticut</option>
226
+ <option value="DE">Delaware</option>
227
+ <option value="DC">District Of Columbia</option>
228
+ <option value="FL">Florida</option>
229
+ <option value="GA">Georgia</option>
230
+ <option value="HI">Hawaii</option>
231
+ <option value="ID">Idaho</option>
232
+ <option value="IL">Illinois</option>
233
+ <option value="IN">Indiana</option>
234
+ <option value="IA">Iowa</option>
235
+ <option value="KS">Kansas</option>
236
+ <option value="KY">Kentucky</option>
237
+ <option value="LA">Louisiana</option>
238
+ <option value="ME">Maine</option>
239
+ <option value="MD">Maryland</option>
240
+ <option value="MA">Massachusetts</option>
241
+ <option value="MI">Michigan</option>
242
+ <option value="MN">Minnesota</option>
243
+ <option value="MS">Mississippi</option>
244
+ <option value="MO">Missouri</option>
245
+ <option value="MT">Montana</option>
246
+ <option value="NE">Nebraska</option>
247
+ <option value="NV">Nevada</option>
248
+ <option value="NH">New Hampshire</option>
249
+ <option value="NJ">New Jersey</option>
250
+ <option value="NM">New Mexico</option>
251
+ <option value="NY">New York</option>
252
+ <option value="NC">North Carolina</option>
253
+ <option value="ND">North Dakota</option>
254
+ <option value="OH">Ohio</option>
255
+ <option value="OK">Oklahoma</option>
256
+ <option value="OR">Oregon</option>
257
+ <option value="PA">Pennsylvania</option>
258
+ <option value="RI">Rhode Island</option>
259
+ <option value="SC">South Carolina</option>
260
+ <option value="SD">South Dakota</option>
261
+ <option value="TN">Tennessee</option>
262
+ <option value="TX">Texas</option>
263
+ <option value="UT">Utah</option>
264
+ <option value="VT">Vermont</option>
265
+ <option value="VA">Virginia</option>
266
+ <option value="WA">Washington</option>
267
+ <option value="WV">West Virginia</option>
268
+ <option value="WI">Wisconsin</option>
269
+ <option value="WY">Wyoming</option>
270
+ </select>
271
+ </div>
272
+ <div className="mb-6 overflow-hidden">
273
+ <label
274
+ className="inline-block mb-2 text-xs font-bold uppercase"
275
+ htmlFor="distance"
276
+ >
277
+ Distance
278
+ </label>
279
+
280
+ {errors.distance &&
281
+ <span
282
+ id="distance-error"
283
+ name="distance"
284
+ className="inline-block text-red-500 uppercase text-xs font-bold ml-1"
285
+ >
286
+ {errors.distance?.message}
287
+ </span>
288
+ }
289
+
290
+ <Controller
291
+ name="distance"
292
+ control={control}
293
+ render={({ field }) =>
294
+ <>
295
+ <input
296
+ {...field}
297
+ type="hidden"
298
+ aria-invalid={errors.distance ? 'true' : null}
299
+ aria-describedby={errors.distance ? 'distance-error' : null}
300
+ aria-required="true"
301
+ />
302
+
303
+ <Slider
304
+ max={99}
305
+ className="py-4"
306
+ thumbClassName={`p-2 w-10 rounded-full bg-gray-100 text-gray-700 transform -translate-y-1/3 text-center outline-none cursor-grab focus:bg-indigo-700 focus:text-white transition-colors ${errors.distance && "!text-red-500"}`}
307
+ trackClassName="bg-gray-300 h-3 rounded-md transition-colors"
308
+ renderThumb={(props, state) => <div {...props}>{state.valueNow}</div>}
309
+ onChange={v => setValue('distance', v)}
310
+ onAfterChange={() => trigger('distance')}
311
+ />
312
+ </>
313
+ }
314
+ />
315
+ </div>
316
+ </div>
317
+
318
+ <div className="mb-6">
319
+ <label
320
+ className="inline-block mb-2 text-xs font-bold uppercase"
321
+ htmlFor="message"
322
+ >
323
+ Message
324
+ </label>
325
+
326
+ {errors.message &&
327
+ <span
328
+ id="message-error"
329
+ name="message"
330
+ className="inline-block text-red-500 uppercase text-xs font-bold ml-1"
331
+ >
332
+ {errors.message?.message}
333
+ </span>
334
+ }
335
+
336
+ <textarea
337
+ {...register(`message`)}
338
+ id="message"
339
+ placeholder="Say something..."
340
+ rows="8"
341
+ className={`w-full rounded-md transition-colors ${
342
+ errors.message ? "border-red-500" : "border-gray-800"
343
+ }`}
344
+ aria-invalid={errors.message ? 'true' : null}
345
+ aria-describedby={errors.message ? 'state-error' : null}
346
+ aria-required="true"
347
+ disabled={isSubmitting}
348
+ />
349
+ </div>
350
+
351
+ <button
352
+ type="submit"
353
+ className="px-4 py-2 text-sm font-bold text-white bg-gray-700 border-b-4 border-gray-800 rounded hover:border-gray-700 hover:bg-gray-600 transfrom disabled:bg-gray-200 disabled:text-gray-400 transition-colors"
354
+ disabled={isSubmitting}
355
+ >
356
+ {isSubmitting ? "Please wait..." : "Submit"}
357
+ </button>
358
+ </form>
359
+ );
360
+ };
361
+
362
+ export default ContactForm;
@@ -0,0 +1,75 @@
1
+ import { forwardRef } from 'react';
2
+ import { twMerge } from 'tailwind-merge';
3
+ import React from 'react'
4
+ import SlideIn from '~/components/modules/animations/slidein';
5
+
6
+ const Grid = forwardRef((props, ref) => {
7
+ const {
8
+ as = 'div',
9
+ isAnimated = true,
10
+ children,
11
+ className,
12
+ autoRows = true,
13
+ columns = 'md:grid-cols-2',
14
+ gap = 'gap-12 lg:gap-16',
15
+ ...rest
16
+ } = props;
17
+
18
+ const Container = as;
19
+
20
+ return (
21
+ isAnimated ?
22
+ <SlideIn>
23
+ <Container
24
+ ref={ref}
25
+ className={twMerge(
26
+ 'grid',
27
+ gap,
28
+ autoRows ? 'auto-rows-min' : '',
29
+ 'grid-cols-1',
30
+ columns,
31
+ className ?? ''
32
+ )}
33
+ {...rest}
34
+ >
35
+ {children}
36
+ </Container>
37
+ </SlideIn>
38
+ :
39
+ <Container
40
+ ref={ref}
41
+ className={twMerge(
42
+ 'grid',
43
+ gap,
44
+ autoRows ? 'auto-rows-min' : '',
45
+ 'grid-cols-1',
46
+ columns,
47
+ className ?? ''
48
+ )}
49
+ {...rest}
50
+ >
51
+ {children}
52
+ </Container>
53
+ );
54
+ });
55
+
56
+ export const GridItem = ({
57
+ as = 'div',
58
+ children,
59
+ className
60
+ }) => {
61
+ const Container = as;
62
+
63
+ return (
64
+ <Container
65
+ className={className ?? ''}
66
+ >
67
+ {children}
68
+ </Container>
69
+ );
70
+ };
71
+
72
+ Grid.Item = GridItem;
73
+
74
+ Grid.displayName = 'Grid';
75
+ export default Grid;
@@ -0,0 +1,33 @@
1
+ import { Icon } from '@iconify/react';
2
+ import React from 'react'
3
+
4
+ const IconContained = ({
5
+ className,
6
+ size,
7
+ icon,
8
+ iconClasses,
9
+ title,
10
+ ...iconProps
11
+ }) => {
12
+ return (
13
+ <span
14
+ title={title}
15
+ className={`
16
+ inline-block align-middle
17
+ ${className ?? ''}
18
+ ${size ?? ''}
19
+ `}
20
+ >
21
+ <Icon
22
+ icon={icon}
23
+ className={`
24
+ ${iconClasses ?? ''}
25
+ ${size ?? ''}
26
+ `}
27
+ {...iconProps}
28
+ />
29
+ </span>
30
+ );
31
+ };
32
+
33
+ export default IconContained;
@@ -0,0 +1,87 @@
1
+ import React, { useEffect } from "react";
2
+ import RecruiterHeadshot from "../maps/list/item-expand-card/recruiter-headshot";
3
+ import RecruiterDetails from "../maps/list/item-expand-card/recruiter-details";
4
+ import ApplyButtonGroup from "../buttons/button-group-apply";
5
+ import RecruiterContactNav from "../maps/list/item-expand-card/recruiter-contact-nav";
6
+ import { useMap } from "~/contexts/mapContext";
7
+ import { useMapList } from "~/contexts/mapListContext";
8
+ import CommutePill from "../buttons/commute-pill";
9
+
10
+ const ListingDetails = ({ item, recruiters }) => {
11
+ const { travelTime } = useMap();
12
+ const { siteConfig } = useMapList();
13
+ if (!item) {
14
+ return null;
15
+ }
16
+ let matchingRecruiter = !recruiters ? null : recruiters[item?.recruiterId];
17
+ return (<div className="w-full">
18
+ <div className="grow flex flex-wrap items-center gap-4">
19
+ {matchingRecruiter?.headshot && (
20
+ <RecruiterHeadshot
21
+ image={`https:${matchingRecruiter.headshot}`}
22
+ alt={matchingRecruiter?.firstName}
23
+ className="bg-gray-300"
24
+ />
25
+ )}
26
+ {matchingRecruiter && (
27
+ <RecruiterDetails
28
+ contactNav={
29
+ <RecruiterContactNav>
30
+ {matchingRecruiter?.mobilePhone && (
31
+ <RecruiterContactNav.Button
32
+ href={`tel:${matchingRecruiter.mobilePhone}`}
33
+ title={`Call ${matchingRecruiter.mobilePhone}`}
34
+ icon="fluent:phone-32-regular"
35
+ />
36
+ )}
37
+ {matchingRecruiter?.email && (
38
+ <RecruiterContactNav.Button
39
+ href={`mailto:${matchingRecruiter.email}`}
40
+ title={`email ${matchingRecruiter.email}`}
41
+ icon="bi:envelope-at"
42
+ />
43
+ )}
44
+ {matchingRecruiter?.linkedIn && (
45
+ <RecruiterContactNav.Button
46
+ href={matchingRecruiter.linkedIn}
47
+ title="LinkedIn"
48
+ icon="ant-design:linkedin-outlined"
49
+ />
50
+ )}
51
+ </RecruiterContactNav>
52
+ }
53
+ >
54
+ {matchingRecruiter?.firstName && matchingRecruiter?.lastName && (
55
+ <RecruiterDetails.Title>
56
+ {`${matchingRecruiter?.firstName} ${matchingRecruiter?.lastName}`}
57
+ </RecruiterDetails.Title>
58
+ )}
59
+ {item.details?.recruiter?.title && (
60
+ <RecruiterDetails.Text>
61
+ {item.details.recruiter.title}
62
+ </RecruiterDetails.Text>
63
+ )}
64
+ </RecruiterDetails>
65
+ )}
66
+ <ApplyButtonGroup
67
+ useDetailsPostMessage={siteConfig.useDetailsPostMessage}
68
+ includeDialog={siteConfig.useApplyDialog}
69
+ internalApplyLink={siteConfig.internalApplyLink}
70
+ companyName={siteConfig.companyName}
71
+ applyUrl={item?.applyUrl}
72
+ itemId={item.id}
73
+ detailsUrl={item.useClientJobUrl ? item?.detailsUrl : `${siteConfig.jobsDomain}${item.id}`}
74
+ className={`
75
+ lg:flex-col lg:w-auto order-first lg:order-last md:self-center py-2 lg:p-0 lg:mb-0 border-b lg:border-none border-uiAccent/20
76
+ ${matchingRecruiter ? "lg:flex-col lg:w-auto" : "lg:flex-row"}
77
+ `}
78
+ />
79
+ </div>
80
+ <div className="w-full">
81
+ <CommutePill travelTime={travelTime} className="ml-0" />
82
+ </div>
83
+ </div>
84
+ );
85
+ };
86
+
87
+ export default ListingDetails;
@@ -0,0 +1,81 @@
1
+ import { twMerge } from 'tailwind-merge';
2
+ import React from 'react'
3
+
4
+ const Jumbotron = ({
5
+ className,
6
+ contentClasses,
7
+ image,
8
+ children,
9
+ ...rest
10
+ }) => {
11
+ return (
12
+ <section
13
+ className={twMerge(
14
+ 'relative grid grid-cols-1 auto-rows-min md:grid-rows-1 overflow-hidden bg-gray-800 text-white',
15
+ className ?? ''
16
+ )}
17
+ {...rest}
18
+ >
19
+ <div
20
+ className={twMerge(
21
+ 'md:row-span-full col-span-full grid place-content-center relative z-10 container p-4',
22
+ contentClasses ?? ''
23
+ )}
24
+ >
25
+ {children}
26
+ </div>
27
+
28
+ {image && image}
29
+ </section>
30
+ );
31
+ };
32
+
33
+ export const JumbotronTitle = ({
34
+ className,
35
+ children
36
+ }) => {
37
+ return (
38
+ <h1
39
+ className={twMerge(
40
+ 'text-3xl font-bold',
41
+ className ?? ''
42
+ )}
43
+ >
44
+ {children}
45
+ </h1>
46
+ );
47
+ };
48
+
49
+ export const JumbotronImage = ({
50
+ image,
51
+ alt,
52
+ className,
53
+ containerClassName,
54
+ ...rest
55
+ }) => {
56
+ return (
57
+ <div
58
+ className={twMerge(
59
+ 'relative order-first md:order-last row-span-full col-span-full',
60
+ containerClassName ?? ''
61
+ )}
62
+ >
63
+ <img
64
+ src={image || image.src}
65
+ width={image.width ? image.width : null}
66
+ height={image.height ? image.height : null}
67
+ alt={alt ?? ''}
68
+ className={twMerge(
69
+ 'md:col-start-1 h-full w-full object-cover object-center opacity-70 md:opacity-20',
70
+ className ?? ''
71
+ )}
72
+ {...rest}
73
+ />
74
+ </div>
75
+ );
76
+ };
77
+
78
+ Jumbotron.Title = JumbotronTitle;
79
+ Jumbotron.Image = JumbotronImage;
80
+
81
+ export default Jumbotron;
@@ -0,0 +1,17 @@
1
+ import React from 'react'
2
+
3
+ const CardInfoWindow = ({ className, content, id }) => {
4
+ return (
5
+ <div
6
+ id={id}
7
+ className={`
8
+ relative flex flex-col break-words bg-clip-border
9
+ ${className ?? ""}
10
+ `}
11
+ >
12
+ {content}
13
+ </div>
14
+ );
15
+ };
16
+
17
+ export default CardInfoWindow;