chore: Move editor into codebase (#2930)
This commit is contained in:
@@ -1,26 +1,21 @@
|
||||
import { lighten } from "polished";
|
||||
import * as React from "react";
|
||||
import { Props as EditorProps } from "rich-markdown-editor";
|
||||
import { EmbedDescriptor } from "rich-markdown-editor/dist/types";
|
||||
import styled, { useTheme } from "styled-components";
|
||||
import { Optional } from "utility-types";
|
||||
import embeds from "@shared/embeds";
|
||||
import { light } from "@shared/theme";
|
||||
import embeds from "@shared/editor/embeds";
|
||||
import { EmbedDescriptor } from "@shared/editor/types";
|
||||
import ErrorBoundary from "~/components/ErrorBoundary";
|
||||
import Tooltip from "~/components/Tooltip";
|
||||
import { Props as EditorProps } from "~/editor";
|
||||
import useDictionary from "~/hooks/useDictionary";
|
||||
import useMediaQuery from "~/hooks/useMediaQuery";
|
||||
import useToasts from "~/hooks/useToasts";
|
||||
import history from "~/utils/history";
|
||||
import { isModKey } from "~/utils/keyboard";
|
||||
import { uploadFile } from "~/utils/uploadFile";
|
||||
import { isInternalUrl, isHash } from "~/utils/urls";
|
||||
|
||||
const RichMarkdownEditor = React.lazy(
|
||||
const SharedEditor = React.lazy(
|
||||
() =>
|
||||
import(
|
||||
/* webpackChunkName: "rich-markdown-editor" */
|
||||
"rich-markdown-editor"
|
||||
/* webpackChunkName: "shared-editor" */
|
||||
"~/editor"
|
||||
)
|
||||
);
|
||||
|
||||
@@ -28,7 +23,7 @@ const EMPTY_ARRAY: EmbedDescriptor[] = [];
|
||||
|
||||
export type Props = Optional<
|
||||
EditorProps,
|
||||
"placeholder" | "defaultValue" | "tooltip" | "onClickLink" | "embeds"
|
||||
"placeholder" | "defaultValue" | "onClickLink" | "embeds" | "dictionary"
|
||||
> & {
|
||||
shareId?: string | undefined;
|
||||
disableEmbeds?: boolean;
|
||||
@@ -39,9 +34,7 @@ export type Props = Optional<
|
||||
|
||||
function Editor(props: Props, ref: React.Ref<any>) {
|
||||
const { id, shareId } = props;
|
||||
const theme = useTheme();
|
||||
const { showToast } = useToasts();
|
||||
const isPrinting = useMediaQuery("print");
|
||||
const dictionary = useDictionary();
|
||||
|
||||
const onUploadImage = React.useCallback(
|
||||
@@ -97,144 +90,19 @@ function Editor(props: Props, ref: React.Ref<any>) {
|
||||
|
||||
return (
|
||||
<ErrorBoundary reloadOnChunkMissing>
|
||||
<StyledEditor
|
||||
<SharedEditor
|
||||
ref={ref}
|
||||
uploadImage={onUploadImage}
|
||||
onShowToast={onShowToast}
|
||||
embeds={props.disableEmbeds ? EMPTY_ARRAY : embeds}
|
||||
dictionary={dictionary}
|
||||
{...props}
|
||||
tooltip={EditorTooltip}
|
||||
onClickLink={onClickLink}
|
||||
placeholder={props.placeholder || ""}
|
||||
defaultValue={props.defaultValue || ""}
|
||||
theme={isPrinting ? light : theme}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
const StyledEditor = styled(RichMarkdownEditor)<{ grow?: boolean }>`
|
||||
flex-grow: ${(props) => (props.grow ? 1 : 0)};
|
||||
justify-content: start;
|
||||
|
||||
> div {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
& * {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.notice-block.tip,
|
||||
.notice-block.warning {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.heading-anchor {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.heading-name {
|
||||
pointer-events: none;
|
||||
display: block;
|
||||
position: relative;
|
||||
top: -60px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.heading-name:first-child,
|
||||
.heading-name:first-child + .ProseMirror-yjs-cursor {
|
||||
& + h1,
|
||||
& + h2,
|
||||
& + h3,
|
||||
& + h4 {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
a {
|
||||
color: ${(props) => props.theme.text};
|
||||
border-bottom: 1px solid ${(props) => lighten(0.5, props.theme.text)};
|
||||
text-decoration: none !important;
|
||||
font-weight: 500;
|
||||
|
||||
&:hover {
|
||||
border-bottom: 1px solid ${(props) => props.theme.text};
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ProseMirror {
|
||||
& > .ProseMirror-yjs-cursor {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ProseMirror-yjs-cursor {
|
||||
position: relative;
|
||||
margin-left: -1px;
|
||||
margin-right: -1px;
|
||||
border-left: 1px solid black;
|
||||
border-right: 1px solid black;
|
||||
height: 1em;
|
||||
word-break: normal;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -8px;
|
||||
right: -8px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
> div {
|
||||
opacity: 0;
|
||||
transition: opacity 100ms ease-in-out;
|
||||
position: absolute;
|
||||
top: -1.8em;
|
||||
font-size: 13px;
|
||||
background-color: rgb(250, 129, 0);
|
||||
font-style: normal;
|
||||
line-height: normal;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
color: white;
|
||||
padding: 2px 6px;
|
||||
font-weight: 500;
|
||||
border-radius: 4px;
|
||||
pointer-events: none;
|
||||
left: -1px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
> div {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.show-cursor-names .ProseMirror-yjs-cursor > div {
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
type TooltipProps = {
|
||||
children: React.ReactNode;
|
||||
tooltip: string;
|
||||
};
|
||||
|
||||
const EditorTooltip = ({ children, tooltip, ...props }: TooltipProps) => (
|
||||
<Tooltip offset="0, 16" delay={150} tooltip={tooltip} {...props}>
|
||||
<TooltipContent>{children}</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
const TooltipContent = styled.span`
|
||||
outline: none;
|
||||
`;
|
||||
|
||||
export default React.forwardRef<typeof Editor, Props>(Editor);
|
||||
|
||||
@@ -15,9 +15,10 @@ function Theme({ children }: Props) {
|
||||
const theme = ui.resolvedTheme === "dark" ? dark : light;
|
||||
const mobileTheme = ui.resolvedTheme === "dark" ? darkMobile : lightMobile;
|
||||
const isMobile = useMediaQuery(`(max-width: ${theme.breakpoints.tablet}px)`);
|
||||
const isPrinting = useMediaQuery("print");
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={isMobile ? mobileTheme : theme}>
|
||||
<ThemeProvider theme={isPrinting ? light : isMobile ? mobileTheme : theme}>
|
||||
<>
|
||||
<GlobalStyles />
|
||||
{children}
|
||||
|
||||
Reference in New Issue
Block a user