mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
style: pages edit history components
This commit is contained in:
parent
41d8005f0b
commit
5f24c0f838
@ -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",
|
||||||
|
@ -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"
|
||||||
|
@ -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": {
|
||||||
|
@ -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",
|
||||||
|
@ -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",
|
||||||
|
2
web/components/pages/edit-history/index.ts
Normal file
2
web/components/pages/edit-history/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./main-content";
|
||||||
|
export * from "./sidebar";
|
32
web/components/pages/edit-history/main-content.tsx
Normal file
32
web/components/pages/edit-history/main-content.tsx
Normal 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,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
26
web/components/pages/edit-history/sidebar.tsx
Normal file
26
web/components/pages/edit-history/sidebar.tsx
Normal 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>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -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>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -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";
|
||||||
|
81
web/components/pages/modals/edit-history-modal.tsx
Normal file
81
web/components/pages/modals/edit-history-modal.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
@ -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";
|
||||||
|
10
yarn.lock
10
yarn.lock
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user