Skip to content

Commit a4efa4a

Browse files
author
Rajat
committed
Added error handler to text editor; added highlight extension;
1 parent 04922ae commit a4efa4a

10 files changed

Lines changed: 102 additions & 76 deletions

File tree

4.49 MB
Loading

apps/docs/src/pages/en/website/blocks.md

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ layout: ../../../layouts/MainLayout.astro
66

77
Every page in CourseLit is made up of various blocks, stacked in a top-to-bottom fashion. Each block serves a unique purpose and can be customized.
88

9-
The following screenshot shows [Header](/en/pages/header), [Rich Text](/en/pages/banner), [Hero](/en/pages/content), and [Grid](/en/pages/grid) blocks (top to bottom) in action. Different blocks are highlighted in different colors.
9+
The following screenshot shows [Header](/en/website/blocks#header), [Rich Text](/en/website/blocks#rich-text), [Hero](/en/website/blocks#hero), and [Grid](/en/website/blocks#grid) blocks (top to bottom) in action. Different blocks are highlighted in different colors.
1010

1111
![CourseLit page blocks](/assets/pages/page-builder-blocks.png)
1212

@@ -36,32 +36,40 @@ You will also see the newly added link on the header itself.
3636
3. Click on the pencil icon against the newly added link to edit it as shown above.
3737
4. Change the label (displayed as text on the header block) and the URL (where the user should be taken upon clicking the label on the header) and click `Done` to save.
3838
![Header edit link](/assets/pages/header-edit-link.png)
39-
</details>
39+
</details>
4040

4141
### [Rich Text](#rich-text)
4242

4343
<details>
4444
<summary>Expand to see Rich Text block details</summary>
4545

46-
The rich text block can be used to add text blocks containing elements like hyperlinks, etc.
46+
The rich text block uses the same text editor available elsewhere on the platform. It supports all functionality that does not require a toolbar, as the toolbar is hidden in this block.
4747

48-
#### Making text bold/italic/underline
48+
#### Keyboard shortcuts
4949

5050
1. Select the text.
51-
2. To make the selected text bold, press <kbd>Ctrl+B</kbd>; to make it italic, press <kbd>Ctrl+I</kbd>; and for underline, press <kbd>Ctrl+U</kbd>.
52-
53-
You can also use the floating controls to do the same as shown below.
51+
2. Use the following shortcuts to format it:
52+
53+
- **Bold**: <kbd>Ctrl+B</kbd>
54+
- **Italic**: <kbd>Ctrl+I</kbd>
55+
- **Underline**: <kbd>Ctrl+U</kbd>
56+
- **Strikethrough**: <kbd>Ctrl+Shift+S</kbd>
57+
- **Undo**: <kbd>Ctrl+Z</kbd>
58+
- **Redo**: <kbd>Ctrl+Shift+Z</kbd>
59+
- **Paste**: <kbd>Ctrl+V</kbd>
60+
- **Ordered list**: <kbd>Ctrl+Shift+7</kbd>
61+
- **Bulleted list**: <kbd>Ctrl+Shift+8</kbd>
62+
- **Highlight**: <kbd>Ctrl+Shift+H</kbd> (or type `==two equal signs==`)
5463

5564
![Stylised text](/assets/pages/rich-text-styling.gif)
5665

5766
#### Creating hyperlinks
5867

5968
1. Select the text.
60-
> Double-clicking the text to select won't work due to a bug. We are working on it.
61-
2. Click on the floating `link` button to reveal a popup text input.
62-
3. In the popup text input, enter the URL as shown below.
63-
![Create a hyperlink in rich text block](/assets/pages/rich-text-create-hyperlink.gif)
64-
</details>
69+
2. Click on the floating `link` icon to reveal a text input.
70+
3. In the popup text input, enter the URL as shown below and press <kbd>Enter</kbd>.
71+
![Create a hyperlink in rich text block](/assets/pages/courselit-text-editor-create-links.gif)
72+
</details>
6573

6674
### [Hero](#hero)
6775

@@ -87,7 +95,7 @@ Following is how it looks on a page.
8795
4. In the button action, enter the URL the user should be taken to upon clicking.
8896
a. If the URL is from your own school, use its relative form, i.e., `/courses`.
8997
b. If the URL is from some external website, use the absolute (complete) URL, i.e., `https://website.com/courses`.
90-
</details>
98+
</details>
9199

92100
### [Grid](#grid)
93101

@@ -132,7 +140,7 @@ A grid block comes in handy when you want to show some sort of list, for example
132140
4. In the button action, enter the URL the user should be taken to upon clicking.
133141
a. If the URL is from your own school, use its relative form, i.e., `/courses`.
134142
b. If the URL is from some external website, use the absolute (complete) URL, i.e., `https://website.com/courses`.
135-
</details>
143+
</details>
136144

137145
### [Featured](#featured)
138146

@@ -268,7 +276,7 @@ In the `Design` panel, you can customize:
268276
- Maximum width
269277
- Vertical padding
270278
- Social media links (Facebook, Twitter, Instagram, LinkedIn, YouTube, Discord, GitHub)
271-
</details>
279+
</details>
272280

273281
## [Shared blocks](#shared-blocks)
274282

apps/web/components/admin/blogs/editor/details.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,13 @@ export default function Details({ id }: DetailsProps) {
150150
onChange={(state: any) => setDescription(state)}
151151
url={address.backend}
152152
placeholder={TEXT_EDITOR_PLACEHOLDER}
153+
onError={(err: any) => {
154+
toast({
155+
title: TOAST_TITLE_ERROR,
156+
description: err,
157+
variant: "destructive",
158+
});
159+
}}
153160
/>
154161
<div>
155162
<Button type="submit" disabled={loading}>

packages/page-blocks/src/components/text-renderer.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,11 @@ export function TextRenderer({ json, className, theme }: TextRendererProps) {
7272
</Header3>
7373
);
7474
},
75-
codeMirror: ({ children }) => {
76-
return (
77-
<pre>
78-
<code>{children}</code>
79-
</pre>
80-
);
81-
},
75+
codeMirror: ({ children }) => (
76+
<pre>
77+
<code>{children}</code>
78+
</pre>
79+
),
8280
},
8381
markMapping: {
8482
link: ({ mark, children, node }) => {
@@ -95,6 +93,11 @@ export function TextRenderer({ json, className, theme }: TextRendererProps) {
9593
</Link>
9694
);
9795
},
96+
highlight: ({ children }) => (
97+
<mark className="bg-accent text-accent-foreground">
98+
{children}
99+
</mark>
100+
),
98101
},
99102
},
100103
});

