@levo-so/blocks 0.1.54 → 0.1.58

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 (117) hide show
  1. package/package.json +2 -2
  2. package/src/blocks/about-us/about-us-1.schema.ts +14 -0
  3. package/src/blocks/about-us/about-us-1.tsx +4 -2
  4. package/src/blocks/about-us/about-us-2.schema.ts +48 -0
  5. package/src/blocks/about-us/about-us-2.tsx +6 -0
  6. package/src/blocks/blogs/blog-listing-1.schema.ts +10 -0
  7. package/src/blocks/blogs/blog-listing-2.schema.ts +42 -162
  8. package/src/blocks/blogs/blog-listing-2.tsx +7 -0
  9. package/src/blocks/blogs/blog-listing-3.schema.ts +9 -0
  10. package/src/blocks/blogs/blog-post-1.schema.ts +7 -1
  11. package/src/blocks/blogs/blog-post-1.tsx +1 -1
  12. package/src/blocks/blogs/blog-post-2.schema.ts +464 -28
  13. package/src/blocks/blogs/blog-post-2.tsx +6 -13
  14. package/src/blocks/blogs/blog-post-3.schema.ts +42 -0
  15. package/src/blocks/blogs/blog-post-3.tsx +4 -1
  16. package/src/blocks/calendar/calendar-1.schema.ts +537 -0
  17. package/src/blocks/calendar/calendar-1.tsx +145 -0
  18. package/src/blocks/cards/cards-10.schema.ts +52 -4
  19. package/src/blocks/cards/cards-10.tsx +13 -1
  20. package/src/blocks/cards/cards-14.schema.ts +532 -0
  21. package/src/blocks/cards/cards-14.tsx +54 -0
  22. package/src/blocks/cards/cards-15.schema.ts +277 -0
  23. package/src/blocks/cards/cards-15.tsx +40 -0
  24. package/src/blocks/cards/cards-6.schema.ts +46 -0
  25. package/src/blocks/cards/cards-6.tsx +27 -1
  26. package/src/blocks/cards/cards-7.tsx +2 -0
  27. package/src/blocks/carousel/carousel-2.schema.ts +1128 -0
  28. package/src/blocks/carousel/carousel-2.tsx +159 -0
  29. package/src/blocks/content/content-5.schema.ts +112 -6
  30. package/src/blocks/content/content-5.tsx +19 -3
  31. package/src/blocks/content/content-6.schema.ts +16 -3
  32. package/src/blocks/content/content-6.tsx +1 -0
  33. package/src/blocks/content/content-8.schema.ts +125 -0
  34. package/src/blocks/content/content-8.tsx +27 -0
  35. package/src/blocks/content/content-9.schema.ts +2729 -0
  36. package/src/blocks/content/content-9.tsx +91 -0
  37. package/src/blocks/cta/cta-2.schema.ts +46 -4
  38. package/src/blocks/cta/cta-2.tsx +9 -1
  39. package/src/blocks/embed/embed-1.schema.ts +100 -0
  40. package/src/blocks/event/ClientOnly.tsx +27 -0
  41. package/src/blocks/event/event-details.tsx +10 -3
  42. package/src/blocks/event/event-listing-3.tsx +9 -2
  43. package/src/blocks/event/event-listing-4.tsx +11 -2
  44. package/src/blocks/event/event-listing.tsx +11 -4
  45. package/src/blocks/faq/faq-1.schema.ts +58 -1
  46. package/src/blocks/faq/faq-1.tsx +18 -1
  47. package/src/blocks/faq/faq-2.tsx +2 -1
  48. package/src/blocks/faq/faq-3.schema.ts +6 -1
  49. package/src/blocks/faq/faq-3.tsx +1 -0
  50. package/src/blocks/features/features-1/features-1.schema.ts +2 -0
  51. package/src/blocks/features/features-1/variants/index.ts +2 -0
  52. package/src/blocks/features/features-1/variants/stylized-cards-v3.ts +451 -0
  53. package/src/blocks/features/features-4.schema.ts +358 -20
  54. package/src/blocks/features/features-4.tsx +3 -1
  55. package/src/blocks/features/features-6.tsx +2 -0
  56. package/src/blocks/filter-listing/filter-listing-1.schema.ts +614 -0
  57. package/src/blocks/filter-listing/filter-listing-1.tsx +128 -0
  58. package/src/blocks/footer/footer-6.schema.ts +2 -2
  59. package/src/blocks/hero/hero-11.schema.ts +849 -0
  60. package/src/blocks/hero/hero-11.tsx +59 -0
  61. package/src/blocks/hero/hero-12.schema.ts +712 -0
  62. package/src/blocks/hero/hero-12.tsx +76 -0
  63. package/src/blocks/hero/hero-13.schema.ts +238 -0
  64. package/src/blocks/hero/hero-13.tsx +31 -0
  65. package/src/blocks/hero/hero-4.tsx +2 -0
  66. package/src/blocks/hero/hero-5.tsx +2 -0
  67. package/src/blocks/hero/hero-7.tsx +2 -1
  68. package/src/blocks/hero/hero-8.tsx +2 -0
  69. package/src/blocks/hero/hero-9.schema.ts +5 -0
  70. package/src/blocks/hero/hero-9.tsx +2 -0
  71. package/src/blocks/index.ts +27 -0
  72. package/src/blocks/navbar/navbar-1.schema.ts +6 -6
  73. package/src/blocks/navbar/navbar-1.tsx +6 -7
  74. package/src/blocks/navbar/navbar-2.schema.ts +9 -9
  75. package/src/blocks/navbar/navbar-2.tsx +7 -8
  76. package/src/blocks/navbar/navbar-3.schema.ts +9 -9
  77. package/src/blocks/navbar/navbar-3.tsx +139 -114
  78. package/src/blocks/polling/polling-1.schema.ts +134 -0
  79. package/src/blocks/polling/polling-1.tsx +466 -0
  80. package/src/blocks/products/products-listing-2.schema.ts +596 -0
  81. package/src/blocks/products/products-listing-2.tsx +56 -0
  82. package/src/blocks/products/products-listing-3.schema.ts +818 -0
  83. package/src/blocks/products/products-listing-3.tsx +125 -0
  84. package/src/blocks/profile/profile-2.schema.ts +505 -0
  85. package/src/blocks/profile/profile-2.tsx +64 -0
  86. package/src/blocks/profile/profile-3.schema.ts +867 -0
  87. package/src/blocks/profile/profile-3.tsx +98 -0
  88. package/src/blocks/services/service-1.schema.ts +1743 -0
  89. package/src/blocks/services/service-1.tsx +139 -0
  90. package/src/blocks/services/service-2.schema.ts +433 -0
  91. package/src/blocks/services/service-2.tsx +98 -0
  92. package/src/blocks/services/service-3.schema.ts +631 -0
  93. package/src/blocks/services/service-3.tsx +135 -0
  94. package/src/blocks/tabs/tab-1.schema.ts +831 -0
  95. package/src/blocks/tabs/tab-1.tsx +126 -0
  96. package/src/blocks/tabs/tab-2.schema.ts +767 -0
  97. package/src/blocks/tabs/tab-2.tsx +60 -0
  98. package/src/blocks/team/team-3.schema.ts +5 -1
  99. package/src/blocks/team/team-3.tsx +7 -0
  100. package/src/blocks/team/team-4.schema.ts +17 -13
  101. package/src/blocks/team/team-4.tsx +4 -1
  102. package/src/blocks/team/team-5.schema.ts +369 -0
  103. package/src/blocks/team/team-5.tsx +38 -0
  104. package/src/blocks/testimonial/testimonial-1.tsx +0 -1
  105. package/src/blocks/testimonial/testimonial-2.tsx +2 -1
  106. package/src/blocks/testimonial/testimonial-3.tsx +2 -0
  107. package/src/blocks/testimonial/testimonial-4.tsx +2 -1
  108. package/src/blocks/testimonial/testimonial-5.tsx +2 -0
  109. package/src/blocks/testimonial/testimonial-6.tsx +2 -1
  110. package/src/blocks/testimonial/testimonial-7.schema.ts +438 -0
  111. package/src/blocks/testimonial/testimonial-7.tsx +125 -0
  112. package/src/blocks/timeline/timeline-1.schema.ts +741 -0
  113. package/src/blocks/timeline/timeline-1.tsx +52 -0
  114. package/src/blocks/users/edit-profile.schema.ts +294 -0
  115. package/src/blocks/users/edit-profile.tsx +184 -0
  116. package/src/schemas/blocks.ts +64 -12
  117. package/src/schemas/categories.ts +36 -0
