Skip to content

Commit 4a5f070

Browse files
authored
Merge pull request #40 from duylongpro99/development
feat: rename, remove direct document
2 parents ac25289 + 02f9ad5 commit 4a5f070

File tree

13 files changed

+253
-31
lines changed

13 files changed

+253
-31
lines changed

src/app/(home)/TemplatesGallery.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export const TemplatesGallery: React.FC = () => {
5454
<button
5555
disabled={isCreating}
5656
onClick={() => {
57-
onTemplateClick(tpl.label, "");
57+
onTemplateClick(tpl.label, tpl.initialContent);
5858
}}
5959
style={{
6060
backgroundImage: `url(${tpl.imageUrl})`,

src/app/(home)/document-menu.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,13 @@ export const DocumentMenu: React.FC<Props> = ({
5454
Remove
5555
</DropdownMenuItem>
5656
</RemoveDialog>
57-
<DropdownMenuItem onClick={() => onNewTab(documentId)}>
57+
<DropdownMenuItem
58+
onSelect={(e) => e.preventDefault()}
59+
onClick={(e) => {
60+
e.stopPropagation();
61+
onNewTab(documentId);
62+
}}
63+
>
5864
<ExternalLinkIcon className="size-4 mr-2" />
5965
Open in a new tab
6066
</DropdownMenuItem>

src/app/api/auth/liveblocks/route.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,22 @@ import { api } from "../../../../../convex/_generated/api";
66
// Ensure these environment variables are defined in your GitHub Actions workflow
77
// Add error handling for missing environment variables
88
const convex = new ConvexHttpClient(
9-
process.env.NEXT_PUBLIC_CONVEX_URL ??
10-
(() => { throw new Error("NEXT_PUBLIC_CONVEX_URL environment variable is not defined") })()
9+
process.env.NEXT_PUBLIC_CONVEX_URL ??
10+
(() => {
11+
throw new Error(
12+
"NEXT_PUBLIC_CONVEX_URL environment variable is not defined"
13+
);
14+
})()
1115
);
1216

1317
const liveblocks = new Liveblocks({
14-
secret: process.env.LIVE_BLOCK_SECRET_API_KEY ??
15-
(() => { throw new Error("LIVE_BLOCK_SECRET_API_KEY environment variable is not defined") })()
18+
secret:
19+
process.env.LIVE_BLOCK_SECRET_API_KEY ??
20+
(() => {
21+
throw new Error(
22+
"LIVE_BLOCK_SECRET_API_KEY environment variable is not defined"
23+
);
24+
})(),
1625
});
1726

1827
export async function POST(req: Request) {

src/app/document/[documentId]/(navbar)/menu-bar.tsx

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,43 @@ import {
3232
Undo2Icon,
3333
} from "lucide-react";
3434
import { Doc } from "../../../../../convex/_generated/dataModel";
35+
import { useMutation } from "convex/react";
36+
import { api } from "../../../../../convex/_generated/api";
37+
import { useRouter } from "next/navigation";
38+
import { useToast } from "@/hooks/use-toast";
39+
import { RemoveDialog } from "@/components/remove-dialog";
40+
import { RenameDialog } from "@/components/rename-dialog";
3541

3642
type Props = {
3743
data: Doc<"documents">;
3844
};
3945

4046
export const MenuBar: React.FC<Props> = ({ data }) => {
47+
const router = useRouter();
4148
const { editor } = useEditorStore();
49+
const mutation = useMutation(api.document.create);
50+
const { toast } = useToast();
51+
52+
const onNewDoc = () => {
53+
mutation({
54+
title: "Untitled",
55+
initialContent: "",
56+
})
57+
.then((id) => {
58+
toast({
59+
title: "New document created",
60+
description: "New document has been created.",
61+
});
62+
router.push(`/document/${id}`);
63+
})
64+
.catch(() => {
65+
toast({
66+
title: "Document creation failed",
67+
description: "Your document could not be created",
68+
variant: "destructive",
69+
});
70+
});
71+
};
4272

4373
const addTable = ({ rows, cols }: { rows: number; cols: number }) => {
4474
editor
@@ -129,22 +159,32 @@ export const MenuBar: React.FC<Props> = ({ data }) => {
129159
</MenubarSubContent>
130160
</MenubarSub>
131161

132-
<MenubarItem>
162+
<MenubarItem onClick={onNewDoc}>
133163
<FilePlusIcon className="size-4 mr-2" />
134164
New Document
135165
</MenubarItem>
136166

137167
<MenubarSeparator />
138168

139-
<MenubarItem>
140-
<FilePenIcon className="size-4 mr-2" />
141-
Rename
142-
</MenubarItem>
169+
<RenameDialog documentId={data._id} title={data.title}>
170+
<MenubarItem
171+
onClick={(e) => e.stopPropagation()}
172+
onSelect={(e) => e.preventDefault()}
173+
>
174+
<FilePenIcon className="size-4 mr-2" />
175+
Rename
176+
</MenubarItem>
177+
</RenameDialog>
143178

144-
<MenubarItem>
145-
<TrashIcon className="size-4 mr-2" />
146-
Remove
147-
</MenubarItem>
179+
<RemoveDialog documentId={data._id}>
180+
<MenubarItem
181+
onClick={(e) => e.stopPropagation()}
182+
onSelect={(e) => e.preventDefault()}
183+
>
184+
<TrashIcon className="size-4 mr-2" />
185+
Remove
186+
</MenubarItem>
187+
</RemoveDialog>
148188

149189
<MenubarSeparator />
150190
<MenubarItem onClick={() => window?.print()}>

src/app/document/[documentId]/(ruler)/rulers.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1+
import { INITIAL_MG, MINIMUM_SPACE, PAGE_WIDTH } from "@/constants/measure";
12
import { useMutation, useStorage } from "@liveblocks/react/suspense";
23
import React, { useRef, useState } from "react";
34
import { Marker } from "./markers";
45

56
const makers = Array.from({ length: 83 }, (_, i) => i);
67

7-
const PAGE_WIDTH = 816;
8-
const MINIMUM_SPACE = 100;
9-
const INITIAL_MG = 56;
10-
118
export const Ruler: React.FC = () => {
129
const leftMg = useStorage((root) => root.leftMg) ?? INITIAL_MG;
1310
const rightMg = useStorage((root) => root.rightMg) ?? INITIAL_MG;

src/app/document/[documentId]/document.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const Document: React.FC<Props> = ({ preloadedDocument }) => {
2121
</div>
2222

2323
<div className="pt-[114px] print:pt-0">
24-
<Editor />
24+
<Editor initialContent={document.initialContent} />
2525
</div>
2626
</div>
2727
</Room>

src/app/document/[documentId]/editor.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { EditorContent, useEditor } from "@tiptap/react";
1818
import StarterKit from "@tiptap/starter-kit";
1919
import ResizeImage from "tiptap-extension-resize-image";
2020

21+
import { INITIAL_MG } from "@/constants/measure";
2122
import { FontSizeExtension } from "@/extensions/font-size";
2223
import { LineHeightExtension } from "@/extensions/line-height";
2324
import { useLiveblocksExtension } from "@liveblocks/react-tiptap";
@@ -26,11 +27,18 @@ import TextStyle from "@tiptap/extension-text-style";
2627
import { Ruler } from "./(ruler)/rulers";
2728
import { Threads } from "./threads";
2829

29-
export const Editor: React.FC = () => {
30+
type Props = {
31+
initialContent?: string;
32+
};
33+
34+
export const Editor: React.FC<Props> = ({ initialContent }) => {
3035
const leftMg = useStorage((root) => root.leftMg);
3136
const rightMg = useStorage((root) => root.rightMg);
3237
const { setEditor } = useEditorStore();
33-
const liveblocks = useLiveblocksExtension();
38+
const liveblocks = useLiveblocksExtension({
39+
initialContent,
40+
offlineSupport_experimental: true,
41+
});
3442

3543
const editor = useEditor({
3644
immediatelyRender: false,
@@ -60,7 +68,7 @@ export const Editor: React.FC = () => {
6068
},
6169
editorProps: {
6270
attributes: {
63-
style: `padding-left: ${leftMg ?? 56}px; padding-right: ${rightMg ?? 56}px;`,
71+
style: `padding-left: ${leftMg ?? INITIAL_MG}px; padding-right: ${rightMg ?? INITIAL_MG}px;`,
6472
class:
6573
"focus:outline-none print:border-0 bg-white border-[#c7c7c7] flex flex-col min-h-[1054px] w-[816px] pt-10 pr-14 pb-10 cursor-text",
6674
},

src/app/document/[documentId]/room.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client";
22

33
import { FullscreenLoader } from "@/components/fullscreen-loader";
4+
import { INITIAL_MG } from "@/constants/measure";
45
import { useToast } from "@/hooks/use-toast";
56
import {
67
ClientSideSuspense,
@@ -82,8 +83,8 @@ export function Room({ children }: { children: ReactNode }) {
8283
<RoomProvider
8384
id={params.documentId}
8485
initialStorage={{
85-
leftMg: 56,
86-
rightMg: 56,
86+
leftMg: INITIAL_MG,
87+
rightMg: INITIAL_MG,
8788
}}
8889
>
8990
<ClientSideSuspense

src/app/document/[documentId]/threads.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1-
import { useThreads } from "@liveblocks/react/suspense";
21
import {
32
AnchoredThreads,
43
FloatingComposer,
54
FloatingThreads,
65
} from "@liveblocks/react-tiptap";
6+
import { ClientSideSuspense, useThreads } from "@liveblocks/react/suspense";
77
import { Editor } from "@tiptap/react";
88

9-
export function Threads({ editor }: { editor: Editor | null }) {
9+
export const Threads = ({ editor }: { editor: Editor | null }) => {
10+
return (
11+
<ClientSideSuspense fallback={null}>
12+
<ThreadsList editor={editor} />
13+
</ClientSideSuspense>
14+
);
15+
};
16+
17+
function ThreadsList({ editor }: { editor: Editor | null }) {
1018
const { threads } = useThreads({ query: { resolved: false } });
1119

1220
return (
@@ -22,4 +30,4 @@ export function Threads({ editor }: { editor: Editor | null }) {
2230
<FloatingComposer editor={editor} className="floating-composer" />
2331
</>
2432
);
25-
}
33+
}

src/components/remove-dialog.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { useToast } from "@/hooks/use-toast";
44
import { useMutation } from "convex/react";
5+
import { useRouter } from "next/navigation";
56
import React, { useState } from "react";
67
import { api } from "../../convex/_generated/api";
78
import { Id } from "../../convex/_generated/dataModel";
@@ -25,6 +26,7 @@ export const RemoveDialog: React.FC<Props> = ({ children, documentId }) => {
2526
const remove = useMutation(api.document.remove);
2627
const [isRemoving, setIsRemoving] = useState<boolean>(false);
2728
const { toast } = useToast();
29+
const router = useRouter();
2830

2931
return (
3032
<AlertDialog>
@@ -47,12 +49,13 @@ export const RemoveDialog: React.FC<Props> = ({ children, documentId }) => {
4749
remove({
4850
documentId,
4951
})
50-
.then(() =>
52+
.then(() => {
5153
toast({
5254
title: "Document removed!",
5355
variant: "default",
54-
})
55-
)
56+
});
57+
router.push("/");
58+
})
5659
.catch(() => {
5760
toast({
5861
title: "Cannot delete!",

0 commit comments

Comments
 (0)