Skip to content

Commit

Permalink
✨ feat(documents):Add liveblocks
Browse files Browse the repository at this point in the history
  • Loading branch information
BlackishGreen33 committed Dec 16, 2024
1 parent cd9b116 commit 30f704b
Show file tree
Hide file tree
Showing 16 changed files with 455 additions and 31 deletions.
Binary file modified bun.lockb
Binary file not shown.
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@
"@lexical/rich-text": "^0.19.0",
"@lexical/selection": "^0.19.0",
"@lexical/utils": "^0.19.0",
"@liveblocks/client": "^2.11.0",
"@liveblocks/node": "^2.11.0",
"@liveblocks/react": "^2.11.0",
"@liveblocks/react-lexical": "^2.11.0",
"@liveblocks/react-tiptap": "^2.14.0",
"@liveblocks/react-ui": "^2.11.0",
"@liveblocks/client": "^2.12.2",
"@liveblocks/node": "^2.12.2",
"@liveblocks/react": "^2.12.2",
"@liveblocks/react-lexical": "^2.12.2",
"@liveblocks/react-tiptap": "^2.12.2",
"@liveblocks/react-ui": "^2.12.2",
"@mantine/hooks": "^7.15.0",
"@nextui-org/react": "^2.6.8",
"@pinecone-database/pinecone": "^4.0.0",
Expand Down Expand Up @@ -126,6 +126,7 @@
"tiptap-extension-resize-image": "^1.2.1",
"uploadthing": "^7.4.0",
"vaul": "^1.1.1",
"y-protocols": "^1.0.6",
"zod": "^3.23.8",
"zustand": "^5.0.2"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client';

import { NextPage } from 'next';

import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
'use client';

import { useGetDocument } from '@/common/api/documents';
import { Editor, Navbar, Toolbar } from '@/common/components/documents';
import { Editor, Navbar, Room, Toolbar } from '@/common/components/documents';
import { PageError, PageLoader } from '@/common/components/elements';

// import { Room } from "./room";

interface DocumentProps {
documentId: string;
}
Expand All @@ -22,17 +20,17 @@ const DocumentClient: React.FC<DocumentProps> = ({ documentId }) => {
}

return (
// <Room>
<div className="min-h-screen bg-[#F9FBFD]">
<div className="fixed left-0 right-0 top-0 z-10 flex flex-col gap-y-2 bg-neutral-50 px-4 pt-2 print:hidden">
<Navbar data={data} />
<Toolbar />
</div>
<div className="pt-[114px] print:pt-0">
<Editor initialContent={data.initialContent} />
<Room>
<div className="min-h-screen bg-[#F9FBFD]">
<div className="fixed left-0 right-0 top-0 z-10 flex flex-col gap-y-2 bg-neutral-50 px-4 pt-2 print:hidden">
<Navbar data={data} />
<Toolbar />
</div>
<div className="pt-[114px] print:pt-0">
<Editor initialContent={data.initialContent} />
</div>
</div>
</div>
// </Room>
</Room>
);
};

Expand Down
17 changes: 17 additions & 0 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type { Metadata } from 'next';
import { Inter as FontSans } from 'next/font/google';

import '@/common/styles/globals.scss';
import '@liveblocks/react-tiptap/styles.css';
import '@liveblocks/react-ui/styles.css';
import 'react-loading-skeleton/dist/skeleton.css';
import 'simplebar-react/dist/simplebar.min.css';

