style: pages edit history components

This commit is contained in:
Aaryan Khandelwal 2024-04-16 15:09:48 +05:30
parent 41d8005f0b
commit 5f24c0f838
13 changed files with 209 additions and 45 deletions

View File

@ -51,7 +51,7 @@
"jsx-dom-cjs": "^8.0.3", "jsx-dom-cjs": "^8.0.3",
"linkifyjs": "^4.1.3", "linkifyjs": "^4.1.3",
"lowlight": "^3.0.0", "lowlight": "^3.0.0",
"lucide-react": "^0.294.0", "lucide-react": "^0.368.0",
"prosemirror-codemark": "^0.4.2", "prosemirror-codemark": "^0.4.2",
"react-moveable": "^0.54.2", "react-moveable": "^0.54.2",
"tailwind-merge": "^1.14.0", "tailwind-merge": "^1.14.0",

View File

@ -36,7 +36,7 @@
"@tiptap/core": "^2.1.13", "@tiptap/core": "^2.1.13",
"@tiptap/pm": "^2.1.13", "@tiptap/pm": "^2.1.13",
"@tiptap/suggestion": "^2.1.13", "@tiptap/suggestion": "^2.1.13",
"lucide-react": "^0.309.0", "lucide-react": "^0.368.0",
"react-popper": "^2.3.0", "react-popper": "^2.3.0",
"tippy.js": "^6.3.7", "tippy.js": "^6.3.7",
"uuid": "^9.0.1" "uuid": "^9.0.1"

View File

