diff --git a/.gitignore b/.gitignore index c3c2b40926ed..210cc643e6d3 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ .env.development.local .env.test.local .env.production.local +nginx.conf npm-debug.log* yarn-debug.log* diff --git a/package-lock.json b/package-lock.json index b063377ae774..e7d95519779c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,12 @@ "name": "landing", "version": "0.1.0", "dependencies": { - "@diplodoc/transform": "^4.26.0", + "@diplodoc/transform": "^4.18.0", "@gravity-ui/chartkit": "^5.10.1", "@gravity-ui/components": "^3.10.1", "@gravity-ui/date-components": "^2.10.1", "@gravity-ui/icons": "^2.11.0", + "@gravity-ui/markdown-editor": "^13.18.0", "@gravity-ui/navigation": "^2.23.1", "@gravity-ui/page-constructor": "^5.2.0", "@gravity-ui/uikit": "^6.27.2", @@ -2916,6 +2917,143 @@ "resolved": "https://registry.npmjs.org/@bem-react/classname/-/classname-1.6.0.tgz", "integrity": "sha512-SFBwUHMcb7TFFK5ld88+JhecoEun3/kHZ6KvLDjj3w5hv/tfRV8mtGHA8N42uMctXLF4bPEcr96xwXXcRFuweg==" }, + "node_modules/@bem-react/classnames": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@bem-react/classnames/-/classnames-1.3.10.tgz", + "integrity": "sha512-tn+45Ii+S5FcYuO5FMs9YLSMUc355iUho7mwFeMMihi/ZZCQjvdR5AhVexnL9GS7pMtOeV0OsDOPDkW1sXVI3A==" + }, + "node_modules/@codemirror/autocomplete": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.16.0.tgz", + "integrity": "sha512-P/LeCTtZHRTCU4xQsa89vSKWecYv1ZqwzOd5topheGRf+qtacFgBeIMQi3eL8Kt/BUNvxUWkx+5qP2jlGoARrg==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + }, + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.5.0.tgz", + "integrity": "sha512-rK+sj4fCAN/QfcY9BEzYMgp4wwL/q5aj/VfNSoH1RWPF9XS/dUwBkvlL3hpWgEjOqlpdN1uLC9UkjJ4tmyjJYg==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/lang-css": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.0.tgz", + "integrity": "sha512-CyR4rUNG9OYcXDZwMPvJdtb6PHbBDKUc/6Na2BIwZ6dKab1JQqKa4di+RNRY9Myn7JB81vayKwJeQ7jEdmNVDA==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/css": "^1.1.7" + } + }, + "node_modules/@codemirror/lang-html": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz", + "integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/css": "^1.1.0", + "@lezer/html": "^1.3.0" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.2.tgz", + "integrity": "sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-markdown": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.2.5.tgz", + "integrity": "sha512-Hgke565YcO4fd9pe2uLYxnMufHO5rQwRr+AAhFq8ABuhkrjyX8R5p5s+hZUTdV60O0dMRjxKhBLxz8pu/MkUVA==", + "dependencies": { + "@codemirror/autocomplete": "^6.7.1", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.3.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/markdown": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.1.tgz", + "integrity": "sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.1.tgz", + "integrity": "sha512-IZ0Y7S4/bpaunwggW2jYqwLuHj0QtESf5xcROewY6+lDNwZ/NzvR4t+vpYgg9m7V8UXLPYqG+lu3DF470E5Oxg==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.5.6", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.6.tgz", + "integrity": "sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==" + }, + "node_modules/@codemirror/view": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.26.3.tgz", + "integrity": "sha512-gmqxkPALZjkgSxIeeweY/wGQXBfwTUaLs8h7OKtSwfbj9Ct3L11lD+u1sS7XHppxFQoMDiMDp07P9f3I2jWOHw==", + "dependencies": { + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, "node_modules/@csstools/selector-specificity": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", @@ -2933,9 +3071,9 @@ } }, "node_modules/@diplodoc/tabs-extension": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@diplodoc/tabs-extension/-/tabs-extension-3.1.1.tgz", - "integrity": "sha512-FWywClCNtMUQGZAsd6Hr/Cs1TX9aOJ4t9SOR9pIuOVsJwVWXNihdUW7x2yaAT0WwP4bBqXg7GSUQ/DIVIde9Ww==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@diplodoc/tabs-extension/-/tabs-extension-2.2.1.tgz", + "integrity": "sha512-12I873v9CLZ4mqWgpDf0vMiQAfLg2x48fmExnXt/6s6ZBsjc4pIe3uJk+LU0qfL6MqnCDgoIU4ZUIAa3B0y9GQ==", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" }, @@ -2946,11 +3084,11 @@ } }, "node_modules/@diplodoc/transform": { - "version": "4.26.0", - "resolved": "https://registry.npmjs.org/@diplodoc/transform/-/transform-4.26.0.tgz", - "integrity": "sha512-k6TxF3DzWkAdfPnjzfUBR4mNGiE4dQC5Cvk9flGazhX2aNOXetSYU1/Y1voSNNnG8EmTJqXOsTptGMLBxAz/hw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@diplodoc/transform/-/transform-4.18.0.tgz", + "integrity": "sha512-1mApsc5MAkedcREgCd5PUAtp325DmYR++AJComE1DXdBnzFC+BVrTzsnX1lCT4vJzG4yh46MkuC+ZvuhOj37Qg==", "dependencies": { - "@diplodoc/tabs-extension": "^3.0.0", + "@diplodoc/tabs-extension": "^2.1.0", "chalk": "^4.1.2", "cheerio": "^1.0.0-rc.12", "css": "^3.0.0", @@ -3340,6 +3478,90 @@ } } }, + "node_modules/@gravity-ui/markdown-editor": { + "version": "13.18.0", + "resolved": "https://registry.npmjs.org/@gravity-ui/markdown-editor/-/markdown-editor-13.18.0.tgz", + "integrity": "sha512-a2L3/0ATCc3hyCmINLWGxHLJSgApR9bB/XhESGGR8LKI7SCEmdwanXRVwWNnUkiFvt8zURWq0/ZRkrpHr5pEzQ==", + "dependencies": { + "@bem-react/classname": "^1.6.0", + "@bem-react/classnames": "1.3.10", + "@codemirror/autocomplete": "6.16.0", + "@codemirror/commands": "6.5.0", + "@codemirror/lang-markdown": "6.2.5", + "@codemirror/language": "6.10.1", + "@codemirror/search": "6.5.6", + "@codemirror/state": "6.4.1", + "@codemirror/view": "6.26.3", + "@gravity-ui/i18n": "^1.1.0", + "@gravity-ui/icons": "^2.10.0", + "@lezer/highlight": "1.2.0", + "@lezer/markdown": "1.3.0", + "@types/is-number": "^7.0.1", + "@types/markdown-it": "^12.2.3", + "base64-arraybuffer": "1.0.2", + "is-number": "^7.0.0", + "markdown-it-attrs": "4.1.4", + "markdown-it-color": "^2.1.1", + "markdown-it-emoji": "2.0.2", + "markdown-it-ins": "^3.0.1", + "markdown-it-mark": "^3.0.1", + "markdown-it-sub": "^1.0.0", + "prosemirror-autocomplete": "0.4.3", + "prosemirror-codemark": "0.4.2", + "prosemirror-commands": "1.5.2", + "prosemirror-dropcursor": "1.8.1", + "prosemirror-history": "1.4.0", + "prosemirror-inputrules": "1.4.0", + "prosemirror-keymap": "1.2.2", + "prosemirror-model": "1.21.0", + "prosemirror-schema-list": "1.3.0", + "prosemirror-state": "1.4.3", + "prosemirror-test-builder": "1.1.1", + "prosemirror-transform": "1.9.0", + "prosemirror-utils": "1.2.0", + "prosemirror-view": "1.33.6", + "react-error-boundary": "^3.1.4", + "react-hotkeys-hook": "4.5.0", + "react-use": "^17.3.2", + "tslib": "^2.3.1" + }, + "peerDependencies": { + "@diplodoc/folding-headings-extension": "^0.1.0", + "@diplodoc/html-extension": "2.1.0", + "@diplodoc/latex-extension": "^1.0.3", + "@diplodoc/mermaid-extension": "^1.0.0", + "@diplodoc/transform": ">=4.5.0 <4.19.0", + "@gravity-ui/components": "^3.0.0", + "@gravity-ui/uikit": "^6.11.0", + "highlight.js": "^11.8.0", + "katex": "^0.16.9", + "lodash": "^4.17.20", + "lowlight": "^3.0.0", + "markdown-it": "^13.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@diplodoc/folding-headings-extension": { + "optional": true + }, + "@diplodoc/html-extension": { + "optional": true + }, + "@diplodoc/latex-extension": { + "optional": true + }, + "@diplodoc/mermaid-extension": { + "optional": true + }, + "highlight.js": { + "optional": true + }, + "lowlight": { + "optional": true + } + } + }, "node_modules/@gravity-ui/navigation": { "version": "2.23.1", "resolved": "https://registry.npmjs.org/@gravity-ui/navigation/-/navigation-2.23.1.tgz", @@ -3637,6 +3859,66 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@lezer/common": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz", + "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==" + }, + "node_modules/@lezer/css": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.9.tgz", + "integrity": "sha512-TYwgljcDv+YrV0MZFFvYFQHCfGgbPMR6nuqLabBdmZoFH3EP1gvw8t0vae326Ne3PszQkbXfVBjCnf3ZVCr0bA==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz", + "integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz", + "integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.4.17", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.17.tgz", + "integrity": "sha512-bYW4ctpyGK+JMumDApeUzuIezX01H76R1foD6LcRX224FWfyYit/HYxiPGDjXXe/wQWASjCvVGoukTH68+0HIA==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", + "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/markdown": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.3.0.tgz", + "integrity": "sha512-ErbEQ15eowmJUyT095e9NJc3BI9yZ894fjSDtHftD0InkfUBGgnKSU6dvan9jqsZuNHg2+ag/1oyDRxNsENupQ==", + "dependencies": { + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0" + } + }, "node_modules/@mdx-js/mdx": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-2.3.0.tgz", @@ -5434,6 +5716,11 @@ "hoist-non-react-statics": "^3.3.0" } }, + "node_modules/@types/is-number": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@types/is-number/-/is-number-7.0.5.tgz", + "integrity": "sha512-NGmRpXeZg9qDX+AlmBeq4Xk9ruTMj0KfzspDCxTLAcpbts2EjojAvY6A1eumKHInMwGY4xHM8ILA9CHRHfUUWA==" + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -5493,6 +5780,11 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "node_modules/@types/js-cookie": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz", + "integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==" + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -5505,12 +5797,26 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==" + }, "node_modules/@types/lodash": { "version": "4.14.197", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==", "dev": true }, + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, "node_modules/@types/mdast": { "version": "3.0.11", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.11.tgz", @@ -5519,6 +5825,11 @@ "@types/unist": "*" } }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==" + }, "node_modules/@types/mdx": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.4.tgz", @@ -6112,6 +6423,11 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@xobotyi/scrollbar-width": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz", + "integrity": "sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==" + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -6472,6 +6788,14 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/before-after-hook": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", @@ -7161,6 +7485,11 @@ "node": ">=10" } }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -7201,6 +7530,14 @@ "node": ">=12.22" } }, + "node_modules/css-in-js-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz", + "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==", + "dependencies": { + "hyphenate-style-name": "^1.0.3" + } + }, "node_modules/css-select": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", @@ -7340,9 +7677,9 @@ "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" }, "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/d3": { "version": "7.9.0", @@ -8067,6 +8404,14 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dependencies": { + "stackframe": "^1.3.4" + } + }, "node_modules/es-abstract": { "version": "1.22.4", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz", @@ -8995,6 +9340,11 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-shallow-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz", + "integrity": "sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==" + }, "node_modules/fast-xml-parser": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", @@ -9026,6 +9376,11 @@ "node": ">= 4.9.1" } }, + "node_modules/fastest-stable-stringify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz", + "integrity": "sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==" + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -9828,6 +10183,11 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/hyphenate-style-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", + "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==" + }, "node_modules/i18next": { "version": "23.8.3", "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.8.3.tgz", @@ -9949,6 +10309,14 @@ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" }, + "node_modules/inline-style-prefixer": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-7.0.1.tgz", + "integrity": "sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==", + "dependencies": { + "css-in-js-utils": "^3.1.0" + } + }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", @@ -10495,6 +10863,11 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" + }, "node_modules/js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", @@ -10603,6 +10976,31 @@ "node": ">=4.0" } }, + "node_modules/katex": { + "version": "0.16.11", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", + "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "peer": true, + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "peer": true, + "engines": { + "node": ">= 12" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -11282,11 +11680,31 @@ "markdown-it": ">= 9.0.0" } }, + "node_modules/markdown-it-color": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/markdown-it-color/-/markdown-it-color-2.1.1.tgz", + "integrity": "sha512-GqXOSjT+RdGvxjdmPfRS/9XDr5dg4e2kC/mXbXK5Y1lbh/rVepoeaUGaD0Lmi1qS5M6cnbm9GrC8bu9YY8rRKQ==" + }, "node_modules/markdown-it-deflist": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/markdown-it-deflist/-/markdown-it-deflist-2.1.0.tgz", "integrity": "sha512-3OuqoRUlSxJiuQYu0cWTLHNhhq2xtoSFqsZK8plANg91+RJQU1ziQ6lA2LzmFAEes18uPBsHZpcX6We5l76Nzg==" }, + "node_modules/markdown-it-emoji": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-2.0.2.tgz", + "integrity": "sha512-zLftSaNrKuYl0kR5zm4gxXjHaOI3FAOEaloKmRA5hijmJZvSjmxcokOLlzycb/HXlUFWzXqpIEoyEMCE4i9MvQ==" + }, + "node_modules/markdown-it-ins": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-3.0.1.tgz", + "integrity": "sha512-32SSfZqSzqyAmmQ4SHvhxbFqSzPDqsZgMHDwxqPzp+v+t8RsmqsBZRG+RfRQskJko9PfKC2/oxyOs4Yg/CfiRw==" + }, + "node_modules/markdown-it-mark": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-3.0.1.tgz", + "integrity": "sha512-HyxjAu6BRsdt6Xcv6TKVQnkz/E70TdGXEFHRYBGLncRE9lBFwDNLVtFojKxjJWgJ+5XxUwLaHXy+2sGBbDn+4A==" + }, "node_modules/markdown-it-meta": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/markdown-it-meta/-/markdown-it-meta-0.0.1.tgz", @@ -11315,6 +11733,11 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/markdown-it-sub": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz", + "integrity": "sha512-z2Rm/LzEE1wzwTSDrI+FlPEveAAbgdAdPhdWarq/ZGJrGW/uCQbKAnhoCsE4hAbc3SEym26+W2z/VQB0cQiA9Q==" + }, "node_modules/markdown-it-sup": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz", @@ -12517,6 +12940,55 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/nano-css": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/nano-css/-/nano-css-5.6.2.tgz", + "integrity": "sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "css-tree": "^1.1.2", + "csstype": "^3.1.2", + "fastest-stable-stringify": "^2.0.2", + "inline-style-prefixer": "^7.0.1", + "rtl-css-js": "^1.16.1", + "stacktrace-js": "^2.0.2", + "stylis": "^4.3.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/nano-css/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/nano-css/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/nano-css/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/nano-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -12873,6 +13345,11 @@ "node": ">= 0.8.0" } }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==" + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -13392,6 +13869,149 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/prosemirror-autocomplete": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/prosemirror-autocomplete/-/prosemirror-autocomplete-0.4.3.tgz", + "integrity": "sha512-a4w/SOzgrTjXaWpSYMrai6H3KHSUBuADZC/DBm4VApiD9LGHpv98zQbHzsHgInrEoWcBGzYVT0HUD3tLgrsEVQ==", + "dependencies": { + "prosemirror-inputrules": "^1.2.0", + "prosemirror-state": "^1.4.1", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-codemark": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/prosemirror-codemark/-/prosemirror-codemark-0.4.2.tgz", + "integrity": "sha512-4n+PnGQToa/vTjn0OiivUvE8/moLtguUAfry8UA4Q8p47MhqT2Qpf2zBLustX5Upi4mSp3z1ZYBqLLovZC6abA==", + "peerDependencies": { + "prosemirror-inputrules": "^1.2.0", + "prosemirror-model": "^1.18.1", + "prosemirror-state": "^1.4.1", + "prosemirror-view": "^1.26.2" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz", + "integrity": "sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz", + "integrity": "sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.0.tgz", + "integrity": "sha512-UUiGzDVcqo1lovOPdi9YxxUps3oBFWAIYkXLu3Ot+JPv1qzVogRbcizxK3LhHmtaUxclohgiOVesRw5QSlMnbQ==", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-inputrules": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz", + "integrity": "sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz", + "integrity": "sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-model": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.21.0.tgz", + "integrity": "sha512-zLpS1mVCZLA7VTp82P+BfMiYVPcX1/z0Mf3gsjKZtzMWubwn2pN7CceMV0DycjlgE5JeXPR7UF4hJPbBV98oWA==", + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-schema-basic": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.3.tgz", + "integrity": "sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==", + "dependencies": { + "prosemirror-model": "^1.19.0" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.3.0.tgz", + "integrity": "sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.3.tgz", + "integrity": "sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-test-builder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prosemirror-test-builder/-/prosemirror-test-builder-1.1.1.tgz", + "integrity": "sha512-DJ1+4TNTE9ZcYN/ozXCaWJVrGA99UttMoVvZuidvAotRg7FaiNtEYxL/vlDwfZDRnzJDXNYhmM3XPv3EweK7yA==", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-schema-basic": "^1.0.0", + "prosemirror-schema-list": "^1.0.0" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.9.0.tgz", + "integrity": "sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg==", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/prosemirror-utils/-/prosemirror-utils-1.2.0.tgz", + "integrity": "sha512-O2HAjTOxdut3fgFi98ue4Xvw1GMeSSS1cnbcsSbYCjxULCJVUsfMa6DdS2sGGgXQDytTKUxbdQIMQ21Ejst8qA==", + "peerDependencies": { + "prosemirror-model": "^1.19.2", + "prosemirror-state": "^1.4.3" + } + }, + "node_modules/prosemirror-view": { + "version": "1.33.6", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.6.tgz", + "integrity": "sha512-zRLUNgLIQfd8IfGprsXxWTjdA8xEAFJe8cDNrOptj6Mop9sj+BMeVbJvceyAYCm5G2dOdT2prctH7K9dfnpIMw==", + "dependencies": { + "prosemirror-model": "^1.20.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -13569,6 +14189,21 @@ "react": "^18.3.1" } }, + "node_modules/react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-fast-compare": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.1.tgz", @@ -13590,6 +14225,15 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-hotkeys-hook": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.5.0.tgz", + "integrity": "sha512-Samb85GSgAWFQNvVt3PS90LPPGSf9mkH/r4au81ZP1yOIFayLC3QAvqTgGtJ8YEDMXtPmaVBs6NgipHO6h4Mug==", + "peerDependencies": { + "react": ">=16.8.1", + "react-dom": ">=16.8.1" + } + }, "node_modules/react-i18next": { "version": "14.0.5", "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.0.5.tgz", @@ -13746,6 +14390,40 @@ "react-dom": ">=16.6.0" } }, + "node_modules/react-universal-interface": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz", + "integrity": "sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==", + "peerDependencies": { + "react": "*", + "tslib": "*" + } + }, + "node_modules/react-use": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/react-use/-/react-use-17.5.1.tgz", + "integrity": "sha512-LG/uPEVRflLWMwi3j/sZqR00nF6JGqTTDblkXK2nzXsIvij06hXl1V/MZIlwj1OKIQUtlh1l9jK8gLsRyCQxMg==", + "dependencies": { + "@types/js-cookie": "^2.2.6", + "@xobotyi/scrollbar-width": "^1.9.5", + "copy-to-clipboard": "^3.3.1", + "fast-deep-equal": "^3.1.3", + "fast-shallow-equal": "^1.0.0", + "js-cookie": "^2.2.1", + "nano-css": "^5.6.2", + "react-universal-interface": "^0.6.2", + "resize-observer-polyfill": "^1.5.1", + "screenfull": "^5.1.0", + "set-harmonic-interval": "^1.0.1", + "throttle-debounce": "^3.0.1", + "ts-easing": "^0.2.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, "node_modules/react-virtualized-auto-sizer": { "version": "1.0.24", "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.24.tgz", @@ -14305,6 +14983,19 @@ "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==" + }, + "node_modules/rtl-css-js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", + "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -14494,6 +15185,17 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/screenfull": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz", + "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==", + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -14544,6 +15246,14 @@ "node": ">= 0.4" } }, + "node_modules/set-harmonic-interval": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz", + "integrity": "sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==", + "engines": { + "node": ">=6.9" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -14727,6 +15437,14 @@ "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", "dev": true }, + "node_modules/stack-generator": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz", + "integrity": "sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==", + "dependencies": { + "stackframe": "^1.3.4" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -14746,6 +15464,38 @@ "node": ">=8" } }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" + }, + "node_modules/stacktrace-gps": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz", + "integrity": "sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==", + "dependencies": { + "source-map": "0.5.6", + "stackframe": "^1.3.4" + } + }, + "node_modules/stacktrace-gps/node_modules/source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stacktrace-js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz", + "integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==", + "dependencies": { + "error-stack-parser": "^2.0.6", + "stack-generator": "^2.0.5", + "stacktrace-gps": "^3.0.4" + } + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -14949,6 +15699,11 @@ "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", "dev": true }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==" + }, "node_modules/style-search": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", @@ -15130,6 +15885,11 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -15412,6 +16172,14 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/throttle-debounce": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-3.0.1.tgz", + "integrity": "sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==", + "engines": { + "node": ">=10" + } + }, "node_modules/tiny-invariant": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", @@ -15490,6 +16258,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-easing": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ts-easing/-/ts-easing-0.2.0.tgz", + "integrity": "sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==" + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -16090,6 +16863,11 @@ "node": ">=0.10.0" } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" + }, "node_modules/warning": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", diff --git a/package.json b/package.json index 5a884b42d991..0b9843c96920 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,12 @@ "private": true, "homepage": "https://gravity-ui.com/", "dependencies": { - "@diplodoc/transform": "^4.26.0", + "@diplodoc/transform": "^4.18.0", "@gravity-ui/chartkit": "^5.10.1", "@gravity-ui/components": "^3.10.1", "@gravity-ui/date-components": "^2.10.1", "@gravity-ui/icons": "^2.11.0", + "@gravity-ui/markdown-editor": "^13.18.0", "@gravity-ui/navigation": "^2.23.1", "@gravity-ui/page-constructor": "^5.2.0", "@gravity-ui/uikit": "^6.27.2", diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 6ac5a5515d25..9e6939bb5c62 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -4,9 +4,11 @@ "actions_share": "Share", "actions_github": "GitHub", "actions_storybook": "Storybook", + "actions_playground": "Playground", "menu_libraries": "Libraries", "menu_components": "Components", "menu_design": "Design", + "menu_editor": "Editor", "menu_icons": "Icons", "menu_themer": "Themer", "roadmap_inProgress": "In progress", diff --git a/public/locales/en/home.json b/public/locales/en/home.json index 8eab1ee69e6b..b181596cefa0 100644 --- a/public/locales/en/home.json +++ b/public/locales/en/home.json @@ -2,6 +2,8 @@ "header_title": "Build modern interfaces with the Gravity design system and libraries", "header_actions_howToStart": "How to Start", "news_title": "Recent updates", + "banner_title": "Introducing MarkdownEditor", + "banner_content": "Markdown-editor combines two modes.
It allows you to create and edit content in a convenient visual form while retaining full control over the underlying markup.

Test it on the playground ✨.", "news_items_item1": "We're thrilled to unveil Themer. Now you can easily customize our design system to your brand style and export your theme as a CSS file.", "news_items_item2": "500⭐️ for our UIKit! We just wanted to say thanks for all the support and feedback we've been getting. There's more to come, so stay tuned!", "news_items_item3": "We've released the PinInput component. You may need it to enter OTP or confirmation codes.", diff --git a/public/locales/en/markdown-editor.json b/public/locales/en/markdown-editor.json new file mode 100644 index 000000000000..1c81638c4734 --- /dev/null +++ b/public/locales/en/markdown-editor.json @@ -0,0 +1,4 @@ +{ + "goToLibrary": "Go to library", + "title": "Editor" +} diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index 2bcff4b68778..182bb76dd8b8 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -4,9 +4,11 @@ "actions_share": "Поделиться", "actions_github": "GitHub", "actions_storybook": "Storybook", + "actions_playground": "Playground", "menu_libraries": "Библиотеки", "menu_components": "Компоненты", "menu_design": "Дизайн", + "menu_editor": "Редактор", "menu_icons": "Иконки", "menu_themer": "Темизатор", "roadmap_inProgress": "В работе", diff --git a/public/locales/ru/home.json b/public/locales/ru/home.json index aa05cd7071b7..1dbfd2002769 100644 --- a/public/locales/ru/home.json +++ b/public/locales/ru/home.json @@ -2,6 +2,8 @@ "header_title": "Создавайте современные интерфейсы с дизайн‑системой Gravity", "header_actions_howToStart": "С чего начать", "news_title": "Новости", + "banner_title": "Представляем MarkdownEditor", + "banner_content": "Markdown-редактор объединяет два режима. Это даёт возможность создавать и редактировать контент в удобной визуальной форме, не теряя контроля над исходной разметкой.

Попробуйте в playground ✨.", "news_items_item1": "Мы запустили новый раздел Themer. В нём вы можете легко адаптировать нашу дизайн-систему к своему бренду и экспортировать результат в CSS файл.", "news_items_item2": "500⭐️ у UIKit! Просто хотим поблагодарить вас за поддержку и идеи. Впереди много нового, продолжайте следить за проектом!", "news_items_item3": "Мы выложили компонент PinInput. Он может пригодиться для ввода OTP кодов или подтверждений.", diff --git a/public/locales/ru/markdown-editor.json b/public/locales/ru/markdown-editor.json new file mode 100644 index 000000000000..87aab8bd04fd --- /dev/null +++ b/public/locales/ru/markdown-editor.json @@ -0,0 +1,4 @@ +{ + "goToLibrary": "К библиотеке", + "title": "Редактор" +} diff --git a/public/static/images/markdown-editor/banner.png b/public/static/images/markdown-editor/banner.png new file mode 100644 index 000000000000..ee3ec700f069 Binary files /dev/null and b/public/static/images/markdown-editor/banner.png differ diff --git a/public/static/images/markdown-editor/context-menu.png b/public/static/images/markdown-editor/context-menu.png new file mode 100644 index 000000000000..f540f621c871 Binary files /dev/null and b/public/static/images/markdown-editor/context-menu.png differ diff --git a/public/static/images/markdown-editor/main.png b/public/static/images/markdown-editor/main.png new file mode 100644 index 000000000000..f73dddbf7bf4 Binary files /dev/null and b/public/static/images/markdown-editor/main.png differ diff --git a/src/[locale]/libraries/[libId]/playground/index.tsx b/src/[locale]/libraries/[libId]/playground/index.tsx new file mode 100644 index 000000000000..5c58ce206af8 --- /dev/null +++ b/src/[locale]/libraries/[libId]/playground/index.tsx @@ -0,0 +1,64 @@ +import {GetStaticPaths, GetStaticPathsResult, GetStaticProps} from 'next'; +import {useTranslation} from 'next-i18next'; +import React from 'react'; +import {useLocaleRedirect} from 'src/hooks/useLocaleRedirect'; + +import {Layout} from '../../../../components/Layout/Layout'; +import {MarkdownEditor} from '../../../../components/MarkdownEditor/MarkdownEditor'; +import {getI18nPaths, getI18nProps, getLibsList} from '../../../../utils'; + +const libs = getLibsList(); + +export const getStaticPaths: GetStaticPaths = async () => { + const paths = getI18nPaths().reduce((acc, localeItem) => { + acc.push( + ...libs.map((libItem) => ({ + params: {locale: localeItem.params.locale, libId: libItem.config.id}, + })), + ); + return acc; + }, []); + + return { + paths, + fallback: false, + }; +}; + +export const getStaticProps: GetStaticProps = async (context) => { + const libId = Array.isArray(context.params?.libId) + ? context.params?.libId[0] + : context.params?.libId; + + return { + props: { + libId: libId || null, + ...(await getI18nProps(context, ['library', 'libraries-info', libId ?? ''])), + }, + }; +}; + +// TODO: open with article +// export const availablePlaygrounds = ['markdown-editor']; +export const availablePlaygrounds = [] as string[]; + +export const PlaygroundPage = ({libId}: {libId: string}) => { + const hasPlayground = availablePlaygrounds.includes(libId); + + useLocaleRedirect(); + const {t} = useTranslation(); + + return ( + <> + {hasPlayground && ( + <> + + {libId === 'markdown-editor' && } + + + )} + + ); +}; + +export default PlaygroundPage; diff --git a/src/blocks/CustomHeader/CustomHeader.scss b/src/blocks/CustomHeader/CustomHeader.scss index 85da45e1e62e..367ddd7d23e7 100644 --- a/src/blocks/CustomHeader/CustomHeader.scss +++ b/src/blocks/CustomHeader/CustomHeader.scss @@ -46,6 +46,43 @@ $block: '.#{variables.$ns}custom-header'; } } + &__banner { + overflow: hidden; + border-radius: 24px; + background-color: rgba(37, 27, 37, 0.5); + backdrop-filter: blur(60px); + + @media (max-width: map-get(pcVariables.$gridBreakpoints, 'lg') - 1) { + margin-top: 32px; + } + } + &__banner-image { + width: 100%; + } + &__banner-text { + padding: 12px 32px 32px; + } + &__banner-title { + @include pcStyles.heading4(); + margin-bottom: 16px; + } + &__banner-content { + @include pcStyles.text-size(body-2); + + a { + color: #ffbe5c; + text-decoration: none; + + &:visited { + color: #ffbe5c; + } + + &:hover { + color: #f3cb8f; + } + } + } + &__news-title { @include pcStyles.heading4(); diff --git a/src/blocks/CustomHeader/CustomHeader.tsx b/src/blocks/CustomHeader/CustomHeader.tsx index 258d7a13f9fb..07d9bcc36ac2 100644 --- a/src/blocks/CustomHeader/CustomHeader.tsx +++ b/src/blocks/CustomHeader/CustomHeader.tsx @@ -18,6 +18,7 @@ type CustomButton = ButtonProps & { }; type NewsItem = { + title?: string; date: string; content: string; }; @@ -29,27 +30,61 @@ export type CustomHeaderProps = Animatable & { title?: string; items: NewsItem[]; }; + banner?: BannerBlockProps; }; export type CustomHeaderModel = CustomHeaderProps & { type: CustomBlock.CustomHeader; }; +interface BannerImage { + href: string; + src: string; + alt: string; + title: string; +} +interface BannerBlockProps { + image: BannerImage; + title?: string; + content?: string; +} + +const Banner: React.FC = ({image, title, content}) => { + const img = ( + {image.alt} + ); + + return ( +
+ {image.href ? {img} : img} +
+ {title &&
{title}
} + {content && ( +
+ {content} +
+ )} +
+
+ ); +}; + export const CustomHeader: React.FC = ({ animated, title, buttons = [], news, + banner, }) => { const {i18n} = useTranslation(); - const showNewsBlock = news && news.items && news.items.length > 0; + const showNewsBlock = !banner && news && news.items && news.items.length > 0; return ( - +

{title}

@@ -78,7 +113,7 @@ export const CustomHeader: React.FC = ({ ) : null} - {showNewsBlock ? ( + {showNewsBlock && (
{news.title ? ( @@ -102,7 +137,12 @@ export const CustomHeader: React.FC = ({ )}
- ) : null} + )} + {banner && ( + + + + )}
diff --git a/src/components/Library/Library.tsx b/src/components/Library/Library.tsx index f62402324c3d..73e8836b5506 100644 --- a/src/components/Library/Library.tsx +++ b/src/components/Library/Library.tsx @@ -4,6 +4,7 @@ import {useTranslation} from 'next-i18next'; import React from 'react'; // import issuesIcon from '../../assets/icons/issues.svg'; +import {availablePlaygrounds} from '../../[locale]/libraries/[libId]/playground'; import arrowIcon from '../../assets/icons/arrow.svg'; import githubIcon from '../../assets/icons/github.svg'; import lastUpdateIcon from '../../assets/icons/last-update.svg'; @@ -166,6 +167,17 @@ export const Library: React.FC = ({lib}) => { {t('actions_storybook')} ) : null} + {availablePlaygrounds.includes(lib.config.id) ? ( + + ) : null} ) : null} diff --git a/src/components/MarkdownEditor/MarkdownEditor.scss b/src/components/MarkdownEditor/MarkdownEditor.scss new file mode 100644 index 000000000000..fc85b166d8bf --- /dev/null +++ b/src/components/MarkdownEditor/MarkdownEditor.scss @@ -0,0 +1,72 @@ +@use '~@gravity-ui/page-constructor/styles/variables.scss' as pcVariables; +@use '~@gravity-ui/uikit/styles/mixins' as ukitMixins; +@use '../../variables.scss'; + +$block: '.#{variables.$ns}markdown-editor'; + +#{$block} { + margin-block-start: calc(var(--g-spacing-base) * 8); + + &__heading { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: pcVariables.$indentXS; + + @media (max-width: map-get(pcVariables.$gridBreakpoints, 'md') - 1) { + margin-bottom: pcVariables.$indentXXXS; + } + } + + &__title { + font-size: 48px; + line-height: 56px; + font-weight: 600; + color: #fff; + margin: 0; + + @media (max-width: map-get(pcVariables.$gridBreakpoints, 'md') - 1) { + font-size: 32px; + line-height: 48px; + margin-bottom: pcVariables.$indentXXXS; + } + } + + &__content { + width: 100%; + min-height: 300px; + } +} + +.g-md-editor-component__editor-wrapper { + border-radius: 10px; + border: 1px solid rgba(255, 255, 255, 0.2); + padding: 15px 20px 20px; + margin-bottom: 20px; +} + +.yfm-editor { + color: var(--g-color-text-primary); +} + +// FIXME: This is a temporary solution, will be fixed after +// https://github.com/gravity-ui/markdown-editor/pull/369 */ + +:root { + --g-md-sticky-offset-compensate: 100px; +} + +.gravity-ui-landing-markdown-editor_sticky .g-md-editor-component__toolbar { + z-index: 2000; + position: sticky; + top: 8px; +} + +.gravity-ui-landing-markdown-editor_sticky .g-md-editor-component__toolbar::before { + position: absolute; + inset: -4px; + content: ''; + border: 1px solid var(--g-color-line-generic-solid); + border-radius: 4px; + background-color: var(--g-color-base-background); +} diff --git a/src/components/MarkdownEditor/MarkdownEditor.tsx b/src/components/MarkdownEditor/MarkdownEditor.tsx new file mode 100644 index 000000000000..076acb76cee7 --- /dev/null +++ b/src/components/MarkdownEditor/MarkdownEditor.tsx @@ -0,0 +1,90 @@ +import { + MarkdownEditorView, + markupToolbarConfigs, + useMarkdownEditor, + wToolbarConfig, +} from '@gravity-ui/markdown-editor'; +import {Col, Grid, Row} from '@gravity-ui/page-constructor'; +import {Button, ThemeProvider} from '@gravity-ui/uikit'; +import {toaster} from '@gravity-ui/uikit/toaster-singleton-react-18'; +import {useTranslation} from 'next-i18next'; +import React, {useEffect, useRef} from 'react'; + +import {main} from '../../content/markdown-editor/main'; +import {EnvironmentContext} from '../../contexts'; +import {block, getLocaleLink} from '../../utils'; + +import './MarkdownEditor.scss'; +import {useSticky} from './hooks'; +import './yfm.scss'; + +const b = block('markdown-editor'); + +function Editor() { + const editor = useMarkdownEditor({ + initialEditorMode: 'wysiwyg', + initialToolbarVisible: true, + allowHTML: false, + linkify: true, + breaks: true, + initialMarkup: main, + }); + + // FIXME: This is a temporary solution, will be fixed after + // https://github.com/gravity-ui/markdown-editor/pull/369 */ + const toolbarRef = useRef(null); + useEffect(() => { + const element = document.querySelector('.g-md-editor-component__toolbar'); + if (element) { + toolbarRef.current = element; + } + }, []); + const sticky = useSticky(toolbarRef); + + return ( + + ); +} + +export const MarkdownEditor = () => { + const {t, i18n} = useTranslation('markdown-editor'); + const {isClient} = React.useContext(EnvironmentContext); + + return ( + + + +

{t('title')}

+
+ +
+ +
+ + + {isClient && ( + + + + )} + + +
+ ); +}; diff --git a/src/components/MarkdownEditor/hooks/index.ts b/src/components/MarkdownEditor/hooks/index.ts new file mode 100644 index 000000000000..3cbbecc17498 --- /dev/null +++ b/src/components/MarkdownEditor/hooks/index.ts @@ -0,0 +1,138 @@ +import throttle from 'lodash/throttle'; +import {RefObject, useEffect, useState} from 'react'; + +/** + * Finds the closest parent element with overflow: auto or overflow: scroll. + * + * This function traverses up the DOM tree starting from the given element, + * checking each parent element for overflow: auto or overflow: scroll styles. + * If such an element is found, it is returned as the scroll container. + * If no matching element is found, the global window object is returned. + * + * @param {HTMLElement | null} element - The starting element from which to begin the search. + * @returns {HTMLElement | Window} - The first parent with overflow: auto/scroll, or window. + */ +const findScrollContainer = (element: HTMLElement | null): HTMLElement | Window => { + let currentElement = element; + while (currentElement) { + const overflow = window.getComputedStyle(currentElement).overflow; + if (overflow === 'auto' || overflow === 'scroll') { + return currentElement; + } + currentElement = currentElement.parentElement; + } + return window; +}; + +/** + * Finds the value of a CSS variable starting from the specified element. + * If not found locally, it will fallback to the global :root. + * + * @param {HTMLElement | null} element - The starting element to search for the CSS variable. + * @param {string} variableName - The name of the CSS variable to search for. + * @returns {number} - The value of the CSS variable or 0 if not found. + */ +const findCssVariableValue = (element: HTMLElement | null, variableName: string): number => { + let currentElement = element; + while (currentElement) { + const value = getComputedStyle(currentElement).getPropertyValue(variableName); + if (value) { + return parseFloat(value); + } + currentElement = currentElement.parentElement; + } + // Fallback to global :root if not found locally + return ( + parseFloat(getComputedStyle(document.documentElement).getPropertyValue(variableName)) || 0 + ); +}; + +interface UseStickyOptions { + /** + * Throttle delay in milliseconds for the scroll event handler. + * This controls how frequently the scroll event is processed. + * Lower values make the scroll handler more responsive but can increase CPU usage. + * + * Default is 100ms. + */ + throttleDelay?: number; + + /** + * An optional name of a CSS variable that defines an offset value for the sticky element. + * The variable is needed to set an offset if there are other sticky or + * fixed elements on the page. + * + * Default is '--g-md-sticky-offset-compensate'. + */ + offsetCssVariable?: string; + + /** + * An optional element reference to scope the search for the CSS variable. + * If not provided, the search defaults to the global :root. + */ + cssVariableScope?: HTMLElement | null; +} + +/** + * useSticky hook + * + * This hook determines whether an element should be in a sticky state based on its position + * relative to the scroll container and a custom offset. + * The offset is calculated based on the CSS variable `--g-md-toolbar-sticky-offset`. + * + * @param {RefObject} elemRef - A reference to the DOM element for which sticky state is being managed. + * @param {UseStickyOptions} options - Options for configuring the hook's behavior. + * @returns {boolean} - A boolean indicating whether the element is currently sticky. + */ +export function useSticky( + elemRef: RefObject, + { + throttleDelay = 100, + offsetCssVariable = '--g-md-sticky-offset-compensate', + cssVariableScope = null, + }: UseStickyOptions = {}, +) { + const [sticky, setSticky] = useState(false); + const [initialOffset, setInitialOffset] = useState(null); + + useEffect(() => { + const scrollContainer = findScrollContainer(elemRef.current); + + if (elemRef.current) { + if (initialOffset === null) { + // Determine the scope element for the CSS variable search + const scopeElement = cssVariableScope || document.documentElement; + const stickyOffsetCompensate = findCssVariableValue( + scopeElement, + offsetCssVariable, + ); + + setInitialOffset( + elemRef.current.getBoundingClientRect().top - stickyOffsetCompensate, + ); + } + } + + // Throttled scroll handler + const handleScroll = throttle(() => { + if (initialOffset !== null) { + const scrollY = + scrollContainer === window + ? window.scrollY + : (scrollContainer as HTMLElement).scrollTop; + const newSticky = (initialOffset ?? 0) <= scrollY; + + setSticky(newSticky); + } + }, throttleDelay); + + scrollContainer.addEventListener('scroll', handleScroll); + + return () => { + scrollContainer.removeEventListener('scroll', handleScroll); + handleScroll.cancel(); // Cancel the throttled function + }; + }, [elemRef, initialOffset, offsetCssVariable, throttleDelay, cssVariableScope]); + + return sticky; +} diff --git a/src/components/MarkdownEditor/lib/constants.ts b/src/components/MarkdownEditor/lib/constants.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/components/MarkdownEditor/lib/types.ts b/src/components/MarkdownEditor/lib/types.ts new file mode 100644 index 000000000000..6a0dfa123d56 --- /dev/null +++ b/src/components/MarkdownEditor/lib/types.ts @@ -0,0 +1 @@ +export type ThemeVariant = 'light' | 'dark'; diff --git a/src/components/MarkdownEditor/sections/index.ts b/src/components/MarkdownEditor/sections/index.ts new file mode 100644 index 000000000000..d8d01d60d040 --- /dev/null +++ b/src/components/MarkdownEditor/sections/index.ts @@ -0,0 +1,50 @@ +import guideBasicsContent from '../../../content/design/guides/content/Basics.mdx'; +import guideResourcesContent from '../../../content/design/guides/content/Resources.mdx'; +import guideTypographyContent from '../../../content/design/guides/content/Typography.mdx'; +import {Section} from '../../../content/design/types'; + +export const settings: Section = { + id: 'settings', + title: 'Editor settings', + description: 'Configure your editor', + articles: [ + { + id: 'modes', + title: 'Modes', + description: '', + content: guideResourcesContent, + }, + { + id: 'split', + title: 'Split mode', + description: '', + content: guideBasicsContent, + }, + { + id: 'light-theme', + title: 'Theme', + description: '', + content: guideTypographyContent, + }, + ], +}; + +export const presets: Section = { + id: 'presets', + title: 'Presets', + description: 'Set presets', + articles: [ + { + id: 'markdown', + title: 'Markdown', + description: '', + content: guideResourcesContent, + }, + { + id: 'yfm', + title: 'Yfm', + description: '', + content: guideBasicsContent, + }, + ], +}; diff --git a/src/components/MarkdownEditor/yfm.scss b/src/components/MarkdownEditor/yfm.scss new file mode 100644 index 000000000000..3f1873db7325 --- /dev/null +++ b/src/components/MarkdownEditor/yfm.scss @@ -0,0 +1,126 @@ +// переопределение стилей из '@doc-tools/transform/dist/css/yfm.css' + +.g-root .yfm { + --yfm-font-family-sans: var(--g-font-family-sans); + --yfm-font-family-monospace: var(--g-font-family-monospace); +} + +.g-root .yfm:not(.yfm_only-light) { + color: var(--g-color-text-primary); + + --yfm-color-hljs-background: var(--g-color-base-background); + --yfm-color-hljs-subst: var(--g-color-text-complementary); + --yfm-color-hljs-comment: var(--g-color-text-secondary); + --yfm-color-hljs-deletion: var(--g-color-text-danger); + --yfm-color-hljs-section: var(--g-color-text-danger); + + --yfm-file-icon-color: var(--g-color-text-primary); + --mermaid-zoom-control-color: var(--g-color-text-primary); + + a { + color: var(--g-color-text-link); + + &:hover, + &:active { + color: var(--g-color-text-link-hover); + } + } + + &.yfm_links-visited { + a { + &:visited { + color: var(--g-color-text-link-visited); + } + + &:visited:hover { + color: var(--g-color-text-link-visited-hover); + } + } + } + + img { + background-color: var(--g-color-base-background); + } + + $backgroundColors: ( + yfm-accent-info: var(--g-color-base-info-light), + yfm-accent-tip: var(--g-color-base-positive-light), + yfm-accent-alert: var(--g-color-base-danger-light), + yfm-accent-warning: var(--g-color-base-warning-light), + ); + + @each $type, $color in $backgroundColors { + &.#{$type} { + background: $color; + } + } + + code { + background: var(--g-color-base-misc-light); + color: var(--g-color-text-misc-heavy); + } + + pre > code { + background: var(--g-color-base-misc-light); + color: var(--g-color-text-complementary); + } + + table { + color: var(--g-color-text-primary); + border-color: var(--g-color-line-generic); + background: var(--g-color-base-background); + + thead, + tr:nth-child(2n) { + background: var(--g-color-base-generic); + } + + td, + td:first-child, + th { + border-color: var(--g-color-line-generic-solid); + } + } + + hr { + background-color: var(--g-color-line-generic); + } + + blockquote { + border-left-color: var(--g-color-line-info); + } + + .yfm-tab-list { + border-bottom-color: var(--g-color-line-generic); + } + + .yfm-tab:hover, + .yfm-tab:active { + color: var(--g-color-text-link-hover); + } + + .yfm-tab.active { + border-bottom-color: var(--g-color-line-brand); + } +} + +.g-root_theme_dark .yfm, +.g-root_theme_dark-hc .yfm { + .yfm-cut-title:before { + background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+PHBhdGggc3Ryb2tlPSJyZ2JhKDI1NSwgMjU1LCAyNTUsIDAuNykiIGZpbGw9Im5vbmUiIGQ9Ik0zIDZsNSA1IDUtNSI+PC9wYXRoPjwvc3ZnPg=='); + } +} + +.g-root .yfm:not(.yfm_only-light) blockquote { + border-left-color: #ffbe5c; +} + +.yfm blockquote { + position: relative; + padding-left: 12px; + border-left: 3px solid #ffbe5c; +} + +.ProseMirror .yfm-tab[data-diplodoc-is-active='true'] .g-md-yfm-tab__wrapper { + border-bottom-color: #ffbe5c; +} diff --git a/src/content/landing.ts b/src/content/landing.ts index 4e5cfc8580f0..150a1c4704db 100644 --- a/src/content/landing.ts +++ b/src/content/landing.ts @@ -81,6 +81,17 @@ export const getLanding = (t: TFunction): CustomPageContent => ({ }, ], }, + // TODO: open with article + // banner: { + // image: { + // src: './static/images/markdown-editor/banner.png', + // href: '/libraries/markdown-editor/playground', + // alt: 'markdown-editor', + // title: 'markdown-editor', + // }, + // title: t('home:banner_title'), + // content: t('home:banner_content'), + // }, }, { type: CustomBlock.CustomExtendedFeatures, diff --git a/src/content/markdown-editor/main.ts b/src/content/markdown-editor/main.ts new file mode 100644 index 000000000000..3c10c5340733 --- /dev/null +++ b/src/content/markdown-editor/main.ts @@ -0,0 +1,126 @@ +/* eslint-disable */ +export const main = ` + \n  +Welcome to the editor! Start typing the character \`/\` + +![](/static/images/markdown-editor/main.png =800x) + +## Markdown WYSIWYG and markup editor + +MarkdownEditor is a powerful tool for working with Markdown, which combines WYSIWYG and Markup modes. This means that you can create and edit content in a convenient visual mode, as well as have full control over the markup. +  +The editor supports following formats: + +* WYSIWYG + +* markup + +Click on the gear in the upper right corner to change the mode and see the \`md\` markup. + +  +### Various blocks included + +{% cut "Combine different blocks" %} + +{% note info "Block for notes, tips, warnings, and alerts" %} + +Depending on the content, notes with different titles and formats are used: + +* Note: provides additional information. +* Tip: offers a recommendation. +* Warning: issues a warning. +* Alert: indicates a restriction. + +{% endnote %} + +> [Improve](https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-add-preview.md) the editor interface +> +> *improved by you* + +{% endcut %} + +Or write your extension using a [convenient api](https://github.com/gravity-ui/markdown-editor/blob/main/docs/how-to-create-extension.md) + +  +### A user-friendly API is provided + +Easily connect to your React app with a hook: + +\`\`\` +import React from 'react'; +import { useMarkdownEditor, MarkdownEditorView } from '@gravity-ui/markdown-editor'; +import { toaster } from '@gravity-ui/uikit/toaster-singleton-react-18'; + +function Editor({ onSubmit }) { + const editor = useMarkdownEditor({ allowHTML: false }); + + React.useEffect(() => { + function submitHandler() { + // Serialize current content to markdown markup + const value = editor.getValue(); + onSubmit(value); + } + + editor.on('submit', submitHandler); + return () => { + editor.off('submit', submitHandler); + }; + }, [onSubmit]); + + return ; +} +\`\`\` + +  +### Convenient UX control is equipped + +#### Hot keys +{% list tabs %} + +- WYSIWYG mode + + + + |Formatting|Windows Shortcut|Mac OS Shortcut| + |:---|:---|:---| + |Bold text|Ctrl \\+ B|⌘ \\+ B| + |Italic|Ctrl \\+ I|⌘ \\+ I| + |Underlined text|Ctrl \\+ U|⌘ \\+ U| + |Strikethrough text|Ctrl \\+ Shift \\+ S|⌘ \\+ Shift \\+ S| + +- Markup mode + + + |Formatting|Markup|Result| + |:---|:---|:---| + |Bold text|\`**Bold**\`|**Bold**| + |Italic|\`*Italic*\`|*Italic*| + |Underlined text|\`++Underlined++\`|++Underlined++| + |Strikethrough text|\`~~Strikethrough~~\`|~~Strikethrough~~| + +{% endlist %} +#### Context menu +Select this text and you will see a context menu **##like this##**: + +![](/static/images/markdown-editor/context-menu.png =360x) + +#### Auto-conversion +Quickly create blocks by entering characters that will be replaced by blocks. For example, the automatic conversion of \`-\` and space creates a list, \`>\` and space creates a quote. Try it out. + +--- + +### Current and future features + +[X] Some already finished things + +[ ] VS Code plugin + +[ ] Mobile version + +### And a multitude of other functionalities :sweat_smile: :fire: + +See + +  +`; +/* eslint-enable */ diff --git a/src/content/menu.ts b/src/content/menu.ts index 2f911aabe0eb..37acdd048056 100644 --- a/src/content/menu.ts +++ b/src/content/menu.ts @@ -26,6 +26,5 @@ export const menu: MenuItem[] = [ { titleKey: 'menu_themer', url: '/themer', - isNew: true, }, ]; diff --git a/src/pages/libraries/[libId]/playground/index.tsx b/src/pages/libraries/[libId]/playground/index.tsx new file mode 100644 index 000000000000..856e4c4aecd9 --- /dev/null +++ b/src/pages/libraries/[libId]/playground/index.tsx @@ -0,0 +1,23 @@ +import {GetStaticPaths} from 'next'; +import { + PlaygroundPage, + availablePlaygrounds, + getStaticProps, +} from 'src/[locale]/libraries/[libId]/playground'; + +import {getLibsList} from '../../../../utils'; + +const libs = getLibsList(); + +export const getStaticPaths: GetStaticPaths = async () => { + return { + paths: libs + .filter((lib) => availablePlaygrounds.includes(lib.config.id)) + .map((item) => ({params: {libId: item.config.id}})), + fallback: false, + }; +}; + +export {PlaygroundPage, getStaticProps}; + +export default PlaygroundPage;