Editor.tsx 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. /** @jsx h */
  2. import { h } from "preact";
  3. import { useEffect, useState } from "preact/hooks";
  4. import showdown, { Converter } from "showdown";
  5. interface EditorProps {
  6. content: string;
  7. allowMode: "edit" | "read" | "both";
  8. }
  9. let converter: Converter | null = null;
  10. export default function Editor(props: EditorProps) {
  11. const [mode, setMode] = useState(props.allowMode);
  12. const [displayContent, setDisplayContent] = useState("");
  13. const [convertedContent, setConvertedContent] = useState("");
  14. // Event listener
  15. const modeChangeListener = (e: CustomEvent) => {
  16. if (e.detail && props.allowMode === "both") {
  17. setMode(e.detail);
  18. }
  19. };
  20. // Init event listeners
  21. useEffect(() => {
  22. window.addEventListener("ModeChange", modeChangeListener);
  23. return () => {
  24. window.removeEventListener("ModeChange", modeChangeListener);
  25. };
  26. }, []);
  27. // Init conversion
  28. useEffect(() => {
  29. if (props.content) {
  30. convertText(props.content);
  31. }
  32. }, [props.content]);
  33. const convertText = (text: string) => {
  34. // Init converter
  35. if (!converter) {
  36. converter = new showdown.Converter();
  37. }
  38. // Save display text
  39. setDisplayContent(text);
  40. // Convert text and save
  41. setConvertedContent(converter.makeHtml(text));
  42. };
  43. return (
  44. <div className={`pd-editor pd-mode-${mode}`}>
  45. {mode !== "read"
  46. ? (
  47. <div className="pd-edit-view">
  48. <textarea
  49. placeholder="Some Markdown here"
  50. onInput={(e) => {
  51. convertText((e.target as HTMLInputElement).value);
  52. }}
  53. value={displayContent}
  54. />
  55. </div>
  56. )
  57. : null}
  58. {mode !== "edit"
  59. ? (
  60. <div
  61. className="pd-read-view"
  62. dangerouslySetInnerHTML={{ __html: convertedContent }}
  63. />
  64. )
  65. : null}
  66. </div>
  67. );
  68. }