@levo-so/blocks 0.1.98 → 0.1.100

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@levo-so/blocks",
3
- "version": "0.1.98",
3
+ "version": "0.1.100",
4
4
  "author": "Levo Engineering <devs@theinternetfolks.com>",
5
5
  "description": "Set of blocks for Levo studio",
6
6
  "type": "module",
@@ -16,7 +16,7 @@
16
16
  "react": ">=18",
17
17
  "react-dom": ">=18",
18
18
  "@levo-so/react": "0.1.86",
19
- "@levo-so/studio": "0.1.98",
19
+ "@levo-so/studio": "0.1.100",
20
20
  "@levo-so/core": "0.1.82"
21
21
  },
22
22
  "dependencies": {
@@ -29,10 +29,10 @@
29
29
  "@types/react": "19.2.14",
30
30
  "@types/react-dom": "19.2.3",
31
31
  "typescript": "5.9.3",
32
+ "@levo/ts-config": "0.0.0",
32
33
  "@levo-so/react": "0.1.86",
33
- "@levo-so/studio": "0.1.98",
34
- "@levo-so/core": "0.1.82",
35
- "@levo/ts-config": "0.0.0"
34
+ "@levo-so/studio": "0.1.100",
35
+ "@levo-so/core": "0.1.82"
36
36
  },
37
37
  "main": "./src/index.ts",
