accords-library.com/src/pages/dev/editor.tsx

362 lines
12 KiB
TypeScript
Raw Normal View History

import { AppLayout } from "components/AppLayout";
import { Button } from "components/Inputs/Button";
import { Markdawn } from "components/Markdown/Markdawn";
import {
ContentPanel,
2022-02-17 16:55:44 +00:00
ContentPanelWidthSizes,
} from "components/Panels/ContentPanel";
import { Popup } from "components/Popup";
import { ToolTip } from "components/ToolTip";
2022-05-08 10:26:36 +00:00
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
2022-05-08 19:37:41 +00:00
import { Immutable } from "helpers/types";
import { GetStaticPropsContext } from "next";
2022-03-26 16:09:42 +00:00
import { useCallback, useState } from "react";
import TurndownService from "turndown";
2022-05-22 14:24:16 +00:00
import { Ico, Icon } from "components/Ico";
2022-02-17 16:55:44 +00:00
2022-04-03 08:34:21 +00:00
interface Props extends AppStaticProps {}
2022-02-17 16:55:44 +00:00
2022-05-08 19:37:41 +00:00
export default function Editor(props: Immutable<Props>): JSX.Element {
const handleInput = useCallback((text: string) => {
setMarkdown(text);
2022-02-17 16:55:44 +00:00
}, []);
const [markdown, setMarkdown] = useState("");
const [converterOpened, setConverterOpened] = useState(false);
function insert(
text: string,
prepend: string,
append: string,
selectionStart: number,
selectionEnd: number
): string {
let newText = text.slice(0, selectionStart);
newText += prepend;
newText += text.slice(selectionStart, selectionEnd);
newText += append;
newText += text.slice(selectionEnd);
return newText;
}
2022-02-17 16:55:44 +00:00
const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.large}>
<Popup setState={setConverterOpened} state={converterOpened}>
<div className="text-center">
<h2 className="mt-4">Convert HTML to markdown</h2>
<p>
Copy and paste any HTML content (content from web pages) here.{" "}
<br />
The text will immediatly be converted to valid Markdown.
<br />
You can then copy the converted text and paste it anywhere you want
in the editor
</p>
</div>
<textarea
readOnly
id="htmlMdTextArea"
title="Ouput textarea"
onPaste={(event) => {
const turndownService = new TurndownService({
headingStyle: "atx",
codeBlockStyle: "fenced",
bulletListMarker: "-",
emDelimiter: "_",
strongDelimiter: "**",
});
let paste = event.clipboardData.getData("text/html");
paste = paste.replace(/<!--.*?-->/u, "");
paste = turndownService.turndown(paste);
paste = paste.replace(/<!--.*?-->/u, "");
const target = event.target as HTMLTextAreaElement;
target.value = paste;
target.select();
event.preventDefault();
}}
2022-05-21 11:18:57 +00:00
className="h-[50vh] w-[50vw] font-monospace mobile:w-[75vw]"
/>
</Popup>
2022-05-21 11:18:57 +00:00
<div className="mb-4 flex flex-row gap-2">
<ToolTip
placement="bottom"
content={
<>
<h3 className="text-lg">Transcript container</h3>
<p>
Use this to create dialogues and transcripts. You can then add
transcript speech line within (
2022-05-22 14:24:16 +00:00
<Ico className="text-xs" icon={Icon.RecordVoiceOver} />)
</p>
</>
}
>
<Button
onClick={() => {
const textarea = document.querySelector(
"#editorTextArea"
) as HTMLTextAreaElement;
const { value, selectionStart, selectionEnd } = textarea;
textarea.value = insert(
value,
"\n<Transcript>\n",
"\n</Transcript>\n",
selectionStart,
selectionEnd
);
handleInput(textarea.value);
}}
2022-05-22 14:24:16 +00:00
icon={Icon.QuestionAnswer}
/>
</ToolTip>
<ToolTip
placement="bottom"
content={
<>
<h3 className="text-lg">Transcript speech line</h3>
<p>
Use to add a dialogue/transcript line. Change the{" "}
<kbd>name</kbd> property to chang the name of the speaker
</p>
</>
}
>
<Button
onClick={() => {
const textarea = document.querySelector(
"#editorTextArea"
) as HTMLTextAreaElement;
const { value, selectionStart, selectionEnd } = textarea;
textarea.value = insert(
value,
2022-04-04 09:09:30 +00:00
'<Line name="speaker">',
"</Line>\n",
selectionStart,
selectionEnd
);
handleInput(textarea.value);
}}
2022-05-22 14:24:16 +00:00
icon={Icon.RecordVoiceOver}
/>
</ToolTip>
<ToolTip
placement="bottom"
content={<h3 className="text-lg">Vertical spacer</h3>}
>
<Button
onClick={() => {
const textarea = document.querySelector(
"#editorTextArea"
) as HTMLTextAreaElement;
const { value, selectionStart, selectionEnd } = textarea;
textarea.value = insert(
value,
"<Sep />",
"",
selectionStart,
selectionEnd
);
handleInput(textarea.value);
}}
2022-05-22 14:24:16 +00:00
icon={Icon.DensityLarge}
/>
</ToolTip>
<ToolTip
placement="bottom"
content={<h3 className="text-lg">Inset box</h3>}
>
<Button
onClick={() => {
const textarea = document.querySelector(
"#editorTextArea"
) as HTMLTextAreaElement;
const { value, selectionStart, selectionEnd } = textarea;
textarea.value = insert(
value,
"\n<InsetBox>\n",
"\n</InsetBox>\n",
selectionStart,
selectionEnd
);
handleInput(textarea.value);
}}
2022-05-22 14:24:16 +00:00
icon={Icon.CheckBoxOutlineBlank}
/>
</ToolTip>
<ToolTip
placement="bottom"
content={<h3 className="text-lg">Scene break</h3>}
>
<Button
onClick={() => {
const textarea = document.querySelector(
"#editorTextArea"
) as HTMLTextAreaElement;
const { value, selectionStart, selectionEnd } = textarea;
textarea.value = insert(
value,
"\n\n<SceneBreak />\n\n",
"",
selectionStart,
selectionEnd
);
handleInput(textarea.value);
}}
2022-05-22 14:24:16 +00:00
icon={Icon.MoreHoriz}
/>
</ToolTip>
<ToolTip
content={
<div className="flex flex-col place-items-center gap-2">
<h3 className="text-lg">Intralink</h3>
<ToolTip
placement="right"
content={
<>
<h3 className="text-lg">Intralink</h3>
<p className="text-xs">
Interlinks are used to add links to a header within the
same document
</p>
</>
}
>
<Button
onClick={() => {
const textarea = document.querySelector(
"#editorTextArea"
) as HTMLTextAreaElement;
const { value, selectionStart, selectionEnd } = textarea;
textarea.value = insert(
value,
"<IntraLink>",
"</IntraLink>",
selectionStart,
selectionEnd
);
handleInput(textarea.value);
}}
2022-05-22 14:24:16 +00:00
icon={Icon.Link}
/>
</ToolTip>
<ToolTip
placement="right"
content={
<>
<h3 className="text-lg">Intralink (with target)</h3>{" "}
<p className="text-xs">
Use this one if you want the intralink text to be
different from the target header&rsquo;s name.
</p>
</>
}
>
<Button
onClick={() => {
const textarea = document.querySelector(
"#editorTextArea"
) as HTMLTextAreaElement;
const { value, selectionStart, selectionEnd } = textarea;
textarea.value = insert(
value,
'<IntraLink target="target">',
"</IntraLink>",
selectionStart,
selectionEnd
);
handleInput(textarea.value);
}}
2022-05-22 14:24:16 +00:00
icon={Icon.Link}
text="+ target"
/>
</ToolTip>
</div>
}
>
2022-05-22 14:24:16 +00:00
<Button icon={Icon.Link} />
</ToolTip>
<ToolTip
placement="bottom"
content={<h3 className="text-lg">Player&rsquo;s name placeholder</h3>}
>
<Button
onClick={() => {
const textarea = document.querySelector(
"#editorTextArea"
) as HTMLTextAreaElement;
const { value, selectionStart, selectionEnd } = textarea;
textarea.value = insert(
value,
"<player>",
"",
selectionStart,
selectionEnd
);
handleInput(textarea.value);
}}
2022-05-22 14:24:16 +00:00
icon={Icon.Person}
/>
</ToolTip>
<ToolTip
placement="bottom"
content={<h3 className="text-lg">Open HTML Converter</h3>}
>
<Button
onClick={() => {
setConverterOpened(true);
}}
2022-05-22 14:24:16 +00:00
icon={Icon.Html}
/>
</ToolTip>
</div>
2022-02-17 16:55:44 +00:00
<div className="grid grid-cols-2 gap-8">
2022-02-17 16:55:44 +00:00
<div>
<h2>Editor</h2>
<textarea
id="editorTextArea"
onInput={(event) => {
const textarea = event.target as HTMLTextAreaElement;
handleInput(textarea.value);
}}
2022-05-21 11:18:57 +00:00
className="h-[70vh] w-full rounded-xl
bg-mid !bg-opacity-40 p-8 font-monospace text-black outline-none"
value={markdown}
title="Input textarea"
/>
2022-02-17 16:55:44 +00:00
</div>
<div>
<h2>Preview</h2>
2022-05-21 11:18:57 +00:00
<div className="h-[70vh] overflow-scroll rounded-xl bg-mid bg-opacity-40 p-8">
<Markdawn className="w-full" text={markdown} />
2022-02-17 16:55:44 +00:00
</div>
</div>
</div>
</ContentPanel>
);
return (
<AppLayout
2022-02-24 03:50:00 +00:00
navTitle="Markdawn Editor"
contentPanel={contentPanel}
{...props}
/>
);
2022-02-17 16:55:44 +00:00
}
export async function getStaticProps(
context: GetStaticPropsContext
2022-04-03 08:34:21 +00:00
): Promise<{ notFound: boolean } | { props: Props }> {
const props: Props = {
...(await getAppStaticProps(context)),
};
return {
props: props,
};
}