diff --git a/.github/workflows/build-pull-request.yml b/.github/workflows/build-pull-request.yml index 450e4e29..60822231 100644 --- a/.github/workflows/build-pull-request.yml +++ b/.github/workflows/build-pull-request.yml @@ -14,7 +14,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4.2.0 - name: Setup node - uses: actions/setup-node@v4.4.0 + uses: actions/setup-node@v4.2.0 with: node-version: 20.12.2 cache: 'npm' @@ -25,7 +25,7 @@ jobs: NODE_OPTIONS: '--max_old_space_size=4096' run: npm run build - name: Upload artifact - uses: actions/upload-artifact@v4.6.2 + uses: actions/upload-artifact@v4.6.0 with: name: preview path: dist @@ -33,7 +33,7 @@ jobs: - name: Save pr number run: echo ${PR_NUMBER} > ./pr.txt - name: Upload pr number - uses: actions/upload-artifact@v4.6.2 + uses: actions/upload-artifact@v4.6.0 with: name: pr path: ./pr.txt diff --git a/.github/workflows/deploy-pull-request.yml b/.github/workflows/deploy-pull-request.yml index b330c3c1..c079ae3e 100644 --- a/.github/workflows/deploy-pull-request.yml +++ b/.github/workflows/deploy-pull-request.yml @@ -15,7 +15,7 @@ jobs: if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: Download pr number - uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 + uses: dawidd6/action-download-artifact@20319c5641d495c8a52e688b7dc5fada6c3a9fbc with: workflow: ${{ github.event.workflow.id }} run_id: ${{ github.event.workflow_run.id }} @@ -24,7 +24,7 @@ jobs: id: pr run: echo "id=$(> $GITHUB_OUTPUT - name: Download artifact - uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 + uses: dawidd6/action-download-artifact@20319c5641d495c8a52e688b7dc5fada6c3a9fbc with: workflow: ${{ github.event.workflow.id }} run_id: ${{ github.event.workflow_run.id }} diff --git a/.github/workflows/docker-pr.yml b/.github/workflows/docker-pr.yml index 398785ab..7e8e99f3 100644 --- a/.github/workflows/docker-pr.yml +++ b/.github/workflows/docker-pr.yml @@ -13,7 +13,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4.2.0 - name: Build Docker image - uses: docker/build-push-action@v6.18.0 + uses: docker/build-push-action@v6.13.0 with: context: . push: false diff --git a/.github/workflows/netlify-dev.yml b/.github/workflows/netlify-dev.yml index 66cd5ad5..d53ebee6 100644 --- a/.github/workflows/netlify-dev.yml +++ b/.github/workflows/netlify-dev.yml @@ -13,7 +13,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4.2.0 - name: Setup node - uses: actions/setup-node@v4.4.0 + uses: actions/setup-node@v4.2.0 with: node-version: 20.12.2 cache: 'npm' diff --git a/.github/workflows/prod-deploy.yml b/.github/workflows/prod-deploy.yml index 24edda96..ee0561da 100644 --- a/.github/workflows/prod-deploy.yml +++ b/.github/workflows/prod-deploy.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4.2.0 - name: Setup node - uses: actions/setup-node@v4.4.0 + uses: actions/setup-node@v4.2.0 with: node-version: 20.12.2 cache: 'npm' @@ -52,7 +52,7 @@ jobs: gpg --export | xxd -p echo '${{ secrets.GNUPG_PASSPHRASE }}' | gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 --armor --detach-sign cinny-${{ steps.vars.outputs.tag }}.tar.gz - name: Upload tagged release - uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 + uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda with: files: | cinny-${{ steps.vars.outputs.tag }}.tar.gz @@ -68,29 +68,29 @@ jobs: - name: Checkout repository uses: actions/checkout@v4.2.0 - name: Set up QEMU - uses: docker/setup-qemu-action@v3.6.0 + uses: docker/setup-qemu-action@v3.4.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.10.0 + uses: docker/setup-buildx-action@v3.9.0 - name: Login to Docker Hub - uses: docker/login-action@v3.5.0 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Login to the Container registry - uses: docker/login-action@v3.5.0 + uses: docker/login-action@v3.3.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@v5.8.0 + uses: docker/metadata-action@v5.6.1 with: images: | ${{ secrets.DOCKER_USERNAME }}/cinny ghcr.io/${{ github.repository }} - name: Build and push Docker image - uses: docker/build-push-action@v6.18.0 + uses: docker/build-push-action@v6.13.0 with: context: . platforms: linux/amd64,linux/arm64 diff --git a/Dockerfile b/Dockerfile index 718fed72..abb65ee5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ RUN npm run build ## App -FROM nginx:1.29.0-alpine +FROM nginx:1.27.4-alpine COPY --from=builder /src/dist /app COPY --from=builder /src/docker-nginx.conf /etc/nginx/conf.d/default.conf diff --git a/contrib/caddy/caddyfile b/contrib/caddy/caddyfile index d23dcccb..e55efe92 100644 --- a/contrib/caddy/caddyfile +++ b/contrib/caddy/caddyfile @@ -1,6 +1,6 @@ -# more info: https://caddyserver.com/docs/caddyfile/patterns#single-page-apps-spas cinny.domain.tld { - root * /path/to/cinny/dist - try_files {path} / index.html + @nativeRouter not file {path} / + rewrite @nativeRouter {http.matchers.file.relative} + root * /path/to/caddy/dist file_server } diff --git a/contrib/nginx/cinny.domain.tld.conf b/contrib/nginx/cinny.domain.tld.conf index 02c7ead9..0b6c8aad 100644 --- a/contrib/nginx/cinny.domain.tld.conf +++ b/contrib/nginx/cinny.domain.tld.conf @@ -23,6 +23,7 @@ server { rewrite ^/config.json$ /config.json break; rewrite ^/manifest.json$ /manifest.json break; + rewrite ^.*/olm.wasm$ /olm.wasm break; rewrite ^/sw.js$ /sw.js break; rewrite ^/pdf.worker.min.js$ /pdf.worker.min.js break; diff --git a/docker-nginx.conf b/docker-nginx.conf index a2dbeba0..fca10746 100644 --- a/docker-nginx.conf +++ b/docker-nginx.conf @@ -8,6 +8,7 @@ server { rewrite ^/config.json$ /config.json break; rewrite ^/manifest.json$ /manifest.json break; + rewrite ^.*/olm.wasm$ /olm.wasm break; rewrite ^/sw.js$ /sw.js break; rewrite ^/pdf.worker.min.js$ /pdf.worker.min.js break; diff --git a/index.html b/index.html index 2eefeee2..9196cf3d 100644 --- a/index.html +++ b/index.html @@ -90,7 +90,6 @@ window.global ||= window;
-
diff --git a/netlify.toml b/netlify.toml index a8710303..1b192bec 100644 --- a/netlify.toml +++ b/netlify.toml @@ -13,6 +13,11 @@ to = "/sw.js" status = 200 +[[redirects]] + from = "*/olm.wasm" + to = "/olm.wasm" + status = 200 + force = true [[redirects]] from = "/pdf.worker.min.js" diff --git a/package-lock.json b/package-lock.json index 4aacff72..b173bc70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,29 +1,29 @@ { "name": "cinny", - "version": "4.10.0", + "version": "4.5.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cinny", - "version": "4.10.0", + "version": "4.5.1", "license": "AGPL-3.0-only", "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "1.1.6", "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "1.3.0", "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.0.3", "@fontsource/inter": "4.5.14", + "@matrix-org/olm": "3.2.15", "@tanstack/react-query": "5.24.1", "@tanstack/react-query-devtools": "5.24.1", "@tanstack/react-virtual": "3.2.0", + "@tippyjs/react": "4.2.6", "@vanilla-extract/css": "1.9.3", "@vanilla-extract/recipes": "0.3.0", "@vanilla-extract/vite-plugin": "3.7.1", "await-to-js": "3.0.0", - "badwords-list": "2.0.1-4", "blurhash": "2.0.4", "browser-encrypt-attachment": "0.3.0", - "chroma-js": "3.1.2", "classnames": "2.3.2", "dateformat": "5.0.3", "dayjs": "1.11.10", @@ -31,8 +31,10 @@ "emojibase": "15.3.1", "emojibase-data": "15.3.2", "file-saver": "2.0.5", + "flux": "4.0.3", "focus-trap-react": "10.0.2", - "folds": "2.3.0", + "folds": "2.1.0", + "formik": "2.4.6", "html-dom-parser": "4.0.0", "html-react-parser": "4.2.0", "i18next": "23.12.2", @@ -43,18 +45,20 @@ "jotai": "2.6.0", "linkify-react": "4.1.3", "linkifyjs": "4.1.3", - "matrix-js-sdk": "37.5.0", + "matrix-js-sdk": "35.0.0", "millify": "6.1.0", "pdfjs-dist": "4.2.67", - "prismjs": "1.30.0", + "prismjs": "1.29.0", + "prop-types": "15.8.1", "react": "18.2.0", "react-aria": "3.29.1", + "react-autosize-textarea": "7.1.0", "react-blurhash": "0.2.0", - "react-colorful": "5.6.1", "react-dom": "18.2.0", "react-error-boundary": "4.0.13", "react-google-recaptcha": "2.1.0", "react-i18next": "15.0.0", + "react-modal": "3.16.1", "react-range": "1.8.14", "react-router-dom": "6.20.0", "sanitize-html": "2.12.1", @@ -62,13 +66,13 @@ "slate-dom": "0.112.2", "slate-history": "0.110.3", "slate-react": "0.112.1", + "tippy.js": "6.3.7", "ua-parser-js": "1.0.35" }, "devDependencies": { "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@rollup/plugin-inject": "5.0.3", "@rollup/plugin-wasm": "6.1.1", - "@types/chroma-js": "3.1.1", "@types/file-saver": "2.0.5", "@types/is-hotkey": "0.1.10", "@types/node": "18.11.18", @@ -90,8 +94,9 @@ "eslint-plugin-react": "7.31.11", "eslint-plugin-react-hooks": "4.6.0", "prettier": "2.8.1", + "sass": "1.56.2", "typescript": "4.9.4", - "vite": "5.4.19", + "vite": "5.0.13", "vite-plugin-pwa": "0.20.5", "vite-plugin-static-copy": "1.0.4", "vite-plugin-top-level-await": "1.4.4" @@ -2256,19 +2261,17 @@ } }, "node_modules/@matrix-org/matrix-sdk-crypto-wasm": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-14.1.0.tgz", - "integrity": "sha512-vcSxHJIr6lP0Fgo8jl0sTHg+OZxZn+skGjiyB62erfgw/R2QqJl0ZVSY8SRcbk9LtHo/ZGld1tnaOyjL2e3cLQ==", - "license": "Apache-2.0", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-11.1.0.tgz", + "integrity": "sha512-JPuO9RCVDklDjbFzMvZfQb7PuiFkLY72bniRSu81lRzkkrcbZtmKqBFMm9H4f2FSz+tHVkDnmsvn12I4sdJJ5A==", "engines": { - "node": ">= 18" + "node": ">= 10" } }, "node_modules/@matrix-org/olm": { "version": "3.2.15", "resolved": "https://registry.npmjs.org/@matrix-org/olm/-/olm-3.2.15.tgz", - "integrity": "sha512-S7lOrndAK9/8qOtaTq/WhttJC/o4GAzdfK0MUPpo8ApzsJEC0QjtwrkC3KBXdFP1cD1MXi/mlKR7aaoVMKgs6Q==", - "license": "Apache-2.0" + "integrity": "sha512-S7lOrndAK9/8qOtaTq/WhttJC/o4GAzdfK0MUPpo8ApzsJEC0QjtwrkC3KBXdFP1cD1MXi/mlKR7aaoVMKgs6Q==" }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -2305,6 +2308,15 @@ "node": ">= 8" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@react-aria/breadcrumbs": { "version": "3.5.20", "resolved": "https://registry.npmjs.org/@react-aria/breadcrumbs/-/breadcrumbs-3.5.20.tgz", @@ -4507,6 +4519,18 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tippyjs/react": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz", + "integrity": "sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw==", + "dependencies": { + "tippy.js": "^6.3.1" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -4548,13 +4572,6 @@ "@babel/types": "^7.20.7" } }, - "node_modules/@types/chroma-js": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-3.1.1.tgz", - "integrity": "sha512-SFCr4edNkZ1bGaLzGz7rgR1bRzVX4MmMxwsIa3/Bh6ose8v+hRpneoizHv0KChdjxaXyjRtaMq7sCuZSzPomQA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -4563,8 +4580,7 @@ "node_modules/@types/events": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.3.tgz", - "integrity": "sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==", - "license": "MIT" + "integrity": "sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==" }, "node_modules/@types/file-saver": { "version": "2.0.5", @@ -4572,6 +4588,15 @@ "integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==", "dev": true }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz", + "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/is-hotkey": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/@types/is-hotkey/-/is-hotkey-0.1.10.tgz", @@ -4605,14 +4630,12 @@ "node_modules/@types/prop-types": { "version": "15.7.14", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", - "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", - "dev": true + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==" }, "node_modules/@types/react": { "version": "18.2.39", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.39.tgz", "integrity": "sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==", - "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4646,8 +4669,7 @@ "node_modules/@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "license": "MIT" + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, "node_modules/@types/sanitize-html": { "version": "2.9.0", @@ -4661,8 +4683,7 @@ "node_modules/@types/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==", - "dev": true + "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==" }, "node_modules/@types/semver": { "version": "7.5.8", @@ -5058,8 +5079,7 @@ "node_modules/another-json": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/another-json/-/another-json-0.2.0.tgz", - "integrity": "sha512-/Ndrl68UQLhnCdsAzEXLMFuOR546o2qbYRqCglaNHbjXrwG1ayTcdwr3zkSGOGtGXDyR5X9nCFfnyG2AFJIsqg==", - "license": "Apache-2.0" + "integrity": "sha512-/Ndrl68UQLhnCdsAzEXLMFuOR546o2qbYRqCglaNHbjXrwG1ayTcdwr3zkSGOGtGXDyR5X9nCFfnyG2AFJIsqg==" }, "node_modules/ansi-regex": { "version": "5.0.1", @@ -5285,6 +5305,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, "node_modules/ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", @@ -5306,6 +5331,11 @@ "node": ">= 4.0.0" } }, + "node_modules/autosize": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/autosize/-/autosize-4.0.4.tgz", + "integrity": "sha512-5yxLQ22O0fCRGoxGfeLSNt3J8LB1v+umtpMnPW6XjkTWXKoN0AmXAIhelJcDtFT/Y/wYWmfE+oqU10Q0b8FhaQ==" + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -5392,12 +5422,6 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/badwords-list": { - "version": "2.0.1-4", - "resolved": "https://registry.npmjs.org/badwords-list/-/badwords-list-2.0.1-4.tgz", - "integrity": "sha512-FxfZUp7B9yCnesNtFQS9v6PvZdxTYa14Q60JR6vhjdQdWI4naTjJIyx22JzoER8ooeT8SAAKoHLjKfCV7XgYUQ==", - "license": "MIT" - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -5405,10 +5429,9 @@ "devOptional": true }, "node_modules/base-x": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", - "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", - "license": "MIT" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.0.tgz", + "integrity": "sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -5514,7 +5537,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", - "license": "MIT", "dependencies": { "base-x": "^5.0.0" } @@ -5707,12 +5729,6 @@ "node": ">=10" } }, - "node_modules/chroma-js": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-3.1.2.tgz", - "integrity": "sha512-IJnETTalXbsLx1eKEgx19d5L6SRM7cH4vINw/99p/M11HCuXGRWL+6YmCm7FWFGIo6dtWuQoQi1dc5yQ7ESIHg==", - "license": "(BSD-3-Clause AND Apache-2.0)" - }, "node_modules/classnames": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", @@ -5785,6 +5801,11 @@ "integrity": "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==", "license": "MIT" }, + "node_modules/computed-style": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/computed-style/-/computed-style-0.1.4.tgz", + "integrity": "sha512-WpAmaKbMNmS3OProfHIdJiNleNJdgUrJfbKArXua28QF7+0CoZjlLn0lp6vlc+dl5r2/X9GQiQRQQU4BzSa69w==" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -5812,7 +5833,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5846,6 +5866,14 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -6956,11 +6984,15 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "license": "MIT", "engines": { "node": ">=0.8.x" } }, + "node_modules/exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -7032,6 +7064,33 @@ "reusify": "^1.0.4" } }, + "node_modules/fbemitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", + "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", + "dependencies": { + "fbjs": "^3.0.0" + } + }, + "node_modules/fbjs": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", + "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", + "dependencies": { + "cross-fetch": "^3.1.5", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^1.0.35" + } + }, + "node_modules/fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + }, "node_modules/fdir": { "version": "6.4.3", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", @@ -7140,6 +7199,18 @@ "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "dev": true }, + "node_modules/flux": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.3.tgz", + "integrity": "sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==", + "dependencies": { + "fbemitter": "^3.0.0", + "fbjs": "^3.0.1" + }, + "peerDependencies": { + "react": "^15.0.2 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/focus-trap": { "version": "7.6.4", "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.4.tgz", @@ -7163,16 +7234,15 @@ } }, "node_modules/folds": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/folds/-/folds-2.3.0.tgz", - "integrity": "sha512-1KoM21jrg5daxvKrmSY0V04wa946KlNT0z6h017Rsnw2fdtNC6J0f34Ce5GF46Tzi00gZ/7SvCDXMzW/7e5s0w==", - "license": "Apache-2.0", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/folds/-/folds-2.1.0.tgz", + "integrity": "sha512-KwAG8bH3jsyZ9FKPMg+6ABV2YOcpp4nL0cCelsalnaPeRThkc5fgG1Xj5mhmdffYKjEXpEbERi5qmGbepgJryg==", "peerDependencies": { - "@vanilla-extract/css": "1.9.2", - "@vanilla-extract/recipes": "0.3.0", - "classnames": "2.3.2", - "react": "17.0.0", - "react-dom": "17.0.0" + "@vanilla-extract/css": "^1.9.2", + "@vanilla-extract/recipes": "^0.3.0", + "classnames": "^2.3.2", + "react": "^17.0.0", + "react-dom": "^17.0.0" } }, "node_modules/for-each": { @@ -7184,6 +7254,38 @@ "is-callable": "^1.1.3" } }, + "node_modules/formik": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.6.tgz", + "integrity": "sha512-A+2EI7U7aG296q2TLGvNapDNTZp1khVt5Vk0Q/fyfSROss0V/V6+txt2aJnwEos44IxTCW/LYAi/zgWzlevj+g==", + "funding": [ + { + "type": "individual", + "url": "https://opencollective.com/formik" + } + ], + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.1", + "deepmerge": "^2.1.1", + "hoist-non-react-statics": "^3.3.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-fast-compare": "^2.0.1", + "tiny-warning": "^1.0.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/formik/node_modules/deepmerge": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", + "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fs-extra": { "version": "11.3.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", @@ -7762,6 +7864,12 @@ "url": "https://opencollective.com/immer" } }, + "node_modules/immutable": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -8434,7 +8542,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", - "license": "MIT", "engines": { "node": ">=18" } @@ -8496,6 +8603,17 @@ "node": ">=10" } }, + "node_modules/line-height": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/line-height/-/line-height-0.3.1.tgz", + "integrity": "sha512-YExecgqPwnp5gplD2+Y8e8A5+jKpr25+DzMbFdI1/1UAr0FJrTFv4VkHLf8/6B590i1wUPJWMKKldkd/bdQ//w==", + "dependencies": { + "computed-style": "~0.1.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/linkify-react": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/linkify-react/-/linkify-react-4.1.3.tgz", @@ -8529,6 +8647,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -8551,7 +8674,6 @@ "version": "1.9.2", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", - "license": "MIT", "engines": { "node": ">= 0.6.0" }, @@ -8627,23 +8749,21 @@ "node_modules/matrix-events-sdk": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz", - "integrity": "sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==", - "license": "Apache-2.0" + "integrity": "sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==" }, "node_modules/matrix-js-sdk": { - "version": "37.5.0", - "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-37.5.0.tgz", - "integrity": "sha512-5tyuAi5hnKud1UkVq8Z2/3c22hWGELBZzErJPZkE6Hju2uGUfGtrIx6uj6puv0ZjvsUU3X6Qgm8vdReKO1PGig==", - "license": "Apache-2.0", + "version": "35.0.0", + "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-35.0.0.tgz", + "integrity": "sha512-X8hIsd/8x1SC9vRr8DiNKQxmdrfRujtvEWPz8mY4FxVDJG8HEGDHvqUmaSy2jrtnOUn4oHzGQVLFO3DnhsSf8w==", "dependencies": { "@babel/runtime": "^7.12.5", - "@matrix-org/matrix-sdk-crypto-wasm": "^14.0.1", + "@matrix-org/matrix-sdk-crypto-wasm": "^11.0.0", "@matrix-org/olm": "3.2.15", "another-json": "^0.2.0", "bs58": "^6.0.0", "content-type": "^1.0.4", "jwt-decode": "^4.0.0", - "loglevel": "^1.9.2", + "loglevel": "^1.7.1", "matrix-events-sdk": "0.0.1", "matrix-widget-api": "^1.10.0", "oidc-client-ts": "^3.0.1", @@ -8657,23 +8777,21 @@ } }, "node_modules/matrix-js-sdk/node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz", + "integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "license": "MIT", "bin": { "uuid": "dist/esm/bin/uuid" } }, "node_modules/matrix-widget-api": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/matrix-widget-api/-/matrix-widget-api-1.13.1.tgz", - "integrity": "sha512-mkOHUVzaN018TCbObfGOSaMW2GoUxOfcxNNlTVx5/HeMk3OSQPQM0C9oEME5Liiv/dBUoSrEB64V8wF7e/gb1w==", - "license": "Apache-2.0", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/matrix-widget-api/-/matrix-widget-api-1.12.0.tgz", + "integrity": "sha512-6JRd9fJGGvuBRhcTg9wX+Skn/Q1wox3jdp5yYQKJ6pPw4urW9bkTR90APBKVDB1vorJKT44jml+lCzkDMRBjww==", "dependencies": { "@types/events": "^3.0.0", "events": "^3.2.0" @@ -9065,10 +9183,9 @@ } }, "node_modules/oidc-client-ts": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-3.2.1.tgz", - "integrity": "sha512-hS5AJ5s/x4bXhHvNJT1v+GGvzHUwdRWqNQQbSrp10L1IRmzfRGKQ3VWN3dstJb+oF3WtAyKezwD2+dTEIyBiAA==", - "license": "Apache-2.0", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-3.1.0.tgz", + "integrity": "sha512-IDopEXjiwjkmJLYZo6BTlvwOtnlSniWZkKZoXforC/oLZHC9wkIxd25Kwtmo5yKFMMVcsp3JY6bhcNJqdYk8+g==", "dependencies": { "jwt-decode": "^4.0.0" }, @@ -9156,7 +9273,6 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "license": "MIT", "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" @@ -9377,14 +9493,21 @@ } }, "node_modules/prismjs": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", - "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", - "license": "MIT", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", "engines": { "node": ">=6" } }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dependencies": { + "asap": "~2.0.3" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -9508,6 +9631,20 @@ "react": ">=16.4.1" } }, + "node_modules/react-autosize-textarea": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/react-autosize-textarea/-/react-autosize-textarea-7.1.0.tgz", + "integrity": "sha512-BHpjCDkuOlllZn3nLazY2F8oYO1tS2jHnWhcjTWQdcKiiMU6gHLNt/fzmqMSyerR0eTdKtfSIqtSeTtghNwS+g==", + "dependencies": { + "autosize": "^4.0.2", + "line-height": "^0.3.1", + "prop-types": "^15.5.6" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16.0.0", + "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0" + } + }, "node_modules/react-blurhash": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/react-blurhash/-/react-blurhash-0.2.0.tgz", @@ -9517,16 +9654,6 @@ "react": ">=15" } }, - "node_modules/react-colorful": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", - "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", - "license": "MIT", - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -9550,6 +9677,11 @@ "react": ">=16.13.1" } }, + "node_modules/react-fast-compare": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", + "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" + }, "node_modules/react-google-recaptcha": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-2.1.0.tgz", @@ -9588,6 +9720,29 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-modal": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz", + "integrity": "sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==", + "dependencies": { + "exenv": "^1.2.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.0", + "warning": "^4.0.3" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18", + "react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18" + } + }, "node_modules/react-property": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-property/-/react-property-2.0.0.tgz", @@ -9870,7 +10025,6 @@ "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "license": "MIT", "engines": { "node": ">= 4" } @@ -10046,6 +10200,23 @@ "postcss": "^8.3.11" } }, + "node_modules/sass": { + "version": "1.56.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.2.tgz", + "integrity": "sha512-ciEJhnyCRwzlBCB+h5cCPM6ie/6f8HrhZMQOf5vlU60Y1bI1rx5Zb0vlDZvaycHsg/MqFfF1Eq2eokAa32iw8w==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -10067,7 +10238,6 @@ "version": "2.15.0", "resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.15.0.tgz", "integrity": "sha512-KrOH82c/W+GYQ0LHqtr3caRpM3ITglq3ljGUIb8LTki7ByacJZ9z+piSGiwZDsRyhQbYBOBJgr2k6X4BZXi3Kw==", - "license": "MIT", "bin": { "sdp-verify": "checker.js" } @@ -10145,6 +10315,11 @@ "node": ">= 0.4" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -10741,6 +10916,14 @@ "node": ">=12.0.0" } }, + "node_modules/tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", + "dependencies": { + "@popperjs/core": "^2.9.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -10963,8 +11146,7 @@ "node_modules/unhomoglyph": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/unhomoglyph/-/unhomoglyph-1.0.6.tgz", - "integrity": "sha512-7uvcWI3hWshSADBu4JpnyYbTVc7YlhF5GDW/oPD5AxIxl34k4wXR3WDkPnzLxkN32LiTCTKMQLtKVZiwki3zGg==", - "license": "MIT" + "integrity": "sha512-7uvcWI3hWshSADBu4JpnyYbTVc7YlhF5GDW/oPD5AxIxl34k4wXR3WDkPnzLxkN32LiTCTKMQLtKVZiwki3zGg==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", @@ -11095,14 +11277,13 @@ } }, "node_modules/vite": { - "version": "5.4.19", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", - "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", - "license": "MIT", + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.13.tgz", + "integrity": "sha512-/9ovhv2M2dGTuA+dY93B9trfyWMDRQw2jdVBhHNP6wr0oF34wG2i/N55801iZIpgUpnHDm4F/FabGQLyc+eOgg==", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.19.3", + "postcss": "^8.4.32", + "rollup": "^4.2.0" }, "bin": { "vite": "bin/vite.js" @@ -11121,7 +11302,6 @@ "less": "*", "lightningcss": "^1.21.0", "sass": "*", - "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -11139,9 +11319,6 @@ "sass": { "optional": true }, - "sass-embedded": { - "optional": true - }, "stylus": { "optional": true }, @@ -11241,412 +11418,6 @@ "vite": ">=2.8" } }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", @@ -11655,6 +11426,14 @@ "node": ">=0.10.0" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/package.json b/package.json index 5a2356f4..aea713ed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cinny", - "version": "4.10.0", + "version": "4.5.1", "description": "Yet another matrix client", "main": "index.js", "type": "module", @@ -24,17 +24,17 @@ "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "1.3.0", "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.0.3", "@fontsource/inter": "4.5.14", + "@matrix-org/olm": "3.2.15", "@tanstack/react-query": "5.24.1", "@tanstack/react-query-devtools": "5.24.1", "@tanstack/react-virtual": "3.2.0", + "@tippyjs/react": "4.2.6", "@vanilla-extract/css": "1.9.3", "@vanilla-extract/recipes": "0.3.0", "@vanilla-extract/vite-plugin": "3.7.1", "await-to-js": "3.0.0", - "badwords-list": "2.0.1-4", "blurhash": "2.0.4", "browser-encrypt-attachment": "0.3.0", - "chroma-js": "3.1.2", "classnames": "2.3.2", "dateformat": "5.0.3", "dayjs": "1.11.10", @@ -42,8 +42,10 @@ "emojibase": "15.3.1", "emojibase-data": "15.3.2", "file-saver": "2.0.5", + "flux": "4.0.3", "focus-trap-react": "10.0.2", - "folds": "2.3.0", + "folds": "2.1.0", + "formik": "2.4.6", "html-dom-parser": "4.0.0", "html-react-parser": "4.2.0", "i18next": "23.12.2", @@ -54,18 +56,20 @@ "jotai": "2.6.0", "linkify-react": "4.1.3", "linkifyjs": "4.1.3", - "matrix-js-sdk": "37.5.0", + "matrix-js-sdk": "35.0.0", "millify": "6.1.0", "pdfjs-dist": "4.2.67", - "prismjs": "1.30.0", + "prismjs": "1.29.0", + "prop-types": "15.8.1", "react": "18.2.0", "react-aria": "3.29.1", + "react-autosize-textarea": "7.1.0", "react-blurhash": "0.2.0", - "react-colorful": "5.6.1", "react-dom": "18.2.0", "react-error-boundary": "4.0.13", "react-google-recaptcha": "2.1.0", "react-i18next": "15.0.0", + "react-modal": "3.16.1", "react-range": "1.8.14", "react-router-dom": "6.20.0", "sanitize-html": "2.12.1", @@ -73,13 +77,13 @@ "slate-dom": "0.112.2", "slate-history": "0.110.3", "slate-react": "0.112.1", + "tippy.js": "6.3.7", "ua-parser-js": "1.0.35" }, "devDependencies": { "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@rollup/plugin-inject": "5.0.3", "@rollup/plugin-wasm": "6.1.1", - "@types/chroma-js": "3.1.1", "@types/file-saver": "2.0.5", "@types/is-hotkey": "0.1.10", "@types/node": "18.11.18", @@ -101,8 +105,9 @@ "eslint-plugin-react": "7.31.11", "eslint-plugin-react-hooks": "4.6.0", "prettier": "2.8.1", + "sass": "1.56.2", "typescript": "4.9.4", - "vite": "5.4.19", + "vite": "5.0.13", "vite-plugin-pwa": "0.20.5", "vite-plugin-static-copy": "1.0.4", "vite-plugin-top-level-await": "1.4.4" diff --git a/public/res/ic/filled/category.svg b/public/res/ic/filled/category.svg new file mode 100644 index 00000000..87b2588d --- /dev/null +++ b/public/res/ic/filled/category.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + diff --git a/public/res/ic/filled/pin.svg b/public/res/ic/filled/pin.svg new file mode 100644 index 00000000..6a701474 --- /dev/null +++ b/public/res/ic/filled/pin.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/public/res/ic/filled/star.svg b/public/res/ic/filled/star.svg new file mode 100644 index 00000000..378c891e --- /dev/null +++ b/public/res/ic/filled/star.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/public/res/ic/outlined/add-pin.svg b/public/res/ic/outlined/add-pin.svg new file mode 100644 index 00000000..9634bede --- /dev/null +++ b/public/res/ic/outlined/add-pin.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/add-user.svg b/public/res/ic/outlined/add-user.svg new file mode 100644 index 00000000..c3803d80 --- /dev/null +++ b/public/res/ic/outlined/add-user.svg @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/public/res/ic/outlined/ball.svg b/public/res/ic/outlined/ball.svg new file mode 100644 index 00000000..d4b89ff5 --- /dev/null +++ b/public/res/ic/outlined/ball.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/public/res/ic/outlined/bell-off.svg b/public/res/ic/outlined/bell-off.svg new file mode 100644 index 00000000..79ce8a33 --- /dev/null +++ b/public/res/ic/outlined/bell-off.svg @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/public/res/ic/outlined/bell-ping.svg b/public/res/ic/outlined/bell-ping.svg new file mode 100644 index 00000000..3431bea1 --- /dev/null +++ b/public/res/ic/outlined/bell-ping.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/public/res/ic/outlined/bell-ring.svg b/public/res/ic/outlined/bell-ring.svg new file mode 100644 index 00000000..57fc2679 --- /dev/null +++ b/public/res/ic/outlined/bell-ring.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/public/res/ic/outlined/bell.svg b/public/res/ic/outlined/bell.svg new file mode 100644 index 00000000..43d470b5 --- /dev/null +++ b/public/res/ic/outlined/bell.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/bin.svg b/public/res/ic/outlined/bin.svg new file mode 100644 index 00000000..984be625 --- /dev/null +++ b/public/res/ic/outlined/bin.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/public/res/ic/outlined/bulb.svg b/public/res/ic/outlined/bulb.svg new file mode 100644 index 00000000..00e80886 --- /dev/null +++ b/public/res/ic/outlined/bulb.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/public/res/ic/outlined/category.svg b/public/res/ic/outlined/category.svg new file mode 100644 index 00000000..c7c33b38 --- /dev/null +++ b/public/res/ic/outlined/category.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/public/res/ic/outlined/check.svg b/public/res/ic/outlined/check.svg new file mode 100644 index 00000000..72a18327 --- /dev/null +++ b/public/res/ic/outlined/check.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/public/res/ic/outlined/chevron-bottom.svg b/public/res/ic/outlined/chevron-bottom.svg new file mode 100644 index 00000000..5562b7aa --- /dev/null +++ b/public/res/ic/outlined/chevron-bottom.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/public/res/ic/outlined/chevron-left.svg b/public/res/ic/outlined/chevron-left.svg new file mode 100644 index 00000000..ba9e12cc --- /dev/null +++ b/public/res/ic/outlined/chevron-left.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/public/res/ic/outlined/chevron-right.svg b/public/res/ic/outlined/chevron-right.svg new file mode 100644 index 00000000..7f6a806e --- /dev/null +++ b/public/res/ic/outlined/chevron-right.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/public/res/ic/outlined/chevron-top.svg b/public/res/ic/outlined/chevron-top.svg new file mode 100644 index 00000000..f5948fe9 --- /dev/null +++ b/public/res/ic/outlined/chevron-top.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/public/res/ic/outlined/circle-plus.svg b/public/res/ic/outlined/circle-plus.svg new file mode 100644 index 00000000..41690a08 --- /dev/null +++ b/public/res/ic/outlined/circle-plus.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/cmd.svg b/public/res/ic/outlined/cmd.svg new file mode 100644 index 00000000..75ae0d98 --- /dev/null +++ b/public/res/ic/outlined/cmd.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/public/res/ic/outlined/coin.svg b/public/res/ic/outlined/coin.svg new file mode 100644 index 00000000..025424e8 --- /dev/null +++ b/public/res/ic/outlined/coin.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/cross.svg b/public/res/ic/outlined/cross.svg new file mode 100644 index 00000000..0acda884 --- /dev/null +++ b/public/res/ic/outlined/cross.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/public/res/ic/outlined/cup.svg b/public/res/ic/outlined/cup.svg new file mode 100644 index 00000000..8921e2c9 --- /dev/null +++ b/public/res/ic/outlined/cup.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/public/res/ic/outlined/dog.svg b/public/res/ic/outlined/dog.svg new file mode 100644 index 00000000..3b252956 --- /dev/null +++ b/public/res/ic/outlined/dog.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/public/res/ic/outlined/download.svg b/public/res/ic/outlined/download.svg new file mode 100644 index 00000000..677014f3 --- /dev/null +++ b/public/res/ic/outlined/download.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/public/res/ic/outlined/emoji-add.svg b/public/res/ic/outlined/emoji-add.svg new file mode 100644 index 00000000..c4cacef2 --- /dev/null +++ b/public/res/ic/outlined/emoji-add.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/public/res/ic/outlined/emoji.svg b/public/res/ic/outlined/emoji.svg new file mode 100644 index 00000000..0daac879 --- /dev/null +++ b/public/res/ic/outlined/emoji.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/public/res/ic/outlined/explore.svg b/public/res/ic/outlined/explore.svg new file mode 100644 index 00000000..7cc2a479 --- /dev/null +++ b/public/res/ic/outlined/explore.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/external.svg b/public/res/ic/outlined/external.svg new file mode 100644 index 00000000..adade1bd --- /dev/null +++ b/public/res/ic/outlined/external.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/res/ic/outlined/eye-blind.svg b/public/res/ic/outlined/eye-blind.svg new file mode 100644 index 00000000..fbc8e2ae --- /dev/null +++ b/public/res/ic/outlined/eye-blind.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/res/ic/outlined/eye.svg b/public/res/ic/outlined/eye.svg new file mode 100644 index 00000000..1ce868bf --- /dev/null +++ b/public/res/ic/outlined/eye.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/res/ic/outlined/file.svg b/public/res/ic/outlined/file.svg new file mode 100644 index 00000000..d6a2a27a --- /dev/null +++ b/public/res/ic/outlined/file.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/public/res/ic/outlined/flag.svg b/public/res/ic/outlined/flag.svg new file mode 100644 index 00000000..8fce98d6 --- /dev/null +++ b/public/res/ic/outlined/flag.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/public/res/ic/outlined/hash-globe.svg b/public/res/ic/outlined/hash-globe.svg new file mode 100644 index 00000000..ce3df083 --- /dev/null +++ b/public/res/ic/outlined/hash-globe.svg @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/hash-lock.svg b/public/res/ic/outlined/hash-lock.svg new file mode 100644 index 00000000..ae263ced --- /dev/null +++ b/public/res/ic/outlined/hash-lock.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/hash-plus.svg b/public/res/ic/outlined/hash-plus.svg new file mode 100644 index 00000000..69737fd5 --- /dev/null +++ b/public/res/ic/outlined/hash-plus.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/public/res/ic/outlined/hash-search.svg b/public/res/ic/outlined/hash-search.svg new file mode 100644 index 00000000..f135e898 --- /dev/null +++ b/public/res/ic/outlined/hash-search.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/hash-shield.svg b/public/res/ic/outlined/hash-shield.svg new file mode 100644 index 00000000..dfd344b1 --- /dev/null +++ b/public/res/ic/outlined/hash-shield.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/hash.svg b/public/res/ic/outlined/hash.svg new file mode 100644 index 00000000..dcb8b964 --- /dev/null +++ b/public/res/ic/outlined/hash.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/public/res/ic/outlined/heart.svg b/public/res/ic/outlined/heart.svg new file mode 100644 index 00000000..c5b940b6 --- /dev/null +++ b/public/res/ic/outlined/heart.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/public/res/ic/outlined/home.svg b/public/res/ic/outlined/home.svg new file mode 100644 index 00000000..3c7a02df --- /dev/null +++ b/public/res/ic/outlined/home.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/horizontal-menu.svg b/public/res/ic/outlined/horizontal-menu.svg new file mode 100644 index 00000000..a19b3c35 --- /dev/null +++ b/public/res/ic/outlined/horizontal-menu.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/public/res/ic/outlined/inbox.svg b/public/res/ic/outlined/inbox.svg new file mode 100644 index 00000000..65435876 --- /dev/null +++ b/public/res/ic/outlined/inbox.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/public/res/ic/outlined/info.svg b/public/res/ic/outlined/info.svg new file mode 100644 index 00000000..30a57887 --- /dev/null +++ b/public/res/ic/outlined/info.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/public/res/ic/outlined/invite-arrow.svg b/public/res/ic/outlined/invite-arrow.svg new file mode 100644 index 00000000..370bf8e8 --- /dev/null +++ b/public/res/ic/outlined/invite-arrow.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/invite-cancel-arrow.svg b/public/res/ic/outlined/invite-cancel-arrow.svg new file mode 100644 index 00000000..795a773a --- /dev/null +++ b/public/res/ic/outlined/invite-cancel-arrow.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/invite.svg b/public/res/ic/outlined/invite.svg new file mode 100644 index 00000000..3896e15e --- /dev/null +++ b/public/res/ic/outlined/invite.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/join-arrow.svg b/public/res/ic/outlined/join-arrow.svg new file mode 100644 index 00000000..90cfa651 --- /dev/null +++ b/public/res/ic/outlined/join-arrow.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/public/res/ic/outlined/leave-arrow.svg b/public/res/ic/outlined/leave-arrow.svg new file mode 100644 index 00000000..a51ac1d1 --- /dev/null +++ b/public/res/ic/outlined/leave-arrow.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/public/res/ic/outlined/lock.svg b/public/res/ic/outlined/lock.svg new file mode 100644 index 00000000..77021f0f --- /dev/null +++ b/public/res/ic/outlined/lock.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/markdown.svg b/public/res/ic/outlined/markdown.svg new file mode 100644 index 00000000..775afbfb --- /dev/null +++ b/public/res/ic/outlined/markdown.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/message-unread.svg b/public/res/ic/outlined/message-unread.svg new file mode 100644 index 00000000..fc5e9ff0 --- /dev/null +++ b/public/res/ic/outlined/message-unread.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/public/res/ic/outlined/message.svg b/public/res/ic/outlined/message.svg new file mode 100644 index 00000000..d36e9a30 --- /dev/null +++ b/public/res/ic/outlined/message.svg @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/public/res/ic/outlined/pause.svg b/public/res/ic/outlined/pause.svg new file mode 100644 index 00000000..c312613b --- /dev/null +++ b/public/res/ic/outlined/pause.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/public/res/ic/outlined/peace.svg b/public/res/ic/outlined/peace.svg new file mode 100644 index 00000000..8a7c81a3 --- /dev/null +++ b/public/res/ic/outlined/peace.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/public/res/ic/outlined/pencil.svg b/public/res/ic/outlined/pencil.svg new file mode 100644 index 00000000..1b8ac24a --- /dev/null +++ b/public/res/ic/outlined/pencil.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/public/res/ic/outlined/photo.svg b/public/res/ic/outlined/photo.svg new file mode 100644 index 00000000..af01a330 --- /dev/null +++ b/public/res/ic/outlined/photo.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/pin.svg b/public/res/ic/outlined/pin.svg new file mode 100644 index 00000000..211242cd --- /dev/null +++ b/public/res/ic/outlined/pin.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/public/res/ic/outlined/play.svg b/public/res/ic/outlined/play.svg new file mode 100644 index 00000000..87b3a8f6 --- /dev/null +++ b/public/res/ic/outlined/play.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/plus.svg b/public/res/ic/outlined/plus.svg new file mode 100644 index 00000000..ce37594e --- /dev/null +++ b/public/res/ic/outlined/plus.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/public/res/ic/outlined/power.svg b/public/res/ic/outlined/power.svg new file mode 100644 index 00000000..8aeb6db8 --- /dev/null +++ b/public/res/ic/outlined/power.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/recent-clock.svg b/public/res/ic/outlined/recent-clock.svg new file mode 100644 index 00000000..30b10d59 --- /dev/null +++ b/public/res/ic/outlined/recent-clock.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/public/res/ic/outlined/reply-arrow.svg b/public/res/ic/outlined/reply-arrow.svg new file mode 100644 index 00000000..3cda01cd --- /dev/null +++ b/public/res/ic/outlined/reply-arrow.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/public/res/ic/outlined/search.svg b/public/res/ic/outlined/search.svg new file mode 100644 index 00000000..75dd6320 --- /dev/null +++ b/public/res/ic/outlined/search.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/public/res/ic/outlined/send.svg b/public/res/ic/outlined/send.svg new file mode 100644 index 00000000..aa487132 --- /dev/null +++ b/public/res/ic/outlined/send.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/public/res/ic/outlined/settings.svg b/public/res/ic/outlined/settings.svg new file mode 100644 index 00000000..ee640b39 --- /dev/null +++ b/public/res/ic/outlined/settings.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/public/res/ic/outlined/shield-empty.svg b/public/res/ic/outlined/shield-empty.svg new file mode 100644 index 00000000..6bc9d304 --- /dev/null +++ b/public/res/ic/outlined/shield-empty.svg @@ -0,0 +1,7 @@ + + + + + + diff --git a/public/res/ic/outlined/shield-user.svg b/public/res/ic/outlined/shield-user.svg new file mode 100644 index 00000000..bd5f07c5 --- /dev/null +++ b/public/res/ic/outlined/shield-user.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/public/res/ic/outlined/shield.svg b/public/res/ic/outlined/shield.svg new file mode 100644 index 00000000..9bb46fa1 --- /dev/null +++ b/public/res/ic/outlined/shield.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/space-globe.svg b/public/res/ic/outlined/space-globe.svg new file mode 100644 index 00000000..63d71f1d --- /dev/null +++ b/public/res/ic/outlined/space-globe.svg @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/space-lock.svg b/public/res/ic/outlined/space-lock.svg new file mode 100644 index 00000000..b15705ca --- /dev/null +++ b/public/res/ic/outlined/space-lock.svg @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/space-plus.svg b/public/res/ic/outlined/space-plus.svg new file mode 100644 index 00000000..4d69a1ef --- /dev/null +++ b/public/res/ic/outlined/space-plus.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/space.svg b/public/res/ic/outlined/space.svg new file mode 100644 index 00000000..a4b54b3e --- /dev/null +++ b/public/res/ic/outlined/space.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/public/res/ic/outlined/star.svg b/public/res/ic/outlined/star.svg new file mode 100644 index 00000000..290f159a --- /dev/null +++ b/public/res/ic/outlined/star.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/public/res/ic/outlined/sticker.svg b/public/res/ic/outlined/sticker.svg new file mode 100644 index 00000000..bc486e5e --- /dev/null +++ b/public/res/ic/outlined/sticker.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/res/ic/outlined/sun.svg b/public/res/ic/outlined/sun.svg new file mode 100644 index 00000000..d8ed06fd --- /dev/null +++ b/public/res/ic/outlined/sun.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/res/ic/outlined/tick-mark.svg b/public/res/ic/outlined/tick-mark.svg new file mode 100644 index 00000000..8e76ed55 --- /dev/null +++ b/public/res/ic/outlined/tick-mark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/public/res/ic/outlined/user.svg b/public/res/ic/outlined/user.svg new file mode 100644 index 00000000..6756a1b2 --- /dev/null +++ b/public/res/ic/outlined/user.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/public/res/ic/outlined/vertical-menu.svg b/public/res/ic/outlined/vertical-menu.svg new file mode 100644 index 00000000..ec5c544c --- /dev/null +++ b/public/res/ic/outlined/vertical-menu.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/public/res/ic/outlined/vlc.svg b/public/res/ic/outlined/vlc.svg new file mode 100644 index 00000000..8a2b844f --- /dev/null +++ b/public/res/ic/outlined/vlc.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/public/res/ic/outlined/volume-full.svg b/public/res/ic/outlined/volume-full.svg new file mode 100644 index 00000000..20419e72 --- /dev/null +++ b/public/res/ic/outlined/volume-full.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/public/res/ic/outlined/volume-mute.svg b/public/res/ic/outlined/volume-mute.svg new file mode 100644 index 00000000..beb06771 --- /dev/null +++ b/public/res/ic/outlined/volume-mute.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/app/atoms/avatar/Avatar.jsx b/src/app/atoms/avatar/Avatar.jsx new file mode 100644 index 00000000..27bf7c90 --- /dev/null +++ b/src/app/atoms/avatar/Avatar.jsx @@ -0,0 +1,69 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './Avatar.scss'; + +import Text from '../text/Text'; +import RawIcon from '../system-icons/RawIcon'; + +import ImageBrokenSVG from '../../../../public/res/svg/image-broken.svg'; +import { avatarInitials } from '../../../util/common'; + +const Avatar = React.forwardRef(({ text, bgColor, iconSrc, iconColor, imageSrc, size }, ref) => { + let textSize = 's1'; + if (size === 'large') textSize = 'h1'; + if (size === 'small') textSize = 'b1'; + if (size === 'extra-small') textSize = 'b3'; + + return ( +
+ {imageSrc !== null ? ( + { + e.target.style.backgroundColor = 'transparent'; + }} + onError={(e) => { + e.target.src = ImageBrokenSVG; + }} + alt="" + /> + ) : ( + + {iconSrc !== null ? ( + + ) : ( + text !== null && ( + + {avatarInitials(text)} + + ) + )} + + )} +
+ ); +}); + +Avatar.defaultProps = { + text: null, + bgColor: 'transparent', + iconSrc: null, + iconColor: null, + imageSrc: null, + size: 'normal', +}; + +Avatar.propTypes = { + text: PropTypes.string, + bgColor: PropTypes.string, + iconSrc: PropTypes.string, + iconColor: PropTypes.string, + imageSrc: PropTypes.string, + size: PropTypes.oneOf(['large', 'normal', 'small', 'extra-small']), +}; + +export default Avatar; diff --git a/src/app/atoms/avatar/Avatar.scss b/src/app/atoms/avatar/Avatar.scss new file mode 100644 index 00000000..ea69c9e8 --- /dev/null +++ b/src/app/atoms/avatar/Avatar.scss @@ -0,0 +1,56 @@ +@use '../../partials/flex'; + +.avatar-container { + display: inline-flex; + width: 42px; + height: 42px; + border-radius: var(--bo-radius); + position: relative; + + &__large { + width: var(--av-large); + height: var(--av-large); + } + &__normal { + width: var(--av-normal); + height: var(--av-normal); + } + + &__small { + width: var(--av-small); + height: var(--av-small); + } + + &__extra-small { + width: var(--av-extra-small); + height: var(--av-extra-small); + } + + > img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: inherit; + background-color: var(--bg-surface-hover); + } + + .avatar__border { + @extend .cp-fx__row--c-c; + + position: absolute; + top: 0; + left: 0; + + width: 100%; + height: 100%; + border-radius: inherit; + + .text { + color: white; + } + &--active { + @extend .avatar__border; + box-shadow: var(--bs-surface-border); + } + } +} \ No newline at end of file diff --git a/src/app/atoms/avatar/render.js b/src/app/atoms/avatar/render.js new file mode 100644 index 00000000..e8cf1a66 --- /dev/null +++ b/src/app/atoms/avatar/render.js @@ -0,0 +1,57 @@ +import { avatarInitials, cssVar } from '../../../util/common'; + +// renders the avatar and returns it as an URL +export default async function renderAvatar({ + text, bgColor, imageSrc, size, borderRadius, scale, +}) { + try { + const canvas = document.createElement('canvas'); + canvas.width = size * scale; + canvas.height = size * scale; + + const ctx = canvas.getContext('2d'); + + ctx.scale(scale, scale); + + // rounded corners + ctx.beginPath(); + ctx.moveTo(size, size); + ctx.arcTo(0, size, 0, 0, borderRadius); + ctx.arcTo(0, 0, size, 0, borderRadius); + ctx.arcTo(size, 0, size, size, borderRadius); + ctx.arcTo(size, size, 0, size, borderRadius); + + if (imageSrc) { + // clip corners of image + ctx.closePath(); + ctx.clip(); + + const img = new Image(); + img.crossOrigin = 'anonymous'; + const promise = new Promise((resolve, reject) => { + img.onerror = reject; + img.onload = resolve; + }); + img.src = imageSrc; + await promise; + + ctx.drawImage(img, 0, 0, size, size); + } else { + // colored background + ctx.fillStyle = cssVar(bgColor); + ctx.fill(); + + // centered letter + ctx.fillStyle = '#fff'; + ctx.font = `${cssVar('--fs-s1')} ${cssVar('--font-primary')}`; + ctx.textBaseline = 'middle'; + ctx.textAlign = 'center'; + ctx.fillText(avatarInitials(text), size / 2, size / 2); + } + + return canvas.toDataURL(); + } catch (e) { + console.error(e); + return imageSrc; + } +} diff --git a/src/app/atoms/badge/NotificationBadge.jsx b/src/app/atoms/badge/NotificationBadge.jsx new file mode 100644 index 00000000..12c1bd44 --- /dev/null +++ b/src/app/atoms/badge/NotificationBadge.jsx @@ -0,0 +1,29 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './NotificationBadge.scss'; + +import Text from '../text/Text'; + +function NotificationBadge({ alert, content }) { + const notificationClass = alert ? ' notification-badge--alert' : ''; + return ( +
+ {content !== null && {content}} +
+ ); +} + +NotificationBadge.defaultProps = { + alert: false, + content: null, +}; + +NotificationBadge.propTypes = { + alert: PropTypes.bool, + content: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + ]), +}; + +export default NotificationBadge; diff --git a/src/app/atoms/badge/NotificationBadge.scss b/src/app/atoms/badge/NotificationBadge.scss new file mode 100644 index 00000000..f5cfa73f --- /dev/null +++ b/src/app/atoms/badge/NotificationBadge.scss @@ -0,0 +1,21 @@ +.notification-badge { + min-width: 16px; + min-height: 8px; + padding: 0 var(--sp-ultra-tight); + background-color: var(--bg-badge); + border-radius: var(--bo-radius); + + .text { + color: var(--tc-badge); + text-align: center; + } + + &--alert { + background-color: var(--bg-positive); + } + + &:empty { + min-width: 8px; + margin: 0 var(--sp-ultra-tight); + } +} \ No newline at end of file diff --git a/src/app/atoms/button/Button.jsx b/src/app/atoms/button/Button.jsx new file mode 100644 index 00000000..1c1c950c --- /dev/null +++ b/src/app/atoms/button/Button.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './Button.scss'; + +import Text from '../text/Text'; +import RawIcon from '../system-icons/RawIcon'; +import { blurOnBubbling } from './script'; + +const Button = React.forwardRef(({ + id, className, variant, iconSrc, + type, onClick, children, disabled, +}, ref) => { + const iconClass = (iconSrc === null) ? '' : `btn-${variant}--icon`; + return ( + + ); +}); + +Button.defaultProps = { + id: '', + className: null, + variant: 'surface', + iconSrc: null, + type: 'button', + onClick: null, + disabled: false, +}; + +Button.propTypes = { + id: PropTypes.string, + className: PropTypes.string, + variant: PropTypes.oneOf(['surface', 'primary', 'positive', 'caution', 'danger']), + iconSrc: PropTypes.string, + type: PropTypes.oneOf(['button', 'submit', 'reset']), + onClick: PropTypes.func, + children: PropTypes.node.isRequired, + disabled: PropTypes.bool, +}; + +export default Button; diff --git a/src/app/atoms/button/Button.scss b/src/app/atoms/button/Button.scss new file mode 100644 index 00000000..e1a01bb0 --- /dev/null +++ b/src/app/atoms/button/Button.scss @@ -0,0 +1,81 @@ +@use 'state'; +@use '../../partials/dir'; +@use '../../partials/text'; + +.btn-surface, +.btn-primary, +.btn-positive, +.btn-caution, +.btn-danger { + display: inline-flex; + align-items: center; + justify-content: center; + + min-width: 80px; + padding: var(--sp-extra-tight) var(--sp-normal); + background-color: transparent; + border: none; + border-radius: var(--bo-radius); + cursor: pointer; + @include state.disabled; + + & .text { + @extend .cp-txt__ellipsis; + } + + &--icon { + @include dir.side(padding, var(--sp-tight), var(--sp-loose)); + + } + .ic-raw { + @include dir.side(margin, 0, var(--sp-extra-tight)); + flex-shrink: 0; + } +} + +@mixin color($textColor, $iconColor) { + .text { + color: $textColor; + } + .ic-raw { + background-color: $iconColor; + } +} + + +.btn-surface { + box-shadow: var(--bs-surface-border); + @include color(var(--tc-surface-high), var(--ic-surface-normal)); + @include state.hover(var(--bg-surface-hover)); + @include state.focus(var(--bs-surface-outline)); + @include state.active(var(--bg-surface-active)); +} + +.btn-primary { + background-color: var(--bg-primary); + @include color(var(--tc-primary-high), var(--ic-primary-normal)); + @include state.hover(var(--bg-primary-hover)); + @include state.focus(var(--bs-primary-outline)); + @include state.active(var(--bg-primary-active)); +} +.btn-positive { + box-shadow: var(--bs-positive-border); + @include color(var(--tc-positive-high), var(--ic-positive-normal)); + @include state.hover(var(--bg-positive-hover)); + @include state.focus(var(--bs-positive-outline)); + @include state.active(var(--bg-positive-active)); +} +.btn-caution { + box-shadow: var(--bs-caution-border); + @include color(var(--tc-caution-high), var(--ic-caution-normal)); + @include state.hover(var(--bg-caution-hover)); + @include state.focus(var(--bs-caution-outline)); + @include state.active(var(--bg-caution-active)); +} +.btn-danger { + box-shadow: var(--bs-danger-border); + @include color(var(--tc-danger-high), var(--ic-danger-normal)); + @include state.hover(var(--bg-danger-hover)); + @include state.focus(var(--bs-danger-outline)); + @include state.active(var(--bg-danger-active)); +} \ No newline at end of file diff --git a/src/app/atoms/button/Checkbox.jsx b/src/app/atoms/button/Checkbox.jsx new file mode 100644 index 00000000..7fcea3b5 --- /dev/null +++ b/src/app/atoms/button/Checkbox.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './Checkbox.scss'; + +function Checkbox({ + variant, isActive, onToggle, + disabled, tabIndex, +}) { + const className = `checkbox checkbox-${variant}${isActive ? ' checkbox--active' : ''}`; + if (onToggle === null) return ; + return ( + // eslint-disable-next-line jsx-a11y/control-has-associated-label + + ); + if (tooltip === null) return btn; + return ( + {tooltip}} + > + {btn} + + ); +}); + +IconButton.defaultProps = { + variant: 'surface', + size: 'normal', + type: 'button', + tooltip: null, + tooltipPlacement: 'top', + onClick: null, + tabIndex: 0, + disabled: false, + isImage: false, + className: '', +}; + +IconButton.propTypes = { + variant: PropTypes.oneOf(['surface', 'primary', 'positive', 'caution', 'danger']), + size: PropTypes.oneOf(['normal', 'small', 'extra-small']), + type: PropTypes.oneOf(['button', 'submit', 'reset']), + tooltip: PropTypes.string, + tooltipPlacement: PropTypes.oneOf(['top', 'right', 'bottom', 'left']), + src: PropTypes.string.isRequired, + onClick: PropTypes.func, + tabIndex: PropTypes.number, + disabled: PropTypes.bool, + isImage: PropTypes.bool, + className: PropTypes.string, +}; + +export default IconButton; diff --git a/src/app/atoms/button/IconButton.scss b/src/app/atoms/button/IconButton.scss new file mode 100644 index 00000000..aa6480c0 --- /dev/null +++ b/src/app/atoms/button/IconButton.scss @@ -0,0 +1,56 @@ +@use 'state'; + +.ic-btn { + padding: var(--sp-extra-tight); + border: none; + border-radius: var(--bo-radius); + background-color: transparent; + font-size: 0; + line-height: 0; + cursor: pointer; + @include state.disabled; +} + +@mixin color($color) { + .ic-raw { + background-color: $color; + } +} +@mixin focus($color) { + &:focus { + outline: none; + background-color: $color; + } +} + +.ic-btn-surface { + @include color(var(--ic-surface-normal)); + @include state.hover(var(--bg-surface-hover)); + @include focus(var(--bg-surface-hover)); + @include state.active(var(--bg-surface-active)); +} +.ic-btn-primary { + @include color(var(--ic-primary-normal)); + @include state.hover(var(--bg-primary-hover)); + @include focus(var(--bg-primary-hover)); + @include state.active(var(--bg-primary-active)); + background-color: var(--bg-primary); +} +.ic-btn-positive { + @include color(var(--ic-positive-normal)); + @include state.hover(var(--bg-positive-hover)); + @include focus(var(--bg-positive-hover)); + @include state.active(var(--bg-positive-active)); +} +.ic-btn-caution { + @include color(var(--ic-caution-normal)); + @include state.hover(var(--bg-caution-hover)); + @include focus(var(--bg-caution-hover)); + @include state.active(var(--bg-caution-active)); +} +.ic-btn-danger { + @include color(var(--ic-danger-normal)); + @include state.hover(var(--bg-danger-hover)); + @include focus(var(--bg-danger-hover)); + @include state.active(var(--bg-danger-active)); +} \ No newline at end of file diff --git a/src/app/atoms/button/RadioButton.jsx b/src/app/atoms/button/RadioButton.jsx new file mode 100644 index 00000000..35b68baf --- /dev/null +++ b/src/app/atoms/button/RadioButton.jsx @@ -0,0 +1,30 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './RadioButton.scss'; + +function RadioButton({ isActive, onToggle, disabled }) { + if (onToggle === null) return ; + return ( + // eslint-disable-next-line jsx-a11y/control-has-associated-label + + ); +} + +Chip.propTypes = { + iconSrc: PropTypes.string, + iconColor: PropTypes.string, + text: PropTypes.string, + children: PropTypes.element, + onClick: PropTypes.func, +}; + +Chip.defaultProps = { + iconSrc: null, + iconColor: null, + text: null, + children: null, + onClick: null, +}; + +export default Chip; diff --git a/src/app/atoms/chip/Chip.scss b/src/app/atoms/chip/Chip.scss new file mode 100644 index 00000000..7396b0dc --- /dev/null +++ b/src/app/atoms/chip/Chip.scss @@ -0,0 +1,31 @@ +@use '../../partials/dir'; + +.chip { + padding: var(--sp-ultra-tight) var(--sp-extra-tight); + + display: inline-flex; + flex-direction: row; + align-items: center; + + background: var(--bg-surface-low); + border-radius: var(--bo-radius); + box-shadow: var(--bs-surface-border); + cursor: pointer; + + @media (hover: hover) { + &:hover { + background-color: var(--bg-surface-hover); + } + } + + & > .text { + flex: 1; + color: var(--tc-surface-high); + } + + & > .ic-raw { + width: 16px; + height: 16px; + @include dir.side(margin, 0, var(--sp-ultra-tight)); + } +} \ No newline at end of file diff --git a/src/app/atoms/context-menu/ContextMenu.jsx b/src/app/atoms/context-menu/ContextMenu.jsx new file mode 100644 index 00000000..7d1acd44 --- /dev/null +++ b/src/app/atoms/context-menu/ContextMenu.jsx @@ -0,0 +1,115 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import './ContextMenu.scss'; + +import Tippy from '@tippyjs/react'; +import 'tippy.js/animations/scale-extreme.css'; + +import Text from '../text/Text'; +import Button from '../button/Button'; +import ScrollView from '../scroll/ScrollView'; + +function ContextMenu({ + content, placement, maxWidth, render, afterToggle, +}) { + const [isVisible, setVisibility] = useState(false); + const showMenu = () => setVisibility(true); + const hideMenu = () => setVisibility(false); + + useEffect(() => { + if (afterToggle !== null) afterToggle(isVisible); + }, [isVisible]); + + return ( + {typeof content === 'function' ? content(hideMenu) : content}} + placement={placement} + interactive + arrow={false} + maxWidth={maxWidth} + duration={200} + > + {render(isVisible ? hideMenu : showMenu)} + + ); +} + +ContextMenu.defaultProps = { + maxWidth: 'unset', + placement: 'right', + afterToggle: null, +}; + +ContextMenu.propTypes = { + content: PropTypes.oneOfType([ + PropTypes.node, + PropTypes.func, + ]).isRequired, + placement: PropTypes.oneOf(['top', 'right', 'bottom', 'left']), + maxWidth: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + ]), + render: PropTypes.func.isRequired, + afterToggle: PropTypes.func, +}; + +function MenuHeader({ children }) { + return ( +
+ { children } +
+ ); +} + +MenuHeader.propTypes = { + children: PropTypes.node.isRequired, +}; + +function MenuItem({ + variant, iconSrc, type, + onClick, children, disabled, +}) { + return ( +
+ +
+ ); +} + +MenuItem.defaultProps = { + variant: 'surface', + iconSrc: null, + type: 'button', + disabled: false, + onClick: null, +}; + +MenuItem.propTypes = { + variant: PropTypes.oneOf(['surface', 'positive', 'caution', 'danger']), + iconSrc: PropTypes.string, + type: PropTypes.oneOf(['button', 'submit']), + onClick: PropTypes.func, + children: PropTypes.node.isRequired, + disabled: PropTypes.bool, +}; + +function MenuBorder() { + return
; +} + +export { + ContextMenu as default, MenuHeader, MenuItem, MenuBorder, +}; diff --git a/src/app/atoms/context-menu/ContextMenu.scss b/src/app/atoms/context-menu/ContextMenu.scss new file mode 100644 index 00000000..2df9f0a4 --- /dev/null +++ b/src/app/atoms/context-menu/ContextMenu.scss @@ -0,0 +1,81 @@ +@use '../../partials/flex'; +@use '../../partials/text'; +@use '../../partials/dir'; + +.context-menu { + background-color: var(--bg-surface); + box-shadow: var(--bs-popup); + border-radius: var(--bo-radius); + overflow: hidden; + + &:focus { + outline: none; + } + & .tippy-content > div > .scrollbar { + max-height: 90vh; + } +} + +.context-menu__click-wrapper { + display: inline-flex; + + &:focus { + outline: none; + } +} + +.context-menu__header { + height: 34px; + padding: 0 var(--sp-normal); + margin-bottom: var(--sp-ultra-tight); + display: flex; + align-items: center; + border-bottom: 1px solid var(--bg-surface-border); + + .text { + @extend .cp-txt__ellipsis; + color: var(--tc-surface-low); + } + + &:not(:first-child) { + margin-top: var(--sp-extra-tight); + border-top: 1px solid var(--bg-surface-border); + } +} + +.context-menu__item { + display: flex; + button[class^="btn"] { + @extend .cp-fx__item-one; + justify-content: flex-start; + border-radius: 0; + box-shadow: none; + white-space: nowrap; + padding: var(--sp-extra-tight) var(--sp-normal); + + & > .ic-raw { + @include dir.side(margin, 0, var(--sp-tight)); + } + + // if item doesn't have icon + .text:first-child { + @include dir.side( + margin, + calc(var(--ic-small) + var(--sp-tight)), + 0 + ); + } + } + .btn-surface:focus { + background-color: var(--bg-surface-hover); + } + .btn-positive:focus { + background-color: var(--bg-positive-hover); + } + .btn-caution:focus { + background-color: var(--bg-caution-hover); + } + .btn-danger:focus { + background-color: var(--bg-danger-hover); + } +} \ No newline at end of file diff --git a/src/app/atoms/context-menu/ReusableContextMenu.jsx b/src/app/atoms/context-menu/ReusableContextMenu.jsx new file mode 100644 index 00000000..59bdb142 --- /dev/null +++ b/src/app/atoms/context-menu/ReusableContextMenu.jsx @@ -0,0 +1,87 @@ +import React, { useState, useEffect, useRef } from 'react'; + +import cons from '../../../client/state/cons'; +import navigation from '../../../client/state/navigation'; + +import ContextMenu from './ContextMenu'; + +let key = null; +function ReusableContextMenu() { + const [data, setData] = useState(null); + const openerRef = useRef(null); + + const closeMenu = () => { + key = null; + if (data) openerRef.current.click(); + }; + + useEffect(() => { + if (data) { + const { cords } = data; + openerRef.current.style.transform = `translate(${cords.x}px, ${cords.y}px)`; + openerRef.current.style.width = `${cords.width}px`; + openerRef.current.style.height = `${cords.height}px`; + openerRef.current.click(); + } + const handleContextMenuOpen = (placement, cords, render, afterClose) => { + if (key) { + closeMenu(); + return; + } + setData({ + placement, cords, render, afterClose, + }); + }; + navigation.on(cons.events.navigation.REUSABLE_CONTEXT_MENU_OPENED, handleContextMenuOpen); + return () => { + navigation.removeListener( + cons.events.navigation.REUSABLE_CONTEXT_MENU_OPENED, + handleContextMenuOpen, + ); + }; + }, [data]); + + const handleAfterToggle = (isVisible) => { + if (isVisible) { + key = Math.random(); + return; + } + data?.afterClose?.(); + if (setData) setData(null); + + if (key === null) return; + const copyKey = key; + setTimeout(() => { + if (key === copyKey) key = null; + }, 200); + }; + + return ( + ( + + )} + /> + ); +} + +export default ReusableContextMenu; diff --git a/src/app/atoms/divider/Divider.jsx b/src/app/atoms/divider/Divider.jsx new file mode 100644 index 00000000..76721241 --- /dev/null +++ b/src/app/atoms/divider/Divider.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './Divider.scss'; + +import Text from '../text/Text'; + +function Divider({ text, variant, align }) { + const dividerClass = ` divider--${variant} divider--${align}`; + return ( +
+ {text !== null && {text}} +
+ ); +} + +Divider.defaultProps = { + text: null, + variant: 'surface', + align: 'center', +}; + +Divider.propTypes = { + text: PropTypes.string, + variant: PropTypes.oneOf(['surface', 'primary', 'positive', 'caution', 'danger']), + align: PropTypes.oneOf(['left', 'center', 'right']), +}; + +export default Divider; diff --git a/src/app/atoms/divider/Divider.scss b/src/app/atoms/divider/Divider.scss new file mode 100644 index 00000000..0f013ff0 --- /dev/null +++ b/src/app/atoms/divider/Divider.scss @@ -0,0 +1,68 @@ +.divider-line { + content: ''; + display: inline-block; + flex: 1; + border-bottom: 1px solid var(--local-divider-color); + opacity: var(--local-divider-opacity); +} + +.divider { + display: flex; + align-items: center; + + &--center::before, + &--right::before { + @extend .divider-line; + } + &--center::after, + &--left::after { + @extend .divider-line; + } + + &__text { + padding: 2px var(--sp-extra-tight); + border-radius: calc(var(--bo-radius) / 2); + } +} + +.divider--surface { + --local-divider-color: var(--bg-divider); + --local-divider-opacity: 1; + + .divider__text { + color: var(--tc-surface-low); + border: 1px solid var(--bg-divider); + } +} +.divider--primary { + --local-divider-color: var(--bg-primary); + --local-divider-opacity: .8; + .divider__text { + color: var(--tc-primary-high); + background-color: var(--bg-primary); + } +} +.divider--positive { + --local-divider-color: var(--bg-positive); + --local-divider-opacity: .8; + .divider__text { + color: var(--bg-surface); + background-color: var(--bg-positive); + } +} +.divider--danger { + --local-divider-color: var(--bg-danger); + --local-divider-opacity: .8; + .divider__text { + color: var(--bg-surface); + background-color: var(--bg-danger); + } +} +.divider--caution { + --local-divider-color: var(--bg-caution); + --local-divider-opacity: .8; + .divider__text { + color: var(--bg-surface); + background-color: var(--bg-caution); + } +} diff --git a/src/app/atoms/header/Header.jsx b/src/app/atoms/header/Header.jsx new file mode 100644 index 00000000..3c81e423 --- /dev/null +++ b/src/app/atoms/header/Header.jsx @@ -0,0 +1,29 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './Header.scss'; + +function Header({ children }) { + return ( +
+ {children} +
+ ); +} + +Header.propTypes = { + children: PropTypes.node.isRequired, +}; + +function TitleWrapper({ children }) { + return ( +
+ {children} +
+ ); +} + +TitleWrapper.propTypes = { + children: PropTypes.node.isRequired, +}; + +export { Header as default, TitleWrapper }; diff --git a/src/app/atoms/header/Header.scss b/src/app/atoms/header/Header.scss new file mode 100644 index 00000000..9e45f824 --- /dev/null +++ b/src/app/atoms/header/Header.scss @@ -0,0 +1,43 @@ +@use '../../partials/text'; +@use '../../partials/dir'; + +.header { + @include dir.side(padding, var(--sp-normal), var(--sp-extra-tight)); + width: 100%; + height: var(--header-height); + border-bottom: 1px solid var(--bg-surface-border); + display: flex; + align-items: center; + + &__title-wrapper { + flex: 1; + min-width: 0; + display: flex; + align-items: center; + margin: 0 var(--sp-tight); + + &:first-child { + @include dir.side(margin, 0, var(--sp-tight)); + } + + & > .text:first-child { + @extend .cp-txt__ellipsis; + min-width: 0; + } + & > .text-b3{ + flex: 1; + min-width: 0; + + margin-top: var(--sp-ultra-tight); + @include dir.side(margin, var(--sp-tight), 0); + @include dir.side(padding, var(--sp-tight), 0); + @include dir.side(border, 1px solid var(--bg-surface-border), none); + + max-height: calc(2 * var(--lh-b3)); + overflow: hidden; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + display: -webkit-box; + } + } +} \ No newline at end of file diff --git a/src/app/atoms/input/Input.jsx b/src/app/atoms/input/Input.jsx new file mode 100644 index 00000000..96c94967 --- /dev/null +++ b/src/app/atoms/input/Input.jsx @@ -0,0 +1,97 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './Input.scss'; + +import TextareaAutosize from 'react-autosize-textarea'; + +function Input({ + id, label, name, value, placeholder, + required, type, onChange, forwardRef, + resizable, minHeight, onResize, state, + onKeyDown, disabled, autoFocus, +}) { + return ( +
+ { label !== '' && } + { resizable + ? ( + + ) : ( + + )} +
+ ); +} + +Input.defaultProps = { + id: null, + name: '', + label: '', + value: '', + placeholder: '', + type: 'text', + required: false, + onChange: null, + forwardRef: null, + resizable: false, + minHeight: 46, + onResize: null, + state: 'normal', + onKeyDown: null, + disabled: false, + autoFocus: false, +}; + +Input.propTypes = { + id: PropTypes.string, + name: PropTypes.string, + label: PropTypes.string, + value: PropTypes.string, + placeholder: PropTypes.string, + required: PropTypes.bool, + type: PropTypes.string, + onChange: PropTypes.func, + forwardRef: PropTypes.shape({}), + resizable: PropTypes.bool, + minHeight: PropTypes.number, + onResize: PropTypes.func, + state: PropTypes.oneOf(['normal', 'success', 'error']), + onKeyDown: PropTypes.func, + disabled: PropTypes.bool, + autoFocus: PropTypes.bool, +}; + +export default Input; diff --git a/src/app/atoms/input/Input.scss b/src/app/atoms/input/Input.scss new file mode 100644 index 00000000..40fe43ec --- /dev/null +++ b/src/app/atoms/input/Input.scss @@ -0,0 +1,52 @@ +@use '../../atoms/scroll/scrollbar'; + +.input { + display: block; + width: 100%; + min-width: 0px; + margin: 0; + padding: var(--sp-tight) var(--sp-normal); + background-color: var(--bg-surface-low); + color: var(--tc-surface-normal); + box-shadow: none; + border-radius: var(--bo-radius); + border: 1px solid var(--bg-surface-border); + font-size: var(--fs-b2); + letter-spacing: var(--ls-b2); + line-height: var(--lh-b2); + + :disabled { + opacity: 0.4; + cursor: no-drop; + } + + &__label { + display: inline-block; + margin-bottom: var(--sp-ultra-tight); + color: var(--tc-surface-low); + } + + &--resizable { + resize: vertical !important; + overflow-y: auto !important; + @include scrollbar.scroll; + @include scrollbar.scroll__v; + @include scrollbar.scroll--auto-hide; + } + &--success { + border: 1px solid var(--bg-positive); + box-shadow: none !important; + } + &--error { + border: 1px solid var(--bg-danger); + box-shadow: none !important; + } + + &:focus { + outline: none; + box-shadow: var(--bs-primary-border); + } + &::placeholder { + color: var(--tc-surface-low) + } +} \ No newline at end of file diff --git a/src/app/atoms/modal/RawModal.jsx b/src/app/atoms/modal/RawModal.jsx new file mode 100644 index 00000000..450be0e0 --- /dev/null +++ b/src/app/atoms/modal/RawModal.jsx @@ -0,0 +1,73 @@ +import React, { useEffect } from 'react'; +import PropTypes from 'prop-types'; +import './RawModal.scss'; + +import Modal from 'react-modal'; + +import navigation from '../../../client/state/navigation'; + +Modal.setAppElement('#root'); + +function RawModal({ + className, overlayClassName, + isOpen, size, onAfterOpen, onAfterClose, + onRequestClose, closeFromOutside, children, +}) { + let modalClass = (className !== null) ? `${className} ` : ''; + switch (size) { + case 'large': + modalClass += 'raw-modal__large '; + break; + case 'medium': + modalClass += 'raw-modal__medium '; + break; + case 'small': + default: + modalClass += 'raw-modal__small '; + } + + useEffect(() => { + navigation.setIsRawModalVisible(isOpen); + }, [isOpen]); + + const modalOverlayClass = (overlayClassName !== null) ? `${overlayClassName} ` : ''; + return ( + + {children} + + ); +} + +RawModal.defaultProps = { + className: null, + overlayClassName: null, + size: 'small', + onAfterOpen: null, + onAfterClose: null, + onRequestClose: null, + closeFromOutside: true, +}; + +RawModal.propTypes = { + className: PropTypes.string, + overlayClassName: PropTypes.string, + isOpen: PropTypes.bool.isRequired, + size: PropTypes.oneOf(['large', 'medium', 'small']), + onAfterOpen: PropTypes.func, + onAfterClose: PropTypes.func, + onRequestClose: PropTypes.func, + closeFromOutside: PropTypes.bool, + children: PropTypes.node.isRequired, +}; + +export default RawModal; diff --git a/src/app/atoms/modal/RawModal.scss b/src/app/atoms/modal/RawModal.scss new file mode 100644 index 00000000..d612a4bc --- /dev/null +++ b/src/app/atoms/modal/RawModal.scss @@ -0,0 +1,66 @@ +.raw-modal { + --small-modal-width: 525px; + --medium-modal-width: 712px; + --large-modal-width: 1024px; + + position: relative; + width: 100%; + max-height: 100%; + border-radius: var(--bo-radius); + box-shadow: var(--bs-popup); + outline: none; + overflow: hidden; + + &__small { + max-width: var(--small-modal-width); + } + &__medium { + max-width: var(--medium-modal-width); + } + &__large { + max-width: var(--large-modal-width); + } + + &__overlay { + position: fixed; + top: 0; + left: 0; + z-index: 999; + + display: flex; + justify-content: center; + align-items: center; + + padding: var(--sp-normal); + width: 100%; + height: 100%; + background-color: var(--bg-overlay); + } +} + +.ReactModal__Overlay { + animation: raw-modal--overlay 150ms; +} + +.ReactModal__Content { + animation: raw-modal--content 150ms; +} + +@keyframes raw-modal--content { + 0% { + transform: translateY(100px); + opacity: .5; + } + 100% { + transform: translateY(0); + opacity: 1; + } +} +@keyframes raw-modal--overlay { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} diff --git a/src/app/atoms/scroll/ScrollView.jsx b/src/app/atoms/scroll/ScrollView.jsx new file mode 100644 index 00000000..26c0c83a --- /dev/null +++ b/src/app/atoms/scroll/ScrollView.jsx @@ -0,0 +1,37 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './ScrollView.scss'; + +const ScrollView = React.forwardRef(({ + horizontal, vertical, autoHide, invisible, onScroll, children, +}, ref) => { + let scrollbarClasses = ''; + if (horizontal) scrollbarClasses += ' scrollbar__h'; + if (vertical) scrollbarClasses += ' scrollbar__v'; + if (autoHide) scrollbarClasses += ' scrollbar--auto-hide'; + if (invisible) scrollbarClasses += ' scrollbar--invisible'; + return ( +
+ {children} +
+ ); +}); + +ScrollView.defaultProps = { + horizontal: false, + vertical: true, + autoHide: false, + invisible: false, + onScroll: null, +}; + +ScrollView.propTypes = { + horizontal: PropTypes.bool, + vertical: PropTypes.bool, + autoHide: PropTypes.bool, + invisible: PropTypes.bool, + onScroll: PropTypes.func, + children: PropTypes.node.isRequired, +}; + +export default ScrollView; diff --git a/src/app/atoms/scroll/ScrollView.scss b/src/app/atoms/scroll/ScrollView.scss new file mode 100644 index 00000000..251037e1 --- /dev/null +++ b/src/app/atoms/scroll/ScrollView.scss @@ -0,0 +1,31 @@ +@use '../../partials/dir'; +@use '_scrollbar'; + +@mixin paddingForSafari($padding) { + @media not all and (min-resolution:.001dpcm) { + @include dir.side(padding, 0, $padding); + } +} + +.scrollbar { + width: 100%; + height: 100%; + @include scrollbar.scroll; + @include paddingForSafari(var(--sp-extra-tight)); + + &__h { + @include scrollbar.scroll__h; + } + + &__v { + @include scrollbar.scroll__v; + } + + &--auto-hide { + @include scrollbar.scroll--auto-hide; + } + &--invisible { + @include scrollbar.scroll--invisible; + @include paddingForSafari(0); + } +} \ No newline at end of file diff --git a/src/app/atoms/scroll/_scrollbar.scss b/src/app/atoms/scroll/_scrollbar.scss new file mode 100644 index 00000000..78ec75ad --- /dev/null +++ b/src/app/atoms/scroll/_scrollbar.scss @@ -0,0 +1,65 @@ +.firefox-scrollbar { + scrollbar-width: thin; + scrollbar-color: var(--bg-surface-hover) transparent; + &--transparent { + scrollbar-color: transparent transparent; + } +} +.webkit-scrollbar { + &::-webkit-scrollbar { + width: 8px; + height: 8px; + } +} +.webkit-scrollbar-track { + &::-webkit-scrollbar-track { + background-color: transparent; + } +} +.webkit-scrollbar-thumb { + &::-webkit-scrollbar-thumb { + background-color: var(--bg-surface-hover); + } + &::-webkit-scrollbar-thumb:hover { + background-color: var(--bg-surface-active); + } + &--transparent { + &::-webkit-scrollbar-thumb { + background-color: transparent; + } + } +} + +@mixin scroll { + overflow: hidden; + // Below code stop scroll when x-scrollable content come in timeline + // overscroll-behavior: none; + @extend .firefox-scrollbar; + @extend .webkit-scrollbar; + @extend .webkit-scrollbar-track; + @extend .webkit-scrollbar-thumb; +} + +@mixin scroll__h { + overflow-x: scroll; +} +@mixin scroll__v { + overflow-y: scroll; +} +@mixin scroll--auto-hide { + @extend .firefox-scrollbar--transparent; + @extend .webkit-scrollbar-thumb--transparent; + + &:hover { + @extend .firefox-scrollbar; + @extend .webkit-scrollbar-thumb; + } +} +@mixin scroll--invisible { + -ms-overflow-style: none; + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; + } +} \ No newline at end of file diff --git a/src/app/atoms/segmented-controls/SegmentedControls.jsx b/src/app/atoms/segmented-controls/SegmentedControls.jsx new file mode 100644 index 00000000..1d54dd06 --- /dev/null +++ b/src/app/atoms/segmented-controls/SegmentedControls.jsx @@ -0,0 +1,55 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import './SegmentedControls.scss'; + +import { blurOnBubbling } from '../button/script'; + +import Text from '../text/Text'; +import RawIcon from '../system-icons/RawIcon'; + +function SegmentedControls({ + selected, segments, onSelect, +}) { + const [select, setSelect] = useState(selected); + + function selectSegment(segmentIndex) { + setSelect(segmentIndex); + onSelect(segmentIndex); + } + + useEffect(() => { + setSelect(selected); + }, [selected]); + + return ( +
+ { + segments.map((segment, index) => ( + + )) + } +
+ ); +} + +SegmentedControls.propTypes = { + selected: PropTypes.number.isRequired, + segments: PropTypes.arrayOf(PropTypes.shape({ + iconSrc: PropTypes.string, + text: PropTypes.string, + })).isRequired, + onSelect: PropTypes.func.isRequired, +}; + +export default SegmentedControls; diff --git a/src/app/atoms/segmented-controls/SegmentedControls.scss b/src/app/atoms/segmented-controls/SegmentedControls.scss new file mode 100644 index 00000000..fb1fd987 --- /dev/null +++ b/src/app/atoms/segmented-controls/SegmentedControls.scss @@ -0,0 +1,57 @@ +@use '../button/state'; +@use '../../partials/dir'; + +.segmented-controls { + background-color: var(--bg-surface-low); + border-radius: var(--bo-radius); + border: 1px solid var(--bg-surface-border); + + display: inline-flex; + overflow: hidden; +} + +.segment-btn { + padding: var(--sp-extra-tight) 0; + cursor: pointer; + @include state.hover(var(--bg-surface-hover)); + @include state.active(var(--bg-surface-active)); + + &__base { + padding: 0 var(--sp-normal); + display: flex; + align-items: center; + justify-content: center; + @include dir.side(border, 1px solid var(--bg-surface-border), none); + + & .text:nth-child(2) { + margin: 0 var(--sp-extra-tight); + } + } + &:first-child &__base { + border: none; + } + + &--active { + background-color: var(--bg-surface); + border: 1px solid var(--bg-surface-border); + border-width: 0 1px 0 1px; + + & .segment-btn__base, + & + .segment-btn .segment-btn__base { + border: none; + } + &:first-child{ + border-left: none; + } + &:last-child { + border-right: none; + } + [dir=rtl] & { + border-left: 1px solid var(--bg-surface-border); + border-right: 1px solid var(--bg-surface-border); + + &:first-child { border-right: none;} + &:last-child { border-left: none;} + } + } +} \ No newline at end of file diff --git a/src/app/atoms/spinner/Spinner.jsx b/src/app/atoms/spinner/Spinner.jsx new file mode 100644 index 00000000..61c9747e --- /dev/null +++ b/src/app/atoms/spinner/Spinner.jsx @@ -0,0 +1,19 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './Spinner.scss'; + +function Spinner({ size }) { + return ( +
+ ); +} + +Spinner.defaultProps = { + size: 'normal', +}; + +Spinner.propTypes = { + size: PropTypes.oneOf(['normal', 'small']), +}; + +export default Spinner; diff --git a/src/app/atoms/spinner/Spinner.scss b/src/app/atoms/spinner/Spinner.scss new file mode 100644 index 00000000..73fbf676 --- /dev/null +++ b/src/app/atoms/spinner/Spinner.scss @@ -0,0 +1,22 @@ +.donut-spinner { + display: inline-block; + border: 4px solid var(--bg-surface-border); + border-left-color: var(--tc-surface-normal); + border-radius: 50%; + animation: donut-spin 1.2s cubic-bezier(0.73, 0.32, 0.67, 0.86) infinite; + + &--normal { + width: 40px; + height: 40px; + } + &--small { + width: 28px; + height: 28px; + } +} + +@keyframes donut-spin { + to { + transform: rotate(1turn); + } +} \ No newline at end of file diff --git a/src/app/atoms/system-icons/RawIcon.jsx b/src/app/atoms/system-icons/RawIcon.jsx new file mode 100644 index 00000000..a6697f4f --- /dev/null +++ b/src/app/atoms/system-icons/RawIcon.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './RawIcon.scss'; + +function RawIcon({ color, size, src, isImage }) { + const style = {}; + if (color !== null) style.backgroundColor = color; + if (isImage) { + style.backgroundColor = 'transparent'; + style.backgroundImage = `url("${src}")`; + } else { + style.WebkitMaskImage = `url("${src}")`; + style.maskImage = `url("${src}")`; + } + + return ; +} + +RawIcon.defaultProps = { + color: null, + size: 'normal', + isImage: false, +}; + +RawIcon.propTypes = { + color: PropTypes.string, + size: PropTypes.oneOf(['large', 'normal', 'small', 'extra-small']), + src: PropTypes.string.isRequired, + isImage: PropTypes.bool, +}; + +export default RawIcon; diff --git a/src/app/atoms/system-icons/RawIcon.scss b/src/app/atoms/system-icons/RawIcon.scss new file mode 100644 index 00000000..56fc9b3c --- /dev/null +++ b/src/app/atoms/system-icons/RawIcon.scss @@ -0,0 +1,28 @@ +@mixin icSize($size) { + width: $size; + height: $size; +} + +.ic-raw { + display: inline-block; + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: cover; + mask-size: cover; + background-color: var(--ic-surface-normal); + + background-size: cover; + background-repeat: no-repeat; +} +.ic-raw-large { + @include icSize(var(--ic-large)); +} +.ic-raw-normal { + @include icSize(var(--ic-normal)); +} +.ic-raw-small { + @include icSize(var(--ic-small)); +} +.ic-raw-extra-small { + @include icSize(var(--ic-extra-small)); +} \ No newline at end of file diff --git a/src/app/atoms/tabs/Tabs.jsx b/src/app/atoms/tabs/Tabs.jsx new file mode 100644 index 00000000..bcdc8ef7 --- /dev/null +++ b/src/app/atoms/tabs/Tabs.jsx @@ -0,0 +1,88 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import './Tabs.scss'; + +import Button from '../button/Button'; +import ScrollView from '../scroll/ScrollView'; + +function TabItem({ + selected, iconSrc, + onClick, children, disabled, +}) { + const isSelected = selected ? 'tab-item--selected' : ''; + + return ( + + ); +} + +TabItem.defaultProps = { + selected: false, + iconSrc: null, + onClick: null, + disabled: false, +}; + +TabItem.propTypes = { + selected: PropTypes.bool, + iconSrc: PropTypes.string, + onClick: PropTypes.func, + children: PropTypes.node.isRequired, + disabled: PropTypes.bool, +}; + +function Tabs({ items, defaultSelected, onSelect }) { + const [selectedItem, setSelectedItem] = useState(items[defaultSelected]); + + const handleTabSelection = (item, index, target) => { + if (selectedItem === item) return; + target.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); + setSelectedItem(item); + onSelect(item, index); + }; + + return ( +
+ +
+ {items.map((item, index) => ( + handleTabSelection(item, index, e.currentTarget)} + > + {item.text} + + ))} +
+
+
+ ); +} + +Tabs.defaultProps = { + defaultSelected: 0, +}; + +Tabs.propTypes = { + items: PropTypes.arrayOf( + PropTypes.shape({ + iconSrc: PropTypes.string, + text: PropTypes.string, + disabled: PropTypes.bool, + }), + ).isRequired, + defaultSelected: PropTypes.number, + onSelect: PropTypes.func.isRequired, +}; + +export default Tabs; diff --git a/src/app/atoms/tabs/Tabs.scss b/src/app/atoms/tabs/Tabs.scss new file mode 100644 index 00000000..39ddddec --- /dev/null +++ b/src/app/atoms/tabs/Tabs.scss @@ -0,0 +1,45 @@ +@use '../../partials/dir'; + +.tabs { + height: var(--header-height); + box-shadow: inset 0 -1px 0 var(--bg-surface-border); + + &__content { + min-width: 100%; + height: 100%; + display: flex; + } +} + +.tab-item { + flex-shrink: 0; + + @include dir.side(padding, var(--sp-normal), 24px); + border-radius: 0; + height: 100%; + box-shadow: none; + border-radius: var(--bo-radius) var(--bo-radius) 0 0; + + &:focus, + &:active { + background-color: var(--bg-surface-active); + box-shadow: none; + } + + &--selected { + --bs-tab-selected: inset 0 -2px 0 var(--tc-surface-high); + box-shadow: var(--bs-tab-selected); + + & .ic-raw { + background-color: var(--ic-surface-high); + } + & .text { + font-weight: var(--fw-medium); + } + &:focus, + &:active { + background-color: var(--bg-surface-active); + box-shadow: var(--bs-tab-selected); + } + } +} \ No newline at end of file diff --git a/src/app/atoms/text/Text.jsx b/src/app/atoms/text/Text.jsx new file mode 100644 index 00000000..3f507ee3 --- /dev/null +++ b/src/app/atoms/text/Text.jsx @@ -0,0 +1,42 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './Text.scss'; + +function Text({ + className, style, variant, weight, + primary, span, children, +}) { + const classes = []; + if (className) classes.push(className); + + classes.push(`text text-${variant} text-${weight}`); + if (primary) classes.push('font-primary'); + + const textClass = classes.join(' '); + if (span) return { children }; + if (variant === 'h1') return

{ children }

; + if (variant === 'h2') return

{ children }

; + if (variant === 's1') return

{ children }

; + return

{ children }

; +} + +Text.defaultProps = { + className: null, + style: null, + variant: 'b1', + weight: 'normal', + primary: false, + span: false, +}; + +Text.propTypes = { + className: PropTypes.string, + style: PropTypes.shape({}), + variant: PropTypes.oneOf(['h1', 'h2', 's1', 'b1', 'b2', 'b3']), + weight: PropTypes.oneOf(['light', 'normal', 'medium', 'bold']), + primary: PropTypes.bool, + span: PropTypes.bool, + children: PropTypes.node.isRequired, +}; + +export default Text; diff --git a/src/app/atoms/text/Text.scss b/src/app/atoms/text/Text.scss new file mode 100644 index 00000000..256bf6ea --- /dev/null +++ b/src/app/atoms/text/Text.scss @@ -0,0 +1,61 @@ +@mixin font($type) { + font-size: var(--fs-#{$type}); + letter-spacing: var(--ls-#{$type}); + line-height: var(--lh-#{$type}); + + & img.emoji, + & img[data-mx-emoticon] { + height: calc(var(--lh-#{$type}) - .25rem); + } +} + +.text { + margin: 0; + padding: 0; + color: var(--tc-surface-high); + + & img.emoji, + & img[data-mx-emoticon] { + margin: 0 !important; + margin-right: 2px !important; + padding: 0 !important; + position: relative; + top: -.1rem; + vertical-align: middle; + } +} + +.text-light { + font-weight: var(--fw-light); +} +.text-normal { + font-weight: var(--fw-normal); +} +.text-medium { + font-weight: var(--fw-medium); +} +.text-bold { + font-weight: var(--fw-bold); +} + +.text-h1 { + @include font(h1); +} +.text-h2 { + @include font(h2); +} +.text-s1 { + @include font(s1); +} +.text-b1 { + @include font(b1); + color: var(--tc-surface-normal); +} +.text-b2 { + @include font(b2); + color: var(--tc-surface-normal); +} +.text-b3 { + @include font(b3); + color: var(--tc-surface-low); +} \ No newline at end of file diff --git a/src/app/atoms/time/Time.jsx b/src/app/atoms/time/Time.jsx new file mode 100644 index 00000000..750b958f --- /dev/null +++ b/src/app/atoms/time/Time.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import dateFormat from 'dateformat'; +import { isInSameDay } from '../../../util/common'; + +function Time({ timestamp, fullTime }) { + const date = new Date(timestamp); + + const formattedFullTime = dateFormat(date, 'dd mmmm yyyy, hh:MM TT'); + let formattedDate = formattedFullTime; + + if (!fullTime) { + const compareDate = new Date(); + const isToday = isInSameDay(date, compareDate); + compareDate.setDate(compareDate.getDate() - 1); + const isYesterday = isInSameDay(date, compareDate); + + formattedDate = dateFormat(date, isToday || isYesterday ? 'hh:MM TT' : 'dd/mm/yyyy'); + if (isYesterday) { + formattedDate = `Yesterday, ${formattedDate}`; + } + } + + return ( + + ); +} + +Time.defaultProps = { + fullTime: false, +}; + +Time.propTypes = { + timestamp: PropTypes.number.isRequired, + fullTime: PropTypes.bool, +}; + +export default Time; diff --git a/src/app/atoms/tooltip/Tooltip.jsx b/src/app/atoms/tooltip/Tooltip.jsx new file mode 100644 index 00000000..0f9067f5 --- /dev/null +++ b/src/app/atoms/tooltip/Tooltip.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './Tooltip.scss'; +import Tippy from '@tippyjs/react'; + +function Tooltip({ + className, placement, content, delay, children, +}) { + return ( + + {children} + + ); +} + +Tooltip.defaultProps = { + placement: 'top', + className: '', + delay: [200, 0], +}; + +Tooltip.propTypes = { + className: PropTypes.string, + placement: PropTypes.string, + content: PropTypes.node.isRequired, + delay: PropTypes.arrayOf(PropTypes.number), + children: PropTypes.node.isRequired, +}; + +export default Tooltip; diff --git a/src/app/atoms/tooltip/Tooltip.scss b/src/app/atoms/tooltip/Tooltip.scss new file mode 100644 index 00000000..f609aa58 --- /dev/null +++ b/src/app/atoms/tooltip/Tooltip.scss @@ -0,0 +1,10 @@ +.tooltip { + padding: var(--sp-extra-tight) var(--sp-normal); + background-color: var(--bg-tooltip); + border-radius: var(--bo-radius); + box-shadow: var(--bs-popup); + + .text { + color: var(--tc-tooltip); + } +} \ No newline at end of file diff --git a/src/app/components/BetaNoticeBadge.tsx b/src/app/components/BetaNoticeBadge.tsx deleted file mode 100644 index d1859876..00000000 --- a/src/app/components/BetaNoticeBadge.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import { TooltipProvider, Tooltip, Box, Text, Badge, toRem } from 'folds'; - -export function BetaNoticeBadge() { - return ( - - - Notice - This feature is under testing and may change over time. - - - } - > - {(triggerRef) => ( - - Beta - - )} - - ); -} diff --git a/src/app/components/CapabilitiesAndMediaConfigLoader.tsx b/src/app/components/CapabilitiesAndMediaConfigLoader.tsx new file mode 100644 index 00000000..574d0ca7 --- /dev/null +++ b/src/app/components/CapabilitiesAndMediaConfigLoader.tsx @@ -0,0 +1,36 @@ +import { ReactNode, useCallback, useEffect } from 'react'; +import { Capabilities } from 'matrix-js-sdk'; +import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback'; +import { useMatrixClient } from '../hooks/useMatrixClient'; +import { MediaConfig } from '../hooks/useMediaConfig'; +import { promiseFulfilledResult } from '../utils/common'; + +type CapabilitiesAndMediaConfigLoaderProps = { + children: (capabilities?: Capabilities, mediaConfig?: MediaConfig) => ReactNode; +}; +export function CapabilitiesAndMediaConfigLoader({ + children, +}: CapabilitiesAndMediaConfigLoaderProps) { + const mx = useMatrixClient(); + + const [state, load] = useAsyncCallback< + [Capabilities | undefined, MediaConfig | undefined], + unknown, + [] + >( + useCallback(async () => { + const result = await Promise.allSettled([mx.getCapabilities(), mx.getMediaConfig()]); + const capabilities = promiseFulfilledResult(result[0]); + const mediaConfig = promiseFulfilledResult(result[1]); + return [capabilities, mediaConfig]; + }, [mx]) + ); + + useEffect(() => { + load(); + }, [load]); + + const [capabilities, mediaConfig] = + state.status === AsyncStatus.Success ? state.data : [undefined, undefined]; + return children(capabilities, mediaConfig); +} diff --git a/src/app/components/DeviceVerificationSetup.tsx b/src/app/components/DeviceVerificationSetup.tsx index 433fa6a1..fb09c150 100644 --- a/src/app/components/DeviceVerificationSetup.tsx +++ b/src/app/components/DeviceVerificationSetup.tsx @@ -20,7 +20,7 @@ import { PasswordInput } from './password-input'; import { ContainerColor } from '../styles/ContainerColor.css'; import { copyToClipboard } from '../utils/dom'; import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback'; -import { clearSecretStorageKeys } from '../../client/secretStorageKeys'; +import { clearSecretStorageKeys } from '../../client/state/secretStorageKeys'; import { ActionUIA, ActionUIAFlowsLoader } from './ActionUIA'; import { useMatrixClient } from '../hooks/useMatrixClient'; import { useAlive } from '../hooks/useAlive'; diff --git a/src/app/components/HexColorPickerPopOut.tsx b/src/app/components/HexColorPickerPopOut.tsx deleted file mode 100644 index d8fb4bc3..00000000 --- a/src/app/components/HexColorPickerPopOut.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import FocusTrap from 'focus-trap-react'; -import { Box, Button, config, Menu, PopOut, RectCords, Text } from 'folds'; -import React, { MouseEventHandler, ReactNode, useState } from 'react'; -import { stopPropagation } from '../utils/keyboard'; - -type HexColorPickerPopOutProps = { - children: (onOpen: MouseEventHandler, opened: boolean) => ReactNode; - picker: ReactNode; - onRemove?: () => void; -}; -export function HexColorPickerPopOut({ picker, onRemove, children }: HexColorPickerPopOutProps) { - const [cords, setCords] = useState(); - - const handleOpen: MouseEventHandler = (evt) => { - setCords(evt.currentTarget.getBoundingClientRect()); - }; - - return ( - setCords(undefined), - clickOutsideDeactivates: true, - escapeDeactivates: stopPropagation, - }} - > - - - {picker} - {onRemove && ( - - )} - - - - } - > - {children(handleOpen, !!cords)} - - ); -} diff --git a/src/app/components/JoinRulesSwitcher.tsx b/src/app/components/JoinRulesSwitcher.tsx deleted file mode 100644 index 9507317a..00000000 --- a/src/app/components/JoinRulesSwitcher.tsx +++ /dev/null @@ -1,155 +0,0 @@ -import React, { MouseEventHandler, useCallback, useMemo, useState } from 'react'; -import { - config, - Box, - MenuItem, - Text, - Icon, - Icons, - IconSrc, - RectCords, - PopOut, - Menu, - Button, - Spinner, -} from 'folds'; -import { JoinRule } from 'matrix-js-sdk'; -import FocusTrap from 'focus-trap-react'; -import { stopPropagation } from '../utils/keyboard'; - -export type ExtraJoinRules = 'knock_restricted'; -export type ExtendedJoinRules = JoinRule | ExtraJoinRules; - -type JoinRuleIcons = Record; -export const useRoomJoinRuleIcon = (): JoinRuleIcons => - useMemo( - () => ({ - [JoinRule.Invite]: Icons.HashLock, - [JoinRule.Knock]: Icons.HashLock, - knock_restricted: Icons.Hash, - [JoinRule.Restricted]: Icons.Hash, - [JoinRule.Public]: Icons.HashGlobe, - [JoinRule.Private]: Icons.HashLock, - }), - [] - ); -export const useSpaceJoinRuleIcon = (): JoinRuleIcons => - useMemo( - () => ({ - [JoinRule.Invite]: Icons.SpaceLock, - [JoinRule.Knock]: Icons.SpaceLock, - knock_restricted: Icons.Space, - [JoinRule.Restricted]: Icons.Space, - [JoinRule.Public]: Icons.SpaceGlobe, - [JoinRule.Private]: Icons.SpaceLock, - }), - [] - ); - -type JoinRuleLabels = Record; -export const useRoomJoinRuleLabel = (): JoinRuleLabels => - useMemo( - () => ({ - [JoinRule.Invite]: 'Invite Only', - [JoinRule.Knock]: 'Knock & Invite', - knock_restricted: 'Space Members or Knock', - [JoinRule.Restricted]: 'Space Members', - [JoinRule.Public]: 'Public', - [JoinRule.Private]: 'Invite Only', - }), - [] - ); - -type JoinRulesSwitcherProps = { - icons: JoinRuleIcons; - labels: JoinRuleLabels; - rules: T; - value: T[number]; - onChange: (value: T[number]) => void; - disabled?: boolean; - changing?: boolean; -}; -export function JoinRulesSwitcher({ - icons, - labels, - rules, - value, - onChange, - disabled, - changing, -}: JoinRulesSwitcherProps) { - const [cords, setCords] = useState(); - - const handleOpenMenu: MouseEventHandler = (evt) => { - setCords(evt.currentTarget.getBoundingClientRect()); - }; - - const handleChange = useCallback( - (selectedRule: ExtendedJoinRules) => { - setCords(undefined); - onChange(selectedRule); - }, - [onChange] - ); - - return ( - setCords(undefined), - clickOutsideDeactivates: true, - isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown', - isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp', - escapeDeactivates: stopPropagation, - }} - > - - - {rules.map((rule) => ( - handleChange(rule)} - before={} - disabled={disabled} - > - - {labels[rule]} - - - ))} - - - - } - > - - - ); -} diff --git a/src/app/components/ManualVerification.tsx b/src/app/components/ManualVerification.tsx index f7cde92b..03f3e710 100644 --- a/src/app/components/ManualVerification.tsx +++ b/src/app/components/ManualVerification.tsx @@ -19,7 +19,7 @@ import { SecretStorageKeyContent } from '../../types/matrix/accountData'; import { SecretStorageRecoveryKey, SecretStorageRecoveryPassphrase } from './SecretStorage'; import { useMatrixClient } from '../hooks/useMatrixClient'; import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback'; -import { storePrivateKey } from '../../client/secretStorageKeys'; +import { storePrivateKey } from '../../client/state/secretStorageKeys'; export enum ManualVerificationMethod { RecoveryPassphrase = 'passphrase', diff --git a/src/app/components/MemberSortMenu.tsx b/src/app/components/MemberSortMenu.tsx deleted file mode 100644 index d77c80c6..00000000 --- a/src/app/components/MemberSortMenu.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import FocusTrap from 'focus-trap-react'; -import React from 'react'; -import { config, Menu, MenuItem, Text } from 'folds'; -import { stopPropagation } from '../utils/keyboard'; -import { useMemberSortMenu } from '../hooks/useMemberSort'; - -type MemberSortMenuProps = { - requestClose: () => void; - selected: number; - onSelect: (index: number) => void; -}; -export function MemberSortMenu({ selected, onSelect, requestClose }: MemberSortMenuProps) { - const memberSortMenu = useMemberSortMenu(); - - return ( - evt.key === 'ArrowDown', - isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp', - escapeDeactivates: stopPropagation, - }} - > - - {memberSortMenu.map((menuItem, index) => ( - { - onSelect(index); - requestClose(); - }} - > - {menuItem.name} - - ))} - - - ); -} diff --git a/src/app/components/MembershipFilterMenu.tsx b/src/app/components/MembershipFilterMenu.tsx deleted file mode 100644 index bf17677d..00000000 --- a/src/app/components/MembershipFilterMenu.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import FocusTrap from 'focus-trap-react'; -import React from 'react'; -import { config, Menu, MenuItem, Text } from 'folds'; -import { stopPropagation } from '../utils/keyboard'; -import { useMembershipFilterMenu } from '../hooks/useMemberFilter'; - -type MembershipFilterMenuProps = { - requestClose: () => void; - selected: number; - onSelect: (index: number) => void; -}; -export function MembershipFilterMenu({ - selected, - onSelect, - requestClose, -}: MembershipFilterMenuProps) { - const membershipFilterMenu = useMembershipFilterMenu(); - - return ( - evt.key === 'ArrowDown', - isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp', - escapeDeactivates: stopPropagation, - }} - > - - {membershipFilterMenu.map((menuItem, index) => ( - { - onSelect(index); - requestClose(); - }} - > - {menuItem.name} - - ))} - - - ); -} diff --git a/src/app/components/RenderMessageContent.tsx b/src/app/components/RenderMessageContent.tsx index 2457e5e3..55b0ffc2 100644 --- a/src/app/components/RenderMessageContent.tsx +++ b/src/app/components/RenderMessageContent.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { MsgType } from 'matrix-js-sdk'; import { HTMLReactParserOptions } from 'html-react-parser'; import { Opts } from 'linkifyjs'; -import { config } from 'folds'; import { AudioContent, DownloadFile, @@ -30,7 +29,7 @@ import { ImageViewer } from './image-viewer'; import { PdfViewer } from './Pdf-viewer'; import { TextViewer } from './text-viewer'; import { testMatrixTo } from '../plugins/matrix-to'; -import { IImageContent } from '../../types/matrix/common'; +import {IImageContent} from "../../types/matrix/common"; type RenderMessageContentProps = { displayName: string; @@ -71,10 +70,9 @@ export function RenderMessageContent({ }; const renderCaption = () => { const content: IImageContent = getContent(); - if (content.filename && content.filename !== content.body) { + if(content.filename && content.filename !== content.body) { return ( ( @@ -87,40 +85,41 @@ export function RenderMessageContent({ )} renderUrlsPreview={urlPreview ? renderUrlsPreview : undefined} /> - ); + ) } return null; - }; + } const renderFile = () => ( <> ( - ( - } - /> - )} - renderAsTextFile={() => ( - } - /> - )} - > - - + ( + } + /> + )} + renderAsTextFile={() => ( + } + /> + )} + > + + + )} outlined={outlineAttachment} /> @@ -189,12 +188,12 @@ export function RenderMessageContent({ ( - } - renderViewer={(p) => } - /> + } + renderViewer={(p) => } + /> )} outlined={outlineAttachment} /> @@ -219,13 +218,13 @@ export function RenderMessageContent({ renderThumbnail={ mediaAutoLoad ? () => ( - ( - {body} - )} - /> - ) + ( + {body} + )} + /> + ) : undefined } renderVideo={(p) =>