@ -34,7 +34,7 @@
"@tiptap/pm": "^2.1.13", "@tiptap/pm": "^2.1.13",
"@tiptap/react": "^2.1.13", "@tiptap/react": "^2.1.13",
"@tiptap/suggestion": "^2.1.13", "@tiptap/suggestion": "^2.1.13",
"lucide-react": "^0.294.0", "lucide-react": "^0.368.0",
"tippy.js": "^6.3.7" "tippy.js": "^6.3.7"
}, },
"devDependencies": { "devDependencies": {

View File

@ -32,7 +32,7 @@
"@plane/editor-core": "*", "@plane/editor-core": "*",
"@plane/editor-extensions": "*", "@plane/editor-extensions": "*",
"@tiptap/core": "^2.1.13", "@tiptap/core": "^2.1.13",
"lucide-react": "^0.294.0" "lucide-react": "^0.368.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "18.15.3", "@types/node": "18.15.3",

View File

@ -29,7 +29,7 @@
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"lowlight": "^2.9.0", "lowlight": "^2.9.0",
"lucide-react": "^0.294.0", "lucide-react": "^0.368.0",
"mobx": "^6.10.0", "mobx": "^6.10.0",
"mobx-react-lite": "^4.0.3", "mobx-react-lite": "^4.0.3",
"next": "^14.0.3", "next": "^14.0.3",

View File

@ -0,0 +1,2 @@
export * from "./main-content";
export * from "./sidebar";

View File

@ -0,0 +1,32 @@
import { useRef } from "react";
// editor
import { DocumentReadOnlyEditorWithRef, EditorRefApi } from "@plane/document-editor";
// hooks
import { useMention } from "@/hooks/store";
type Props = {
projectId: string;
workspaceSlug: string;
};
export const PageEditHistoryMainContent: React.FC<Props> = (props) => {
const { projectId, workspaceSlug } = props;
// refs
const editorRef = useRef<EditorRefApi>(null);
// store hooks
const { mentionHighlights } = useMention({
workspaceSlug,
projectId,
});
return (
<DocumentReadOnlyEditorWithRef
ref={editorRef}
initialValue={"<p>Page edit history</p>"}
containerClassName="p-5 pl-10 border-none"
mentionHandler={{
highlights: mentionHighlights,
}}
/>
);
};

View File

@ -0,0 +1,26 @@
import { cn } from "@/helpers/common.helper";
type Props = {
activeVersionId: string;
};
export const PageEditHistorySidebar: React.FC<Props> = (props) => {
const {} = props;
return (
<>
{Array.from({ length: 10 }).map((_, index) => (
<button
key={index}
type="button"
className={cn("block w-full py-1 px-3 rounded hover:bg-custom-background-90 text-left", {
// "bg-custom-background-90": version.id === activeVersionId,
})}
>
<p className="text-sm">{index}. Today at 1:28 PM</p>
<span className="text-custom-text-400 text-sm">Aaryan Khandelwal</span>
</button>
))}
</>
);
};

View File

@ -1,9 +1,12 @@
import { useState } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Clipboard, Copy, Link, Lock } from "lucide-react"; import { Clipboard, Copy, History, Link, Lock } from "lucide-react";
// document editor // document editor
import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/document-editor"; import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/document-editor";
// ui // ui
import { ArchiveIcon, CustomMenu, TOAST_TYPE, ToggleSwitch, setToast } from "@plane/ui"; import { ArchiveIcon, CustomMenu, TOAST_TYPE, ToggleSwitch, setToast } from "@plane/ui";
// components
import { PageEditHistoryModal } from "@/components/pages";
// helpers // helpers
import { copyTextToClipboard, copyUrlToClipboard } from "@/helpers/string.helper"; import { copyTextToClipboard, copyUrlToClipboard } from "@/helpers/string.helper";
// hooks // hooks
@ -17,8 +20,18 @@ type Props = {
pageStore: IPageStore; pageStore: IPageStore;
}; };
type TMenuItems = {
key: string;
action: () => void;
label: string;
icon: React.FC<any>;
shouldRender: boolean;
};
export const PageOptionsDropdown: React.FC<Props> = observer((props) => { export const PageOptionsDropdown: React.FC<Props> = observer((props) => {
const { editorRef, handleDuplicatePage, pageStore } = props; const { editorRef, handleDuplicatePage, pageStore } = props;
// states
const [editHistoryModal, setEditHistoryModal] = useState(false);
// store values // store values
const { const {
archive, archive,
@ -73,13 +86,7 @@ export const PageOptionsDropdown: React.FC<Props> = observer((props) => {
); );
// menu items list // menu items list
const MENU_ITEMS: { const PAGE_ACTIONS: TMenuItems[] = [
key: string;
action: () => void;
label: string;
icon: React.FC<any>;
shouldRender: boolean;
}[] = [
{ {
key: "copy-markdown", key: "copy-markdown",
action: () => { action: () => {
@ -148,28 +155,52 @@ export const PageOptionsDropdown: React.FC<Props> = observer((props) => {
}, },
]; ];
const EXTRA_OPTIONS: TMenuItems[] = [
{
key: "edit-history",
action: () => setEditHistoryModal(true),
label: "View edit history",
icon: History,
shouldRender: true,
},
];
return ( return (
<CustomMenu maxHeight="md" placement="bottom-start" verticalEllipsis closeOnSelect> <>
<CustomMenu.MenuItem <PageEditHistoryModal isOpen={editHistoryModal} onClose={() => setEditHistoryModal(false)} />
className="flex w-full items-center justify-between gap-2" <CustomMenu maxHeight="lg" placement="bottom-start" verticalEllipsis closeOnSelect>
onClick={() => <CustomMenu.MenuItem
updateViewProps({ className="flex w-full items-center justify-between gap-2"
full_width: !view_props?.full_width, onClick={() =>
}) updateViewProps({
} full_width: !view_props?.full_width,
> })
Full width }
<ToggleSwitch value={!!view_props?.full_width} onChange={() => {}} /> >
</CustomMenu.MenuItem> Full width
{MENU_ITEMS.map((item) => { <ToggleSwitch value={!!view_props?.full_width} onChange={() => {}} />
if (!item.shouldRender) return null; </CustomMenu.MenuItem>
return ( <hr className="my-2 border-custom-border-200" />
<CustomMenu.MenuItem key={item.key} onClick={item.action} className="flex items-center gap-2"> {PAGE_ACTIONS.map((item) => {
<item.icon className="h-3 w-3" /> if (!item.shouldRender) return null;
<div className="text-custom-text-300">{item.label}</div> return (
</CustomMenu.MenuItem> <CustomMenu.MenuItem key={item.key} onClick={item.action} className="flex items-center gap-2">
); <item.icon className="h-3 w-3" />
})} <span>{item.label}</span>
</CustomMenu> </CustomMenu.MenuItem>
);
})}
<hr className="my-2 border-custom-border-200" />
{EXTRA_OPTIONS.map((item) => {
if (!item.shouldRender) return null;
return (
<CustomMenu.MenuItem key={item.key} onClick={item.action} className="flex items-center gap-2">
<item.icon className="h-3 w-3" />
<span>{item.label}</span>
</CustomMenu.MenuItem>
);
})}
</CustomMenu>
</>
); );
}); });

View File

@ -1,4 +1,5 @@
export * from "./dropdowns"; export * from "./dropdowns";
export * from "./edit-history";
export * from "./editor"; export * from "./editor";
export * from "./header"; export * from "./header";
export * from "./list"; export * from "./list";

View File

@ -0,0 +1,81 @@
import React from "react";
import { useRouter } from "next/router";
import { CircleHelp } from "lucide-react";
import { Dialog, Transition } from "@headlessui/react";
// ui
import { Button } from "@plane/ui";
// components
import { PageEditHistoryMainContent, PageEditHistorySidebar } from "@/components/pages";
type Props = {
isOpen: boolean;
onClose: () => void;
};
export const PageEditHistoryModal: React.FC<Props> = (props) => {
const { isOpen, onClose } = props;
// router
const router = useRouter();
const { projectId, workspaceSlug } = router.query;
const handleClose = () => {
onClose();
};
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-custom-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="h-full w-full grid place-items-center overflow-hidden">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="size-4/5 bg-custom-background-100 border border-custom-border-200 shadow-custom-shadow-md rounded-lg overflow-hidden">
<div className="h-full w-full grid grid-cols-5 overflow-hidden">
<div className="h-full col-span-4">
<PageEditHistoryMainContent
projectId={projectId?.toString() ?? ""}
workspaceSlug={workspaceSlug?.toString() ?? ""}
/>
</div>
<div className="h-full w-full flex flex-col divide-y divide-custom-border-200 border-l border-custom-border-200 overflow-hidden">
<div className="h-full p-1 overflow-y-scroll vertical-scrollbar scrollbar-sm">
<PageEditHistorySidebar activeVersionId="" />
</div>
<div className="py-3 px-4">
<Button variant="primary" size="sm">
Restore version
</Button>
</div>
<div className="py-3 px-4 flex items-center gap-2 text-custom-text-400 text-sm">
<CircleHelp className="h-3 w-3" />
Learn about page history
</div>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
);
};

View File

@ -1,3 +1,4 @@
export * from "./create-page-modal"; export * from "./create-page-modal";
export * from "./delete-page-modal"; export * from "./delete-page-modal";
export * from "./edit-history-modal";
export * from "./page-form"; export * from "./page-form";

View File

@ -5893,16 +5893,6 @@ lru-cache@^6.0.0:
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484"
integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag== integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==
lucide-react@^0.294.0:
version "0.294.0"
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.294.0.tgz#dc406e1e7e2f722cf93218fe5b31cf3c95778817"
integrity sha512-V7o0/VECSGbLHn3/1O67FUgBwWB+hmzshrgDVRJQhMh8uj5D3HBuIvhuAmQTtlupILSplwIZg5FTc4tTKMA2SA==
lucide-react@^0.309.0:
version "0.309.0"
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.309.0.tgz#7369893cb4b074a0a0b1d3acdc6fd9a8bdb5add1"
integrity sha512-zNVPczuwFrCfksZH3zbd1UDE6/WYhYAdbe2k7CImVyPAkXLgIwbs6eXQ4loigqDnUFjyFYCI5jZ1y10Kqal0dg==
lucide-react@^0.368.0: lucide-react@^0.368.0:
version "0.368.0" version "0.368.0"
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.368.0.tgz#3c0ee63f4f7d30ae63b621b2b8f04f9e409ee6e7" resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.368.0.tgz#3c0ee63f4f7d30ae63b621b2b8f04f9e409ee6e7"