Compare commits

..

16 Commits

Author SHA1 Message Date
Krishan
17fabcaf02 Release v2.1.3 2022-08-31 21:25:35 +05:30
Krishan
44875d0de0 Bump matrix-js-sdk from 19.2.0 to 19.4.0 2022-08-31 21:07:18 +05:30
Ajay Bura
214d49f1d9 Release v2.1.2 2022-08-11 19:10:12 +05:30
dependabot[bot]
c4e36a1f97 Bump @fontsource/inter from 4.5.11 to 4.5.12 (#726)
Bumps [@fontsource/inter](https://github.com/fontsource/fontsource/tree/HEAD/fonts/google/inter) from 4.5.11 to 4.5.12.
- [Release notes](https://github.com/fontsource/fontsource/releases)
- [Changelog](https://github.com/fontsource/fontsource/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fontsource/fontsource/commits/HEAD/fonts/google/inter)

---
updated-dependencies:
- dependency-name: "@fontsource/inter"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-11 18:46:19 +05:30
dependabot[bot]
5de6a1bea6 Bump @fontsource/roboto from 4.5.7 to 4.5.8 (#727)
Bumps [@fontsource/roboto](https://github.com/fontsource/fontsource/tree/HEAD/fonts/google/roboto) from 4.5.7 to 4.5.8.
- [Release notes](https://github.com/fontsource/fontsource/releases)
- [Changelog](https://github.com/fontsource/fontsource/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fontsource/fontsource/commits/HEAD/fonts/google/roboto)

---
updated-dependencies:
- dependency-name: "@fontsource/roboto"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-11 18:44:00 +05:30
dependabot[bot]
74a20a0e14 Bump sass from 1.54.1 to 1.54.3 (#728)
Bumps [sass](https://github.com/sass/dart-sass) from 1.54.1 to 1.54.3.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.54.1...1.54.3)

---
updated-dependencies:
- dependency-name: sass
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-11 18:43:31 +05:30
Ajay Bura
820d08017a Fix image not loading without h/w data (#738) 2022-08-11 18:41:09 +05:30
Ajay Bura
258afec391 Only render mxc images in markdown 2022-08-11 17:20:55 +05:30
Ajay Bura
0cf5aac591 Fix emoji board style 2022-08-11 16:31:02 +05:30
Ajay Bura
59fd34a4b4 Replace space by underscore in emoji shortcodes 2022-08-11 16:24:22 +05:30
Ajay Bura
1da3d252e8 Add navigation bar to sticker board 2022-08-11 16:13:53 +05:30
Ajay Bura
3c1cc59d59 Escape html with markdown off (#732) 2022-08-11 14:28:39 +05:30
Ajay Bura
1692098d5d Fix logout not working when server offline 2022-08-11 13:41:07 +05:30
Ajay Bura
fbab53af22 Merge branch 'dev' of https://github.com/ajbura/cinny into dev 2022-08-11 13:33:59 +05:30
Ajay Bura
ce1e263d57 Only scale image bigger than 512px (#731) 2022-08-11 13:33:54 +05:30
dependabot[bot]
9f99320fda Bump docker/build-push-action from 3.1.0 to 3.1.1 (#725)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-09 09:30:34 +05:30
18 changed files with 239 additions and 170 deletions

View File

@@ -15,7 +15,7 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3.0.2
- name: Build Docker image
uses: docker/build-push-action@v3.1.0
uses: docker/build-push-action@v3.1.1
with:
context: .
push: false

View File

@@ -86,7 +86,7 @@ jobs:
with:
images: ajbura/cinny
- name: Build and push Docker image
uses: docker/build-push-action@v3.1.0
uses: docker/build-push-action@v3.1.1
with:
context: .
platforms: linux/amd64,linux/arm64

60
package-lock.json generated
View File

@@ -1,16 +1,16 @@
{
"name": "cinny",
"version": "2.1.1",
"version": "2.1.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cinny",
"version": "2.1.1",
"version": "2.1.3",
"license": "MIT",
"dependencies": {
"@fontsource/inter": "^4.5.11",
"@fontsource/roboto": "^4.5.7",
"@fontsource/inter": "^4.5.12",
"@fontsource/roboto": "^4.5.8",
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.12.tgz",
"@tippyjs/react": "^4.2.6",
"babel-polyfill": "^6.26.0",
@@ -25,7 +25,7 @@
"katex": "^0.16.0",
"linkify-html": "^4.0.0-beta.5",
"linkifyjs": "^4.0.0-beta.5",
"matrix-js-sdk": "^19.2.0",
"matrix-js-sdk": "^19.4.0",
"micromark": "^3.0.10",
"micromark-extension-gfm": "^2.0.1",
"micromark-extension-math": "^2.0.2",
@@ -70,7 +70,7 @@
"html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^2.6.1",
"path-browserify": "^1.0.1",
"sass": "^1.54.1",
"sass": "^1.54.3",
"sass-loader": "^13.0.2",
"stream-browserify": "^3.0.0",
"style-loader": "^3.3.1",
@@ -1837,14 +1837,14 @@
}
},
"node_modules/@fontsource/inter": {
"version": "4.5.11",
"resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.11.tgz",
"integrity": "sha512-toizzQkfXL8YJcG/f8j3EYXYGQe4OxiDEItThSigvHU+cYNDw8HPp3wLYQX745hddsnHqOGCM4exitFSBOU8+w=="
"version": "4.5.12",
"resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.12.tgz",
"integrity": "sha512-bGKk4/8tube/nCk8hav0ZDBVbzJzc7m0Vt4xF5p15IN4YImwGdtKG38Oq5bU8xHNS+VfvbFFCepgQNj7Pr/Lvg=="
},
"node_modules/@fontsource/roboto": {
"version": "4.5.7",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.7.tgz",
"integrity": "sha512-m57UMER23Mk6Drg9OjtHW1Y+0KPGyZfE5XJoPTOsLARLar6013kJj4X2HICt+iFLJqIgTahA/QAvSn9lwF1EEw=="
"version": "4.5.8",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.8.tgz",
"integrity": "sha512-CnD7zLItIzt86q4Sj3kZUiLcBk1dSk81qcqgMGaZe7SQ1P8hFNxhMl5AZthK1zrDM5m74VVhaOpuMGIL4gagaA=="
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.10.4",
@@ -9104,9 +9104,9 @@
"integrity": "sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA=="
},
"node_modules/matrix-js-sdk": {
"version": "19.2.0",
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-19.2.0.tgz",
"integrity": "sha512-alvTasCTCo/XXSIkKEj8xKe1NMsyiVDDVIQdU9ZHI1aePq+DrAcx8CqB7L/dgjk842v+63Eke1f/jZuFWvjn4w==",
"version": "19.4.0",
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-19.4.0.tgz",
"integrity": "sha512-B8Mm4jCsCHaMaChcdM3VhZDVKrn0nMSDtYvHmS15Iu8Pe0G4qmIpk2AoADBAL9U9yN3pCqvs3TDXaQhM8UxRRA==",
"dependencies": {
"@babel/runtime": "^7.12.5",
"another-json": "^0.2.0",
@@ -12181,9 +12181,9 @@
}
},
"node_modules/sass": {
"version": "1.54.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.54.1.tgz",
"integrity": "sha512-GHJJr31Me32RjjUBagyzx8tzjKBUcDwo5239XANIRBq0adDu5iIG0aFO0i/TBb/4I9oyxkEv44nq/kL1DxdDhA==",
"version": "1.54.3",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.54.3.tgz",
"integrity": "sha512-fLodey5Qd41Pxp/Tk7Al97sViYwF/TazRc5t6E65O7JOk4XF8pzwIW7CvCxYVOfJFFI/1x5+elDyBIixrp+zrw==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
@@ -15526,14 +15526,14 @@
}
},
"@fontsource/inter": {
"version": "4.5.11",
"resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.11.tgz",
"integrity": "sha512-toizzQkfXL8YJcG/f8j3EYXYGQe4OxiDEItThSigvHU+cYNDw8HPp3wLYQX745hddsnHqOGCM4exitFSBOU8+w=="
"version": "4.5.12",
"resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.12.tgz",
"integrity": "sha512-bGKk4/8tube/nCk8hav0ZDBVbzJzc7m0Vt4xF5p15IN4YImwGdtKG38Oq5bU8xHNS+VfvbFFCepgQNj7Pr/Lvg=="
},
"@fontsource/roboto": {
"version": "4.5.7",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.7.tgz",
"integrity": "sha512-m57UMER23Mk6Drg9OjtHW1Y+0KPGyZfE5XJoPTOsLARLar6013kJj4X2HICt+iFLJqIgTahA/QAvSn9lwF1EEw=="
"version": "4.5.8",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.8.tgz",
"integrity": "sha512-CnD7zLItIzt86q4Sj3kZUiLcBk1dSk81qcqgMGaZe7SQ1P8hFNxhMl5AZthK1zrDM5m74VVhaOpuMGIL4gagaA=="
},
"@humanwhocodes/config-array": {
"version": "0.10.4",
@@ -21248,9 +21248,9 @@
"integrity": "sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA=="
},
"matrix-js-sdk": {
"version": "19.2.0",
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-19.2.0.tgz",
"integrity": "sha512-alvTasCTCo/XXSIkKEj8xKe1NMsyiVDDVIQdU9ZHI1aePq+DrAcx8CqB7L/dgjk842v+63Eke1f/jZuFWvjn4w==",
"version": "19.4.0",
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-19.4.0.tgz",
"integrity": "sha512-B8Mm4jCsCHaMaChcdM3VhZDVKrn0nMSDtYvHmS15Iu8Pe0G4qmIpk2AoADBAL9U9yN3pCqvs3TDXaQhM8UxRRA==",
"requires": {
"@babel/runtime": "^7.12.5",
"another-json": "^0.2.0",
@@ -23442,9 +23442,9 @@
}
},
"sass": {
"version": "1.54.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.54.1.tgz",
"integrity": "sha512-GHJJr31Me32RjjUBagyzx8tzjKBUcDwo5239XANIRBq0adDu5iIG0aFO0i/TBb/4I9oyxkEv44nq/kL1DxdDhA==",
"version": "1.54.3",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.54.3.tgz",
"integrity": "sha512-fLodey5Qd41Pxp/Tk7Al97sViYwF/TazRc5t6E65O7JOk4XF8pzwIW7CvCxYVOfJFFI/1x5+elDyBIixrp+zrw==",
"dev": true,
"requires": {
"chokidar": ">=3.0.0 <4.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "cinny",
"version": "2.1.1",
"version": "2.1.3",
"description": "Yet another matrix client",
"main": "index.js",
"engines": {
@@ -15,8 +15,8 @@
"author": "Ajay Bura",
"license": "MIT",
"dependencies": {
"@fontsource/inter": "^4.5.11",
"@fontsource/roboto": "^4.5.7",
"@fontsource/inter": "^4.5.12",
"@fontsource/roboto": "^4.5.8",
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.12.tgz",
"@tippyjs/react": "^4.2.6",
"babel-polyfill": "^6.26.0",
@@ -31,7 +31,7 @@
"katex": "^0.16.0",
"linkify-html": "^4.0.0-beta.5",
"linkifyjs": "^4.0.0-beta.5",
"matrix-js-sdk": "^19.2.0",
"matrix-js-sdk": "^19.4.0",
"micromark": "^3.0.10",
"micromark-extension-gfm": "^2.0.1",
"micromark-extension-math": "^2.0.2",
@@ -76,7 +76,7 @@
"html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^2.6.1",
"path-browserify": "^1.0.1",
"sass": "^1.54.1",
"sass": "^1.54.3",
"sass-loader": "^13.0.2",
"stream-browserify": "^3.0.0",
"style-loader": "^3.3.1",

View File

@@ -118,7 +118,7 @@ function useImagePackHandles(pack, sendPackContent) {
const getNewKey = (key) => {
if (typeof key !== 'string') return undefined;
let newKey = key?.replace(/\s/g, '-');
let newKey = key?.replace(/\s/g, '_');
if (pack.getImages().get(newKey)) {
newKey = suffixRename(
newKey,

View File

@@ -41,11 +41,13 @@ function ImagePackUpload({ onUpload }) {
const img = evt.target.files[0];
if (!img) return;
setImgFile(img);
shortcodeRef.current.value = img.name.slice(0, img.name.indexOf('.'));
shortcodeRef.current.focus();
};
const handleRemove = () => {
setImgFile(null);
inputRef.current.value = null;
shortcodeRef.current.value = '';
};
return (

View File

@@ -178,7 +178,7 @@ function Image({
<FileHeader name={name} link={url || link} type={type} external />
<div style={{ height: width !== null ? getNativeHeight(width, height) : 'unset' }} className="image-container">
{ blurhash && blur && <BlurhashCanvas hash={blurhash} punch={1} />}
{ url !== null && <img onLoad={() => setBlur(false)} src={url || link} alt={name} />}
{ url !== null && <img style={{ display: blur ? 'none' : 'unset' }} onLoad={() => setBlur(false)} src={url || link} alt={name} />}
</div>
</div>
);
@@ -227,11 +227,11 @@ function Sticker({
Sticker.defaultProps = {
file: null,
type: '',
width: null,
height: null,
};
Sticker.propTypes = {
name: PropTypes.string.isRequired,
width: null,
height: null,
width: PropTypes.number,
height: PropTypes.number,
link: PropTypes.string.isRequired,
@@ -289,6 +289,7 @@ function Video({
const [isLoading, setIsLoading] = useState(false);
const [url, setUrl] = useState(null);
const [thumbUrl, setThumbUrl] = useState(null);
const [blur, setBlur] = useState(true);
useEffect(() => {
let unmounted = false;
@@ -303,16 +304,16 @@ function Video({
};
}, []);
async function loadVideo() {
const loadVideo = async () => {
const myUrl = await getUrl(link, type, file);
setUrl(myUrl);
setIsLoading(false);
}
};
function handlePlayVideo() {
const handlePlayVideo = () => {
setIsLoading(true);
loadVideo();
}
};
return (
<div className="file-container">
@@ -323,15 +324,17 @@ function Video({
}}
className="video-container"
>
{ url === null && blurhash && <BlurhashCanvas hash={blurhash} punch={1} />}
{ url === null && thumbUrl !== null && (
/* eslint-disable-next-line jsx-a11y/alt-text */
<img src={thumbUrl} />
)}
{ url === null && isLoading && <Spinner size="small" /> }
{ url === null && !isLoading && <IconButton onClick={handlePlayVideo} tooltip="Play video" src={PlaySVG} />}
{ url !== null && (
/* eslint-disable-next-line jsx-a11y/media-has-caption */
{ url === null ? (
<>
{ blurhash && blur && <BlurhashCanvas hash={blurhash} punch={1} />}
{ thumbUrl !== null && (
<img style={{ display: blur ? 'none' : 'unset' }} src={thumbUrl} onLoad={() => setBlur(false)} alt={name} />
)}
{isLoading && <Spinner size="small" />}
{!isLoading && <IconButton onClick={handlePlayVideo} tooltip="Play video" src={PlaySVG} />}
</>
) : (
/* eslint-disable-next-line jsx-a11y/media-has-caption */
<video autoPlay controls poster={thumbUrl}>
<source src={url} type={getBlobSafeMimeType(type)} />
</video>

View File

@@ -27,14 +27,21 @@
white-space: initial;
}
.sticker-container {
display: inline-flex;
max-width: 128px;
width: 100%;
& img {
width: 100% !important;
}
}
.image-container,
.video-container,
.audio-container {
font-size: 0;
line-height: 0;
position: relative;
display: flex;
justify-content: center;
align-items: center;
@@ -48,7 +55,6 @@
.video-container {
& img,
& canvas {
position: absolute;
max-width: unset !important;
width: 100% !important;
height: 100%;
@@ -57,18 +63,13 @@
}
}
.sticker-container {
display: inline-flex;
max-width: 128px;
width: 100%;
& img {
width: 100% !important;
}
}
.video-container {
position: relative;
& .ic-btn-surface {
background-color: var(--bg-surface-low);
}
& .ic-btn-surface,
& .donut-spinner {
position: absolute;
}
video {

View File

@@ -206,7 +206,13 @@ const MessageBody = React.memo(({
let content = null;
if (isCustomHTML) {
try {
content = twemojify(sanitizeCustomHtml(body), undefined, true, false, true);
content = twemojify(
sanitizeCustomHtml(initMatrix.matrixClient, body),
undefined,
true,
false,
true,
);
} catch {
console.error('Malformed custom html: ', body);
content = twemojify(body, undefined);

View File

@@ -252,6 +252,58 @@ function EmojiBoard({ onSelect, searchRef }) {
return (
<div id="emoji-board" className="emoji-board">
<ScrollView invisible>
<div className="emoji-board__nav">
{recentEmojis.length > 0 && (
<IconButton
onClick={() => openGroup(0)}
src={RecentClockIC}
tooltip="Recent"
tooltipPlacement="left"
/>
)}
<div className="emoji-board__nav-custom">
{
availableEmojis.map((pack) => {
const src = initMatrix.matrixClient
.mxcUrlToHttp(pack.avatarUrl ?? pack.getEmojis()[0].mxc);
return (
<IconButton
onClick={() => openGroup(recentOffset + pack.packIndex)}
src={src}
key={pack.packIndex}
tooltip={pack.displayName ?? 'Unknown'}
tooltipPlacement="left"
isImage
/>
);
})
}
</div>
<div className="emoji-board__nav-twemoji">
{
[
[0, EmojiIC, 'Smilies'],
[1, DogIC, 'Animals'],
[2, CupIC, 'Food'],
[3, BallIC, 'Activities'],
[4, PhotoIC, 'Travel'],
[5, BulbIC, 'Objects'],
[6, PeaceIC, 'Symbols'],
[7, FlagIC, 'Flags'],
].map(([indx, ico, name]) => (
<IconButton
onClick={() => openGroup(recentOffset + availableEmojis.length + indx)}
key={indx}
src={ico}
tooltip={name}
tooltipPlacement="left"
/>
))
}
</div>
</div>
</ScrollView>
<div className="emoji-board__content">
<div className="emoji-board__content__search">
<RawIcon size="small" src={SearchIC} />
@@ -285,58 +337,6 @@ function EmojiBoard({ onSelect, searchRef }) {
<Text>:slight_smile:</Text>
</div>
</div>
<ScrollView invisible>
<div className="emoji-board__nav">
{recentEmojis.length > 0 && (
<IconButton
onClick={() => openGroup(0)}
src={RecentClockIC}
tooltip="Recent"
tooltipPlacement="right"
/>
)}
<div className="emoji-board__nav-custom">
{
availableEmojis.map((pack) => {
const src = initMatrix.matrixClient
.mxcUrlToHttp(pack.avatarUrl ?? pack.getEmojis()[0].mxc);
return (
<IconButton
onClick={() => openGroup(recentOffset + pack.packIndex)}
src={src}
key={pack.packIndex}
tooltip={pack.displayName ?? 'Unknown'}
tooltipPlacement="right"
isImage
/>
);
})
}
</div>
<div className="emoji-board__nav-twemoji">
{
[
[0, EmojiIC, 'Smilies'],
[1, DogIC, 'Animals'],
[2, CupIC, 'Food'],
[3, BallIC, 'Activities'],
[4, PhotoIC, 'Travel'],
[5, BulbIC, 'Objects'],
[6, PeaceIC, 'Symbols'],
[7, FlagIC, 'Flags'],
].map(([indx, ico, name]) => (
<IconButton
onClick={() => openGroup(recentOffset + availableEmojis.length + indx)}
key={indx}
src={ico}
tooltip={name}
tooltipPlacement="right"
/>
))
}
</div>
</div>
</ScrollView>
</div>
);
}

View File

@@ -25,8 +25,7 @@
min-height: 100%;
padding: 4px 6px;
background-color: var(--bg-surface-low);
@include dir.side(border, 1px solid var(--bg-surface-border), none);
@include dir.side(border, none, 1px solid var(--bg-surface-border));
position: relative;
@@ -122,8 +121,11 @@
@include dir.side(margin, var(--left-margin), var(--right-margin));
}
& .emoji {
width: 38px;
height: 38px;
max-width: 38px;
max-height: 38px;
width: 100%;
height: 100%;
overflow: hidden;
object-fit: contain;
padding: var(--emoji-padding);
cursor: pointer;

View File

@@ -1,6 +1,6 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/no-static-element-interactions */
import React from 'react';
import React, { useRef } from 'react';
import PropTypes from 'prop-types';
import './StickerBoard.scss';
@@ -9,10 +9,12 @@ import { getRelevantPacks } from '../emoji-board/custom-emoji';
import Text from '../../atoms/text/Text';
import ScrollView from '../../atoms/scroll/ScrollView';
import IconButton from '../../atoms/button/IconButton';
function StickerBoard({ roomId, onSelect }) {
const mx = initMatrix.matrixClient;
const room = mx.getRoom(roomId);
const scrollRef = useRef(null);
const parentIds = initMatrix.roomList.getAllParentSpaces(room.roomId);
const parentRooms = [...parentIds].map((id) => mx.getRoom(id));
@@ -38,6 +40,11 @@ function StickerBoard({ roomId, onSelect }) {
onSelect(stickerData);
};
const openGroup = (groupIndex) => {
const scrollContent = scrollRef.current.firstElementChild;
scrollContent.children[groupIndex].scrollIntoView();
};
const renderPack = (pack) => (
<div className="sticker-board__pack" key={pack.id}>
<Text className="sticker-board__pack-header" variant="b2" weight="bold">{pack.displayName ?? 'Unknown'}</Text>
@@ -50,6 +57,7 @@ function StickerBoard({ roomId, onSelect }) {
alt={sticker.shortcode}
title={sticker.body ?? sticker.shortcode}
data-mx-sticker={sticker.mxc}
loading="lazy"
/>
))}
</div>
@@ -58,8 +66,27 @@ function StickerBoard({ roomId, onSelect }) {
return (
<div className="sticker-board">
{packs.length > 0 && (
<ScrollView invisible>
<div className="sticker-board__sidebar">
{packs.map((pack, index) => {
const src = mx.mxcUrlToHttp(pack.avatarUrl ?? pack.getStickers()[0].mxc);
return (
<IconButton
key={pack.id}
onClick={() => openGroup(index)}
src={src}
tooltip={pack.displayName || 'Unknown'}
tooltipPlacement="left"
isImage
/>
);
})}
</div>
</ScrollView>
)}
<div className="sticker-board__container">
<ScrollView autoHide>
<ScrollView autoHide ref={scrollRef}>
<div
onClick={handleOnSelect}
className="sticker-board__content"

View File

@@ -5,6 +5,20 @@
--sticker-board-width: 286px;
display: flex;
height: var(--sticker-board-height);
display: flex;
& > .scrollbar {
width: initial;
height: var(--sticker-board-height);
}
&__sidebar {
display: flex;
flex-direction: column;
min-height: 100%;
padding: 4px 6px;
@include dir.side(border, none, 1px solid var(--bg-surface-border));
}
&__container {
flex-grow: 1;

View File

@@ -1,13 +1,16 @@
import initMatrix from '../initMatrix';
function logout() {
async function logout() {
const mx = initMatrix.matrixClient;
mx.stopClient();
mx.logout().then(() => {
mx.clearStores();
window.localStorage.clear();
window.location.reload();
});
try {
await mx.logout();
} catch {
// ignore if failed to logout
}
mx.clearStores();
window.localStorage.clear();
window.location.reload();
}
export default logout;

View File

@@ -6,6 +6,7 @@ import { math } from 'micromark-extension-math';
import { encode } from 'blurhash';
import { getShortcodeToEmoji } from '../../app/organisms/emoji-board/custom-emoji';
import { mathExtensionHtml, spoilerExtension, spoilerExtensionHtml } from '../../util/markdown';
import { sanitizeText } from '../../util/sanitize';
import cons from './cons';
import settings from './settings';
@@ -148,29 +149,25 @@ function findAndReplace(text, regex, filter, replace) {
return copyText;
}
function formatAndEmojifyText(mx, roomList, room, text) {
function formatUserPill(room, text) {
const { userIdsToDisplayNames } = room.currentState;
const parentIds = roomList.getAllParentSpaces(room.roomId);
const parentRooms = [...parentIds].map((id) => mx.getRoom(id));
const allEmoji = getShortcodeToEmoji(mx, [room, ...parentRooms]);
let formattedText;
if (settings.isMarkdown) {
formattedText = getFormattedBody(text);
} else {
formattedText = text;
}
formattedText = findAndReplace(
formattedText,
return findAndReplace(
text,
MXID_REGEX,
(match) => userIdsToDisplayNames[match[0]],
(match) => (
`<a href="https://matrix.to/#/${match[0]}">@${userIdsToDisplayNames[match[0]]}</a>`
),
);
formattedText = findAndReplace(
formattedText,
}
function formatEmoji(mx, room, roomList, text) {
const parentIds = roomList.getAllParentSpaces(room.roomId);
const parentRooms = [...parentIds].map((id) => mx.getRoom(id));
const allEmoji = getShortcodeToEmoji(mx, [room, ...parentRooms]);
return findAndReplace(
text,
SHORTCODE_REGEX,
(match) => allEmoji.has(match[1]),
(match) => {
@@ -191,8 +188,6 @@ function formatAndEmojifyText(mx, roomList, room, text) {
return tag;
},
);
return formattedText;
}
class RoomsInput extends EventEmitter {
@@ -295,25 +290,27 @@ class RoomsInput extends EventEmitter {
}
if (this.getMessage(roomId).trim() !== '') {
const rawMessage = input.message;
let content = {
body: input.message,
body: rawMessage,
msgtype: 'm.text',
};
// Apply formatting if relevant
const formattedBody = formatAndEmojifyText(
this.matrixClient,
this.roomList,
room,
input.message,
);
let formattedBody = settings.isMarkdown
? getFormattedBody(rawMessage)
: sanitizeText(rawMessage);
formattedBody = formatUserPill(room, formattedBody);
formattedBody = formatEmoji(this.matrixClient, room, this.roomList, formattedBody);
content.body = findAndReplace(
content.body,
MXID_REGEX,
(match) => room.currentState.userIdsToDisplayNames[match[0]],
(match) => `@${room.currentState.userIdsToDisplayNames[match[0]]}`,
);
if (formattedBody !== input.message) {
if (formattedBody !== sanitizeText(rawMessage)) {
// Formatting was applied, and we need to switch to custom HTML
content.format = 'org.matrix.custom.html';
content.formatted_body = formattedBody;
@@ -481,19 +478,19 @@ class RoomsInput extends EventEmitter {
};
// Apply formatting if relevant
const formattedBody = formatAndEmojifyText(
this.matrixClient,
this.roomList,
room,
editedBody,
);
let formattedBody = settings.isMarkdown
? getFormattedBody(editedBody)
: sanitizeText(editedBody);
formattedBody = formatUserPill(room, formattedBody);
formattedBody = formatEmoji(this.matrixClient, room, this.roomList, formattedBody);
content.body = findAndReplace(
content.body,
MXID_REGEX,
(match) => room.currentState.userIdsToDisplayNames[match[0]],
(match) => `@${room.currentState.userIdsToDisplayNames[match[0]]}`,
);
if (formattedBody !== editedBody) {
if (formattedBody !== sanitizeText(editedBody)) {
content.formatted_body = ` * ${formattedBody}`;
content.format = 'org.matrix.custom.html';
content['m.new_content'].formatted_body = formattedBody;

View File

@@ -1,5 +1,5 @@
const cons = {
version: '2.1.1',
version: '2.1.3',
secretKey: {
ACCESS_TOKEN: 'cinny_access_token',
DEVICE_ID: 'cinny_device_id',

View File

@@ -166,6 +166,9 @@ export function scaleDownImage(imageFile, width, height) {
img.onload = () => {
let newWidth = img.width;
let newHeight = img.height;
if (newHeight <= height && newWidth <= width) {
resolve(imageFile);
}
if (newHeight > height) {
newWidth = Math.floor(newWidth * (height / newHeight));

View File

@@ -1,7 +1,7 @@
import sanitizeHtml from 'sanitize-html';
import initMatrix from '../client/initMatrix';
const MAX_TAG_NESTING = 100;
let mx = null;
const permittedHtmlTags = [
'font', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
@@ -54,7 +54,7 @@ function transformATag(tagName, attribs) {
'data-mx-pill': userId,
},
};
if (userId === initMatrix.matrixClient.getUserId()) {
if (userId === mx?.getUserId()) {
pill.attribs['data-mx-ping'] = undefined;
}
return pill;
@@ -76,17 +76,28 @@ function transformATag(tagName, attribs) {
function transformImgTag(tagName, attribs) {
const { src } = attribs;
const mx = initMatrix.matrixClient;
if (src.startsWith('mxc://') === false) {
return {
tagName: 'a',
attribs: {
href: src,
rel: 'noopener',
target: '_blank',
},
text: attribs.alt || src,
};
}
return {
tagName,
attribs: {
...attribs,
src: src.startsWith('mxc://') ? mx.mxcUrlToHttp(src) : src,
src: mx?.mxcUrlToHttp(src),
},
};
}
export function sanitizeCustomHtml(body) {
export function sanitizeCustomHtml(matrixClient, body) {
mx = matrixClient;
return sanitizeHtml(body, {
allowedTags: permittedHtmlTags,
allowedAttributes: permittedTagToAttributes,