diff --git a/README.md b/README.md index 7113dcdc..5bb7e49d 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ At least **Redmine version `3.0` or higher** required. Recommended version `5.0` | Feature | Unsupported Redmine version | | --------------------------------------------------------------------------------- | --------------------------- | +| Auto-detect text formatting (CommonMark, Textile) from Redmine instance | `< 6.0.0` | | Show only **enabled** issue field for selected tracker when _creating new issues_ | `< 5.0.0` | | Show only **allowed statuses** when _updating issue_ | `< 5.0.0` | | Show spent vs estimated hours | `< 5.0.0` | diff --git a/package.json b/package.json index 36e279f3..31bc5096 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@tanstack/react-query-devtools": "^5.99.0", "@tanstack/react-query-persist-client": "^5.99.0", "@tanstack/react-router": "^1.168.22", + "@uiw/react-md-editor": "^4.1.0", "axios": "^1.15.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5e62881..7b09757e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: '@tanstack/react-router': specifier: ^1.168.22 version: 1.168.22(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@uiw/react-md-editor': + specifier: ^4.1.0 + version: 4.1.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) axios: specifier: ^1.15.0 version: 1.15.0 @@ -1649,6 +1652,12 @@ packages: '@types/chrome@0.1.40': resolution: {integrity: sha512-UnfyRAe8ORu9HSuTH0EqyOEUin3JrWW9Nl/gDXezNfTUrfIoxw+WRZgKOxGz0t5BnjbfXBnS2eCYfW2PxH1wcA==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -1661,18 +1670,30 @@ packages: '@types/har-format@1.2.16': resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==} + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + '@types/minimatch@3.0.5': resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@24.12.2': resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/prismjs@1.26.6': + resolution: {integrity: sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==} + '@types/qs@6.15.0': resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==} @@ -1690,6 +1711,12 @@ packages: '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/validate-npm-package-name@4.0.2': resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==} @@ -1752,6 +1779,24 @@ packages: resolution: {integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@uiw/copy-to-clipboard@1.0.20': + resolution: {integrity: sha512-IFQhS62CLNon1YgYJTEzXR2N3WVXg7V1FaBRDLMlzU6JY5X6Hr3OPAcw4WNoKcz2XcFD6XCgwEjlsmj+JA0mWA==} + + '@uiw/react-markdown-preview@5.2.0': + resolution: {integrity: sha512-39kgf+Wk6DXpYtztUt34xFPt0BzGkuxmFZKI7rNAlCFKXdAmyhqLlRbQKyrRwOVeuRyrQy/Z96UBSw5AHFBivg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@uiw/react-md-editor@4.1.0': + resolution: {integrity: sha512-ti8WO9Mf55bFdb5JXEJmQ77NQRG8VyUAuE6c5XRwMI3S05Q0uuiRKOs5yAyJWiISgkV39DMmf4UU8DbADPILhw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@vitejs/plugin-react@6.0.1': resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1948,6 +1993,9 @@ packages: babel-plugin-react-compiler@1.0.0: resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==} + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1960,6 +2008,9 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + bcp-47-match@2.0.3: + resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} + before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} @@ -2056,6 +2107,9 @@ packages: caniuse-lite@1.0.30001788: resolution: {integrity: sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -2072,6 +2126,18 @@ packages: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -2170,6 +2236,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -2304,6 +2373,9 @@ packages: css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + css-selector-parser@3.3.0: + resolution: {integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==} + css-tree@3.2.1: resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} @@ -2366,6 +2438,9 @@ packages: supports-color: optional: true + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + dedent@1.7.2: resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} peerDependencies: @@ -2431,6 +2506,9 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + diff@8.0.4: resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} engines: {node: '>=0.3.1'} @@ -2439,6 +2517,10 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + direction@2.0.1: + resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} + hasBin: true + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -2517,6 +2599,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} @@ -2673,6 +2759,9 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -2720,6 +2809,9 @@ packages: exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} @@ -2966,6 +3058,9 @@ packages: git-log-parser@1.2.1: resolution: {integrity: sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==} + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -3072,6 +3167,48 @@ packages: resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} engines: {node: '>= 0.4'} + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-has-property@3.0.0: + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + + hast-util-heading-rank@3.0.0: + resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-select@6.0.4: + resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + + hast-util-to-string@3.0.1: + resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + headers-polyfill@5.0.1: resolution: {integrity: sha512-1TJ6Fih/b8h5TIcv+1+Hw0PDQWJTKDKzFZzcKOiW1wJza3XoAQlkCuXLbymPYB8+ZQyw8mHvdw560e8zVFIWyA==} @@ -3116,6 +3253,12 @@ packages: resolution: {integrity: sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==} engines: {node: '>=20.10'} + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} @@ -3199,6 +3342,9 @@ packages: resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -3222,6 +3368,12 @@ packages: resolution: {integrity: sha512-Xi9/ZSn4NFapG8RP98iNPMOeaV3mXPisxKxzKtHVqr3g56j/fBn+yZmnxSVAA8lmZbl2J9b/a4kJvfU3hqQYgA==} engines: {node: '>=0.10.0'} + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -3261,6 +3413,9 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -3295,6 +3450,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-in-ci@1.0.0: resolution: {integrity: sha512-eUuAjybVTHMYWm/U+vBO1sY/JOCgoPCXRxzdju0K+K0BiGW0SChEL1MLC0PoCIR1OlPo5YAp8HuQoUlsWEICwg==} engines: {node: '>=18'} @@ -3756,6 +3914,9 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -3792,6 +3953,9 @@ packages: resolution: {integrity: sha512-1DiZmDHPXMBgMRjeUtHy1q1VYmeJscHxhIAexX9z/zjRMP80+0ETuPfssi8z+kMY4DwUgsKuHqpjxgmeA9gBNA==} engines: {node: '>=18'} + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked-terminal@7.3.0: resolution: {integrity: sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==} engines: {node: '>=16.0.0'} @@ -3813,6 +3977,51 @@ packages: mathml-tag-names@4.0.0: resolution: {integrity: sha512-aa6AU2Pcx0VP/XWnh8IGL0SYSgQHDT6Ucror2j2mXeFAlN3ahaNs8EZtG1YiticMkSLj3Gt6VPFfZogt7G5iFQ==} + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} @@ -3839,6 +4048,90 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -4229,6 +4522,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse-json@4.0.0: resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} @@ -4249,6 +4545,9 @@ packages: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} + parse-numeric-range@1.3.0: + resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} + parse5-htmlparser2-tree-adapter@6.0.1: resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} @@ -4258,6 +4557,9 @@ packages: parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -4459,6 +4761,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} @@ -4535,6 +4840,12 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + react@19.2.5: resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} engines: {node: '>=0.10.0'} @@ -4578,6 +4889,9 @@ packages: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} + refractor@5.0.0: + resolution: {integrity: sha512-QXOrHQF5jOpjjLfiNk5GFnWhRXvxjUVnlFxkeDmewR5sXkr3iM46Zo+CnRR8B+MDVqkULW4EcLVcRBNOPXHosw==} + regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} @@ -4590,6 +4904,55 @@ packages: resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} engines: {node: '>=12'} + rehype-attr@4.0.2: + resolution: {integrity: sha512-v4+gw7pvUVLbG/dUpLgBE6r3TWTBYJ7z+sfAH3zapmM5CKzk5+CopFQgr4gMR6OBSKl/qpI6HR7gv1Cbig0uow==} + engines: {node: '>=16'} + + rehype-autolink-headings@7.1.0: + resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==} + + rehype-ignore@2.0.3: + resolution: {integrity: sha512-IzhP6/u/6sm49sdktuYSmeIuObWB+5yC/5eqVws8BhuGA9kY25/byz6uCy/Ravj6lXUShEd2ofHM5MyAIj86Sg==} + engines: {node: '>=16'} + + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + + rehype-prism-plus@2.0.2: + resolution: {integrity: sha512-jTHb8ZtQHd2VWAAKeCINgv/8zNEF0+LesmwJak69GemoPVN9/8fGEARTvqOpKqmN57HwaM9z8UKBVNVJe8zggw==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + rehype-rewrite@4.0.4: + resolution: {integrity: sha512-L/FO96EOzSA6bzOam4DVu61/PB3AGKcSPXpa53yMIozoxH4qg1+bVZDF8zh1EsuxtSauAhzt5cCnvoplAaSLrw==} + engines: {node: '>=16.0.0'} + + rehype-slug@6.0.0: + resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==} + + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + rehype@13.0.2: + resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-github-blockquote-alert@1.3.1: + resolution: {integrity: sha512-OPNnimcKeozWN1w8KVQEuHOxgN3L4rah8geMOLhA5vN9wITqU4FWD+G26tkEsCGHiOVDbISx+Se5rGZ+D1p0Jg==} + engines: {node: '>=16'} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4844,6 +5207,9 @@ packages: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + spawn-error-forwarder@1.0.0: resolution: {integrity: sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==} @@ -4924,6 +5290,9 @@ packages: string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + stringify-object@5.0.0: resolution: {integrity: sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==} engines: {node: '>=14.16'} @@ -4977,6 +5346,12 @@ packages: stubborn-utils@1.0.2: resolution: {integrity: sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==} + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + stylelint-config-recommended@18.0.0: resolution: {integrity: sha512-mxgT2XY6YZ3HWWe3Di8umG6aBmWmHTblTgu/f10rqFXnyWxjKWwNdjSWkgkwCtxIKnqjSJzvFmPT5yabVIRxZg==} engines: {node: '>=20.19.0'} @@ -5124,6 +5499,12 @@ packages: resolution: {integrity: sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==} engines: {node: '>= 0.4'} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} @@ -5253,6 +5634,9 @@ packages: resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} engines: {node: '>=20'} + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + unimport@6.1.0: resolution: {integrity: sha512-ocgNKyiqj7Hw7oHt7A7D3za3fq28eShe1EloL6hsoQgn7CF51Y4CqFT9ISG3rEy0JpA8CCz/sY5h5OovOn62VQ==} engines: {node: '>=18.12.0'} @@ -5261,6 +5645,27 @@ packages: resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} engines: {node: '>=12'} + unist-util-filter@5.0.1: + resolution: {integrity: sha512-pHx7D4Zt6+TsfwylH9+lYhBhzyhEnCXs/lbq/Hstxno5z4gVdyc2WEW0asfjGKPyG4pEKrnBv5hdkO6+aRnQJw==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + universal-user-agent@7.0.3: resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} @@ -5333,6 +5738,15 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + vite-node@6.0.0: resolution: {integrity: sha512-oj4PVrT+pDh6GYf5wfUXkcZyekYS8kKPfLPXVl8qe324Ec6l4K2DUKNadRbZ3LQl0qGcDz+PyOo7ZAh00Y+JjQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5389,6 +5803,9 @@ packages: resolution: {integrity: sha512-rQicL7OwuqWdQWI33JkSXKcp7cuv1mJG8u3jRQwx/8aDsmhbTHs9ZRmNYOL+LX0wX8edIEQX8jj4bB60GoXtKA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} @@ -5570,6 +5987,9 @@ packages: zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: '@1natsu/wait-element@4.2.0': @@ -6865,6 +7285,14 @@ snapshots: '@types/filesystem': 0.0.36 '@types/har-format': 1.2.16 + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + '@types/estree@1.0.8': {} '@types/filesystem@0.0.36': @@ -6875,16 +7303,28 @@ snapshots: '@types/har-format@1.2.16': {} + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/json-schema@7.0.15': {} + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/minimatch@3.0.5': {} + '@types/ms@2.1.0': {} + '@types/node@24.12.2': dependencies: undici-types: 7.16.0 '@types/normalize-package-data@2.4.4': {} + '@types/prismjs@1.26.6': {} + '@types/qs@6.15.0': {} '@types/react-dom@19.2.3(@types/react@19.2.14)': @@ -6901,6 +7341,10 @@ snapshots: '@types/statuses@2.0.6': {} + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + '@types/validate-npm-package-name@4.0.2': {} '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3)': @@ -6994,6 +7438,43 @@ snapshots: '@typescript-eslint/types': 8.58.2 eslint-visitor-keys: 5.0.1 + '@uiw/copy-to-clipboard@1.0.20': {} + + '@uiw/react-markdown-preview@5.2.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + dependencies: + '@babel/runtime': 7.29.2 + '@uiw/copy-to-clipboard': 1.0.20 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-markdown: 10.1.0(@types/react@19.2.14)(react@19.2.5) + rehype-attr: 4.0.2 + rehype-autolink-headings: 7.1.0 + rehype-ignore: 2.0.3 + rehype-prism-plus: 2.0.2 + rehype-raw: 7.0.0 + rehype-rewrite: 4.0.4 + rehype-slug: 6.0.0 + remark-gfm: 4.0.1 + remark-github-blockquote-alert: 1.3.1 + unist-util-visit: 5.1.0 + transitivePeerDependencies: + - '@types/react' + - supports-color + + '@uiw/react-md-editor@4.1.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + dependencies: + '@babel/runtime': 7.29.2 + '@uiw/react-markdown-preview': 5.2.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + rehype: 13.0.2 + rehype-prism-plus: 2.0.2 + transitivePeerDependencies: + - '@types/react' + - supports-color + + '@ungap/structured-clone@1.3.0': {} + '@vitejs/plugin-react@6.0.1(@rolldown/plugin-babel@0.2.3(@babel/core@7.29.0)(@babel/runtime@7.29.2)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.7.1)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.7.1))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7 @@ -7212,12 +7693,16 @@ snapshots: dependencies: '@babel/types': 7.29.0 + bail@2.0.2: {} + balanced-match@1.0.2: {} balanced-match@4.0.4: {} baseline-browser-mapping@2.10.19: {} + bcp-47-match@2.0.3: {} + before-after-hook@4.0.0: {} binary-extensions@2.3.0: {} @@ -7336,6 +7821,8 @@ snapshots: caniuse-lite@1.0.30001788: {} + ccount@2.0.1: {} + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -7351,6 +7838,14 @@ snapshots: char-regex@1.0.2: {} + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -7460,6 +7955,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} + commander@11.1.0: {} commander@14.0.3: {} @@ -7584,6 +8081,8 @@ snapshots: domutils: 3.2.2 nth-check: 2.1.1 + css-selector-parser@3.3.0: {} + css-tree@3.2.1: dependencies: mdn-data: 2.27.1 @@ -7631,6 +8130,10 @@ snapshots: dependencies: ms: 2.1.3 + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + dedent@1.7.2: {} deep-extend@0.6.0: {} @@ -7674,12 +8177,18 @@ snapshots: detect-libc@2.1.2: {} + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + diff@8.0.4: {} dir-glob@3.0.1: dependencies: path-type: 4.0.0 + direction@2.0.1: {} + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -7758,6 +8267,8 @@ snapshots: entities@4.5.0: {} + entities@6.0.1: {} + entities@7.0.1: {} env-ci@11.2.0: @@ -8034,6 +8545,8 @@ snapshots: estraverse@5.3.0: {} + estree-util-is-identifier-name@3.0.0: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.8 @@ -8129,6 +8642,8 @@ snapshots: exsolve@1.0.8: {} + extend@3.0.2: {} + fast-content-type-parse@3.0.0: {} fast-deep-equal@3.1.3: {} @@ -8375,6 +8890,8 @@ snapshots: through2: 2.0.5 traverse: 0.6.8 + github-slugger@2.0.0: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -8470,6 +8987,136 @@ snapshots: dependencies: function-bind: 1.1.2 + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-has-property@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-heading-rank@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.0 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-select@6.0.4: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + bcp-47-match: 2.0.3 + comma-separated-tokens: 2.0.3 + css-selector-parser: 3.3.0 + devlop: 1.1.0 + direction: 2.0.1 + hast-util-has-property: 3.0.0 + hast-util-to-string: 3.0.1 + hast-util-whitespace: 3.0.0 + nth-check: 2.1.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-string@3.0.1: + dependencies: + '@types/hast': 3.0.4 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + headers-polyfill@5.0.1: dependencies: '@types/set-cookie-parser': 2.4.10 @@ -8505,6 +9152,10 @@ snapshots: html-tags@5.1.0: {} + html-url-attributes@3.0.1: {} + + html-void-elements@3.0.0: {} + htmlparser2@10.1.0: dependencies: domelementtype: 2.3.0 @@ -8580,6 +9231,8 @@ snapshots: ini@4.1.3: {} + inline-style-parser@0.2.7: {} + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -8604,6 +9257,13 @@ snapshots: dependencies: is-relative: 0.1.3 + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.9 @@ -8650,6 +9310,8 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-decimal@2.0.1: {} + is-docker@2.2.1: {} is-docker@3.0.0: {} @@ -8678,6 +9340,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-hexadecimal@2.0.1: {} + is-in-ci@1.0.0: {} is-in-ssh@1.0.0: {} @@ -9070,6 +9734,8 @@ snapshots: strip-ansi: 7.2.0 wrap-ansi: 9.0.2 + longest-streak@3.1.0: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -9106,6 +9772,8 @@ snapshots: many-keys-map@3.0.3: {} + markdown-table@3.0.4: {} + marked-terminal@7.3.0(marked@15.0.12): dependencies: ansi-escapes: 7.3.0 @@ -9125,6 +9793,159 @@ snapshots: mathml-tag-names@4.0.0: {} + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdn-data@2.27.1: {} media-typer@1.1.0: {} @@ -9139,6 +9960,197 @@ snapshots: merge2@1.4.1: {} + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -9484,6 +10496,16 @@ snapshots: dependencies: callsites: 3.1.0 + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + parse-json@4.0.0: dependencies: error-ex: 1.3.4 @@ -9512,6 +10534,8 @@ snapshots: parse-ms@4.0.0: {} + parse-numeric-range@1.3.0: {} + parse5-htmlparser2-tree-adapter@6.0.1: dependencies: parse5: 6.0.1 @@ -9520,6 +10544,10 @@ snapshots: parse5@6.0.1: {} + parse5@7.3.0: + dependencies: + entities: 6.0.1 + parseurl@1.3.3: {} path-browserify@1.0.1: {} @@ -9651,6 +10679,8 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + property-information@7.1.0: {} + proto-list@1.2.4: {} proxy-addr@2.0.7: @@ -9736,6 +10766,24 @@ snapshots: react-is@16.13.1: {} + react-markdown@10.1.0(@types/react@19.2.14)(react@19.2.5): + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/react': 19.2.14 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.1 + react: 19.2.5 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + react@19.2.5: {} read-package-up@11.0.0: @@ -9803,6 +10851,13 @@ snapshots: get-proto: 1.0.1 which-builtin-type: 1.2.1 + refractor@5.0.0: + dependencies: + '@types/hast': 3.0.4 + '@types/prismjs': 1.26.6 + hastscript: 9.0.1 + parse-entities: 4.0.2 + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.9 @@ -9820,6 +10875,112 @@ snapshots: dependencies: rc: 1.2.8 + rehype-attr@4.0.2: + dependencies: + unified: 11.0.5 + unist-util-visit: 5.0.0 + + rehype-autolink-headings@7.1.0: + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.3.0 + hast-util-heading-rank: 3.0.0 + hast-util-is-element: 3.0.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + + rehype-ignore@2.0.3: + dependencies: + hast-util-select: 6.0.4 + unified: 11.0.5 + unist-util-visit: 5.1.0 + + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-prism-plus@2.0.2: + dependencies: + hast-util-to-string: 3.0.1 + parse-numeric-range: 1.3.0 + refractor: 5.0.0 + rehype-parse: 9.0.1 + unist-util-filter: 5.0.1 + unist-util-visit: 5.1.0 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + rehype-rewrite@4.0.4: + dependencies: + hast-util-select: 6.0.4 + unified: 11.0.5 + unist-util-visit: 5.1.0 + + rehype-slug@6.0.0: + dependencies: + '@types/hast': 3.0.4 + github-slugger: 2.0.0 + hast-util-heading-rank: 3.0.0 + hast-util-to-string: 3.0.1 + unist-util-visit: 5.1.0 + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + rehype@13.0.2: + dependencies: + '@types/hast': 3.0.4 + rehype-parse: 9.0.1 + rehype-stringify: 10.0.1 + unified: 11.0.5 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-github-blockquote-alert@1.3.1: + dependencies: + unist-util-visit: 5.1.0 + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -10224,6 +11385,8 @@ snapshots: source-map@0.7.6: {} + space-separated-tokens@2.0.2: {} + spawn-error-forwarder@1.0.0: {} spawn-sync@1.0.15: @@ -10336,6 +11499,11 @@ snapshots: dependencies: safe-buffer: 5.1.2 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + stringify-object@5.0.0: dependencies: get-own-enumerable-keys: 1.0.0 @@ -10376,6 +11544,14 @@ snapshots: stubborn-utils@1.0.2: {} + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + stylelint-config-recommended@18.0.0(stylelint@17.8.0(typescript@6.0.3)): dependencies: stylelint: 17.8.0(typescript@6.0.3) @@ -10550,6 +11726,10 @@ snapshots: traverse@0.6.8: {} + trim-lines@3.0.1: {} + + trough@2.2.0: {} + ts-api-utils@2.5.0(typescript@6.0.3): dependencies: typescript: 6.0.3 @@ -10676,6 +11856,16 @@ snapshots: unicorn-magic@0.4.0: {} + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + unimport@6.1.0: dependencies: acorn: 8.16.0 @@ -10697,6 +11887,41 @@ snapshots: dependencies: crypto-random-string: 4.0.0 + unist-util-filter@5.0.1: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + universal-user-agent@7.0.3: {} universalify@2.0.1: {} @@ -10770,6 +11995,21 @@ snapshots: vary@1.1.2: {} + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + vite-node@6.0.0(@types/node@24.12.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.7.1): dependencies: cac: 7.0.0 @@ -10836,6 +12076,8 @@ snapshots: transitivePeerDependencies: - supports-color + web-namespaces@2.0.1: {} + web-streams-polyfill@3.3.3: {} web-worker@1.5.0: {} @@ -11082,3 +12324,5 @@ snapshots: zod@3.25.76: {} zod@4.3.6: {} + + zwitch@2.0.4: {} diff --git a/src/api/redmine/RedmineApiClient.ts b/src/api/redmine/RedmineApiClient.ts index 2e7bcd19..b4b3c949 100644 --- a/src/api/redmine/RedmineApiClient.ts +++ b/src/api/redmine/RedmineApiClient.ts @@ -19,6 +19,8 @@ import { TTimeEntryActivity, TUpdateIssue, TUpdateTimeEntry, + TUploadAttachment, + TUploadResponse, TUser, TVersion, } from "./types"; @@ -44,6 +46,9 @@ export class RedmineApiClient { }); this.instance.interceptors.response.use( (response) => { + if (response.config.headers?.["Accept"] === "text/html") { + return response; + } const contentType = response.headers["content-type"]; if (contentType && !contentType.startsWith("application/json")) { throw new Error(`Invalid content-type '${contentType}'. Expected 'application/json'`); @@ -295,4 +300,38 @@ export class RedmineApiClient { async getCurrentUser(): Promise { return this.instance.get("/users/current.json?include=memberships").then((res) => res.data.user); } + + // Attachments + async uploadAttachment(file: File): Promise { + const arrayBuffer = await file.arrayBuffer(); + const response = await this.instance.post(`/uploads.json?filename=${encodeURIComponent(file.name)}`, arrayBuffer, { + headers: { "Content-Type": "application/octet-stream" }, + }); + return { + id: response.data.upload.id, + token: response.data.upload.token, + filename: file.name, + content_type: file.type, + url: `${this.instance.defaults.baseURL}/attachments/download/${response.data.upload.id}/${encodeURIComponent(file.name)}`, + }; + } + + async removeAttachment(id: number): Promise { + await this.instance.delete(`/attachments/${id}.json`); + } + + // Other + async detectTextFormatting(): Promise<"none" | "common_mark" | "textile" | undefined> { + const resp = await this.instance.get("/", { + headers: { Accept: "text/html" }, + }); + // available since Redmine 6.0.0 + const match = String(resp.data).match(/data-text-formatting="(common_mark|textile|)"/); + if (match) { + if (match[1] === "") { + return "none"; + } + return match[1] as "common_mark" | "textile"; + } + } } diff --git a/src/api/redmine/types.ts b/src/api/redmine/types.ts index 231c5522..9e9c8265 100644 --- a/src/api/redmine/types.ts +++ b/src/api/redmine/types.ts @@ -58,9 +58,17 @@ export type TCreateIssue = { done_ratio?: number | null; }; +export type TUploadAttachment = { + token: string; + filename: string; + content_type?: string; + description?: string; +}; + export type TUpdateIssue = Partial & { notes?: string | null; private_notes?: boolean; + uploads?: TUploadAttachment[]; }; export type TIssuePriority = { @@ -87,6 +95,13 @@ export type TSearchResult = { description: string; }; +export type TUploadResponse = { + upload: { + id: number; + token: string; + }; +}; + // Projects export type TProject = { id: number; diff --git a/src/components/form/RedmineMdEditorField.tsx b/src/components/form/RedmineMdEditorField.tsx new file mode 100644 index 00000000..5471cabc --- /dev/null +++ b/src/components/form/RedmineMdEditorField.tsx @@ -0,0 +1,210 @@ +import { Field, FieldError, FieldLabel } from "@/components/ui/field"; +import { useFieldContext } from "@/hooks/useAppForm"; +import MDEditor, { commands } from "@uiw/react-md-editor"; +import { + BoldIcon, + ChevronsLeftRightEllipsisIcon, + CodeXmlIcon, + EyeIcon, + Grid2x2PlusIcon, + Heading1Icon, + Heading2Icon, + Heading3Icon, + HeadingIcon, + ImageIcon, + ItalicIcon, + ListIcon, + ListIndentIncreaseIcon, + ListOrderedIcon, + ListTodoIcon, + PencilIcon, + StrikethroughIcon, + TypeIcon, + UnderlineIcon, +} from "lucide-react"; +import { ComponentProps, useId, useState } from "react"; +import { useIntl } from "react-intl"; + +type RedmineTextEditorFieldProps = Omit, "id" | "value" | "onChange" | "onBlur"> & { + required?: boolean; + onUploadImage?: (file: File) => Promise<{ url: string; alt?: string } | void>; +}; + +export const RedmineMdEditorField = ({ title, required, className, onUploadImage, ...props }: RedmineTextEditorFieldProps) => { + const { state, handleChange, handleBlur } = useFieldContext(); + const isInvalid = !state.meta.isValid && state.meta.isTouched; + const id = useId(); + + const { formatMessage } = useIntl(); + + const [preview, setPreview] = useState<"edit" | "preview">("edit"); + + return ( + + {title && ( + + {title} + + )} + , + }, + { + ...commands.italic, + buttonProps: { "aria-label": "Italic", title: formatMessage({ id: "editor.command.italic" }) }, + icon: , + }, + { + name: "underline", + keyCommand: "underline", + shortcuts: "ctrlcmd+u", + prefix: "", + suffix: "", + buttonProps: { "aria-label": "Underline", title: formatMessage({ id: "editor.command.underline" }) }, + icon: , + execute: commands.bold.execute, + }, + { + ...commands.strikethrough, + buttonProps: { "aria-label": "Strikethrough", title: formatMessage({ id: "editor.command.strikethrough" }) }, + icon: , + }, + ], + { + name: "format", + groupName: "format", + buttonProps: { "aria-label": "Format" }, + icon: , + } + ), + commands.group( + [ + { + ...commands.heading1, + buttonProps: { "aria-label": "Heading 1", title: formatMessage({ id: "editor.command.heading1" }) }, + icon: , + }, + { + ...commands.heading2, + buttonProps: { "aria-label": "Heading 2", title: formatMessage({ id: "editor.command.heading2" }) }, + icon: , + }, + { + ...commands.heading3, + buttonProps: { "aria-label": "Heading 3", title: formatMessage({ id: "editor.command.heading3" }) }, + icon: , + }, + ], + { + name: "heading", + groupName: "heading", + buttonProps: { "aria-label": "Heading" }, + icon: , + } + ), + commands.group( + [ + { + ...commands.unorderedListCommand, + buttonProps: { "aria-label": "Unordered List", title: formatMessage({ id: "editor.command.unordered-list" }) }, + icon: , + }, + { + ...commands.orderedListCommand, + buttonProps: { "aria-label": "Ordered List", title: formatMessage({ id: "editor.command.ordered-list" }) }, + icon: , + }, + { + ...commands.checkedListCommand, + buttonProps: { "aria-label": "Checked List", title: formatMessage({ id: "editor.command.checked-list" }) }, + icon: , + }, + ], + { + name: "list", + groupName: "list", + buttonProps: { "aria-label": "List" }, + icon: , + } + ), + { + ...commands.code, + buttonProps: { "aria-label": "Inline Code", title: formatMessage({ id: "editor.command.inline-code" }) }, + icon: , + }, + { + ...commands.codeBlock, + buttonProps: { "aria-label": "Code Block", title: formatMessage({ id: "editor.command.code-block" }) }, + icon: , + }, + { + ...commands.quote, + buttonProps: { "aria-label": "Quote", title: formatMessage({ id: "editor.command.quote" }) }, + icon: , + }, + { + ...commands.table, + buttonProps: { "aria-label": "Table", title: formatMessage({ id: "editor.command.table" }) }, + icon: , + }, + { + ...commands.image, + buttonProps: { "aria-label": "Image", title: formatMessage({ id: "editor.command.image" }) }, + icon: , + }, + ]} + preview={preview} + extraCommands={[ + preview === "edit" + ? { + name: "preview", + keyCommand: "preview", + buttonProps: { "aria-label": "Preview", title: formatMessage({ id: "editor.command.preview" }) }, + icon: , + execute: () => setPreview("preview"), + } + : { + name: "edit", + keyCommand: "preview", + buttonProps: { "aria-label": "Edit", title: formatMessage({ id: "editor.command.edit" }) }, + icon: , + execute: () => setPreview("edit"), + }, + ]} + height={150} + {...props} + value={state.value ?? undefined} + onChange={(value) => handleChange(value ?? null)} + onBlur={handleBlur} + onPaste={async (event) => { + if (!onUploadImage) return; + const files = Array.from(event.clipboardData.items) + .filter((item) => item.kind === "file" && item.type.startsWith("image/")) + .map((item) => item.getAsFile()) + .filter((f): f is File => f !== null); + if (files.length === 0) return; + event.preventDefault(); + for (const file of files) { + try { + const upload = await onUploadImage(file); + if (!upload) continue; + const imageMarkdown = `![${upload.alt}](${upload.url})`; + handleChange((prev) => (prev ?? "") + imageMarkdown + " "); + } catch (error) { + console.error("Image upload failed", error); + } + } + }} + /> + {isInvalid && } + + ); +}; diff --git a/src/components/issue/AddIssueNotesModal.tsx b/src/components/issue/AddIssueNotesModal.tsx index a9a3eed8..fbe6838d 100644 --- a/src/components/issue/AddIssueNotesModal.tsx +++ b/src/components/issue/AddIssueNotesModal.tsx @@ -1,5 +1,8 @@ /* eslint-disable react/no-children-prop */ import { redmineIssuesQueries } from "@/api/redmine/queries/issues"; +import UploadsField from "@/components/issue/form/fields/UploadsField"; +import { useSettings } from "@/provider/SettingsProvider"; +import { markdownToTextile } from "@/utils/markdownToTextile"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useIntl } from "react-intl"; import { z } from "zod"; @@ -14,6 +17,7 @@ const addIssueNotesFormSchema = ({ formatMessage }: { formatMessage: ReturnType< z.object({ notes: z.string(formatMessage({ id: "issues.issue.field.notes.validation.required" })).nonempty(formatMessage({ id: "issues.issue.field.notes.validation.required" })), private_notes: z.boolean().optional(), + uploads: z.array(z.object({ token: z.string(), filename: z.string(), content_type: z.string().optional(), description: z.string().optional() })), }); type TAddIssueNotesForm = z.infer>; @@ -25,13 +29,21 @@ type PropTypes = { }; const AddIssueNotesModal = ({ issue, onClose, onSuccess }: PropTypes) => { + const { settings } = useSettings(); const { formatMessage } = useIntl(); const redmineApi = useRedmineApi(); const queryClient = useQueryClient(); const updateIssueMutation = useMutation({ - mutationFn: (data: TUpdateIssue) => redmineApi.updateIssue(issue.id, data), + mutationFn: (data: TUpdateIssue) => + redmineApi.updateIssue(issue.id, { + ...data, + ...(data.notes && + settings.redmine.settings.textFormatting === "textile" && { + notes: markdownToTextile(data.notes), + }), + }), onSuccess: () => { queryClient.invalidateQueries(redmineIssuesQueries); onSuccess(); @@ -40,11 +52,15 @@ const AddIssueNotesModal = ({ issue, onClose, onSuccess }: PropTypes) => { successMessage: formatMessage({ id: "issues.modal.add-issue-notes.success" }), }, }); + const uploadAttachmentMutation = useMutation({ + mutationFn: (file: File) => redmineApi.uploadAttachment(file), + }); const form = useAppForm({ defaultValues: { notes: "", private_notes: false, + uploads: [], } satisfies TAddIssueNotesForm as TAddIssueNotesForm, validators: { onChange: addIssueNotesFormSchema({ formatMessage }), @@ -65,9 +81,23 @@ const AddIssueNotesModal = ({ issue, onClose, onSuccess }: PropTypes) => { ( - + { + const { id: _, url, ...attachment } = await uploadAttachmentMutation.mutateAsync(file); + form.pushFieldValue("uploads", attachment); + if (settings.redmine.settings.textFormatting !== "none") { + return { url, alt: attachment.filename }; + } + }} + /> )} /> + } /> } /> diff --git a/src/components/issue/form/IssueForm.tsx b/src/components/issue/form/IssueForm.tsx index d4bc3a5b..40f6bd21 100644 --- a/src/components/issue/form/IssueForm.tsx +++ b/src/components/issue/form/IssueForm.tsx @@ -2,8 +2,12 @@ import { useRedmineCurrentUser } from "@/api/redmine/hooks/useRedmineCurrentUser"; import { useRedmineIssueAllowedStatuses } from "@/api/redmine/hooks/useRedmineIssueAllowedStatuses"; import { useRedmineProject } from "@/api/redmine/hooks/useRedmineProject"; +import UploadsField from "@/components/issue/form/fields/UploadsField"; import { DialogFooter } from "@/components/ui/dialog"; import { Form, FormGrid } from "@/components/ui/form"; +import { useRedmineApi } from "@/provider/RedmineApiProvider"; +import { useSettings } from "@/provider/SettingsProvider"; +import { useMutation } from "@tanstack/react-query"; import { parseISO } from "date-fns"; import { useIntl } from "react-intl"; import { z } from "zod"; @@ -46,6 +50,7 @@ const createOrEditIssueFormSchema = ({ formatMessage }: { formatMessage: ReturnT due_date: z.date().nullable(), estimated_hours: z.number().nullable(), done_ratio: z.int().min(0).max(100), + uploads: z.array(z.object({ token: z.string(), filename: z.string(), content_type: z.string().optional(), description: z.string().optional() })), }) .check((ctx) => { if (ctx.value.start_date && ctx.value.due_date && ctx.value.start_date > ctx.value.due_date) { @@ -61,6 +66,7 @@ const createOrEditIssueFormSchema = ({ formatMessage }: { formatMessage: ReturnT type TCreateOrEditIssueForm = z.infer>; export const IssueForm = (props: PropTypes) => { + const { settings } = useSettings(); const { formatMessage } = useIntl(); const projectId = props.action === "create" ? props.projectId : props.issue.project.id; @@ -74,6 +80,11 @@ export const IssueForm = (props: PropTypes) => { staleTime: 0, }); + const redmineApi = useRedmineApi(); + const uploadAttachmentMutation = useMutation({ + mutationFn: (file: File) => redmineApi.uploadAttachment(file), + }); + const form = useAppForm({ defaultValues: props.action === "create" @@ -91,6 +102,7 @@ export const IssueForm = (props: PropTypes) => { due_date: null, estimated_hours: null, done_ratio: 0, + uploads: [], } satisfies Partial as TCreateOrEditIssueForm) : ({ project_id: props.issue.project.id, @@ -106,6 +118,7 @@ export const IssueForm = (props: PropTypes) => { due_date: props.issue.due_date ? parseISO(props.issue.due_date) : null, estimated_hours: props.issue.estimated_hours ?? null, done_ratio: props.issue.done_ratio, + uploads: [], } satisfies TCreateOrEditIssueForm as TCreateOrEditIssueForm), validators: { onChange: createOrEditIssueFormSchema({ formatMessage }), @@ -192,12 +205,29 @@ export const IssueForm = (props: PropTypes) => { /> {(hasTrackerNoEnabledFields || selectedTracker?.enabled_standard_fields?.includes("description")) && ( - ( - - )} - /> + <> + + settings.redmine.settings.textFormatting === "common_mark" ? ( + { + const { id: _, url, ...attachment } = await uploadAttachmentMutation.mutateAsync(file); + form.pushFieldValue("uploads", attachment); + if (settings.redmine.settings.textFormatting !== "none") { + return { url, alt: attachment.filename }; + } + }} + /> + ) : ( + + ) + } + /> + } /> + )} diff --git a/src/components/issue/form/fields/UploadsField.tsx b/src/components/issue/form/fields/UploadsField.tsx new file mode 100644 index 00000000..9ae984ca --- /dev/null +++ b/src/components/issue/form/fields/UploadsField.tsx @@ -0,0 +1,51 @@ +import { TUploadAttachment } from "@/api/redmine/types"; +import { Button } from "@/components/ui/button"; +import { Field, FieldLabel } from "@/components/ui/field"; +import { useFieldContext } from "@/hooks/useAppForm"; +import { useRedmineApi } from "@/provider/RedmineApiProvider"; +import { useMutation } from "@tanstack/react-query"; +import { PaperclipIcon, Trash2Icon } from "lucide-react"; +import { useIntl } from "react-intl"; + +const UploadsField = () => { + const { formatMessage } = useIntl(); + + const { state, removeValue } = useFieldContext(); + + const redmineApi = useRedmineApi(); + const removeAttachmentMutation = useMutation({ + mutationFn: (id: number) => redmineApi.removeAttachment(id), + }); + + if (!state.value || state.value.length === 0) return null; + + return ( + + {formatMessage({ id: "issues.issue.field.uploads" })} +
+ {state.value?.map((upload, index) => ( +
+ + {upload.filename} + +
+ ))} +
+
+ ); +}; + +export default UploadsField; diff --git a/src/components/time-entry/CreateTimeEntryModal.tsx b/src/components/time-entry/CreateTimeEntryModal.tsx index a7d74cd8..b1d73b34 100644 --- a/src/components/time-entry/CreateTimeEntryModal.tsx +++ b/src/components/time-entry/CreateTimeEntryModal.tsx @@ -3,8 +3,10 @@ import { useRedmineCurrentUser } from "@/api/redmine/hooks/useRedmineCurrentUser import { useRedmineProjectTimeEntryActivities } from "@/api/redmine/hooks/useRedmineProjectTimeEntryActivities"; import { redmineIssuesQueries } from "@/api/redmine/queries/issues"; import { redmineTimeEntriesQueries } from "@/api/redmine/queries/timeEntries"; +import UploadsField from "@/components/issue/form/fields/UploadsField"; import { usePersistentComments } from "@/hooks/usePersistentComments"; import { Timer } from "@/hooks/useTimers"; +import { markdownToTextile } from "@/utils/markdownToTextile"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { startOfDay } from "date-fns"; import { useIntl } from "react-intl"; @@ -46,6 +48,7 @@ const createTimeEntryFormSchema = ({ formatMessage }: { formatMessage?: ReturnTy done_ratio: z.number().min(0).max(100), _add_notes: z.boolean(), notes: z.string().nullable(), + uploads: z.array(z.object({ token: z.string(), filename: z.string(), content_type: z.string().optional(), description: z.string().optional() })), }), }); @@ -82,6 +85,10 @@ const CreateTimeEntryModal = ({ timer, issue, initialValues, onClose, onSuccess }, }); + const uploadAttachmentMutation = useMutation({ + mutationFn: (file: File) => redmineApi.uploadAttachment(file), + }); + const persistentComments = usePersistentComments({ identifier: timer.id, enabled: settings.features.persistentComments, @@ -99,6 +106,7 @@ const CreateTimeEntryModal = ({ timer, issue, initialValues, onClose, onSuccess done_ratio: issue.done_ratio, _add_notes: false, notes: null, + uploads: [], }, ...initialValues, ...(persistentComments.isEnabled && @@ -114,11 +122,14 @@ const CreateTimeEntryModal = ({ timer, issue, initialValues, onClose, onSuccess // Update issue done_ratio and notes const updatedDoneRatio = updateIssue.done_ratio !== issue.done_ratio ? updateIssue.done_ratio : undefined; - const addNotes = updateIssue._add_notes && updateIssue.notes ? updateIssue.notes : undefined; - if (updatedDoneRatio !== undefined || addNotes) { + const notes = updateIssue._add_notes && updateIssue.notes ? updateIssue.notes : undefined; + if (updatedDoneRatio !== undefined || notes) { await updateIssueMutation.mutateAsync({ done_ratio: updatedDoneRatio, - notes: addNotes, + ...(notes && { + notes: settings.redmine.settings.textFormatting === "textile" ? markdownToTextile(notes) : notes, + }), + uploads: updateIssue.uploads, }); } @@ -239,7 +250,25 @@ const CreateTimeEntryModal = ({ timer, issue, initialValues, onClose, onSuccess } /> - } /> + ( + { + const { id: _, url, ...attachment } = await uploadAttachmentMutation.mutateAsync(file); + form.pushFieldValue("issue.uploads", attachment); + if (settings.redmine.settings.textFormatting !== "none") { + return { url, alt: attachment.filename }; + } + }} + /> + )} + /> + } /> ) diff --git a/src/hooks/useAppForm.ts b/src/hooks/useAppForm.ts index f29c9aef..b5a84bec 100644 --- a/src/hooks/useAppForm.ts +++ b/src/hooks/useAppForm.ts @@ -2,6 +2,7 @@ import { CheckboxField } from "@/components/form/CheckboxField"; import { ComboboxField } from "@/components/form/ComboboxField"; import { DateField } from "@/components/form/DateField"; import { HoursField } from "@/components/form/HoursField"; +import { RedmineMdEditorField } from "@/components/form/RedmineMdEditorField"; import { SelectField } from "@/components/form/SelectField"; import { SubmitButton } from "@/components/form/SubmitButton"; import { SwitchField } from "@/components/form/SwitchField"; @@ -25,6 +26,7 @@ export const { useAppForm, withForm } = createFormHook({ ComboboxField, ToggleGroupField, HoursField, + RedmineMdEditorField, }, formComponents: { SubmitButton, diff --git a/src/index.css b/src/index.css index d691f9e5..2709f0b4 100644 --- a/src/index.css +++ b/src/index.css @@ -185,3 +185,50 @@ border-radius: 3px; } } + +.wmde-markdown, +.wmde-markdown-var { + --color-canvas-default: transparent; + --color-border-default: var(--color-input); + --color-fg-default: var(--color-foreground); + --color-neutral-muted: var(--color-muted); + --color-accent-fg: var(--color-primary); + --color-danger-fg: var(--color-destructive); + --color-border-muted: var(--color-border); + --color-canvas-subtle: var(--color-muted); + --md-editor-font-family: var(--font-sans); + + border-radius: var(--radius) !important; +} + +.w-md-editor-toolbar-child { + background-color: var(--color-popover); +} + +.w-md-editor-toolbar li > button { + border-radius: var(--radius-sm); +} + +@media (prefers-color-scheme: dark) { + .w-md-editor { + --color-canvas-default: color-mix(in oklab, var(--color-input) 30%, transparent); + } +} + +.w-md-editor-preview { + ul { + list-style: disc; + } + + ol { + list-style: decimal; + } + + ul ul { + list-style: circle; + } + + ul ul ul { + list-style: square; + } +} diff --git a/src/lang/de.json b/src/lang/de.json index 106e2042..57771b3f 100644 --- a/src/lang/de.json +++ b/src/lang/de.json @@ -86,6 +86,7 @@ "issues.issue.field.notes": "Notizen", "issues.issue.field.notes.validation.required": "Notizen werden benötigt", "issues.issue.field.private-notes": "Private Notizen", + "issues.issue.field.uploads": "Dateien", "issues.modal.add-spent-time.title": "Zeitaufwand hinzufügen", "issues.modal.add-spent-time.add-notes": "Notizen hinzufügen", "issues.modal.add-spent-time.submit": "Erstellen", @@ -147,6 +148,13 @@ "settings.redmine.hello-user": "Hallo {firstName} {lastName} ({accountName})", "settings.redmine.edit": "Bearbeiten", "settings.redmine.test-connection": "Verbindung testen", + "settings.redmine.settings": "Redmine Einstellungen", + "settings.redmine.settings.description": "Einstellungen auf Ihre Redmine Instanz bezogen", + "settings.redmine.settings.detect": "Erkennen", + "settings.redmine.settings.text-formatting.title": "Textformatierung", + "settings.redmine.settings.text-formatting.none": "Keine", + "settings.redmine.settings.text-formatting.common_mark": "CommonMark", + "settings.redmine.settings.text-formatting.textile": "Textile", "settings.features": "Funktionen", "settings.features.auto-pause-on-switch.title": "Auto Pause", "settings.features.auto-pause-on-switch.description": "Timer automatisch pausieren, wenn Ticket gewechselt wird", @@ -195,5 +203,23 @@ "general.error.unknown-error": "Unbekannter Fehler: {name}", "general.error.page-not-found": "Seite nicht gefunden", - "format.hours": "{hours} Std." + "format.hours": "{hours} Std.", + + "editor.command.bold": "Fett (Ctrl+B)", + "editor.command.italic": "Kursiv (Ctrl+I)", + "editor.command.underline": "Unterstrichen (Ctrl+U)", + "editor.command.strikethrough": "Durchgestrichen", + "editor.command.heading1": "Überschrift 1", + "editor.command.heading2": "Überschrift 2", + "editor.command.heading3": "Überschrift 3", + "editor.command.unordered-list": "Ungeordnete Liste", + "editor.command.ordered-list": "Geordnete Liste", + "editor.command.checked-list": "Checkliste", + "editor.command.inline-code": "Code", + "editor.command.code-block": "Codeblock", + "editor.command.quote": "Zitat", + "editor.command.table": "Tabelle", + "editor.command.image": "Bild", + "editor.command.edit": "Bearbeiten", + "editor.command.preview": "Vorschau" } diff --git a/src/lang/en.json b/src/lang/en.json index e57aa313..b98b37c8 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -86,6 +86,7 @@ "issues.issue.field.notes": "Notes", "issues.issue.field.notes.validation.required": "Notes is required", "issues.issue.field.private-notes": "Private notes", + "issues.issue.field.uploads": "Files", "issues.modal.add-spent-time.title": "Add spent time", "issues.modal.add-spent-time.add-notes": "Add notes", "issues.modal.add-spent-time.submit": "Create", @@ -147,6 +148,13 @@ "settings.redmine.hello-user": "Hello {firstName} {lastName} ({accountName})", "settings.redmine.edit": "Edit", "settings.redmine.test-connection": "Test connection", + "settings.redmine.settings": "Redmine Settings", + "settings.redmine.settings.description": "Settings related to your Redmine instance", + "settings.redmine.settings.detect": "Detect", + "settings.redmine.settings.text-formatting.title": "Text formatting", + "settings.redmine.settings.text-formatting.none": "None", + "settings.redmine.settings.text-formatting.common_mark": "CommonMark", + "settings.redmine.settings.text-formatting.textile": "Textile", "settings.features": "Features", "settings.features.auto-pause-on-switch.title": "Auto pause", "settings.features.auto-pause-on-switch.description": "Automatic pause timers when changing issue", @@ -195,5 +203,23 @@ "general.error.unknown-error": "Unknown error: {name}", "general.error.page-not-found": "Page not found", - "format.hours": "{hours} h" + "format.hours": "{hours} h", + + "editor.command.bold": "Bold (Ctrl+B)", + "editor.command.italic": "Italic (Ctrl+I)", + "editor.command.underline": "Underline (Ctrl+U)", + "editor.command.strikethrough": "Strikethrough", + "editor.command.heading1": "Heading 1", + "editor.command.heading2": "Heading 2", + "editor.command.heading3": "Heading 3", + "editor.command.unordered-list": "Unordered List", + "editor.command.ordered-list": "Ordered List", + "editor.command.checked-list": "Checked List", + "editor.command.inline-code": "Inline Code", + "editor.command.code-block": "Code Block", + "editor.command.quote": "Quote", + "editor.command.table": "Table", + "editor.command.image": "Image", + "editor.command.edit": "Edit", + "editor.command.preview": "Preview" } diff --git a/src/lang/fr.json b/src/lang/fr.json index 8c8748a1..7e616f61 100644 --- a/src/lang/fr.json +++ b/src/lang/fr.json @@ -86,6 +86,7 @@ "issues.issue.field.notes": "Notes", "issues.issue.field.notes.validation.required": "Notes is required", "issues.issue.field.private-notes": "Private notes", + "issues.issue.field.uploads": "Files", "issues.modal.add-spent-time.title": "Ajouter du temps passé", "issues.modal.add-spent-time.add-notes": "Ajouter des notes", "issues.modal.add-spent-time.submit": "Créer", @@ -147,6 +148,13 @@ "settings.redmine.hello-user": "Bonjour {firstName} {lastName} ({accountName})", "settings.redmine.edit": "Modifier", "settings.redmine.test-connection": "Test connection", + "settings.redmine.settings": "Redmine Settings", + "settings.redmine.settings.description": "Settings related to your Redmine instance", + "settings.redmine.settings.detect": "Detect", + "settings.redmine.settings.text-formatting.title": "Text formatting", + "settings.redmine.settings.text-formatting.none": "None", + "settings.redmine.settings.text-formatting.common_mark": "CommonMark", + "settings.redmine.settings.text-formatting.textile": "Textile", "settings.features": "Fonctionnalités", "settings.features.auto-pause-on-switch.title": "Pause automatique", "settings.features.auto-pause-on-switch.description": "Pause automatique des minuteurs lors du changement de ticket", @@ -195,5 +203,23 @@ "general.error.unknown-error": "Unknown error: {name}", "general.error.page-not-found": "Page introuvable", - "format.hours": "{hours} h" + "format.hours": "{hours} h", + + "editor.command.bold": "Bold (Ctrl+B)", + "editor.command.italic": "Italic (Ctrl+I)", + "editor.command.underline": "Underline (Ctrl+U)", + "editor.command.strikethrough": "Strikethrough", + "editor.command.heading1": "Heading 1", + "editor.command.heading2": "Heading 2", + "editor.command.heading3": "Heading 3", + "editor.command.unordered-list": "Unordered List", + "editor.command.ordered-list": "Ordered List", + "editor.command.checked-list": "Checked List", + "editor.command.inline-code": "Inline Code", + "editor.command.code-block": "Code Block", + "editor.command.quote": "Quote", + "editor.command.table": "Table", + "editor.command.image": "Image", + "editor.command.edit": "Edit", + "editor.command.preview": "Preview" } diff --git a/src/lang/ru.json b/src/lang/ru.json index 5e637458..1cfb0d48 100644 --- a/src/lang/ru.json +++ b/src/lang/ru.json @@ -86,6 +86,7 @@ "issues.issue.field.notes": "Примечания", "issues.issue.field.notes.validation.required": "Notes is required", "issues.issue.field.private-notes": "Private notes", + "issues.issue.field.uploads": "Files", "issues.modal.add-spent-time.title": "Добавление затраченного времени", "issues.modal.add-spent-time.add-notes": "Добавление примечаний", "issues.modal.add-spent-time.submit": "Добавить", @@ -147,6 +148,13 @@ "settings.redmine.hello-user": "Здравствуйте {firstName} {lastName} ({accountName})", "settings.redmine.edit": "Изменить", "settings.redmine.test-connection": "Test connection", + "settings.redmine.settings": "Redmine Settings", + "settings.redmine.settings.description": "Settings related to your Redmine instance", + "settings.redmine.settings.detect": "Detect", + "settings.redmine.settings.text-formatting.title": "Text formatting", + "settings.redmine.settings.text-formatting.none": "None", + "settings.redmine.settings.text-formatting.common_mark": "CommonMark", + "settings.redmine.settings.text-formatting.textile": "Textile", "settings.features": "Дополнительно", "settings.features.auto-pause-on-switch.title": "Авто остановка", "settings.features.auto-pause-on-switch.description": "Автоматически останавливать таймеры при изменении задачи", @@ -195,5 +203,23 @@ "general.error.unknown-error": "Unknown error: {name}", "general.error.page-not-found": "Страница не найдена", - "format.hours": "{hours} ч" + "format.hours": "{hours} ч", + + "editor.command.bold": "Bold (Ctrl+B)", + "editor.command.italic": "Italic (Ctrl+I)", + "editor.command.underline": "Underline (Ctrl+U)", + "editor.command.strikethrough": "Strikethrough", + "editor.command.heading1": "Heading 1", + "editor.command.heading2": "Heading 2", + "editor.command.heading3": "Heading 3", + "editor.command.unordered-list": "Unordered List", + "editor.command.ordered-list": "Ordered List", + "editor.command.checked-list": "Checked List", + "editor.command.inline-code": "Inline Code", + "editor.command.code-block": "Code Block", + "editor.command.quote": "Quote", + "editor.command.table": "Table", + "editor.command.image": "Image", + "editor.command.edit": "Edit", + "editor.command.preview": "Preview" } diff --git a/src/provider/SettingsProvider.tsx b/src/provider/SettingsProvider.tsx index 4547a3fd..fbce57ff 100644 --- a/src/provider/SettingsProvider.tsx +++ b/src/provider/SettingsProvider.tsx @@ -14,6 +14,11 @@ export const settingsSchema = ({ formatMessage }: { formatMessage?: ReturnType(undefined); const redmineConnection = useTestRedmineConnection(redmineApiClient); + // Reset when form is submitted const isSubmitted = useFormStore(form.store, (state) => state.isSubmitted); useEffect(() => { if (isSubmitted) { @@ -307,6 +310,18 @@ const RedmineServerSection = withForm({ } }, [isSubmitted]); + // Detect Redmine configuration (e.g. text formatting) after successful connection + const defaultRedmineApi = useRedmineApi(); + const detectRedmineConfig = useEffectEvent(async () => { + const detectedTextFormatting = await (redmineApiClient ?? defaultRedmineApi).detectTextFormatting(); + if (detectedTextFormatting) { + form.setFieldValue("redmine.settings.textFormatting", detectedTextFormatting); + } + }); + useEffect(() => { + if (redmineApiClient && redmineConnection.data) detectRedmineConfig(); + }, [redmineApiClient, redmineConnection.data]); + return ( @@ -428,6 +443,33 @@ const RedmineServerSection = withForm({ ) : undefined} +
+ + {formatMessage({ id: "settings.redmine.settings" })} + + + {formatMessage({ id: "settings.redmine.settings.description" })} + + ( + + )} + /> + +
)} diff --git a/src/utils/markdownToTextile.ts b/src/utils/markdownToTextile.ts new file mode 100644 index 00000000..bd88b20b --- /dev/null +++ b/src/utils/markdownToTextile.ts @@ -0,0 +1,104 @@ +/** + * Converts Markdown to Textile format + * + * @see https://www.redmine.org/projects/redmine/wiki/RedmineTextFormattingMarkdown + * @see https://www.redmine.org/projects/redmine/wiki/RedmineTextFormattingTextile + */ +export function markdownToTextile(markdown: string): string { + let result = markdown; + + // ATX headings h1–h6 + result = result.replace(/^#{6}\s+(.+)$/gm, "h6. $1\n"); + result = result.replace(/^#{5}\s+(.+)$/gm, "h5. $1\n"); + result = result.replace(/^#{4}\s+(.+)$/gm, "h4. $1\n"); + result = result.replace(/^#{3}\s+(.+)$/gm, "h3. $1\n"); + result = result.replace(/^#{2}\s+(.+)$/gm, "h2. $1\n"); + result = result.replace(/^#\s+(.+)$/gm, "h1. $1\n"); + + // Code block + result = result.replace(/```(\w+)?\n([\s\S]*?)```/gm, (_: string, lang: string | undefined, code: string) => { + const langAttr = lang ? ` class="${lang}"` : ""; + return `
${code.trimEnd()}
`; + }); + + // Inline code + result = result.replace(/`([^`]+)`/g, "@$1@"); + + // Bold+italic ***text*** or ___text___ → *_text_* + result = result.replace(/\*\*\*(.+?)\*\*\*/g, "*_$1_*"); + result = result.replace(/___(.+?)___/g, "*_$1_*"); + + // Italic *text* → _text_ + result = result.replace(/(?text → -text- + result = result.replace(/~~(.+?)~~/g, "-$1-"); + result = result.replace(/(.+?)<\/del>/g, "-$1-"); + + // Underline text → +text+ + result = result.replace(/(.+?)<\/ins>/g, "+$1+"); + + // Images ![alt](url) → !url(alt)! + result = result.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_, alt: string | undefined, url: string) => (alt ? `!${url}(${alt})!` : `!${url}!`)); + + // Links [text](url) → "text":url + result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '"$1":$2'); + + // Horizontal rules --- or *** or ___ + result = result.replace(/^(?:---+|\*\*\*+|___+)$/gm, "----"); + + // Lists + result = result.replace(/^([ \t]*)[-*]\s+(.+)$/gm, (_, indent: string, content: string) => { + const level = Math.floor(indent.length / 2) + 1; + return "*".repeat(level) + " " + content; + }); + result = result.replace(/^([ \t]*)\d+\.\s+(.+)$/gm, (_, indent: string, content: string) => { + const level = Math.floor(indent.length / 2) + 1; + return "#".repeat(level) + " " + content; + }); + + // Tables + result = result.replace(/(?:^\|.+\|$\n?)+/gm, (table: string) => { + const lines = table.trim().split("\n"); + + if (lines.length < 2) return table; // Not a valid table + if (!/^\|[\s|:-]+\|$/.test(lines[1]!)) return table; // Missing separator row + + const alignments = lines[1]! + .slice(1, -1) + .split("|") + .map((cell) => { + const trimmed = cell.trim(); + if (/^:-+$/.test(trimmed)) return "<"; // Left align + if (/^-+:$/.test(trimmed)) return ">"; // Right align + if (/^:-+:$/.test(trimmed)) return "="; // Center align + return "<"; // Default to left align + }); + + const headerRow = + "|" + + lines[0]! + .slice(1, -1) + .split("|") + .map((cell) => cell.trim()) + .map((cell, i) => `_${alignments[i]}. ${cell}`) + .join("|") + + "|"; + + const bodyRows = lines.slice(2).map((line) => { + const cells = line + .slice(1, -1) + .split("|") + .map((cell) => cell.trim()); + return "|" + cells.map((cell, i) => `${alignments[i]}. ${cell}`).join("|") + "|"; + }); + + return [headerRow, ...bodyRows].join("\n") + "\n"; + }); + + return result; +}