From fba58ffadb7a7af0a14cfb2c47478e56b0cc595d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=A1=E3=82=83=E3=82=93?= <125573400+random776@users.noreply.github.com> Date: Mon, 13 Jan 2025 19:31:35 +0900 Subject: [PATCH] Revert "update-markdown" --- .eslintrc.cjs | 5 +- src/App.tsx | 292 +++++++++++++++++++++++------------------ src/MDToHTML.tsx | 3 +- src/external-syntax.ts | 8 +- src/extractPDF.tsx | 4 +- src/index.css | 14 -- src/uploadImage.tsx | 16 +-- src/uploadMarkdown.tsx | 20 +-- 8 files changed, 191 insertions(+), 171 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index f0137e2..6c381bd 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -27,8 +27,5 @@ module.exports = { }, plugins: ["@typescript-eslint", "react"], ignorePatterns: ["/dist/*"], - rules: { - 'react/react-in-jsx-scope': 'off', // React 17+ ではJSXトランスフォームが不要 - '@typescript-eslint/no-explicit-any': 'warn', // any型の使用を警告(エラーにしたい場合は`error`) - }, + rules: {}, }; diff --git a/src/App.tsx b/src/App.tsx index 4ee1737..fb5e8d9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,10 @@ -import { useEffect, useRef, useState, SetStateAction } from "react"; +import { useEffect, useState, SetStateAction } from "react"; import parse, { Element, HTMLReactParserOptions } from "html-react-parser"; +// import Markdown from "react-markdown"; +// import rehypeKatex from "rehype-katex"; +// import remarkMath from "remark-math"; import Tippy from "@tippyjs/react"; +// import markdownLink from "/hoge.md?url"; import { ExtractDefinitions } from "./MDToDefinitions"; import { MDToHTML } from "./MDToHTML"; import { replaceExternalSyntax } from "./external-syntax"; @@ -8,6 +12,7 @@ import { ExtractPDF } from "./extractPDF"; import pdfFile from "/chibutsu_nyumon.pdf"; import Textarea from "@mui/joy/Textarea"; import { Button } from "@mui/material"; + import "katex/dist/katex.min.css"; import "tippy.js/dist/tippy.css"; import UploadMarkdown from "./uploadMarkdown"; @@ -19,15 +24,26 @@ export default function App() { const [markdown, setMarkdown] = useState(""); const [html, setHTML] = useState(""); const [dict, setDict] = useState(new Map()); - const opts = { prefix: "!define", suffix: "!enddef" }; - const [inputPosition, setInputPosition] = useState(null); + const opts = { + prefix: "!define", + suffix: "!enddef", + }; + + // ドラッグして直接参照できる機能の部分 + const [inputPosition, setInputPosition] = useState(null); // ドラッグされた位置 const [inputValue, setInputValue] = useState(""); const [isTextAreaFocused, setIsTextAreaFocused] = useState(false); - const [visualize, setVisualize] = useState(true); + const [visualize, setVisualize] = useState(true); // テキストエリアを表示にするか非表示にするか const [fileContent, setFileContent] = useState(""); const [imageData, setImageData] = useState(""); - const textAreaRef = useRef(null); - const previewRef = useRef(null); + + // get markdown + // useEffect(() => { + // fetch(markdownLink) + // .then((res) => res.text()) + // .then((t) => setMarkdown(t)) + // .catch((err) => console.error("Error fetching Hoge.md:", err)); + // }, []); useEffect(() => { setMarkdown(fileContent); @@ -35,92 +51,93 @@ export default function App() { useEffect(() => { localStorage.setItem("item", markdown); - }, [markdown]); + }, [markdown]); // markdownの内容が変わるたびにlocalStorageに保存。 - useEffect(() => { - async function processMarkdown() { - const d = ExtractDefinitions(markdown, opts.prefix, opts.suffix); - const newd = new Map(); - const promises = Array.from(d.entries()).map(([k, v]) => { - const md = replaceExternalSyntax(v) - .replaceAll(opts.prefix, "##") - .replaceAll(opts.suffix, ""); - return MDToHTML(md).then((newv) => newd.set(k, newv)); - }); - await Promise.all(promises); - setDict(newd); + // use markdown (separation is necessary because it's async) + useEffect(() => void insideUseEffect(), [markdown]); + async function insideUseEffect() { + // prepare dictionary + let d = ExtractDefinitions(markdown, opts.prefix, opts.suffix); + const newd = new Map(); + const promises: Promise>[] = []; + d.forEach((v, k) => { + let md = replaceExternalSyntax(v); + md = md.replaceAll(opts.prefix, "##").replaceAll(opts.suffix, ""); + const p = MDToHTML(md).then((newv) => newd.set(k, newv)); + promises.push(p); + }); + Promise.all(promises).then(() => setDict(newd)); - let md = replaceExternalSyntax(markdown.replace(/!define[\s\S]*$/m, "")); - try { - md = replaceExternalSyntax(md); - } catch (e: any) { - md = e.toString(); - } - MDToHTML(md.replaceAll(opts.prefix, "##").replaceAll(opts.suffix, "")) - .then(setHTML) - .catch(() => console.log("MDToHTML failed")); + // prepare HTML + var md; + try { + md = replaceExternalSyntax(markdown.replace(/!define[\s\S]*$/m, "")); // !define以下をすべて取り去る。 + } catch (e: any) { + md = e.toString(); } - processMarkdown(); - }, [markdown]); + MDToHTML(md.replaceAll(opts.prefix, "##").replaceAll(opts.suffix, "")) + .then((h) => setHTML(h)) + .catch(() => console.log("MDToHTML failed")); + } + // ドラッグして直接参照できる機能の部分 useEffect(() => { const handleSelectionChange = () => { - if (!isTextAreaFocused) { - const selection = document.getSelection(); - if (selection && selection.rangeCount > 0) { - const range = selection.getRangeAt(0); - const rect = range.getBoundingClientRect(); - if (selection.toString()) { - setInputPosition({ - top: rect.bottom + window.scrollY, - left: rect.left + window.scrollX, - }); - setInputValue("!define " + selection.toString()); - } else { - setInputPosition(null); - } + const selection = document.getSelection(); + if (selection && selection.rangeCount > 0 && !isTextAreaFocused) { + // textareaがFocusされていないときのみ、selectionを発令する。 + const range = selection.getRangeAt(0); // Range { commonAncestorContainer: #text, startContainer: #text, startOffset: 8, endContainer: #text, endOffset: 23, collapsed: true } + // 左から8文字目から23文字目であることを指している。 + const rect = range.getBoundingClientRect(); // DOMRect { x: 209.56666564941406, y: 167.25, width: 130.38333129882812, height: 29, top: 167.25, right: 339.9499969482422, bottom: 196.25, left: 209.56666564941406 } + // 位置情報の取得 + + // setSelectedText(selection.toString()); // ...unused + + if (selection.toString()) { + // console.log(selection.toString()) 選択した範囲の文字列。 + setInputPosition({ + top: rect.bottom + window.scrollY, + left: rect.left + window.scrollX, + }); + setInputValue("!define " + selection.toString()); + } else { + setInputPosition(null); } } }; document.addEventListener("selectionchange", handleSelectionChange); - return () => + return () => { document.removeEventListener("selectionchange", handleSelectionChange); + }; }, [isTextAreaFocused]); const handleInputChange = (event: { target: { value: SetStateAction }; }) => { setInputValue(event.target.value); + // console.log(inputValue) 入力された内容がここに入る。 }; - const handleScrollSync = ( - sourceRef: React.RefObject, - targetRef: React.RefObject, - ) => { - if (sourceRef.current && targetRef.current) { - targetRef.current.scrollTop = sourceRef.current.scrollTop; - } + const handleImageChange = (content: string) => { + setImageData(content); }; - const insertDollarSignsAtCursor = (command: string) => { - if (textAreaRef.current) { - const textarea = textAreaRef.current; - const start = textarea.selectionStart; - const end = textarea.selectionEnd; - const newText = `${markdown.slice(0, start)}$$ \n ${command} \n $$${markdown.slice(end)}`; - setMarkdown(newText); - setTimeout(() => { - textarea.selectionStart = textarea.selectionEnd = start + 3; - textarea.focus(); - }, 0); - } + const handleTextAreaFocus = () => { + setIsTextAreaFocused(true); + }; + + const handleTextAreaBlur = () => { + setIsTextAreaFocused(false); }; + // テキストファイルを保存する const saveFile = () => { - const blob = new Blob([markdown], { type: ".md, text/markdown" }); + const blob = new Blob([markdown], { + type: ".md, text/markdown", + }); const link = document.createElement("a"); link.href = URL.createObjectURL(blob); - link.download = localStorage.getItem("filename") ?? "hoge.md"; + link.download = localStorage.getItem("filename") ?? "hoge.md"; // localStorage上に保存したファイル名を使う。 link.click(); }; @@ -134,13 +151,18 @@ export default function App() {
- +
- {!visualize && ( + {visualize == false && ( <>
-
@@ -150,45 +172,34 @@ export default function App() { )}
{imageData}
- {visualize && ( + {visualize == true && ( <>
-
- -
-
handleScrollSync(previewRef, textAreaRef)} - > +