@@ -0,0 +1,52 @@
1
+ import {
2
+ type ILevoBlockBaseProps,
3
+ Box,
4
+ Container,
5
+ Heading,
6
+ Image,
7
+ Section,
8
+ Typography,
9
+ } from "@levo-so/studio";
10
+
11
+ import type { ITimeline1 } from "./timeline-1.schema";
12
+
13
+ const Timeline1: React.FC<ILevoBlockBaseProps<ITimeline1>> = ({ content }) => (
14
+ <Section elementKey="layout">
15
+ <Container elementKey="header_wrapper">
16
+ <Heading elementKey="title" />
17
+ <Typography elementKey="description" />
18
+ </Container>
19
+ <Container elementKey="container">
20
+ <Box elementKey="center_line" />
21
+ <Box elementKey="events_levoGroup" data-levo_group>
22
+ {(content?.events ?? [])?.map((_, index) => (
23
+ <Box
24
+ key={index}
25
+ data-levo_group_item
26
+ elementKey={`events.${index}.wrapper`}
27
+ >
28
+ {/* Left Side Content */}
29
+ <Box elementKey={`events.${index}.content_wrapper`}>
30
+ <Typography elementKey={`events.${index}.description`} />
31
+ <Image
32
+ elementKey={`events.${index}.image`}
33
+ alt={content?.events?.[index]?.title || "Timeline event image"}
34
+ />
35
+ </Box>
36
+
37
+ {/* Timeline Dot and Line */}
38
+ <Box elementKey={`events.${index}.timeline_wrapper`}>
39
+ <Box elementKey="timeline_dot_wrapper">
40
+ <Box elementKey={`events.${index}.timeline_line`} />
41
+ <Box elementKey={`events.${index}.timeline_dot`} />
42
+ </Box>
43
+ <Typography elementKey={`events.${index}.year`} />
44
+ </Box>
45
+ </Box>
46
+ ))}
47
+ </Box>
48
+ </Container>
49
+ </Section>
50
+ );
51
+
52
+ export default Timeline1;
@@ -0,0 +1,294 @@
1
+ import type { IBlock } from "@levo-so/studio";
2
+
3
+ const DEFAULT_CONTENT = {
4
+ layout: null,
5
+ container: null,
6
+ header_section: null,
7
+ title: "Settings",
8
+ description: "Manage your account settings.",
9
+ profile_section: null,
10
+ content: null,
11
+ sections: [
12
+ {
13
+ cta: "Profile",
14
+ wrapper: null,
15
+ header: null,
16
+ title: "Profile",
17
+ description: "This is how others will see you on the site.",
18
+ },
19
+ ],
20
+ profile_settings_form: null,
21
+ loading_container: null,
22
+ };
23
+
24
+ export type IEditProfileContent = typeof DEFAULT_CONTENT;
25
+
26
+ export const EditProfile: IBlock = {
27
+ category_id: "users",
28
+ title: "Edit Profile",
29
+ key: "edit-profile",
30
+ version: "v1",
31
+ prompt_description:
32
+ "A comprehensive edit profile form with avatar upload, personal information fields, and additional sections for security settings. Features form validation hints and actionable buttons.",
33
+ content_schema: [
34
+ {
35
+ key: "layout",
36
+ label: "Layout",
37
+ field_interface: "LayoutWidget",
38
+ },
39
+ {
40
+ key: "container",
41
+ label: "Container",
42
+ field_interface: "LayoutWidget",
43
+ },
44
+ {
45
+ key: "header_section",
46
+ label: "Header Section",
47
+ field_interface: "BoxWidget",
48
+ },
49
+ {
50
+ key: "title",
51
+ label: "Title",
52
+ field_interface: "HeadingWidget",
53
+ },
54
+ {
55
+ key: "description",
56
+ label: "Description",
57
+ field_interface: "TypographyWidget",
58
+ },
59
+ {
60
+ key: "profile_section",
61
+ label: "Profile Section",
62
+ field_interface: "BoxWidget",
63
+ },
64
+ {
65
+ key: "sections",
66
+ label: "Sections",
67
+ field_interface: "BoxWidget",
68
+ kind: "group",
69
+ fields: [
70
+ {
71
+ key: "cta",
72
+ label: "CTA",
73
+ field_interface: "ButtonWidget",
74
+ },
75
+ {
76
+ key: "wrapper",
77
+ label: "Wrapper",
78
+ field_interface: "BoxWidget",
79
+ },
80
+ {
81
+ key: "header",
82
+ label: "Header",
83
+ field_interface: "BoxWidget",
84
+ },
85
+ {
86
+ key: "title",
87
+ label: "Title",
88
+ field_interface: "HeadingWidget",
89
+ },
90
+ {
91
+ key: "description",
92
+ label: "Description",
93
+ field_interface: "TypographyWidget",
94
+ },
95
+ ],
96
+ },
97
+ {
98
+ key: "content",
99
+ label: "Content",
100
+ field_interface: "BoxWidget",
101
+ },
102
+ {
103
+ key: "profile_settings_form",
104
+ label: "Profile Settings Form",
105
+ field_interface: "FormWidget",
106
+ },
107
+ {
108
+ key: "loading_container",
109
+ label: "Loading Container",
110
+ field_interface: "BoxWidget",
111
+ },
112
+ ],
113
+ layouts: [
114
+ {
115
+ title: "Default",
116
+ key: "default",
117
+ styles: {
118
+ layout: {
119
+ width: "100%",
120
+ "padding-top": "10xl",
121
+ "padding-bottom": "10xl",
122
+ "padding-right": "8xl",
123
+ "padding-left": "8xl",
124
+ tablet: {
125
+ "padding-top": "5xl",
126
+ "padding-bottom": "5xl",
127
+ "padding-right": "5xl",
128
+ "padding-left": "5xl",
129
+ },
130
+ mobile: {
131
+ "padding-top": "2xl",
132
+ "padding-bottom": "2xl",
133
+ "padding-right": "2xl",
134
+ "padding-left": "2xl",
135
+ },
136
+ },
137
+ container: {
138
+ width: "100%",
139
+ display: "flex",
140
+ "flex-direction": "column",
141
+ "row-gap": "xl",
142
+ tablet: {
143
+ "row-gap": "3xl",
144
+ },
145
+ mobile: {
146
+ "row-gap": "4xl",
147
+ },
148
+ },
149
+ header_section: {
150
+ "margin-bottom": "none",
151
+ "border-style": "solid",
152
+ "border-color": "brandSecondary",
153
+ "border-right-width": "0px",
154
+ "border-bottom-width": "1px",
155
+ "border-left-width": "0px",
156
+ "border-top-width": "0px",
157
+ "padding-bottom": "xl",
158
+ },
159
+ title: {
160
+ "font-weight": 700,
161
+ },
162
+ description: {
163
+ "margin-top": "5xs",
164
+ },
165
+ profile_section: {
166
+ display: "flex",
167
+ width: "100%",
168
+ "flex-grow": "1",
169
+ gap: "xl",
170
+ },
171
+ sections_levoGroup: {
172
+ display: "flex",
173
+ width: "100%",
174
+ "flex-direction": "column",
175
+ gap: "6xs",
176
+ "max-width": "235px",
177
+ },
178
+ content: {
179
+ display: "flex",
180
+ width: "100%",
181
+ },
182
+ sections: Array(1)
183
+ .fill(0)
184
+ .map(() => {
185
+ return {
186
+ cta: {},
187
+ header: {},
188
+ title: {},
189
+ description: {},
190
+ wrapper: {
191
+ width: "100%",
192
+ },
193
+ };
194
+ }),
195
+ profile_settings_form: {
196
+ "margin-top": "xl",
197
+ },
198
+ loading_container: {
199
+ display: "flex",
200
+ "flex-direction": "column",
201
+ "justify-content": "center",
202
+ "align-items": "center",
203
+ "min-height": "256px",
204
+ },
205
+ },
206
+ content: DEFAULT_CONTENT,
207
+ config: {
208
+ title: {
209
+ heading: {
210
+ level: 1,
211
+ },
212
+ selectedVariants: {
213
+ Heading_Level: "H5",
214
+ },
215
+ },
216
+ description: {
217
+ selectedVariants: {
218
+ Typography_Variants: "Body",
219
+ },
220
+ },
221
+ sections: [
222
+ {
223
+ cta: {
224
+ selectedVariants: {
225
+ Button_Variants: "Secondary",
226
+ },
227
+ },
228
+ title: {
229
+ selectedVariants: {
230
+ Heading_Level: "H6",
231
+ },
232
+ },
233
+ description: {
234
+ selectedVariants: {
235
+ Typography_Variants: "Small",
236
+ },
237
+ },
238
+ },
239
+ ],
240
+ profile_settings_form: {
241
+ form: {
242
+ collection_id: "so_levo_membership_account",
243
+ collection_name: "Membership Account",
244
+ workspace_id: "WZZKMUBH",
245
+ hidden_fields: [
246
+ // Extra Fields in headstart
247
+ "7315443834393400293",
248
+ "7315443834420559484",
249
+ "7315443834430280457",
250
+ "7315443834441059829",
251
+ // Default Fields
252
+ "_id",
253
+ "slug",
254
+ "email",
255
+ "display_email",
256
+ "reducted_email",
257
+ "organizations",
258
+ "mobile",
259
+ "reducted_mobile",
260
+ "verified_at",
261
+ "email_verified_at",
262
+ "mobile_verified_at",
263
+ "last_access_at",
264
+ "account_locked_at",
265
+ "credentials_expired_at",
266
+ "referral_count",
267
+ "referral_code",
268
+ "referred_by_account",
269
+ "referred_by_organization",
270
+ "deactivated_at",
271
+ "flagged_at",
272
+ "created_at",
273
+ "updated_at",
274
+ "onboarded_at",
275
+ "password",
276
+ "tfa_secret",
277
+ "source",
278
+ "acquisition_visit",
279
+ "acquisition_page",
280
+ "conversion_visit",
281
+ "conversion_page",
282
+ "oauth_credentials",
283
+ "attendees",
284
+ "bookings",
285
+ "deliveries",
286
+ "status",
287
+ "modified_by",
288
+ ],
289
+ },
290
+ },
291
+ },
292
+ },
293
+ ],
294
+ };
@@ -0,0 +1,184 @@
1
+ import {
2
+ type ILevoBlockBaseProps,
3
+ Box,
4
+ Button,
5
+ Container,
6
+ EditForm,
7
+ Heading,
8
+ Section,
9
+ Typography,
10
+ useAuth,
11
+ useBlockContext,
12
+ } from "@levo-so/studio";
13
+ import { useEffect, useState } from "react";
14
+ import { errorHandler, Spinner, successToast, useLevo } from "@levo-so/react";
15
+
16
+ import type { IEditProfileContent } from "./edit-profile.schema";
17
+
18
+ const EditProfile: React.FC<ILevoBlockBaseProps<IEditProfileContent>> = ({
19
+ content,
20
+ config,
21
+ }) => {
22
+ const levoClient = useLevo();
23
+
24
+ const [activeIndex, setActiveIndex] = useState<number>(0);
25
+ const [isLoading, setIsLoading] = useState<boolean>(false);
26
+ const [formData, setFormData] = useState<any>(null);
27
+ const [entry, setEntry] = useState<any>(null);
28
+ const [isFormLoading, setIsFormLoading] = useState<boolean>(true);
29
+
30
+ const { account, isAuthLoaded } = useAuth();
31
+ const { isBuilder } = useBlockContext();
32
+
33
+ const collectionKey = config?.profile_settings_form?.form?.schema?.key;
34
+ const isMembershipForm = collectionKey === "so_levo_membership_account";
35
+
36
+ useEffect(() => {
37
+ const fetchFormData = async () => {
38
+ if (!isAuthLoaded || !collectionKey || !account) {
39
+ setIsFormLoading(false);
40
+ return;
41
+ }
42
+
43
+ try {
44
+ setIsFormLoading(true);
45
+
46
+ if (isMembershipForm) {
47
+ setFormData(account ?? {});
48
+ setEntry(null);
49
+ } else {
50
+ const response =
51
+ await levoClient?.collection?.getDraftEntry(collectionKey);
52
+
53
+ const entries = response?.content?.data ?? [];
54
+
55
+ if (entries?.length > 0) {
56
+ const firstEntry = entries[0];
57
+ setEntry(firstEntry);
58
+ setFormData(firstEntry);
59
+ } else {
60
+ setFormData({});
61
+ setEntry(null);
62
+ }
63
+ }
64
+ } catch (error) {
65
+ // const levoError = getLevoError(error);
66
+ levoClient?.logger?.error("Failed to fetch form data", error);
67
+ setFormData(isMembershipForm ? (account ?? {}) : {});
68
+ } finally {
69
+ setIsFormLoading(false);
70
+ }
71
+ };
72
+
73
+ fetchFormData();
74
+ }, [isAuthLoaded, collectionKey, isMembershipForm, account, levoClient]);
75
+
76
+ const onSubmit = async (values: any) => {
77
+ if (!collectionKey) return;
78
+
79
+ setIsLoading(true);
80
+ try {
81
+ const allFields =
82
+ config?.profile_settings_form?.form?.schema?.sections?.flatMap(
83
+ (v) => v?.fields,
84
+ );
85
+ const hiddenFieldsInstance =
86
+ config?.profile_settings_form?.form?.hidden_fields ?? [];
87
+
88
+ const availableFields =
89
+ allFields
90
+ ?.filter((v) => !hiddenFieldsInstance?.includes(v?.id))
91
+ ?.map((v) => v?.key) ?? [];
92
+
93
+ const filteredValues = Object.entries(values)?.filter(([key]) =>
94
+ availableFields?.includes(key),
95
+ );
96
+
97
+ const filteredData = Object.fromEntries(filteredValues);
98
+
99
+ let response;
100
+
101
+ if (isMembershipForm) {
102
+ response = await levoClient?.membership?.updateMe(filteredData);
103
+ } else {
104
+ if (entry?._id) {
105
+ response = await levoClient?.collection?.editDraftEntry(
106
+ collectionKey,
107
+ entry._id,
108
+ filteredData,
109
+ );
110
+ } else {
111
+ response = await levoClient?.collection?.saveCollectionData({
112
+ collection_id: collectionKey,
113
+ data: filteredData,
114
+ });
115
+ }
116
+ }
117
+
118
+ if (response) {
119
+ successToast("Profile updated successfully.");
120
+ }
121
+ } catch (err: unknown) {
122
+ levoClient?.logger?.error("Failed to update profile", err);
123
+ errorHandler(err);
124
+ } finally {
125
+ setIsLoading(false);
126
+ }
127
+ };
128
+
129
+ return (
130
+ <Section elementKey="layout">
131
+ <Container elementKey="container">
132
+ <Box elementKey="header_section">
133
+ <Heading elementKey="title" />
134
+ <Typography elementKey="description" />
135
+ </Box>
136
+ <Box elementKey="profile_section">
137
+ <Box elementKey="sections_levoGroup" data-levo_group>
138
+ {(content?.sections ?? [])?.map((_: any, index: number) => {
139
+ return (
140
+ <Button
141
+ data-levo_group_item
142
+ key={`sections-${index}`}
143
+ elementKey={`sections.${index}.cta`}
144
+ onClick={() => setActiveIndex(index)}
145
+ />
146
+ );
147
+ })}
148
+ </Box>
149
+ <Box elementKey="content">
150
+ <Box elementKey={`sections.${activeIndex}.wrapper`}>
151
+ <Box elementKey={`sections.${activeIndex}.header`}>
152
+ <Heading elementKey={`sections.${activeIndex}.title`} />
153
+ <Typography
154
+ elementKey={`sections.${activeIndex}.description`}
155
+ />
156
+ </Box>
157
+
158
+ <>
159
+ {isFormLoading ? (
160
+ <Box elementKey="loading_container">
161
+ <Spinner />
162
+ </Box>
163
+ ) : formData ? (
164
+ <EditForm
165
+ elementKey="profile_settings_form"
166
+ initialValues={formData}
167
+ onSubmit={onSubmit}
168
+ isLoading={isLoading}
169
+ />
170
+ ) : (
171
+ <Box elementKey="loading_container">
172
+ <Spinner />
173
+ </Box>
174
+ )}
175
+ </>
176
+ </Box>
177
+ </Box>
178
+ </Box>
179
+ </Container>
180
+ </Section>
181
+ );
182
+ };
183
+
184
+ export default EditProfile;