packages/text-editor/README.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,20 @@ import "@courselit/text-editor/styles.css";
2626

2727
`Ctrl + u`: Underline
2828

29-
`Ctrl + d`: Strikethrough
30-
31-
`Ctrl + k`: Create/edit a link
29+
`Ctrl + Shift + s`: Strikethrough
3230

3331
`Ctrl + z`: Undo
3432

3533
`Ctrl + Z`: Redo
3634

3735
`Ctrl + v`: Paste
3836

39-
`Ctrl + Shift + 8`: Bulleted list
37+
`Ctrl + Shift + 7`: Ordered list
4038

41-
`Ctrl + Shift + 9`: Ordered list
39+
`Ctrl + Shift + 8`: Bulleted list
4240

43-
`Ctrl + Shift + 7`: Task list
41+
`Ctrl + Shift + H`: Highlight (or type `==two equal signs==` and it will be converted to highlight)
4442

4543
## Images
4644

47-
Use the _Image_ button in the toolbar to upload assets to CourseLit. Uploads are limited to 2MB per file.
45+
Use the _Image_ button in the toolbar to upload assets to CourseLit. Uploads are limited to `2 Mega bytes` per file.

packages/text-editor/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"@tiptap/extension-dropcursor": "^3.0.0",
5959
"@tiptap/extension-gapcursor": "^3.0.0",
6060
"@tiptap/extension-heading": "^3.0.0",
61+
"@tiptap/extension-highlight": "^3.11.0",
6162
"@tiptap/extension-image": "^3.0.0",
6263
"@tiptap/extension-link": "^3.0.0",
6364
"@tiptap/extension-placeholder": "^3.0.0",