38
38
  "exports": {
@@ -31,7 +31,7 @@ interface IBlogMeta {
31
31
 
32
32
  const BlogListing1: React.FC<ILevoBlockBaseProps<IBlogListing1Content>> = ({ content }) => {
33
33
  const { response, query, setQuery } = useContextEngine<IPost, IBlogMeta>("blogs");
34
- const { isBuilder, blockData } = useBlockContext();
34
+ const { isStudio, blockData } = useBlockContext();
35
35
 
36
36
  const handleNext = () => setQuery({ page: (query?.page || 0) + 1 });
37
37
  const handlePrevious = () => setQuery({ page: (query?.page || 0) - 1 });
@@ -67,14 +67,14 @@ const BlogListing1: React.FC<ILevoBlockBaseProps<IBlogListing1Content>> = ({ con
67
67
  key={index}
68
68
  elementKey={`blogs.${index}.blog`}
69
69
  config={
70
- (isBuilder && studioConfig?.preview_url) || (!isBuilder && studioConfig?.live_url)
70
+ (isStudio && studioConfig?.preview_url) || (!isStudio && studioConfig?.live_url)
71
71
  ? {
72
72
  action: {
73
73
  type: "external_link",
74
74
  value:
75
- isBuilder && studioConfig.preview_url
75
+ isStudio && studioConfig.preview_url
76
76
  ? studioConfig.preview_url.replace(/\{[^}]+\}/g, item?.slug)
77
- : !isBuilder && studioConfig.live_url
77
+ : !isStudio && studioConfig.live_url
78
78
  ? studioConfig.live_url.replace(/\{[^}]+\}/g, item?.slug)
79
79
  : "",
80
80
  options: {},
@@ -31,7 +31,7 @@ interface IBlogMeta {
31
31
 
32
32
  const BlogListing2: React.FC<ILevoBlockBaseProps<IBlogListing2Content>> = ({ content }) => {
33
33
  const { response, query, setQuery } = useContextEngine<IPost, IBlogMeta>("blogs");
34
- const { isBuilder, blockData } = useBlockContext();
34
+ const { isStudio, blockData } = useBlockContext();
35
35
 
36
36
  const handleNext = () => setQuery({ page: (query?.page || 0) + 1 });
37
37
  const handlePrevious = () => setQuery({ page: (query?.page || 0) - 1 });
@@ -67,14 +67,14 @@ const BlogListing2: React.FC<ILevoBlockBaseProps<IBlogListing2Content>> = ({ con
67
67
  data-levo_group_item
68
68
  elementKey={`blogs.${index}.blog`}
69
69
  config={
70
- (isBuilder && studioConfig?.preview_url) || (!isBuilder && studioConfig?.live_url)
70
+ (isStudio && studioConfig?.preview_url) || (!isStudio && studioConfig?.live_url)
71
71
  ? {
72
72
  action: {
73
73
  type: "external_link",
74
74
  value:
75
- isBuilder && studioConfig.preview_url
75
+ isStudio && studioConfig.preview_url
76
76
  ? studioConfig.preview_url.replace(/\{[^}]+\}/g, item?.slug)
77
- : !isBuilder && studioConfig.live_url
77
+ : !isStudio && studioConfig.live_url
78
78
  ? studioConfig.live_url.replace(/\{[^}]+\}/g, item?.slug)
79
79
  : "",
80
80
  options: {},
@@ -31,7 +31,7 @@ interface IBlogMeta {
31
31
 
32
32
  const BlogListing3: React.FC<ILevoBlockBaseProps<IBlogListing3Content>> = ({ content, config }) => {
33
33
  const { response, query, setQuery } = useContextEngine<IPost, IBlogMeta>("blogs");
34
- const { isBuilder, blockData } = useBlockContext();
34
+ const { isStudio, blockData } = useBlockContext();
35
35
 
36
36
  const handleNext = () => setQuery({ page: (query?.page || 0) + 1 });
37
37
  const handlePrevious = () => setQuery({ page: (query?.page || 0) - 1 });
@@ -63,14 +63,14 @@ const BlogListing3: React.FC<ILevoBlockBaseProps<IBlogListing3Content>> = ({ con
63
63
  data-levo_group_item
64
64
  elementKey={`blogs.${index}.blog`}
65
65
  config={
66
- (isBuilder && studioConfig?.preview_url) || (!isBuilder && studioConfig?.live_url)
66
+ (isStudio && studioConfig?.preview_url) || (!isStudio && studioConfig?.live_url)
67
67
  ? {
68
68
  action: {
69
69
  type: "external_link",
70
70
  value:
71
- isBuilder && studioConfig.preview_url
71
+ isStudio && studioConfig.preview_url
72
72
  ? studioConfig.preview_url.replace(/\{[^}]+\}/g, item?.slug)
73
- : !isBuilder && studioConfig.live_url
73
+ : !isStudio && studioConfig.live_url
74
74
  ? studioConfig.live_url.replace(/\{[^}]+\}/g, item?.slug)
75
75
  : "",
76
76
  options: {},
@@ -103,7 +103,7 @@ const Community1: React.FC<ILevoBlockBaseProps<ICommunity1Content>> = ({ content
103
103
  // Join request state
104
104
  const [joinRequest, setJoinRequest] = useState<IForumJoinRequest | null>(null);
105
105
 
106
- const { parsedBlockData, isBuilder } = useBlockContext();
106
+ const { parsedBlockData, isStudio } = useBlockContext();
107
107
  const forumKey = useMemo(() => {
108
108
  return (
109
109
  parsedBlockData?.source?.find((s) => s.module === "community")?.identifier ||
@@ -129,7 +129,7 @@ const Community1: React.FC<ILevoBlockBaseProps<ICommunity1Content>> = ({ content
129
129
  .json<IResponseSingle<IForum>>();
130
130
 
131
131
  if (response?.content?.data) {
132
- if (isBuilder) {
132
+ if (isStudio) {
133
133
  setForumData({
134
134
  ...response.content.data,
135
135
  settings: {
@@ -147,7 +147,7 @@ const Community1: React.FC<ILevoBlockBaseProps<ICommunity1Content>> = ({ content
147
147
  levoClient?.logger?.error("Error fetching single forum data:", error);
148
148
  return null;
149
149
  }
150
- }, [forumKey, isBuilder]);
150
+ }, [forumKey, isStudio]);
151
151
 
152
152
  const checkMembership = useCallback(async () => {
153
153
  if (!forumData?.settings?.invite_only || !isLoggedIn) {
@@ -158,7 +158,7 @@ const Community1: React.FC<ILevoBlockBaseProps<ICommunity1Content>> = ({ content
158
158
  }
159
159
 
160
160
  // In builder mode, bypass API call and use sample data
161
- if (isBuilder) {
161
+ if (isStudio) {
162
162
  const data = SAMPLE_GET_MEMBER_RESPONSE.content.data;
163
163
  setIsMember(!!data?.member);
164
164
  setJoinRequest(data?.join_request || null);
@@ -186,7 +186,7 @@ const Community1: React.FC<ILevoBlockBaseProps<ICommunity1Content>> = ({ content
186
186
  setIsLoadingMembership(false);
187
187
  hasFetchedMembershipRef.current = true;
188
188
  }
189
- }, [forumKey, forumData?.settings?.invite_only, isLoggedIn, isBuilder, levoClient]);
189
+ }, [forumKey, forumData?.settings?.invite_only, isLoggedIn, isStudio, levoClient]);
190
190
 
191
191
  /**
192
192
  * Submit a join request for the current user
@@ -368,29 +368,29 @@ const Community1: React.FC<ILevoBlockBaseProps<ICommunity1Content>> = ({ content
368
368
 
369
369
  const postDetailPageURLPattern = useMemo(() => {
370
370
  if (
371
- (isBuilder && detailPageStudioConfig?.preview_url) ||
372
- (!isBuilder && detailPageStudioConfig?.live_url)
371
+ (isStudio && detailPageStudioConfig?.preview_url) ||
372
+ (!isStudio && detailPageStudioConfig?.live_url)
373
373
  ) {
374
- return isBuilder && detailPageStudioConfig.preview_url
374
+ return isStudio && detailPageStudioConfig.preview_url
375
375
  ? detailPageStudioConfig.preview_url
376
- : !isBuilder && detailPageStudioConfig.live_url
376
+ : !isStudio && detailPageStudioConfig.live_url
377
377
  ? detailPageStudioConfig.live_url
378
378
  : "";
379
379
  }
380
- }, [isBuilder, detailPageStudioConfig]);
380
+ }, [isStudio, detailPageStudioConfig]);
381
381
 
382
382
  const postListingPageURL = useMemo(() => {
383
383
  if (
384
- (isBuilder && listingPageStudioConfig?.preview_url) ||
385
- (!isBuilder && listingPageStudioConfig?.live_url)
384
+ (isStudio && listingPageStudioConfig?.preview_url) ||
385
+ (!isStudio && listingPageStudioConfig?.live_url)
386
386
  ) {
387
- return isBuilder && listingPageStudioConfig.preview_url
387
+ return isStudio && listingPageStudioConfig.preview_url
388
388
  ? listingPageStudioConfig.preview_url
389
- : !isBuilder && listingPageStudioConfig.live_url
389
+ : !isStudio && listingPageStudioConfig.live_url
390
390
  ? listingPageStudioConfig.live_url
391
391
  : "";
392
392
  }
393
- }, [isBuilder, listingPageStudioConfig]);
393
+ }, [isStudio, listingPageStudioConfig]);
394
394
 
395
395
  const isInviteOnly = forumData?.settings?.invite_only ?? false;
396
396
  const allowJoinRequests = forumData?.settings?.allow_join_requests ?? false;
@@ -91,7 +91,7 @@ const PostDetailSkeleton: React.FC = () => (
91
91
  const CommunityPost1: React.FC<ILevoBlockBaseProps<ICommunityPost1Content>> = ({ content }) => {
92
92
  const { fetch, logger } = useLevo();
93
93
  const { isLoggedIn } = useAuth();
94
- const { isBuilder } = useBlockContext();
94
+ const { isStudio } = useBlockContext();
95
95
  const pagePost = usePageContext("community");
96
96
 
97
97
  const postSource = pagePost && Object.keys(pagePost).length > 0 ? pagePost : content?.post;
@@ -123,7 +123,7 @@ const CommunityPost1: React.FC<ILevoBlockBaseProps<ICommunityPost1Content>> = ({
123
123
  .json<IResponseSingle<IForum>>();
124
124
 
125
125
  if (response?.content?.data) {
126
- if (isBuilder) {
126
+ if (isStudio) {
127
127
  setForumData({
128
128
  ...response.content.data,
129
129
  settings: {
@@ -142,7 +142,7 @@ const CommunityPost1: React.FC<ILevoBlockBaseProps<ICommunityPost1Content>> = ({
142
142
  logger?.error("Failed to fetch forum data", levoError);
143
143
  failedForumAttemptsRef.current += 1;
144
144
  }
145
- }, [forumKey, fetch, logger, isBuilder]);
145
+ }, [forumKey, fetch, logger, isStudio]);
146
146
 
147
147
  const checkMembership = useCallback(async () => {
148
148
  if (!forumData?.settings?.invite_only || !isLoggedIn) {
@@ -153,7 +153,7 @@ const CommunityPost1: React.FC<ILevoBlockBaseProps<ICommunityPost1Content>> = ({
153
153
  }
154
154
 
155
155
  // In builder mode, bypass API call and use sample data
156
- if (isBuilder) {
156
+ if (isStudio) {
157
157
  const data = SAMPLE_GET_MEMBER_RESPONSE.content.data;
158
158
  setIsMember(!!data?.member);
159
159
  setJoinRequest(data?.join_request || null);
@@ -186,7 +186,7 @@ const CommunityPost1: React.FC<ILevoBlockBaseProps<ICommunityPost1Content>> = ({
186
186
  } finally {
187
187
  setIsLoadingMembership(false);
188
188
  }
189
- }, [forumKey, forumData?.settings?.invite_only, isLoggedIn, isBuilder, fetch, logger]);
189
+ }, [forumKey, forumData?.settings?.invite_only, isLoggedIn, isStudio, fetch, logger]);
190
190
 
191
191
  /** Submit a join request for the current user */
192
192
  const handleSubmitJoinRequest = useCallback(
@@ -239,29 +239,29 @@ const CommunityPost1: React.FC<ILevoBlockBaseProps<ICommunityPost1Content>> = ({
239
239
 
240
240
  const postDetailPageURLPattern = useMemo(() => {
241
241
  if (
242
- (isBuilder && detailPageStudioConfig?.preview_url) ||
243
- (!isBuilder && detailPageStudioConfig?.live_url)
242
+ (isStudio && detailPageStudioConfig?.preview_url) ||
243
+ (!isStudio && detailPageStudioConfig?.live_url)
244
244
  ) {
245
- return isBuilder && detailPageStudioConfig.preview_url
245
+ return isStudio && detailPageStudioConfig.preview_url
246
246
  ? detailPageStudioConfig.preview_url
247
- : !isBuilder && detailPageStudioConfig.live_url
247
+ : !isStudio && detailPageStudioConfig.live_url
248
248
  ? detailPageStudioConfig.live_url
249
249
  : "";
250
250
  }
251
- }, [isBuilder, detailPageStudioConfig]);
251
+ }, [isStudio, detailPageStudioConfig]);
252
252
 
253
253
  const postListingPageURL = useMemo(() => {
254
254
  if (
255
- (isBuilder && listingPageStudioConfig?.preview_url) ||
256
- (!isBuilder && listingPageStudioConfig?.live_url)
255
+ (isStudio && listingPageStudioConfig?.preview_url) ||
256
+ (!isStudio && listingPageStudioConfig?.live_url)
257
257
  ) {
258
- return isBuilder && listingPageStudioConfig.preview_url
258
+ return isStudio && listingPageStudioConfig.preview_url
259
259
  ? listingPageStudioConfig.preview_url
260
- : !isBuilder && listingPageStudioConfig.live_url
260
+ : !isStudio && listingPageStudioConfig.live_url
261
261
  ? listingPageStudioConfig.live_url
262
262
  : "";
263
263
  }
264
- }, [isBuilder, listingPageStudioConfig]);
264
+ }, [isStudio, listingPageStudioConfig]);
265
265
 
266
266
  // Reset fetch state when the post changes
267
267
  const postCommentsCount = (postSource as unknown as IForumPost)?.comments_count ?? 0;
@@ -245,7 +245,7 @@ export const Content10: IBlock = {
245
245
  {
246
246
  key: "content",
247
247
  label: "Content",
248
- field_interface: "TypographyWidget",
248
+ field_interface: "BlogContentWidget",
249
249
  hint: {
250
250
  prompt_description:
251
251
  "Full blog article body. Use formal, professional tone suitable for financial topics. Include headings, paragraphs, and clear explanations. Length should be 800–2000 words for a comprehensive post.",
@@ -1,5 +1,5 @@
1
1
  import type { ILevoBlockBaseProps } from "@levo-so/studio";
2
- import { Box, Container, Heading, Icon, Media, Section, Typography } from "@levo-so/studio";
2
+ import { BlogContent, Box, Container, Heading, Icon, Media, Section, Typography } from "@levo-so/studio";
3
3
  import type React from "react";
4
4
 
5
5
  import type { IContent10Content } from "./content-10.schema";
@@ -32,7 +32,7 @@ const Content10: React.FC<ILevoBlockBaseProps<IContent10Content>> = ({ content }
32
32
  </Box>
33
33
  <Box elementKey="content-wrapper">
34
34
  <Box elementKey="content-section">
35
- <Typography elementKey="content" className="LevoProseMirror" />
35
+ <BlogContent elementKey="content" />
36
36
  </Box>
37
37
  </Box>
38
38
  </Container>
@@ -0,0 +1,36 @@
1
+ import type { IBlock } from "@levo-so/studio";
2
+
3
+ const DEFAULT_CONTENT = {
4
+ html: '<div style="padding:40px;text-align:center;background:#f3f4f6;border-radius:12px;font-family:system-ui,sans-serif;">\n <h2 style="margin:0 0 8px;font-size:24px;">Custom HTML</h2>\n <p style="margin:0;color:#6b7280;">Paste any HTML here — it renders as-is.</p>\n</div>',
5
+ };
6
+
7
+ export type IEmbed2Content = typeof DEFAULT_CONTENT;
8
+
9
+ export const Embed2: IBlock = {
10
+ category_id: "embed",
11
+ title: "Custom HTML",
12
+ key: "embed-2",
13
+ version: "v1",
14
+ prompt_description:
15
+ "A transparent block for embedding custom HTML. The wrapper is invisible to layout so the pasted HTML renders as if no wrapper exists.",
16
+ content_schema: [
17
+ {
18
+ key: "html",
19
+ label: "HTML",
20
+ field_interface: "IframeWidget",
21
+ },
22
+ ],
23
+ layouts: [
24
+ {
25
+ key: "default",
26
+ title: "Default",
27
+ styles: {
28
+ html: {
29
+ display: "contents",
30
+ },
31
+ },
32
+ content: DEFAULT_CONTENT,
33
+ config: {},
34
+ },
35
+ ],
36
+ };
@@ -0,0 +1,10 @@
1
+ import type { ILevoBlockBaseProps } from "@levo-so/studio";
2
+ import { Iframe } from "@levo-so/studio";
3
+
4
+ import type { IEmbed2Content } from "./embed-2.schema";
5
+
6
+ const Embed2: React.FC<ILevoBlockBaseProps<IEmbed2Content>> = () => (
7
+ <Iframe elementKey="html" />
8
+ );
9
+
10
+ export default Embed2;
@@ -62,9 +62,9 @@ const EventDetails: React.FC<ILevoBlockBaseProps<IEventDetailsContent>> = () =>
62
62
 
63
63
  <Box elementKey="content-section">
64
64
  <Box elementKey="main-content">
65
- {data?.id ? (
65
+ {data?._id ? (
66
66
  <RegisterModal
67
- eventID={data?.id as string}
67
+ eventID={data?._id as string}
68
68
  title={data?.title}
69
69
  external={data?.external_ticketing}
70
70
  />
@@ -28,7 +28,7 @@ interface IEventMeta {
28
28
 
29
29
  const EventListing2: React.FC<ILevoBlockBaseProps<IEventListing2Content>> = ({ content }) => {
30
30
  const { response, query, setQuery } = useContextEngine<LevoEvent.Root, IEventMeta>("events");
31
- const { isBuilder } = useBlockContext();
31
+ const { isStudio } = useBlockContext();
32
32
 
33
33
  const handleNext = () => setQuery({ page: (query?.page || 0) + 1 });
34
34
  const handlePrevious = () => setQuery({ page: (query?.page || 0) - 1 });
@@ -59,14 +59,14 @@ const EventListing2: React.FC<ILevoBlockBaseProps<IEventListing2Content>> = ({ c
59
59
  data-levo_group_item
60
60
  elementKey={`events.${index}.eventWrapper`}
61
61
  config={
62
- (isBuilder && studioConfig?.preview_url) || (!isBuilder && studioConfig?.live_url)
62
+ (isStudio && studioConfig?.preview_url) || (!isStudio && studioConfig?.live_url)
63
63
  ? {
64
64
  action: {
65
65
  type: "external_link",
66
66
  value:
67
- isBuilder && studioConfig.preview_url
67
+ isStudio && studioConfig.preview_url
68
68
  ? studioConfig.preview_url.replace(/\{[^}]+\}/g, item?.slug)
69
- : !isBuilder && studioConfig.live_url
69
+ : !isStudio && studioConfig.live_url
70
70
  ? studioConfig.live_url.replace(/\{[^}]+\}/g, item?.slug)
71
71
  : "",
72
72
  options: {},
@@ -28,7 +28,7 @@ interface IEventMeta {
28
28
 
29
29
  const EventListing3: React.FC<ILevoBlockBaseProps<IEventListing3>> = ({ content }) => {
30
30
  const { response, query, setQuery } = useContextEngine<LevoEvent.Root, IEventMeta>("events");
31
- const { isBuilder } = useBlockContext();
31
+ const { isStudio } = useBlockContext();
32
32
 
33
33
  const handleNext = () => setQuery({ page: (query?.page || 0) + 1 });
34
34
  const handlePrevious = () => setQuery({ page: (query?.page || 0) - 1 });
@@ -59,14 +59,14 @@ const EventListing3: React.FC<ILevoBlockBaseProps<IEventListing3>> = ({ content
59
59
  data-levo_group_item
60
60
  elementKey={`events.${index}.eventWrapper`}
61
61
  config={
62
- (isBuilder && studioConfig?.preview_url) || (!isBuilder && studioConfig?.live_url)
62
+ (isStudio && studioConfig?.preview_url) || (!isStudio && studioConfig?.live_url)
63
63
  ? {
64
64
  action: {
65
65
  type: "external_link",
66
66
  value:
67
- isBuilder && studioConfig.preview_url
67
+ isStudio && studioConfig.preview_url
68
68
  ? studioConfig.preview_url.replace(/\{[^}]+\}/g, item?.slug)
69
- : !isBuilder && studioConfig.live_url
69
+ : !isStudio && studioConfig.live_url
70
70
  ? studioConfig.live_url.replace(/\{[^}]+\}/g, item?.slug)
71
71
  : "",
72
72
  options: {},
@@ -28,7 +28,7 @@ interface IEventMeta {
28
28
 
29
29
  const EventListing4: React.FC<ILevoBlockBaseProps<IEventListing4>> = ({ content }) => {
30
30
  const { response, query, setQuery } = useContextEngine<LevoEvent.Root, IEventMeta>("events");
31
- const { isBuilder } = useBlockContext();
31
+ const { isStudio } = useBlockContext();
32
32
 
33
33
  const handleNext = () => setQuery({ page: (query?.page || 0) + 1 });
34
34
  const handlePrevious = () => setQuery({ page: (query?.page || 0) - 1 });
@@ -58,14 +58,14 @@ const EventListing4: React.FC<ILevoBlockBaseProps<IEventListing4>> = ({ content
58
58
  data-levo_group_item
59
59
  elementKey={`events.${index}.eventWrapper`}
60
60
  config={
61
- (isBuilder && studioConfig?.preview_url) || (!isBuilder && studioConfig?.live_url)
61
+ (isStudio && studioConfig?.preview_url) || (!isStudio && studioConfig?.live_url)
62
62
  ? {
63
63
  action: {
64
64
  type: "external_link",
65
65
  value:
66
- isBuilder && studioConfig.preview_url
66
+ isStudio && studioConfig.preview_url
67
67
  ? studioConfig.preview_url.replace(/\{[^}]+\}/g, item?.slug)
68
- : !isBuilder && studioConfig.live_url
68
+ : !isStudio && studioConfig.live_url
69
69
  ? studioConfig.live_url.replace(/\{[^}]+\}/g, item?.slug)
70
70
  : "",
71
71
  options: {},
@@ -28,7 +28,7 @@ interface IEventMeta {
28
28
 
29
29
  const EventListing: React.FC<ILevoBlockBaseProps<IEventListing>> = ({ content }) => {
30
30
  const { response, query, setQuery } = useContextEngine<LevoEvent.Root, IEventMeta>("events");
31
- const { isBuilder } = useBlockContext();
31
+ const { isStudio } = useBlockContext();
32
32
 
33
33
  const handleNext = () => setQuery({ page: (query?.page || 0) + 1 });
34
34
  const handlePrevious = () => setQuery({ page: (query?.page || 0) - 1 });
@@ -58,14 +58,14 @@ const EventListing: React.FC<ILevoBlockBaseProps<IEventListing>> = ({ content })
58
58
  data-levo_group_item
59
59
  elementKey={`events.${index}.eventWrapper`}
60
60
  config={
61
- (isBuilder && studioConfig?.preview_url) || (!isBuilder && studioConfig?.live_url)
61
+ (isStudio && studioConfig?.preview_url) || (!isStudio && studioConfig?.live_url)
62
62
  ? {
63
63
  action: {
64
64
  type: "external_link",
65
65
  value:
66
- isBuilder && studioConfig.preview_url
66
+ isStudio && studioConfig.preview_url
67
67
  ? studioConfig.preview_url.replace(/\{[^}]+\}/g, item?.slug)
68
- : !isBuilder && studioConfig.live_url
68
+ : !isStudio && studioConfig.live_url
69
69
  ? studioConfig.live_url.replace(/\{[^}]+\}/g, item?.slug)
70
70
  : "",
71
71
  options: {},
@@ -48,6 +48,7 @@ const Cta1 = lazy(() => import("./cta/cta-1"));
48
48
  const Cta2 = lazy(() => import("./cta/cta-2"));
49
49
  const Cta3 = lazy(() => import("./cta/cta-3"));
50
50
  const Embed1 = lazy(() => import("./embed/embed-1"));
51
+ const Embed2 = lazy(() => import("./embed/embed-2"));
51
52
  const EventListing = lazy(() => import("./event/event-listing"));
52
53
  const EventListing2 = lazy(() => import("./event/event-listing-2"));
53
54
  const EventListing3 = lazy(() => import("./event/event-listing-3"));
@@ -175,6 +176,7 @@ export const blocks: Record<string, React.LazyExoticComponent<React.ComponentTyp
175
176
  "cta-2:v1": Cta2,
176
177
  "cta-3:v1": Cta3,
177
178
  "embed-1:v1": Embed1,
179
+ "embed-2:v1": Embed2,
178
180
  "event-listing:v1": EventListing,
179
181
  "event-listing-2:v1": EventListing2,
180
182
  "event-listing-3:v1": EventListing3,
@@ -572,7 +572,7 @@ export const Jobs1: IBlock = {
572
572
  {
573
573
  key: "description_content",
574
574
  label: "Job Description",
575
- field_interface: "TypographyWidget",
575
+ field_interface: "BlogContentWidget",
576
576
  hint: {
577
577
  prompt_description:
578
578
  "Full job description including responsibilities, requirements, and benefits.",
@@ -1,5 +1,6 @@
1
1
  import type { ILevoBlockBaseProps } from "@levo-so/studio";
2
2
  import {
3
+ BlogContent,
3
4
  Box,
4
5
  Button,
5
6
  Container,
@@ -132,7 +133,7 @@ const Jobs1: React.FC<ILevoBlockBaseProps<IJobs1Content>> = ({ content }) => (
132
133
  {/* Job Description Content */}
133
134
  <Box elementKey="description_section">
134
135
  <Heading elementKey="description_title" />
135
- <Typography elementKey="description_content" className="LevoProseMirror" />
136
+ <BlogContent elementKey="description_content" />
136
137
  </Box>
137
138
  </Box>
138
139
  <Form elementKey="application_form" />
@@ -158,7 +158,7 @@ const PollOption: React.FC<{
158
158
  fetchPolls?: () => Promise<void>;
159
159
  }> = ({ option, totalVotes, selectedOption, pollId, fetchPolls }) => {
160
160
  const levoClient = useLevo();
161
- const { isBuilder } = useBlockContext();
161
+ const { isStudio } = useBlockContext();
162
162
 
163
163
  const [isUserOnOption, setIsUserOnOption] = useState(false);
164
164
  const [isVoting, setIsVoting] = useState(false);
@@ -183,7 +183,7 @@ const PollOption: React.FC<{
183
183
  }, [percentage]);
184
184
 
185
185
  const handleOptionClick = async () => {
186
- if (isBuilder || isVoting || isCurrentOptionSelected) return;
186
+ if (isStudio || isVoting || isCurrentOptionSelected) return;
187
187
 
188
188
  try {
189
189
  setIsVoting(true);
@@ -368,7 +368,7 @@ const Poll: React.FC<{
368
368
 
369
369
  const Polling1: React.FC<ILevoBlockBaseProps<IPolling1Content>> = ({ content }) => {
370
370
  const levoClient = useLevo();
371
- const { isBuilder } = useBlockContext();
371
+ const { isStudio } = useBlockContext();
372
372
 
373
373
  const { account, isAuthLoaded } = useAuth();
374
374
 
@@ -395,7 +395,7 @@ const Polling1: React.FC<ILevoBlockBaseProps<IPolling1Content>> = ({ content })
395
395
  }, []);
396
396
 
397
397
  useEffect(() => {
398
- if (isBuilder) return;
398
+ if (isStudio) return;
399
399
  fetchPolls();
400
400
  }, []);
401
401
 
@@ -407,7 +407,7 @@ const Polling1: React.FC<ILevoBlockBaseProps<IPolling1Content>> = ({ content })
407
407
  <Typography elementKey="description" />
408
408
  </Box>
409
409
  <Box elementKey="polls">
410
- {isBuilder ? (
410
+ {isStudio ? (
411
411
  <>
412
412
  {POLLS_RESPONSE_SAMPLE?.content?.data?.map((item: any, index: number) => {
413
413
  return (
@@ -471,7 +471,7 @@ export const Profile4: IBlock = {
471
471
  {
472
472
  key: "content",
473
473
  label: "Content",
474
- field_interface: "TypographyWidget",
474
+ field_interface: "BlogContentWidget",
475
475
  hint: {
476
476
  prompt_description:
477
477
  "Full profile article content. Should be comprehensive and informative.",
@@ -1,5 +1,5 @@
1
1
  import type { ILevoBlockBaseProps } from "@levo-so/studio";
2
- import { Box, Button, Container, Form, Heading, Icon, Section, Typography } from "@levo-so/studio";
2
+ import { BlogContent, Box, Button, Container, Form, Heading, Icon, Section, Typography } from "@levo-so/studio";
3
3
  import dayjs from "dayjs";
4
4
  import type React from "react";
5
5
 
@@ -84,7 +84,7 @@ const Profile4: React.FC<ILevoBlockBaseProps<IProfile4Content>> = ({ content })
84
84
  {/* Blog Content */}
85
85
  <Box elementKey="content-section">
86
86
  <Typography elementKey="content_title" />
87
- <Typography elementKey="content" className="LevoProseMirror" />
87
+ <BlogContent elementKey="content" />
88
88
  </Box>
89
89
  </Box>
90
90
  <Form elementKey="contact_form" />
@@ -180,7 +180,7 @@ export const Profile5: IBlock = {
180
180
  {
181
181
  key: "content_description",
182
182
  label: "Content Description",
183
- field_interface: "TypographyWidget",
183
+ field_interface: "BlogContentWidget",
184
184
  hint: {
185
185
  prompt_description:
186
186
  "Main content paragraph providing comprehensive information about the team, services, or offerings. Should be engaging and informative.",
@@ -1,4 +1,5 @@
1
1
  import {
2
+ BlogContent,
2
3
  Box,
3
4
  Button,
4
5
  Container,
@@ -45,7 +46,7 @@ const Profile5: React.FC<ILevoBlockBaseProps<IProfile5Content>> = ({ content })
45
46
  </Box>
46
47
  </Box>
47
48
  <Box elementKey="content_container">
48
- <Typography elementKey="content_description" className="LevoProseMirror" />
49
+ <BlogContent elementKey="content_description" />
49
50
  </Box>
50
51
  </Box>
51
52
  </Box>
@@ -17,7 +17,7 @@ import type { IService2Content } from "./service-2.schema";
17
17
 
18
18
  const Service2: React.FC<ILevoBlockBaseProps<IService2Content>> = ({ content, config }) => {
19
19
  const [zipcode, setZipcode] = useState("");
20
- const { isBuilder } = useBlockContext();
20
+ const { isStudio } = useBlockContext();
21
21
  return (
22
22
  <Section elementKey="layout">
23
23
  <Container elementKey="container">
@@ -73,7 +73,7 @@ const Service2: React.FC<ILevoBlockBaseProps<IService2Content>> = ({ content, co
73
73
  elementKey="search_button"
74
74
  onClick={() => {
75
75
  if (
76
- !isBuilder &&
76
+ !isStudio &&
77
77
  zipcode &&
78
78
  zipcode.length === 6 &&
79
79
  config?.search_button?.custom_fields?.redirect_url
@@ -17,7 +17,7 @@ import type { IService3Content } from "./service-3.schema";
17
17
 
18
18
  const Service3: React.FC<ILevoBlockBaseProps<IService3Content>> = ({ content, config }) => {
19
19
  const [zipcode, setZipcode] = useState("");
20
- const { isBuilder } = useBlockContext();
20
+ const { isStudio } = useBlockContext();
21
21
  return (
22
22
  <Section elementKey="layout">
23
23
  <Container elementKey="container">
@@ -106,7 +106,7 @@ const Service3: React.FC<ILevoBlockBaseProps<IService3Content>> = ({ content, co
106
106
  elementKey="search_button"
107
107
  onClick={() => {
108
108
  if (
109
- !isBuilder &&
109
+ !isStudio &&
110
110
  zipcode &&
111
111
  zipcode.length === 6 &&
112
112
  config?.search_button?.custom_fields?.redirect_url
@@ -82,7 +82,7 @@ export const TermsAndConditions1: IBlock = {
82
82
  {
83
83
  key: "content",
84
84
  label: "Content",
85
- field_interface: "TypographyWidget",
85
+ field_interface: "BlogContentWidget",
86
86
  hint: {
87
87
  prompt_description:
88
88
  "Main legal document content with structured sections, headings, and paragraphs. Should include comprehensive terms covering service usage, responsibilities, privacy, and legal compliance. Tone: formal, clear, legally compliant.",
@@ -1,4 +1,5 @@
1
1
  import {
2
+ BlogContent,
2
3
  Box,
3
4
  Container,
4
5
  Heading,
@@ -18,7 +19,7 @@ const TermsAndConditions1: React.FC<ILevoBlockBaseProps<ITermsAndConditions1Cont
18
19
  <Typography elementKey="subtitle" />
19
20
  </Box>
20
21
  <Box elementKey="content_wrapper">
21
- <Typography className="LevoProseMirror" elementKey="content" />
22
+ <BlogContent elementKey="content" />
22
23
  </Box>
23
24
  </Container>
24
25
  </Section>
@@ -49,6 +49,7 @@ import { Cta1 } from "../blocks/cta/cta-1.schema";
49
49
  import { Cta2 } from "../blocks/cta/cta-2.schema";
50
50
  import { Cta3 } from "../blocks/cta/cta-3.schema";
51
51
  import { Embed1 } from "../blocks/embed/embed-1.schema";
52
+ import { Embed2 } from "../blocks/embed/embed-2.schema";
52
53
  import { EventDetails } from "../blocks/event/event-details.schema";
53
54
  import { EventListing } from "../blocks/event/event-listing.schema";
54
55
  import { EventListing2 } from "../blocks/event/event-listing-2.schema";
@@ -176,6 +177,7 @@ export const BlockList: IBlock[] = [
176
177
  Cta3,
177
178
  EditProfile,
178
179
  Embed1,
180
+ Embed2,
179
181
  EventDetails,
180
182
  EventListing,
181
183
  EventListing2,