@stackshift-ui/newsletter 6.0.3 → 6.0.5-beta.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.
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@stackshift-ui/newsletter",
3
3
  "description": "",
4
- "version": "6.0.3",
4
+ "version": "6.0.5-beta.0",
5
5
  "private": false,
6
6
  "sideEffects": false,
7
7
  "main": "./dist/index.js",
8
8
  "module": "./dist/index.mjs",
9
9
  "types": "./dist/index.d.ts",
10
10
  "files": [
11
- "dist/**"
11
+ "dist/**",
12
+ "src"
12
13
  ],
13
14
  "author": "WebriQ <info@webriq.com>",
14
15
  "devDependencies": {
@@ -28,29 +29,29 @@
28
29
  "typescript": "^5.6.2",
29
30
  "vite-tsconfig-paths": "^5.0.1",
30
31
  "vitest": "^2.1.1",
31
- "@stackshift-ui/eslint-config": "6.0.2",
32
- "@stackshift-ui/typescript-config": "6.0.2"
32
+ "@stackshift-ui/eslint-config": "6.0.3-beta.0",
33
+ "@stackshift-ui/typescript-config": "6.0.3-beta.0"
33
34
  },
34
35
  "dependencies": {
35
- "@stackshift-ui/scripts": "6.0.2",
36
- "@stackshift-ui/button": "6.0.2",
37
- "@stackshift-ui/system": "6.0.2",
38
- "@stackshift-ui/form": "6.0.2",
39
- "@stackshift-ui/heading": "6.0.2",
40
- "@stackshift-ui/image": "6.0.2",
41
- "@stackshift-ui/input": "6.0.3",
42
- "@stackshift-ui/link": "6.0.2",
43
- "@stackshift-ui/section": "6.0.2",
44
- "@stackshift-ui/container": "6.0.2",
45
- "@stackshift-ui/flex": "6.0.2",
46
- "@stackshift-ui/text": "6.0.2"
36
+ "@stackshift-ui/system": "6.0.4-beta.0",
37
+ "@stackshift-ui/form": "6.0.4-beta.0",
38
+ "@stackshift-ui/scripts": "6.0.3-beta.0",
39
+ "@stackshift-ui/button": "6.0.4-beta.0",
40
+ "@stackshift-ui/image": "6.0.4-beta.0",
41
+ "@stackshift-ui/text": "6.0.4-beta.0",
42
+ "@stackshift-ui/heading": "6.0.4-beta.0",
43
+ "@stackshift-ui/link": "6.0.4-beta.0",
44
+ "@stackshift-ui/container": "6.0.4-beta.0",
45
+ "@stackshift-ui/flex": "6.0.4-beta.0",
46
+ "@stackshift-ui/input": "6.0.5-beta.0",
47
+ "@stackshift-ui/section": "6.0.4-beta.0"
47
48
  },
48
49
  "peerDependencies": {
49
50
  "@types/react": "16.8 - 19",
50
51
  "next": "10 - 14",
51
52
  "react": "16.8 - 19",
52
53
  "react-dom": "16.8 - 19",
53
- "@stackshift-ui/system": ">=0.0.0"
54
+ "@stackshift-ui/system": ">=6.0.4-beta.0"
54
55
  },