packages/text-editor/src/editor.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ export interface EditorProps {
2828
initialContent?: ReactEditorProps["initialContent"];
2929
placeholder?: string;
3030
autoFocus?: boolean;
31+
imageSizeLimit?: number;
32+
onError?: (...args: any[]) => void;
3133
}
3234

3335
interface EditorType extends FC<PropsWithChildren<EditorProps>> {
@@ -46,6 +48,8 @@ const Editor: EditorType = Object.assign(
4648
refresh,
4749
url,
4850
autoFocus,
51+
imageSizeLimit,
52+
onError,
4953
}) => {
5054
const [isUploading, setIsUploading] = useState(false);
5155
const fileInputRef = useRef<HTMLInputElement | null>(null);
@@ -144,7 +148,12 @@ const Editor: EditorType = Object.assign(
144148
async (file: File) => {
145149
try {
146150
setIsUploading(true);
147-
const result = await uploadImageToMediaLit(url, file);
151+
const result = await uploadImageToMediaLit({
152+
url,
153+
file,
154+
fileSizeLimit: imageSizeLimit,
155+
onError,
156+
});
148157
editor
149158
?.chain()
150159
.focus()

packages/text-editor/src/extensions.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Dropcursor from "@tiptap/extension-dropcursor";
1212
import Gapcursor from "@tiptap/extension-gapcursor";
1313
import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
1414
import Heading from "@tiptap/extension-heading";
15+
import Highlight from "@tiptap/extension-highlight";
1516
import { lowlight } from "lowlight";
1617
import javascript from "highlight.js/lib/languages/javascript";
1718
import typescript from "highlight.js/lib/languages/typescript";
@@ -58,6 +59,7 @@ export const createExtensions = ({
5859
},
5960
resize: {
6061
enabled: true,
62+
directions: ["top", "bottom", "left", "right"],
6163
alwaysPreserveAspectRatio: true,
6264
},
6365
}),
@@ -89,4 +91,5 @@ export const createExtensions = ({
8991
];
9092
},
9193
}),
94+
Highlight,
9295
];
Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { FetchBuilder } from "@courselit/utils";
22
import { Media } from "@courselit/common-models";
33

4-
type SetProgress = (progress: number) => void;
5-
64
async function getPresignedUrl(url: string) {
75
const fetch = new FetchBuilder()
86
.setUrl(`${url}/api/media/presigned`)
@@ -12,17 +10,29 @@ async function getPresignedUrl(url: string) {
1210
}
1311

1412
export interface UploadedImage {
13+
mediaId: string;
1514
src: string;
1615
fileName?: string;
1716
}
1817

19-
export async function uploadImageToMediaLit(
20-
url: string,
21-
file: File,
22-
progress?: SetProgress,
23-
): Promise<UploadedImage> {
24-
if (file.size > 2097152) {
25-
throw new Error("File is larger than 2MB");
18+
export async function uploadImageToMediaLit({
19+
url,
20+
file,
21+
fileSizeLimit = 2097152, // 2 MB,
22+
onError,
23+
}: {
24+
url: string;
25+
file: File;
26+
fileSizeLimit?: number;
27+
onError?: (args: any) => void;
28+
}): Promise<UploadedImage> {
29+
if (file.size > fileSizeLimit) {
30+
if (onError) {
31+
onError("File is larger than 2MB");
32+
return { src: "", mediaId: "", fileName: "" };
33+
} else {
34+
throw new Error("File is larger than 2MB");
35+
}
2636
}
2737

2838
const { signature, endpoint } = await getPresignedUrl(url);
@@ -40,14 +50,11 @@ export async function uploadImageToMediaLit(
4050
body: formData,
4151
});
4252

43-
if (progress) {
44-
progress(1);
45-
}
46-
4753
const data: Media = await response.json();
4854

4955
return {
5056
src: data.file,
5157
fileName: data.originalFileName,
58+
mediaId: data.mediaId,
5259
};
5360
}

0 commit comments

Comments
 (0)