From 3508b7f2c3c7590548455255d374b3ac41cf5c2a Mon Sep 17 00:00:00 2001 From: Rajat Date: Sun, 8 Mar 2026 23:19:45 +0530 Subject: [PATCH 01/14] open content by default --- .../src/blocks/content/admin-widget.tsx | 29 ++++- .../src/blocks/content/settings.ts | 1 + .../page-blocks/src/blocks/content/widget.tsx | 103 +++++++++--------- 3 files changed, 83 insertions(+), 50 deletions(-) diff --git a/packages/page-blocks/src/blocks/content/admin-widget.tsx b/packages/page-blocks/src/blocks/content/admin-widget.tsx index e9b9e6a15..e7537c5c2 100644 --- a/packages/page-blocks/src/blocks/content/admin-widget.tsx +++ b/packages/page-blocks/src/blocks/content/admin-widget.tsx @@ -11,9 +11,12 @@ import { CssIdField, MaxWidthSelector, VerticalPaddingSelector, + Tooltip, + Checkbox, } from "@courselit/components-library"; import { Theme, ThemeStyle } from "@courselit/page-models"; import { Editor } from "@courselit/text-editor"; +import { Help } from "@courselit/icons"; interface AdminWidgetProps { settings: Settings; @@ -39,6 +42,9 @@ export default function AdminWidget({ ThemeStyle["structure"]["section"]["padding"]["y"] >(settings.verticalPadding); const [cssId, setCssId] = useState(settings.cssId); + const [openByDefault, setOpenByDefault] = useState( + settings.openByDefault || false, + ); useEffect(() => { onChange({ @@ -47,9 +53,18 @@ export default function AdminWidget({ headerAlignment, maxWidth, verticalPadding, + openByDefault, cssId, }); - }, [title, description, headerAlignment, maxWidth, verticalPadding, cssId]); + }, [ + title, + description, + headerAlignment, + maxWidth, + verticalPadding, + openByDefault, + cssId, + ]); return ( +
+
+

Open by default

+ + + +
+ setOpenByDefault(value)} + /> +
diff --git a/packages/page-blocks/src/blocks/content/settings.ts b/packages/page-blocks/src/blocks/content/settings.ts index 46306125b..74475a31b 100644 --- a/packages/page-blocks/src/blocks/content/settings.ts +++ b/packages/page-blocks/src/blocks/content/settings.ts @@ -8,5 +8,6 @@ export default interface Settings extends WidgetDefaultSettings { title: string; description: TextEditorContent; headerAlignment: Alignment; + openByDefault?: boolean; cssId?: string; } diff --git a/packages/page-blocks/src/blocks/content/widget.tsx b/packages/page-blocks/src/blocks/content/widget.tsx index 354d07f9e..e4b459bb1 100644 --- a/packages/page-blocks/src/blocks/content/widget.tsx +++ b/packages/page-blocks/src/blocks/content/widget.tsx @@ -42,6 +42,7 @@ export default function Widget({ cssId, maxWidth, verticalPadding, + openByDefault = false, }, state, pageData: product, @@ -184,59 +185,63 @@ export default function Widget({ ))} )} - - {Object.keys(formattedCourse).map((group, index) => ( - 0 && + (openByDefault ? ( + - -
+ {renderItems()} + + ) : ( + + {renderItems()} + + ))} +
+ + ); + + function renderItems() { + return Object.keys(formattedCourse).map((group) => ( + + +
+ {group} + + {`${formattedCourse[group].length} lessons`} + +
+
+ + {formattedCourse[group].map((lesson: Lesson) => ( + +
+ + + - {group} + {lesson.title} - - {`${formattedCourse[group].length} lessons`} - -
-
- - {formattedCourse[group].map( - (lesson: Lesson) => ( - -
- - + - - {lesson.title} - - - - {!lesson.requiresEnrollment && ( - - Preview - - )} -
- - ), + {!lesson.requiresEnrollment && ( + Preview )} -
-
+ + ))} -
- - - ); + + + )); + } } From d686479e831b98a879a3574d6eac5dc784077907 Mon Sep 17 00:00:00 2001 From: Rajat Date: Sun, 8 Mar 2026 23:22:01 +0530 Subject: [PATCH 02/14] bugfix: Left alignment on mobile for FAQ block --- packages/page-blocks/src/blocks/faq/widget.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/page-blocks/src/blocks/faq/widget.tsx b/packages/page-blocks/src/blocks/faq/widget.tsx index 7489fd19f..56df8817f 100644 --- a/packages/page-blocks/src/blocks/faq/widget.tsx +++ b/packages/page-blocks/src/blocks/faq/widget.tsx @@ -98,7 +98,7 @@ export default function Widget({ key={`${item.title}-${index}`} value={`${item.title}-${index}`} > - + {item.title} From 8f4b3ccf21494f6b66133214d81c94d01c5ad06b Mon Sep 17 00:00:00 2001 From: Rajat Date: Sun, 8 Mar 2026 23:31:56 +0530 Subject: [PATCH 03/14] wider community post popup for better reading --- apps/web/components/community/comment-section.tsx | 2 +- apps/web/components/community/create-post-dialog.tsx | 2 +- apps/web/components/community/index.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/components/community/comment-section.tsx b/apps/web/components/community/comment-section.tsx index f6f8161a2..cdd3f106b 100644 --- a/apps/web/components/community/comment-section.tsx +++ b/apps/web/components/community/comment-section.tsx @@ -594,7 +594,7 @@ export default function CommentSection({ return (
-
+
{comments.map((comment) => ( ))} - +
diff --git a/apps/web/components/community/index.tsx b/apps/web/components/community/index.tsx index bea629cc5..930c98bf1 100644 --- a/apps/web/components/community/index.tsx +++ b/apps/web/components/community/index.tsx @@ -1413,7 +1413,7 @@ export function CommunityForum({ }} > From 8dfb1db18d4854eabd0d7ec18003ba0282c4684e Mon Sep 17 00:00:00 2001 From: Rajat Date: Sun, 8 Mar 2026 23:32:38 +0530 Subject: [PATCH 04/14] invalidate domain cache on theme switch --- apps/web/graphql/themes/logic.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/web/graphql/themes/logic.ts b/apps/web/graphql/themes/logic.ts index b75f0128a..0b9707a62 100644 --- a/apps/web/graphql/themes/logic.ts +++ b/apps/web/graphql/themes/logic.ts @@ -8,6 +8,7 @@ import UserThemeModel from "@/models/UserTheme"; import { themes as SystemThemes } from "@courselit/page-primitives"; import { ThemeStyle } from "@courselit/page-models"; import { UITheme } from "@models/UITheme"; +import { invalidateDomainCache } from "@/lib/domain-cache"; const { permissions } = constants; @@ -224,6 +225,8 @@ export const switchTheme = async (themeId: string, ctx: GQLContext) => { { $set: { themeId, lastEditedThemeId: themeId } }, ); + invalidateDomainCache(ctx.subdomain.name); + return formatTheme(theme); }; From f48b08c0802f1bf02aaa5e37c08831aff692a081 Mon Sep 17 00:00:00 2001 From: Rajat Date: Sun, 8 Mar 2026 23:35:12 +0530 Subject: [PATCH 05/14] Better error handling when media operations fail while updating page --- apps/web/graphql/pages/logic.ts | 23 ++++++++++++++----- ...-media-with-sealed-media-in-page-layout.ts | 10 +++++++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/apps/web/graphql/pages/logic.ts b/apps/web/graphql/pages/logic.ts index 96c4e5709..5c8cd37fa 100644 --- a/apps/web/graphql/pages/logic.ts +++ b/apps/web/graphql/pages/logic.ts @@ -18,9 +18,12 @@ import { Domain } from "../../models/Domain"; import { homePageTemplate } from "./page-templates"; import { publishTheme } from "../themes/logic"; import getDeletedMediaIds from "@/lib/get-deleted-media-ids"; -import { deleteMedia, sealMedia } from "@/services/medialit"; +import { deleteMedia } from "@/services/medialit"; import CommunityModel from "@models/Community"; -import { replaceTempMediaWithSealedMediaInPageLayout } from "@/lib/replace-temp-media-with-sealed-media-in-page-layout"; +import { + replaceTempMediaWithSealedMediaInPageLayout, + safeSealMedia, +} from "@/lib/replace-temp-media-with-sealed-media-in-page-layout"; const { product, site, blogPage, communityPage, permissions, defaultPages } = constants; const { pageNames } = Constants; @@ -198,9 +201,12 @@ export const updatePage = async ({ if (page.draftSocialImage?.mediaId) { deletedMediaIds.push(page.draftSocialImage.mediaId); } - page.draftSocialImage = socialImage?.mediaId - ? await sealMedia(socialImage.mediaId) - : undefined; + if (socialImage?.mediaId) { + const sealedMedia = await safeSealMedia(socialImage.mediaId); + if (sealedMedia) { + page.draftSocialImage = sealedMedia; + } + } } if (typeof robotsAllowed === "boolean") { page.draftRobotsAllowed = robotsAllowed; @@ -211,7 +217,12 @@ export const updatePage = async ({ ); for (const mediaId of deletableMediaIds) { - await deleteMedia(mediaId); + try { + await deleteMedia(mediaId); + } catch (err) { + // eslint-disable-next-line no-console + console.log(`Error while deleting media`, mediaId); + } } try { diff --git a/apps/web/lib/replace-temp-media-with-sealed-media-in-page-layout.ts b/apps/web/lib/replace-temp-media-with-sealed-media-in-page-layout.ts index f745d0362..810f6fbf4 100644 --- a/apps/web/lib/replace-temp-media-with-sealed-media-in-page-layout.ts +++ b/apps/web/lib/replace-temp-media-with-sealed-media-in-page-layout.ts @@ -7,7 +7,7 @@ export async function replaceTempMediaWithSealedMediaInPageLayout( ): Promise { const mediaIds = Array.from(extractMediaIDs(JSON.stringify(layout))); for (const mediaId of mediaIds) { - const media = await sealMedia(mediaId); + const media = await safeSealMedia(mediaId); if (media) { layout = replaceMediaURLinPageLayout(layout, mediaId, media); } @@ -16,6 +16,14 @@ export async function replaceTempMediaWithSealedMediaInPageLayout( return layout; } +export async function safeSealMedia(mediaId: string) { + try { + return await sealMedia(mediaId); + } catch (err) { + console.error(`Error while sealing media`, mediaId); + } +} + function replaceMediaURLinPageLayout( layout: any, mediaId: string, From 56b3c65c6675be8cc9986b08567d0cb52fa38aed Mon Sep 17 00:00:00 2001 From: Rajat Date: Sun, 8 Mar 2026 23:36:33 +0530 Subject: [PATCH 06/14] bug fix: lists don't render in text block of email editor --- .../email-editor/src/blocks/text/block.tsx | 134 +++++++++--------- 1 file changed, 64 insertions(+), 70 deletions(-) diff --git a/packages/email-editor/src/blocks/text/block.tsx b/packages/email-editor/src/blocks/text/block.tsx index 2d0a92d7c..8fb77066e 100644 --- a/packages/email-editor/src/blocks/text/block.tsx +++ b/packages/email-editor/src/blocks/text/block.tsx @@ -23,6 +23,39 @@ export function TextBlock({ block, style, selectedBlockId }: TextBlockProps) { const content = block.settings.content || (isSelected ? "" : "Text content"); + // Common text styles to avoid repetition + const commonTextStyles = { + fontFamily: + block.settings.fontFamily || + style?.typography.text.fontFamily || + "Arial, sans-serif", + fontSize: + block.settings.fontSize || + style?.typography.text.fontSize || + "16px", + lineHeight: + block.settings.lineHeight || + style?.typography.text.lineHeight || + "1.5", + letterSpacing: + block.settings.letterSpacing || + style?.typography.text.letterSpacing || + "normal", + textTransform: + block.settings.textTransform || + style?.typography.text.textTransform || + "none", + textDecoration: + block.settings.textDecoration || + style?.typography.text.textDecoration || + "none", + }; + + const headerFontFamily = + block.settings.fontFamily || + style?.typography.header.fontFamily || + "Arial, sans-serif"; + return (
Date: Wed, 11 Mar 2026 23:40:09 +0530 Subject: [PATCH 07/14] Code injection blocks can be completely reset --- apps/web/components/admin/settings/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/web/components/admin/settings/index.tsx b/apps/web/components/admin/settings/index.tsx index ee94136bc..c502a8559 100644 --- a/apps/web/components/admin/settings/index.tsx +++ b/apps/web/components/admin/settings/index.tsx @@ -365,7 +365,10 @@ const Settings = (props: SettingsProps) => { ) => { event.preventDefault(); - if (!newSettings.codeInjectionHead && !newSettings.codeInjectionBody) { + if ( + newSettings.codeInjectionHead === settings.codeInjectionHead && + newSettings.codeInjectionBody === settings.codeInjectionBody + ) { return; } From 7a55b345b5b4fe7a60fff74a3cc57b79787285db Mon Sep 17 00:00:00 2001 From: Rajat Date: Wed, 11 Mar 2026 23:52:54 +0530 Subject: [PATCH 08/14] Preview is disabled for Quiz lessons --- .../content/section/[section]/lesson/page.tsx | 52 ++++++++++--------- apps/web/config/strings.ts | 1 + apps/web/graphql/lessons/helpers.ts | 12 ++++- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/page.tsx b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/page.tsx index 41a92cbef..c581a354b 100644 --- a/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/page.tsx +++ b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/page.tsx @@ -604,32 +604,34 @@ export default function LessonPage() { /> )} - {product?.type?.toLowerCase() !== - UIConstants.COURSE_TYPE_DOWNLOAD && ( -
-
- -

- Allow students to preview this - lesson without enrolling -

+ {product?.type?.toLowerCase() === + Constants.CourseType.COURSE && + lesson.type !== Constants.LessonType.QUIZ && ( +
+
+ +

+ Allow students to preview this + lesson without enrolling +

+
+ + updateLesson({ + requiresEnrollment: + !checked, + }) + } + />
- - updateLesson({ - requiresEnrollment: !checked, - }) - } - /> -
- )} + )}