Files
plane/web/core/constants/editor.ts
Bavisetti Narayan b83a442a2b [WIKI-212] feat: nested pages (#2599)
* chore: workspace pages

* chore: moved page icons and ui added

* chore: deploy board changes

* fix: workspace sub page count

* fix: added proper creation and redirection in workspace pages

* fix: name of var

* fix: subpages

* fix: fetch subpages in workspace pages

* fix root node bug

* update recursion with loop

* fix: deletion plugin handler for sub pages added

* fix: handle multiple sub page deletions

* fix: handle multiple delete of deleted pages

* fix: collaboration cursor color

* chore: wiki sidebar hierarchy

* fix: private and archived pages hierarchy

* fix: ui, clicking and displaying deleted pages

* fix: make the server code more extendable

* fix: better handle real time events

* fix: handle recursively opening the subpages

* fix: better animations while unfurling the nested pages

* fix: added breadcrumbs ui for workspace pages

* fix: responsiveness of editor toolbar

* fix: loading document and storing only when there's content

* fix: preview for workspace pages fixed

* feat: realtime title updates

* feat: added live page collaborators

* fix: fetch details on focus and got back old updates

* fix: move page workflow fixed

* fix: archived at

* fix: build errors

* fix: build

* fix: build errors

* fix: revert yarn lock

* fix: build

* fix: more build errors

* fix: saved status for live docs

* fix: migration changes

* fix: collaborators on click scroll added

* fix: restrict access in project list view and workspace sidebar view

* fix: public parent pages unfurl as well

* fix: title sync handled

* fix: archive modal removed and version history added

* fix: modal core logo for restricted page fixed

* fix: colors

* fix: patch ux copy

* fix: list item icon

* fix: page link and embed component added to space

* fix: nested traversing added for replacing embeds

* fix: responsiveness and delete redirection

* fix: build issues

* fix: added loader back

* fix: unpublish project page

* fix: publish in workspace page

* fix: show on when editable in title editor

* fix: upublish workspace paegs

* fix: random colors fix

* fix: owned by added

* fix: permission layaer changes

* fix: fetch parent pages and update store in project pages

* fix: title editor backspace, enter, tab and arrow keys handled

* fix: sequential async processing for tasks on different documents

* chore: move pages inetrnally

* chore: wiki sidebar dnd

* chore: dnd patch request added

* fix: changed params

* chore: update the parent page id

* refactor: dnd code

* chore: remove wrong rule

* fallback: removing nodes if not in subpages endpoint

* fix: remove console logs and names

* fix: remove more console logs and ui fixes

* fix: editor css for nested pages in list

* fix: deleted at redirection

* patch fix: docker version

* fix: additional stuff

* fix: removal of drop cursor

* style: sidebar dnd ui

* fix drop cursor

* chore: changed the access controls

* fix: realtime events for moving pages

* chore: nested pages delete mutations for workspace and project level

* chore: updated deleted_at in issue detail types

* fix: logger and added working global error handling with sentry

* fix: tsup hot reloading

* fix: dividing server code

* fix: better error handling

* fix: file structure for error handling

* fix: better error handling for redis client

* fix: errors and imports

* fix: handlers

* chore: updated nested archived, restore and delete pages

* chore: updated is_description_empty in the page

* chore: broadcasting the nested page mutations

* fix: stop event prop on error

* chore: current page archive, unarchive and delete

* chore: wiki nested list

* chore: bulk delete pages =

* fix: is_description_empty added for mobile

* chore: addes is_description_empty in page types

* fix: added title sync capabilities along with migration

* fix: navigation between title and main editor made seamless

* fix: seperated decorators into it's own package

* chore: added title of page in binary request

* fix: title saving logic with debounce and abortion handled neatly

* fix: not shutting down the app for any reason

* chore: restructuring project-page methods, transformers and handlers

* fix: title updation with new structure

* fix: extensions index ts cleaned up

* fix: syncing title using mobx

* revert: profile page changes

* fix: reverting back extra changes

* chore: remove saved saving state

* fix: getting back old title to avoid merge conflicts

* fix: redis process improved a lot

* fix: nested pages endpoints

* fix: cleaning up decorators and fixing live server

* feat: express decorators for rest apis and websocket

* Merge branch 'fix/live-server-restructuring' into fix/live-server-restructuring

* feat: express decorators for rest apis and websocket

* fix: added package dependency

* fix: sync agent up and running

* fix: refactor decorators

* fix: add missing packages

* fix: exit with error 1

* fix: error factory types and document controller error handling

* fix: added zod validation

* chore: remove js extension

* fix: version history shows correct data

* chore: removed parent is null in workspace page query

* feat: added ability to skip archiving before deleting nodes

* fix: title position

* fix: syncing changes

* fix: build errors

* fix: added feature flagging for nested pages

* fix: added feature flagging

* fix: live build stop

* fix: drag handle

* chore: added new endpoint to restore page

* fix: title sync and animations

* fix: title real time sync

* chore: restore the deleted version

* fix: moving around pages

* fix: registering handlers made simplified

* fix: common initializer

* chore: remove services

* fix: reverse changes

* fix: page restoration

* changed from datetime to timezone

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: removing code duplicacy

* fix: getconfig removed

* chore: remove repetitive code

* fix: type errors

* fix: all context errors

* fix: removed document registry

* chore :removed unuesed config

* fix: move server agent to ee

* fix: broadcast controller fixed

* fix: removed dead code

* fix: socket connection getting disconnected

* fix:realtime events and their types

* fix: realtime events made robust

* fix: restore operation

* fix: title sync and archiving/etc in project page

* chore: updated the version

* chore: massively improved typescript inference for realtime events

* chore: added deleted page ids in data

* fix: types pro max

* fix: modified the page ids

* fix: change component name for nested page

* fix: realtime events duplication

* fix: added logs

* fix: added common place to differentiate nested pages behaviour

* fix: added new flagging

* fix: remove page link references

* fix: remove page link references

* fix: feature flagging

* fix: feature flagging

* fix: added back missing bits

* chore: added the logic to restored the moved page

* fix: breadcrumbs loading fixed

* chore: added feature flag

* fix: transforming headers

* fix: page updates

* fix: editor body refactored

* chore: sorted the pages parent order

* fix: duplicate page

* fix: common realtime events for all pages

* fix: create/fetch page details

* fix: better animations and creation of embeds

* fix: better loadin animations and better deletion of nodes

* fix: better transitions

* fix: added event customization

* fix: logo props showing wrong data

* fix: reverted back changes

* fix: workspace store searching

* fix: console logs

* fix: build errors

* fix: more build errors

* fix: revert changes

* fix: remove not needed code

* fix: add access denied to non upgraded users

---------

Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
Co-authored-by: VipinDevelops <vipinchaudhary1809@gmail.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
Co-authored-by: gurusinath <gurusainath007@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-04-12 16:28:36 +05:30

391 lines
10 KiB
TypeScript

import { Styles, StyleSheet } from "@react-pdf/renderer";
import {
AlignCenter,
AlignLeft,
AlignRight,
Bold,
CaseSensitive,
Code2,
Heading1,
Heading2,
Heading3,
Heading4,
Heading5,
Heading6,
Image,
Italic,
List,
ListCollapse,
ListOrdered,
ListTodo,
LucideIcon,
Strikethrough,
Table,
TextQuote,
Underline,
} from "lucide-react";
// editor
import { TCommandExtraProps, TEditorCommands, TEditorFontStyle } from "@plane/editor";
// ui
import { MonospaceIcon, SansSerifIcon, SerifIcon } from "@plane/ui";
// helpers
import { convertRemToPixel } from "@/helpers/common.helper";
type TEditorTypes = "lite" | "document" | "sticky";
// Utility type to enforce the necessary extra props or make extraProps optional
type ExtraPropsForCommand<T extends TEditorCommands> = T extends keyof TCommandExtraProps
? TCommandExtraProps[T]
: object; // Default to empty object for commands without extra props
export type ToolbarMenuItem<T extends TEditorCommands = TEditorCommands> = {
itemKey: T;
renderKey: string;
name: string;
icon: LucideIcon;
shortcut?: string[];
editors: TEditorTypes[];
extraProps?: ExtraPropsForCommand<T>;
};
export const TYPOGRAPHY_ITEMS: ToolbarMenuItem<"text" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6">[] = [
{ itemKey: "text", renderKey: "text", name: "Text", icon: CaseSensitive, editors: ["document"] },
{ itemKey: "h1", renderKey: "h1", name: "Heading 1", icon: Heading1, editors: ["document"] },
{ itemKey: "h2", renderKey: "h2", name: "Heading 2", icon: Heading2, editors: ["document"] },
{ itemKey: "h3", renderKey: "h3", name: "Heading 3", icon: Heading3, editors: ["document"] },
{ itemKey: "h4", renderKey: "h4", name: "Heading 4", icon: Heading4, editors: ["document"] },
{ itemKey: "h5", renderKey: "h5", name: "Heading 5", icon: Heading5, editors: ["document"] },
{ itemKey: "h6", renderKey: "h6", name: "Heading 6", icon: Heading6, editors: ["document"] },
];
export const TEXT_ALIGNMENT_ITEMS: ToolbarMenuItem<"text-align">[] = [
{
itemKey: "text-align",
renderKey: "text-align-left",
name: "Left align",
icon: AlignLeft,
shortcut: ["Cmd", "Shift", "L"],
editors: ["lite", "document"],
extraProps: {
alignment: "left",
},
},
{
itemKey: "text-align",
renderKey: "text-align-center",
name: "Center align",
icon: AlignCenter,
shortcut: ["Cmd", "Shift", "E"],
editors: ["lite", "document"],
extraProps: {
alignment: "center",
},
},
{
itemKey: "text-align",
renderKey: "text-align-right",
name: "Right align",
icon: AlignRight,
shortcut: ["Cmd", "Shift", "R"],
editors: ["lite", "document"],
extraProps: {
alignment: "right",
},
},
];
const BASIC_MARK_ITEMS: ToolbarMenuItem<"bold" | "italic" | "underline" | "strikethrough">[] = [
{
itemKey: "bold",
renderKey: "bold",
name: "Bold",
icon: Bold,
shortcut: ["Cmd", "B"],
editors: ["lite", "document"],
},
{
itemKey: "italic",
renderKey: "italic",
name: "Italic",
icon: Italic,
shortcut: ["Cmd", "I"],
editors: ["lite", "document"],
},
{
itemKey: "underline",
renderKey: "underline",
name: "Underline",
icon: Underline,
shortcut: ["Cmd", "U"],
editors: ["lite", "document"],
},
{
itemKey: "strikethrough",
renderKey: "strikethrough",
name: "Strikethrough",
icon: Strikethrough,
shortcut: ["Cmd", "Shift", "S"],
editors: ["lite", "document"],
},
];
const LIST_ITEMS: ToolbarMenuItem<"bulleted-list" | "numbered-list" | "to-do-list">[] = [
{
itemKey: "bulleted-list",
renderKey: "bulleted-list",
name: "Bulleted list",
icon: List,
shortcut: ["Cmd", "Shift", "7"],
editors: ["lite", "document"],
},
{
itemKey: "numbered-list",
renderKey: "numbered-list",
name: "Numbered list",
icon: ListOrdered,
shortcut: ["Cmd", "Shift", "8"],
editors: ["lite", "document"],
},
{
itemKey: "to-do-list",
renderKey: "to-do-list",
name: "To-do list",
icon: ListTodo,
shortcut: ["Cmd", "Shift", "9"],
editors: ["lite", "document"],
},
];
const USER_ACTION_ITEMS: ToolbarMenuItem<"quote" | "code">[] = [
{ itemKey: "quote", renderKey: "quote", name: "Quote", icon: TextQuote, editors: ["lite", "document"] },
{ itemKey: "code", renderKey: "code", name: "Code", icon: Code2, editors: ["lite", "document"] },
];
const COMPLEX_ITEMS: ToolbarMenuItem<"table" | "image">[] = [
{ itemKey: "table", renderKey: "table", name: "Table", icon: Table, editors: ["document"] },
{ itemKey: "image", renderKey: "image", name: "Image", icon: Image, editors: ["lite", "document"], extraProps: {} },
];
export const TOOLBAR_ITEMS: {
[editorType in TEditorTypes]: {
[key: string]: ToolbarMenuItem<TEditorCommands>[];
};
} = {
lite: {
basic: BASIC_MARK_ITEMS.filter((item) => item.editors.includes("lite")),
alignment: TEXT_ALIGNMENT_ITEMS.filter((item) => item.editors.includes("lite")),
list: LIST_ITEMS.filter((item) => item.editors.includes("lite")),
userAction: USER_ACTION_ITEMS.filter((item) => item.editors.includes("lite")),
complex: COMPLEX_ITEMS.filter((item) => item.editors.includes("lite")),
},
document: {
basic: BASIC_MARK_ITEMS.filter((item) => item.editors.includes("document")),
alignment: TEXT_ALIGNMENT_ITEMS.filter((item) => item.editors.includes("document")),
list: LIST_ITEMS.filter((item) => item.editors.includes("document")),
userAction: USER_ACTION_ITEMS.filter((item) => item.editors.includes("document")),
complex: COMPLEX_ITEMS.filter((item) => item.editors.includes("document")),
},
sticky: {
basic: BASIC_MARK_ITEMS.filter((item) => ["Bold", "Italic"].includes(item.name)),
list: LIST_ITEMS.filter((item) => ["To-do list"].includes(item.name)),
},
};
export const EDITOR_FONT_STYLES: {
key: TEditorFontStyle;
label: string;
icon: any;
}[] = [
{
key: "sans-serif",
label: "Sans serif",
icon: SansSerifIcon,
},
{
key: "serif",
label: "Serif",
icon: SerifIcon,
},
{
key: "monospace",
label: "Mono",
icon: MonospaceIcon,
},
];
const EDITOR_PDF_FONT_FAMILY_STYLES: Styles = {
"*:not(.courier, .courier-bold)": {
fontFamily: "Inter",
},
".courier": {
fontFamily: "Courier",
},
".courier-bold": {
fontFamily: "Courier-Bold",
},
};
const EDITOR_PDF_TYPOGRAPHY_STYLES: Styles = {
// page title
"h1.page-title": {
fontSize: convertRemToPixel(1.6),
fontWeight: "bold",
marginTop: 0,
marginBottom: convertRemToPixel(2),
},
// headings
"h1:not(.page-title)": {
fontSize: convertRemToPixel(1.4),
fontWeight: "semibold",
marginTop: convertRemToPixel(2),
marginBottom: convertRemToPixel(0.25),
},
h2: {
fontSize: convertRemToPixel(1.2),
fontWeight: "semibold",
marginTop: convertRemToPixel(1.4),
marginBottom: convertRemToPixel(0.0625),
},
h3: {
fontSize: convertRemToPixel(1.1),
fontWeight: "semibold",
marginTop: convertRemToPixel(1),
marginBottom: convertRemToPixel(0.0625),
},
h4: {
fontSize: convertRemToPixel(1),
fontWeight: "semibold",
marginTop: convertRemToPixel(1),
marginBottom: convertRemToPixel(0.0625),
},
h5: {
fontSize: convertRemToPixel(0.9),
fontWeight: "semibold",
marginTop: convertRemToPixel(1),
marginBottom: convertRemToPixel(0.0625),
},
h6: {
fontSize: convertRemToPixel(0.8),
fontWeight: "semibold",
marginTop: convertRemToPixel(1),
marginBottom: convertRemToPixel(0.0625),
},
// paragraph
"p:not(table p)": {
fontSize: convertRemToPixel(0.8),
},
"p:not(ol p, ul p)": {
marginTop: convertRemToPixel(0.25),
marginBottom: convertRemToPixel(0.0625),
},
};
const EDITOR_PDF_LIST_STYLES: Styles = {
"ul, ol": {
fontSize: convertRemToPixel(0.8),
marginHorizontal: -20,
},
"ol p, ul p": {
marginVertical: 0,
},
"ol li, ul li": {
marginTop: convertRemToPixel(0.45),
},
"ul ul, ul ol, ol ol, ol ul": {
marginVertical: 0,
},
"ul[data-type='taskList']": {
position: "relative",
},
"div.input-checkbox": {
position: "absolute",
top: convertRemToPixel(0.15),
left: -convertRemToPixel(1.2),
height: convertRemToPixel(0.75),
width: convertRemToPixel(0.75),
borderWidth: "1.5px",
borderStyle: "solid",
borderRadius: convertRemToPixel(0.125),
},
"div.input-checkbox:not(.checked)": {
backgroundColor: "#ffffff",
borderColor: "#171717",
},
"div.input-checkbox.checked": {
backgroundColor: "#3f76ff",
borderColor: "#3f76ff",
},
"ul li[data-checked='true'] p": {
color: "#a3a3a3",
},
};
const EDITOR_PDF_CODE_STYLES: Styles = {
// code block
"[data-node-type='code-block']": {
marginVertical: convertRemToPixel(0.5),
padding: convertRemToPixel(1),
borderRadius: convertRemToPixel(0.5),
backgroundColor: "#f7f7f7",
fontSize: convertRemToPixel(0.7),
},
// inline code block
"[data-node-type='inline-code-block']": {
margin: 0,
paddingVertical: convertRemToPixel(0.25 / 4 + 0.25 / 8),
paddingHorizontal: convertRemToPixel(0.375),
border: "0.5px solid #e5e5e5",
borderRadius: convertRemToPixel(0.25),
backgroundColor: "#e8e8e8",
color: "#f97316",
fontSize: convertRemToPixel(0.7),
},
};
export const EDITOR_PDF_DOCUMENT_STYLESHEET = StyleSheet.create({
...EDITOR_PDF_FONT_FAMILY_STYLES,
...EDITOR_PDF_TYPOGRAPHY_STYLES,
...EDITOR_PDF_LIST_STYLES,
...EDITOR_PDF_CODE_STYLES,
// quote block
blockquote: {
borderLeft: "3px solid gray",
paddingLeft: convertRemToPixel(1),
marginTop: convertRemToPixel(0.625),
marginBottom: 0,
marginHorizontal: 0,
},
// image
img: {
marginVertical: 0,
borderRadius: convertRemToPixel(0.375),
},
// divider
"div[data-type='horizontalRule']": {
marginVertical: convertRemToPixel(1),
height: 1,
width: "100%",
backgroundColor: "gray",
},
// mention block
"[data-node-type='mention-block']": {
margin: 0,
color: "#3f76ff",
backgroundColor: "#3f76ff33",
paddingHorizontal: convertRemToPixel(0.375),
},
// table
table: {
marginTop: convertRemToPixel(0.5),
marginBottom: convertRemToPixel(1),
marginHorizontal: 0,
},
"table td": {
padding: convertRemToPixel(0.625),
border: "1px solid #e5e5e5",
},
"table p": {
fontSize: convertRemToPixel(0.7),
},
});