Expand All @@ -24,6 +26,20 @@ export default function RootLayout({
}: Readonly<{
children: React.ReactNode;
}>) {
const chatbotScript = `
<script>
window.embeddedChatbotConfig = {
chatbotId: "yywnk94ZYc4X6DzPiNKFv",
domain: "www.chatbase.co"
}
</script>
<script
src="https://www.chatbase.co/embed.min.js"
chatbotId="yywnk94ZYc4X6DzPiNKFv"
domain="www.chatbase.co"
defer>
</script>
`;
return (
<html lang="en" suppressHydrationWarning>
<body
Expand All @@ -33,6 +49,7 @@ export default function RootLayout({
<Toaster />
{children}
</Provider>
<div dangerouslySetInnerHTML={{ __html: chatbotScript }} />
</body>
</html>
);
Expand Down
62 changes: 62 additions & 0 deletions src/common/components/documents/Avatars.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use client';

import { ClientSideSuspense } from '@liveblocks/react';
import { useOthers, useSelf } from '@liveblocks/react/suspense';

import { Separator } from '@/common/components/ui/separator';

interface AvatarProps {
src: string;
name: string;
}

const AVATAR_SIZE = 36;

const Avatar: React.FC<AvatarProps> = ({ src, name }) => {
return (
<div
style={{ width: AVATAR_SIZE, height: AVATAR_SIZE }}
className="group relative -ml-2 flex shrink-0 place-content-center rounded-full border-4 border-white bg-gray-400"
>
<div className="absolute top-full z-10 mt-2.5 whitespace-nowrap rounded-lg bg-black px-2 py-1 text-xs text-white opacity-0 transition-opacity group-hover:opacity-100">
{name}
</div>
<img alt={name} src={src} className="size-full rounded-full" />
</div>
);
};

const AvatarStack: React.FC = () => {
const users = useOthers();
const currentUser = useSelf();

if (users.length === 0) return null;

return (
<>
<div className="flex items-center">
{currentUser && (
<div className="relative ml-2">
<Avatar src={currentUser.info.avatar} name="You" />
</div>
)}
<div className="flex">
{users.map(({ connectionId, info }) => {
return (
<Avatar key={connectionId} src={info.avatar} name={info.name} />
);
})}
</div>
</div>
<Separator orientation="vertical" className="h-6" />
</>
);
};

const Avatars: React.FC = () => (
<ClientSideSuspense fallback={null}>
<AvatarStack />
</ClientSideSuspense>
);

export default Avatars;
4 changes: 2 additions & 2 deletions src/common/components/documents/DocumentInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

// import { useStatus } from '@liveblocks/react';
import { useStatus } from '@liveblocks/react';
import { LoaderIcon } from 'lucide-react';
import { useRef, useState } from 'react';
import { BsCloudCheck, BsCloudSlash } from 'react-icons/bs';
Expand All @@ -14,7 +14,7 @@ interface DocumentInputProps {
}

const DocumentInput: React.FC<DocumentInputProps> = ({ title, id }) => {
// const status = useStatus();
const status = useStatus();

const [value, setValue] = useState(title);
const [isEditing, setIsEditing] = useState(false);
Expand Down
4 changes: 2 additions & 2 deletions src/common/components/documents/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';

// import { useStorage } from '@liveblocks/react';
// import { useLiveblocksExtension } from '@liveblocks/react-tiptap';
import { Color } from '@tiptap/extension-color';
import FontFamily from '@tiptap/extension-font-family';
Expand Down Expand Up @@ -27,7 +28,6 @@ import {
} from '@/common/libs/extensions';

import { Ruler } from '.';
// import { Threads } from './threads';

interface EditorProps {
initialContent?: string | undefined;
Expand Down Expand Up @@ -121,7 +121,7 @@ const Editor: React.FC<EditorProps> = ({ initialContent }) => {
<Ruler />
<div className="mx-auto flex w-[816px] min-w-max justify-center py-4 print:w-full print:min-w-0 print:py-0">
<EditorContent editor={editor} />
{/*<Threads editor={editor} /> */}
{/* <Threads editor={editor} /> */}
</div>
</div>
);
Expand Down
70 changes: 70 additions & 0 deletions src/common/components/documents/Inbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/* eslint-disable simple-import-sort/imports */
'use client';

import { ClientSideSuspense } from '@liveblocks/react';
import { InboxNotification, InboxNotificationList } from '@liveblocks/react-ui';
import { useInboxNotifications } from '@liveblocks/react/suspense';
import { BellIcon } from 'lucide-react';

import { Button } from '@/common/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
} from '@/common/components/ui/dropdown-menu';
import { Separator } from '@/common/components/ui/separator';

const InboxMenu: React.FC = () => {
const { inboxNotifications } = useInboxNotifications();

return (
<>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="relative" size="icon">
<BellIcon className="size-5" />
{inboxNotifications.length > 0 && (
<span className="absolute -right-1 -top-1 flex size-4 items-center justify-center rounded-full bg-sky-500 text-xs text-white">
{inboxNotifications.length}
</span>
)}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-auto">
{inboxNotifications.length > 0 ? (
<InboxNotificationList>
{inboxNotifications.map((inboxNotification) => (
<InboxNotification
key={inboxNotification.id}
inboxNotification={inboxNotification}
/>
))}
</InboxNotificationList>
) : (
<div className="w-[400px] p-2 text-center text-sm text-muted-foreground">
无消息
</div>
)}
</DropdownMenuContent>
</DropdownMenu>
<Separator orientation="vertical" className="h-6" />
</>
);
};

const Inbox: React.FC = () => (
<ClientSideSuspense
fallback={
<>
<Button variant="ghost" disabled className="relative" size="icon">
<BellIcon className="size-5" />
</Button>
<Separator orientation="vertical" className="h-6" />
</>
}
>
<InboxMenu />
</ClientSideSuspense>
);

export default Inbox;
10 changes: 3 additions & 7 deletions src/common/components/documents/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@ import {
import { useEditorStore, useWorkspaceId } from '@/common/hooks';
import { type Document } from '@/common/types/documents';

import { RemoveDialog, RenameDialog } from '.';
import DocumentInput from './DocumentInput';

// import { Avatars } from './avatars';
// import { Inbox } from './inbox';
import { Avatars, DocumentInput, RemoveDialog, RenameDialog } from '.';

interface NavbarProps {
data: Document;
Expand Down Expand Up @@ -300,8 +296,8 @@ const Navbar: React.FC<NavbarProps> = ({ data }) => {
</div>
</div>
<div className="flex items-center gap-3 pl-6">
{/* <Avatars />
<Inbox /> */}
<Avatars />
{/* <Inbox /> */}
<UserButton />
</div>
</nav>
Expand Down
Loading

0 comments on commit 30f704b

Please sign in to comment.