Skip to content

Commit e3a1b7b

Browse files
author
Rajat Saxena
committed
Embed and Marquee page blocks and icons for grid blocks
1 parent 1bfad88 commit e3a1b7b

44 files changed

Lines changed: 2282 additions & 465 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/web/components/admin/page-editor/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,7 @@ export default function PageEditor({
829829
leftPaneContent === "widgets"
830830
? EDIT_PAGE_ADD_WIDGET_TITLE
831831
: leftPaneContent === "editor"
832-
? "Edit Widget"
832+
? "Edit Block"
833833
: leftPaneContent === "fonts"
834834
? "Fonts"
835835
: leftPaneContent === "theme"

apps/web/graphql/pages/logic.ts

Lines changed: 74 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -265,91 +265,91 @@ export const getPages = async (
265265
};
266266

267267
export const initMandatoryPages = async (domain: Domain, user: User) => {
268-
await PageModel.insertMany<Page>([
268+
await PageModel.bulkWrite([
269269
{
270-
domain: domain._id,
271-
pageId: defaultPages[0],
272-
type: site,
273-
creatorId: user.userId,
274-
name: pageNames.home,
275-
entityId: domain.name,
276-
layout: [
277-
{
278-
name: "header",
279-
deleteable: false,
280-
shared: true,
281-
},
282-
...homePageTemplate,
283-
{
284-
name: "footer",
285-
deleteable: false,
286-
shared: true,
270+
updateOne: {
271+
filter: { domain: domain._id, pageId: defaultPages[0] },
272+
update: {
273+
$setOnInsert: {
274+
domain: domain._id,
275+
pageId: defaultPages[0],
276+
type: site,
277+
creatorId: user.userId,
278+
name: pageNames.home,
279+
entityId: domain.name,
280+
layout: [
281+
{ name: "header", deleteable: false, shared: true },
282+
...homePageTemplate,
283+
{ name: "footer", deleteable: false, shared: true },
284+
],
285+
draftLayout: [],
286+
},
287287
},
288-
],
289-
draftLayout: [],
288+
upsert: true,
289+
},
290290
},
291291
{
292-
domain: domain._id,
293-
pageId: defaultPages[2],
294-
type: site,
295-
creatorId: user.userId,
296-
name: pageNames.privacy,
297-
entityId: domain.name,
298-
layout: [
299-
{
300-
name: "header",
301-
deleteable: false,
302-
shared: true,
303-
},
304-
{
305-
name: "footer",
306-
deleteable: false,
307-
shared: true,
292+
updateOne: {
293+
filter: { domain: domain._id, pageId: defaultPages[2] },
294+
update: {
295+
$setOnInsert: {
296+
domain: domain._id,
297+
pageId: defaultPages[2],
298+
type: site,
299+
creatorId: user.userId,
300+
name: pageNames.privacy,
301+
entityId: domain.name,
302+
layout: [
303+
{ name: "header", deleteable: false, shared: true },
304+
{ name: "footer", deleteable: false, shared: true },
305+
],
306+
draftLayout: [],
307+
},
308308
},
309-
],
310-
draftLayout: [],
309+
upsert: true,
310+
},
311311
},
312312
{
313-
domain: domain._id,
314-
pageId: defaultPages[1],
315-
type: site,
316-
creatorId: user.userId,
317-
name: pageNames.terms,
318-
entityId: domain.name,
319-
layout: [
320-
{
321-
name: "header",
322-
deleteable: false,
323-
shared: true,
324-
},
325-
{
326-
name: "footer",
327-
deleteable: false,
328-
shared: true,
313+
updateOne: {
314+
filter: { domain: domain._id, pageId: defaultPages[1] },
315+
update: {
316+
$setOnInsert: {
317+
domain: domain._id,
318+
pageId: defaultPages[1],
319+
type: site,
320+
creatorId: user.userId,
321+
name: pageNames.terms,
322+
entityId: domain.name,
323+
layout: [
324+
{ name: "header", deleteable: false, shared: true },
325+
{ name: "footer", deleteable: false, shared: true },
326+
],
327+
draftLayout: [],
328+
},
329329
},
330-
],
331-
draftLayout: [],
330+
upsert: true,
331+
},
332332
},
333333
{
334-
domain: domain._id,
335-
pageId: defaultPages[3],
336-
type: blogPage,
337-
creatorId: user.userId,
338-
name: pageNames.blog,
339-
entityId: domain.name,
340-
layout: [
341-
{
342-
name: "header",
343-
deleteable: false,
344-
shared: true,
345-
},
346-
{
347-
name: "footer",
348-
deleteable: false,
349-
shared: true,
334+
updateOne: {
335+
filter: { domain: domain._id, pageId: defaultPages[3] },
336+
update: {
337+
$setOnInsert: {
338+
domain: domain._id,
339+
pageId: defaultPages[3],
340+
type: blogPage,
341+
creatorId: user.userId,
342+
name: pageNames.blog,
343+
entityId: domain.name,
344+
layout: [
345+
{ name: "header", deleteable: false, shared: true },
346+
{ name: "footer", deleteable: false, shared: true },
347+
],
348+
draftLayout: [],
349+
},
350350
},
351-
],
352-
draftLayout: [],
351+
upsert: true,
352+
},
353353
},
354354
]);
355355
};

apps/web/ui-config/widgets.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ import {
1212
FAQ,
1313
Pricing,
1414
Media,
15+
Marquee,
16+
Embed,
1517
} from "@courselit/page-blocks";
1618

1719
function loadWidgets(): Record<string, any> {
1820
const widgets: Record<string, Widget> = {};
1921

20-
// Add common widgets to CourseLit
22+
// Adding page blocks to CourseLit
2123
widgets[RichText.metadata.name] = RichText;
2224
widgets[Featured.metadata.name] = Featured;
2325
widgets[Banner.metadata.name] = Banner;
@@ -27,14 +29,11 @@ function loadWidgets(): Record<string, any> {
2729
widgets[FAQ.metadata.name] = FAQ;
2830
widgets[Pricing.metadata.name] = Pricing;
2931
widgets[Media.metadata.name] = Media;
32+
widgets[Marquee.metadata.name] = Marquee;
33+
widgets[Embed.metadata.name] = Embed;
34+
widgets[EmailForm.metadata.name] = EmailForm;
3035
widgets[Footer.metadata.name] = Object.assign({}, Footer, { shared: true });
3136
widgets[Header.metadata.name] = Object.assign({}, Header, { shared: true });
32-
widgets[EmailForm.metadata.name] = Object.assign({}, EmailForm, {
33-
shared: true,
34-
});
35-
36-
// Additional widgets are added here
37-
// widgets[buttondown.metadata.name] = buttondown;
3837

3938
return widgets;
4039
}
Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,74 @@
11
import * as React from "react";
22
import Section from "./section";
3+
import {
4+
Accordion,
5+
AccordionContent,
6+
AccordionItem,
7+
AccordionTrigger,
8+
} from "./components/ui/accordion";
9+
10+
interface AdminWidgetPanelContainerProps {
11+
children: React.ReactNode;
12+
className?: string;
13+
type?: "single" | "multiple";
14+
defaultValue?: string | string[];
15+
}
16+
17+
export function AdminWidgetPanelContainer({
18+
children,
19+
className = "",
20+
type = "multiple",
21+
defaultValue,
22+
}: AdminWidgetPanelContainerProps) {
23+
return (
24+
<div className={`flex flex-col gap-4 mb-4 ${className}`}>
25+
{type === "single" ? (
26+
<Accordion
27+
type="single"
28+
collapsible
29+
defaultValue={defaultValue as string}
30+
>
31+
{children}
32+
</Accordion>
33+
) : (
34+
<Accordion
35+
type="multiple"
36+
defaultValue={defaultValue as string[]}
37+
>
38+
{children}
39+
</Accordion>
40+
)}
41+
</div>
42+
);
43+
}
344

445
interface AdminWidgetPanelProps {
546
title?: string;
647
children: React.ReactNode;
748
className?: string;
49+
value: string;
50+
defaultExpanded?: boolean;
851
}
952

10-
export default function AdminWidgetPanel({
53+
export function AdminWidgetPanel({
1154
title,
1255
children,
1356
className = "",
57+
value,
1458
}: AdminWidgetPanelProps) {
59+
if (!title) {
60+
// If no title, render as non-collapsible section
61+
return <Section className={className}>{children}</Section>;
62+
}
63+
1564
return (
16-
<Section className={className}>
17-
{title && <h2 className="text-lg font-semibold">{title}</h2>}
18-
{children}
19-
</Section>
65+
<AccordionItem value={value} className={className}>
66+
<AccordionTrigger className="text-base hover:no-underline">
67+
{title}
68+
</AccordionTrigger>
69+
<AccordionContent className="flex flex-col gap-4">
70+
{children}
71+
</AccordionContent>
72+
</AccordionItem>
2073
);
2174
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import * as React from "react";
2+
import { cva, type VariantProps } from "class-variance-authority";
3+
4+
import { cn } from "@/lib/utils";
5+
6+
const alertVariants = cva(
7+
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
8+
{
9+
variants: {
10+
variant: {
11+
default: "bg-background text-foreground",
12+
destructive:
13+
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
14+
},
15+
},
16+
defaultVariants: {
17+
variant: "default",
18+
},
19+
},
20+
);
21+
22+
const Alert = React.forwardRef<
23+
HTMLDivElement,
24+
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
25+
>(({ className, variant, ...props }, ref) => (
26+
<div
27+
ref={ref}
28+
role="alert"
29+
className={cn(alertVariants({ variant }), className)}
30+
{...props}
31+
/>
32+
));
33+
Alert.displayName = "Alert";
34+
35+
const AlertTitle = React.forwardRef<
36+
HTMLParagraphElement,
37+
React.HTMLAttributes<HTMLHeadingElement>
38+
>(({ className, ...props }, ref) => (
39+
<h5
40+
ref={ref}
41+
className={cn(
42+
"mb-1 font-medium leading-none tracking-tight",
43+
className,
44+
)}
45+
{...props}
46+
/>
47+
));
48+
AlertTitle.displayName = "AlertTitle";
49+
50+
const AlertDescription = React.forwardRef<
51+
HTMLParagraphElement,
52+
React.HTMLAttributes<HTMLParagraphElement>
53+
>(({ className, ...props }, ref) => (
54+
<div
55+
ref={ref}
56+
className={cn("text-sm [&_p]:leading-relaxed", className)}
57+
{...props}
58+
/>
59+
));
60+
AlertDescription.displayName = "AlertDescription";
61+
62+
export { Alert, AlertTitle, AlertDescription };

packages/components-library/src/index.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import TextEditor, { emptyDoc as TextEditorEmptyDoc } from "./text-editor";
1111
import TextRenderer from "./text-renderer";
1212
import LessonIcon from "./lesson-icon";
1313
import ColorSelector from "./color-selector";
14-
import AdminWidgetPanel from "./admin-widget-panel";
1514
import Button from "./button";
1615
import IconButton from "./icon-button";
1716
import Form from "./form";
@@ -41,14 +40,17 @@ import Tooltip from "./tooltip";
4140
import DragAndDrop from "./drag-and-drop";
4241

4342
export { Button as Button2 } from "./components/ui/button";
44-
export * from "./menu";
4543
export * from "./components/ui/avatar";
4644
export * from "./components/ui/accordion";
4745
export * from "./components/ui/slider";
4846
export * from "./components/ui/card";
4947
export * from "./components/ui/badge";
5048
export * from "./components/ui/skeleton";
49+
export * from "./components/ui/textarea";
50+
export * from "./components/ui/alert";
5151

52+
export * from "./admin-widget-panel";
53+
export * from "./menu";
5254
export * from "./toast2";
5355
export * from "./paginated-table";
5456
import getSymbolFromCurrency from "currency-symbol-map";
@@ -58,6 +60,7 @@ export * from "./video-with-preview";
5860
export * from "./image";
5961
export * from "./vertical-padding-selector";
6062
export * from "./max-width-selector";
63+
export * from "./lib/utils";
6164

6265
export {
6366
PriceTag,
@@ -72,7 +75,6 @@ export {
7275
TextRenderer,
7376
LessonIcon,
7477
ColorSelector,
75-
AdminWidgetPanel,
7678
Button,
7779
IconButton,
7880
Form,

0 commit comments

Comments
 (0)