From 44b4ef1a4482b443a9eb89a0ecd2a28e8eaf5485 Mon Sep 17 00:00:00 2001 From: mattuy Date: Tue, 5 Oct 2021 23:45:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 222 ++++++++++++++++++++++++ src/App.js | 2 + src/component/EditableContent/index.js | 19 +- src/menu/editor.js | 146 +++++++++------- src/menu/notation.js | 102 ++++++++--- src/menu/paragraph.js | 12 +- src/store/history.js | 11 +- src/view/ConfigModal/index.js | 75 +++++++- src/view/Editor/index.js | 30 +++- src/view/Header/RightInfoBlock/index.js | 6 +- src/view/HelpModal/index.js | 6 + src/view/Notation/index.js | 14 +- src/view/Paragraph/index.js | 3 +- 13 files changed, 524 insertions(+), 124 deletions(-) create mode 100644 src/view/HelpModal/index.js diff --git a/package-lock.json b/package-lock.json index cdc4388..ade733b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,13 @@ "@testing-library/react": "^11.2.7", "@testing-library/user-event": "^12.8.3", "antd": "^4.16.13", + "bootstrap": "^4.6.0", "mobx": "^6.3.3", "mobx-react-lite": "^3.2.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "4.0.3", + "reactstrap": "^8.10.0", "web-vitals": "^1.1.2" } }, @@ -1928,6 +1930,19 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==" }, + "node_modules/@hypnosphi/create-react-context": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz", + "integrity": "sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A==", + "dependencies": { + "gud": "^1.0.0", + "warning": "^4.0.3" + }, + "peerDependencies": { + "prop-types": "^15.0.0", + "react": ">=0.14.0" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -5528,6 +5543,19 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, + "node_modules/bootstrap": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz", + "integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + }, + "peerDependencies": { + "jquery": "1.9.1 - 3", + "popper.js": "^1.16.1" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -7436,6 +7464,14 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, "node_modules/dom-serializer": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", @@ -9810,6 +9846,11 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "optional": true }, + "node_modules/gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, "node_modules/gzip-size": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", @@ -13090,6 +13131,12 @@ "node": ">=8" } }, + "node_modules/jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==", + "peer": true + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -15003,6 +15050,16 @@ "node": ">=6" } }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -17354,6 +17411,28 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-popper": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz", + "integrity": "sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "@hypnosphi/create-react-context": "^0.3.1", + "deep-equal": "^1.1.1", + "popper.js": "^1.14.4", + "prop-types": "^15.6.1", + "typed-styles": "^0.0.7", + "warning": "^4.0.2" + }, + "peerDependencies": { + "react": "0.14.x || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/react-refresh": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", @@ -17483,6 +17562,48 @@ "semver": "bin/semver" } }, + "node_modules/react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "dependencies": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0", + "react-dom": ">=15.0.0" + } + }, + "node_modules/reactstrap": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-8.10.0.tgz", + "integrity": "sha512-MsFUB/fRZj6Orf8Mxc93iYuAs+9ngnFmy2cfYlzkmc4vi5oM4u6ziY/DsO71lDG3cotxHRyS3Flr51cuYv+IEQ==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "classnames": "^2.2.3", + "prop-types": "^15.5.8", + "react-popper": "^1.3.6", + "react-transition-group": "^2.3.1" + }, + "peerDependencies": { + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, + "node_modules/reactstrap/node_modules/@babel/runtime": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", + "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -20374,6 +20495,11 @@ "node": ">= 0.6" } }, + "node_modules/typed-styles": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", + "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==" + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -23959,6 +24085,15 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==" }, + "@hypnosphi/create-react-context": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz", + "integrity": "sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A==", + "requires": { + "gud": "^1.0.0", + "warning": "^4.0.3" + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -26715,6 +26850,12 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, + "bootstrap": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz", + "integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw==", + "requires": {} + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -28239,6 +28380,14 @@ "utila": "~0.4" } }, + "dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, "dom-serializer": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", @@ -30023,6 +30172,11 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "optional": true }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, "gzip-size": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", @@ -32433,6 +32587,12 @@ } } }, + "jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==", + "peer": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -33903,6 +34063,11 @@ "ts-pnp": "^1.1.6" } }, + "popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" + }, "portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -35749,6 +35914,25 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-popper": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz", + "integrity": "sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg==", + "requires": { + "@babel/runtime": "^7.1.2", + "@hypnosphi/create-react-context": "^0.3.1", + "deep-equal": "^1.1.1", + "popper.js": "^1.14.4", + "prop-types": "^15.6.1", + "typed-styles": "^0.0.7", + "warning": "^4.0.2" + } + }, "react-refresh": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", @@ -35852,6 +36036,39 @@ } } }, + "react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "requires": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + }, + "reactstrap": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-8.10.0.tgz", + "integrity": "sha512-MsFUB/fRZj6Orf8Mxc93iYuAs+9ngnFmy2cfYlzkmc4vi5oM4u6ziY/DsO71lDG3cotxHRyS3Flr51cuYv+IEQ==", + "requires": { + "@babel/runtime": "^7.12.5", + "classnames": "^2.2.3", + "prop-types": "^15.5.8", + "react-popper": "^1.3.6", + "react-transition-group": "^2.3.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", + "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -38145,6 +38362,11 @@ "mime-types": "~2.1.24" } }, + "typed-styles": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", + "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==" + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", diff --git a/src/App.js b/src/App.js index 9f31d1d..75c68df 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,7 @@ import Editor from "./view/Editor"; import globalStore, { GlobalContext } from "./store/global"; + +// ENHANCE: 替换掉antd组件库。。一堆莫名其妙的毛病 function App() { return ( diff --git a/src/component/EditableContent/index.js b/src/component/EditableContent/index.js index 8c36a5c..c847879 100644 --- a/src/component/EditableContent/index.js +++ b/src/component/EditableContent/index.js @@ -4,7 +4,18 @@ import PopoverOnSvg from "../PopoverOnSvg"; import Styles from "./index.module.css"; const EditableContent = function ( - { children, title, initialValue, inputType, options, onChange, popoverProps }, + { + children, + title, + initialValue, + inputType, + // ENHANCE: 去除这个prop,使用overlay代替 + options, + // 选择模式要渲染的菜单,如果没有提供则根据options生成 + overlay, + onChange, + popoverProps, + }, ref ) { const [inputValue, setInputValue] = useState(initialValue); @@ -37,6 +48,9 @@ const EditableContent = function ( }, [inputValue, onChange] ); + const handleHideContextMenu = useCallback(() => { + setPopoverVisible(false); + }, []); const handleCancel = useCallback( function () { setInputValue(initialValue); @@ -68,6 +82,9 @@ const EditableContent = function ( [inputValue, handleInput, handleConfirm, handleCancel] ); const renderSelectionPopover = useCallback(() => { + if (overlay) { + return
{overlay}
; + } return ( {(options || []) diff --git a/src/menu/editor.js b/src/menu/editor.js index 29b7dd9..ab8124a 100644 --- a/src/menu/editor.js +++ b/src/menu/editor.js @@ -1,7 +1,11 @@ import { FolderOpenOutlined, + HighlightOutlined, + MenuUnfoldOutlined, PlusOutlined, + RedoOutlined, SaveOutlined, + UndoOutlined, } from "@ant-design/icons"; import { Menu } from "antd"; import { action } from "mobx"; @@ -13,69 +17,8 @@ import { findParagraphAndNotation } from "../util/editor"; import { go, runInWrappedAction, wrappedAction } from "../store/history"; const { SubMenu } = Menu; -const fileMenu = ( - - }> - 新建 - - }> - 打开 - - }> - 保存 - - -); -const editMenu = ( - - 撤销 - 重做 - 添加段落 - 重置歌曲名称 - 重置作者信息 - -); -const convertMenu = ( - - - 1 = C - 1 = D - 1 = E - 1 = F - 1 = G - 1 = A - 1 = B - - 1 = C - - - 1 = D - - - 1 = E - - - 1 = F - - - 1 = G - - - 1 = A - - - 1 = B - - - 升高一个音 - 降低一个音 - 升高一个八度 - 降低一个八度 - -); - -function handleMenu({ key }) { +const handleEditMenu = wrappedAction(({ key }) => { switch (key) { case "undo": go(-1); @@ -96,7 +39,11 @@ function handleMenu({ key }) { ]; break; } -} +}); +const handleConvertMenu = wrappedAction(() => { + + console.log(111); +}); const handleClick = wrappedAction((ev) => { if (state.shouldNotationBlurAfterClick) { @@ -217,4 +164,77 @@ const handleKeyPress = wrappedAction((ev) => { } }); + +const fileMenu = ( + + }> + 新建 + + }> + 打开 + + }> + 保存 + + +); +const editMenu = ( + + }> + 撤销 + + }> + 重做 + + }> + 添加段落 + + }> + 重置歌曲名称 + + }> + 重置作者信息 + + +); + +const convertMenu = ( + + + 1 = C + 1 = D + 1 = E + 1 = F + 1 = G + 1 = A + 1 = B + + 1 = C + + + 1 = D + + + 1 = E + + + 1 = F + + + 1 = G + + + 1 = A + + + 1 = B + + + 升高一个音 + 降低一个音 + 升高一个八度 + 降低一个八度 + +); + export { fileMenu, editMenu, convertMenu, handleKeyPress, handleClick }; diff --git a/src/menu/notation.js b/src/menu/notation.js index 0685965..3060f99 100644 --- a/src/menu/notation.js +++ b/src/menu/notation.js @@ -1,33 +1,36 @@ -import { message } from "antd"; +import { + ArrowDownOutlined, + ArrowUpOutlined, + FontColorsOutlined, + MinusOutlined, + PlusOutlined, + RadiusSettingOutlined, + StopOutlined, +} from "@ant-design/icons"; +import { Menu, message } from "antd"; import state from "../store/state"; import { findParagraphAndNotation } from "../util/editor"; import { isNote } from "../util/notation"; import { runInWrappedAction, wrappedAction } from "../store/history"; -const getNotationContextItems = (notation, paragraph) => { +const getNotationContextMenu = (notation, paragraph) => { const hasTie = notation.tieTo; - return [ - { - key: "octaveUp", - text: "升高一个八度", - visible: isNote(notation), - onClick: wrappedAction(() => { + const handleMenu = wrappedAction(function ({ key }) { + switch (key) { + case "octave-up": notation.octave += 1; - }), - }, - { - key: "octaveDown", - text: "降低一个八度", - visible: isNote(notation), - onClick: wrappedAction(() => { + break; + case "octave-down": notation.octave -= 1; - }), - }, - { - key: "tie", - text: notation.tieTo ? "删除连音线" : "从此处添加连音线到...", - visible: isNote(notation), - onClick: wrappedAction(() => { + break; + case "underline-add": + notation.underline += 1; + break; + case "underline-remove": + notation.underline -= 1; + notation.underline = Math.max(0, notation.underline); + break; + case "tie": if (!hasTie) { state.tieSourceKey = notation.key; return; @@ -37,8 +40,59 @@ const getNotationContextItems = (notation, paragraph) => { tieDesc.tieTo = null; } notation.tieTo = null; + break; + case "break-underline": + notation.breakUnderline = !notation.breakUnderline; + break; + } + }); + + return ( + + }> + 升高一个八度(8) + + }> + 降低一个八度(Shift + 8) + + }> + 添加增减时线(U) + + }> + 减少增减时线(Shift + U) + + }> + {notation.breakUnderline ? "在此处延续增减时线" : "在此处打断增减时线"} + + }> + {notation.tieTo ? "删除连音线" : "从此处添加连音线到..."} + + + ); + + return [ + { + key: "octaveUp", + text: "升高一个八度(8)", + visible: isNote(notation), + onClick: wrappedAction(() => { + notation.octave += 1; }), }, + { + key: "octaveDown", + text: "降低一个八度(Shift + 8)", + visible: isNote(notation), + onClick: wrappedAction(() => { + notation.octave -= 1; + }), + }, + { + key: "tie", + text: notation.tieTo ? "删除连音线" : "从此处添加连音线到...", + visible: isNote(notation), + onClick: wrappedAction(() => {}), + }, { key: "break-underline", text: notation.breakUnderline @@ -64,7 +118,7 @@ const getNotationContextItems = (notation, paragraph) => { ]; }; -// ENHANCE: 改变组件这个反人类的回调执行 +// ENHANCE: 使用EditableContent组件的overlay属性传入菜单 // 执行选项回调。。 function handleNotationContext(options, key) { runInWrappedAction(() => (state.shouldNotationBlurAfterClick = false)); @@ -72,4 +126,4 @@ function handleNotationContext(options, key) { callback && callback(); } -export { getNotationContextItems, handleNotationContext }; +export { getNotationContextMenu, handleNotationContext }; diff --git a/src/menu/paragraph.js b/src/menu/paragraph.js index fabdb7f..3edd018 100644 --- a/src/menu/paragraph.js +++ b/src/menu/paragraph.js @@ -11,8 +11,8 @@ import store from "../store/global"; import { go, runInWrappedAction, wrappedAction } from "../store/history"; function getParagraphMenuOptions(paragraph) { - return []; const handleMenu = wrappedAction(({ key }) => { + console.log(1111111111, key); switch (key) { case "justify-auto": paragraph.alignJustify = null; @@ -46,12 +46,4 @@ function getParagraphMenuOptions(paragraph) { ); } -// ENHANCE: 同notation的菜单项处理函数,改改改 -// TODO: working 现在就改!然后EditableContent应该直接传入antd的菜单项 -_function handleSelectParagraphMenu(options, key) { - runInWrappedAction(() => (state.shouldNotationBlurAfterClick = false)); - const callback = options.find((ops) => ops.key === key)?.onClick; - callback && callback(); -} - -export { getParagraphMenuOptions, handleSelectParagraphMenu }; +export { getParagraphMenuOptions }; diff --git a/src/store/history.js b/src/store/history.js index 392c2ee..7b02445 100644 --- a/src/store/history.js +++ b/src/store/history.js @@ -88,5 +88,14 @@ function runInWrappedAction(func) { executeAction.call(this, func); }); } +// 不需要记录历史记录的时候直接使用原action +const unwrappedAction = action; +const runInUnwrappedAction = runInAction; -export { go, wrappedAction, runInWrappedAction }; +export { + go, + wrappedAction, + runInWrappedAction, + unwrappedAction, + runInUnwrappedAction, +}; diff --git a/src/view/ConfigModal/index.js b/src/view/ConfigModal/index.js index e346127..94d2c45 100644 --- a/src/view/ConfigModal/index.js +++ b/src/view/ConfigModal/index.js @@ -1,6 +1,75 @@ -function ConfigModal({ visible, onVisibleChange }) { - return null; +import { Button, Form, Input, InputNumber, Modal } from "antd"; +import { observer } from "mobx-react-lite"; +import { useCallback } from "react"; +import store from "../../store/global"; +import { unwrappedAction, wrappedAction } from "../../store/history"; + +const ImmediateNumberConfigInput = observer(({ propertyName, ...props }) => { + const handleChange = unwrappedAction((ev) => { + const v = Number(ev.target.value) | 0; + store[propertyName] = v; + }); + return ( + + ); +}); +function ImmediateNumberConfigItem({ propertyName, label, ...props }) { + return ( + + + + ); +} + +function ConfigModal({ visible, onVisibleChange }) { + const handleClose = useCallback(() => { + onVisibleChange?.call(null, false); + }, [onVisibleChange]); + + return ( + + 关闭 + + } + > +
+ + + + + + + + + + +
+ ); } -// TODO: do this export default ConfigModal; diff --git a/src/view/Editor/index.js b/src/view/Editor/index.js index 80c48a6..59b91c8 100644 --- a/src/view/Editor/index.js +++ b/src/view/Editor/index.js @@ -2,12 +2,12 @@ import { Button, Dropdown } from "antd"; import { EditOutlined, FileTextOutlined, + QuestionOutlined, RetweetOutlined, SettingOutlined, - SyncOutlined, } from "@ant-design/icons"; import { observer } from "mobx-react-lite"; -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import store from "../../store/global"; import P, { calcParagraphAboveOffset, @@ -28,7 +28,8 @@ import Row from "../Row"; import Styles from "./index.module.css"; function Editor() { - const [isModalVisible, setIsModalVisible] = useState(false); + const [isConfigModalVisible, setIsConfigModalVisible] = useState(false); + const [isHelpModalVisible, setIsHelpModalVisible] = useState(false); const heightCache = []; function accumulate(index) { const paragraphs = store.paragraphs || []; @@ -42,6 +43,12 @@ function Editor() { height += calcParagraphAboveOffset(paragraphs[index]); return height; } + const handleShowConfigDialog = useCallback(() => { + setIsConfigModalVisible(true); + }, []); + const handleShowHelpDialog = useCallback(() => { + setIsHelpModalVisible(true); + }, []); useEffect(() => { document.addEventListener("keydown", handleKeyPress); @@ -77,9 +84,20 @@ function Editor() { 转调 - + @@ -102,8 +120,8 @@ function Editor() { ); diff --git a/src/view/Header/RightInfoBlock/index.js b/src/view/Header/RightInfoBlock/index.js index 1ec64f4..c04ee14 100644 --- a/src/view/Header/RightInfoBlock/index.js +++ b/src/view/Header/RightInfoBlock/index.js @@ -13,7 +13,7 @@ const authorContextMenu = [ { key: "create", text: "添加", - icon: , + icon: , onClick: () => { store.authors.push("作者信息"); }, @@ -21,7 +21,7 @@ const authorContextMenu = [ { key: "delete", text: "删除", - icon: , + icon: , onClick: (index) => { store.authors.splice(index, 1); }, @@ -31,7 +31,7 @@ const blockContextMenu = [ { key: "create", text: "添加作者信息", - icon: , + icon: , onClick: () => { store.authors.push("【记谱者】 记谱"); }, diff --git a/src/view/HelpModal/index.js b/src/view/HelpModal/index.js new file mode 100644 index 0000000..ef68c9b --- /dev/null +++ b/src/view/HelpModal/index.js @@ -0,0 +1,6 @@ +function HelpModal({ visible, onVisibleChange }) { + return null; +} + +// TODO: do this +export default HelpModal; diff --git a/src/view/Notation/index.js b/src/view/Notation/index.js index d3086d0..e9f9358 100644 --- a/src/view/Notation/index.js +++ b/src/view/Notation/index.js @@ -4,15 +4,9 @@ import { observer } from "mobx-react-lite"; import EditableContent from "../../component/EditableContent"; import state from "../../store/state"; import store from "../../store/global"; -import P, { - calcNotationPrefixOffset, - calcSubTextWidth, -} from "../../util/placement"; +import P, { calcSubTextWidth } from "../../util/placement"; import { findParagraphAndNotation } from "../../util/editor"; -import { - getNotationContextItems, - handleNotationContext, -} from "../../menu/notation"; +import { getNotationContextMenu } from "../../menu/notation"; import { notations } from "../../util/notation"; import { wrappedAction } from "../../store/history"; import Row from "../Row"; @@ -128,13 +122,11 @@ function Notation({ offsetX, notation, paragraph }) { )); }; - const options = getNotationContextItems(notation, paragraph); return (