55
56
  "peerDependenciesMeta": {
56
57
  "next": {
@@ -0,0 +1,42 @@
1
+ import { Logo } from "../types";
2
+
3
+ // WebriQ form redirect thank you page on successful submission
4
+ export const thankYouPageLink = (link: any) => {
5
+ if (!link) {
6
+ return "/thank-you";
7
+ } else {
8
+ if (link?.linkType === "linkInternal") {
9
+ return `/${link?.internalLink}`;
10
+ } else {
11
+ return link?.externalLink;
12
+ }
13
+ }
14
+ };
15
+
16
+ export function getInputType(
17
+ type?: string | undefined,
18
+ ): "text" | "email" | "password" | "number" | undefined {
19
+ switch (type) {
20
+ case "inputEmail":
21
+ return "email";
22
+ case "inputPassword":
23
+ return "password";
24
+ case "inputNumber":
25
+ return "number";
26
+ default:
27
+ return "text";
28
+ }
29
+ }
30
+
31
+ export const logoLink = (logo: Logo) => {
32
+ if (logo?.internalLink && logo?.type === "linkInternal") {
33
+ if (logo?.internalLink?.toLowerCase()?.includes("home")) {
34
+ return "/";
35
+ }
36
+ return `/${logo.internalLink}`;
37
+ } else if (logo?.externalLink && logo?.type === "linkExternal") {
38
+ return logo?.externalLink ?? "/";
39
+ } else {
40
+ return "/";
41
+ }
42
+ };
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ "use client";
2
+
3
+ // component exports
4
+ export * from "./newsletter";
5
+ export * from "./newsletter_a";
6
+ export * from "./newsletter_b";
@@ -0,0 +1,13 @@
1
+ import { cleanup, render, screen } from "@testing-library/react";
2
+ import { afterEach, describe, test } from "vitest";
3
+ import { Newsletter } from "./newsletter";
4
+
5
+ describe.concurrent("newsletter", () => {
6
+ afterEach(cleanup);
7
+
8
+ test.skip("Dummy test - test if renders without errors", ({ expect }) => {
9
+ const clx = "my-class";
10
+ render(<Newsletter />);
11
+ expect(screen.getByTestId("{ kebabCase name }}").classList).toContain(clx);
12
+ });
13
+ });
@@ -0,0 +1,32 @@
1
+ import React, { lazy } from "react";
2
+ import { Form, Logo, SectionsProps } from "./types";
3
+
4
+ const Variants = {
5
+ variant_a: lazy(() => import("./newsletter_a")),
6
+ variant_b: lazy(() => import("./newsletter_b")),
7
+ };
8
+
9
+ export interface NewsletterProps {
10
+ logo?: Logo | null;
11
+ title?: string | null;
12
+ description?: string | null;
13
+ form?: Form | null;
14
+ }
15
+
16
+ const displayName = "Newsletter";
17
+
18
+ export const Newsletter: React.FC<SectionsProps> = ({ data }) => {
19
+ const variant = data?.variant;
20
+ const Variant = variant && Variants?.[variant as keyof typeof Variants];
21
+
22
+ const props = {
23
+ logo: data?.variants?.logo,
24
+ title: data?.variants?.title,
25
+ description: data?.variants?.description,
26
+ form: data?.variants?.form,
27
+ };
28
+
29
+ return Variant ? <Variant {...props} /> : null;
30
+ };
31
+
32
+ Newsletter.displayName = displayName;
@@ -0,0 +1,125 @@
1
+ import React from "react";
2
+ import { Button } from "@stackshift-ui/button";
3
+ import { Form } from "@stackshift-ui/form";
4
+ import { Heading } from "@stackshift-ui/heading";
5
+ import { Image } from "@stackshift-ui/image";
6
+ import { Input } from "@stackshift-ui/input";
7
+ import { Text } from "@stackshift-ui/text";
8
+ import { Link } from "@stackshift-ui/link";
9
+ import { Section } from "@stackshift-ui/section";
10
+ import { Container } from "@stackshift-ui/container";
11
+ import { Flex } from "@stackshift-ui/flex";
12
+
13
+ import { Form as FormFields, Logo } from "./types";
14
+ import { getInputType, logoLink, thankYouPageLink } from "./helper";
15
+ import { NewsletterProps } from ".";
16
+
17
+ export default function Newsletter_A({
18
+ logo,
19
+ title,
20
+ description,
21
+ form,
22
+ }: NewsletterProps): React.JSX.Element {
23
+ return (
24
+ <Section className="py-20 bg-background">
25
+ <Container maxWidth={1280}>
26
+ <Container maxWidth={576} className="text-center">
27
+ <LogoSection logo={logo} />
28
+ <TitleAndDescriptionText title={title} description={description} />
29
+ <NewsletterForm
30
+ id={form?.id ?? undefined}
31
+ fields={form?.fields}
32
+ buttonLabel={form?.buttonLabel}
33
+ thankYouPage={form?.thankYouPage}
34
+ />
35
+ </Container>
36
+ </Container>
37
+ </Section>
38
+ );
39
+ }
40
+
41
+ function LogoSection({ logo }: { logo?: Logo | null }) {
42
+ if (!logo) return null;
43
+
44
+ return (
45
+ <Link
46
+ aria-label={logoLink(logo) === "/" ? "Go to home page" : `Go to ${logoLink(logo)}`}
47
+ className="inline-block mb-6 text-3xl font-bold leading-none"
48
+ href={logoLink(logo)}
49
+ target={logo?.linkTarget}
50
+ rel={logo?.linkTarget === "_blank" ? "noopener noreferrer" : ""}>
51
+ <Image
52
+ src={logo?.image}
53
+ alt={logo.alt ?? "newsletter-logo"}
54
+ width={48}
55
+ height={48}
56
+ className="inline-block mb-6 text-3xl font-bold leading-none"
57
+ />
58
+ </Link>
59
+ );
60
+ }
61
+
62
+ function TitleAndDescriptionText({
63
+ title,
64
+ description,
65
+ }: {
66
+ title?: string | null;
67
+ description?: string | null;
68
+ }) {
69
+ return (
70
+ <React.Fragment>
71
+ {title && (
72
+ <Heading fontSize="2xl" className="mb-3 text-primary">
73
+ {title}
74
+ </Heading>
75
+ )}
76
+ {description && (
77
+ <Text muted className="my-4">
78
+ {description}
79
+ </Text>
80
+ )}
81
+ </React.Fragment>
82
+ );
83
+ }
84
+
85
+ function NewsletterForm({ id, fields, thankYouPage, buttonLabel }: FormFields) {
86
+ const hasFields = Array.isArray(fields) && fields.length > 0;
87
+
88
+ if (!hasFields) return null;
89
+
90
+ return (
91
+ <Form
92
+ id={id ?? undefined}
93
+ name="NewsletterA-Form"
94
+ className="form-newsletter"
95
+ thankyouPage={thankYouPageLink(thankYouPage)}>
96
+ <Flex align="center" gap={2} className="max-w-md mx-auto">
97
+ <Input
98
+ variant="outline"
99
+ noLabel
100
+ ariaLabel={fields[0]?.placeholder ?? fields[0]?.name}
101
+ className="flex-grow w-full"
102
+ type={getInputType(fields[0]?.type)}
103
+ placeholder={fields[0]?.placeholder}
104
+ name={fields[0]?.name}
105
+ required={fields[0]?.isRequired}
106
+ />
107
+
108
+ <div>
109
+ <div className="webriq-recaptcha" />
110
+ </div>
111
+ {buttonLabel && (
112
+ <Button
113
+ as="button"
114
+ ariaLabel={buttonLabel ?? "Newsletter form submit button"}
115
+ type="submit"
116
+ className="w-1/2 text-white">
117
+ {buttonLabel}
118
+ </Button>
119
+ )}
120
+ </Flex>
121
+ </Form>
122
+ );
123
+ }
124
+
125
+ export { Newsletter_A };
@@ -0,0 +1,137 @@
1
+ import { Button } from "@stackshift-ui/button";
2
+ import { Form } from "@stackshift-ui/form";
3
+ import { Heading } from "@stackshift-ui/heading";
4
+ import { Image } from "@stackshift-ui/image";
5
+ import { Input } from "@stackshift-ui/input";
6
+ import { Text } from "@stackshift-ui/text";
7
+ import { Link } from "@stackshift-ui/link";
8
+ import { Section } from "@stackshift-ui/section";
9
+ import { Container } from "@stackshift-ui/container";
10
+ import { Flex } from "@stackshift-ui/flex";
11
+ import React from "react";
12
+
13
+ import { Form as FormFields, Logo } from "./types";
14
+ import { getInputType, logoLink, thankYouPageLink } from "./helper";
15
+ import { NewsletterProps } from ".";
16
+
17
+ export default function Newsletter_B({
18
+ logo,
19
+ title,
20
+ description,
21
+ form,
22
+ }: NewsletterProps): React.JSX.Element {
23
+ return (
24
+ <Section className="mx-auto w-full py-20 bg-background">
25
+ <Container maxWidth={1280}>
26
+ <Flex wrap align="center">
27
+ <div className="w-full mb-4 text-center lg:mr-8 lg:w-auto">
28
+ <Flex align="center" justify="center" className="mx-auto">
29
+ <LogoSection logo={logo} />
30
+ </Flex>
31
+ </div>
32
+ <Container
33
+ maxWidth={412}
34
+ className="mx-auto px-4 w-full mb-6 text-center lg:ml-0 lg:text-left">
35
+ <TitleAndDescriptionText title={title} description={description} />
36
+ </Container>
37
+ <div className="w-full lg:w-[35%]">
38
+ <NewsletterForm
39
+ {...{
40
+ id: form?.id,
41
+ fields: form?.fields,
42
+ thankYouPage: form?.thankYouPage,
43
+ buttonLabel: form?.buttonLabel,
44
+ }}
45
+ />
46
+ </div>
47
+ </Flex>
48
+ </Container>
49
+ </Section>
50
+ );
51
+ }
52
+
53
+ function LogoSection({ logo }: { logo?: Logo | null }) {
54
+ if (!logo) return null;
55
+
56
+ return (
57
+ <Link
58
+ aria-label={logoLink(logo) === "/" ? "Go to home page" : `Go to ${logoLink(logo)}`}
59
+ className="inline-block mb-6 text-3xl font-bold leading-none"
60
+ href={logoLink(logo)}
61
+ target={logo?.linkTarget}
62
+ rel={logo?.linkTarget === "_blank" ? "noopener noreferrer" : ""}>
63
+ <Image
64
+ src={logo?.image}
65
+ alt={logo.alt ?? "newsletter-logo"}
66
+ width={48}
67
+ height={48}
68
+ className="inline-block mb-6 text-3xl font-bold leading-none"
69
+ />
70
+ </Link>
71
+ );
72
+ }
73
+
74
+ function TitleAndDescriptionText({
75
+ title,
76
+ description,
77
+ }: {
78
+ title?: string | null;
79
+ description?: string | null;
80
+ }) {
81
+ return (
82
+ <React.Fragment>
83
+ {title && (
84
+ <Heading fontSize="2xl" className="text-primary">
85
+ {title}
86
+ </Heading>
87
+ )}
88
+ {description && (
89
+ <Text className="my-4 leading-loose" muted>
90
+ {description}
91
+ </Text>
92
+ )}
93
+ </React.Fragment>
94
+ );
95
+ }
96
+
97
+ function NewsletterForm({ id, fields, thankYouPage, buttonLabel }: FormFields) {
98
+ const hasFields = Array.isArray(fields) && fields.length > 0;
99
+
100
+ if (!hasFields) return null;
101
+
102
+ return (
103
+ <Form
104
+ id={id ?? undefined}
105
+ name="NewsletterB-Form"
106
+ className="form-newsletter"
107
+ thankyouPage={thankYouPageLink(thankYouPage)}>
108
+ <Flex align="center" gap={2} className="max-w-md mx-auto">
109
+ <Input
110
+ variant="outline"
111
+ noLabel
112
+ ariaLabel={fields[0]?.placeholder ?? fields[0]?.name}
113
+ className="flex-grow w-full"
114
+ type={getInputType(fields[0]?.type)}
115
+ placeholder={fields[0]?.placeholder}
116
+ name={fields[0]?.name}
117
+ required={fields[0]?.isRequired}
118
+ />
119
+
120
+ <div>
121
+ <div className="webriq-recaptcha" />
122
+ </div>
123
+ {buttonLabel && (
124
+ <Button
125
+ as="button"
126
+ ariaLabel={buttonLabel ?? "Newsletter form submit button"}
127
+ type="submit"
128
+ className="w-1/2 text-white">
129
+ {buttonLabel}
130
+ </Button>
131
+ )}
132
+ </Flex>
133
+ </Form>
134
+ );
135
+ }
136
+
137
+ export { Newsletter_B };
package/src/types.ts ADDED
@@ -0,0 +1,412 @@
1
+ export type StyleVariants<T extends string> = Record<T, string>;
2
+
3
+ export type Socials = "facebook" | "instagram" | "youtube" | "linkedin" | "twitter";
4
+ export interface MainImage {
5
+ image: string;
6
+ alt?: string;
7
+ }
8
+
9
+ export interface LabeledRoute extends ConditionalLink {
10
+ ariaLabel?: string;
11
+ label?: string;
12
+ linkTarget?: string;
13
+ linkType?: string;
14
+ _type?: string;
15
+ linkInternal?: any;
16
+ }
17
+ export interface ConditionalLink {
18
+ type?: string;
19
+ internalLink?: string | null;
20
+ externalLink?: string | null;
21
+ }
22
+
23
+ export interface StatItems {
24
+ label?: string;
25
+ mainImage?: MainImage;
26
+ value?: string;
27
+ _key?: string;
28
+ _type?: string;
29
+ }
30
+
31
+ export interface Logo extends ConditionalLink {
32
+ alt?: string;
33
+ linkTarget?: string;
34
+ image?: string;
35
+ }
36
+
37
+ export interface Images {
38
+ image?: string;
39
+ _key?: string;
40
+ _type?: string;
41
+ alt?: string;
42
+ }
43
+
44
+ export interface ContactDetails {
45
+ addressInfo?: string;
46
+ contactInfo?: string;
47
+ emailInfo?: string;
48
+ _key?: string;
49
+ }
50
+
51
+ export interface SocialLink {
52
+ socialMedia?: string | null;
53
+ socialMediaLink?: string | null;
54
+ _key?: string | null;
55
+ _type?: string | null;
56
+ socialMediaIcon?: {
57
+ alt?: string;
58
+ image?: string;
59
+ } | null;
60
+ socialMediaPlatform?: string | null;
61
+ }
62
+
63
+ export interface LabeledRouteWithKey extends LabeledRoute {
64
+ _key?: string;
65
+ }
66
+
67
+ export interface ArrayOfImageTitleAndText {
68
+ mainImage?: {
69
+ alt?: string;
70
+ image?: string;
71
+ };
72
+ plainText?: string;
73
+ title?: string;
74
+ _key?: string;
75
+ _type?: string;
76
+ }
77
+
78
+ export interface FeaturedItem {
79
+ description?: string;
80
+ mainImage?: MainImage;
81
+ title?: string;
82
+ subtitle?: string;
83
+ _key?: string;
84
+ _type?: string;
85
+ }
86
+
87
+ export interface ArrayOfTitleAndText {
88
+ _key?: string;
89
+ plainText?: string;
90
+ title?: string;
91
+ }
92
+
93
+ export interface BlogPost extends SanityBody {
94
+ authors?: Author[] | null;
95
+ body?: any;
96
+ categories?: Category[] | null;
97
+ excerpt?: string | null;
98
+ link?: string | null;
99
+ mainImage?: string | null;
100
+ publishedAt?: string;
101
+ seo?: Seo | null;
102
+ slug?: SanitySlug | null;
103
+ title?: string;
104
+ }
105
+
106
+ export interface Seo {
107
+ _type?: string;
108
+ seoTitle?: string;
109
+ seoDescription?: string;
110
+ seoImage?: string;
111
+ seoKeywords?: string;
112
+ seoSynonyms?: string;
113
+ }
114
+
115
+ export interface SanitySlug {
116
+ current?: string;
117
+ _type?: "slug";
118
+ }
119
+
120
+ export interface SanityBody {
121
+ _createdAt?: string;
122
+ _id?: string;
123
+ _rev?: string;
124
+ _type?: string;
125
+ _updatedAt?: string;
126
+ }
127
+
128
+ export interface Author extends SanityBody {
129
+ link?: string | null;
130
+ bio?: string | null;
131
+ name?: string | null;
132
+ slug?: SanitySlug | null;
133
+ image?: string | null;
134
+ profile?: {
135
+ alt: string;
136
+ image: string;
137
+ } | null;
138
+ }
139
+
140
+ export interface Category extends SanityBody {
141
+ title?: string;
142
+ }
143
+
144
+ export interface Form {
145
+ id?: string | null;
146
+ buttonLabel?: string | null;
147
+ name?: string | null;
148
+ subtitle?: string | null;
149
+ fields?: FormFields[] | null;
150
+ thankYouPage?: ThankYouPage | null;
151
+ }
152
+
153
+ export interface FormFields {
154
+ name?: string;
155
+ placeholder?: string;
156
+ pricingType?: string;
157
+ type?: FormTypes;
158
+ _key?: string;
159
+ _type?: string;
160
+ isRequired?: boolean;
161
+ label?: string;
162
+ items?: string[];
163
+ }
164
+
165
+ export type FormTypes =
166
+ | "inputText"
167
+ | "inputEmail"
168
+ | "inputPassword"
169
+ | "inputNumber"
170
+ | "textarea"
171
+ | "inputFile"
172
+ | "inputRadio"
173
+ | "inputCheckbox"
174
+ | "inputSelect";
175
+
176
+ export interface ThankYouPage {
177
+ externalLink?: string | null;
178
+ internalLink?: string | null;
179
+ linkInternal?: any;
180
+ linkTarget?: string;
181
+ linkType?: string;
182
+ type?: string;
183
+ }
184
+
185
+ //Used on different sections
186
+ export interface SectionsProps {
187
+ template?: Template;
188
+ data?: Sections;
189
+ variant?: string | null | undefined;
190
+ schema?: Variants;
191
+ }
192
+
193
+ export interface Sections extends SanityBody {
194
+ label?: string;
195
+ variant?: string;
196
+ variants?: Variants;
197
+ _key?: string;
198
+ }
199
+
200
+ //*EDIT THIS SECTION WHEN CREATING/UPDATING SCHEMAS ON STUDIO */
201
+ export interface Variants {
202
+ template?: Template;
203
+ multipleMenus?: any;
204
+ arrayOfTitleAndText?: ArrayOfTitleAndText[] | null;
205
+ logo?: Logo | null;
206
+ primaryButton?: LabeledRoute | null;
207
+ secondaryButton?: LabeledRoute | null;
208
+ routes?: LabeledRouteWithKey[] | null;
209
+ menu?: LabeledRouteWithKey[] | null;
210
+ plans?: Plans[] | null;
211
+ formLinks?: LabeledRouteWithKey[] | null;
212
+ portfolios?: Portfolios[] | null;
213
+ portfoliosWithCategories?: PortfoliosWithCategories[] | null;
214
+ length?: number;
215
+ signInLink?: LabeledRoute | null;
216
+ signinLink?: LabeledRoute | null;
217
+ tags?: string[] | null;
218
+ posts?: BlogPost[] | null;
219
+ blogsPerPage?: number | null;
220
+ form?: Form | null;
221
+ collections?: Collection | null;
222
+ products?: CollectionProduct | null;
223
+ allProducts?: Collection[];
224
+ subtitle?: string | null;
225
+ caption?: string | null;
226
+ title?: string | null;
227
+ plainText?: string | null;
228
+ contactDescription?: string | null;
229
+ officeInformation?: string | null;
230
+ contactEmail?: string | null;
231
+ contactNumber?: string | null;
232
+ socialLinks?: SocialLink[] | null;
233
+ block?: any;
234
+ heading?: string | null;
235
+ acceptButtonLabel?: string | null;
236
+ declineButtonLabel?: string | null;
237
+ faqsWithCategories?: FaqsWithCategory[] | null;
238
+ faqs?: AskedQuestion[] | null;
239
+ arrayOfImageTitleAndText?: ArrayOfImageTitleAndText[] | null;
240
+ description?: string | null;
241
+ featuredItems?: FeaturedItem[] | null;
242
+ images?: Images[] | null;
243
+ contactDetails?: ContactDetails[] | null;
244
+ copyright?: string | null;
245
+ mainImage?: MainImage | null;
246
+ youtubeLink?: string | null;
247
+ banner?: any;
248
+ stats?: StatItems[] | null;
249
+ teams?: Team[] | null;
250
+ testimonials?: Testimonial[] | null;
251
+ selectStripeAccount?: string;
252
+ annualBilling?: string;
253
+ monthlyBilling?: string;
254
+ productDetails?: ProductDetail[];
255
+ btnLabel?: string;
256
+ selectAccount?: string;
257
+ hashtags?: string[];
258
+ numberOfPosts?: number;
259
+ text?: string;
260
+ button?: LabeledRoute;
261
+ features?: string[];
262
+ config?: {
263
+ enableAnalytics: boolean;
264
+ cookiePolicy?: {
265
+ siteName: string;
266
+ cookiePolicyPage: Reference;
267
+ };
268
+ consentModalPosition?: string;
269
+ };
270
+ contactLink?: LabeledRoute;
271
+ }
272
+
273
+ export interface Template {
274
+ bg?: string;
275
+ color?: string;
276
+ }
277
+
278
+ export type Plans = {
279
+ _key?: string | null;
280
+ _type?: "planItems" | null;
281
+ checkoutButtonName?: string | null;
282
+ description?: string | null;
283
+ monthlyPrice?: string | null;
284
+ planType?: string | null;
285
+ yearlyPrice?: string | null;
286
+ planIncludes?: string[] | null;
287
+ primaryButton?: LabeledRoute | null;
288
+ } & Record<string, string>;
289
+
290
+ export interface Portfolios {
291
+ dateAdded?: string | null;
292
+ mainImage?: {
293
+ image?: string | null;
294
+ alt?: string | null;
295
+ } | null;
296
+ primaryButton?: LabeledRoute | null;
297
+ title?: string | null;
298
+ _key?: string | null;
299
+ _type?: string | null;
300
+ }
301
+
302
+ export interface PortfoliosWithCategories {
303
+ category?: string | null;
304
+ content?: Content[] | null;
305
+ primaryButton?: LabeledRoute | null;
306
+ _key?: string | null;
307
+ _type?: string | null;
308
+ }
309
+
310
+ export interface Content extends Portfolios {
311
+ description?: string | null;
312
+ subtitle?: string | null;
313
+ }
314
+
315
+ export interface Collection extends SanityBody {
316
+ collectionInfoVariant?: {
317
+ variant?: string;
318
+ } | null;
319
+ name?: string | null;
320
+ products?: CollectionProduct[] | null;
321
+ sections?: any; //todo
322
+ seo?: Seo | null;
323
+ slug?: SanitySlug | null;
324
+ }
325
+
326
+ export interface CollectionProduct extends SanityBody {
327
+ compareToPrice?: number | null;
328
+ description?: string | null;
329
+ ecwidProductId?: number | null;
330
+ name?: string | null;
331
+ price?: number | null;
332
+ productInfo?: ProductInfo | null;
333
+ productInfoVariant?: {
334
+ variant?: string;
335
+ } | null;
336
+ sections?: any; //todo
337
+ seo?: Seo | null;
338
+ slug?: SanitySlug | null;
339
+ }
340
+
341
+ //TODO, RECHECK PRODUCT INFO DATA FROM SANITY
342
+ interface ProductInfo {
343
+ btnLabel?: string | null;
344
+ images?: ProductInfoImage[] | null;
345
+ productDetails?: ProductDetail[] | null;
346
+ socialLinks?: SocialLink[] | null;
347
+ subtitle?: string | null;
348
+ }
349
+
350
+ //TODO, RECHECK PRODUCT INFO DATA FROM SANITY
351
+ export interface ProductDetail {
352
+ blockContent?: any;
353
+ contentType?: string;
354
+ tabName?: string;
355
+ _key?: string;
356
+ [key: string]: any;
357
+ }
358
+ interface ProductInfoImage {
359
+ alt?: string | null;
360
+ _key: string;
361
+ _type: string;
362
+ image?: string | null;
363
+ }
364
+
365
+ export interface FaqsWithCategory {
366
+ askedQuestions?: AskedQuestion[] | null;
367
+ category?: string | null;
368
+ _key?: string;
369
+ _type?: string;
370
+ }
371
+
372
+ export interface AskedQuestion {
373
+ answer?: string | null;
374
+ question?: string | null;
375
+ hidden?: boolean;
376
+ _key?: string;
377
+ _type?: string;
378
+ }
379
+
380
+ export interface Team {
381
+ jobTitle?: string;
382
+ mainImage?: MainImage;
383
+ name?: string;
384
+ plainText?: string;
385
+ _key?: string;
386
+ _type?: string;
387
+ }
388
+
389
+ export interface Testimonial {
390
+ jobTitle?: string;
391
+ mainImage?: MainImage;
392
+ name?: string;
393
+ rating?: string;
394
+ testimony?: string;
395
+ _key?: string;
396
+ _type?: string;
397
+ }
398
+
399
+ export declare interface Reference {
400
+ _type: string;
401
+ _ref: string;
402
+ _key?: string;
403
+ _weak?: boolean;
404
+ _strengthenOnPublish?: {
405
+ type: string;
406
+ weak?: boolean;
407
+ template?: {
408
+ id: string;
409
+ params: Record<string, string | number | boolean>;
410
+ };
411
+ };
412
+ }