Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e89b8f7d12 | |||
| 9bc1e7e9ff | |||
| c05a6be6f2 | |||
| f7f4a41d61 | |||
| 81327678b1 | |||
| bad1fb609a | |||
| bef267257a | |||
| 909aa430b8 | |||
| 0b99d85244 | |||
| 21bbf4bee0 | |||
| e5e0b96861 | |||
| 02d1001583 | |||
| 64468dfb1b |
@@ -21,9 +21,15 @@ jobs:
|
|||||||
workflow: ${{ github.event.workflow.id }}
|
workflow: ${{ github.event.workflow.id }}
|
||||||
run_id: ${{ github.event.workflow_run.id }}
|
run_id: ${{ github.event.workflow_run.id }}
|
||||||
name: pr
|
name: pr
|
||||||
- name: Output pr number
|
- name: Validate and output pr number
|
||||||
id: pr
|
id: pr
|
||||||
run: echo "id=$(<pr.txt)" >> $GITHUB_OUTPUT
|
run: |
|
||||||
|
PR_ID=$(<pr.txt)
|
||||||
|
if ! [[ "${PR_ID}" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "::error::pr.txt contains non-numeric content: ${PR_ID}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "id=${PR_ID}" >> "${GITHUB_OUTPUT}"
|
||||||
- name: Download artifact
|
- name: Download artifact
|
||||||
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
|
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
|
||||||
with:
|
with:
|
||||||
@@ -42,7 +48,7 @@ jobs:
|
|||||||
enable-pull-request-comment: false
|
enable-pull-request-comment: false
|
||||||
enable-commit-comment: false
|
enable-commit-comment: false
|
||||||
env:
|
env:
|
||||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN_PR }}
|
||||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID_PR_CINNY }}
|
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID_PR_CINNY }}
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
- name: Comment preview on PR
|
- name: Comment preview on PR
|
||||||
|
|||||||
+7
-8
@@ -6,21 +6,20 @@
|
|||||||
"featuredCommunities": {
|
"featuredCommunities": {
|
||||||
"openAsDefault": false,
|
"openAsDefault": false,
|
||||||
"spaces": [
|
"spaces": [
|
||||||
"#cinny-space:matrix.org",
|
"#cinny:matrix.org",
|
||||||
"#community:matrix.org",
|
"#community:matrix.org",
|
||||||
"#space:unredacted.org",
|
"#space:unredacted.org",
|
||||||
|
"#librewolf-community:matrix.org",
|
||||||
|
"#stickers-and-emojis:tastytea.de",
|
||||||
|
"#videogames:waywardinn.com",
|
||||||
"#science-space:matrix.org",
|
"#science-space:matrix.org",
|
||||||
"#libregaming-games:tchncs.de",
|
"#libregaming-games:tchncs.de",
|
||||||
"#mathematics-on:matrix.org",
|
"#mathematics-on:matrix.org"
|
||||||
"#stickers-and-emojis:tastytea.de"
|
|
||||||
],
|
],
|
||||||
"rooms": [
|
"rooms": [
|
||||||
"#cinny:matrix.org",
|
"#tuwunel:grin.hu",
|
||||||
"#freesoftware:matrix.org",
|
"#freesoftware:matrix.org",
|
||||||
"#pcapdroid:matrix.org",
|
"#gentoo:matrix.org"
|
||||||
"#gentoo:matrix.org",
|
|
||||||
"#PrivSec.dev:arcticfoxes.net",
|
|
||||||
"#disroot:aria-net.org"
|
|
||||||
],
|
],
|
||||||
"servers": ["matrixrooms.info", "matrix.org", "mozilla.org", "unredacted.org"]
|
"servers": ["matrixrooms.info", "matrix.org", "mozilla.org", "unredacted.org"]
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+56
-30
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "cinny",
|
"name": "cinny",
|
||||||
"version": "4.11.1",
|
"version": "4.12.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "cinny",
|
"name": "cinny",
|
||||||
"version": "4.11.1",
|
"version": "4.12.1",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atlaskit/pragmatic-drag-and-drop": "1.1.6",
|
"@atlaskit/pragmatic-drag-and-drop": "1.1.6",
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
"react-i18next": "15.0.0",
|
"react-i18next": "15.0.0",
|
||||||
"react-range": "1.8.14",
|
"react-range": "1.8.14",
|
||||||
"react-router-dom": "6.30.3",
|
"react-router-dom": "6.30.3",
|
||||||
"sanitize-html": "2.12.1",
|
"sanitize-html": "2.17.4",
|
||||||
"slate": "0.123.0",
|
"slate": "0.123.0",
|
||||||
"slate-dom": "0.123.0",
|
"slate-dom": "0.123.0",
|
||||||
"slate-history": "0.113.1",
|
"slate-history": "0.113.1",
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
"@types/react": "18.2.39",
|
"@types/react": "18.2.39",
|
||||||
"@types/react-dom": "18.2.17",
|
"@types/react-dom": "18.2.17",
|
||||||
"@types/react-google-recaptcha": "2.1.8",
|
"@types/react-google-recaptcha": "2.1.8",
|
||||||
"@types/sanitize-html": "2.9.0",
|
"@types/sanitize-html": "2.16.1",
|
||||||
"@types/ua-parser-js": "0.7.36",
|
"@types/ua-parser-js": "0.7.36",
|
||||||
"@typescript-eslint/eslint-plugin": "5.46.1",
|
"@typescript-eslint/eslint-plugin": "5.46.1",
|
||||||
"@typescript-eslint/parser": "5.46.1",
|
"@typescript-eslint/parser": "5.46.1",
|
||||||
@@ -5691,12 +5691,13 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/sanitize-html": {
|
"node_modules/@types/sanitize-html": {
|
||||||
"version": "2.9.0",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.16.1.tgz",
|
||||||
"integrity": "sha512-4fP/kEcKNj2u39IzrxWYuf/FnCCwwQCpif6wwY6ROUS1EPRIfWJjGkY3HIowY1EX/VbX5e86yq8AAE7UPMgATg==",
|
"integrity": "sha512-n9wjs8bCOTyN/ynwD8s/nTcTreIHB1vf31vhLMGqUPNHaweKC4/fAl4Dj+hUlCTKYgm4P3k83fmiFfzkZ6sgMA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"htmlparser2": "^8.0.0"
|
"htmlparser2": "^10.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/scheduler": {
|
"node_modules/@types/scheduler": {
|
||||||
@@ -6041,7 +6042,7 @@
|
|||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||||
"devOptional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.14.0",
|
"version": "8.14.0",
|
||||||
@@ -6885,7 +6886,7 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||||
"devOptional": true,
|
"optional": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
@@ -9498,7 +9499,7 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
||||||
"devOptional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minipass": "^3.0.0"
|
"minipass": "^3.0.0"
|
||||||
},
|
},
|
||||||
@@ -9510,7 +9511,7 @@
|
|||||||
"version": "3.3.6",
|
"version": "3.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||||
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||||
"devOptional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"yallist": "^4.0.0"
|
"yallist": "^4.0.0"
|
||||||
},
|
},
|
||||||
@@ -9522,7 +9523,7 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
"devOptional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/fs.realpath": {
|
"node_modules/fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -10169,9 +10170,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/htmlparser2": {
|
"node_modules/htmlparser2": {
|
||||||
"version": "8.0.2",
|
"version": "10.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz",
|
||||||
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
"integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
"https://github.com/fb55/htmlparser2?sponsor=1",
|
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||||
{
|
{
|
||||||
@@ -10179,11 +10180,24 @@
|
|||||||
"url": "https://github.com/sponsors/fb55"
|
"url": "https://github.com/sponsors/fb55"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"domelementtype": "^2.3.0",
|
"domelementtype": "^2.3.0",
|
||||||
"domhandler": "^5.0.3",
|
"domhandler": "^5.0.3",
|
||||||
"domutils": "^3.0.1",
|
"domutils": "^3.2.2",
|
||||||
"entities": "^4.4.0"
|
"entities": "^7.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/htmlparser2/node_modules/entities": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/http-proxy-agent": {
|
"node_modules/http-proxy-agent": {
|
||||||
@@ -10448,6 +10462,7 @@
|
|||||||
"integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==",
|
"integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
"optional": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||||
}
|
}
|
||||||
@@ -11303,6 +11318,15 @@
|
|||||||
"node": ">=0.10"
|
"node": ">=0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/launder": {
|
||||||
|
"version": "1.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/launder/-/launder-1.7.1.tgz",
|
||||||
|
"integrity": "sha512-mU6WRz5EusL9ZZuiZ5SO4Y6C0P9PAUR9iwdb6bzj4KDihm28DiHFw+/yk9DBH4f+Pv1wuzQ4e2jV3oQ7mkIqvw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dayjs": "^1.11.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/leven": {
|
"node_modules/leven": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||||
@@ -12284,7 +12308,7 @@
|
|||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||||
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
|
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
|
||||||
"devOptional": true,
|
"optional": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@@ -12293,7 +12317,7 @@
|
|||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||||
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
||||||
"devOptional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minipass": "^3.0.0",
|
"minipass": "^3.0.0",
|
||||||
"yallist": "^4.0.0"
|
"yallist": "^4.0.0"
|
||||||
@@ -12306,7 +12330,7 @@
|
|||||||
"version": "3.3.6",
|
"version": "3.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||||
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||||
"devOptional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"yallist": "^4.0.0"
|
"yallist": "^4.0.0"
|
||||||
},
|
},
|
||||||
@@ -12318,13 +12342,13 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
"devOptional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/mkdirp": {
|
"node_modules/mkdirp": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
"devOptional": true,
|
"optional": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"mkdirp": "bin/cmd.js"
|
"mkdirp": "bin/cmd.js"
|
||||||
},
|
},
|
||||||
@@ -12465,7 +12489,7 @@
|
|||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
|
||||||
"integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
|
"integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
|
||||||
"devOptional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"abbrev": "1"
|
"abbrev": "1"
|
||||||
},
|
},
|
||||||
@@ -16198,14 +16222,16 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/sanitize-html": {
|
"node_modules/sanitize-html": {
|
||||||
"version": "2.12.1",
|
"version": "2.17.4",
|
||||||
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.17.4.tgz",
|
||||||
"integrity": "sha512-Plh+JAn0UVDpBRP/xEjsk+xDCoOvMBwQUf/K+/cBAVuTbtX8bj2VB7S1sL1dssVpykqp0/KPSesHrqXtokVBpA==",
|
"integrity": "sha512-2HW7v2ol/uAM7sX4hbD8Z59OGWmAPrvjL8E71UWlBcj6m+kcF6ilQBLny+cIgY214QJeJT5tQuxKKqX0SQqjGQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"deepmerge": "^4.2.2",
|
"deepmerge": "^4.2.2",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"htmlparser2": "^8.0.0",
|
"htmlparser2": "^10.1.0",
|
||||||
"is-plain-object": "^5.0.0",
|
"is-plain-object": "^5.0.0",
|
||||||
|
"launder": "^1.7.1",
|
||||||
"parse-srcset": "^1.0.2",
|
"parse-srcset": "^1.0.2",
|
||||||
"postcss": "^8.3.11"
|
"postcss": "^8.3.11"
|
||||||
}
|
}
|
||||||
@@ -17414,7 +17440,7 @@
|
|||||||
"version": "6.2.1",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||||
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
||||||
"devOptional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chownr": "^2.0.0",
|
"chownr": "^2.0.0",
|
||||||
"fs-minipass": "^2.0.0",
|
"fs-minipass": "^2.0.0",
|
||||||
@@ -17431,7 +17457,7 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
"devOptional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/temp-dir": {
|
"node_modules/temp-dir": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cinny",
|
"name": "cinny",
|
||||||
"version": "4.11.1",
|
"version": "4.12.1",
|
||||||
"description": "Yet another matrix client",
|
"description": "Yet another matrix client",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
"react-i18next": "15.0.0",
|
"react-i18next": "15.0.0",
|
||||||
"react-range": "1.8.14",
|
"react-range": "1.8.14",
|
||||||
"react-router-dom": "6.30.3",
|
"react-router-dom": "6.30.3",
|
||||||
"sanitize-html": "2.12.1",
|
"sanitize-html": "2.17.4",
|
||||||
"slate": "0.123.0",
|
"slate": "0.123.0",
|
||||||
"slate-dom": "0.123.0",
|
"slate-dom": "0.123.0",
|
||||||
"slate-history": "0.113.1",
|
"slate-history": "0.113.1",
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
"@types/react": "18.2.39",
|
"@types/react": "18.2.39",
|
||||||
"@types/react-dom": "18.2.17",
|
"@types/react-dom": "18.2.17",
|
||||||
"@types/react-google-recaptcha": "2.1.8",
|
"@types/react-google-recaptcha": "2.1.8",
|
||||||
"@types/sanitize-html": "2.9.0",
|
"@types/sanitize-html": "2.16.1",
|
||||||
"@types/ua-parser-js": "0.7.36",
|
"@types/ua-parser-js": "0.7.36",
|
||||||
"@typescript-eslint/eslint-plugin": "5.46.1",
|
"@typescript-eslint/eslint-plugin": "5.46.1",
|
||||||
"@typescript-eslint/parser": "5.46.1",
|
"@typescript-eslint/parser": "5.46.1",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
OverlayBackdrop,
|
OverlayBackdrop,
|
||||||
OverlayCenter,
|
OverlayCenter,
|
||||||
Text,
|
Text,
|
||||||
|
toRem,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
import {
|
import {
|
||||||
EventTimelineSetHandlerMap,
|
EventTimelineSetHandlerMap,
|
||||||
@@ -54,6 +55,8 @@ import { getPowersLevelFromMatrixEvent } from '../hooks/usePowerLevels';
|
|||||||
import { getRoomCreatorsForRoomId } from '../hooks/useRoomCreators';
|
import { getRoomCreatorsForRoomId } from '../hooks/useRoomCreators';
|
||||||
import { getRoomPermissionsAPI } from '../hooks/useRoomPermissions';
|
import { getRoomPermissionsAPI } from '../hooks/useRoomPermissions';
|
||||||
import { useLivekitSupport } from '../hooks/useLivekitSupport';
|
import { useLivekitSupport } from '../hooks/useLivekitSupport';
|
||||||
|
import { CallAvatarAnimation } from '../styles/Animations.css';
|
||||||
|
import { webRTCSupported } from '../utils/rtc';
|
||||||
|
|
||||||
type IncomingCallInfo = {
|
type IncomingCallInfo = {
|
||||||
room: Room;
|
room: Room;
|
||||||
@@ -75,6 +78,8 @@ function IncomingCall({ dm, info, onIgnore, onAnswer, onReject }: IncomingCallPr
|
|||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
const livekitSupported = useLivekitSupport();
|
const livekitSupported = useLivekitSupport();
|
||||||
|
const rtcSupported = webRTCSupported();
|
||||||
|
const canAnswer = livekitSupported && rtcSupported;
|
||||||
const { room } = info;
|
const { room } = info;
|
||||||
|
|
||||||
const audioRef = useRef<HTMLAudioElement>(null);
|
const audioRef = useRef<HTMLAudioElement>(null);
|
||||||
@@ -110,7 +115,7 @@ function IncomingCall({ dm, info, onIgnore, onAnswer, onReject }: IncomingCallPr
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Overlay open backdrop={<OverlayBackdrop />}>
|
<Overlay open backdrop={<OverlayBackdrop />}>
|
||||||
<OverlayCenter style={{ alignItems: 'start', paddingTop: config.space.S100 }}>
|
<OverlayCenter>
|
||||||
<FocusTrap
|
<FocusTrap
|
||||||
focusTrapOptions={{
|
focusTrapOptions={{
|
||||||
initialFocus: false,
|
initialFocus: false,
|
||||||
@@ -119,73 +124,36 @@ function IncomingCall({ dm, info, onIgnore, onAnswer, onReject }: IncomingCallPr
|
|||||||
escapeDeactivates: false,
|
escapeDeactivates: false,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Dialog>
|
<Dialog style={{ maxWidth: toRem(324) }}>
|
||||||
<Box
|
<Box style={{ padding: config.space.S400 }} direction="Column" gap="700">
|
||||||
style={{
|
<Text size="T200" align="Center">
|
||||||
padding: `${config.space.S300} ${config.space.S400} ${config.space.S400}`,
|
{info.sender}
|
||||||
}}
|
</Text>
|
||||||
direction="Column"
|
<Box direction="Column" gap="500" alignItems="Center">
|
||||||
gap="500"
|
<Box shrink="No">
|
||||||
>
|
<Avatar size="500" className={CallAvatarAnimation}>
|
||||||
<Box direction="Column" gap="300">
|
<RoomAvatar
|
||||||
<Box gap="200" alignItems="Center">
|
roomId={room.roomId}
|
||||||
{info.intent === 'video' && <Icon size="50" src={Icons.VideoCamera} filled />}
|
src={avatarUrl}
|
||||||
<Text size="L400">Incoming Call</Text>
|
alt={roomName}
|
||||||
|
renderFallback={() => (
|
||||||
|
<RoomIcon
|
||||||
|
roomType={room.getType()}
|
||||||
|
size="400"
|
||||||
|
joinRule={room.getJoinRule()}
|
||||||
|
filled
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
</Box>
|
</Box>
|
||||||
<Box direction="Row" gap="300" alignItems="Center">
|
<Box grow="Yes" direction="Column" gap="100">
|
||||||
<Box shrink="No">
|
<Text size="H3" align="Center" truncate>
|
||||||
<Avatar size="400">
|
{roomName}
|
||||||
<RoomAvatar
|
</Text>
|
||||||
roomId={room.roomId}
|
<Text size="T300">Incoming Call</Text>
|
||||||
src={avatarUrl}
|
|
||||||
alt={roomName}
|
|
||||||
renderFallback={() => (
|
|
||||||
<RoomIcon
|
|
||||||
roomType={room.getType()}
|
|
||||||
size="400"
|
|
||||||
joinRule={room.getJoinRule()}
|
|
||||||
filled
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Avatar>
|
|
||||||
</Box>
|
|
||||||
<Box grow="Yes" direction="Column" gap="0">
|
|
||||||
<Text size="H4" truncate>
|
|
||||||
{roomName}
|
|
||||||
</Text>
|
|
||||||
<Text size="T200">{info.sender}</Text>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box gap="300">
|
|
||||||
<Button
|
|
||||||
style={{ flexGrow: 1 }}
|
|
||||||
variant="Critical"
|
|
||||||
fill="Soft"
|
|
||||||
size="400"
|
|
||||||
radii="400"
|
|
||||||
onClick={() => (dm ? onReject(room, info.refEventId) : onIgnore())}
|
|
||||||
before={<Icon size="200" src={Icons.PhoneDown} filled />}
|
|
||||||
>
|
|
||||||
<Text as="span" size="B400">
|
|
||||||
{dm ? 'Reject' : 'Ignore'}
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
style={{ flexGrow: 1 }}
|
|
||||||
variant="Success"
|
|
||||||
size="400"
|
|
||||||
radii="400"
|
|
||||||
onClick={() => onAnswer(room, info.intent === 'video')}
|
|
||||||
before={<Icon size="200" src={Icons.Phone} filled />}
|
|
||||||
disabled={!livekitSupported}
|
|
||||||
>
|
|
||||||
<Text as="span" size="B400">
|
|
||||||
Answer
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
{!livekitSupported && (
|
{!livekitSupported && (
|
||||||
<Text
|
<Text
|
||||||
style={{ margin: 'auto', color: color.Critical.Main }}
|
style={{ margin: 'auto', color: color.Critical.Main }}
|
||||||
@@ -195,6 +163,49 @@ function IncomingCall({ dm, info, onIgnore, onAnswer, onReject }: IncomingCallPr
|
|||||||
Your homeserver does not support calling.
|
Your homeserver does not support calling.
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
{!webRTCSupported && (
|
||||||
|
<Text
|
||||||
|
style={{ margin: 'auto', color: color.Critical.Main }}
|
||||||
|
size="L400"
|
||||||
|
align="Center"
|
||||||
|
>
|
||||||
|
Your browser does not support WebRTC, which is required for calling.
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
<Box direction="Column" gap="300">
|
||||||
|
<Button
|
||||||
|
style={{ flexGrow: 1 }}
|
||||||
|
variant="Success"
|
||||||
|
size="400"
|
||||||
|
radii="400"
|
||||||
|
onClick={() => onAnswer(room, info.intent === 'video')}
|
||||||
|
before={
|
||||||
|
<Icon
|
||||||
|
size="200"
|
||||||
|
src={info.intent === 'video' ? Icons.VideoCamera : Icons.Phone}
|
||||||
|
filled
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
disabled={!canAnswer}
|
||||||
|
>
|
||||||
|
<Text as="span" size="B400">
|
||||||
|
Answer
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
style={{ flexGrow: 1 }}
|
||||||
|
variant="Success"
|
||||||
|
fill="Soft"
|
||||||
|
size="400"
|
||||||
|
radii="400"
|
||||||
|
onClick={() => (dm ? onReject(room, info.refEventId) : onIgnore())}
|
||||||
|
before={<Icon size="200" src={Icons.Cross} filled />}
|
||||||
|
>
|
||||||
|
<Text as="span" size="B400">
|
||||||
|
{dm ? 'Reject' : 'Ignore'}
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</FocusTrap>
|
</FocusTrap>
|
||||||
|
|||||||
@@ -255,10 +255,67 @@ const parseCodeBlockNode = (node: Element): CodeBlockElement[] | ParagraphElemen
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
const parseListNode = (
|
|
||||||
|
const parseListMarkdown = (
|
||||||
node: Element,
|
node: Element,
|
||||||
processText: ProcessTextCallback
|
processText: ProcessTextCallback,
|
||||||
): OrderedListElement[] | UnorderedListElement[] | ParagraphElement[] => {
|
depth = 0
|
||||||
|
): ParagraphElement[] => {
|
||||||
|
const md = isTag(node) && node.name === 'ul' ? '*' : '-';
|
||||||
|
const prefix = node.attribs['data-md'] ?? md;
|
||||||
|
const [starOrHyphen] = prefix.match(/^\*|-$/) ?? [];
|
||||||
|
const [digitOrChar] = prefix.match(/^[\da-zA-Z]/) ?? [];
|
||||||
|
|
||||||
|
const digit = digitOrChar ? parseInt(digitOrChar, 10) : undefined;
|
||||||
|
|
||||||
|
const lines: ParagraphElement[] = [];
|
||||||
|
let lineNo = digit === undefined || Number.isNaN(digit) ? digitOrChar ?? 1 : digit;
|
||||||
|
const pushLine = (line: InlineElement[]) => {
|
||||||
|
lines.push({
|
||||||
|
type: BlockType.Paragraph,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: `${Array(depth + 1).join(' ')}${starOrHyphen ? `${starOrHyphen} ` : `${lineNo}. `}`,
|
||||||
|
},
|
||||||
|
...line,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
if (typeof lineNo === 'string') {
|
||||||
|
lineNo = String.fromCharCode(lineNo.charCodeAt(0) + 1);
|
||||||
|
} else {
|
||||||
|
lineNo += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
node.children.forEach((child) => {
|
||||||
|
if (isText(child)) {
|
||||||
|
pushLine([{ text: processText(child.data) }]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTag(child)) {
|
||||||
|
if (child.name === 'ul' || child.name === 'ol') {
|
||||||
|
lines.push(...parseListMarkdown(child, processText, depth + 1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (child.name === 'li') {
|
||||||
|
child.children.forEach((c) => {
|
||||||
|
if (isTag(c) && (c.name === 'ul' || c.name === 'ol')) {
|
||||||
|
lines.push(...parseListMarkdown(c, processText, depth + 1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pushLine(getInlineElement(c, processText));
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pushLine(getInlineElement(child, processText));
|
||||||
|
});
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
};
|
||||||
|
const parseListLines = (children: ChildNode[], processText: ProcessTextCallback) => {
|
||||||
const listLines: Array<InlineElement[]> = [];
|
const listLines: Array<InlineElement[]> = [];
|
||||||
let lineHolder: InlineElement[] = [];
|
let lineHolder: InlineElement[] = [];
|
||||||
|
|
||||||
@@ -269,7 +326,7 @@ const parseListNode = (
|
|||||||
lineHolder = [];
|
lineHolder = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
node.children.forEach((child) => {
|
children.forEach((child) => {
|
||||||
if (isText(child)) {
|
if (isText(child)) {
|
||||||
lineHolder.push({ text: processText(child.data) });
|
lineHolder.push({ text: processText(child.data) });
|
||||||
return;
|
return;
|
||||||
@@ -292,24 +349,23 @@ const parseListNode = (
|
|||||||
});
|
});
|
||||||
appendLine();
|
appendLine();
|
||||||
|
|
||||||
const mdSequence = node.attribs['data-md'];
|
return listLines;
|
||||||
if (mdSequence !== undefined) {
|
};
|
||||||
const prefix = mdSequence || '-';
|
const parseListNode = (
|
||||||
const [starOrHyphen] = prefix.match(/^\*|-$/) ?? [];
|
node: Element,
|
||||||
return listLines.map((lineChildren) => ({
|
processText: ProcessTextCallback
|
||||||
type: BlockType.Paragraph,
|
): OrderedListElement[] | UnorderedListElement[] | ParagraphElement[] => {
|
||||||
children: [
|
if (node.attribs['data-md'] !== undefined) {
|
||||||
{ text: `${starOrHyphen ? `${starOrHyphen} ` : `${prefix}. `} ` },
|
return parseListMarkdown(node, processText);
|
||||||
...lineChildren,
|
|
||||||
],
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lines = parseListLines(node.childNodes, processText);
|
||||||
|
|
||||||
if (node.name === 'ol') {
|
if (node.name === 'ol') {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
type: BlockType.OrderedList,
|
type: BlockType.OrderedList,
|
||||||
children: listLines.map((lineChildren) => ({
|
children: lines.map((lineChildren) => ({
|
||||||
type: BlockType.ListItem,
|
type: BlockType.ListItem,
|
||||||
children: lineChildren,
|
children: lineChildren,
|
||||||
})),
|
})),
|
||||||
@@ -320,7 +376,7 @@ const parseListNode = (
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
type: BlockType.UnorderedList,
|
type: BlockType.UnorderedList,
|
||||||
children: listLines.map((lineChildren) => ({
|
children: lines.map((lineChildren) => ({
|
||||||
type: BlockType.ListItem,
|
type: BlockType.ListItem,
|
||||||
children: lineChildren,
|
children: lineChildren,
|
||||||
})),
|
})),
|
||||||
|
|||||||
@@ -28,7 +28,11 @@ import { copyToClipboard } from '../../utils/dom';
|
|||||||
import { getExploreServerPath } from '../../pages/pathUtils';
|
import { getExploreServerPath } from '../../pages/pathUtils';
|
||||||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
|
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
|
||||||
import { factoryRoomIdByAtoZ } from '../../utils/sort';
|
import { factoryRoomIdByAtoZ } from '../../utils/sort';
|
||||||
import { useMutualRooms, useMutualRoomsSupport } from '../../hooks/useMutualRooms';
|
import {
|
||||||
|
useMutualRooms,
|
||||||
|
useMutualRoomsSupport,
|
||||||
|
useUnstableMutualRoomsSupport,
|
||||||
|
} from '../../hooks/useMutualRooms';
|
||||||
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
|
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
|
||||||
import { useDirectRooms } from '../../pages/client/direct/useDirectRooms';
|
import { useDirectRooms } from '../../pages/client/direct/useDirectRooms';
|
||||||
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
|
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
|
||||||
@@ -233,7 +237,9 @@ type MutualRoomsData = {
|
|||||||
export function MutualRoomsChip({ userId }: { userId: string }) {
|
export function MutualRoomsChip({ userId }: { userId: string }) {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const mutualRoomSupported = useMutualRoomsSupport();
|
const mutualRoomSupported = useMutualRoomsSupport();
|
||||||
|
const mutualRoomUnstable = useUnstableMutualRoomsSupport();
|
||||||
const mutualRoomsState = useMutualRooms(userId);
|
const mutualRoomsState = useMutualRooms(userId);
|
||||||
|
console.log(mutualRoomSupported, mutualRoomsState);
|
||||||
const { navigateRoom, navigateSpace } = useRoomNavigate();
|
const { navigateRoom, navigateSpace } = useRoomNavigate();
|
||||||
const closeUserRoomProfile = useCloseUserRoomProfile();
|
const closeUserRoomProfile = useCloseUserRoomProfile();
|
||||||
const directs = useDirectRooms();
|
const directs = useDirectRooms();
|
||||||
@@ -279,7 +285,7 @@ export function MutualRoomsChip({ userId }: { userId: string }) {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
userId === mx.getSafeUserId() ||
|
userId === mx.getSafeUserId() ||
|
||||||
!mutualRoomSupported ||
|
(!mutualRoomSupported && !mutualRoomUnstable) ||
|
||||||
mutualRoomsState.status === AsyncStatus.Error
|
mutualRoomsState.status === AsyncStatus.Error
|
||||||
) {
|
) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { CallMemberRenderer } from './CallMemberCard';
|
|||||||
import * as css from './styles.css';
|
import * as css from './styles.css';
|
||||||
import { CallControls } from './CallControls';
|
import { CallControls } from './CallControls';
|
||||||
import { useLivekitSupport } from '../../hooks/useLivekitSupport';
|
import { useLivekitSupport } from '../../hooks/useLivekitSupport';
|
||||||
|
import { webRTCSupported } from '../../utils/rtc';
|
||||||
|
|
||||||
function LivekitServerMissingMessage() {
|
function LivekitServerMissingMessage() {
|
||||||
return (
|
return (
|
||||||
@@ -23,13 +24,27 @@ function LivekitServerMissingMessage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function WebRTCMissingError() {
|
||||||
|
return (
|
||||||
|
<Text style={{ margin: 'auto', color: color.Critical.Main }} size="L400" align="Center">
|
||||||
|
Your browser does not support WebRTC, which is required for calling.
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function JoinMessage({
|
function JoinMessage({
|
||||||
hasParticipant,
|
hasParticipant,
|
||||||
livekitSupported,
|
livekitSupported,
|
||||||
|
rtcSupported,
|
||||||
}: {
|
}: {
|
||||||
hasParticipant?: boolean;
|
hasParticipant?: boolean;
|
||||||
livekitSupported?: boolean;
|
livekitSupported?: boolean;
|
||||||
|
rtcSupported?: boolean;
|
||||||
}) {
|
}) {
|
||||||
|
if (rtcSupported === false) {
|
||||||
|
return <WebRTCMissingError />;
|
||||||
|
}
|
||||||
|
|
||||||
if (livekitSupported === false) {
|
if (livekitSupported === false) {
|
||||||
return <LivekitServerMissingMessage />;
|
return <LivekitServerMissingMessage />;
|
||||||
}
|
}
|
||||||
@@ -63,6 +78,7 @@ function CallPrescreen() {
|
|||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const room = useRoom();
|
const room = useRoom();
|
||||||
const livekitSupported = useLivekitSupport();
|
const livekitSupported = useLivekitSupport();
|
||||||
|
const rtcSupported = webRTCSupported();
|
||||||
|
|
||||||
const powerLevels = usePowerLevelsContext();
|
const powerLevels = usePowerLevelsContext();
|
||||||
const creators = useRoomCreators(room);
|
const creators = useRoomCreators(room);
|
||||||
@@ -80,7 +96,7 @@ function CallPrescreen() {
|
|||||||
const callEmbed = useCallEmbed();
|
const callEmbed = useCallEmbed();
|
||||||
const inOtherCall = callEmbed && callEmbed.roomId !== room.roomId;
|
const inOtherCall = callEmbed && callEmbed.roomId !== room.roomId;
|
||||||
|
|
||||||
const canJoin = hasPermission && livekitSupported;
|
const canJoin = hasPermission && livekitSupported && rtcSupported;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Scroll variant="Surface" hideTrack>
|
<Scroll variant="Surface" hideTrack>
|
||||||
@@ -103,7 +119,11 @@ function CallPrescreen() {
|
|||||||
<Box className={css.PrescreenMessage} alignItems="Center">
|
<Box className={css.PrescreenMessage} alignItems="Center">
|
||||||
{!inOtherCall &&
|
{!inOtherCall &&
|
||||||
(hasPermission ? (
|
(hasPermission ? (
|
||||||
<JoinMessage hasParticipant={hasParticipant} livekitSupported={livekitSupported} />
|
<JoinMessage
|
||||||
|
hasParticipant={hasParticipant}
|
||||||
|
livekitSupported={livekitSupported}
|
||||||
|
rtcSupported={rtcSupported}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<NoPermissionMessage />
|
<NoPermissionMessage />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ import { useCallPreferencesAtom } from '../../state/hooks/callPreferences';
|
|||||||
import { useAutoDiscoveryInfo } from '../../hooks/useAutoDiscoveryInfo';
|
import { useAutoDiscoveryInfo } from '../../hooks/useAutoDiscoveryInfo';
|
||||||
import { livekitSupport } from '../../hooks/useLivekitSupport';
|
import { livekitSupport } from '../../hooks/useLivekitSupport';
|
||||||
import { StateEvent } from '../../../types/matrix/room';
|
import { StateEvent } from '../../../types/matrix/room';
|
||||||
|
import { webRTCSupported } from '../../utils/rtc';
|
||||||
|
|
||||||
type RoomNavItemMenuProps = {
|
type RoomNavItemMenuProps = {
|
||||||
room: Room;
|
room: Room;
|
||||||
@@ -298,8 +299,8 @@ export function RoomNavItem({
|
|||||||
mx.getSafeUserId()
|
mx.getSafeUserId()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Do not join if missing permissions or no livekit support
|
// Do not join if missing permissions or no livekit support or no webRTC support
|
||||||
if (!hasCallPermission || !livekitSupport(autoDiscoveryInfo)) {
|
if (!hasCallPermission || !livekitSupport(autoDiscoveryInfo) || !webRTCSupported()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const usePermissionGroups = (): PermissionGroup[] => {
|
|||||||
state: true,
|
state: true,
|
||||||
key: StateEvent.GroupCallMemberPrefix,
|
key: StateEvent.GroupCallMemberPrefix,
|
||||||
},
|
},
|
||||||
name: 'Join Call',
|
name: 'Start or Join Call',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ import { ContainerColor } from '../../styles/ContainerColor.css';
|
|||||||
import { RoomSettingsPage } from '../../state/roomSettings';
|
import { RoomSettingsPage } from '../../state/roomSettings';
|
||||||
import { useCallEmbed, useCallStart } from '../../hooks/useCallEmbed';
|
import { useCallEmbed, useCallStart } from '../../hooks/useCallEmbed';
|
||||||
import { useLivekitSupport } from '../../hooks/useLivekitSupport';
|
import { useLivekitSupport } from '../../hooks/useLivekitSupport';
|
||||||
|
import { webRTCSupported } from '../../utils/rtc';
|
||||||
|
|
||||||
type RoomMenuProps = {
|
type RoomMenuProps = {
|
||||||
room: Room;
|
room: Room;
|
||||||
@@ -339,6 +340,14 @@ function CallButton() {
|
|||||||
fill="None"
|
fill="None"
|
||||||
ref={triggerRef}
|
ref={triggerRef}
|
||||||
onClick={handleOpenMenu}
|
onClick={handleOpenMenu}
|
||||||
|
onContextMenu={(evt) => {
|
||||||
|
evt.preventDefault();
|
||||||
|
startCall(room, {
|
||||||
|
microphone: true,
|
||||||
|
video: true,
|
||||||
|
sound: true,
|
||||||
|
});
|
||||||
|
}}
|
||||||
disabled={inAnotherCall || callStarted}
|
disabled={inAnotherCall || callStarted}
|
||||||
aria-pressed={!!menuAnchor}
|
aria-pressed={!!menuAnchor}
|
||||||
>
|
>
|
||||||
@@ -390,6 +399,7 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
|
|||||||
mx.getSafeUserId()
|
mx.getSafeUserId()
|
||||||
);
|
);
|
||||||
const livekitSupported = useLivekitSupport();
|
const livekitSupported = useLivekitSupport();
|
||||||
|
const rtcSupported = webRTCSupported();
|
||||||
|
|
||||||
const [menuAnchor, setMenuAnchor] = useState<RectCords>();
|
const [menuAnchor, setMenuAnchor] = useState<RectCords>();
|
||||||
const [pinMenuAnchor, setPinMenuAnchor] = useState<RectCords>();
|
const [pinMenuAnchor, setPinMenuAnchor] = useState<RectCords>();
|
||||||
@@ -584,7 +594,9 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
|
|||||||
</FocusTrap>
|
</FocusTrap>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{!room.isCallRoom() && livekitSupported && hasCallPermission && <CallButton />}
|
{!room.isCallRoom() && livekitSupported && rtcSupported && hasCallPermission && (
|
||||||
|
<CallButton />
|
||||||
|
)}
|
||||||
{screenSize === ScreenSize.Desktop && (
|
{screenSize === ScreenSize.Desktop && (
|
||||||
<TooltipProvider
|
<TooltipProvider
|
||||||
position="Bottom"
|
position="Bottom"
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export function About({ requestClose }: AboutProps) {
|
|||||||
<Box direction="Column" gap="100">
|
<Box direction="Column" gap="100">
|
||||||
<Box gap="100" alignItems="End">
|
<Box gap="100" alignItems="End">
|
||||||
<Text size="H3">Cinny</Text>
|
<Text size="H3">Cinny</Text>
|
||||||
<Text size="T200">v4.11.1</Text>
|
<Text size="T200">v4.12.1</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Text>Yet another matrix client.</Text>
|
<Text>Yet another matrix client.</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { MatrixClient, Method } from 'matrix-js-sdk';
|
||||||
import { useMatrixClient } from './useMatrixClient';
|
import { useMatrixClient } from './useMatrixClient';
|
||||||
import { AsyncState, useAsyncCallbackValue } from './useAsyncCallback';
|
import { AsyncState, useAsyncCallbackValue } from './useAsyncCallback';
|
||||||
import { useSpecVersions } from './useSpecVersions';
|
import { useSpecVersions } from './useSpecVersions';
|
||||||
|
|
||||||
export const useMutualRoomsSupport = (): boolean => {
|
export const useUnstableMutualRoomsSupport = (): boolean => {
|
||||||
const { unstable_features: unstableFeatures } = useSpecVersions();
|
const { unstable_features: unstableFeatures } = useSpecVersions();
|
||||||
|
|
||||||
const supported =
|
const supported =
|
||||||
@@ -14,16 +15,59 @@ export const useMutualRoomsSupport = (): boolean => {
|
|||||||
return !!supported;
|
return !!supported;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useMutualRoomsSupport = (): boolean => {
|
||||||
|
const { unstable_features: unstableFeatures, versions } = useSpecVersions();
|
||||||
|
|
||||||
|
const supported =
|
||||||
|
versions.includes('v1.19') ||
|
||||||
|
unstableFeatures?.['uk.half-shot.msc2666.query_mutual_rooms.stable'];
|
||||||
|
|
||||||
|
return !!supported;
|
||||||
|
};
|
||||||
|
|
||||||
|
type MutualRoomsOK = {
|
||||||
|
joined: string[];
|
||||||
|
next_batch?: string;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchAllMutualRooms = async (mx: MatrixClient, userId: string): Promise<string[]> => {
|
||||||
|
const mutualRooms: Set<string> = new Set();
|
||||||
|
|
||||||
|
let nextBatch: string | undefined;
|
||||||
|
do {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const result = await mx.http.authedRequest<MutualRoomsOK>(
|
||||||
|
Method.Get,
|
||||||
|
'/mutual_rooms',
|
||||||
|
{
|
||||||
|
user_id: userId,
|
||||||
|
from: nextBatch,
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
prefix: '/_matrix/client/v1',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
result.joined.forEach((r) => mutualRooms.add(r));
|
||||||
|
nextBatch = result.next_batch;
|
||||||
|
} while (typeof nextBatch === 'string');
|
||||||
|
|
||||||
|
return Array.from(mutualRooms);
|
||||||
|
};
|
||||||
|
|
||||||
export const useMutualRooms = (userId: string): AsyncState<string[], unknown> => {
|
export const useMutualRooms = (userId: string): AsyncState<string[], unknown> => {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
|
|
||||||
const supported = useMutualRoomsSupport();
|
const unstableSupport = useUnstableMutualRoomsSupport();
|
||||||
|
const support = useMutualRoomsSupport();
|
||||||
|
|
||||||
const [mutualRoomsState] = useAsyncCallbackValue(
|
const [mutualRoomsState] = useAsyncCallbackValue(
|
||||||
useCallback(
|
useCallback(() => {
|
||||||
() => (supported ? mx._unstable_getSharedRooms(userId) : Promise.resolve([])),
|
if (support) return fetchAllMutualRooms(mx, userId);
|
||||||
[mx, userId, supported]
|
if (unstableSupport) return mx._unstable_getSharedRooms(userId);
|
||||||
)
|
return Promise.resolve([]);
|
||||||
|
}, [mx, userId, unstableSupport, support])
|
||||||
);
|
);
|
||||||
|
|
||||||
return mutualRoomsState;
|
return mutualRoomsState;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export function AuthFooter() {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
v4.11.1
|
v4.12.1
|
||||||
</Text>
|
</Text>
|
||||||
<Text as="a" size="T300" href="https://twitter.com/cinnyapp" target="_blank" rel="noreferrer">
|
<Text as="a" size="T300" href="https://twitter.com/cinnyapp" target="_blank" rel="noreferrer">
|
||||||
Twitter
|
Twitter
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export function WelcomePage() {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer noopener"
|
rel="noreferrer noopener"
|
||||||
>
|
>
|
||||||
v4.11.1
|
v4.12.1
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ export function getCallCapabilities(
|
|||||||
|
|
||||||
capabilities.add(MatrixCapabilities.Screenshots);
|
capabilities.add(MatrixCapabilities.Screenshots);
|
||||||
capabilities.add(MatrixCapabilities.AlwaysOnScreen);
|
capabilities.add(MatrixCapabilities.AlwaysOnScreen);
|
||||||
|
capabilities.add(MatrixCapabilities.MSC4039UploadFile);
|
||||||
|
capabilities.add(MatrixCapabilities.MSC4039DownloadFile);
|
||||||
capabilities.add(MatrixCapabilities.MSC3846TurnServers);
|
capabilities.add(MatrixCapabilities.MSC3846TurnServers);
|
||||||
capabilities.add(MatrixCapabilities.MSC4157SendDelayedEvent);
|
capabilities.add(MatrixCapabilities.MSC4157SendDelayedEvent);
|
||||||
capabilities.add(MatrixCapabilities.MSC4157UpdateDelayedEvent);
|
capabilities.add(MatrixCapabilities.MSC4157UpdateDelayedEvent);
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
import { replaceMatch } from '../internal';
|
import { replaceMatch } from '../internal';
|
||||||
import {
|
import { BlockQuoteRule, CodeBlockRule, ESC_BLOCK_SEQ, HeadingRule, ListRule } from './rules';
|
||||||
BlockQuoteRule,
|
|
||||||
CodeBlockRule,
|
|
||||||
ESC_BLOCK_SEQ,
|
|
||||||
HeadingRule,
|
|
||||||
OrderedListRule,
|
|
||||||
UnorderedListRule,
|
|
||||||
} from './rules';
|
|
||||||
import { runBlockRule } from './runner';
|
import { runBlockRule } from './runner';
|
||||||
import { BlockMDParser } from './type';
|
import { BlockMDParser } from './type';
|
||||||
|
|
||||||
@@ -23,8 +16,7 @@ export const parseBlockMD: BlockMDParser = (text, parseInline) => {
|
|||||||
|
|
||||||
if (!result) result = runBlockRule(text, CodeBlockRule, parseBlockMD, parseInline);
|
if (!result) result = runBlockRule(text, CodeBlockRule, parseBlockMD, parseInline);
|
||||||
if (!result) result = runBlockRule(text, BlockQuoteRule, parseBlockMD, parseInline);
|
if (!result) result = runBlockRule(text, BlockQuoteRule, parseBlockMD, parseInline);
|
||||||
if (!result) result = runBlockRule(text, OrderedListRule, parseBlockMD, parseInline);
|
if (!result) result = runBlockRule(text, ListRule, parseBlockMD, parseInline);
|
||||||
if (!result) result = runBlockRule(text, UnorderedListRule, parseBlockMD, parseInline);
|
|
||||||
if (!result) result = runBlockRule(text, HeadingRule, parseBlockMD, parseInline);
|
if (!result) result = runBlockRule(text, HeadingRule, parseBlockMD, parseInline);
|
||||||
|
|
||||||
// replace \n with <br/> because want to preserve empty lines
|
// replace \n with <br/> because want to preserve empty lines
|
||||||
|
|||||||
@@ -10,18 +10,22 @@ export const HeadingRule: BlockMDRule = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const CODEBLOCK_MD_1 = '```';
|
// opening fence: 3 or more backticks
|
||||||
const CODEBLOCK_REG_1 = /^`{3}(\S*)\n((?:.*\n)+?)`{3} *(?!.)\n?/m;
|
// capture the exact fence length in group 1
|
||||||
|
// optional info string in group 2
|
||||||
|
// code content in group 3
|
||||||
|
// closing fence must match the exact same fence sequence via \1
|
||||||
|
const CODEBLOCK_REG_1 = /^(`{3,})(?!`)(\S*)\n((?:.*\n)+?)\1 *(?!.)\n?/m;
|
||||||
export const CodeBlockRule: BlockMDRule = {
|
export const CodeBlockRule: BlockMDRule = {
|
||||||
match: (text) => text.match(CODEBLOCK_REG_1),
|
match: (text) => text.match(CODEBLOCK_REG_1),
|
||||||
html: (match) => {
|
html: (match) => {
|
||||||
const [, g1, g2] = match;
|
const [, fence, g1, g2] = match;
|
||||||
// use last identifier after dot, e.g. for "example.json" gets us "json" as language code.
|
// use last identifier after dot, e.g. for "example.json" gets us "json" as language code.
|
||||||
const langCode = g1 ? g1.substring(g1.lastIndexOf('.') + 1) : null;
|
const langCode = g1 ? g1.substring(g1.lastIndexOf('.') + 1) : null;
|
||||||
const filename = g1 !== langCode ? g1 : null;
|
const filename = g1 !== langCode ? g1 : null;
|
||||||
const classNameAtt = langCode ? ` class="language-${langCode}"` : '';
|
const classNameAtt = langCode ? ` class="language-${langCode}"` : '';
|
||||||
const filenameAtt = filename ? ` data-label="${filename}"` : '';
|
const filenameAtt = filename ? ` data-label="${filename}"` : '';
|
||||||
return `<pre data-md="${CODEBLOCK_MD_1}"><code${classNameAtt}${filenameAtt}>${g2}</code></pre>`;
|
return `<pre data-md="${fence}"><code${classNameAtt}${filenameAtt}>${g2}</code></pre>`;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,55 +52,146 @@ export const BlockQuoteRule: BlockMDRule = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ORDERED_LIST_MD_1 = '-';
|
const ORDERED_LIST_MD_1 = '-';
|
||||||
const O_LIST_ITEM_PREFIX = /^(-|[\da-zA-Z]\.) */;
|
|
||||||
const O_LIST_START = /^([\d])\./;
|
|
||||||
const O_LIST_TYPE = /^([aAiI])\./;
|
|
||||||
const O_LIST_TRAILING_NEWLINE = /\n$/;
|
|
||||||
const ORDERED_LIST_REG_1 = /(^(?:-|[\da-zA-Z]\.) +.+\n?)+/m;
|
|
||||||
export const OrderedListRule: BlockMDRule = {
|
|
||||||
match: (text) => text.match(ORDERED_LIST_REG_1),
|
|
||||||
html: (match, parseInline) => {
|
|
||||||
const [listText] = match;
|
|
||||||
const [, listStart] = listText.match(O_LIST_START) ?? [];
|
|
||||||
const [, listType] = listText.match(O_LIST_TYPE) ?? [];
|
|
||||||
|
|
||||||
const lines = listText
|
|
||||||
.replace(O_LIST_TRAILING_NEWLINE, '')
|
|
||||||
.split('\n')
|
|
||||||
.map((lineText) => {
|
|
||||||
const line = lineText.replace(O_LIST_ITEM_PREFIX, '');
|
|
||||||
const txt = parseInline ? parseInline(line) : line;
|
|
||||||
return `<li><p>${txt}</p></li>`;
|
|
||||||
})
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
const dataMdAtt = `data-md="${listType || listStart || ORDERED_LIST_MD_1}"`;
|
|
||||||
const startAtt = listStart ? ` start="${listStart}"` : '';
|
|
||||||
const typeAtt = listType ? ` type="${listType}"` : '';
|
|
||||||
return `<ol ${dataMdAtt}${startAtt}${typeAtt}>${lines}</ol>`;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const UNORDERED_LIST_MD_1 = '*';
|
const UNORDERED_LIST_MD_1 = '*';
|
||||||
const U_LIST_ITEM_PREFIX = /^\* */;
|
const LIST_ITEM_REG = /^( *)([-*]|[\da-zA-Z]\.) +(.+)$/;
|
||||||
const U_LIST_TRAILING_NEWLINE = /\n$/;
|
type ListType = 'ol' | 'ul';
|
||||||
const UNORDERED_LIST_REG_1 = /(^\* +.+\n?)+/m;
|
|
||||||
export const UnorderedListRule: BlockMDRule = {
|
function getListType(marker: string): ListType {
|
||||||
match: (text) => text.match(UNORDERED_LIST_REG_1),
|
return marker === '*' ? 'ul' : 'ol';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOrderedMeta(marker: string) {
|
||||||
|
const startMatch = marker.match(/^(\d)\./);
|
||||||
|
const typeMatch = marker.match(/^([aAiI])\./);
|
||||||
|
|
||||||
|
return {
|
||||||
|
start: startMatch?.[1],
|
||||||
|
type: typeMatch?.[1],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParsedLine {
|
||||||
|
indent: number;
|
||||||
|
marker: string;
|
||||||
|
content: string;
|
||||||
|
listType: ListType;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseLines(text: string): ParsedLine[] {
|
||||||
|
return text
|
||||||
|
.replace(/\n$/, '')
|
||||||
|
.split('\n')
|
||||||
|
.map((line) => {
|
||||||
|
const match = line.match(LIST_ITEM_REG);
|
||||||
|
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
const [, spaces, marker, content] = match;
|
||||||
|
|
||||||
|
return {
|
||||||
|
indent: spaces.length,
|
||||||
|
marker,
|
||||||
|
content,
|
||||||
|
listType: getListType(marker),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(Boolean) as ParsedLine[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function openList(line: ParsedLine) {
|
||||||
|
if (line.listType === 'ul') {
|
||||||
|
return `<ul data-md="${UNORDERED_LIST_MD_1}">`;
|
||||||
|
}
|
||||||
|
const { type, start } = getOrderedMeta(line.marker);
|
||||||
|
const dataMdAtt = `data-md="${type || start || ORDERED_LIST_MD_1}"`;
|
||||||
|
const startAtt = start ? ` start="${start}"` : '';
|
||||||
|
const typeAtt = type ? ` type="${type}"` : '';
|
||||||
|
return `<ol ${dataMdAtt}${startAtt}${typeAtt}>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeList(listType: ListType) {
|
||||||
|
return listType === 'ul' ? '</ul>' : '</ol>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildList(lines: ParsedLine[], parseInline?: (s: string) => string): string {
|
||||||
|
let html = '';
|
||||||
|
|
||||||
|
const stack: ('ul' | 'ol')[] = [];
|
||||||
|
|
||||||
|
lines.forEach((line, index) => {
|
||||||
|
const prev = lines[index - 1];
|
||||||
|
const next = lines[index + 1];
|
||||||
|
|
||||||
|
const content = parseInline ? parseInline(line.content) : line.content;
|
||||||
|
|
||||||
|
// FIRST ITEM
|
||||||
|
if (!prev) {
|
||||||
|
html += openList(line);
|
||||||
|
stack.push(line.listType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEEPER INDENT > open nested list
|
||||||
|
else if (line.indent > prev.indent) {
|
||||||
|
html += openList(line);
|
||||||
|
stack.push(line.listType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAME LEVEL
|
||||||
|
else if (line.indent === prev.indent) {
|
||||||
|
html += '</li>';
|
||||||
|
|
||||||
|
// different list type
|
||||||
|
if (line.listType !== prev.listType) {
|
||||||
|
html += closeList(stack.pop()!);
|
||||||
|
|
||||||
|
html += openList(line);
|
||||||
|
stack.push(line.listType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GOING BACK UP
|
||||||
|
else if (line.indent < prev.indent) {
|
||||||
|
html += '</li>';
|
||||||
|
|
||||||
|
while (stack.length > line.indent + 1) {
|
||||||
|
html += closeList(stack.pop()!);
|
||||||
|
html += '</li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.listType !== stack[stack.length - 1]) {
|
||||||
|
html += closeList(stack.pop()!);
|
||||||
|
|
||||||
|
html += openList(line);
|
||||||
|
stack.push(line.listType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html += `<li><p>${content}</p>`;
|
||||||
|
|
||||||
|
// LAST ITEM cleanup
|
||||||
|
if (!next) {
|
||||||
|
html += '</li>';
|
||||||
|
|
||||||
|
while (stack.length) {
|
||||||
|
html += closeList(stack.pop()!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LIST_REG_1 = /^(?: *(?:[-*]|[\da-zA-Z]\.) +.+\n?)+/m;
|
||||||
|
export const ListRule: BlockMDRule = {
|
||||||
|
match: (text) => text.match(LIST_REG_1),
|
||||||
html: (match, parseInline) => {
|
html: (match, parseInline) => {
|
||||||
const [listText] = match;
|
const [listText] = match;
|
||||||
|
|
||||||
const lines = listText
|
const lines = parseLines(listText);
|
||||||
.replace(U_LIST_TRAILING_NEWLINE, '')
|
|
||||||
.split('\n')
|
|
||||||
.map((lineText) => {
|
|
||||||
const line = lineText.replace(U_LIST_ITEM_PREFIX, '');
|
|
||||||
const txt = parseInline ? parseInline(line) : line;
|
|
||||||
return `<li><p>${txt}</p></li>`;
|
|
||||||
})
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
return `<ul data-md="${UNORDERED_LIST_MD_1}">${lines}</ul>`;
|
const html = buildList(lines, parseInline);
|
||||||
|
|
||||||
|
return html;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { keyframes, style } from '@vanilla-extract/css';
|
||||||
|
import { color, toRem } from 'folds';
|
||||||
|
|
||||||
|
const wobble = keyframes({
|
||||||
|
'0%': {
|
||||||
|
transform: 'translateX(0) rotateZ(0deg)',
|
||||||
|
},
|
||||||
|
'20%': {
|
||||||
|
transform: `translateX(-${toRem(4)}) rotateZ(-4deg)`,
|
||||||
|
},
|
||||||
|
'40%': {
|
||||||
|
transform: `translateX(${toRem(4)}) rotateZ(4deg)`,
|
||||||
|
},
|
||||||
|
'60%': {
|
||||||
|
transform: `translateX(-${toRem(3)}) rotateZ(-3deg)`,
|
||||||
|
},
|
||||||
|
'80%': {
|
||||||
|
transform: `translateX(${toRem(3)}) rotateZ(3deg)`,
|
||||||
|
},
|
||||||
|
'100%': {
|
||||||
|
transform: 'translateX(0) rotateZ(0deg)',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const glowPulse = keyframes({
|
||||||
|
'0%': {
|
||||||
|
boxShadow: `0 0 0 ${toRem(0)} ${color.Success.ContainerActive}`,
|
||||||
|
},
|
||||||
|
'100%': {
|
||||||
|
boxShadow: `0 0 0 ${toRem(8)} ${color.Success.ContainerActive}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WobbleAnimation = style({
|
||||||
|
animation: `${wobble} 2000ms ease-in-out`,
|
||||||
|
animationIterationCount: 'infinite',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const GlowAnimation = style({
|
||||||
|
animation: `${glowPulse} 2000ms ease-out`,
|
||||||
|
animationIterationCount: 'infinite',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CallAvatarAnimation = style({
|
||||||
|
animation: `${wobble} 2000ms ease-in-out, ${glowPulse} 2000ms ease-out`,
|
||||||
|
animationIterationCount: 'infinite',
|
||||||
|
});
|
||||||
@@ -120,12 +120,23 @@ export const CodeBlockBottomShadow = style({
|
|||||||
background: `linear-gradient(to top, #00000022, #00000000)`,
|
background: `linear-gradient(to top, #00000022, #00000000)`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const BaseList = style({});
|
||||||
export const List = style([
|
export const List = style([
|
||||||
|
BaseList,
|
||||||
DefaultReset,
|
DefaultReset,
|
||||||
MarginSpaced,
|
MarginSpaced,
|
||||||
{
|
{
|
||||||
padding: `0 ${config.space.S100}`,
|
padding: `0 ${config.space.S100}`,
|
||||||
paddingLeft: config.space.S600,
|
paddingLeft: config.space.S600,
|
||||||
|
selectors: {
|
||||||
|
'& &': {
|
||||||
|
marginTop: config.space.S200,
|
||||||
|
marginBottom: config.space.S200,
|
||||||
|
},
|
||||||
|
'li:last-child &': {
|
||||||
|
marginBottom: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -233,7 +233,15 @@ export const notificationPermission = (permission: NotificationPermission) => {
|
|||||||
if ('Notification' in window) {
|
if ('Notification' in window) {
|
||||||
return window.Notification.permission === permission;
|
return window.Notification.permission === permission;
|
||||||
}
|
}
|
||||||
return false;
|
try {
|
||||||
|
// https://stackoverflow.com/questions/29774836/failed-to-construct-notification-illegal-constructor
|
||||||
|
// https://issues.chromium.org/issues/40415865
|
||||||
|
// eslint-disable-next-line no-new
|
||||||
|
new Notification('');
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getMouseEventCords = (event: MouseEvent) => ({
|
export const getMouseEventCords = (event: MouseEvent) => ({
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export const APPLICATION_MIME_TYPES = [
|
|||||||
'application/javascript',
|
'application/javascript',
|
||||||
'application/xhtml+xml',
|
'application/xhtml+xml',
|
||||||
'application/xml',
|
'application/xml',
|
||||||
|
'application/ogg',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const TEXT_MIME_TYPE = [
|
export const TEXT_MIME_TYPE = [
|
||||||
@@ -115,6 +116,10 @@ export const getBlobSafeMimeType = (mimeType: string) => {
|
|||||||
if (type === 'video/quicktime') {
|
if (type === 'video/quicktime') {
|
||||||
return 'video/mp4';
|
return 'video/mp4';
|
||||||
}
|
}
|
||||||
|
// Fixes missing playback for Ogg audio
|
||||||
|
if (type === 'application/ogg') {
|
||||||
|
return 'audio/ogg';
|
||||||
|
}
|
||||||
return type;
|
return type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export const webRTCSupported = () =>
|
||||||
|
['RTCPeerConnection', 'webkitRTCPeerConnection', 'mozRTCPeerConnection', 'RTCIceGatherer'].some(
|
||||||
|
(item) => item in window
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user